-
Notifications
You must be signed in to change notification settings - Fork 57
/
pongo.sh
executable file
·1416 lines (1218 loc) · 40.2 KB
/
pongo.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
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
# use the "--debug" flag to debug this script; setting the "set -x" option
function globals {
# Project related global variables
PONGO_VERSION=2.14.0
local script_path
# explicitly resolve the link because realpath doesn't do it on Windows
script_path=$(test -L "$0" && readlink "$0" || echo "$0")
LOCAL_PATH=$(dirname "$(realpath "$script_path")")
if [[ -f "$KONG_TEST_PLUGIN_PATH/.pongo/pongorc" ]]; then
PONGORC_FILE=".pongo/pongorc"
elif [[ -f "$KONG_TEST_PLUGIN_PATH/.pongorc" ]]; then
# for backward compatibility
PONGORC_FILE=".pongorc"
else
PONGORC_FILE=".pongo/pongorc"
fi
# shellcheck disable=SC1090 # do not follow source
source "${LOCAL_PATH}/assets/set_variables.sh"
DOCKER_FILE=${PONGO_DOCKER_FILE:-$LOCAL_PATH/assets/Dockerfile}
DOCKER_COMPOSE_FILES="-f ${LOCAL_PATH}/assets/docker-compose.yml"
IMAGE_BASE_PREFIX="kong-pongo-"
IMAGE_BASE_NAME=$IMAGE_BASE_PREFIX$PONGO_VERSION
# the path where the plugin source is located, as seen from Pongo (this script)
KONG_TEST_PLUGIN_PATH=$(realpath .)
# the working directory, which is the path where the plugin-source is located
# on the host machine. Only if Pongo is running inside docker itself, the
# PONGO_WD differs from the KONG_TEST_PLUGIN_PATH
PONGO_WD=$KONG_TEST_PLUGIN_PATH
if [[ -d "/pongo_wd" ]]; then
local HOST_PATH
PONGO_CONTAINER_ID=$(</pongo_wd/.containerid)
if [[ "$PONGO_CONTAINER_ID" == "" ]]; then
warn "'/pongo_wd' path is defined, but failed to get the container id from"
warn "the '/pongo_wd/.containerid' file. Start the Pongo container with"
warn "'--cidfile \"[plugin-path]/.containerid\"' to set the file."
warn "If you are NOT running Pongo itself inside a container, then make"
warn "sure '/pongo_wd' doesn't exist."
else
#msg "Pongo container: $PONGO_CONTAINER_ID"
HOST_PATH=$(docker inspect "$PONGO_CONTAINER_ID" | grep ":/pongo_wd.*\"" | sed -e 's/^[ \t]*//' | sed s/\"//g | grep -o "^[^:]*")
#msg "Host working directory: $HOST_PATH"
fi
if [[ "$HOST_PATH" == "" ]]; then
warn "Failed to read the container information, could not retrieve the"
warn "host path of the '/pongo_wd' directory."
warn "Make sure to start the container running Pongo with:"
warn " -v /var/run/docker.sock:/var/run/docker.sock"
warn "NOTE: make sure you understand the security implications!"
err "Failed to get container info."
fi
if [[ ! $KONG_TEST_PLUGIN_PATH == /pongo_wd ]] && [[ ! ${KONG_TEST_PLUGIN_PATH:0:10} == /pongo_wd/ ]]; then
err "When Pongo itself runs inside a container, the plugin source MUST be within the '/pongo_wd' path"
fi
PONGO_WD=${KONG_TEST_PLUGIN_PATH/\/pongo_wd/${HOST_PATH}}
fi
# create unique projectID based on file-path (on the host machine)
PROJECT_ID=$(echo -n "$PONGO_WD" | md5sum)
PROJECT_ID="${PROJECT_ID:0:8}"
PROJECT_NAME_PREFIX="pongo-"
PROJECT_NAME=${PROJECT_NAME_PREFIX}${PROJECT_ID}
NETWORK_NAME=pongo-test-network
SERVICE_NETWORK_PREFIX="pongo-"
SERVICE_NETWORK_NAME=${SERVICE_NETWORK_PREFIX}${PROJECT_ID}
unset WINDOWS_SLASH
unset WINPTY_PREFIX
unset PONGO_PLATFORM
if [ "$(uname -s)" == "Darwin" ]; then
# all Apple platforms
export PONGO_PLATFORM="APPLE"
elif uname -s | grep -q "MINGW"; then
# Git Bash for Windows
# Msys (not supported!)
export PONGO_PLATFORM="WINDOWS"
# Windows/MinGW requires an extra / in docker command so //bin/bash
# https://www.reddit.com/r/docker/comments/734arg/cant_figure_out_how_to_bash_into_docker_container/
WINDOWS_SLASH="/"
if winpty --help > /dev/null; then
# for terminal output we passthrough winpty
WINPTY_PREFIX="winpty"
fi
elif grep -q WSL < /proc/version; then
# WSL and WSL2
export PONGO_PLATFORM="WINDOWS"
else
export PONGO_PLATFORM="LINUX"
fi
# when running CI do we have the required secrets available? (used for EE only)
# secrets are unavailable for PR's from outside the organization (untrusted)
# can be set to "true" or "false", defaults to the Travis-CI setting
if [[ "$PONGO_SECRETS_AVAILABLE" == "" ]]; then
PONGO_SECRETS_AVAILABLE="$TRAVIS_SECURE_ENV_VARS"
fi
# regular Kong Enterprise images repo (tag is build as $PREFIX$VERSION$POSTFIX).
KONG_EE_TAG_PREFIX="kong/kong-gateway:"
KONG_EE_TAG_POSTFIX="-ubuntu"
# # all Kong Enterprise images repo (tag is build as $PREFIX$VERSION$POSTFIX).
# # these are private, credentials are needed
# KONG_EE_PRIVATE_TAG_PREFIX="kong/kong-gateway-private:"
# KONG_EE_PRIVATE_TAG_POSTFIX="-ubuntu"
# regular Kong CE images repo (tag is build as $PREFIX$VERSION$POSTFIX)
KONG_OSS_TAG_PREFIX="kong:"
KONG_OSS_TAG_POSTFIX="-ubuntu"
# unoffical Kong CE images repo, the fallback
KONG_OSS_UNOFFICIAL_TAG_PREFIX="kong/kong:"
KONG_OSS_UNOFFICIAL_TAG_POSTFIX="-ubuntu"
# development EE images repo, these are public, no credentials needed
DEVELOPMENT_EE_TAG="kong/kong-gateway-dev:master-ubuntu"
# development CE images, these are public, no credentials needed
DEVELOPMENT_CE_TAG="kong/kong:master-ubuntu"
# dependency health checks
if [[ -z $HEALTH_TIMEOUT ]]; then
export HEALTH_TIMEOUT=60
fi
if [[ $HEALTH_TIMEOUT -lt 0 ]]; then
export HEALTH_TIMEOUT=0
fi
if [[ $HEALTH_TIMEOUT -eq 0 ]]; then
export SERVICE_DISABLE_HEALTHCHECK=true
fi
# Dependency image defaults
if [[ -z $POSTGRES_IMAGE ]] && [[ -n $POSTGRES ]]; then
# backward compat; POSTGRES replaced by POSTGRES_IMAGE
export POSTGRES_IMAGE=postgres:$POSTGRES
fi
if [[ -z $CASSANDRA_IMAGE ]] && [[ -n $CASSANDRA ]]; then
# backward compat; CASSANDRA replaced by CASSANDRA_IMAGE
export CASSANDRA_IMAGE=cassandra:$CASSANDRA
fi
if [[ -z $REDIS_IMAGE ]] && [[ -n $REDIS ]]; then
# backward compat; replaced by REDIS_IMAGE
export REDIS_IMAGE=redis:$REDIS-alpine
fi
if [[ -z $SQUID_IMAGE ]] && [[ -n $SQUID ]]; then
# backward compat; replaced by SQUID_IMAGE
export SQUID_IMAGE=sameersbn/squid:$SQUID
fi
# proxy config, ensure it's set in all lower-case
# shellcheck disable=SC2153
if [[ -z $http_proxy ]] && [[ -n $HTTP_PROXY ]]; then
export http_proxy=$HTTP_PROXY
fi
# shellcheck disable=SC2153
if [[ -z $https_proxy ]] && [[ -n $HTTPS_PROXY ]]; then
export https_proxy=$HTTPS_PROXY
fi
# shellcheck disable=SC2153
if [[ -z $ftp_proxy ]] && [[ -n $FTP_PROXY ]]; then
export ftp_proxy=$FTP_PROXY
fi
# shellcheck disable=SC2153
if [[ -z $no_proxy ]] && [[ -n $NO_PROXY ]]; then
export no_proxy=$NO_PROXY
fi
# Commandline related variables
unset ACTION
FORCE_BUILD=${PONGO_FORCE_BUILD:-false}
KONG_DEPS_AVAILABLE=( "postgres" "cassandra" "redis" "squid" "grpcbin" "expose")
KONG_DEPS_START=( "postgres" )
KONG_DEPS_CUSTOM=()
RC_COMMANDS=( "run" "up" "restart" )
EXTRA_ARGS=()
# resolve a '.x' to a real version; eg. "1.3.0.x" in $KONG_VERSION, and replace
# "stable" and "stable-ee" with actual versions
resolve_version
unset CUSTOM_PLUGINS
unset PLUGINS
}
function check_tools {
local missing=false
docker -v > /dev/null 2>&1
if [[ ! $? -eq 0 ]]; then
>&2 echo "'docker' command not found, please install Docker, and make it available in the path."
missing=true
fi
docker compose > /dev/null 2>&1
if [[ ! $? -eq 0 ]]; then
docker-compose -v > /dev/null 2>&1
if [[ ! $? -eq 0 ]]; then
>&2 echo "'docker-compose' and 'docker compose' commands not found, please upgrade docker or install docker-compose and make it available in the path."
missing=true
fi
# old deprecated way; using docker-compose as a separate command
COMPOSE_COMMAND="docker-compose"
else
# newer version; compose is a subcommand of docker
COMPOSE_COMMAND="docker compose"
fi
realpath . > /dev/null 2>&1
if [[ ! $? -eq 0 ]]; then
>&2 echo "'realpath' command not found, please install it, and make it available in the path (on Mac use Brew to install the 'coreutils' package)."
missing=true
fi
curl -V > /dev/null 2>&1
if [[ ! $? -eq 0 ]]; then
>&2 echo "'curl' command not found, please install it, and make it available in the path."
missing=true
fi
if [[ "$missing" == "true" ]]; then
>&2 echo -e "\033[0;31m[pongo-ERROR] the above dependencies are missing, install and retry.\033[0m"
exit 1
fi
}
function logo {
PONGO_VERSION=$PONGO_VERSION "$LOCAL_PATH"/assets/pongo_logo.sh
}
function usage {
case "$1" in
pongo|init|lint|pack|run|shell|tail|build|nuke|clean|down|restart|status|up|update|expose|logs|docs)
logo
if [ -f "$LOCAL_PATH/assets/help/$1.txt" ]; then
cat "$LOCAL_PATH/assets/help/$1.txt"
else
echo "Help for the '$1' command is not yet available"
fi
echo ""
exit 0
;;
*)
logo
cat "$LOCAL_PATH/assets/help/pongo.txt"
echo ""
exit 1
;;
esac
}
#array_contains arr "a b" && echo yes || echo no
function array_contains {
local array="$1[@]"
local seeking=$2
local in=1
local element
for element in "${!array}"; do
if [[ "$element" == "$seeking" ]]; then
in=0
break
fi
done
return $in
}
function add_custom_dependency {
local to_add=$1
if ! array_contains KONG_DEPS_AVAILABLE "$to_add"; then
KONG_DEPS_AVAILABLE+=("$to_add")
KONG_DEPS_CUSTOM+=("$to_add")
fi
}
function read_rc_dependencies {
local rc_arg
# shellcheck disable=SC2153 # PONGORC_ARGS is defined in sourced file
for rc_arg in ${PONGORC_ARGS[*]}; do
if [[ "--no-" == "${rc_arg:0:5}" ]]; then
rc_arg="${rc_arg:5}"
elif [[ "--" == "${rc_arg:0:2}" ]]; then
rc_arg="${rc_arg:2}"
else
err "not a proper '$PONGORC_FILE' entry: $rc_arg, name must be prefixed with '--' or '--no-'"
fi
add_custom_dependency "$rc_arg"
done;
#msg "custom deps: ${KONG_DEPS_CUSTOM[@]}"
#msg "all deps: ${KONG_DEPS_AVAILABLE[@]}"
local dependency
for dependency in ${KONG_DEPS_CUSTOM[*]}; do
local dcyml
if [[ -f ".pongo/$dependency.yml" ]]; then
dcyml=".pongo/$dependency.yml"
else
err "docker-compose file '.pongo/$dependency.yml' not found for custom local dependency '$dependency' (specified in '$PONGORC_FILE')"
fi
DOCKER_COMPOSE_FILES="$DOCKER_COMPOSE_FILES -f $KONG_TEST_PLUGIN_PATH/$dcyml"
#msg "compose files: $DOCKER_COMPOSE_FILES"
done;
}
function add_dependency_start {
local to_add=$1
array_contains KONG_DEPS_START "$to_add" && return || KONG_DEPS_START+=("$to_add")
}
function remove_dependency_start {
local to_remove=$1
local new_array=()
local dependency
for dependency in ${KONG_DEPS_START[*]}; do
if [[ "$dependency" != "$to_remove" ]]; then
new_array+=("$dependency")
fi
done;
KONG_DEPS_START=("${new_array[@]}")
}
function handle_dep_arg {
local arg=$1
local is_dep=1
for dependency in ${KONG_DEPS_AVAILABLE[*]}; do
if [[ "--$dependency" == "$arg" ]]; then
add_dependency_start "$dependency"
is_dep=0
break
fi
if [[ "--no-$dependency" == "$arg" ]]; then
remove_dependency_start "$dependency"
is_dep=0
break
fi
done;
#msg "after '$arg' deps: ${KONG_DEPS_START[@]} extra-args: ${EXTRA_ARGS[@]}"
return $is_dep
}
function parse_args {
read_rc_dependencies
# inject the RC file commands into the commandline args
local PONGO_ARGS=()
# first add the main Pongo command
local PONGO_COMMAND=$1
PONGO_ARGS+=("$PONGO_COMMAND")
shift
# check for help
if [ "$PONGO_COMMAND" == "--help" ] || [ "$PONGO_COMMAND" == "-h" ] || [ "$PONGO_COMMAND" == "" ]; then
usage pongo
fi
if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
usage "$PONGO_COMMAND"
fi
# only add RC file parameters if command allows it
local rc_command
for rc_command in ${RC_COMMANDS[*]}; do
if [[ "$rc_command" == "$PONGO_COMMAND" ]]; then
# add all the Pongo RC args
local rc_arg
for rc_arg in ${PONGORC_ARGS[*]}; do
PONGO_ARGS+=("$rc_arg")
done;
fi
done;
# add remaining arguments from the command line
while [[ $# -gt 0 ]]; do
PONGO_ARGS+=("$1")
shift
done
# parse the arguments
local args_done=0
local pongo_arg
for pongo_arg in ${PONGO_ARGS[*]}; do
if [[ args_done -eq 0 ]]; then
case "$pongo_arg" in
--)
args_done=1
;;
--debug)
# PONGO_DEBUG=true
set -x
export BUILDKIT_PROGRESS=plain
;;
*)
handle_dep_arg "$pongo_arg" || EXTRA_ARGS+=("$pongo_arg")
;;
esac
else
EXTRA_ARGS+=("$pongo_arg")
fi
done
}
function validate_version {
local version=$1
if version_exists "$version"; then
return
fi
err "Version '$version' is not supported, supported versions are:
Kong: ${KONG_CE_VERSIONS[*]} $STABLE_CE $DEVELOPMENT_CE
Kong Enterprise: ${KONG_EE_VERSIONS[*]} $STABLE_EE $DEVELOPMENT_EE
If the '$version' is valid but not listed, you can try to update Pongo first, and then retry."
}
function check_secret_availability {
if [[ "$PONGO_SECRETS_AVAILABLE" == "true" ]] || [[ "$PONGO_SECRETS_AVAILABLE" == "" ]]; then
return 0
elif [[ "$PONGO_SECRETS_AVAILABLE" == "false" ]]; then
warn "The required secrets for fetching the image:"
warn " '$1'"
warn "are unavailable, it is assumed this is because of a CI run on"
warn "a PR from outside the organization, which means it is untrusted."
warn ""
warn "If the secrets are available then make sure \$PONGO_SECRETS_AVAILABLE is"
warn "set to 'true'."
warn ""
warn "Now exiting with exit-code 0 to indicate success to not fail external"
warn "contributed PR's because of CI security restrictions."
exit 0
else
err "variable \$PONGO_SECRETS_AVAILABLE should be 'true', 'false' or unset, but got: '$PONGO_SECRETS_AVAILABLE'"
fi
}
function docker_login {
if [[ -z $DOCKER_PASSWORD ]] && [[ -z $DOCKER_USERNAME ]]; then
# No credentials, nothing to log into
return 0
fi
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
if [[ ! $? -eq 0 ]]; then
docker logout
err "Docker login failed. Make sure to provide the proper credentials in the \$DOCKER_USERNAME
and \$DOCKER_PASSWORD environment variables."
fi
}
function docker_login_ee {
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
if [[ ! $? -eq 0 ]]; then
docker logout
err "Failed to log into the private Kong Enterprise docker repo. Make sure to provide the
proper credentials in the \$DOCKER_USERNAME and \$DOCKER_PASSWORD environment variables."
fi
}
function get_image {
# Checks if an image based on $KONG_VERSION is available, if not it will try to
# download the image.
# NOTE: the image is an original Kong image, not a development/Pongo one.
# Result: $KONG_IMAGE will be set to an image based on the requested version
local image
# shellcheck disable=SC2153 # will be resolved in set_variables.sh
if is_commit_based "$KONG_VERSION"; then
# go and pull the development image here
if [[ "$KONG_VERSION" == "$DEVELOPMENT_CE" ]]; then
# pull the Opensource development image
image=$DEVELOPMENT_CE_TAG
docker pull "$image"
if [[ ! $? -eq 0 ]]; then
err "failed to pull the Kong CE development image $image"
fi
else
# pull the Enterprise development image
image=$DEVELOPMENT_EE_TAG
docker pull "$image"
if [[ ! $? -eq 0 ]]; then
err "failed to pull: $image"
fi
fi
else
# regular Kong release, fetch the OSS or Enterprise version if needed
if is_enterprise "$KONG_VERSION"; then
image=$KONG_EE_TAG_PREFIX$KONG_VERSION$KONG_EE_TAG_POSTFIX
else
image=$KONG_OSS_TAG_PREFIX$KONG_VERSION$KONG_OSS_TAG_POSTFIX
fi
docker inspect --type=image "$image" &> /dev/null
if [[ ! $? -eq 0 ]]; then
docker pull "$image"
if [[ ! $? -eq 0 ]]; then
# failed to pull CE image, so try the fallback
# NOTE: new releases take a while (days) to become available in the
# official docker hub repo. Hence we fall back on the unofficial Kong
# repo that is immediately available for each release. This will
# prevent any CI from failing in the mean time.
msg "failed to pull: $image from the official repo, retrying unofficial..."
image=$KONG_OSS_UNOFFICIAL_TAG_PREFIX$KONG_VERSION$KONG_OSS_UNOFFICIAL_TAG_POSTFIX
docker pull "$image"
if [[ ! $? -eq 0 ]]; then
err "failed to pull: $image"
fi
msg "pulling unofficial image succeeded"
fi
fi
fi
KONG_IMAGE=$image
}
GET_VERSION_RAN=false
function get_version {
# if $KONG_IMAGE is not yet set, it will get the image (see get_image).
# Then it will read the Kong version from the image (by executing "kong version")
#
# Result: $VERSION will be read from the image, and $KONG_TEST_IMAGE will be set.
# NOTE1: $KONG_TEST_IMAGE is only a name, the image might not have been created yet
# NOTE2: if it is a development tag, then $VERSION will be a commit-id
local custom_image=false
if [[ -z $KONG_IMAGE ]]; then
validate_version "$KONG_VERSION"
get_image
else
custom_image=true
if [[ "$GET_VERSION_RAN" == "false" ]]; then
# display message only once
msg "using provided Kong image '$KONG_IMAGE'"
fi
fi
if is_commit_based "$KONG_VERSION"; then
# it's a development; get the commit-id from the image
VERSION=$(docker inspect \
--format "{{ index .Config.Labels \"org.opencontainers.image.revision\"}}" \
"$KONG_IMAGE")
if [[ ! $? -eq 0 ]]; then
err "failed to read commit-id from Kong image: $KONG_IMAGE, label: org.opencontainers.image.revision"
fi
if [[ "$VERSION" == "" ]]; then
err "Got an empty commit-id from Kong image: $KONG_IMAGE, label: org.opencontainers.image.revision"
fi
if [[ "$GET_VERSION_RAN" == "false" ]]; then
# display message only once
msg "using Kong development/commit based version '$VERSION'"
fi
else
# regular Kong version, so extract the Kong version number
local cmd=(
'/bin/bash' '-c' '/usr/local/openresty/luajit/bin/luajit -e "
local command = [[kong version]]
local version_output = io.popen(command):read()
local version_pattern = [[([%d%.%-]+[%d%.])]]
local parsed_version = version_output:match(version_pattern)
io.stdout:write(parsed_version)
"')
# shellcheck disable=SC2145 # we want WINDOWS_SLASH to be added to the first element
VERSION=$(docker run --rm -e KONG_LICENSE_DATA "$KONG_IMAGE" "$WINDOWS_SLASH${cmd[@]}")
if [[ ! $? -eq 0 ]]; then
err "failed to read version from Kong image: $KONG_IMAGE"
fi
# if a custom_iamge, report the version found
if [[ "$custom_image" == "true" ]]; then
if [[ "$GET_VERSION_RAN" == "false" ]]; then
# display message only once
msg "Kong image '$KONG_IMAGE' reported version '$VERSION'"
fi
fi
fi
GET_VERSION_RAN=true
KONG_TEST_IMAGE=$IMAGE_BASE_NAME:$VERSION
}
function compose {
export NETWORK_NAME
export SERVICE_NETWORK_NAME
export KONG_TEST_IMAGE
export PONGO_WD
export ACTION
export PROJECT_ID
local prefix
if [ -t 1 ] ; then
# only use winpty prefix if we're outputting to terminal,
# hence don't use when piping
prefix=$WINPTY_PREFIX
fi
# shellcheck disable=SC2086 # we need DOCKER_COMPOSE_FILES to be word-split here
$prefix $COMPOSE_COMMAND -p "${PROJECT_NAME}" ${DOCKER_COMPOSE_FILES} "$@"
}
# checks health status of a container. 2 args:
# 1. container id (required)
# 2. container name (optional, defaults to the id)
# returns 0 (success) if healthy, 1 for all other states; starting, unhealthy, stopping, etc.
function healthy {
local iid=$1
[[ -z $iid ]] && return 1
local name=$2
if [[ "$name" == "" ]]; then
# no name provided, use container id
name=$iid
fi
if [[ "${SERVICE_DISABLE_HEALTHCHECK}" == "true" ]]; then
return 0
fi
local health
health=$(docker inspect --format='{{json .State.Health}}' "$iid")
if [ "$health" == "null" ]; then
msg "No health check available for '$name', assuming healthy"
return 0
fi
local state
state=$(docker inspect --format='{{.State.Health.Status}}' "$iid")
if [ "$state" == "healthy" ]; then
return 0
fi
return 1
}
# takes a container name and returns its id
function cid {
compose ps -q "$1" 2> /dev/null
}
# Waits for a dependency to be healthy. 1 arg:
# 1. dependency name
# returns 0 (success) if healthy, throws an error if there was a timeout
function wait_for_dependency {
local iid
local dep="$1"
if [[ "${SERVICE_DISABLE_HEALTHCHECK}" == "true" ]]; then
msg "Health checks disabled, won't wait for '$dep' to be healthy"
return 0
fi
iid=$(cid "$dep")
if healthy "$iid" "$dep"; then
return 0
fi
msg "Waiting for '$dep' to become healthy"
local timeout_count=$((HEALTH_TIMEOUT*2))
while [ $timeout_count -ge 0 ]; do
sleep 0.5
if healthy "$iid" "$dep"; then
return 0
fi
timeout_count=$((timeout_count-1))
done
err "Timeout waiting for '$dep' to become healthy"
}
function compose_up {
docker_login
local dependency
for dependency in ${KONG_DEPS_START[*]}; do
healthy "$(cid "$dependency")" "$dependency" || compose up -d "$dependency"
done;
}
function ensure_available {
if [ -z "$WINDOWS_SLASH" ]; then
# unix check
compose ps | grep "Up (health" &> /dev/null
else
# Windows check
compose ps | grep "running (health" &> /dev/null
fi
if [[ ! $? -eq 0 ]]; then
msg "auto-starting the test environment, use the 'pongo down' action to stop it"
compose_up || err "failed to start the test environment"
fi
local dependency
for dependency in ${KONG_DEPS_START[*]}; do
wait_for_dependency "$dependency"
done;
}
function build_image {
# if $KONG_TEST_IMAGE doesn't exist yet (or if forced), it will build that
# image. This essentially comes down to:
# 1. take $KONG_IMAGE as base image
# 2. inject dev files based on $VERSION
# 3. do a 'make dev' and then some (see the Dockerfile)
# 4. Tag the result as $KONG_TEST_IMAGE
get_version
if is_commit_based "$KONG_VERSION"; then
# in a development then $VERSION is a commit id
validate_version "$KONG_VERSION"
else
# regular version or an image provided, check $VERSION extracted from the image
validate_version "$VERSION"
fi
docker inspect --type=image "$KONG_TEST_IMAGE" &> /dev/null
if [[ $? -eq 0 ]]; then
msg "image '$KONG_TEST_IMAGE' already exists"
if [ "$FORCE_BUILD" = false ] ; then
msg "use 'pongo build --force' to rebuild"
return 0
fi
msg "rebuilding..."
fi
if is_commit_based "$KONG_VERSION"; then
# development; we must fetch the related development files dynamically in this case
# shellcheck disable=SC1090 # do not follow source
source "${LOCAL_PATH}/assets/update_versions.sh"
update_development "$KONG_VERSION" "$VERSION"
fi
msg "starting build of image '$KONG_TEST_IMAGE'"
$WINPTY_PREFIX docker build \
-f "$DOCKER_FILE" \
--build-arg PONGO_VERSION="$PONGO_VERSION" \
--build-arg http_proxy="$http_proxy" \
--build-arg https_proxy="$https_proxy" \
--build-arg ftp_proxy="$ftp_proxy" \
--build-arg no_proxy="$no_proxy" \
--build-arg PONGO_INSECURE="$PONGO_INSECURE" \
--build-arg KONG_BASE="$KONG_IMAGE" \
--build-arg KONG_DEV_FILES="./kong-versions/$VERSION/kong" \
--tag "$KONG_TEST_IMAGE" \
"$LOCAL_PATH" || err "Error: failed to build test environment"
msg "image '$KONG_TEST_IMAGE' successfully build"
}
function get_plugin_names {
if [[ -d ./kong/plugins/ ]]; then
local dir
# shellcheck disable=SC2044 # let's trust the files to not have space in them
for dir in $(find ./kong/plugins -maxdepth 1 -mindepth 1 -type d); do
dir=${dir##*/} # grab everything after the final "/"
if [[ -f ./kong/plugins/$dir/handler.lua ]]; then
if [[ "$CUSTOM_PLUGINS" == "" ]]; then
CUSTOM_PLUGINS=$dir
else
CUSTOM_PLUGINS=$CUSTOM_PLUGINS,$dir
fi
fi
done
fi
if [[ "$CUSTOM_PLUGINS" == "" ]]; then
PLUGINS=bundled
else
PLUGINS=bundled,$CUSTOM_PLUGINS
fi
}
function do_prerun_script {
if [[ -f .pongo/pongo-setup-host.sh ]]; then
# shellcheck disable=SC1091 # not following sourced script
PONGO_COMMAND="$ACTION" .pongo/pongo-setup-host.sh
if [[ $? -ne 0 ]]; then
err "prerun script '.pongo/pongo-setup-host.sh' failed"
fi
fi
}
function pongo_down {
# if '--all' is passed then kill all environments, otherwise just current
if [[ ! "$1" == "--all" ]]; then
# just current env
compose down --remove-orphans --volumes
exit
fi
# use 'docker network ls' command to find networks, and kill them all
local p_id=$PROJECT_ID
local p_name=$PROJECT_NAME
local snn=$SERVICE_NETWORK_NAME
while read -r network ; do
PROJECT_ID=${network: -8}
PROJECT_NAME=${PROJECT_NAME_PREFIX}${PROJECT_ID}
SERVICE_NETWORK_NAME=${SERVICE_NETWORK_PREFIX}${PROJECT_ID}
compose down --remove-orphans --volumes
done < <(docker network ls --filter 'name='$SERVICE_NETWORK_PREFIX --format '{{.Name}}')
PROJECT_ID=$p_id
PROJECT_NAME=$p_name
SERVICE_NETWORK_NAME=$snn
}
function pongo_clean {
pongo_down --all
docker images --filter=reference="${IMAGE_BASE_PREFIX}*:*" --format "found: {{.ID}}" | grep found
if [[ $? -eq 0 ]]; then
# shellcheck disable=SC2046 # we want the image ids to be word-splitted
docker rmi $(docker images --filter=reference="${IMAGE_BASE_PREFIX}*:*" --format "{{.ID}}")
fi
docker images --filter=reference="pongo-expose:*" --format "found: {{.ID}}" | grep found
if [[ $? -eq 0 ]]; then
# shellcheck disable=SC2046 # we want the image ids to be word-splitted
docker rmi $(docker images --filter=reference="pongo-expose:*" --format "{{.ID}}")
fi
# prune to prevent rebuilding to happen from the docker build cache
docker builder prune -f
if [ -d "$LOCAL_PATH/kong" ]; then
rm -rf "$LOCAL_PATH/kong"
fi
if [ -d "$LOCAL_PATH/kong-ee" ]; then
rm -rf "$LOCAL_PATH/kong-ee"
fi
}
function pongo_expose {
local dependency="expose"
healthy "$(cid "$dependency")" "$dependency" || compose up -d "$dependency" || err "failed to start '$dependency'"
wait_for_dependency "$dependency"
}
function pongo_logs {
compose logs "${EXTRA_ARGS[@]}"
}
function pongo_status {
if [ ${#EXTRA_ARGS[@]} -eq 0 ]; then
# default; do all
EXTRA_ARGS=(networks dependencies containers images versions)
fi
local project="${PROJECT_NAME}"
for arg in "${EXTRA_ARGS[@]}"; do
if [ "$arg" == "--all" ]; then
# we need to show everything, so do not grep for project ID
# but use the generic part of the name to list all pongo envs
project="pongo-"
if [ ${#EXTRA_ARGS[@]} -eq 1 ]; then
# only --all specified, so use defaults
EXTRA_ARGS=(networks dependencies containers images versions)
fi
fi
done
local arg
local nl
for arg in "${EXTRA_ARGS[@]}"; do
if [ "$nl" == true ]; then
echo
else
nl=true
fi
case "$arg" in
networks)
echo Pongo networks:
echo ===============
docker network ls | grep "${project}"
;;
dependencies)
echo Pongo available dependencies:
echo =============================
local dep_name
for dep_name in ${KONG_DEPS_AVAILABLE[*]}; do
if array_contains KONG_DEPS_CUSTOM "$dep_name"; then
echo "$dep_name (custom to local plugin)"
else
echo "$dep_name"
fi
done;
;;
containers)
echo Pongo containers:
echo =================
docker ps | grep "${project}"
;;
images)
echo Pongo cached images:
echo ====================
docker images --filter=reference="${IMAGE_BASE_PREFIX}*:*"
;;
versions)
echo Available Kong versions:
echo ========================
echo Kong: "${KONG_CE_VERSIONS[*]}" "$STABLE_CE $DEVELOPMENT_CE"
echo Kong Enterprise: "${KONG_EE_VERSIONS[*]}" "$STABLE_EE $DEVELOPMENT_EE"
;;
--all)
;;
*)
err "unknown option: '$arg', see 'pongo status --help'"
esac
done
}
function pongo_init {
local pluginname
# derive pluginname
if [[ -d ./kong/plugins/ ]]; then
local dir
# shellcheck disable=SC2044 # let's trust the files to not have space in them
for dir in $(find ./kong/plugins -maxdepth 1 -mindepth 1 -type d); do
dir=${dir##*/} # grab everything after the final "/"
msg "found plugin directory: ./kong/plugins/$dir"
if [[ "$pluginname" == "" ]]; then
# found a name
pluginname=$dir
elif [[ ! "$pluginname" == "@" ]]; then
# found multiple names
pluginname="@"
fi
done
fi
if [[ "$pluginname" == "" ]]; then
msg "no plugin-code folders found, e.g. './kong/plugins/<plugin_name>'"
fi
if [[ "$pluginname" == "" ]]; then
local dirname
dirname=$(basename -- "$(pwd)")
if [[ "kong-plugin-" == "${dirname:0:12}" ]]; then
pluginname=${dirname#"kong-plugin-"}
msg "found current working directory; ./kong-plugin-$pluginname"
fi
fi
if [[ "$pluginname" == "" ]]; then
msg "current working dir has no plugin name, e.g. 'kong-plugin-<plugin_name>'"
err "could not detect current working dir to be a kong-plugin dir."
fi
if [ -f ".busted" ]; then
msg "'.busted' config file already present"
else
cp "$LOCAL_PATH/assets/init/busted" .busted
msg "added '.busted' config file for the Busted test framework"
fi
if [ -f ".luacov" ]; then
msg "'.luacov' config file already present"