Add up command, allow fine grain debug output

This commit is contained in:
jpic 2020-02-12 13:19:44 +01:00
parent 409b625309
commit 2e9a23eb5a
6 changed files with 118 additions and 46 deletions

View File

@ -40,7 +40,11 @@ class ConsoleScript(cli2.ConsoleScript):
for name, script in self.podfile.pod.scripts.items(): for name, script in self.podfile.pod.scripts.items():
cb = self.podfile.pod.script(name) cb = self.podfile.pod.script(name)
cb.__doc__ = inspect.getdoc(script) or script.doc cb.__doc__ = inspect.getdoc(script) or script.doc
self[name] = cli2.Callable(name, cb) self[name] = cli2.Callable(
name,
cb,
options=script.options,
)
return super().__call__(*args, **kwargs) return super().__call__(*args, **kwargs)
def call(self, command): def call(self, command):

View File

@ -4,16 +4,48 @@ import os
from .build import Build from .build import Build
from .container import Container from .container import Container
from .exceptions import WrongResult
from .script import Script from .script import Script
from .visitable import Visitable 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): class Pod(Visitable):
default_scripts = dict( default_scripts = dict(
build=Build(), build=Build(),
run=Script('run', 'Run a container command'), run=Script('run', 'Run a container command'),
up=Up('up', 'Start the stack'),
test=Script('test', 'Run tests inside containers'),
) )
@property
def name(self):
return os.getenv('POD', os.getcwd().split('/')[-1])
@property @property
def containers(self): def containers(self):
return [i for i in self.visitors if type(i) == Container] return [i for i in self.visitors if type(i) == Container]
@ -22,20 +54,6 @@ class Pod(Visitable):
async def cb(*args, **kwargs): async def cb(*args, **kwargs):
asyncio.events.get_event_loop() asyncio.events.get_event_loop()
script = copy.deepcopy(self.scripts[name]) script = copy.deepcopy(self.scripts[name])
kwargs['pod'] = self
if args: return await script.run(*args, **kwargs)
containers = [c for c in self.containers if c.name in args]
else:
containers = self.containers
procs = []
for container in containers:
procs.append(script(
container,
*args,
container=container,
pod=self,
**kwargs,
))
return await asyncio.gather(*procs)
return cb return cb

View File

@ -1,4 +1,5 @@
import importlib import importlib
import os
from .container import Container from .container import Container
from .pod import Pod from .pod import Pod
@ -8,9 +9,14 @@ class Podfile:
def __init__(self, pods, containers): def __init__(self, pods, containers):
self.pods = pods self.pods = pods
self.containers = containers self.containers = containers
if not self.pods: if not self.pods:
self.pods['pod'] = Pod(*containers.values()) self.pods['pod'] = Pod(*containers.values())
for pod in self.pods.values():
for container in pod.containers:
container.pod = pod
@property @property
def pod(self): def pod(self):
return self.pods['pod'] return self.pods['pod']

View File

@ -20,12 +20,16 @@ class PrefixStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def pipe_data_received(self, fd, data): def pipe_data_received(self, fd, data):
if fd in (1, 2): from .console_script import console_script
debug = console_script.parser.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'): for line in data.split(b'\n'):
if not line: if not line:
continue continue
sys.stdout.buffer.write( sys.stdout.buffer.write(
self.prefix.encode('utf8') + b' | ' + line + b'\n' self.prefix.encode('utf8') + b' | ' + line + b'\n'
if self.prefix else line + b'\n'
) )
sys.stdout.flush() sys.stdout.flush()
super().pipe_data_received(fd, data) super().pipe_data_received(fd, data)
@ -38,26 +42,6 @@ def protocol_factory(prefix):
loop=asyncio.events.get_event_loop() loop=asyncio.events.get_event_loop()
) )
return _p return _p
'''
async def proc(args, prefix=None, wait=True, raises=True):
loop = asyncio.events.get_event_loop()
transport, protocol = await loop.subprocess_exec(
protocol_factory(prefix), *args)
proc = asyncio.subprocess.Process(transport, protocol, loop)
if wait:
stdout, stderr = await proc.communicate()
log['result'] = await proc.wait()
if raises and log['result']:
raise WrongResult()
if wait:
return log
return proc
'''
class Proc: class Proc:
@ -92,7 +76,13 @@ class Proc:
if self.called: if self.called:
raise Exception('Already called: ' + self.cmd) 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):
if self.prefix:
print(f'{self.prefix} | + {self.cmd}') print(f'{self.prefix} | + {self.cmd}')
else:
print(f'+ {self.cmd}')
loop = asyncio.events.get_event_loop() loop = asyncio.events.get_event_loop()
transport, protocol = await loop.subprocess_exec( transport, protocol = await loop.subprocess_exec(
@ -121,3 +111,8 @@ class Proc:
if self.raises and self.proc.returncode: if self.raises and self.proc.returncode:
raise WrongResult() raise WrongResult()
return self return self
@property
def json(self):
import json
return json.loads(self.out)

View File

@ -1,15 +1,30 @@
import asyncio
import cli2
import textwrap import textwrap
from .proc import Proc from .proc import Proc
class Script: class Script:
options = [
cli2.Option(
'debug',
alias='d',
color=cli2.GREEN,
help='''
Display debug output.
Supports values: proc,out,visit
'''
),
]
def __init__(self, name=None, doc=None): def __init__(self, name=None, doc=None):
self.name = name or type(self).__name__.lower() self.name = name or type(self).__name__.lower()
self.doc = doc or 'Custom script' self.doc = doc or 'Custom script'
async def exec(self, *args, **kwargs): async def exec(self, *args, **kwargs):
"""Execute a command on the host.""" """Execute a command on the host."""
if getattr(self, 'container', None):
kwargs.setdefault('prefix', self.container.name) kwargs.setdefault('prefix', self.container.name)
proc = await Proc(*args, **kwargs)() proc = await Proc(*args, **kwargs)()
if kwargs.get('wait', True): if kwargs.get('wait', True):
@ -17,6 +32,9 @@ class Script:
return proc return proc
async def __call__(self, visitable, *args, **kwargs): async def __call__(self, visitable, *args, **kwargs):
from .console_script import console_script
debug = console_script.parser.options.get('debug', False)
for key, value in kwargs.items(): for key, value in kwargs.items():
setattr(self, key, value) setattr(self, key, value)
@ -36,10 +54,10 @@ class Script:
if not hasattr(visitor, method): if not hasattr(visitor, method):
continue continue
if debug is True or 'visit' in str(debug):
print( print(
visitable.name + ' | ', visitable.name + ' | ',
type(visitor).__name__, '.'.join([type(visitor).__name__, method]),
method,
' '.join(f'{k}={v}' for k, v in visitor.__dict__.items()) ' '.join(f'{k}={v}' for k, v in visitor.__dict__.items())
) )
result = getattr(visitor, method)(self) result = getattr(visitor, method)(self)
@ -49,3 +67,22 @@ class Script:
except Exception as e: except Exception as e:
await clean() await clean()
raise raise
async def run(self, *args, **kwargs):
pod = kwargs.get('pod')
if args:
containers = [c for c in pod.containers if c.name in args]
else:
containers = pod.containers
procs = []
for container in containers:
procs.append(self(
container,
*args,
container=container,
**kwargs,
))
return await asyncio.gather(*procs)

View File

@ -1,6 +1,8 @@
import os import os
import subprocess import subprocess
from ..exceptions import WrongResult
CI_VARS = ( CI_VARS = (
# gitlab # gitlab
'CI_COMMIT_SHORT_SHA', 'CI_COMMIT_SHORT_SHA',
@ -85,3 +87,13 @@ class Commit:
'--name', script.container.name, '--name', script.container.name,
':'.join((self.repo, self.tags[0])), ':'.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])),
)