diff --git a/usr/bin/spoc-container b/usr/bin/spoc-container index 16805fc..776cafd 100644 --- a/usr/bin/spoc-container +++ b/usr/bin/spoc-container @@ -66,35 +66,37 @@ def modify_container(container, depends, mounts, envs, uid, gid, cmd, cwd, ready setattr(container, member, value) def create(container_name, image_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart): + # Create container based on image definition and extrea fields container = Container(container_name, False) container.set_definition(Image(image_name).get_definition()) modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart) container.create() def modify(container_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart): + # Change configuration of an existing container container = Container(container_name) modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart) container.create() def destroy(container_name): - container = Container(container_name, False) - container.destroy() + # Remove container and its directory + Container(container_name, False).destroy() def start(container_name): - container = Container(container_name) - container.start() + # Start the container using init values from its definition + Container(container_name).start() def stop(container_name): - container = Container(container_name) - container.stop() + # Stop the container using halt signal from its definition + Container(container_name).stop() def status(container_name): - container = Container(container_name) - print(container.get_state().value) + # Prints current running status of the container + print(Container(container_name).get_state()) def execute(container_name, command): - container = Container(container_name) - container.execute(command) + # Execute a command in container's namespace + Container(container_name).execute(command) parser = argparse.ArgumentParser(description='SPOC container manager') parser.set_defaults(action=None) @@ -137,11 +139,11 @@ parser_start = subparsers.add_parser('start') parser_start.set_defaults(action=ACTION_START) parser_start.add_argument('container') -parser_stop = subparsers.add_parser('uninstall') +parser_stop = subparsers.add_parser('stop') parser_stop.set_defaults(action=ACTION_STOP) parser_stop.add_argument('container') -parser_status = subparsers.add_parser('start') +parser_status = subparsers.add_parser('status') parser_status.set_defaults(action=ACTION_STATUS) parser_status.add_argument('container') diff --git a/usr/lib/python3.8/spoc/container.py b/usr/lib/python3.8/spoc/container.py index 023141c..789163b 100644 --- a/usr/lib/python3.8/spoc/container.py +++ b/usr/lib/python3.8/spoc/container.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- import os +import shlex import shutil import subprocess import time +from concurrent.futures import ThreadPoolExecutor + from . import network from . import repo_local from .exceptions import InvalidContainerStateError @@ -64,9 +67,9 @@ class Container: state = subprocess.run(['lxc-info', '-sH', '-P', CONTAINERS_DIR, self.name], capture_output=True, check=True) return state.stdout.strip().decode() - def await_state(self, awaited_state, timeout=30): + def await_state(self, awaited_state): # Block execution until the container reaches the desired state or until timeout - subprocess.run(['lxc-wait', '-P', CONTAINERS_DIR, '-s', awaited_state, '-t', timeout, self.name], check=True) + subprocess.run(['lxc-wait', '-P', CONTAINERS_DIR, '-s', awaited_state, '-t', '30', self.name], check=True) def mount_rootfs(self): # Prepares container rootfs @@ -160,7 +163,7 @@ class Container: state = self.get_state() if state != STATE_RUNNING: raise InvalidContainerStateError(self.name, state) - check = subprocess.run(['lxc-attach', '-P', CONTAINERS_DIR, '--clear-env', self.name, '--']+ready_cmd, timeout=30) + check = subprocess.run(['lxc-attach', '-P', CONTAINERS_DIR, '--clear-env', self.name, '--']+ready_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30) if check.returncode == 0: break time.sleep(0.25) diff --git a/usr/lib/python3.8/spoc/imagebuilder.py b/usr/lib/python3.8/spoc/imagebuilder.py index 16e19df..003a324 100644 --- a/usr/lib/python3.8/spoc/imagebuilder.py +++ b/usr/lib/python3.8/spoc/imagebuilder.py @@ -68,14 +68,14 @@ class ImageBuilder: def run_script(self, script_lines): # Creates a temporary container, runs a script in its namespace, and stores the files modified by it as part of the layer - # TODO: Run the script as the correct user if UID/GID has been already set - doesn't this the LXC init do automatically? + # Note: If USER or WORKDIR directive has already been set, the command is run under that UID/GID or working directory os.makedirs(VOLUME_DIR, 0o755, True) script_fd, script_path = tempfile.mkstemp(suffix='.sh', dir=self.image.layer_path, text=True) script_name = os.path.basename(script_path) script_lines = '\n'.join(script_lines) with os.fdopen(script_fd, 'w') as script: script.write(f'#!/bin/sh\nset -ev\n\n{script_lines}\n') - os.chmod(script_path, 0o700) + os.chmod(script_path, 0o755) os.chown(script_path, 100000, 100000) # Create a temporary container from the current image definition and execute the script within the container container = Container(self.image.name, False)