#!/usr/bin/python3 # -*- coding: utf-8 -*- import argparse import os import shlex import sys from spoc import repo_local from spoc.config import VOLUMES_DIR from spoc.container import Container from spoc.image import Image def listing(state): # Lits containers in particular state if state == 'all': containers = repo_local.get_containers().keys() elif state == 'running': containers = [c for c in repo_local.get_containers() if Container(c).is_running()] elif state == 'stopped': containers = [c for c in repo_local.get_containers() if Container(c).is_stopped()] for container in containers: print(container) def modify_depend(container, depend): # Change container dependencies if depend.startswith('!'): try: container.depends.remove(depend[1:]) except KeyError: pass else: # Add the dependency and remove duplicates container.depends.append(depend) container.depends = list(set(container.depends)) def modify_mount(container, mount): # Change container mount points volume,mountpoint = mount.split(':', 1) if mountpoint: container.mounts[volume] = mountpoint else: try: del container.mounts[volume] except KeyError: pass def modify_env(container, env): # Change container environment values key,value = env.split('=', 1) if value: container.env[key] = value else: try: del container.env[key] except KeyError: pass def modify_container(container, depends, mounts, envs, uid, gid, cmd, cwd, ready, halt): # Change container definition for depend in depends: modify_depend(container, depend) for mount in mounts: modify_mount(container, mount) for env in envs: modify_env(container, env) args = locals() for member in ('uid', 'gid', 'cmd', 'cwd', 'ready', 'halt'): value = args[member] if value: setattr(container, member, value) def create(container_name, image_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt): # Create container based on image definition and extra 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) container.create() def modify(container_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt): # Change configuration of an existing container container = Container(container_name) modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt) container.create() def destroy(container_name): # Remove container and its directory container = Container(container_name, False) if container.is_running(): container.stop() container.destroy() def start(container_name, command): # Start the container using init values from its definition Container(container_name).start(command) def stop(container_name): # Stop the container using halt signal from its definition Container(container_name).stop() def status(container_name): # Prints current running status of the container print(Container(container_name).get_state().value) def execute(container_name, command, uid, gid): # Execute a command in container's namespace result = Container(container_name).execute(command, uid, gid) # Set returncode to that of the command sys.exit(result.returncode) parser = argparse.ArgumentParser(description='SPOC container manager') parser.set_defaults(action=None) subparsers = parser.add_subparsers() parser_list = subparsers.add_parser('list') parser_list.set_defaults(action=listing) parser_list.add_argument('type', choices=('all', 'running', 'stopped'), default='all', const='all', nargs='?', help='Selected container criteria') parser_create = subparsers.add_parser('create') parser_create.set_defaults(action=create) parser_create.add_argument('-d', '--depends', action='append', default=[], help='Add another container as a start dependency') parser_create.add_argument('-m', '--mount', action='append', default=[], help='Add mount to the container - format volume:mountpoint[:file]') parser_create.add_argument('-e', '--env', action='append', default=[], help='Add environment variable for the container - format KEY=value') parser_create.add_argument('-u', '--uid', help='Sets the container init UID') parser_create.add_argument('-g', '--gid', help='Sets the container init GID') parser_create.add_argument('-c', '--cmd', help='Sets the container init command') parser_create.add_argument('-w', '--workdir', help='Sets the container init working directory') parser_create.add_argument('-r', '--ready', help='Sets the container ready command') parser_create.add_argument('-s', '--stopsig', help='Sets the signal to be sent to init on container shutdown') parser_create.add_argument('container', help='Name of the container to create') parser_create.add_argument('image', help='Name of the image of which the container should be based') parser_modify = subparsers.add_parser('modify') parser_modify.set_defaults(action=modify) parser_modify.add_argument('-d', '--depends', action='append', default=[], help='Add another container as a start dependency - prepend the name with ! to remove the dependency') parser_modify.add_argument('-m', '--mount', action='append', default=[], help='Add mount to the container - format volume:mountpoint - specify empty mountpoint to remove the mount') parser_modify.add_argument('-e', '--env', action='append', default=[], help='Add environment variable for the container - format KEY=value - specify empty value to remove the env') parser_modify.add_argument('-u', '--uid', help='Sets the container init UID') parser_modify.add_argument('-g', '--gid', help='Sets the container init GID') parser_modify.add_argument('-c', '--cmd', help='Sets the container init command') parser_modify.add_argument('-w', '--workdir', help='Sets the container init working directory') parser_modify.add_argument('-r', '--ready', help='Sets the container ready command') parser_modify.add_argument('-s', '--stopsig', help='Sets the signal to be sent to init on container shutdown') parser_modify.add_argument('container', help='Name of the container to modify') parser_destroy = subparsers.add_parser('destroy') parser_destroy.set_defaults(action=destroy) parser_destroy.add_argument('container', help='Name of the container to destroy') parser_start = subparsers.add_parser('start') parser_start.set_defaults(action=start) parser_start.add_argument('container', help='Name of the container to start') parser_start.add_argument('command', nargs=argparse.REMAINDER, help='Command to be run instead of the default init command') parser_stop = subparsers.add_parser('stop') parser_stop.set_defaults(action=stop) parser_stop.add_argument('container', help='Name of the container to stop') parser_status = subparsers.add_parser('status') parser_status.set_defaults(action=status) parser_status.add_argument('container', help='Name of the container to check') parser_exec = subparsers.add_parser('exec') parser_exec.set_defaults(action=execute) parser_exec.add_argument('-u', '--uid', help='Sets the command UID') parser_exec.add_argument('-g', '--gid', help='Sets the command GID') parser_exec.add_argument('container', help='Name of the container in which to run the command') parser_exec.add_argument('command', nargs=argparse.REMAINDER, help='The command to be run') args = parser.parse_args() if args.action is listing: listing(args.type) elif args.action is create: create(args.container, args.image, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig) elif args.action is modify: modify(args.container, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig) elif args.action is destroy: destroy(args.container) elif args.action is start: start(args.container, args.command) elif args.action is stop: stop(args.container) elif args.action is status: status(args.container) elif args.action is execute: execute(args.container, args.command, args.uid, args.gid) else: parser.print_usage()