-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdidxInclude.sh
897 lines (872 loc) · 33.5 KB
/
didxInclude.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
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
###############################################################################
##
##
## Purpose:
## Define trap processing. Traps will destroy the server and client when
## an unexpected failure occurs.
##
###############################################################################
declare TRAP_SERVER_NAME
declare TRAP_CLIENT_NAME
trap_server_Destroy(){
container_Destroy "$TRAP_SERVER_NAME"
}
trap_server_destroy_Set(){
TRAP_SERVER_NAME="$1"
trap 'trap_server_Destroy' EXIT
}
trap_server_client_Destroy(){
container_Destroy "$TRAP_CLIENT_NAME"
container_Destroy "$TRAP_SERVER_NAME"
}
trap_server_client_destroy_Set(){
TRAP_SERVER_NAME="$1"
TRAP_CLIENT_NAME="$2"
trap 'trap_server_client_Destroy' EXIT
}
trap_Off(){
trap - EXIT
}
###########################################################################
##
## Purpose:
## Assign simple, single valued bash variable references a value.
##
## Input:
## $1 - Variable name to a single valued bash variable.
## $2 - The value to assign to this variable.
##
## Output:
## $1 - Variable assigned value provided by $2.
##
###########################################################################
ref_simple_value_Set(){
eval $1=\"\$2\"
}
###########################################################################
##
## Purpose:
## Obtain the storage driver used by the docker instance that will
## execute this script's docker commands.
##
## Input:
## $1 - Variable name to accept the storage driver name.
##
## Output:
## $1 - Variable assigned the storage driver name displayed by 'docker info.'
##
###########################################################################
docker_stg_driver_Get(){
local -r stgDrvr_ref="$1"
local -r NameRegex='[a-zA-Z0-9][a-zA-Z0-9_.-]*'
if ! [[ $( docker info 2>/dev/null ) =~ Storage.Driver:[[:space:]]*($NameRegex) ]]; then
ScriptUnwind "$LINENO" "Unable to identify 'Storage Driver:' value from 'docker info' command."
fi
ref_simple_value_Set "$stgDrvr_ref" "${BASH_REMATCH[1]}"
}
##############################################################################
##
## Purpose:
## see VirtCmmdInterface.sh -> VirtCmmdArgumentsParse
##
## Override usual implementation to define repeatable option:
## --cp.
##
###############################################################################
function VirtCmmdArgumentsParse () {
local -r -a ucpOptRepeatList=( '--cp' '-v' )
ArgumentsParse "$1" "$2" "$3" 'ucpOptRepeatList'
}
##############################################################################
##
## Purpose:
## see VirtCmmdInterface.sh -> VirtCmmdConfigSetDefault
##
## Override usual implementation to define repeatable option:
## --cp.
##
###############################################################################
VirtCmmdConfigSetDefault(){
DOCKER_LOCAL_REPRO_PATH='/var/lib/docker'
#TODO refactor the following regex into own module.
REG_EX_REPOSITORY_NAME_UUID='^([a-z0-9]([._-]?[a-z0-9]+)*/)*(sha256:)?[a-z0-9]([a-z0-9._-]+)*(:[A-Za-z0-9._-]*)?'
REG_EX_CONTAINER_NAME_UUID='^[a-zA-Z0-9][a-zA-Z0-9_.-]*'
STATUS_TERM_DSTRY='terminated & destroyed'
true
}
##############################################################################
##
## Purpose:
## see VirtCmmdInterface.sh -> VirtCmmdHelpDisplay
##
###############################################################################
VirtCmmdHelpDisplay(){
local stgDrvrDefault
docker_stg_driver_Get 'stgDrvrDefault'
local -r stgDrvrDefault
cat <<HELP_DOC
Usage: didx.sh [OPTIONS] {| COMMAND [COMMAND] ...}
COMMAND - Command executed within context of Docker in Docker (dind)
client container.
Use local Docker Engine to run a Docker Engine container cast as the "server".
Once started, run second Docker Engine container cast as the "client". After
the client starts, copy or mount zero or more files into the client's
file system then execute one or more COMMANDS within the client container.
The server container's local repository is encapsulated as a data volume
attached to only this server. This configuration isolates image and container
storage from the repository used by the Docker Engine server initiating
this script.
OPTIONS:
--sv Docker server version. Defaults to most recent
stable (public) Docker Engine version. Click
https://hub.docker.com/r/library/docker/tags/ to
view supported versions.
--cv Docker client version. Defaults to --sv value.
-p,--pull=false Perform explicit docker pull before running server/client.
--cp[] Copy files from source location into container running
Docker client. (Optional)
Format: <SourceSpec>:<AbsoluteClientContainerPath>
<SourceSpec>-><hostFilePath>
<SourceSpec>-><stream>->-
<SourceSpec>->{<containerName>|<UUID>}:<AbsoluteContainerPath>
<SourceSpec>->{<imageName>[:<tag>]|<UUID>}::<AbsoluteImagePath>
'docker cp' used when <SourceSpec> referrs to host file or
input stream. Otherwise, when source refers to
container or image, cp performed by 'dkrcp'.
-v[] Mount host file system references or create an anynomous
volume in the container running Docker client. (Optional)
Format: [{<HostFilePath>|<VolumeFilePath>}:]<AbsoluteClientContainerPath>
'docker run -v' option used to implement mount.
--clean=none After executing all COMMANDs, sanitize environment. Note
if an option value preserves the server's data volume,
you must manually delete it using the -v option when
removing the server's container.
none: Leave server & client containers running
in background. Preserve server data volume.
success: When all COMMANDs succeed, terminate and
remove server & client containers.
Delete server data volume.
failure: When at least one COMMAND fails, terminate
and remove server & client containers
Delete server data volume.
anycase: Regardless of COMMAND exit code, terminate
and remove server, client containers.
Delete server data volume.
all: Remove all server, client containers from
local repository. If necessary, terminate
running instances.
Delete all server data volumes.
rpt: List all server & client containers then exit.
-s,--storage-driver=$stgDrvrDefault Docker storage driver name. Determines method
applied to physically represent and manage images and
containers stored locally by the Docker server container.
Value defaults to the one utilized by the Docker instance
managing the Docker server container.
--dkropts Other Docker Engine startup options enclosed in quotes to
apply to Docker server.
--cv-env=DIND_CLIENT_NAME Environment variable name which contains the Docker client's
container name. Use in COMMAND to identify client container.
-h,--help=false Don't display this help message.
--version=false Don't display version info.
For more help: https://github.com/WhisperingChaos/didx/blob/master/README.md#didx
HELP_DOC
}
##############################################################################
##
## Purpose:
## see VirtCmmdInterface.sh -> VirtCmmdVersionDisplay
##
###############################################################################
VirtCmmdVersionDisplay(){
cat <<VERSION_DOC
Version : 0.5
Requires: bash 4.0+, Docker Client
Issues : https://github.com/WhisperingChaos/dkind/issues
License : The MIT License (MIT) Copyright (c) 2016-2017 Richard Moyse [email protected]
VERSION_DOC
}
###############################################################################
##
## Purpose:
## see VirtCmmdInterface.sh -> VirtCmmdOptionsArgsDef
##
###############################################################################
VirtCmmdOptionsArgsDef(){
local stgDrvrDefault
docker_stg_driver_Get 'stgDrvrDefault'
local -r stgDrvrDefault
# optArgName cardinality default verifyFunction presence alias
cat <<OPTIONARGS
ArgN single '' '' optional
--sv single 'latest' '' required
--cv single '' '' optional
--pull single false=EXIST=true "OptionsArgsBooleanVerify '\\<--pull\\>'" required "-p"
--storage-driver single '$stgDrvrDefault' '' required "-s"
--cv-env single 'DIND_CLIENT_NAME' "option_envName_Verify '\\<--cv-env\\>'" required
--cp=N single '' "option_cp_format_Verify '\\<--cp=N\\>'" optional
-v=N single '' "option_volume_format_Verify '\\<-v=N\\>'" optional
--dkropts single '' '' optional
--clean single 'none' "option_clean_Verify '\\<--clean\\>'" required
--help single false=EXIST=true "OptionsArgsBooleanVerify '\\<--help\\>'" required "-h"
--version single false=EXIST=true "OptionsArgsBooleanVerify '\\<--version\\>'" required
OPTIONARGS
}
###############################################################################
##
## Purpose:
## Verify environment variable name conforms to Bash standard.
##
## Inputs:
## $1 - Bash environment variable name.
##
## Return Code:
## When Success:
## Nothing.
## When Failure:
## Write error reason to STDERR.
##
###############################################################################
option_envName_Verify(){
local -r envName="$1"
local -r envNameDef='^[a-zA-Z_]+[a-zA-Z0-9_]*$'
if ! [[ $envName =~ $envNameDef ]]; then
ScriptError "Environment name: '$envName' must conform to: '$envNameDef'."
fi
}
###############################################################################
##
## Purpose:
## Verify target-source specification for cp.
##
## Inputs:
## $1 - target-source specification.
##
## Return Code:
## When Success:
## Nothing.
## When Failure:
## Write error reason to STDERR.
##
###############################################################################
option_cp_format_Verify(){
local srcSpec
local trgSpec
cp_srcTrg_Seperate "$1" 'srcSpec' 'trgSpec'
}
###############################################################################
##
## Purpose:
## Verify target-source specification for mounting volumes.
##
## Inputs:
## $1 - target-source specification.
##
## Return Code:
## When Success:
## Nothing.
## When Failure:
## Write error reason to STDERR.
##
###############################################################################
option_volume_format_Verify(){
local -r volumeSpec='^(.+):(/.*)|(/.*)'
if ! [[ $1 =~ $volumeSpec ]]; then
ScriptError "Volume specification: '$1' fails to conform to: '$volumeSpec'."
fi
}
###############################################################################
##
## Purpose:
## Verify --clean option values.
##
## Inputs:
## $1 - Clean option value.
##
## Return Code:
## When Success:
## Nothing.
## When Failure:
## Write error message to STDERR and exit.
##
###############################################################################
option_clean_Verify(){
case $1 in
none|success|failure|anycase|all|rpt)
true
;;
*)
ScriptError "Expected --clean values: 'none|success|failure|anycase|all|rpt', encountered: '$1'."
;;
esac
}
###############################################################################
##
## Purpose:
## Start Docker Engine server and client containers. Run specified
## commands in context of client container. Determine exit status and
## clean up according to --clean option.
##
## Input:
## $1 - Variable name representing the array of all options
## and arguments names in the order encountered on the command line.
## $2 - Variable name representing an associative map of all
## option and argument values keyed by the option/argument names.
##
###############################################################################
VirtCmmdExecute(){
local -r optArgLst_ref="$1"
local -r optArgMap_ref="$2"
# clean all directive short circuits general functionality
local cleanDirective
AssociativeMapAssignIndirect "$optArgMap_ref" '--clean' 'cleanDirective'
local -r cleanDirective
if [ "$cleanDirective" == 'all' ]; then
server_client_Iterate 'all' 'server_or_client_Destroy "$containerType" "$containerName"'
# terminate script
return
elif [ "$cleanDirective" == 'rpt' ]; then
server_client_Iterate 'all' 'dind_container_report "$containerType" "$containerName"'
# terminate script
return
fi
# obtain server version
local serverVersion
AssociativeMapAssignIndirect "$optArgMap_ref" '--sv' 'serverVersion'
# normalize server version so it's either 'latest' or typical version format by
# removing '[-]?dind' as the server must be some form of 'dind'
if [ "$serverVersion" == 'latest' ]; then
local -r stag='dind'
elif [ "$serverVersion" == 'dind' ]; then
local -r stag='dind'
serverVersion='latest'
elif [[ "$serverVersion" =~ (.+)-dind ]]; then
serverVersion="${BASH_REMATCH[1]}"
local -r stag="${serverVersion}-dind"
else
local -r stag="${serverVersion}-dind"
fi
# obtain server storage driver
local storageDriver
AssociativeMapAssignIndirect "$optArgMap_ref" '--storage-driver' 'storageDriver'
local -r storageDriver
# start the docker server
local -r serverName="dind_$$_server_${serverVersion}"
local dkopts
AssociativeMapAssignIndirect "$optArgMap_ref" '--dkropts' 'dkropts'
ScriptDebug "$LINENO" "--dkropts: $dkropts"
local -r dkopts
# need to pull fresh server and client
local dockerPull
AssociativeMapAssignIndirect "$optArgMap_ref" '--pull' 'dockerPull'
local -r dockerPull
if $dockerPull; then
if ! docker pull docker:$stag >/dev/null; then
ScriptUnwind "$LINENO" "Failed to pull Docker server image: 'docker:$stag'."
fi
fi
if ! eval docker run \-\-privileged \-d \-i \-t \-\-name \$serverName \-v \"\$DOCKER_LOCAL_REPRO_PATH\" docker:\$stag /usr/local/bin/dockerd-entrypoint.sh \-\-storage-driver\=\$storageDriver $dkropts >/dev/null; then
ScriptUnwind "$LINENO" "Failed to start Docker server from image: 'docker:$stag', with container name: '$serverName'."
fi
# set trap to destroy when something unexpected happens.
trap_server_destroy_Set "$serverName"
# generate mount, -v, options if specified.
local -r mtOptFilter='[[ $optArg =~ ^-v=[1-9][0-9]*$ ]]'
local -a mtOptLst
local -A mtOptMap
if ! OptionsArgsFilter "$optArgLst_ref" "$optArgMap_ref" 'mtOptLst' 'mtOptMap' "$mtOptFilter" 'true'; then
ScriptUnwind "$LINENO" "Problem filtering volume options."
fi
local mtClientOpts
mt_options_Gen 'mtOptLst' 'mtOptMap' 'mtClientOpts'
local -r mtClientOpts
# determine client tag
local ctag
AssociativeMapAssignIndirect "$optArgMap_ref" '--cv' 'ctag'
if [ -z "$ctag" ]; then ctag="$serverVersion"; fi
local -r ctag
if $dockerPull; then
if ! docker pull docker:$ctag >/dev/null; then
ScriptUnwind "$LINENO" "Failed to pull Docker client image: 'docker:$ctag'."
fi
fi
# start Docker client
local -r clientName="dind_$$_client_${ctag}"
if ! eval docker run \-d \-i \-t $mtClientOpts \-\-name \$clientName \-\-link \$\{serverName\}:docker docker:\$ctag >/dev/null; then
ScriptUnwind "$LINENO" "Failed to start Docker client from image: 'docker:$ctag', with container name: '$clientName'."
fi
server_client_report "$serverName" "$clientName" 'successfully started'
# set trap to destroy both server and client when something unexpected happens.
trap_server_client_destroy_Set "$serverName" "$clientName"
# establish value for environment variable referenced by COMMANDs that
# will resolve to Docker client container name.
local clientName_ref
AssociativeMapAssignIndirect "$optArgMap_ref" '--cv-env' 'clientName_ref'
local -r clientName_ref
ref_simple_value_Set "$clientName_ref" "$clientName"
# create cp argument map by filtering cli options.
local -r cpOptFilter='[[ $optArg =~ ^--cp=[1-9][0-9]*$ ]]'
local -a cpOptLst
local -A cpOptMap
if ! OptionsArgsFilter "$optArgLst_ref" "$optArgMap_ref" 'cpOptLst' 'cpOptMap' "$cpOptFilter" 'true'; then
ScriptUnwind "$LINENO" "Problem filtering cp arguments."
fi
# perform cp operation before executing commands as the files may represent
# scripts that will be executed in context of Docker client.
cp_Perform 'cpOptLst' 'cpOptMap' "$clientName"
# create command map by filtering cli arguments.
local -r cmmdArgFilter='[[ $optArg =~ ^Arg[1-9][0-9]*$ ]]'
local -a cmmdArgLst
local -A cmmdArgMap
if ! OptionsArgsFilter "$optArgLst_ref" "$optArgMap_ref" 'cmmdArgLst' 'cmmdArgMap' "$cmmdArgFilter" 'true'; then
ScriptUnwind "$LINENO" "Problem filtering command arguments."
fi
command_Execute 'cmmdArgLst' 'cmmdArgMap' "$clientName_ref"
local -r rtn_code="$?"
# eliminate trap
trap_Off
server_client_Clean "$serverName" "$clientName" "$cleanDirective" "$rtn_code"
# exit with the return code of the last COMMAND
return $rtn_code
}
###########################################################################
##
## Purpose:
## Generate docker host volume option.
##
## Input:
## $1 - Array variable name of ordered volume keys '-v1','-v2','-v3',... .
## $2 - Map variable name of -vN keys specified in $1 associated to
## to their volume specifier.
## $3 - Variable name to assign generated docker run -v option syntax.
##
###########################################################################
mt_options_Gen(){
local -r mtOptLst_ref="$1"
local -r mtOptMap_ref="$2"
local -r mtClientOpts_ref="$3"
local mtPath
local mtPathComplete
eval set -- \$\{$mtOptLst_ref\[\@\]\}
while (( $# > 0 )); do
AssociativeMapAssignIndirect "$mtOptMap_ref" "$1" 'mtPath'
mtPathComplete+="-v '$mtPath' "
shift
done
ref_simple_value_Set "$mtClientOpts_ref" "$mtPathComplete"
}
###########################################################################
##
## Purpose:
## Copy one or more files/directories from some source, like host file
## system, to container running the Docker client.
##
## Input:
## $1 - List of ordered cp keys.
## $2 - Map of cp keys specified in $1 associated to source-target
## specification.
## $3 - Container name assigned to the Docker client.
##
###########################################################################
cp_Perform(){
local -r cpOptLst_ref="$1"
local -r cpOptMap_ref="$2"
local -r clientName="$3"
local sourceTargetSpec
local srcSpec
local trgSpec
local srcSpecType
local dkrcpExist='false'
local dkrcpName
if dkrcp_Exist 'dkrcpName'; then dkrcpExist='true'; fi
local -r dkrcpName
local -r dkrcpExist
eval set -- \$\{$cpOptLst_ref\[\@\]\}
while (( $# > 0 )); do
AssociativeMapAssignIndirect "$cpOptMap_ref" "$1" 'sourceTargetSpec'
cp_srcTrg_Seperate "$sourceTargetSpec" 'srcSpec' 'trgSpec'
if ! arg_type_format_decide "$srcSpec" 'srcSpecType'; then
ScriptUnwind "$LINENO" "Copy source: '$srcSpec' of unknown type."
fi
case $srcSpecType in
filepath|stream)
if ! docker cp "$srcSpec" "${clientName}:$trgSpec">/dev/null; then
ScriptUnwind "$LINENO" "Copy command failed: 'docker cp $srcSpec ${clientName}:$trgSpec'."
fi
;;
containerfilepath|imagefilepath)
if ! dkrcpExist; then
ScriptUnwind "$LINENO" "Source type: '$srcSpecType' for source spec: '$srcSpec' requires: 'dkrcp.sh'."
elif ! $dkrcpName "$srcSpecType" "${clientName}:$trgSpec"; then
ScriptUnwind "$LINENO" "Copy command failed: 'dkrcp $srcSpec ${clientName}:$trgSpec'."
fi
;;
*)
ScriptUnwind "$LINENO" "Copy source: '$srcSpec' doesn't exist or of unknown type: '$srcSpecType'."
;;
esac
shift
done
}
###########################################################################
##
## Purpose:
## Determine if dkrcp exists and command name.
##
## Input:
## $1 - Variable name to return command name.
##
## Output:
## When success:
## $1 - Reflects name of dkrcp command.
##
###########################################################################
dkrcp_Exist(){
local dkrcpNm_ref="$1"
if dkrcp --version 2>/dev/null | grep 'Moyse'>/dev/null; then
ref_simple_value_Set "$dkrcpNm_ref" 'dkrcp'
elif dkrcp.sh --version 2>/dev/null | grep 'Moyse'>/dev/null; then
ref_simple_value_Set "$dkrcpNm_ref" 'dkrcp.sh'
else false
fi
}
###########################################################################
##
## Purpose:
## Extract source and target argument specifiers for copy operation.
##
## Input:
## $1 - Source-Target specification. Source cp reference separated
## from Target absolute path by colon (':'). Source part
## could reference files with host file, container, or image.
## $2 - Variable name to return source spec part.
## $3 - Variable name to return target spec part.
##
## Output:
## When success:
## $2 - updated to reflect
## STDERR - Abort message due to improper format of Source-Target specification.
## not redirected.
##
###########################################################################
cp_srcTrg_Seperate(){
local -r srcTrgSpec="$1"
local -r srcSpec_ref="$2"
local -r trgSpec_ref="$3"
# seperate source spec from target. Rely on regex greediness to include
# container, image reference in source part even when they include :/ or :
if [[ $srcTrgSpec =~ ^(.+):(/.*) ]] || [[ $srcTrgSpec =~ ^(.+):(.*) ]]; then
ref_simple_value_Set "$srcSpec_ref" "${BASH_REMATCH[1]}"
ref_simple_value_Set "$trgSpec_ref" "${BASH_REMATCH[2]}"
else
ScriptUnwind "$LINENO" "Copy source-target spec: '$srcTrgSpec' must encode a ':' immediately before its absolute target path. Ex: './hostfile:/targetLoc'."
fi
}
##############################################################################
#TODO refactor the fuction into own module.
##
## Purpose:
## Determine the argument type by examining its format.
##
## Input:
## $1 - A SOURCE or TARGET command line argument.
## $2 - A variable name to return the decided type.
##
## Output:
## When Success:
## $2 Reference assigned the decided type:
## 'stream', 'imagefilepath', 'containerimagefilepath', or 'filepath'.
##
###############################################################################
arg_type_format_decide() {
local -r arg="$1"
local -r typeName_ref="$2"
while true; do
if [ "$arg" == '-' ]; then
typeName='stream'
break
fi
if [ "${arg:0:1}" == '/' ] || [ "${arg:0:1}" == '.' ]; then
typeName='filepath'
break
fi
if [[ $arg =~ ${REG_EX_REPOSITORY_NAME_UUID}::.*$ ]]; then
typeName='imagefilepath'
break
fi
if [[ $arg =~ ${REG_EX_CONTAINER_NAME_UUID}:.*$ ]]; then
typeName='containerfilepath'
break
fi
if [ -n "$arg" ]; then
typeName='filepath'
break
fi
return 1
done
eval $typeName_ref\=\"\$typeName\"
}
###########################################################################
##
## Purpose:
## Execute one or more commands within the context of the Docker
## client.
##
## Input:
## $1 - List of keys identifying COMMANDs in order specified by the
## command line.
## $2 - Map of keys specified in $1, and their associated values.
##
## Output:
## STDOUT - Message indicating status of Docker server and client. Will
## also include messages generated by the COMMAND if not
## redirected.
## STDERR - Messages can include messages generated by the COMMMAND if
## not redirected.
##
## Return code set to first failed command or last succcessful one.
##
###########################################################################
command_Execute(){
local -r cmdArgLst_ref="$1"
local -r cmdArgMap_ref="$2"
local -r clientName_ref="$3"
# make selected variable name client name visible
eval local \-r clientName=\"\$$clientName_ref\"
local cmdTmplt
local cmdExec
local cmdRtnCd=0
eval set -- \$\{$cmdArgLst_ref\[\@\]\}
while (( $# > 0 )); do
AssociativeMapAssignIndirect "$cmdArgMap_ref" "$1" 'cmdTmplt'
eval local cmdExec=\"$cmdTmplt\"
if ! [[ $cmdExec =~ ^[[:space:]]*docker[[:space:]]+exec ]]; then
# ensure all commands begin with docker exec. If not
# user relies on script to add it with default exec option values.
cmdExec="docker exec $clientName docker-entrypoint.sh $cmdExec"
fi
if $cmdExec; then
ScriptInform "Command: '$cmdExec' successfully terminated."
else
cmdRtnCd="$?"
ScriptError "Command: '$cmdExec' failed with exit code: '$cmdRtnCd'. Terminating remaining commands."
break
fi
shift
done
return $cmdRtnCd
}
###########################################################################
##
## Purpose:
## When directed, destroy the Docker server and associated client.
##
## Input:
## $1 - Container name for dind server.
## $2 - Container name for client linked to dind server.
## $3 - Clean option value directing behavior after executing COMMANDs
## $4 - Last executed COMMAND return code.
##
## Output:
## STDOUT - Message indicating status of Docker server and client.
##
###########################################################################
server_client_Clean(){
local -r serverName="$1"
local -r clientName="$2"
local -r cleanDirective="$3"
local -r cmmdRtnCode="$4"
local remainsRunning='true'
case $cleanDirective in
none)
true
;;
success)
if [ "$cmmdRtnCode" -eq '0' ]; then
server_client_Destroy "$serverName" "$clientName" \
&& remainsRunning='false'
fi
;;
failure)
if [ "$cmmdRtnCode" -ne '0' ]; then
server_client_Destroy "$serverName" "$clientName" \
&& remainsRunning='false'
fi
;;
anycase)
server_client_Destroy "$serverName" "$clientName" \
&& remainsRunning='false'
;;
*)
ScriptError "Unknown clean directive: '$cleanDirective'."
;;
esac
local status="$STATUS_TERM_DSTRY"
if $remainsRunning; then
status='remains running'
fi
server_client_report "$serverName" "$clientName" "$status"
true
}
###########################################################################
##
## Purpose:
## Iterate over all containers whose name conforms to script generated
## dind server or client name and implements dind entry point name of
## dockerd-entrypoint.sh.
##
## Iterater terminates on first failure or all successful.
##
## Input:
## $1 - A filter pattern to select a subset or a proper superset
## of dind containers. Currently, 'all' simply selects every
## dind container.
## $2 - A function invocation whose parameters reverence
## '$containerType' and '$containerName'
##
###########################################################################
server_client_Iterate(){
local -r pattern="$1" # currently ignored
local -r funExec="$2"
local -r dindpatternClient='dind_[0-9]+_client_([0-9.rcegit-]+|latest)'
local -r dindpatternServer='dind_[0-9]+_server_([0-9.rce-]+|latest)'
local containerType
local containerName
local entryPoint
local rtnStatus=0
while [ "$rtnStatus" -eq '0' ] && read -r containerName; do
if [[ $containerName =~ ($dindpatternClient) ]]; then
containerType='client'
entryPoint='.*docker-entrypoint.sh'
elif [[ $containerName =~ ($dindpatternServer) ]]; then
containerType='server'
entryPoint='.*dockerd-entrypoint.sh'
else
# container name fails to match dind name generated by this script
continue
fi
containerName="${BASH_REMATCH[1]}"
if [[ $( docker inspect -f '{{ .Config.Entrypoint }}' $containerName 2>/dev/null; ) =~ $entryPoint ]]; then
# matches dind container pattern and entrypoint reflects dind signature
# pretty confident that's a dind container generated by this script.
eval $funExec;
rtnStatus="$?"
fi
done < <( docker ps -a )
}
###########################################################################
##
## Purpose:
## Destroy dind server and client.
##
## Input:
## $1 - Server container name.
## $2 - Client container name.
##
###########################################################################
server_client_Destroy(){
local -r serverName="$1"
local -r clientName="$2"
container_Destroy "$clientName" && container_Destroy "$serverName"
}
###########################################################################
##
## Purpose:
## Destroy dind server or client.
##
## Input:
## $1 - Container type: 'client' or 'server'
## $2 - Container name.
##
###########################################################################
server_or_client_Destroy(){
local -r containerType="$1"
local -r containerName="$2"
container_Destroy "$containerName" \
&& dind_Report "${containerType}" "$containerName" "$STATUS_TERM_DSTRY"
}
###########################################################################
##
## Purpose:
## Destroy container and it's repository. The dind server is always
## configured with an anonymous volume. Since the dind client accepts
## docker volume mounts (-v), specifying one or more anonymous volumes
## is possible, therefore, remove them if specified.
##
## Input:
## $1 - Container name.
##
###########################################################################
container_Destroy(){
docker stop "$1" > /dev/null \
&& docker rm -v "$1" > /dev/null
}
###########################################################################
##
## Purpose:
## Generate status report to STDOUT regarding dind server/client status.
##
## Input:
## $1 - Container name for dind server.
## $2 - Container name for dind client linked to dind server.
## $3 - Container status.
##
## Output:
## STDOUT - status message.
##
###########################################################################
server_client_report(){
local -r serverName="$1"
local -r clientName="$2"
local -r status="$3"
dind_Report 'server' "$serverName" "$status"
dind_Report 'client' "$clientName" "$status"
}
###########################################################################
##
## Purpose:
## Report on dind server or client.
##
## Input:
## $1 - Container type: 'client' or 'server'
## $2 - Container name.
##
###########################################################################
dind_container_report(){
local -r containerType="$1"
local -r containerName="$2"
dind_Report "${containerType}" "$containerName" "found"
}
###########################################################################
dind_Report(){
ScriptInform "dind $1 named: '$2' $3."
}
FunctionOverrideCommandGet
###############################################################################
#
# The MIT License (MIT)
# Copyright (c) 2016 Richard Moyse [email protected]
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################
#
# Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc.
# in the United States and/or other countries. Docker, Inc. and other parties
# may also have trademark rights in other terms used herein.
#
###############################################################################