initial commit

This commit is contained in:
Adrian Kuschelyagi Malacoda 2020-03-27 00:17:20 -05:00
commit e7552a277a
2 changed files with 149 additions and 0 deletions

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# Otherworld
Otherworld creates a persistent Docker container running your choice of GNU/Linux distribution, with a matching user account (no need to run everything as root) and with x11 and PulseAudio mappings. The container is created the first time you run otherworld and sticks around until you dispose of it manually.
## Usage
### Run command as user
`otherworld <command> <arguments>`
### Run command as root
`otherworld --sudo <command> <arguments>`
### Run command without printing anything else
`otherworld --quiet <command> <arguments>`
### Remove the container
`otherworld --rm`
## Environment variables
### OW_IMAGE
Image to create the container with (default: `debian:stable`)
### OW_CONTAINER
Name to assign to container (default: `overworld_$USER`)
## License
[GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html) or later

124
otherworld Executable file
View File

@ -0,0 +1,124 @@
#!/usr/bin/env python3
from subprocess import call, check_output
from time import sleep
import os
import sys
import json
CONTAINER_NAME = "otherworld"
IMAGE_NAME = "debian:stable"
def create_x11_mapping ():
home = os.environ["HOME"]
xdg_dir = os.environ["XDG_RUNTIME_DIR"]
display = os.environ["DISPLAY"]
inner_user = home
Xauthority = os.environ["XAUTHORITY"]
return ["-e", f"DISPLAY={display}",
"-v", "/tmp/.X11-unix/:/tmp/.X11-unix",
"-v", "/dev/snd:/dev/snd",
"-v", f"{xdg_dir}/pulse:/run/pulse:ro",
"-v", f"{home}/.gtkrc-2.0:{inner_user}/.gtkrc-2.0",
"-v", f"{home}/.config/gtk-3.0/:{inner_user}/.config/gtk-3.0",
"-v", f"{home}/.guix-profile/share/fonts/truetype:/user/share/fonts/truetype-guix",
"-v", f"{home}/.guix-profile/share/fonts/opentype:/usr/share/fonts/opentype-guix",
"-v", f"{Xauthority}:{inner_user}/.Xauthority",
"-v", f"{home}/otherworld:{inner_user}/otherworld",
"-w", inner_user,
"--shm-size", "2g",
"--privileged"]
DOCKER_CREATE_OPTIONS = ["-t"] + create_x11_mapping()
BACKGROUND_COMMAND = None
DEFAULT_COMMAND = ["bash"]
def docker_inspect (container):
return json.loads(check_output(["docker", "inspect", container]))
def docker_create (image, container, options, command):
docker_command = ["docker", "create", "--name", container] + options + [image]
if command:
docker_command = docker_command + command
call(docker_command)
def docker_get_user (container, user):
return check_output(["docker", "exec", container, "groups", user])
def docker_create_user (container, user):
call(["docker", "exec", container, "adduser", user, "--gecos", ",,,", "--disabled-password"])
call(["docker", "exec", container, "chown", user, f"/home/{user}"])
def docker_start (container):
call(["docker", "start", container])
def docker_exec (container, command, user):
call(["docker", "exec", "--user", user, "-ti", container] + command)
def docker_rm (container):
call(["docker", "rm", "-f", container])
user = os.environ["USER"]
image_name = os.environ.get("OW_IMAGE", IMAGE_NAME)
container_name = os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}")
command = sys.argv[1:]
command_user = user
quiet = False
while len(command) > 0:
arg = command[0]
if arg == "--quiet":
command = command[1:]
quiet = True
elif arg == "--rm":
if not quiet:
print(f">> Removing container: {container_name}")
docker_rm(container_name)
sys.exit(0)
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:]
else:
break
if len(command) == 0:
command = DEFAULT_COMMAND
container = None
try:
container = docker_inspect(container_name)[0]
except Exception:
if not quiet:
print(f">> Creating container: {container_name} (using image: {image_name})")
docker_create(
image_name,
container_name,
DOCKER_CREATE_OPTIONS,
BACKGROUND_COMMAND
)
container = docker_inspect(container_name)[0]
if not container["State"]["Running"]:
if not quiet:
print(f">> 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}")
docker_create_user(container_name, user)
if not quiet:
print(f">> Welcome to {container_name} (IP {container['NetworkSettings']['IPAddress']})")
docker_exec(container_name, command, command_user)