Call compose from Project objects

This commit is contained in:
Jörn-Michael Miehe 2020-08-19 17:09:43 +02:00
parent 4290ed3743
commit 1f1f3b27b2
13 changed files with 80 additions and 117 deletions

View file

@ -1,8 +1,10 @@
# system # system
import logging import logging
import subprocess
# local # local
from . import subcommands from . import subcommands
from .subcommands.utils.executable import Executable
from .parser import Parser from .parser import Parser
@ -15,6 +17,16 @@ class Runner:
__commands = [] __commands = []
def __init__(self): def __init__(self):
# probe for Docker access
try:
Executable('docker').run(
['ps'],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
except subprocess.CalledProcessError:
raise PermissionError("Cannot access docker, please get into the docker group or run as root!")
# setup all subcommands # setup all subcommands
for className in subcommands.__all__: for className in subcommands.__all__:
cmd = getattr(subcommands, className) cmd = getattr(subcommands, className)

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
class BuildCommand(ServiceCommand): class BuildCommand(ServiceCommand):
@ -14,7 +13,6 @@ class BuildCommand(ServiceCommand):
) )
def _run_services(self, runner, args, project, services): def _run_services(self, runner, args, project, services):
DockerCommand('docker-compose').run(project, [ project.compose_run(['build', '--pull', *services])
'build', '--pull', *services
])
return True return True

View file

@ -3,7 +3,6 @@ import logging
# local # local
from ._subcommand import ProjectCommand from ._subcommand import ProjectCommand
from .utils.dockercommand import DockerCommand
class CmdCommand(ProjectCommand): class CmdCommand(ProjectCommand):
@ -36,8 +35,6 @@ class CmdCommand(ProjectCommand):
logging.debug(f"Updated args: {args}") logging.debug(f"Updated args: {args}")
# run with split compose_cmd argument # run with split compose_cmd argument
DockerCommand('docker-compose').run(projects[0], [ projects[0].compose_run([args.compose_cmd, *args.compose_args])
args.compose_cmd, *args.compose_args
])
return True return True

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
from .utils.misc import are_you_sure from .utils.misc import are_you_sure
@ -27,16 +26,12 @@ class DownCommand(ServiceCommand):
def _run_projects(self, runner, args, projects): def _run_projects(self, runner, args, projects):
for project in projects: for project in projects:
DockerCommand('docker-compose').run(project, [ project.compose_run(['down'])
'down'
])
return True return True
def _run_services(self, runner, args, project, services): def _run_services(self, runner, args, project, services):
DockerCommand('docker-compose').run(project, [ project.compose_run(['stop', *services])
'stop', *services project.compose_run(['rm', '-f', *services])
])
DockerCommand('docker-compose').run(project, [
'rm', '-f', *services
])
return True return True

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
class LogsCommand(ServiceCommand): class LogsCommand(ServiceCommand):
@ -31,10 +30,11 @@ class LogsCommand(ServiceCommand):
if services: if services:
compose_cmd = [*compose_cmd, *args.services] compose_cmd = [*compose_cmd, *args.services]
# use 'less' viewer if output will be static
if args.follow: if args.follow:
DockerCommand('docker-compose').run(project, compose_cmd) project.compose_run(compose_cmd)
else: else:
DockerCommand('docker-compose').run_less(project, compose_cmd) # use 'less' viewer if output is static
project.compose_run_less(compose_cmd)
return True return True

View file

@ -4,7 +4,7 @@ import subprocess
# local # local
from ._subcommand import SubCommand from ._subcommand import SubCommand
from .utils.dockercommand import DockerCommand from .utils.executable import Executable
from .utils.misc import are_you_sure from .utils.misc import are_you_sure
# parent # parent
@ -12,7 +12,7 @@ from ..config import LoadedConfig
def _find_net(net_name): def _find_net(net_name):
ps = DockerCommand('docker').run(None, [ ps = Executable('docker').run([
'network', 'ls', '--filter', f"name={net_name}", '--format', '{{.Name}}' 'network', 'ls', '--filter', f"name={net_name}", '--format', '{{.Name}}'
], stdout=subprocess.PIPE) ], stdout=subprocess.PIPE)
@ -41,7 +41,7 @@ class NetUpCommand(SubCommand):
return True return True
try: try:
DockerCommand('docker').run(None, [ Executable('docker').run([
'network', 'create', 'network', 'create',
'--driver', 'bridge', '--driver', 'bridge',
'--internal', '--internal',
@ -77,7 +77,7 @@ class NetDownCommand(SubCommand):
try: try:
if are_you_sure("This will bring down this instance's hub network!"): if are_you_sure("This will bring down this instance's hub network!"):
if runner.run('down'): if runner.run('down'):
DockerCommand('docker').run(None, [ Executable('docker').run([
'network', 'rm', net_name 'network', 'rm', net_name
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
class PullCommand(ServiceCommand): class PullCommand(ServiceCommand):
@ -14,7 +13,6 @@ class PullCommand(ServiceCommand):
) )
def _run_services(self, runner, args, project, services): def _run_services(self, runner, args, project, services):
DockerCommand('docker-compose').run(project, [ project.compose_run(['pull', '--ignore-pull-failures', *services])
'pull', '--ignore-pull-failures', *services
])
return True return True

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
class PushCommand(ServiceCommand): class PushCommand(ServiceCommand):
@ -14,7 +13,6 @@ class PushCommand(ServiceCommand):
) )
def _run_services(self, runner, args, project, services): def _run_services(self, runner, args, project, services):
DockerCommand('docker-compose').run(project, [ project.compose_run(['push', *services])
'push', *services
])
return True return True

View file

@ -4,7 +4,6 @@ import subprocess
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
# parent # parent
from ..config import LoadedConfig from ..config import LoadedConfig
@ -18,9 +17,10 @@ def _service_has_executable(project, service, exe_name):
try: try:
# test if desired shell exists # test if desired shell exists
DockerCommand('docker-compose').run(project, [ project.compose_run(
'exec', service, '/bin/sh', '-c', f"which {exe_name}" ['exec', service, '/bin/sh', '-c', f"which {exe_name}"],
], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
return True return True
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
@ -92,9 +92,7 @@ class ShCommand(ServiceCommand):
if shell is not None: if shell is not None:
# spawn shell # spawn shell
DockerCommand('docker-compose').run(project, [ project.compose_run(['exec', service, shell])
'exec', service, shell
])
return True return True
return False return False

View file

@ -1,6 +1,5 @@
# local # local
from ._subcommand import ServiceCommand from ._subcommand import ServiceCommand
from .utils.dockercommand import DockerCommand
class UpCommand(ServiceCommand): class UpCommand(ServiceCommand):
@ -21,9 +20,7 @@ class UpCommand(ServiceCommand):
def _run_services(self, runner, args, project, services): def _run_services(self, runner, args, project, services):
if runner.run('net-up'): if runner.run('net-up'):
DockerCommand('docker-compose').run(project, [ project.compose_run(['up', '-d', *services])
'up', '-d', *services
])
return True return True
return False return False

View file

@ -1,67 +0,0 @@
# system
import logging
import os
import subprocess
# local
from .executable import Executable
# parent
from ..._constants import CONF_DIRECTORY_NAME
from ...config import LoadedConfig
def _update_kwargs(project, **kwargs):
# enabled project given: command affects a project in this instance
if project is not None and project.is_enabled():
config = LoadedConfig.get()
# execute command in project directory
kwargs['cwd'] = project.dir_name()
# ensure there is an environment
if 'env' not in kwargs:
kwargs['env'] = {}
# create environment variables for docker commands
kwargs['env'].update({
'COMPOSE_PROJECT_NAME': project.get_name(),
'KIWI_HUB_NAME': config['network:name'],
'CONFDIR': os.path.join(config['runtime:storage'], CONF_DIRECTORY_NAME),
'TARGETDIR': project.target_dir_name()
})
logging.debug(f"kwargs updated: {kwargs}")
return kwargs
class DockerCommand(Executable):
__has_tried = False
def __init__(self, exe_name):
super().__init__(exe_name)
if not DockerCommand.__has_tried:
try:
Executable('docker').run(
['ps'],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
DockerCommand.__has_tried = True
except subprocess.CalledProcessError:
raise PermissionError("Cannot access docker, please get into the docker group or run as root!")
def run(self, project, process_args, **kwargs):
# equivalent to 'super().run' but agnostic of nested class construct
return super().__getattr__("run")(
process_args,
**_update_kwargs(project, **kwargs)
)
def run_less(self, project, process_args, **kwargs):
return super().__getattr__("run_less")(
process_args,
**_update_kwargs(project, **kwargs)
)

View file

@ -1,6 +1,8 @@
import logging import logging
import os import os
from .executable import Executable
from ..._constants import CONF_DIRECTORY_NAME from ..._constants import CONF_DIRECTORY_NAME
from ...config import LoadedConfig from ...config import LoadedConfig
@ -63,6 +65,41 @@ class Project:
def has_configs(self): def has_configs(self):
return os.path.isdir(self.conf_dir_name()) return os.path.isdir(self.conf_dir_name())
def __update_kwargs(self, kwargs):
if not self.is_enabled():
# cannot compose in a disabled project
logging.warning(f"Project '{self.get_name()}' is not enabled!")
return False
config = LoadedConfig.get()
# execute command in project directory
kwargs['cwd'] = self.dir_name()
# ensure there is an environment
if 'env' not in kwargs:
kwargs['env'] = {}
# create environment variables for docker commands
kwargs['env'].update({
'COMPOSE_PROJECT_NAME': self.get_name(),
'KIWI_HUB_NAME': config['network:name'],
'CONFDIR': os.path.join(config['runtime:storage'], CONF_DIRECTORY_NAME),
'TARGETDIR': self.target_dir_name()
})
logging.debug(f"kwargs updated: {kwargs}")
return True
def compose_run(self, compose_args, **kwargs):
if self.__update_kwargs(kwargs):
Executable('docker-compose').run(compose_args, **kwargs)
def compose_run_less(self, compose_args, **kwargs):
if self.__update_kwargs(kwargs):
Executable('docker-compose').run_less(compose_args, **kwargs)
def enable(self): def enable(self):
if self.is_disabled(): if self.is_disabled():
logging.info(f"Enabling project '{self.get_name()}'") logging.info(f"Enabling project '{self.get_name()}'")

View file

@ -4,7 +4,7 @@ import os
import subprocess import subprocess
# local # local
from .dockercommand import DockerCommand from .executable import Executable
# parent # parent
from ..._constants import IMAGES_DIRECTORY_NAME, LOCAL_IMAGES_NAME, DEFAULT_IMAGE_NAME from ..._constants import IMAGES_DIRECTORY_NAME, LOCAL_IMAGES_NAME, DEFAULT_IMAGE_NAME
@ -38,7 +38,7 @@ class Rootkit:
self.__image_tag = image_tag self.__image_tag = image_tag
def __exists(self): def __exists(self):
ps = DockerCommand('docker').run(None, [ ps = Executable('docker').run([
'images', 'images',
'--filter', f"reference={_image_name(self.__image_tag)}", '--filter', f"reference={_image_name(self.__image_tag)}",
'--format', '{{.Repository}}:{{.Tag}}' '--format', '{{.Repository}}:{{.Tag}}'
@ -52,13 +52,13 @@ class Rootkit:
else: else:
if self.__image_tag is None: if self.__image_tag is None:
logging.info(f"Pulling image {_image_name(self.__image_tag)}") logging.info(f"Pulling image {_image_name(self.__image_tag)}")
DockerCommand('docker').run(None, [ Executable('docker').run([
'pull', _image_name(self.__image_tag) 'pull', _image_name(self.__image_tag)
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else: else:
logging.info(f"Building image {_image_name(self.__image_tag)}") logging.info(f"Building image {_image_name(self.__image_tag)}")
DockerCommand('docker').run(None, [ Executable('docker').run([
'build', 'build',
'-t', _image_name(self.__image_tag), '-t', _image_name(self.__image_tag),
'-f', f"{IMAGES_DIRECTORY_NAME}/{self.__image_tag}.Dockerfile", '-f', f"{IMAGES_DIRECTORY_NAME}/{self.__image_tag}.Dockerfile",
@ -67,7 +67,7 @@ class Rootkit:
def run(self, process_args, **kwargs): def run(self, process_args, **kwargs):
self.__build_image() self.__build_image()
DockerCommand('docker').run(None, [ Executable('docker').run([
'run', '--rm', 'run', '--rm',
'-v', '/:/mnt', '-v', '/:/mnt',
'-u', 'root', '-u', 'root',