Skip to content

Instantly share code, notes, and snippets.

@atoa
Last active September 10, 2019 13:36
Show Gist options
  • Save atoa/9b3cd28e55cff5d5a54a15ca4ec435b7 to your computer and use it in GitHub Desktop.
Save atoa/9b3cd28e55cff5d5a54a15ca4ec435b7 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Docker for Windows drive mount helper
# Manually mounts a Windows shared drive inside the MobyLinuxVM virtual machine
# (host running on HyperV) so that it is visible to Docker containers.
# It enters the moby VM using nsenter via the 'docker4w/nsenter-dockerd'
# container.
# Then mounts the share drive using the DockerNAT ip address
# This can be useful with unix like environments under Windows
# (e.g. Windows Subsystem for Linux, Cygwin, MSYS2, MinGW, etc)
# If needed, set DockerNAT interface to the windows Private network category
# using the following PowerShell command:
# Set-NetConnectionProfile -InterfaceAlias "vEthernet (DockerNAT)" -NetworkCategory Private
set -u
# Global associative array to populate options. Made readonly after getopts
declare -xgA OPTS=(
# hostname hosting share
['HOST']=''
# Display full help on usage. Boolean if set to non-emnpty
['HELP']=''
# domain of user
['DOMAIN']=''
)
function usage() {
echo "Usage: $0 [-n host] [-u unc] [-m mountpoint] [-d domain] [-h]" >&2
[ ${OPTS['HELP']:=''} ] && cat <<'EOF' >&2
Mounts a CIFS share in the MobyLinuxVM of Docker for Windows
Options:
-d <domain>
Windows domain
-n <hostname>
Hostname for the UNC
-u <unc> [NOT IMPLEMENTED]
UNC of share e.g.: //host/share
EOF
exit 1
}
function get_arguments() {
local OPTARG
while getopts ':d:n:h' opt ; do
case "${opt}" in
d)
OPTS['DOMAIN']="${OPTARG}"
;;
n)
OPTS['HOST']="${OPTARG}"
;;
h)
OPTS['HELP']=true
usage ;;
\?)
echo "[ERROR] unknown option: ${OPTARG}" >&2
usage
;;
:)
echo "[ERROR] option requires an argument: ${OPTARG}" >&2
usage
;;
*)
echo "[ERROR] unimplemented option: ${OPTARG}" >&2
usage
;;
esac
done
}
get_arguments "$@"
# OPTS associative array set to readonly from here
readonly -a OPTS
if [ -z "${OPTS[HOST]}" ] ; then
# HyperV DockerNAT interface name
INTERFACE='DockerNAT'
# obtain ip address of the DockerNAT interface
#HOST="$(ipconfig | grep -A6 "$INTERFACE" | grep IPv4 | sed -e 's/.*: //')"
HOST=$(powershell.exe "(Get-NetIPConfiguration -InterfaceAlias 'vEthernet (DockerNAT)' | Select-Object IPv4Address).IPv4Address.IPAddress" | tr -d '[:space:]' )
if [[ $? -ne 0 || -z "$HOST" ]] ; then
#if [[ -z "$HOST" ]] ; then
echo "[ERROR] failed to obtain ip address" >&2
exit 1
fi
else
HOST="${OPTS[HOST]}"
fi
if [ ! -z "${OPTS[DOMAIN]}" ] ; then
USERDOMAIN="${OPTS[DOMAIN]}"
else
USERDOMAIN=$(powershell.exe 'if ($env:USERDOMAIN) { $env:USERDOMAIN } else { [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().DomainName.split(".")[0] }' | tr -d '[:space:]')
fi
if [ -z "${USERDOMAIN:-}" ] ; then
echo "[ERROR] could not obtain the domain. Use the -d option" >&2
exit 1
fi
# TODO pass as arguments and default to the values below
# userid and domain used for authenticating to the share
export USER="$USER"
export DOMAIN="$USERDOMAIN"
# shared drive
export DRIVE='C'
export UNC="//${HOST}/${DRIVE}\$"
export MOUNT_POINT="/mnt/$(echo "$DRIVE" | tr '[:upper:]' '[:lower:]')"
# docker commands to enter VM with privileges
mount_cmd='/bin/mount'
mount_cifs_cmd='/sbin/mount.cifs'
shell_cmd='/bin/busybox'
shell_args="sh -c"
docker_cmd="docker run -ti --rm --privileged --pid=host"
docker_img='docker4w/nsenter-dockerd'
# get current mounts to see if the share is already mounted
mount=$($docker_cmd "$docker_img" "$mount_cmd") || {
echo '[ERROR] failed to run mount command in host VM' >&2
exit 1
}
echo "$mount" | grep -q "on ${MOUNT_POINT} type cifs" && {
echo '[INFO] drive already mounted'
exit 0
}
echo "[INFO] mounting unc: ${UNC}" >&2
mnt_opts="username=${USER},domain=${DOMAIN},addr=${HOST},vers=3.02,sec=ntlmsspi,cache=strict,uid=0,noforceuid,gid=0,noforcegid,file_mode=0755,dir_mode=0777,iocharset=utf8,nounix,serverino,mapposix,nobrl,mfsymlinks,noperm,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1"
declare mount_script
read -r -d '' mount_script <<EOF
[ -d "${MOUNT_POINT}" ] || mkdir -p "${MOUNT_POINT}" && \
"$mount_cifs_cmd" "${UNC}" "${MOUNT_POINT}" -o "$mnt_opts"
EOF
echo "$mount_script"
$docker_cmd "$docker_img" "$shell_cmd" $shell_args "$mount_script"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment