Last active
September 10, 2019 13:36
-
-
Save atoa/9b3cd28e55cff5d5a54a15ca4ec435b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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