From 4134424bc11119bd8457a583a536c4b929e7b979 Mon Sep 17 00:00:00 2001 From: Martin Mares <mj@ucw.cz> Date: Thu, 6 Jun 2024 11:21:18 +0200 Subject: [PATCH] More commands --- TODO | 1 + shipcat.py | 73 +++++++++++++++++++++++++++++++++++++++++------ shipcat/config.py | 2 +- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/TODO b/TODO index 359e7ba..ba9a0b3 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,3 @@ - colors - status: do not exit on non-zero return code +- "shc CONTAINER start" vs. "shc CONTAINER shell" diff --git a/shipcat.py b/shipcat.py index d9122cb..d3c965b 100755 --- a/shipcat.py +++ b/shipcat.py @@ -25,10 +25,12 @@ def progress(msg: str) -> None: print(msg, file=sys.stderr, end="", flush=True) -def run_command(args: List[str], *rest, **kwargs) -> None: - res = subprocess.run(args, *rest, **kwargs) +def run_command(cmd: List[str], *args, **kwargs) -> None: + if verbose: + print('RUN: ' + " ".join(cmd)) + res = subprocess.run(cmd, *args, **kwargs) if res.returncode != 0: - die('Command failed: ' + " ".join(args)) + sys.exit(res.returncode) def load_config() -> GlobalConfig: @@ -131,7 +133,7 @@ def cmd_init(args: argparse.Namespace) -> None: except KeyError: progress('creating\n') run_command( - ['adduser', '--system', '--group', '--gecos', f'Container {name}', '--disabled-password', cc.user_name], + ['adduser', '--system', '--group', '--gecos', f'Container {name}', '--disabled-password', cc.user_name] ) pwd = getpwnam(cc.user_name) uid = pwd.pw_uid @@ -145,7 +147,7 @@ def cmd_init(args: argparse.Namespace) -> None: progress('allocating\n') sur = subuids.alloc_range(cc.user_name, 65536) run_command( - ['usermod', '--add-subuids', f'{sur.first}-{sur.first + sur.count - 1}', cc.user_name], + ['usermod', '--add-subuids', f'{sur.first}-{sur.first + sur.count - 1}', cc.user_name] ) progress('Subgid range: ') @@ -157,7 +159,7 @@ def cmd_init(args: argparse.Namespace) -> None: progress('allocating\n') sgr = subgids.alloc_range(cc.user_name, 65536) run_command( - ['usermod', '--add-subgids', f'{sgr.first}-{sgr.first + sgr.count - 1}', cc.user_name], + ['usermod', '--add-subgids', f'{sgr.first}-{sgr.first + sgr.count - 1}', cc.user_name] ) progress(f'Using user {cc.user_name}, uid {uid}, subuids {sur.first}+{sur.count}, subgids {sgr.first}+{sgr.count}\n') @@ -190,7 +192,7 @@ def cmd_init(args: argparse.Namespace) -> None: def service_action(cc: ContainerConfig, action: str) -> None: run_command( - ['systemctl', action, f'shc@{cc.container}.service'], + ['systemctl', action, f'shc@{cc.container}.service'] ) @@ -202,13 +204,13 @@ def cmd_create(args: argparse.Namespace) -> None: ip = socket.gethostbyname(name) run_command( - ['podman', 'pull', cc.image], + ['podman', 'pull', cc.image] ) service_action(cc, 'stop') run_command( - ['podman', 'rm', '-if', name], + ['podman', 'rm', '-if', name] ) run_command( @@ -243,6 +245,38 @@ def cmd_status(args: argparse.Namespace) -> None: service_action(cc, 'status') +def cmd_disable(args: argparse.Namespace) -> None: + cc = setup_container(args, False) + service_action(cc, 'disable') + + +def cmd_enable(args: argparse.Namespace) -> None: + cc = setup_container(args, False) + service_action(cc, 'enable') + + +def cmd_shell(args: argparse.Namespace) -> None: + cc = setup_container(args, False) + + run_command( + ['podman', 'exec', '-it', cc.container, '/bin/bash'] + ) + + +def cmd_exec(args: argparse.Namespace) -> None: + cc = setup_container(args, False) + + cmd = ['podman', 'exec'] + if args.tty is not None: + cmd.extend(['--interactive', '--tty']) + if args.user is not None: + cmd.extend(['--user', args.user]) + cmd.append(cc.container) + cmd.extend(args.arg) + + run_command(cmd) + + def parse_int_list(s: str) -> List[int]: return list(map(int, s.split(','))) @@ -252,6 +286,7 @@ parser = argparse.ArgumentParser( ) parser.add_argument('--as-user', type=int, metavar='UID', help='user ID of requesting user') parser.add_argument('--as-groups', type=parse_int_list, metavar='GID,...', help='group IDs of requesting user (primary first)') +parser.add_argument('--verbose', '-v', default=False, action='store_true', help='be chatty and explain what is going on') subparsers = parser.add_subparsers(help='action to perform', dest='action', required=True, metavar='ACTION') init_parser = subparsers.add_parser('init', help='initialize a new container', description='Initialize a new container. Should be called by root.') @@ -260,6 +295,21 @@ init_parser.add_argument('name', help='name of the container') create_parser = subparsers.add_parser('create', help='create a container from an image', description='Create a container from an image.') create_parser.add_argument('name', help='name of the container') +create_parser = subparsers.add_parser('disable', help='disable automatic startup of a container', description='Disable automatic startup of a container.') +create_parser.add_argument('name', help='name of the container') + +create_parser = subparsers.add_parser('enable', help='enable automatic startup of a container', description='Enable automatic startup of a container.') +create_parser.add_argument('name', help='name of the container') + +create_parser = subparsers.add_parser('exec', help='execute a command within a container', description='Execute a command within a container.') +create_parser.add_argument('name', help='name of the container') +create_parser.add_argument('arg', nargs='+', help='command and its arguments') +create_parser.add_argument('--tty', '-t', default=False, action='store_true', help='stdio will be attached to a pseudo-terminal') +create_parser.add_argument('--user', '-u', metavar='USER[:GROUP]', help='user/group to run the command under (default: root)') + +start_parser = subparsers.add_parser('shell', help='run a shell inside a container', description='Run a shell inside a container') +start_parser.add_argument('name', help='name of the container') + start_parser = subparsers.add_parser('start', help='start a container', description='Start a container') start_parser.add_argument('name', help='name of the container') @@ -270,10 +320,15 @@ stop_parser = subparsers.add_parser('stop', help='stop a container', description stop_parser.add_argument('name', help='name of the container') args = parser.parse_args() +verbose = args.verbose actions = { 'create': cmd_create, + 'disable': cmd_disable, + 'enable': cmd_enable, + 'exec': cmd_exec, 'init': cmd_init, + 'shell': cmd_shell, 'start': cmd_start, 'status': cmd_status, 'stop': cmd_stop, diff --git a/shipcat/config.py b/shipcat/config.py index 2d34571..94be7ec 100644 --- a/shipcat/config.py +++ b/shipcat/config.py @@ -100,5 +100,5 @@ class ContainerConfig: wu.raise_error(f'Unknown group {name}') self.allowed_groups.add(grp.gr_gid) - self.pid_file = f'/run/{self.container}.pid' + self.pid_file = f'/run/shc/{self.container}.pid' self.user_name = self.container -- GitLab