2020-02-06 19:00:41 +01:00
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import argparse
import os
2020-02-11 16:15:06 +01:00
import shlex
2020-03-19 10:48:24 +01:00
import sys
2020-02-06 19:00:41 +01:00
2020-02-11 16:15:06 +01:00
from spoc import repo_local
2020-03-12 20:56:52 +01:00
from spoc.config import VOLUMES_DIR
2020-04-26 16:46:09 +02:00
from spoc.container import Container
2020-02-06 19:00:41 +01:00
from spoc.image import Image
2020-02-11 16:15:06 +01:00
def listing(state):
2020-03-26 20:29:27 +01:00
# Lits containers in particular state
2020-02-11 16:15:06 +01:00
if state == 'all':
containers = repo_local.get_containers().keys()
elif state == 'running':
2020-04-26 16:46:09 +02:00
containers = [c for c in repo_local.get_containers() if Container(c).is_running()]
2020-02-11 16:15:06 +01:00
elif state == 'stopped':
2020-04-26 16:46:09 +02:00
containers = [c for c in repo_local.get_containers() if Container(c).is_stopped()]
2020-02-11 16:15:06 +01:00
for container in containers:
print(container)
2020-02-06 19:00:41 +01:00
def modify_depend(container, depend):
2020-03-26 20:29:27 +01:00
# Change container dependencies
2020-02-06 19:00:41 +01:00
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):
2020-03-26 20:29:27 +01:00
# Change container mount points
2020-02-06 19:00:41 +01:00
volume,mountpoint = mount.split(':', 1)
if mountpoint:
2020-02-22 18:06:59 +01:00
container.mounts[volume] = mountpoint
2020-02-06 19:00:41 +01:00
else:
try:
del container.mounts[volume]
except KeyError:
pass
def modify_env(container, env):
2020-03-26 20:29:27 +01:00
# Change container environment values
2020-02-06 19:00:41 +01:00
key,value = env.split('=', 1)
if value:
container.env[key] = value
else:
try:
del container.env[key]
except KeyError:
pass
2020-03-26 19:30:37 +01:00
def modify_container(container, depends, mounts, envs, uid, gid, cmd, cwd, ready, halt):
2020-03-26 20:29:27 +01:00
# Change container definition
2020-02-06 19:00:41 +01:00
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()
2020-03-26 19:30:37 +01:00
for member in ('uid', 'gid', 'cmd', 'cwd', 'ready', 'halt'):
2020-02-06 19:00:41 +01:00
value = args[member]
if value:
setattr(container, member, value)
2020-03-26 19:30:37 +01:00
def create(container_name, image_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt):
2020-03-26 20:29:27 +01:00
# Create container based on image definition and extra fields
2020-02-07 15:12:27 +01:00
container = Container(container_name, False)
2020-02-18 23:37:43 +01:00
container.set_definition(Image(image_name).get_definition())
2020-03-26 19:30:37 +01:00
modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt)
2020-02-06 19:00:41 +01:00
container.create()
2020-03-26 19:30:37 +01:00
def modify(container_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt):
2020-02-07 19:48:43 +01:00
# Change configuration of an existing container
2020-02-07 09:01:47 +01:00
container = Container(container_name)
2020-03-26 19:30:37 +01:00
modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt)
2020-02-06 19:00:41 +01:00
container.create()
def destroy(container_name):
2020-02-07 19:48:43 +01:00
# Remove container and its directory
2020-04-26 18:41:42 +02:00
container = Container(container_name, False)
if container.is_running():
container.stop()
container.destroy()
2020-02-06 19:00:41 +01:00
2020-04-05 20:34:40 +02:00
def start(container_name, command):
2020-02-07 19:48:43 +01:00
# Start the container using init values from its definition
2020-04-05 20:34:40 +02:00
Container(container_name).start(command)
2020-02-06 19:00:41 +01:00
def stop(container_name):
2020-02-07 19:48:43 +01:00
# Stop the container using halt signal from its definition
Container(container_name).stop()
2020-02-06 19:00:41 +01:00
def status(container_name):
2020-02-07 19:48:43 +01:00
# Prints current running status of the container
print(Container(container_name).get_state())
2020-02-06 19:00:41 +01:00
2020-02-07 21:48:53 +01:00
def execute(container_name, command, uid, gid):
2020-02-07 19:48:43 +01:00
# Execute a command in container's namespace
2020-03-19 10:48:24 +01:00
result = Container(container_name).execute(command, uid, gid)
# Set returncode to that of the command
sys.exit(result.returncode)
2020-02-06 19:00:41 +01:00
parser = argparse.ArgumentParser(description='SPOC container manager')
parser.set_defaults(action=None)
subparsers = parser.add_subparsers()
2020-02-11 16:15:06 +01:00
parser_list = subparsers.add_parser('list')
2020-02-18 12:33:54 +01:00
parser_list.set_defaults(action=listing)
2020-05-24 08:55:02 +02:00
parser_list.add_argument('type', choices=('all', 'running', 'stopped'), default='all', const='all', nargs='?', help='Selected container criteria')
2020-02-11 16:15:06 +01:00
2020-02-06 19:00:41 +01:00
parser_create = subparsers.add_parser('create')
2020-02-18 12:33:54 +01:00
parser_create.set_defaults(action=create)
2020-02-06 19:00:41 +01:00
parser_create.add_argument('-d', '--depends', action='append', default=[], help='Add another container as a start dependency')
2020-02-22 18:06:59 +01:00
parser_create.add_argument('-m', '--mount', action='append', default=[], help='Add mount to the container - format volume:mountpoint[:file]')
2020-02-06 19:00:41 +01:00
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')
2020-05-24 08:55:02 +02:00
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')
2020-02-06 19:00:41 +01:00
parser_modify = subparsers.add_parser('modify')
2020-02-18 12:33:54 +01:00
parser_modify.set_defaults(action=modify)
2020-02-06 19:00:41 +01:00
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')
2020-05-24 08:55:02 +02:00
parser_modify.add_argument('container', help='Name of the container to modify')
2020-02-06 19:00:41 +01:00
parser_destroy = subparsers.add_parser('destroy')
2020-02-18 12:33:54 +01:00
parser_destroy.set_defaults(action=destroy)
2020-05-24 08:55:02 +02:00
parser_destroy.add_argument('container', help='Name of the container to destroy')
2020-02-06 19:00:41 +01:00
parser_start = subparsers.add_parser('start')
2020-02-18 12:33:54 +01:00
parser_start.set_defaults(action=start)
2020-05-24 08:55:02 +02:00
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')
2020-02-06 19:00:41 +01:00
2020-02-07 19:48:43 +01:00
parser_stop = subparsers.add_parser('stop')
2020-02-18 12:33:54 +01:00
parser_stop.set_defaults(action=stop)
2020-05-24 08:55:02 +02:00
parser_stop.add_argument('container', help='Name of the container to stop')
2020-02-06 19:00:41 +01:00
2020-02-07 19:48:43 +01:00
parser_status = subparsers.add_parser('status')
2020-02-18 12:33:54 +01:00
parser_status.set_defaults(action=status)
2020-05-24 08:55:02 +02:00
parser_status.add_argument('container', help='Name of the container to check')
2020-02-06 19:00:41 +01:00
parser_exec = subparsers.add_parser('exec')
2020-02-18 12:33:54 +01:00
parser_exec.set_defaults(action=execute)
2020-02-07 21:48:53 +01:00
parser_exec.add_argument('-u', '--uid', help='Sets the command UID')
parser_exec.add_argument('-g', '--gid', help='Sets the command GID')
2020-05-24 08:55:02 +02:00
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')
2020-02-06 19:00:41 +01:00
args = parser.parse_args()
2020-02-18 12:33:54 +01:00
if args.action is listing:
2020-02-11 16:15:06 +01:00
listing(args.type)
2020-02-18 12:33:54 +01:00
elif args.action is create:
2020-03-26 19:30:37 +01:00
create(args.container, args.image, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig)
2020-02-18 12:33:54 +01:00
elif args.action is modify:
2020-03-26 19:30:37 +01:00
modify(args.container, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig)
2020-02-18 12:33:54 +01:00
elif args.action is destroy:
2020-02-06 19:00:41 +01:00
destroy(args.container)
2020-02-18 12:33:54 +01:00
elif args.action is start:
2020-04-05 20:34:40 +02:00
start(args.container, args.command)
2020-02-18 12:33:54 +01:00
elif args.action is stop:
2020-02-06 19:00:41 +01:00
stop(args.container)
2020-02-18 12:33:54 +01:00
elif args.action is status:
2020-02-06 19:00:41 +01:00
status(args.container)
2020-02-18 12:33:54 +01:00
elif args.action is execute:
2020-02-07 21:48:53 +01:00
execute(args.container, args.command, args.uid, args.gid)
2020-02-06 19:00:41 +01:00
else:
parser.print_usage()