From 149c82a063cad138d2f9bd1e9a7a053666c0a4c0 Mon Sep 17 00:00:00 2001 From: David Coppit Date: Wed, 24 Jun 2015 12:45:44 -0400 Subject: [PATCH] Cleanup and dxcumentation for new file ownership feature. --- Dockerfile | 27 +++++++++++++++++++-------- README.md | 38 +++++++++++++++++++++++++++++++++++--- runas.sh | 52 +++++++++++++++++++++++++++++++++++++++++----------- start.sh | 4 ++-- 4 files changed, 97 insertions(+), 24 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4464d1e..229d788 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,13 +18,24 @@ VOLUME ["/config", \ "/dir1", "/dir2", "/dir3", "/dir4", "/dir5", "/dir6", "/dir7", "/dir8", "/dir9", "/dir10", \ "/dir11", "/dir12", "/dir13", "/dir14", "/dir15", "/dir16", "/dir17", "/dir18", "/dir19", "/dir20"] -# Add default config file -ADD sample.conf /root/sample.conf +ENV UGIDS 0:0 +ENV UMAP "" +ENV GMAP "" -# Add scripts -ADD start.sh /root/start.sh -RUN chmod +x /root/start.sh -ADD monitor.sh /root/monitor.sh -RUN chmod +x /root/monitor.sh +# Create dir to keep things tidy. Make sure it's readable by $UID +RUN mkdir /files +RUN chmod a+rwX /files -CMD /root/start.sh +# Add default config file. Make sure it's readable by $UID +ADD sample.conf /files/sample.conf +RUN chmod a+r /files/sample.conf + +# Add scripts. Make sure start.sh and monitor.sh are executable by $UID +ADD start.sh /files/start.sh +RUN chmod a+x /files/start.sh +ADD monitor.sh /files/monitor.sh +RUN chmod a+x /files/monitor.sh +ADD runas.sh /files/runas.sh +RUN chmod +x /files/runas.sh + +CMD /files/runas.sh "$UMAP" "$GMAP" "$UGIDS" /files/start.sh diff --git a/README.md b/README.md index 72e8de9..32be2f2 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,34 @@ them to be used that way as well. After creating your conf files, restart the container and it will begin monitoring. +Controlling File Ownership +-------------------------- + +If your command writes to the directory, you may want to use the `UMAP` and `GMAP` environment variables to update user +IDs and group IDs inside the container so that they match those of the host. For example, if your command is `chown -R +nobody:users /dir1`, then you'll want to make sure that the "nobody" user in the container has the same ID as in the +host. You can set the UMAP environment variable to the value specified by ``echo nobody:`id -u nobody`:`id -g nobody` +``. Similarly, to remap the primary group for the "nobody" user, you would set GMAP to the value specified by ``echo `id +-gn nobody`:`id -g nobody` ``. + +You can specify multiple users or groups to update by separating them with spaces in the UMAP and GMAP variables. For +example, these -e arguments to the `docker run` command will update the "nobody" and "www" users, as well as the "users" +and "wheel" groups: + +`-e UMAP="nobody:99:100 www:80:800" -e GMAP="users:100 wheel:800"` + +For commands that create files without an explicit user or group name, you may want to set the `UGID` environment +variable so that files created by the command will have the correct user and group IDs in the host. For example, if your +command is `echo foo > /dir1/foo.txt`, then by default the file will be created as the "root" user of the container. If +you want it to be created as user "nobody" with its default group, you would set `UGID` to the values specified by +``echo `id -u nobody`:`id -g nobody` `` in the host. For instance: + +`-e UGID=99:100` + Examples -------- -Run a permissions-repairing utility whenever there's a change in the directory: +This example is to run a permissions-repairing utility whenever there's a change in the directory: WATCH_DIR=/dir2 SETTLE_DURATION=5 @@ -46,12 +70,20 @@ Run a permissions-repairing utility whenever there's a change in the directory: # This is important because chmod/chown will change files in the monitored directory IGNORE_EVENTS_WHILE_COMMAND_IS_RUNNING=1 -Tell SageTV to rescan its imported media when the media directory changes: +Since the `newperms` utility does an explicit "chown -R nobody:users", we need to use the UMAP and GMAP environment +variables to update the user and group in the container so that it will match the host. For example: + +`docker run -e UMAP=nobody:99:100 -e GMAP=users:100 --name=inotify-command -d -v /etc/localtime:/etc/localtime -v +/config/dir/path:/config:rw -v /dir/path:/dir2:rw -v /usr/local/sbin/newperms:/newperms coppit/inotify-command` + +This example tells SageTV to rescan its imported media when the media directory changes: WATCH_DIR=/dir1 SETTLE_DURATION=5 MAX_WAIT_TIME=05:00 MIN_PERIOD=10:00 COMMAND="wget -nv -O /dev/null --auth-no-challenge http://sage:frey@192.168.1.102:8080/sagex/api?c=RunLibraryImportScan&1=" - # This is not important because the above is a "fire and forget" asynchronous operation IGNORE_EVENTS_WHILE_COMMAND_IS_RUNNING=0 + +We don't need to ignore events while the command is running because the wget command is a "fire and forget" asynchronous +operation. We also don't need to use UMAP, GMAP, or UGID since this command doesn't write to any watch directory. diff --git a/runas.sh b/runas.sh index 0ac8b8f..02c7289 100755 --- a/runas.sh +++ b/runas.sh @@ -11,6 +11,42 @@ function ts { #----------------------------------------------------------------------------------------------------------------------- +function process_args { + # Shift off the args as we go so that we can exec $@ later. These are meant to be globals. + UMAP=$1 + shift + GMAP=$1 + shift + UGID=$1 + shift + + for NAME_UID_GID in $UMAP + do + if [[ ! "$NAME_UID_GID" =~ ^[A-Za-z0-9._][-A-Za-z0-9._]*:[0-9]{1,}:[0-9]{1,}$ ]] + then + echo "UMAP value $NAME_UID_GID is not valid. It should be of the form ::" + exit 1 + fi + done + + for NAME_GID in $GMAP + do + if [[ ! "$NAME_GID" =~ ^[A-Za-z0-9._][-A-Za-z0-9._]*:[0-9]{1,}$ ]] + then + echo "GMAP value $NAME_GID is not valid. It should be of the form :" + exit 1 + fi + done + + if [[ ! "$UGID" =~ ^[0-9]{1,}:[0-9]{1,}$ ]] + then + echo "UGID value is not valid. It should be of the form :" + exit 1 + fi +} + +#----------------------------------------------------------------------------------------------------------------------- + function update_users { local UMAP=$1 @@ -52,11 +88,11 @@ function update_groups { #----------------------------------------------------------------------------------------------------------------------- function create_user { - local UID_GID=$1 + local UGID=$1 # Create a new user with the proper user and group ID. - local USER_ID=${UID_GID%:*} - local GROUP_ID=${UID_GID#*:} + local USER_ID=${UGID%:*} + local GROUP_ID=${UGID#*:} echo "$(ts) Creating user \"$USER\" (ID $USER_ID) and group \"$GROUP\" (ID $GROUP_ID) to run the command..." @@ -67,17 +103,11 @@ function create_user { #----------------------------------------------------------------------------------------------------------------------- -# Shift off the args as we go so that we can exec $@ -UMAP=$1 -shift -GMAP=$1 -shift -UID_GID=$1 -shift +process_args update_users "$UMAP" update_groups "$GMAP" -create_user "$UID_GID" +create_user "$UGID" echo "$(ts) Running command as user \"$USER\"..." exec /sbin/setuser $USER "$@" diff --git a/start.sh b/start.sh index 156b57e..bfd9b5f 100755 --- a/start.sh +++ b/start.sh @@ -17,7 +17,7 @@ readarray -t CONFIG_FILES < <(ls /config/*.conf) if [[ "$CONFIG_FILES" == "" ]] then echo "$(ts) Creating sample config file. Rename it, check the settings, then rerun the container. Exiting." - cp /root/sample.conf /config/sample.conf + cp /files/sample.conf /config/sample.conf chmod a+w /config/sample.conf exit 1 fi @@ -27,7 +27,7 @@ PIDS=() for CONFIG_FILE in "${CONFIG_FILES[@]}" do echo "$(ts) Launching monitor for $CONFIG_FILE" - /root/monitor.sh $CONFIG_FILE & + /files/monitor.sh $CONFIG_FILE & PIDS+=($!) done