forked from elasticluster/elasticluster
-
Notifications
You must be signed in to change notification settings - Fork 0
/
elasticluster.sh
executable file
·324 lines (276 loc) · 8.9 KB
/
elasticluster.sh
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
#! /bin/sh
#
# Seamless interface to Run ElastiCluster in a Docker image.
# Tries to install Docker if it cannot be found.
#
# Copyright (c) 2018, 2019, 2020 Riccardo Murri <riccardo.murri@gmail.com>
#
# This file is part of ElastiCluster. It can be distributed and
# modified under the same conditions as ElastiCluster.
#
me="$(basename $0)"
## defaults
docker_image_name='riccardomurri/elasticluster'
docker_image_tag='latest'
## helper functions
# see /usr/include/sysexit.h
EX_OK=0 # successful termination
EX_USAGE=1 # command line usage error
EX_DATAERR=65 # data format error
EX_NOINPUT=66 # cannot open input
EX_NOUSER=67 # addressee unknown
EX_NOHOST=68 # host name unknown
EX_UNAVAILABLE=69 # service unavailable
EX_SOFTWARE=70 # internal software error
EX_OSERR=71 # system error (e.g., can't fork)
EX_OSFILE=72 # critical OS file missing
EX_CANTCREAT=73 # can't create (user) output file
EX_IOERR=74 # input/output error
EX_TEMPFAIL=75 # temp failure; user is invited to retry
EX_PROTOCOL=76 # remote error in protocol
EX_NOPERM=77 # permission denied
EX_CONFIG=78 # configuration error
have_command () {
command -v "$1" >/dev/null 2>/dev/null
}
if have_command tput; then
TXT_NORMAL=$(tput sgr0)
TXT_BOLD=$(tput bold)
TXT_DIM=$(tput dim)
TXT_STANDOUT=$(tput smso)
TXT_BLACK=$(tput setaf 0)
TXT_BLUE=$(tput setaf 4)
TXT_CYAN=$(tput setaf 6)
TXT_GREEN=$(tput setaf 2)
TXT_MAGENTA=$(tput setaf 5)
TXT_RED=$(tput setaf 1)
TXT_WHITE=$(tput setaf 7)
TXT_YELLOW=$(tput setaf 3)
TXT_NOCOLOR=$(tput op)
else
TXT_NORMAL=''
TXT_BOLD=''
TXT_DIM=''
TXT_STANDOUT=''
TXT_BLACK=''
TXT_BLUE=''
TXT_CYAN=''
TXT_GREEN=''
TXT_MAGENTA=''
TXT_RED=''
TXT_WHITE=''
TXT_YELLOW=''
TXT_NOCOLOR=''
fi
die () {
rc="$1"
shift
(
echo -n "${TXT_RED}${TXT_BOLD}$me: ERROR:${TXT_NOCOLOR} ";
if [ $# -gt 0 ]; then echo "$@"; else cat; fi
echo -n "${TXT_NORMAL}"
) 1>&2
exit $rc
}
warn () {
(
echo -n "$me: ${TXT_YELLOW}WARNING:${TXT_NOCOLOR} ";
if [ $# -gt 0 ]; then echo "$@"; else cat; fi
) 1>&2
}
require_command () {
if ! have_command "$1"; then
die 1 "Could not find required command '$1' in system PATH. Aborting."
fi
}
## main
if ! have_command docker; then
cat <<__EOF__
${TXT_BOLD}${TXT_YELLOW}${me} requires the 'docker' command,
which could not be found on \$PATH${TXT_NOCOLOR}${TXT_NORMAL}
I can now try to install Docker; this requires the 'sudo' command with
unrestricted administrative access. If you do not have administrative
access to this machine, please ask your system administrator to
install Docker.
To know more about Docker, visit http://www.docker.com/
${TXT_BOLD}Press Ctrl+C now to abort, or Enter/Return to try installing Docker.${TXT_NORMAL}
__EOF__
read _
# work in a temporary directory
require_command mktemp
tmpdir=$(mktemp -d -t)
if [ -z "$tmpdir" ]; then
die $EX_CANTCREAT "Cannot create temporary download directory. Aborting."
fi
orig_wd="$PWD"
trap "cd '$orig_wd'; rm -rf '$tmpdir';" EXIT TERM ABRT INT QUIT
cd "$tmpdir"
if have_command wget; then
wget -nv -O get-docker.sh https://get.docker.com
elif have_command curl; then
curl -fsSL get.docker.com -o get-docker.sh
else
die $EX_UNAVAILABLE <<__EOF__
Docker installation requires either the 'wget' or the 'curl' commands,
and none is available. Aborting.
Please install either 'wget' or 'curl'.
__EOF__
fi
# run Docker installation
if have_command sudo; then
sudo /bin/sh get-docker.sh
if [ $? -ne 0 ]; then
die $EX_NOPERM "Failed to install Docker. Cannot continue."
fi
elif have_command su; then
su -c "/bin/sh $PWD/get-docker.sh"
if [ $? -ne 0 ]; then
die $EX_NOPERM "Failed to install Docker. Cannot continue."
fi
else
die $EX_UNAVAILABLE <<__EOF__
Docker installation requires either the 'sudo' or the 'su' commands,
and none is available. Aborting.
Please ask your system administrator to install Docker.
__EOF__
fi
cd "$orig_wd"
fi
# docker should have been installed by now...
require_command egrep
require_command env
require_command docker
require_command readlink
# check if `env` supports the `--null` flag
if (env -0 >/dev/null 2>&1); then
env_has_null_termination_opt='y'
require_command awk
else
env_has_null_termination_opt='n'
warn <<__EOF__
Command 'env' does not support null-terminated lines;
$(basename $me) cannot properly sanitize the environment in this case.
If you get errors later on about Docker being unable to process environment
variables, you will need to install GNU coreutils' 'env'.
__EOF__
fi
# set up mount commands for host directories
volumes="-v $HOME/.ssh:/home/.ssh -v $HOME/.elasticluster:/home/.elasticluster"
if [ -n "$SSH_AUTH_SOCK" ]; then
volumes="${volumes} -v $SSH_AUTH_SOCK:/home/.ssh-agent.sock"
fi
if [ -d "$HOME/.config" ]; then
volumes="${volumes} -v $HOME/.config:/home/.config"
fi
usage () {
# show ElastiCLuster's main help
docker run --rm --tty "${docker_image_name}:${docker_image_tag}" --help
# add post-scriptum
cat <<EOF
In addition, the following options can be used to control execution of
ElastiCluster in Docker:
--update
Update Docker image to the latest version available
--release TAG
Use the Docker image with the given TAG (default tag: "latest")
--latest
Same as '--update --release latest'
EOF
}
# parse command-line for additional options
argv=''
while [ $# -gt 0 ]; do
case "$1" in
--config|-c)
# canonicalize path to avoid Docker error: "create .:
# volume name is too short, names should be at least two
# alphanumeric characters." (e.g., when path is `.`)
cfgpath=$(readlink -f "$2")
volumes="${volumes} -v ${cfgpath}:/mnt/config"
argv="$argv --config /mnt/config"
shift
;;
--help|-h)
usage;
exit 0
;;
--latest)
pull='yes'
docker_image_tag='latest'
;;
--release)
docker_image_tag="$2"
shift
;;
--update|--pull)
pull='yes'
;;
*)
argv="$argv $1"
;;
esac
shift
done
# put args back for elasticluster python to interpret
set -- $argv
# pull (update) Docker image
elasticluster_docker_image="${docker_image_name}:${docker_image_tag}"
if [ "$pull" = 'yes' ]; then
docker pull "$elasticluster_docker_image"
fi
# cannot run as root, as mountpoints within the Docker image would be
# in the wrong place
if [ $(id -u) -eq 0 ]; then
die $EX_SOFTWARE <<__EOF__
Cannot run as 'root' user: please run ElastiCluster with a normal,
unprivileged user. (But ensure this user has permission to start
and access Docker containers; typically this means being part of
the 'docker' group.)
__EOF__
fi
# cannot run `sftp` in a Docker container
for arg in "$@"; do
if [ "$arg" = 'sftp' ]; then
die $EX_SOFTWARE <<__EOF__
ElastiCluster's 'sftp' command cannot be run in a Docker container.
Please see https://github.com/elasticluster/elasticluster/issues/576
for an explanation and possible workarounds.
__EOF__
fi
done
# ensure mount points exist
for dir in "$HOME/.ssh" "$HOME/.elasticluster"; do
test -d "$dir" || mkdir -v "$dir"
done
# prepare environment to export to Docker
# (necessary e.g. to preserve OpenStack auth)
envfile=$(mktemp -t elasticluster.XXXXXXXXXXXX.env)
if [ -z "$envfile" ]; then
die 1 "Cannot create temporary file."
fi
trap "rm -f '$envfile';" EXIT INT QUIT ABRT TERM
if [ "$env_has_null_termination_opt" = 'y' ]; then
# The following incantation requires some explanation:
#
# * line (1) `env` is to override some environment variables with
# values that are appropriate *within* the container;
#
# * line (2) is for filtering out multi-line env vars,
# which `docker run --env-file` cannot currently handle
# (see https://stackoverflow.com/a/19156442/459543 and
# issue #675 if the `awk` code looks overcomplicated);
#
# * line (3) `egrep -v` is for removing shell customization (e.g.,
# bash/zsh themes with multiline prompts)
#
env -0 HOME="$HOME" SHELL=/bin/sh SSH_AUTH_SOCK=/home/.ssh-agent.sock \
| awk 'BEGIN { RS="\0"; FS="="; OFS="="; }; { n=index($0, "="); $2=substr($0, n+1); NF=2; if ($2 !~ /\n/) print; };' \
| egrep -v '^(BASH_ENV|ENV|PROMPT_COMMAND|PS[1234])=' \
> "$envfile"
else
env HOME="$HOME" SHELL=/bin/sh SSH_AUTH_SOCK=/home/.ssh-agent.sock \
| egrep -v '^(BASH_ENV|ENV|PROMPT_COMMAND|PS[1234])=' \
> "$envfile"
fi
# go!
exec docker run --rm --interactive --tty --env-file "$envfile" $volumes $elasticluster_docker_image "$@"