-
Notifications
You must be signed in to change notification settings - Fork 1
/
entrypoint.sh
executable file
·589 lines (460 loc) · 13.2 KB
/
entrypoint.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
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
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
#!/bin/bash
# Handles the subcommands for this container
main () {
case $1 in
upgrade)
shift
check_env
upgrade "$@"
;;
finish)
shift
check_env
finish "$@"
;;
rollback)
shift
check_env
rollback "$@"
;;
rancher)
shift
check_env
rancher "$@"
;;
test)
shift
_test "$@"
;;
help)
shift
_help "$@"
;;
"bash")
shift
_bash "$@"
;;
*)
# Default to displaying our help
_help
;;
esac
}
###################
# Command functions
###################
# Runs a service upgrade command with helpers
upgrade () {
local cmd
local confirm_upgrade
local docker_image
local docker_tag
local environment
local host
local output
local services
local stack
info "Upgrading $* ..."
# Command argument format
# upgrade [confirm] <environment> <stack> <tag> <service> [service...]
# upgrade --confirm-upgrade Staging Emu master client me-node-api
# upgrade Staging Emu master client me-node-api
# Check for the "--confirm" flag for automatically finishing the upgrade
confirm_upgrade=$1
if [[ "$confirm_upgrade" == "--confirm-upgrade" ]]; then
shift
else
confirm_upgrade=""
fi
# Get our environment
get_environment "$1"
environment="$RANCHER_ENVIRONMENT"
shift
# Get our stack
get_stack "$1"
stack="$RANCHER_STACK"
shift
# Get our tag
check_arg "$1"
docker_tag=$1
shift
# Get our service list
get_services "$*"
services="$RANCHER_SERVICES"
# Make sure the services are all in an active state
check_service_states active "$services"
# Get the Rancher *-compose files
get_config "$stack"
# Find a host
host=$(rancher host -q | head -1)
debug
debug "Host ID: $host"
if [[ -z "$host" ]]; then
error "Host not found"
fi
# local pids
# pids="" # For storing backgrounded process pids
declare -A pids
docker_image=""
# debug "$(cat docker-compose.yml)"
# Iterate services and check for the image tag existing by pulling to a
# Rancher host
for service in $services; do
check_arg "$service"
# debug "Checking $service"
cmd="yaml r docker-compose.yml services.$service.image"
output=$($cmd)
debug "$output"
if [[ "$output" == "null" ]]; then
error "Service not found: $service"
fi
# Modify the image with the new tag
local image
image=${output%%:*}
image="$image:$docker_tag"
docker_image+=" $image"
# Write the new image to the compose yaml
debug "Writing $image to docker-compose.yml"
yaml w -i docker-compose.yml "services.$service.image" "$image"
info "Pulling $image"
# This command requires docker login inside the container
cmd="rancher --host $host docker pull $image"
# Handle backgrounded or inline output appropriately
if [[ -n "$DEBUG" ]]; then
# Run inline with full output
if $cmd; then
success "$image: Image verified"
else
error "$image: Image error"
fi
else
# Background and suppress output
$cmd &>/dev/null &
pids[$!]="$image"
fi
done
# Wait on backgrounded pull processes
for pid in "${!pids[@]}"; do
if wait "$pid"; then
success "${pids[$pid]}: Image verified"
else
error "${pids[$pid]}: Image error"
fi
done
debug
debug "Settings found:"
debug "$(cat <<EOF
environment="$environment"
stack="$stack"
docker_image="$docker_image"
docker_tag="$docker_tag"
services="$services"
confirm_upgrade="$confirm_upgrade"
EOF
)"
info "Upgrading $services"
if [[ -n "$confirm_upgrade" ]]; then
info " ... and automatically finishing upgrade"
fi
# shellcheck disable=SC2086
rancher up -d --pull --upgrade --force-upgrade $confirm_upgrade \
--stack "$stack" $services
if [[ $? -ne 0 ]]; then
error "Upgrade failed"
fi
success "Upgrade successful"
exit 0
}
finish () {
local environment
local services
local stack
info "Finishing upgrade for $*"
# Get our environment
get_environment "$1"
environment="$RANCHER_ENVIRONMENT"
shift
# Get our stack
get_stack "$1"
stack="$RANCHER_STACK"
shift
# Get the remaining arguments as service names
check_arg "$1"
services=$*
# Make sure that we have services specified
if [[ -z "$services" ]]; then
error "Missing required argument: services"
fi
# Make sure the services are all in an upgraded state
check_service_states upgraded "$services"
# Get the Rancher *-compose files
get_config "$stack"
# Parse all the services and output their images
debug
debug "CURRENT IMAGES"
for service in $services; do
output=$(yaml r docker-compose.yml "services.$service.image")
debug "$service $output"
done
debug
info "Finish upgrade for $stack/$services"
# shellcheck disable=SC2086
rancher up -d --confirm-upgrade --stack "$stack" $services
if [[ $? -ne 0 ]]; then
error "Finish failed"
fi
success "Finish successful"
exit 0
}
rollback () {
local environment
local services
local stack
info "Rolling back $*"
# Get our environment
get_environment "$1"
environment="$RANCHER_ENVIRONMENT"
shift
# Get our stack
get_stack "$1"
stack="$RANCHER_STACK"
shift
# Get the remaining arguments as service names
check_arg "$1"
services=$*
# Make sure that we have services specified
if [[ -z "$services" ]]; then
error "Missing required argument: services"
fi
# Make sure the services are all in an upgraded state
check_service_states upgraded "$services"
# Get the Rancher *-compose files
get_config "$stack"
# Parse all the services and output their images
debug
debug "CURRENT IMAGES"
for service in $services; do
output=$(yaml r docker-compose.yml "services.$service.image")
debug "$service $output"
done
debug
info "Rolling back $stack/$services"
# shellcheck disable=SC2086
rancher up -d --rollback --stack "$stack" $services
if [[ $? -ne 0 ]]; then
error "Rollback failed"
fi
success "Rollback successful"
# If we got this far, output the images again
# Get the rolled back Rancher *-compose files
get_config "$stack"
# Parse all the services and output their images, again
echo
echo "ROLLBACK IMAGES"
for service in $services; do
output=$(yaml r docker-compose.yml "services.$service.image")
echo "$service $output"
done
echo
exit 0
}
_bash () {
# Create a useful bash prompt when we get into the container
debug "Setting PS1 for bash shell"
export PS1="rancher-${RANCHER_CLI_VERSION} \\$ "
# Symlink in the development version of the entrypoint script if it exists
if [[ -f "/usr/local/src/rancher-client/entrypoint.sh" ]]; then
debug "Mounting development entrypoint script"
ln -sf /usr/local/src/rancher-client/entrypoint.sh \
/usr/local/bin/entrypoint
fi
debug "Launching bash shell"
/bin/bash "$@"
}
# Run tests on this container
_test () {
echo "> $(green "0 tests passed")"
exit 0
}
# Show help and exit
_help () {
# XXX: Individual command help instead of link to docs.
cat << EOF
Usage: entrypoint.sh <upgrade|rollback|rancher|test|help|bash> [options]
upgrade Upgrade a service to a new image tag
rollback Roll back a service in an upgraded state
rancher Run commands directly using the Rancher CLI
help Display this help
bash Drop into a bash shell
test Run the test suite
Read the docs at https://github.com/aboutdotme/rancher-client/ for more details.
EOF
exit 0
}
##################
# Helper functions
##################
# Helper function to confirm that the Rancher CLI will have the information it
# needs to connect to a Rancher server and do things
check_env () {
# Check for docker authentication
# Uncommenting these is insecure since it would output these to logs, which
# can be vulnerable
# debug "$(cat "$HOME/.docker/config.json" 2>/dev/null)"
if [[ ! -f "$HOME/.docker/config.json" ]]; then
error "Missing docker login"
else
debug "Found Docker credentials"
fi
# Check if we have a cli.json mounted into the container
# debug "$(cat "$HOME/.rancher/cli.json" 2>/dev/null)"
if [[ -f "$HOME/.rancher/cli.json" ]]; then
debug "Found Rancher credentials"
return
fi
# Otherwise check we have all the environment variables we need
if [[ -z "$RANCHER_URL" ]]; then
error "Missing required environment variable: RANCHER_URL"
fi
if [[ -z "$RANCHER_ACCESS_KEY" ]]; then
error "Missing required environment variable: RANCHER_ACCESS_KEY"
fi
if [[ -z "$RANCHER_SECRET_KEY" ]]; then
error "Missing required environment variable: RANCHER_SECRET_KEY"
fi
# if [[ -z "$RANCHER_ENVIRONMENT" ]]; then
# error "Missing required environment variable: RANCHER_ENVIRONMENT"
# fi
}
# Make sure an argument is not a --param instead
check_arg () {
local arg=${1:-}
if [[ ${arg:0:1} == "-" ]]; then
error "Invalid argument: $arg"
fi
}
# Get the environment from the passed args
get_environment () {
# Check that we have all the arguments we need
check_arg "$1"
environment=$1
shift
# Check if this environment is real
output=$(rancher environment ls --format "{{.Environment.Name}}")
debug
debug "Environments found:"
debug "$output"
if ! (echo "$output" | grep "^${environment}$" &>/dev/null); then
error "Environment not found: $environment"
fi
# We can't use the environment name, we need to use the ID it maps to, so
# do this magic to get that.
id=$(rancher env | grep $environment | awk '{ print $1 }')
# Check if the environment ID exists
if ! (echo "$id"); then
error "Environment ID not found: $environment"
fi
debug "Found id: $id for environment: $environment"
# Set the environment
# shellcheck disable=SC2034
RANCHER_ENVIRONMENT="$id"
}
get_stack () {
check_arg "$1"
stack=$1
shift
# Check if the stack is real
output=$(rancher stacks ls --format "{{.Stack.Name}}")
debug
debug "Stacks found:"
debug "$output"
if ! (echo "$output" | grep "^${stack}$" &>/dev/null); then
error "Stack not found: $environment/$stack"
fi
# Set the stack
# shellcheck disable=SC2034
RANCHER_STACK="$stack"
}
check_service_states () {
local services
local stack
local state
# Get our state from args
state="$1"
shift
# Get our services from args
services="$*"
if [[ -z "$RANCHER_STACK" ]]; then
error "Rancher stack name not set"
fi
stack="$RANCHER_STACK"
debug
debug "Service states:"
# Iterate services and make sure that all of them are in an upgraded state
for service in $services; do
output=$(rancher inspect --format '{{.state}}' "$stack/$service")
debug "$service: $output"
if [[ "$output" != "$state" ]]; then
error "$stack/$service is not '$state' state, got '$output'"
fi
done
}
get_services () {
local services
# All these args should be services
services="$*"
# Make sure that we have services specified
if [[ -z "$services" ]]; then
error "Missing required argument: services"
fi
# Make sure someone didn't try to pass a param as a service
for service in $services; do
check_arg "$service"
done
export RANCHER_SERVICES="$services"
}
get_config () {
local stack
stack="$1"
# Pull the Rancher config from the API
info "Retrieving Rancher configuration"
rancher export "$stack"
if [[ $? -ne 0 ]]; then
error "Rancher export failed"
fi
# Move the config files into the current directory
mv "$stack"/* .
rmdir "$stack"
}
# Display informative things
info () {
blue "${1:-}"
echo
}
# Display informative things
success () {
drk_green "${1:-}"
echo
}
# Display an angry error message then give up and quit like a baby
error () {
red "${1:-}"
echo
exit 1
}
# Debug output
debug () {
# Only output if we have the debug environment variable set
if [[ -z "$DEBUG" ]]; then return; fi
cyan "${*:-}"
echo
}
# Colors
red () { printf "\033[1;31m%s\033[0m" "$*"; }
pink () { printf "\033[1;35m%s\033[0m" "$*"; }
blue () { printf "\033[1;34m%s\033[0m" "$*"; }
green () { printf "\033[1;32m%s\033[0m" "$*"; }
drk_green () { printf "\033[0;32m%s\033[0m" "$*"; }
cyan () { printf "\033[0;36m%s\033[0m" "$*"; }
# Start the main program
main "$@"