From 7ea6f7d329001db4610561d10460123c5464dc8e Mon Sep 17 00:00:00 2001 From: "Kevin C. Wells" Date: Tue, 7 Nov 2017 11:14:15 -0800 Subject: [PATCH] Create clr-sdk Docker Container. Docker container for running Clear Linux developer tooling. Allows a user to run mixer tool in a cross-platform way. Built atop the clearlinux:latest image, and includes the os-clr-on-clr bundle for devloper tools. A python script sets up up a non-root user (with UID & GID mapped to the mix directory mounted at runtime), with sudo privileges only for mixer, swupd, and mock. Note: The README mentions privileges needed to run mixer build-image. This is sufficient for now, and narrowing the --privileged to the specific CAP subset (SYS_ADMIN, MKNOD, etc?) is left for a future task. Signed-off-by: Kevin C. Wells --- README.md | 1 + clr-sdk/Dockerfile | 16 ++++++++++ clr-sdk/README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++ clr-sdk/clruser | 2 ++ clr-sdk/setup.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 clr-sdk/Dockerfile create mode 100644 clr-sdk/README.md create mode 100644 clr-sdk/clruser create mode 100755 clr-sdk/setup.py diff --git a/README.md b/README.md index 3805c28..1f25386 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Containers - ciao-scheduler - ciao-deploy - ciao-webui +- clr-sdk - machine-learning - Keystone - MariaDB diff --git a/clr-sdk/Dockerfile b/clr-sdk/Dockerfile new file mode 100644 index 0000000..89a763d --- /dev/null +++ b/clr-sdk/Dockerfile @@ -0,0 +1,16 @@ +FROM clearlinux:latest +MAINTAINER kevin.c.wells@intel.com + +ARG swupd_args + +COPY setup.py /usr/bin/setup.py +COPY clruser /usr/share/defaults/sudo/sudoers.d/ + +# Update and add bundles +RUN swupd update $swupd_args && \ + swupd bundle-add os-clr-on-clr $swupd_args && \ + chmod 755 /usr/bin/setup.py && \ + chmod 440 /usr/share/defaults/sudo/sudoers.d/clruser + +ENTRYPOINT ["/usr/bin/setup.py"] + diff --git a/clr-sdk/README.md b/clr-sdk/README.md new file mode 100644 index 0000000..e1b55f9 --- /dev/null +++ b/clr-sdk/README.md @@ -0,0 +1,79 @@ +# Clear SDK Container +[![](https://images.microbadger.com/badges/image/clearlinux/clr-sdk.svg)](http://microbadger.com/images/clearlinux/clr-sdk "Get your own image badge on microbadger.com") +[![](https://images.microbadger.com/badges/version/clearlinux/clr-sdk.svg)](http://microbadger.com/images/clearlinux/clr-sdk "Get your own version badge on microbadger.com") + +This repo provides a Clear Linux* SDK container for running the Clear Linux devloper tools. This container will allow you to use the [mixer tool](https://clearlinux.org/features/mixer) on your Linux host. + +# Build +## Building Locally + +``` +docker build -t clearlinux/clr-sdk . +``` +> #### Note: +> If you are behind a firewall, you may need to pass the `--network host` and/or `--build-arg http://:` flags to docker build to configure your proxy. + +#### Optional Build ARGs +* `--build-arg swupd_args` specifies [SWUPD](https://clearlinux.org/documentation/swupdate_how_to_run_the_updater.html) flags passed to the update during build. +## Pulling from Dockerhub +``` +docker pull clearlinux/clr-sdk +``` + +# Run +* **Create a mix directory** + + The directory you create will be used for the output created while using the container. + ``` + mkdir -p /home/myuser/mix + ``` + *It is important that you are the owner of this directory.* The owner of the + directory is what determines the user id used inside the container. If you + are not the owner of the directory, you may not have access to the files the + container creates. +* **Running the docker container** + + Assuming you created the mix directory as described above, the command to + run the docker container would be: + ``` + docker run --rm -it -v /home/myuser/mix:/home/clr/mix clearlinux/clr-sdk --mixdir=/home/clr/mix + ``` + ### A note on the arguments: + #### docker run arguments + * `--rm` cleans up and removes the container once you exit it. The files + generated in the mounted directory will persist on the host. + * `-it` attaches an interactive terminal. + * `-v /path/on/host:/path/in/container` bind mounts a directory on the host + to a path inside the container. Only the files generated in this path + inside the container will be accessible on the host or persist after + the container has exited. The container path will be automatically + generated within the container if it doesn't already exist, and will + replace whatever may already be there, so _use caution_. + * If you plan to run `sudo mixer build-image` inside the container, you + must additionally pass `--privileged -v /dev:/dev` to docker run. This is + because `mixer build-image` needs to mount a loopback device for generating + the image filesystem. The `-v /dev:/dev` bind mount is due to an [outstanding + issue](https://github.com/moby/moby/issues/27886) where loopback devices + created within the container are not visible within the container. **This + can have serious side effects**, so only run the container in this way for + this specific command. + * If you are behind a firewall, you may need to pass the `--network host` + flag to docker run, and then set your `http_proxy` and `https_proxy` + environment variables within the container to configure your proxy. + #### Container arguments + * `-d`|`--mixdir` tells the startup script what directory you mounted using + the `-v` option above. The owner UID and GID of this directory will be + used for user inside the container. This is also the active directory when + the container runs. Omitting this argument will result in a default user + id and active directory, _even if you mounted a directory with -v_. This + can be useful, but is likely not what you want, and may cause the container + user to not have permission to access the mounted mix directory. + * `--id` manually sets the UID and GID for the user inside the container. + Should be in the form UID:GID. Takes precedence over id inferred by + mixdir argument. This may cause the container user to not have permission + to access the mounted mix directory. + + At this point, you should be able to run the commands described in the + [mixer guide](https://clearlinux.org/documentation/clear-linux/guides/maintenance/mixer.html). + + \ No newline at end of file diff --git a/clr-sdk/clruser b/clr-sdk/clruser new file mode 100644 index 0000000..655631a --- /dev/null +++ b/clr-sdk/clruser @@ -0,0 +1,2 @@ +clr ALL=NOPASSWD:SETENV: /usr/bin/mixer, /usr/bin/swupd + diff --git a/clr-sdk/setup.py b/clr-sdk/setup.py new file mode 100755 index 0000000..870d63a --- /dev/null +++ b/clr-sdk/setup.py @@ -0,0 +1,80 @@ +#!/usr/bin/python3 + +import argparse +import subprocess +import os +import sys +import pathlib + +parser = argparse.ArgumentParser() +parser.add_argument('-d','--mixdir', + help='The directory where you intend to make your mix. ' + 'This will be the active directory once the container ' + 'is running. In the abscence of the "id" argument, ' + 'the owner uid and gid of the mixdir will be used for ' + 'the user in the container.') + +parser.add_argument("--id", + help='UID and GID to use for the user inside the ' + 'container. It should be in the form UID:GID.') + +args = parser.parse_args() + +mixdir = args.mixdir if args.mixdir else "/home/clr/mix" + + +# Get UID and GID for user +uid,gid = (None, None) +if args.id: + try: + uid,gid = args.id.split(":") + uid = int(uid) + gid = int(gid) + except ValueError: + sys.stderr.write("Invalid id: Must be of form UID:GID\n") + sys.exit(1) +elif args.mixdir: + # Use owner of mixdir + try: + stat = os.stat(args.mixdir) + uid,gid = (stat.st_uid, stat.st_gid) + except FileNotFoundError: + # This implies the --mixdir flag was passed, but to a + # directory that doesn't exist. It will get created below. + pass + +if not uid or not gid: + # Use default + uid,gid = (1000, 1000) +elif uid == 0 or gid == 0: + sys.stderr.write("UID and GID must both be non-zero.\n") + sys.exit(1) + +user = "clr" + +# Create the group and user +try: + cmd = "groupadd -o -g {} {}".format(gid,user) + subprocess.run(cmd.split(),stdout=subprocess.PIPE,stderr=subprocess.STDOUT,check=True) + # Note: adding user to mock group for access to running mock + cmd = "useradd -Nmo -g {} -G mock -u {} {}".format(gid,uid,user) + subprocess.run(cmd.split(),stdout=subprocess.PIPE,stderr=subprocess.STDOUT,check=True) + os.chown("/home/{}".format(user),uid,gid) +except subprocess.SubprocessError: + sys.stderr.write("Error creating user.\n") + sys.exit(1) + +# Create the mix directory if it doesn't exist. +# Note: we catch FileExistsError rather than using exist_ok=True so +# that we only chown the directory if we're the one that created it. +try: + pathlib.Path(mixdir).mkdir(parents=True) + os.chown(mixdir,uid,gid) +except FileExistsError: + pass + +# Move to mixdir and start bash as new user +os.chdir(mixdir) +cmd = "sudo -H -u {} bash -i".format(user).split() +os.execvp(cmd[0], cmd) +