Trying to get somewhere with traefik module
This commit is contained in:
parent
41ec8db301
commit
2db971234a
@ -1,6 +1,7 @@
|
|||||||
from .copy import Copy
|
from .copy import Copy
|
||||||
from .packages import Packages # noqa
|
from .packages import Packages # noqa
|
||||||
from .base import Action # noqa
|
from .base import Action # noqa
|
||||||
|
from .htpasswd import Htpasswd
|
||||||
from .run import Run # noqa
|
from .run import Run # noqa
|
||||||
from .pip import Pip
|
from .pip import Pip
|
||||||
from .service import Service
|
from .service import Service
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
from copy import deepcopy
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import importlib
|
import importlib
|
||||||
@ -25,9 +26,17 @@ class Action:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, doc=None, **kwargs):
|
||||||
self.args = args
|
self.args = args
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
self.call_args = []
|
||||||
|
self.call_kwargs = {}
|
||||||
|
self._doc = doc
|
||||||
|
self.menu = {
|
||||||
|
name: value
|
||||||
|
for name, value in kwargs.items()
|
||||||
|
if isinstance(value, Action)
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def context(self):
|
def context(self):
|
||||||
@ -106,8 +115,8 @@ class Action:
|
|||||||
return Output(**kwargs)
|
return Output(**kwargs)
|
||||||
|
|
||||||
async def __call__(self, *args, **kwargs):
|
async def __call__(self, *args, **kwargs):
|
||||||
self.call_args = args
|
self.call_args = list(self.call_args) + list(args)
|
||||||
self.call_kwargs = kwargs
|
self.call_kwargs.update(kwargs)
|
||||||
self.output = self.output_factory(*args, **kwargs)
|
self.output = self.output_factory(*args, **kwargs)
|
||||||
self.output_start()
|
self.output_start()
|
||||||
self.status = 'running'
|
self.status = 'running'
|
||||||
@ -209,3 +218,8 @@ class Action:
|
|||||||
from ..strategies.script import Actions
|
from ..strategies.script import Actions
|
||||||
self.actions = Actions(self, [p])
|
self.actions = Actions(self, [p])
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
def bind(self, *args):
|
||||||
|
clone = deepcopy(self)
|
||||||
|
clone.call_args = args
|
||||||
|
return clone
|
||||||
|
|||||||
29
shlax/actions/htpasswd.py
Normal file
29
shlax/actions/htpasswd.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import hashlib
|
||||||
|
import secrets
|
||||||
|
import string
|
||||||
|
|
||||||
|
from .base import Action
|
||||||
|
|
||||||
|
|
||||||
|
class Htpasswd(Action):
|
||||||
|
def __init__(self, path, user, *args, **kwargs):
|
||||||
|
self.path = path
|
||||||
|
self.user = user
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
async def call(self, *args, **kwargs):
|
||||||
|
found = False
|
||||||
|
htpasswd = await self.exec('cat', self.path, raises=False)
|
||||||
|
if htpasswd.rc == 0:
|
||||||
|
for line in htpasswd.out.split('\n'):
|
||||||
|
if line.startswith(self.user + ':'):
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
self.password = ''.join(secrets.choice(
|
||||||
|
string.ascii_letters + string.digits
|
||||||
|
) for i in range(20))
|
||||||
|
hashed = hashlib.sha1(self.password.encode('utf8'))
|
||||||
|
line = f'{self.user}:\\$sha1\\${hashed.hexdigest()}'
|
||||||
|
await self.exec(f'echo {line} >> {self.path}')
|
||||||
11
shlax/cli.py
11
shlax/cli.py
@ -36,21 +36,19 @@ class ConsoleScript(cli2.ConsoleScript):
|
|||||||
|
|
||||||
self.shlaxfile = Shlaxfile()
|
self.shlaxfile = Shlaxfile()
|
||||||
self.shlaxfile.parse(shlaxfile)
|
self.shlaxfile.parse(shlaxfile)
|
||||||
if len(self.shlaxfile.actions) == 1 and 'main' in self.shlaxfile.actions:
|
self._doc = inspect.getdoc(mod)
|
||||||
|
if 'main' in self.shlaxfile.actions:
|
||||||
action = self.shlaxfile.actions['main']
|
action = self.shlaxfile.actions['main']
|
||||||
self._doc = inspect.getdoc(action)
|
for name, child in self.shlaxfile.actions['main'].menu.items():
|
||||||
for name, doc in self.shlaxfile.actions['main'].doc.items():
|
|
||||||
self[name] = cli2.Callable(
|
self[name] = cli2.Callable(
|
||||||
name,
|
name,
|
||||||
action.callable(),
|
child.callable(),
|
||||||
options={
|
options={
|
||||||
k: cli2.Option(name=k, **v)
|
k: cli2.Option(name=k, **v)
|
||||||
for k, v in action.options.items()
|
for k, v in action.options.items()
|
||||||
},
|
},
|
||||||
color=getattr(action, 'color', cli2.YELLOW),
|
color=getattr(action, 'color', cli2.YELLOW),
|
||||||
doc=doc,
|
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
for name, action in self.shlaxfile.actions.items():
|
for name, action in self.shlaxfile.actions.items():
|
||||||
self[name] = cli2.Callable(
|
self[name] = cli2.Callable(
|
||||||
name,
|
name,
|
||||||
@ -60,6 +58,7 @@ class ConsoleScript(cli2.ConsoleScript):
|
|||||||
for k, v in action.options.items()
|
for k, v in action.options.items()
|
||||||
},
|
},
|
||||||
color=getattr(action, 'color', cli2.YELLOW),
|
color=getattr(action, 'color', cli2.YELLOW),
|
||||||
|
doc=inspect.getdoc(getattr(action, name, None)) or action._doc,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
from shlax import repo
|
from shlax import repo
|
||||||
|
|||||||
@ -5,7 +5,8 @@ Manage a traefik container maintained by Shlax community.
|
|||||||
|
|
||||||
from shlax import *
|
from shlax import *
|
||||||
|
|
||||||
main = Container(
|
main = Docker(
|
||||||
|
name='traefik',
|
||||||
image='traefik:v2.0.0',
|
image='traefik:v2.0.0',
|
||||||
networks=['web'],
|
networks=['web'],
|
||||||
command=[
|
command=[
|
||||||
@ -26,5 +27,15 @@ main = Container(
|
|||||||
'traefik.http.routers.traefik.rule=Host(`{{ url.split("/")[2] }}`)',
|
'traefik.http.routers.traefik.rule=Host(`{{ url.split("/")[2] }}`)',
|
||||||
'traefik.http.routers.traefik.service=api@internal',
|
'traefik.http.routers.traefik.service=api@internal',
|
||||||
'traefik.http.routers.traefik.entrypoints=web',
|
'traefik.http.routers.traefik.entrypoints=web',
|
||||||
]
|
],
|
||||||
|
doc='Current traefik instance',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
install = Script(
|
||||||
|
Htpasswd('./htpasswd', 'root'),
|
||||||
|
main.bind('up'),
|
||||||
|
doc='Deploy a Traefik instance',
|
||||||
|
)
|
||||||
|
|
||||||
|
up = main.bind('up')
|
||||||
|
rm = main.bind('rm')
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
from .script import Script
|
from .script import Script
|
||||||
|
from ..image import Image
|
||||||
|
|
||||||
|
|
||||||
class Container(Script):
|
class Container(Script):
|
||||||
@ -8,18 +9,23 @@ class Container(Script):
|
|||||||
|
|
||||||
Such wow
|
Such wow
|
||||||
"""
|
"""
|
||||||
doc = dict(
|
def __init__(self, *args, **kwargs):
|
||||||
build='Execute the Build script',
|
kwargs.setdefault('start', dict())
|
||||||
test='Execute the Test script (if any)',
|
super().__init__(*args, **kwargs)
|
||||||
push='Push the container (if Build script defines commit kwarg)',
|
|
||||||
)
|
|
||||||
|
|
||||||
async def call(self, *args, **kwargs):
|
async def call(self, *args, **kwargs):
|
||||||
if not args or 'build' in args:
|
if step('build'):
|
||||||
await self.kwargs['build'](**kwargs)
|
await self.kwargs['build'](**kwargs)
|
||||||
self.image = self.kwargs['build'].image
|
self.image = self.kwargs['build'].image
|
||||||
|
else:
|
||||||
|
self.image = kwargs.get('image', 'alpine')
|
||||||
|
if isinstance(self.image, str):
|
||||||
|
self.image = Image(self.image)
|
||||||
|
|
||||||
if not args or 'test' in args:
|
if step('install'):
|
||||||
|
await self.install(*args, **kwargs)
|
||||||
|
|
||||||
|
if step('test'):
|
||||||
self.output.test(self)
|
self.output.test(self)
|
||||||
await self.action('Docker',
|
await self.action('Docker',
|
||||||
*self.kwargs['test'].actions,
|
*self.kwargs['test'].actions,
|
||||||
@ -28,7 +34,7 @@ class Container(Script):
|
|||||||
workdir='/app',
|
workdir='/app',
|
||||||
)(**kwargs)
|
)(**kwargs)
|
||||||
|
|
||||||
if not args or 'push' in args:
|
if step('push'):
|
||||||
await self.image.push(action=self)
|
await self.image.push(action=self)
|
||||||
|
|
||||||
#name = kwargs.get('name', os.getcwd()).split('/')[-1]
|
#name = kwargs.get('name', os.getcwd()).split('/')[-1]
|
||||||
|
|||||||
@ -14,16 +14,17 @@ class Actions(list):
|
|||||||
self.append(action)
|
self.append(action)
|
||||||
|
|
||||||
def append(self, value):
|
def append(self, value):
|
||||||
value = copy.deepcopy(value)
|
action = copy.deepcopy(value)
|
||||||
value.parent = self.owner
|
action.parent = self.owner
|
||||||
value.status = 'pending'
|
action.status = 'pending'
|
||||||
super().append(value)
|
super().append(action)
|
||||||
|
|
||||||
|
|
||||||
class Script(Action):
|
class Script(Action):
|
||||||
contextualize = ['shargs', 'exec', 'rexec', 'env', 'which', 'copy']
|
contextualize = ['shargs', 'exec', 'rexec', 'env', 'which', 'copy']
|
||||||
|
|
||||||
def __init__(self, *actions, **kwargs):
|
def __init__(self, *actions, **kwargs):
|
||||||
|
self.home = kwargs.pop('home', os.getcwd())
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.actions = Actions(self, actions)
|
self.actions = Actions(self, actions)
|
||||||
|
|
||||||
@ -32,3 +33,9 @@ class Script(Action):
|
|||||||
result = await action(*args, **kwargs)
|
result = await action(*args, **kwargs)
|
||||||
if action.status != 'success':
|
if action.status != 'success':
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def pollute(self, gbls):
|
||||||
|
for name, script in self.kwargs.items():
|
||||||
|
if not isinstance(script, Script):
|
||||||
|
continue
|
||||||
|
gbls[name] = script
|
||||||
|
|||||||
@ -11,10 +11,12 @@ class Docker(Localhost):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.image = kwargs.get('image', 'alpine')
|
self.image = kwargs.get('image', 'alpine')
|
||||||
|
self.name = kwargs.get('name', os.getcwd().split('/')[-1])
|
||||||
|
|
||||||
if not isinstance(self.image, Image):
|
if not isinstance(self.image, Image):
|
||||||
self.image = Image(self.image)
|
self.image = Image(self.image)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.context['ctr'] = None
|
|
||||||
|
|
||||||
def shargs(self, *args, daemon=False, **kwargs):
|
def shargs(self, *args, daemon=False, **kwargs):
|
||||||
if args[0] == 'docker':
|
if args[0] == 'docker':
|
||||||
@ -26,9 +28,9 @@ class Docker(Localhost):
|
|||||||
|
|
||||||
args, kwargs = super().shargs(*args, **kwargs)
|
args, kwargs = super().shargs(*args, **kwargs)
|
||||||
|
|
||||||
if self.context['ctr']:
|
if self.name:
|
||||||
executor = 'exec'
|
executor = 'exec'
|
||||||
extra = [self.context['ctr']]
|
extra = [self.name]
|
||||||
return [self.kwargs.get('docker', 'docker'), executor, '-t'] + extra + list(args), kwargs
|
return [self.kwargs.get('docker', 'docker'), executor, '-t'] + extra + list(args), kwargs
|
||||||
|
|
||||||
executor = 'run'
|
executor = 'run'
|
||||||
@ -39,23 +41,44 @@ class Docker(Localhost):
|
|||||||
return [self.kwargs.get('docker', 'docker'), executor, '-t'] + extra + [str(self.image)] + list(args), kwargs
|
return [self.kwargs.get('docker', 'docker'), executor, '-t'] + extra + [str(self.image)] + list(args), kwargs
|
||||||
|
|
||||||
async def call(self, *args, **kwargs):
|
async def call(self, *args, **kwargs):
|
||||||
name = kwargs.get('name', os.getcwd()).split('/')[-1]
|
def step(step):
|
||||||
self.context['ctr'] = (
|
return not args or step in args
|
||||||
await self.exec(
|
|
||||||
'docker', 'ps', '-aq', '--filter',
|
|
||||||
'name=' + name,
|
|
||||||
raises=False
|
|
||||||
)
|
|
||||||
).out.split('\n')[0]
|
|
||||||
|
|
||||||
if 'recreate' in args and self.context['ctr']:
|
# self.name = (
|
||||||
await self.exec('docker', 'rm', '-f', self.context['ctr'])
|
# await self.exec(
|
||||||
self.context['ctr'] = None
|
# 'docker', 'ps', '-aq', '--filter',
|
||||||
|
# 'name=' + self.name,
|
||||||
|
# raises=False
|
||||||
|
# )
|
||||||
|
# ).out.split('\n')[0]
|
||||||
|
|
||||||
if self.context['ctr']:
|
if step('rm'):
|
||||||
self.context['ctr'] = (await self.exec('docker', 'start', name)).out
|
await self.rm(*args, **kwargs)
|
||||||
|
|
||||||
|
if step('down') and self.name:
|
||||||
|
await self.exec('docker', 'down', '-f', self.name)
|
||||||
|
|
||||||
|
if step('up'):
|
||||||
|
await self.up(*args, **kwargs)
|
||||||
return await super().call(*args, **kwargs)
|
return await super().call(*args, **kwargs)
|
||||||
|
|
||||||
|
async def rm(self, *args, **kwargs):
|
||||||
|
return await self.exec('docker', 'rm', '-f', self.name)
|
||||||
|
|
||||||
|
async def down(self, *args, **kwargs):
|
||||||
|
"""Remove instance, except persistent data if any"""
|
||||||
|
if self.name:
|
||||||
|
self.name = (await self.exec('docker', 'start', self.name)).out
|
||||||
|
else:
|
||||||
|
self.name = (await self.exec('docker', 'run', '-d', '--name', self.name)).out
|
||||||
|
|
||||||
|
async def up(self, *args, **kwargs):
|
||||||
|
"""Perform start or run"""
|
||||||
|
if self.name:
|
||||||
|
self.name = (await self.exec('docker', 'start', self.name)).out
|
||||||
|
else:
|
||||||
|
self.id = (await self.exec('docker', 'run', '-d', '--name', self.name)).out
|
||||||
|
|
||||||
async def copy(self, *args):
|
async def copy(self, *args):
|
||||||
src = args[:-1]
|
src = args[:-1]
|
||||||
dst = args[-1]
|
dst = args[-1]
|
||||||
@ -70,7 +93,7 @@ class Docker(Localhost):
|
|||||||
else:
|
else:
|
||||||
args = ['docker', 'copy', self.ctr, s, dst]
|
args = ['docker', 'copy', self.ctr, s, dst]
|
||||||
'''
|
'''
|
||||||
args = ['docker', 'cp', s, self.context['ctr'] + ':' + dst]
|
args = ['docker', 'cp', s, self.name + ':' + dst]
|
||||||
procs.append(self.exec(*args))
|
procs.append(self.exec(*args))
|
||||||
|
|
||||||
return await asyncio.gather(*procs)
|
return await asyncio.gather(*procs)
|
||||||
|
|||||||
@ -8,6 +8,11 @@ from ..strategies.script import Script
|
|||||||
|
|
||||||
class Localhost(Script):
|
class Localhost(Script):
|
||||||
root = '/'
|
root = '/'
|
||||||
|
contextualize = Script.contextualize + ['home']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.home = kwargs.pop('home', os.getcwd())
|
||||||
|
|
||||||
def shargs(self, *args, **kwargs):
|
def shargs(self, *args, **kwargs):
|
||||||
user = kwargs.pop('user', None)
|
user = kwargs.pop('user', None)
|
||||||
@ -46,6 +51,9 @@ class Localhost(Script):
|
|||||||
async def env(self, name):
|
async def env(self, name):
|
||||||
return (await self.exec('echo $' + name)).out
|
return (await self.exec('echo $' + name)).out
|
||||||
|
|
||||||
|
async def exists(self, *paths):
|
||||||
|
proc = await self.exec('type ' + ' '.join(cmd), raises=False)
|
||||||
|
|
||||||
async def which(self, *cmd):
|
async def which(self, *cmd):
|
||||||
"""
|
"""
|
||||||
Return the first path to the cmd in the container.
|
Return the first path to the cmd in the container.
|
||||||
@ -61,7 +69,10 @@ class Localhost(Script):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def copy(self, *args):
|
async def copy(self, *args):
|
||||||
args = ['cp', '-ra'] + list(args)
|
if args[-1].startswith('./'):
|
||||||
|
args = list(args)
|
||||||
|
args[-1] = self.home + '/' + args[-1][2:]
|
||||||
|
args = ['cp', '-rua'] + list(args)
|
||||||
return await self.exec(*args)
|
return await self.exec(*args)
|
||||||
|
|
||||||
async def mount(self, *dirs):
|
async def mount(self, *dirs):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user