Compare commits
8 Commits
84aaf451f7
...
master
Author | SHA1 | Date | |
---|---|---|---|
911ffe1c92 | |||
f43ac055c2 | |||
2e16523810 | |||
d7052998c8 | |||
488dedb74e | |||
9340dbe720 | |||
556b9d6b75 | |||
6c48e92378 |
252
otherworld
252
otherworld
@@ -80,8 +80,9 @@ def docker_create_user (container, user, uid=None):
|
||||
def docker_start (container):
|
||||
call(["docker", "start", container])
|
||||
|
||||
def docker_exec (container, command, user, env={}, work_dir=None):
|
||||
call(["docker", "exec", "--user", user, "-ti"] + \
|
||||
def docker_exec (container, command, user, env={}, tty=True, work_dir=None):
|
||||
call(["docker", "exec", "--user", user] + \
|
||||
(["-ti" if tty else "-i"]) + \
|
||||
(["--workdir", work_dir] if work_dir else []) + \
|
||||
list(chain.from_iterable([["--env", f"{kv[0]}={kv[1]}"] for kv in env.items()])) + \
|
||||
[container] + command)
|
||||
@@ -92,6 +93,9 @@ def docker_commit (container, image_name):
|
||||
def docker_rm (container):
|
||||
call(["docker", "rm", "-f", container])
|
||||
|
||||
def docker_restart (container):
|
||||
call(["docker", "restart", container])
|
||||
|
||||
def docker_rmi (container):
|
||||
call(["docker", "rmi", "-f", container])
|
||||
|
||||
@@ -131,10 +135,72 @@ def expand_user_volumes (volumes):
|
||||
|
||||
return mappings
|
||||
|
||||
def find_config_files (config_name):
|
||||
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):
|
||||
config_files = []
|
||||
directory = os.path.abspath(os.getcwd())
|
||||
while True:
|
||||
for config_name in config_names:
|
||||
config_file = os.path.join(directory, config_name)
|
||||
if os.path.exists(config_file):
|
||||
config_files.append(config_file)
|
||||
@@ -157,86 +223,69 @@ def load_config_files (namespace, config_files):
|
||||
exec(config_code.read(), {}, namespace)
|
||||
return dict([item for item in namespace.items() if item[0] in config_keys])
|
||||
|
||||
def init_command_as_list (command):
|
||||
if isinstance(command, str):
|
||||
command = ["sh", "-c", command]
|
||||
return command
|
||||
|
||||
# parse options and command from command line
|
||||
(command_line_options, command) = parse_command_line(sys.argv[1:])
|
||||
actions = command_line_options['actions']
|
||||
|
||||
quiet = command_line_options.get("quiet", False)
|
||||
def log (message, *args, **kwargs):
|
||||
if quiet:
|
||||
return
|
||||
print(">> {}".format(message.format(*args, **kwargs)))
|
||||
|
||||
tty = sys.stdout.isatty()
|
||||
|
||||
# default config
|
||||
user = os.environ["USER"]
|
||||
uid = int(check_output(["id", "-u"]).strip())
|
||||
image_name = os.environ.get("OW_IMAGE", None)
|
||||
container_name = os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}")
|
||||
build_path = None
|
||||
|
||||
command = sys.argv[1:]
|
||||
command_user = user
|
||||
user_volumes = USER_VOLUMES
|
||||
pull = False
|
||||
|
||||
actions = []
|
||||
|
||||
command_env = {}
|
||||
command_workdir = None
|
||||
|
||||
quiet = False
|
||||
|
||||
# load config from files
|
||||
config = load_config_files({
|
||||
config = {
|
||||
"command": command,
|
||||
"user": user,
|
||||
"uid": uid,
|
||||
"command_user": command_user,
|
||||
"image_name": image_name,
|
||||
"container_name": container_name,
|
||||
"build_path": build_path,
|
||||
"command_workdir": command_workdir,
|
||||
"user_volumes": user_volumes,
|
||||
"pull": pull,
|
||||
"command_env": command_env,
|
||||
"cwd": os.getcwd()
|
||||
}, find_config_files(OTHERWORLD_CONFIG))
|
||||
locals().update(config)
|
||||
"uid": int(check_output(["id", "-u"]).strip()),
|
||||
"command_user": user,
|
||||
"image_name": os.environ.get("OW_IMAGE", None),
|
||||
"container_name": command_line_options.get("container_name", os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}")),
|
||||
"build_path": None,
|
||||
"command_workdir": None,
|
||||
"user_volumes": USER_VOLUMES,
|
||||
"pull": False,
|
||||
"command_env": {},
|
||||
"cwd": os.getcwd(),
|
||||
"tty": sys.stdout.isatty(),
|
||||
"log": log,
|
||||
"root_init_command": [],
|
||||
"root_init_commmands": [],
|
||||
"user_init_command": [],
|
||||
"user_init_commands": [],
|
||||
"docker_create_options": []
|
||||
}
|
||||
|
||||
while len(command) > 0:
|
||||
arg = command[0]
|
||||
if arg == "--quiet":
|
||||
command = command[1:]
|
||||
quiet = True
|
||||
elif arg == "--rm":
|
||||
actions.append("rm")
|
||||
command = command[1:]
|
||||
elif arg == "--rmi":
|
||||
actions.append("rmi")
|
||||
command = command[1:]
|
||||
elif arg == "--commit":
|
||||
actions.append("commit")
|
||||
command = command[1:]
|
||||
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
|
||||
# load config from files
|
||||
config_files = find_config_files([
|
||||
OTHERWORLD_CONFIG,
|
||||
"{}{}".format(config['container_name'], OTHERWORLD_CONFIG)
|
||||
])
|
||||
|
||||
for config_file in config_files:
|
||||
log("Loading config file {}", config_file)
|
||||
|
||||
config = load_config_files(config, config_files)
|
||||
|
||||
# apply config from command line
|
||||
for key, value in command_line_options.items():
|
||||
if key == "user_volumes":
|
||||
config['user_volumes'] = config['user_volumes'] + value
|
||||
elif key == "command_env":
|
||||
config['command_env'].update(value)
|
||||
else:
|
||||
break
|
||||
config[key] = value
|
||||
|
||||
# update local variables (FIXME: rewrite to avoid doing this)
|
||||
locals().update(config)
|
||||
|
||||
if command_workdir:
|
||||
user_volumes.append(command_workdir)
|
||||
@@ -245,19 +294,20 @@ if command_workdir:
|
||||
if actions:
|
||||
if "commit" in actions:
|
||||
target_image_name = get_generated_image_name(container_name)
|
||||
if not quiet:
|
||||
print(f">> Committing container: {container_name} to image: {target_image_name}")
|
||||
log("Committing container: {} to image: {}", 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 not quiet:
|
||||
print(f">> Removing container: {container_name}")
|
||||
log("Removing container: {}", container_name)
|
||||
docker_rm(container_name)
|
||||
|
||||
if "rmi" in actions:
|
||||
target_image_name = get_generated_image_name(container_name)
|
||||
if not quiet:
|
||||
print(f">> Removing image: {target_image_name}")
|
||||
log("Removing image: {}", target_image_name)
|
||||
docker_rmi(target_image_name)
|
||||
|
||||
if not command:
|
||||
@@ -278,39 +328,45 @@ except Exception:
|
||||
image_name = get_generated_image_name(container_name)
|
||||
try:
|
||||
docker_inspect(image_name)
|
||||
if not quiet:
|
||||
print(f">> Using default otherworld image {image_name}")
|
||||
log("Using default otherworld image {}", image_name)
|
||||
except Exception:
|
||||
if not quiet:
|
||||
print(f">> Default otherworld image {image_name} not found, falling back to {DEFAULT_IMAGE_NAME}")
|
||||
log("Default otherworld image {} not found, falling back to {}", image_name, DEFAULT_IMAGE_NAME)
|
||||
image_name = DEFAULT_IMAGE_NAME
|
||||
|
||||
if pull:
|
||||
docker_pull(image_name)
|
||||
|
||||
if not quiet:
|
||||
print(f">> Creating container: {container_name} (using image: {image_name})")
|
||||
log("Creating container: {} (using image: {})", container_name, image_name)
|
||||
docker_create(
|
||||
image_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 }
|
||||
)
|
||||
container = docker_inspect(container_name)[0]
|
||||
|
||||
if not container["State"]["Running"]:
|
||||
if not quiet:
|
||||
print(f">> Starting container: {container_name}")
|
||||
log("Starting container: {}", container_name)
|
||||
docker_start(container_name)
|
||||
container = docker_inspect(container_name)[0]
|
||||
|
||||
try:
|
||||
docker_get_user(container_name, user)
|
||||
except Exception:
|
||||
if not quiet:
|
||||
print(f">> Creating container user: {user}")
|
||||
log("Creating container user: {}", user)
|
||||
docker_create_user(container_name, user, uid)
|
||||
|
||||
if not quiet:
|
||||
print(f">> Welcome to {container_name} (IP {container['NetworkSettings']['IPAddress']})")
|
||||
docker_exec(container_name, command, command_user, command_env, command_workdir)
|
||||
if config['root_init_command']:
|
||||
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)
|
||||
|
Reference in New Issue
Block a user