Compare commits

..

6 Commits

View File

@@ -93,6 +93,9 @@ def docker_commit (container, image_name):
def docker_rm (container): def docker_rm (container):
call(["docker", "rm", "-f", container]) call(["docker", "rm", "-f", container])
def docker_restart (container):
call(["docker", "restart", container])
def docker_rmi (container): def docker_rmi (container):
call(["docker", "rmi", "-f", container]) call(["docker", "rmi", "-f", container])
@@ -132,6 +135,67 @@ def expand_user_volumes (volumes):
return mappings return mappings
def parse_command_line (command, config=None):
if config is None:
config = {
"actions": [],
"user_volumes": [],
"command_env": {}
}
while len(command) > 0:
arg = command[0]
if arg == "--quiet":
command = command[1:]
config['quiet'] = True
elif arg == "--notty":
command = command[1:]
config['tty'] = False
elif arg == "--rm":
config['actions'].append("rm")
command = command[1:]
elif arg == "--restart":
config['actions'].append("restart")
command = command[1:]
elif arg == "--rmi":
config['actions'].append("rmi")
command = command[1:]
elif arg == "--commit":
config['actions'].append("commit")
command = command[1:]
elif arg == "--sudo":
config['command_user'] = "root"
command = command[1:]
elif arg.startswith("--container="):
config['container_name'] = arg[len("--container="):]
command = command[1:]
elif arg.startswith("--image="):
config['image_name'] = arg[len("--image="):]
command = command[1:]
elif arg.startswith("--build="):
config['build_path'] = arg[len("--build="):]
command = command[1:]
elif arg.startswith("--volume="):
config['user_volumes'].append(arg[len("--volume="):])
command = command[1:]
elif arg.startswith("--env="):
env_pair = arg[len("--env="):]
(key, value) = env_pair.split("=", 1)
config['command_env'][key] = value
command = command[1:]
elif arg == "--cd":
config['command_workdir'] = os.getcwd()
command = command[1:]
elif arg.startswith("--cd="):
config['command_workdir'] = arg[len("--cd="):]
command = command[1:]
elif arg == "--pull":
command = command[1:]
config['pull'] = True
else:
break
return (config, command)
def find_config_files (config_names): def find_config_files (config_names):
config_files = [] config_files = []
directory = os.path.abspath(os.getcwd()) directory = os.path.abspath(os.getcwd())
@@ -159,91 +223,69 @@ def load_config_files (namespace, config_files):
exec(config_code.read(), {}, namespace) exec(config_code.read(), {}, namespace)
return dict([item for item in namespace.items() if item[0] in config_keys]) return dict([item for item in namespace.items() if item[0] in config_keys])
user = os.environ["USER"] def init_command_as_list (command):
uid = int(check_output(["id", "-u"]).strip()) if isinstance(command, str):
image_name = os.environ.get("OW_IMAGE", None) command = ["sh", "-c", command]
container_name = os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}") return command
build_path = None
command = sys.argv[1:] # parse options and command from command line
command_user = user (command_line_options, command) = parse_command_line(sys.argv[1:])
user_volumes = USER_VOLUMES actions = command_line_options['actions']
pull = False
actions = [] quiet = command_line_options.get("quiet", False)
def log (message, *args, **kwargs):
if quiet:
return
print(">> {}".format(message.format(*args, **kwargs)))
command_env = {}
command_workdir = None
quiet = False
tty = sys.stdout.isatty() tty = sys.stdout.isatty()
# load config from files # default config
config = load_config_files({ user = os.environ["USER"]
config = {
"command": command, "command": command,
"user": user, "user": user,
"uid": uid, "uid": int(check_output(["id", "-u"]).strip()),
"command_user": command_user, "command_user": user,
"image_name": image_name, "image_name": os.environ.get("OW_IMAGE", None),
"container_name": container_name, "container_name": command_line_options.get("container_name", os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}")),
"build_path": build_path, "build_path": None,
"command_workdir": command_workdir, "command_workdir": None,
"user_volumes": user_volumes, "user_volumes": USER_VOLUMES,
"pull": pull, "pull": False,
"command_env": command_env, "command_env": {},
"cwd": os.getcwd(), "cwd": os.getcwd(),
"tty": tty "tty": sys.stdout.isatty(),
}, find_config_files([OTHERWORLD_CONFIG, "{}{}".format(container_name, OTHERWORLD_CONFIG)])) "log": log,
locals().update(config) "root_init_command": [],
"root_init_commmands": [],
"user_init_command": [],
"user_init_commands": [],
"docker_create_options": []
}
while len(command) > 0: # load config from files
arg = command[0] config_files = find_config_files([
if arg == "--quiet": OTHERWORLD_CONFIG,
command = command[1:] "{}{}".format(config['container_name'], OTHERWORLD_CONFIG)
quiet = True ])
elif arg == "--notty":
command = command[1:] for config_file in config_files:
tty = False log("Loading config file {}", config_file)
elif arg == "--rm":
actions.append("rm") config = load_config_files(config, config_files)
command = command[1:]
elif arg == "--rmi": # apply config from command line
actions.append("rmi") for key, value in command_line_options.items():
command = command[1:] if key == "user_volumes":
elif arg == "--commit": config['user_volumes'] = config['user_volumes'] + value
actions.append("commit") elif key == "command_env":
command = command[1:] config['command_env'].update(value)
elif arg == "--sudo":
command_user = "root"
command = command[1:]
elif arg.startswith("--container="):
container_name = arg[len("--container="):]
command = command[1:]
elif arg.startswith("--image="):
image_name = arg[len("--image="):]
command = command[1:]
elif arg.startswith("--build="):
build_path = arg[len("--build="):]
command = command[1:]
elif arg.startswith("--volume="):
user_volumes.append(arg[len("--volume="):])
command = command[1:]
elif arg.startswith("--env="):
env_pair = arg[len("--env="):]
(key, value) = env_pair.split("=", 1)
command_env[key] = value
command = command[1:]
elif arg == "--cd":
command_workdir = os.getcwd()
command = command[1:]
elif arg.startswith("--cd="):
command_workdir = arg[len("--cd="):]
command = command[1:]
elif arg == "--pull":
command = command[1:]
pull = True
else: else:
break config[key] = value
# update local variables (FIXME: rewrite to avoid doing this)
locals().update(config)
if command_workdir: if command_workdir:
user_volumes.append(command_workdir) user_volumes.append(command_workdir)
@@ -252,19 +294,20 @@ if command_workdir:
if actions: if actions:
if "commit" in actions: if "commit" in actions:
target_image_name = get_generated_image_name(container_name) target_image_name = get_generated_image_name(container_name)
if not quiet: log("Committing container: {} to image: {}", container_name, target_image_name)
print(f">> Committing container: {container_name} to image: {target_image_name}")
docker_commit(container_name, target_image_name) docker_commit(container_name, target_image_name)
if "restart" in actions:
log("Restarting container: {}", container_name)
docker_restart(container_name)
if "rm" in actions: if "rm" in actions:
if not quiet: log("Removing container: {}", container_name)
print(f">> Removing container: {container_name}")
docker_rm(container_name) docker_rm(container_name)
if "rmi" in actions: if "rmi" in actions:
target_image_name = get_generated_image_name(container_name) target_image_name = get_generated_image_name(container_name)
if not quiet: log("Removing image: {}", target_image_name)
print(f">> Removing image: {target_image_name}")
docker_rmi(target_image_name) docker_rmi(target_image_name)
if not command: if not command:
@@ -285,39 +328,45 @@ except Exception:
image_name = get_generated_image_name(container_name) image_name = get_generated_image_name(container_name)
try: try:
docker_inspect(image_name) docker_inspect(image_name)
if not quiet: log("Using default otherworld image {}", image_name)
print(f">> Using default otherworld image {image_name}")
except Exception: except Exception:
if not quiet: log("Default otherworld image {} not found, falling back to {}", image_name, DEFAULT_IMAGE_NAME)
print(f">> Default otherworld image {image_name} not found, falling back to {DEFAULT_IMAGE_NAME}")
image_name = DEFAULT_IMAGE_NAME image_name = DEFAULT_IMAGE_NAME
if pull: if pull:
docker_pull(image_name) docker_pull(image_name)
if not quiet: log("Creating container: {} (using image: {})", container_name, image_name)
print(f">> Creating container: {container_name} (using image: {image_name})")
docker_create( docker_create(
image_name, image_name,
container_name, container_name,
DOCKER_CREATE_OPTIONS + create_x11_mapping() + expand_user_volumes(user_volumes), DOCKER_CREATE_OPTIONS + config.get("docker_create_options", []) + create_x11_mapping() + expand_user_volumes(user_volumes),
BACKGROUND_COMMAND, { OTHERWORLD_LABEL: user } BACKGROUND_COMMAND, { OTHERWORLD_LABEL: user }
) )
container = docker_inspect(container_name)[0] container = docker_inspect(container_name)[0]
if not container["State"]["Running"]: if not container["State"]["Running"]:
if not quiet: log("Starting container: {}", container_name)
print(f">> Starting container: {container_name}")
docker_start(container_name) docker_start(container_name)
container = docker_inspect(container_name)[0] container = docker_inspect(container_name)[0]
try: try:
docker_get_user(container_name, user) docker_get_user(container_name, user)
except Exception: except Exception:
if not quiet: log("Creating container user: {}", user)
print(f">> Creating container user: {user}")
docker_create_user(container_name, user, uid) docker_create_user(container_name, user, uid)
if not quiet: if config['root_init_command']:
print(f">> Welcome to {container_name} (IP {container['NetworkSettings']['IPAddress']})") config['root_init_commands'].append(config['root_init_command'])
for command in config['root_init_commands']:
docker_exec(container_name, init_command_as_list(command), "root", command_env, tty, "/home/{}".format(command_user))
if config['user_init_command']:
config['user_init_commands'].append(config['user_init_command'])
for command in config['user_init_commands']:
docker_exec(container_name, init_command_as_list(command), command_user, command_env, tty, "/home/{}".format(command_user))
log("Welcome to {} (IP {})", container_name, container['NetworkSettings']['IPAddress'])
docker_exec(container_name, command, command_user, command_env, tty, command_workdir) docker_exec(container_name, command, command_user, command_env, tty, command_workdir)