Now to rewrite the test framework and good to go !
This commit is contained in:
parent
2e9a23eb5a
commit
3413fd8981
@ -22,11 +22,11 @@ class Build(Script):
|
||||
|
||||
async def config(self, line):
|
||||
"""Run buildah config."""
|
||||
return await self.append(f'buildah config {line} {self.ctr}')
|
||||
return await self.exec(f'buildah config {line} {self.ctr}')
|
||||
|
||||
async def copy(self, src, dst):
|
||||
"""Run buildah copy to copy a file from host into container."""
|
||||
return await self.append(f'buildah copy {self.ctr} {src} {dst}')
|
||||
return await self.exec(f'buildah copy {self.ctr} {src} {dst}')
|
||||
|
||||
async def cexec(self, *args, user=None, **kwargs):
|
||||
"""Execute a command in the container."""
|
||||
@ -75,3 +75,6 @@ class Build(Script):
|
||||
p = os.path.join(self.mnt, path[1:], c)
|
||||
if os.path.exists(p):
|
||||
return p[len(str(self.mnt)):]
|
||||
|
||||
def __repr__(self):
|
||||
return f'Build'
|
||||
|
||||
@ -33,6 +33,10 @@ class ConsoleScript(cli2.ConsoleScript):
|
||||
|
||||
self.funckwargs['cmd'] = self.forward_args
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.options = dict()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
import inspect
|
||||
from podctl.podfile import Podfile
|
||||
@ -43,18 +47,22 @@ class ConsoleScript(cli2.ConsoleScript):
|
||||
self[name] = cli2.Callable(
|
||||
name,
|
||||
cb,
|
||||
options=script.options,
|
||||
options={o.name: o for o in script.options},
|
||||
color=getattr(script, 'color', cli2.YELLOW),
|
||||
)
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
def call(self, command):
|
||||
self.options = self.parser.options
|
||||
|
||||
try:
|
||||
return super().call(command)
|
||||
except Mistake as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
except WrongResult:
|
||||
sys.exit(1)
|
||||
except WrongResult as e:
|
||||
print(e)
|
||||
sys.exit(e.proc.rc)
|
||||
|
||||
|
||||
console_script = ConsoleScript(__doc__).add_module('podctl.console_script')
|
||||
|
||||
@ -1,5 +1,53 @@
|
||||
from .build import Build
|
||||
from .exceptions import WrongResult
|
||||
from .visitable import Visitable
|
||||
|
||||
|
||||
class Container(Visitable):
|
||||
pass
|
||||
default_scripts = dict(
|
||||
build=Build(),
|
||||
)
|
||||
|
||||
@property
|
||||
def container_name(self):
|
||||
return '-'.join([self.pod.name, self.name])
|
||||
|
||||
async def down(self, script):
|
||||
try:
|
||||
await script.exec('podman', 'inspect', self.container_name)
|
||||
except WrongResult:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
from podctl.console_script import console_script
|
||||
argv = console_script.parser.nonoptions
|
||||
except AttributeError:
|
||||
argv = []
|
||||
argv = argv + [self.container_name]
|
||||
await script.exec('podman', 'rm', '-f', *argv)
|
||||
|
||||
async def run(self, script):
|
||||
await script.exec(
|
||||
'podman', 'run',
|
||||
'--name', self.container_name,
|
||||
':'.join((self.variable('repo'), self.variable('tags')[0])),
|
||||
)
|
||||
|
||||
async def up(self, script):
|
||||
try:
|
||||
await script.exec('podman', 'inspect', self.container_name)
|
||||
except WrongResult as ee:
|
||||
tag = ':'.join((
|
||||
self.variable('repo'),
|
||||
self.variable('tags')[0],
|
||||
))
|
||||
print(f'{self.name} | Container creating')
|
||||
await script.exec(
|
||||
'podman', 'run', '-d', '--name', self.container_name,
|
||||
tag,
|
||||
)
|
||||
print(f'{self.name} | Container created')
|
||||
else:
|
||||
print(f'{self.name} | Container starting')
|
||||
await script.exec('podman', 'start', self.container_name)
|
||||
print(f'{self.name} | Container started')
|
||||
|
||||
@ -7,4 +7,11 @@ class Mistake(PodctlException):
|
||||
|
||||
|
||||
class WrongResult(PodctlException):
|
||||
pass
|
||||
def __init__(self, proc):
|
||||
self.proc = proc
|
||||
super().__init__('\n'.join([i for i in [
|
||||
f'Command failed ! Exit with {proc.rc}'
|
||||
'+ ' + proc.cmd,
|
||||
proc.out,
|
||||
proc.err,
|
||||
]]))
|
||||
|
||||
@ -1,47 +1,44 @@
|
||||
import asyncio
|
||||
import copy
|
||||
import os
|
||||
|
||||
from .build import Build
|
||||
from .container import Container
|
||||
from .exceptions import WrongResult
|
||||
from .script import Script
|
||||
from .scripts import *
|
||||
from .visitable import Visitable
|
||||
|
||||
|
||||
class Up(Script):
|
||||
async def run(self, *args, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
pod = kwargs.get('pod')
|
||||
|
||||
try:
|
||||
pod.info = (await self.exec(
|
||||
'podman', 'pod', 'inspect', pod.name
|
||||
)).json
|
||||
print(f'Pod {pod.name} ready')
|
||||
except WrongResult:
|
||||
print(f'Pod {pod.name} creating')
|
||||
await self.exec(
|
||||
'podman', 'pod', 'create', '--name', self.pod.name,
|
||||
)
|
||||
print(f'Pod {pod.name} created')
|
||||
pod.info = (await self.exec(
|
||||
'podman', 'pod', 'inspect', pod.name
|
||||
)).json
|
||||
|
||||
return await super().run(*args, **kwargs)
|
||||
|
||||
|
||||
class Pod(Visitable):
|
||||
default_scripts = dict(
|
||||
build=Build(),
|
||||
run=Script('run', 'Run a container command'),
|
||||
up=Up('up', 'Start the stack'),
|
||||
test=Script('test', 'Run tests inside containers'),
|
||||
down=Down('down', 'Destroy the stack'),
|
||||
run=Run('run', 'Run a command in container(s)'),
|
||||
name=Name(
|
||||
'name',
|
||||
'Output the pod name for usage with podman',
|
||||
),
|
||||
)
|
||||
|
||||
async def down(self, script):
|
||||
try:
|
||||
await script.exec('podman', 'pod', 'inspect', self.name)
|
||||
except WrongResult:
|
||||
pass
|
||||
else:
|
||||
await script.exec('podman', 'pod', 'rm', self.name)
|
||||
|
||||
async def up(self, script):
|
||||
try:
|
||||
await script.exec(
|
||||
'podman', 'pod', 'inspect', self.name
|
||||
)
|
||||
print(f'{self.name} | Pod ready')
|
||||
except WrongResult:
|
||||
print(f'{self.name} | Pod creating')
|
||||
await script.exec(
|
||||
'podman', 'pod', 'create', '--name', self.name,
|
||||
)
|
||||
print(f'{self.name} | Pod created')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return os.getenv('POD', os.getcwd().split('/')[-1])
|
||||
@ -53,7 +50,9 @@ class Pod(Visitable):
|
||||
def script(self, name):
|
||||
async def cb(*args, **kwargs):
|
||||
asyncio.events.get_event_loop()
|
||||
script = copy.deepcopy(self.scripts[name])
|
||||
kwargs['pod'] = self
|
||||
return await script.run(*args, **kwargs)
|
||||
return await self.scripts[name].run(*args, **kwargs)
|
||||
return cb
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
@ -21,7 +21,7 @@ class PrefixStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol):
|
||||
|
||||
def pipe_data_received(self, fd, data):
|
||||
from .console_script import console_script
|
||||
debug = console_script.parser.options.get('debug', False)
|
||||
debug = console_script.options.get('debug', False)
|
||||
|
||||
if (debug is True or 'out' in str(debug)) and fd in (1, 2):
|
||||
for line in data.split(b'\n'):
|
||||
@ -34,6 +34,7 @@ class PrefixStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol):
|
||||
sys.stdout.flush()
|
||||
super().pipe_data_received(fd, data)
|
||||
|
||||
|
||||
def protocol_factory(prefix):
|
||||
def _p():
|
||||
return PrefixStreamProtocol(
|
||||
@ -77,8 +78,8 @@ class Proc:
|
||||
raise Exception('Already called: ' + self.cmd)
|
||||
|
||||
from .console_script import console_script
|
||||
debug = console_script.parser.options.get('debug', False)
|
||||
if debug is True or 'proc' in str(debug):
|
||||
debug = console_script.options.get('debug', False)
|
||||
if debug is True or 'cmd' in str(debug):
|
||||
if self.prefix:
|
||||
print(f'{self.prefix} | + {self.cmd}')
|
||||
else:
|
||||
@ -109,7 +110,7 @@ class Proc:
|
||||
if not self.communicated:
|
||||
await self.communicate()
|
||||
if self.raises and self.proc.returncode:
|
||||
raise WrongResult()
|
||||
raise WrongResult(self)
|
||||
return self
|
||||
|
||||
@property
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import copy
|
||||
import cli2
|
||||
import textwrap
|
||||
|
||||
@ -11,10 +12,11 @@ class Script:
|
||||
'debug',
|
||||
alias='d',
|
||||
color=cli2.GREEN,
|
||||
default='visit',
|
||||
help='''
|
||||
Display debug output.
|
||||
Supports values: proc,out,visit
|
||||
'''
|
||||
Display debug output. Supports values (combinable): cmd,out,visit
|
||||
'''.strip(),
|
||||
immediate=True,
|
||||
),
|
||||
]
|
||||
|
||||
@ -24,7 +26,7 @@ class Script:
|
||||
|
||||
async def exec(self, *args, **kwargs):
|
||||
"""Execute a command on the host."""
|
||||
if getattr(self, 'container', None):
|
||||
if getattr(self, 'container', None) and getattr(self.container, 'name', None):
|
||||
kwargs.setdefault('prefix', self.container.name)
|
||||
proc = await Proc(*args, **kwargs)()
|
||||
if kwargs.get('wait', True):
|
||||
@ -33,8 +35,9 @@ class Script:
|
||||
|
||||
async def __call__(self, visitable, *args, **kwargs):
|
||||
from .console_script import console_script
|
||||
debug = console_script.parser.options.get('debug', False)
|
||||
debug = console_script.options.get('debug', False)
|
||||
|
||||
self.args = args
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
@ -44,7 +47,14 @@ class Script:
|
||||
async def clean():
|
||||
for visitor in visitable.visitors:
|
||||
if hasattr(visitor, 'clean_' + self.name):
|
||||
result = getattr(visitor, 'clean_' + self.name)(self)
|
||||
method = 'clean_' + self.name
|
||||
result = getattr(visitor, method)(self)
|
||||
if debug is True or 'visit' in str(debug):
|
||||
print(
|
||||
getattr(visitable, 'name', '') + ' | ',
|
||||
'.'.join([type(visitor).__name__, method]),
|
||||
' '.join(f'{k}={v}' for k, v in visitor.__dict__.items())
|
||||
)
|
||||
if result:
|
||||
await result
|
||||
|
||||
@ -56,7 +66,7 @@ class Script:
|
||||
|
||||
if debug is True or 'visit' in str(debug):
|
||||
print(
|
||||
visitable.name + ' | ',
|
||||
getattr(visitable, 'name', '') + ' | ',
|
||||
'.'.join([type(visitor).__name__, method]),
|
||||
' '.join(f'{k}={v}' for k, v in visitor.__dict__.items())
|
||||
)
|
||||
@ -69,20 +79,28 @@ class Script:
|
||||
raise
|
||||
|
||||
async def run(self, *args, **kwargs):
|
||||
pod = kwargs.get('pod')
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
if args:
|
||||
containers = [c for c in pod.containers if c.name in args]
|
||||
containers = [c for c in self.pod.containers if c.name in args]
|
||||
else:
|
||||
containers = pod.containers
|
||||
containers = self.pod.containers
|
||||
|
||||
procs = []
|
||||
for container in containers:
|
||||
procs.append(self(
|
||||
procs = [
|
||||
copy.deepcopy(self)(
|
||||
self.pod,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
]
|
||||
procs += [
|
||||
copy.deepcopy(self)(
|
||||
container,
|
||||
*args,
|
||||
container=container,
|
||||
**kwargs,
|
||||
))
|
||||
|
||||
)
|
||||
for container in containers
|
||||
]
|
||||
return await asyncio.gather(*procs)
|
||||
|
||||
50
podctl/scripts.py
Normal file
50
podctl/scripts.py
Normal file
@ -0,0 +1,50 @@
|
||||
import asyncio
|
||||
import cli2
|
||||
import copy
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .build import Build
|
||||
from .exceptions import WrongResult
|
||||
from .proc import Proc
|
||||
from .script import Script
|
||||
|
||||
|
||||
class Name(Script):
|
||||
color = cli2.GREEN
|
||||
|
||||
async def run(self, *args, **kwargs):
|
||||
print(kwargs.get('pod').name)
|
||||
|
||||
|
||||
class Down(Script):
|
||||
color = cli2.RED
|
||||
|
||||
|
||||
class Up(Script):
|
||||
pass
|
||||
|
||||
|
||||
class Run(Script):
|
||||
async def run(self, *args, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
|
||||
try:
|
||||
await self.exec(
|
||||
'podman', 'pod', 'inspect', self.pod.name
|
||||
)
|
||||
print(f'{self.pod.name} | Pod ready')
|
||||
except WrongResult:
|
||||
print(f'{self.pod.name} | Pod creating')
|
||||
await self.exec(
|
||||
'podman', 'pod', 'create', '--name', self.pod.name,
|
||||
)
|
||||
print(f'{self.pod.name} | Pod created')
|
||||
|
||||
return await asyncio.gather(*[
|
||||
copy.deepcopy(self)(
|
||||
self.pod,
|
||||
)
|
||||
for container in self.pod.containers
|
||||
])
|
||||
@ -1,5 +1,5 @@
|
||||
import asyncio
|
||||
from copy import copy
|
||||
from copy import copy, deepcopy
|
||||
|
||||
|
||||
class Visitable:
|
||||
@ -7,13 +7,14 @@ class Visitable:
|
||||
|
||||
def __init__(self, *visitors, **scripts):
|
||||
self.visitors = list(visitors)
|
||||
self.scripts = scripts or {
|
||||
k: v for k, v in self.default_scripts.items()
|
||||
}
|
||||
self.scripts = deepcopy(self.default_scripts)
|
||||
self.scripts.update(scripts)
|
||||
|
||||
'''
|
||||
def script(self, name):
|
||||
script = copy(self.scripts[name])
|
||||
return script
|
||||
'''
|
||||
|
||||
def visitor(self, name):
|
||||
for visitor in self.visitors:
|
||||
|
||||
@ -13,3 +13,6 @@ class Base:
|
||||
await script.umounts()
|
||||
await script.umount()
|
||||
proc = await script.exec('buildah', 'rm', script.ctr, raises=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'Base({self.base})'
|
||||
|
||||
@ -18,7 +18,7 @@ CI_VARS = (
|
||||
class Commit:
|
||||
def __init__(self, repo, tags=None, format=None, push=None, registry=None):
|
||||
self.repo = repo
|
||||
self.registry = registry
|
||||
self.registry = registry or 'localhost'
|
||||
self.push = push or os.getenv('CI')
|
||||
|
||||
# figure out registry host
|
||||
@ -81,19 +81,5 @@ class Commit:
|
||||
await script.exec('podman', 'push', f'{self.repo}:{tag}')
|
||||
await script.umount()
|
||||
|
||||
async def run(self, script):
|
||||
await script.exec(
|
||||
'podman', 'run', '-d',
|
||||
'--name', script.container.name,
|
||||
':'.join((self.repo, self.tags[0])),
|
||||
)
|
||||
|
||||
async def up(self, script):
|
||||
name = '-'.join([script.pod.name, script.container.name])
|
||||
try:
|
||||
await script.exec('podman', 'inspect', name)
|
||||
except WrongResult:
|
||||
await script.exec(
|
||||
'podman', 'run', '-d', '--name', name,
|
||||
':'.join((self.repo, self.tags[0])),
|
||||
)
|
||||
def __repr__(self):
|
||||
return f'Commit({self.registry}/{self.repo}:{self.tags})'
|
||||
|
||||
@ -10,6 +10,9 @@ class DumbInit:
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
|
||||
def post_build(self, script):
|
||||
async def post_build(self, script):
|
||||
cmd = '--cmd "dumb-init bash -euxc \'%s\'"' % self.cmd
|
||||
script.config(cmd)
|
||||
await script.config(cmd)
|
||||
|
||||
def __repr__(self):
|
||||
return f'DumbInit({self.cmd})'
|
||||
|
||||
@ -150,3 +150,6 @@ class Packages:
|
||||
cache_lists = os.path.join(cachedir, 'lists')
|
||||
await script.mount(cache_lists, f'/var/lib/apt/lists')
|
||||
return cachedir
|
||||
|
||||
def __repr__(self):
|
||||
return f'Packages({self.packages})'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user