/
wrapper
executable file
Β·357 lines (309 loc) Β· 10.1 KB
/
wrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/usr/bin/env bash
# Geodesic Wrapper Script
set -o pipefail
# Geodesic Settings
export GEODESIC_PORT=${GEODESIC_PORT:-$((30000 + $$ % 30000))}
export GEODESIC_HOST_CWD=$(pwd -P 2>/dev/null || pwd)
readonly OS=$(uname -s)
export USER_ID=$(id -u)
export GROUP_ID=$(id -g)
export options=()
export targets=()
function require_installed() {
if ! which $1 >/dev/null; then
echo "Cannot find $1 installed on this system. Please install and try again."
exit 1
fi
}
function options_to_env() {
local kv
local k
local v
for option in ${options[@]}; do
kv=(${option/=/ })
k=${kv[0]} # Take first element as key
k=${k#--} # Strip leading --
k=${k//-/_} # Convert dashes to underscores
k=$(echo $k | tr '[:lower:]' '[:upper:]') # Convert to uppercase (bash3 compat)
v=${kv[1]} # Treat second element as value
v=${v:-true} # Set it to true for boolean flags
export $k="$v"
done
}
function debug() {
if [ "${VERBOSE}" == "true" ]; then
echo "[DEBUG] $*"
fi
}
function run_exit_hooks() {
command -v geodesic_on_exit >/dev/null && geodesic_on_exit
}
function use() {
DOCKER_ARGS=()
if [ -t 1 ]; then
# Running in terminal
DOCKER_ARGS+=(-it --rm --name="${DOCKER_NAME}" --env LS_COLORS --env TERM --env TERM_COLOR --env TERM_PROGRAM)
if [ -n "$SSH_AUTH_SOCK" ]; then
if [ "${OS}" == 'Linux' ]; then
# Bind-mount SSH agent socket into container (linux only)
DOCKER_ARGS+=(--volume "$SSH_AUTH_SOCK:$SSH_AUTH_SOCK"
--env SSH_AUTH_SOCK
--env SSH_CLIENT
--env SSH_CONNECTION
--env SSH_TTY
--env USER
--env USER_ID
--env GROUP_ID)
elif [ "${OS}" == 'Darwin' ] && [ "${GEODESIC_MAC_FORWARD_SOCKET}" == 'true' ]; then
# Bind-mount SSH-agent socket (available in docker-for mac Edge 2.2 release)
# Note that the file/socket /run/host-services/ssh-auth.sock does not exist
# on the host OS, it is in the Moby Linux VM in which the Docker daemon `dockerd` runs.
# See https://github.com/docker/for-mac/issues/410#issuecomment-557613306
# and https://docs.docker.com/docker-for-mac/osxfs/#namespaces
DOCKER_ARGS+=(--volume /run/host-services/ssh-auth.sock:/run/host-services/ssh-auth.sock
-e SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock)
fi
fi
else
DOCKER_ARGS=()
fi
if [ "${GEODESIC_HOST_BINDFS_ENABLED}" = "true" ]; then
if [ "${USER_ID}" = 0 ]; then
echo "# WARNING: Host user is root. This is DANGEROUS."
echo " * Geodesic should not be launched by the host root user."
echo " * Use \"rootless\" mode instead. See https://docs.docker.com/engine/security/rootless/"
echo "# Not enabling BindFS host filesystem mapping because host user is root."
else
echo "# Enabling BindFS mapping of file system owner and group ID."
DOCKER_ARGS+=(
--env GEODESIC_HOST_UID="${USER_ID}"
--env GEODESIC_HOST_GID="${GROUP_ID}"
--env GEODESIC_LOCALHOST="${GEODESIC_LOCALHOST:=/localhost.bindfs}"
--env GEODESIC_BINDFS_OPTIONS
)
fi
fi
if [ "${WITH_DOCKER}" == "true" ]; then
# Bind-mount docker socket into container
# Should work on Linux and Mac.
# Note that the mounted /var/run/docker.sock is not a file or
# socket in the Mac host OS, it is in the dockerd VM.
# https://docs.docker.com/docker-for-mac/osxfs/#namespaces
echo "# Enabling docker support. Be sure you install a docker CLI binary{{getenv "DOCKER_INSTALL_PROMPT"}}."
DOCKER_ARGS+=(--volume "/var/run/docker.sock:/var/run/docker.sock")
# Some reports say this is needed for Windows WSL
if [[ $(uname -r) =~ Microsoft$ ]]; then
DOCKER_ARGS+=(--user root)
fi
# NOTE: bind mounting the docker CLI binary is no longer recommended and usually does not work.
# Use a docker image with a docker CLI binary installed that is appropriate to the image's OS.
fi
if [[ ${GEODESIC_CUSTOMIZATION_DISABLED-false} == false ]]; then
if [ -n "${GEODESIC_TRACE}" ]; then
DOCKER_ARGS+=(--env GEODESIC_TRACE)
fi
if [ -n "${ENV_FILE}" ]; then
DOCKER_ARGS+=(--env-file ${ENV_FILE})
fi
# allow users to override value of GEODESIC_DEFAULT_ENV_FILE
local geodesic_default_env_file=${GEODESIC_DEFAULT_ENV_FILE:-~/.geodesic/env}
if [ -f "${geodesic_default_env_file}" ]; then
DOCKER_ARGS+=(--env-file=${geodesic_default_env_file})
fi
else
echo "# Disabling user customizations: GEODESIC_CUSTOMIZATION_DISABLED is set and not 'false'"
DOCKER_ARGS+=(--env GEODESIC_CUSTOMIZATION_DISABLED)
fi
if [ -n "${DOCKER_DNS}" ]; then
DOCKER_ARGS+=("--dns=${DOCKER_DNS}")
fi
if [ -n "${LOCAL_HOME}" ]; then
local_home=${LOCAL_HOME}
elif [[ $(uname -r) =~ Microsoft$ ]]; then
# Lookup correct mount path for WSL
mount_path=$(dirname $(findmnt -S C: -t drvfs -no target))
windows_user_name=$($mount_path/c/Windows/System32/cmd.exe /c 'echo %USERNAME%' | tr -d '\r')
user_local_app_data=$(cmd.exe /c echo %LOCALAPPDATA% | tr -d '\r' | sed -e 's/\\/\//g')
if [ -d "$mount_path/c/Users/${windows_user_name}/AppData/Local/lxss/" ]; then
local_home=${user_local_app_data}/lxss${HOME}
else
local restore_nullglob=$(shopt -p nullglob)
shopt -s nullglob
for dir in $mount_path/c/Users/${windows_user_name}/AppData/Local/Packages/CanonicalGroupLimited.Ubuntu*; do
folder_name=$(basename ${dir})
local_home=${user_local_app_data}/Packages/${folder_name}/LocalState/rootfs${HOME}
break
done
$restore_nullglob
fi
if [ -z "${local_home}" ]; then
echo "ERROR: can't identify user home directory, you may specify path via LOCAL_HOME variable"
exit 1
else
echo "Detected Windows Subsystem for Linux, mounting $local_home instead of $HOME"
fi
else
local_home=${HOME}
fi
if [ "${local_home}" == "/localhost" ]; then
echo "WARNING: not mounting ${local_home} because it conflicts with geodesic"
else
if [ "${GEODESIC_LOCALHOST:-/localhost}" != "/localhost" ]; then
echo "# Mounting ${local_home} into container at ${GEODESIC_LOCALHOST} with workdir ${GEODESIC_HOST_CWD}"
else
echo "# Mounting ${local_home} into container with workdir ${GEODESIC_HOST_CWD}"
fi
DOCKER_ARGS+=(
--volume="${local_home}:${GEODESIC_LOCALHOST:-/localhost}"
--env LOCAL_HOME="${local_home}"
)
fi
DOCKER_ARGS+=(
--privileged
--publish ${GEODESIC_PORT}:${GEODESIC_PORT}
--name "${DOCKER_NAME}"
--rm
--env GEODESIC_PORT=${GEODESIC_PORT}
--env DOCKER_IMAGE="${DOCKER_IMAGE%:*}"
--env DOCKER_NAME="${DOCKER_NAME}"
--env DOCKER_TAG="${DOCKER_TAG}"
--env GEODESIC_HOST_CWD="${GEODESIC_HOST_CWD}"
)
trap run_exit_hooks EXIT
# the extra curly braces around .ID are because this file goes through go template substitution locally before being installed as a shell script
container_id=$(docker ps --filter name="^/${DOCKER_NAME}\$" --format '{{`{{ .ID }}`}}')
if [ -n "$container_id" ]; then
echo "# Attaching to existing ${DOCKER_NAME} session ($container_id)"
if [ $# -eq 0 ]; then
set -- "/bin/bash" "-l" "$@"
fi
docker exec -it --env GEODESIC_HOST_CWD="${GEODESIC_HOST_CWD}" "${DOCKER_NAME}" $*
else
echo "# Starting new ${DOCKER_NAME} session from ${DOCKER_IMAGE}"
echo "# Exposing port ${GEODESIC_PORT}"
[ -z "${GEODESIC_DOCKER_EXTRA_ARGS}" ] || echo "# Launching with extra Docker args: ${GEODESIC_DOCKER_EXTRA_ARGS}"
docker run "${DOCKER_ARGS[@]}" ${GEODESIC_DOCKER_EXTRA_ARGS} ${DOCKER_IMAGE} -l $*
fi
}
function parse_args() {
while [[ $1 ]]; do
case "$1" in
-h | --help)
targets+=("help")
shift
;;
-v | --verbose)
export VERBOSE=true
shift
;;
--*)
options+=("${1}")
shift
;;
--) # End of all options
shift
;;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*=*)
declare -g "${1}"
shift
;;
*)
targets+=("${1}")
shift
;;
esac
done
}
function uninstall() {
echo "# Uninstalling ${DOCKER_NAME}..."
docker rm -f ${DOCKER_NAME} >/dev/null 2>&1 || true
docker rmi -f ${DOCKER_IMAGE} >/dev/null 2>&1 || true
echo "# Not deleting $0"
exit 0
}
function update() {
echo "# Installing the latest version of ${DOCKER_IMAGE}"
docker run --rm ${DOCKER_IMAGE} | bash -s ${DOCKER_TAG}
if [ $? -eq 0 ]; then
echo "# ${DOCKER_IMAGE} has been updated."
exit 0
else
echo "Failed to update ${DOCKER_IMAGE}"
exit 1
fi
}
function stop() {
echo "# Stopping ${DOCKER_NAME}..."
exec docker kill ${DOCKER_NAME} >/dev/null 2>&1
}
function help() {
echo "Usage: $0 [target] ARGS"
echo ""
echo " Targets:"
echo " update Upgrade geodesic wrapper shell"
echo " stop Stop a running shell"
echo " uninstall Remove geodesic image"
echo " <empty> Enter into a shell"
echo ""
echo " Arguments:"
echo " --env-file=... Pass an environment file containing key=value pairs"
echo ""
}
require_installed tr
require_installed grep
parse_args "$@"
options_to_env
# Docker settings
export DOCKER_IMAGE="{{getenv "DOCKER_IMAGE" "cloudposse/geodesic"}}"
export DOCKER_TAG="{{getenv "DOCKER_TAG" "${DOCKER_TAG:-dev}"}}"
export DOCKER_NAME="{{getenv "APP_NAME" "${DOCKER_NAME:-$(basename $DOCKER_IMAGE)}"}}"
if [ -n "${GEODESIC_NAME}" ]; then
export DOCKER_NAME=$(basename "${GEODESIC_NAME:-}")
fi
if [ -n "${GEODESIC_TAG}" ]; then
export DOCKER_TAG=${GEODESIC_TAG}
fi
if [ -n "${GEODESIC_IMAGE}" ]; then
export DOCKER_IMAGE=${GEODESIC_IMAGE:-${DOCKER_IMAGE}:${DOCKER_TAG}}
else
export DOCKER_IMAGE=${DOCKER_IMAGE}:${DOCKER_TAG}
fi
export DOCKER_DNS=${DNS:-${DOCKER_DNS}}
if [ "${GEODESIC_SHELL}" == "true" ]; then
echo "Cannot run while in a geodesic shell"
exit 1
fi
if [ -z "${DOCKER_IMAGE}" ]; then
echo "Error: --image not specified (E.g. --image=cloudposse/foobar.example.com:1.0)"
exit 1
fi
require_installed docker
docker ps >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Unable to communicate with docker daemon. Make sure your environment is properly configured and then try again."
exit 1
fi
if [ -z "$targets" ]; then
# Execute default target
targets=("use")
fi
for target in $targets; do
if [ "$target" == "update" ]; then
update
elif [ "$target" == "uninstall" ]; then
uninstall
elif [ "$target" == "stop" ]; then
stop
elif [ "$target" == "use" ]; then
use
elif [ "$target" == "help" ]; then
help
else
echo "Unknown target: $target"
exit 1
fi
done