diff --git a/samba-share/Dockerfile b/samba-share/Dockerfile new file mode 100644 index 0000000..2715448 --- /dev/null +++ b/samba-share/Dockerfile @@ -0,0 +1,15 @@ +FROM debian:stable +LABEL CMDBUILD="docker build -t niccokunzmann/samba-share https://raw.githubusercontent.com/niccokunzmann/dockerfiles/master/samba-share/Dockerfile" +LABEL CMDRUN="docker run niccokunzmann/samba-share" + +MAINTAINER Sven Dowideit (@SvenDowideit) +MAINTAINER Nicco Kunzmann (@dannhaltohneson) + +# gettext for envsubst +RUN apt-get update && \ + apt-get install -yq samba gettext +ADD run.sh /run.sh +ADD setup-samba-share.sh /setup-samba-share.sh +ADD samba-share.sh /samba-share.sh + +ENTRYPOINT ["/run.sh"] diff --git a/samba-share/README.md b/samba-share/README.md new file mode 100644 index 0000000..d2589ab --- /dev/null +++ b/samba-share/README.md @@ -0,0 +1,56 @@ + + +# Samba Docker volume sharing plugin + +Sharing a Docker container's volume should be as simple as `docker run niccokunzmann/samba-share | sh`. + +This 'plugin' will create and configure a samba server container that auto-creates shares for all +the volumes attached to the specified container. + +## Usage + +Possible scenarios are + +- `docker run niccokunzmann/samba-share | sh` shares the volumes of ``. +- `docker run niccokunzmann/samba-share` reminds the user what the options are. +- Additional parameters can be [passed as environment variable](https://docs.docker.com/engine/reference/run/#env-environment-variables) and can be combined. Possible names are USER PASSWORD USERID GROUP READONLY. Example: + + docker run -e READONLY=yes niccokunzmann/samba-share | sh + +## Try it out + +Create a volume in my-data and share its content via samba + + # Make a volume container (only need to do this once) + docker run -v /data --name my-data busybox true + # Share it using Samba (Windows file sharing) + docker run niccokunzmann/samba-share my-data | sh + +## How it works + +The `niccokunzmann/samba-share` container uses the bind-mounted docker client and socket to introspect +the configuration of the specified container, and then uses that information to setup a new container +that is `--volumes-from` setup to give it access. + +## Tested + +- + Client: + Version: 1.9.1 + API version: 1.21 + Go version: go1.4.2 + Git commit: a34a1d5 + Built: Fri Nov 20 13:20:08 UTC 2015 + OS/Arch: linux/amd64 + + Server: + Version: 1.9.1 + API version: 1.21 + Go version: go1.4.2 + Git commit: a34a1d5 + Built: Fri Nov 20 13:20:08 UTC 2015 + OS/Arch: linux/amd64 + +## Credits + +This was derived from [`svendowideit/samba`](https://github.com/SvenDowideit/dockerfiles/tree/master/samba) to [`niccokunzmann/samba-share`](https://github.com/niccokunzmann/dockerfiles/tree/master/samba-share) because of [Issue 29](https://github.com/SvenDowideit/dockerfiles/issues/29). diff --git a/samba-share/run.sh b/samba-share/run.sh new file mode 100755 index 0000000..03dd702 --- /dev/null +++ b/samba-share/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# run.sh does one of these +# - execute samba +# - run sh commands to set up samba +# +set -e + +if [ "$1" == "--start" ] +then + shift 1 + /samba-share.sh "$@" +else + /setup-samba-share.sh "$@" +fi + + + + diff --git a/samba-share/samba-share.sh b/samba-share/samba-share.sh new file mode 100755 index 0000000..655e888 --- /dev/null +++ b/samba-share/samba-share.sh @@ -0,0 +1,48 @@ +#!/bin/bash +#set -e + +USER=${USER:-"root"} +PASSWORD=${PASSWORD:-"tcuser"} +USERID=${USERID:-1000} +GROUP=${GROUP:-"root"} +READONLY=${READONLY:-"no"} + +CONTAINER="$1" +shift 1 + +echo "Setting loglevel to 0." +sed 's/\[global\]/\[global\]\n log level = 0/' -i.bak /etc/samba/smb.conf + +echo "Setting up samba configuration for container \"$CONTAINER\" and volumes "$@"." + +for VOLUME in "$@" +do + echo "Adding volume \"$VOLUME\"." + + VOLUME_NAME=`echo "$VOLUME" | sed "s/\///" | tr '[\/<>:"\\|?*+;,=]' '_'` + + echo "[$VOLUME_NAME] + comment = ${VOLUME_NAME} volume from ${CONTAINER} + read only = ${READONLY} + locking = no + path = ${VOLUME} + force user = ${USER} + force group = ${GROUP} + guest ok = yes + map archive = no + map system = no + map hidden = no" >> /etc/samba/smb.conf +done + +cat /etc/samba/smb.conf + +if ! id -u $USER > /dev/null 2>&1 +then + useradd $USER --uid $USERID --user-group --password $PASSWORD --home-dir / +fi +/etc/init.d/samba start +echo "Watching /var/log/samba/*" +tail -f /var/log/samba/* +# This should allow the samba-server to be removed by --rm. +exit 0 + diff --git a/samba-share/setup-samba-share.sh b/samba-share/setup-samba-share.sh new file mode 100755 index 0000000..71f36fa --- /dev/null +++ b/samba-share/setup-samba-share.sh @@ -0,0 +1,187 @@ +#!/bin/bash +set -e + +docker_host_execute() { + echo "$@" +} +output() { + docker_host_execute echo "$@" +} +error() { + output "ERROR: $@" +} + +print_usage() { + output "Please run with:" + output " docker run niccokunzmann/samba-share \"$container\" | sh" + output "" + output " OR - depending on your Docker Host's location of its docker binary" + output "" + output " DOCKER=/usr/local/bin/docker /usr/local/bin/docker run niccokunzmann/samba-share \"$container\" | /bin/sh" + output "Maybe even add sudo." +} + +usage() { + output + [ -n "$1" ] && error "$@" + print_usage + output + docker_host_execute exit 1 + exit 1 +} + + +# remove the default shell print +docker_host_execute PS1= + +docker_host_execute " +output() { + echo "$@" +} +docker_host_execute() { + true +}" + + +# copy functions to sh +# http://stackoverflow.com/a/9895178 +declare -f usage +declare -f print_usage +declare -f error + +# parse parameters +container=$1 + +# check parameters +if [ -z "$container" ] +then + # some spacing in case this is not piped to sh + docker_host_execute + docker_host_execute + docker_host_execute # Hello user! Read the message below: + container="" + usage "No container name given. Replace with the name of the container to share volumes from." +fi + +# create environment for sh +docker_host_execute "container=$container" +docker_host_execute "sambaContainer=`grep cpu[^a-zA-Z\d] /proc/1/cgroup | grep -oE '[0-9a-fA-F]{64}'`" +# It could be that parameters were passed as +# docker run -e USER=... niccokunzmann/samba-share \"$container\" | sh +# We set them like this so they must be named explicitely and +# are not accidentially taken from the environment. +docker_host_execute "USER=$USER" +docker_host_execute "PASSWORD=$PASSWORD" +docker_host_execute "USERID=$USERID" +docker_host_execute "GROUP=$GROUP" +docker_host_execute "READONLY=$READONLY" + +# define function for sh instead of a string for better syntax highlighting +execute_in_sh() { + + if [ -z "$DOCKER" ] + then + DOCKER=docker + fi + + if ! type "$DOCKER" 2>>/dev/null 1>>/dev/null + then + usage "Could run docker command as \"$DOCKER\". Please specify where to find the docker binary." + fi + + # check if variable transfer from host to shell worked + if [ -z "$container" ] || [ -z "$sambaContainer" ] + then + error "Could not transfer necessary variables form docker container. Not your fault." + exit 1 + fi + + if ! $DOCKER inspect "$container" 1>>/dev/null 2>>/dev/null + then + usage "Container \"$container\" does not exist." + fi + + volumes=`$DOCKER inspect --format='{{range \$k,\$v := .Config.Volumes}}{{println \$k}}{{end}}' "$container" | grep -v -E "^$" + $DOCKER inspect --format='{{range \$k,\$v := .Volumes}}{{println \$k}}{{end}}' "$container" | grep -v -E "^$"` + + if [ -z "$volumes" ] + then + usage "Could not detect any volumes to share in container \"$container\"." + fi + + sambaImage=`$DOCKER inspect --format='{{.Config.Image}}' "$sambaContainer"` + if [ -z "$sambaImage" ] + then + error "Could not find samba image of container \"$sambaContainer\"." + exit 1 + fi + + server_container_name=samba-server + + if $DOCKER inspect --format "{{.State.Running}}" "$server_container_name" >/dev/null 2>&1 + then + echo "Stopping and removing existing server." + $DOCKER stop "$server_container_name" > /dev/null 2>&1 + $DOCKER rm "$server_container_name" >/dev/null 2>&1 + fi + + echo "Starting \"$server_container_name\" container sharing the volumes" $volumes "of container \"${container}\"." + + # from here we should pass the work off to the real samba container + # I'm running this in the background rather than using run -d, so that --rm will still work + $DOCKER run --rm --name "$server_container_name" \ + --expose 137 -p 137:137 \ + --expose 138 -p 138:138 \ + --expose 139 -p 139:139 \ + --expose 445 -p 445:445 \ + -e USER -e PASSWORD -e USERID -e GROUP -e READONLY \ + --volumes-from "$container" \ + "$sambaImage" --start "$container" $volumes > /dev/null 2>&1& + + # wait for the container to finish and remove it + $DOCKER wait "$sambaContainer" 2>>/dev/null 1>>/dev/null + $DOCKER rm "$sambaContainer" 2>>/dev/null 1>>/dev/null + + # give advice + # http://stackoverflow.com/a/20686101 + ips="`docker inspect --format ' {{ .NetworkSettings.IPAddress }}' "$server_container_name"`" + example_ip="`echo "$ips" | head -n1 | grep -o -E '\S+'`" + echo "" + echo "# run 'docker logs \"$server_container_name\"' to view the samba logs" + echo "" + echo "================================================" + echo "" + echo "Your data volumes (" $volumes ") should now be accessible at "'\''\'"$example_ip"'\'" as 'guest' user (no password)" + echo "" + echo "For example, on OSX, using a typical boot2docker vm:" + echo " goto Go|Connect to Server in Finder" + echo " enter 'cifs://$example_ip" + echo " hit the 'Connect' button" + echo " select the volumes you want to mount" + echo " choose the 'Guest' radiobox and connect" + echo + echo "Or on Linux:" + echo " mount -t cifs //$example_ip/data /mnt/data -o username=guest" + echo + echo "Or on Windows:" + echo " Enter "'\''\'"$example_ip"'\'"data' into Explorer" + echo " Log in as Guest - no password" + echo "" + echo "Ip addresses: " + echo "$ips" + echo "" + exit 0 +} + +# copy execute_in_sh to sh +declare -f execute_in_sh + +# execute execute_in_sh in sh +docker_host_execute execute_in_sh + +# finally, if you did not pipe it to sh, you may need some output +output() { + echo "# $@" +} +print_usage +