-
Notifications
You must be signed in to change notification settings - Fork 1
/
agent-install.sh
executable file
·4324 lines (3723 loc) · 193 KB
/
agent-install.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
#!/bin/bash
# Installs the Horizon agent on an edge node (device or edge cluster)
set -e #future: remove?
#====================== Input Gathering ======================
# Global constants
# logging levels
#VERB_FATAL=0 # we always show fata error msgs
VERB_ERROR=1
VERB_WARNING=2
VERB_INFO=3
VERB_VERBOSE=4
VERB_DEBUG=5
# You can add to these lists of supported values by setting/exporting the corresponding <varname>_APPEND variable to a string of space-separated words.
# This allows you to experiment with platforms or variations that are not yet officially tested/supported.
SUPPORTED_DEBIAN_VARIANTS=(ubuntu raspbian debian $SUPPORTED_DEBIAN_VARIANTS_APPEND) # compared to what our detect_distro() sets DISTRO to
SUPPORTED_DEBIAN_VERSION=(bullseye jammy focal bionic buster xenial stretch bookworm $SUPPORTED_DEBIAN_VERSION_APPEND) # compared to what our detect_distro() sets CODENAME to
SUPPORTED_DEBIAN_ARCH=(amd64 arm64 armhf s390x $SUPPORTED_DEBIAN_ARCH_APPEND) # compared to dpkg --print-architecture
SUPPORTED_REDHAT_VARIANTS=(rhel redhatenterprise centos fedora $SUPPORTED_REDHAT_VARIANTS_APPEND) # compared to what our detect_distro() sets DISTRO to
# Note: version 8 and 9 are added because that is what /etc/os-release returns for DISTRO_VERSION_NUM on centos
SUPPORTED_REDHAT_VERSION=(7.6 7.9 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 9.0 9.1 9.2 9.3 8 9 32 35 36 37 38 $SUPPORTED_REDHAT_VERSION_APPEND) # compared to what our detect_distro() sets DISTRO_VERSION_NUM to. For fedora versions see https://fedoraproject.org/wiki/Releases,
SUPPORTED_REDHAT_ARCH=(x86_64 aarch64 ppc64le s390x riscv64 $SUPPORTED_REDHAT_ARCH_APPEND) # compared to uname -m
SUPPORTED_EDGE_CLUSTER_ARCH=(amd64 s390x)
SUPPORTED_ANAX_IN_CONTAINER_ARCH=(amd64 arm64 s390x)
SUPPORTED_OS=(macos linux) # compared to what our get_os() returns
SUPPORTED_LINUX_DISTRO=(${SUPPORTED_DEBIAN_VARIANTS[@]} ${SUPPORTED_REDHAT_VARIANTS[@]}) # compared to what our detect_distro() sets DISTRO to
HOSTNAME=$(hostname -s)
MAC_PACKAGE_CERT="horizon-cli.crt"
PERMANENT_CERT_PATH='/etc/horizon/agent-install.crt'
ANAX_DEFAULT_PORT=8510
AGENT_CERT_FILE_DEFAULT='agent-install.crt'
AGENT_CFG_FILE_DEFAULT='agent-install.cfg'
CSS_OBJ_PATH_DEFAULT='/api/v1/objects/IBM/agent_files'
CSS_OBJ_AGENT_SOFTWARE_BASE='/api/v1/objects/IBM/agent_software_files'
CSS_OBJ_AGENT_CERT_BASE='/api/v1/objects/IBM/agent_cert_files'
CSS_OBJ_AGENT_CONFIG_BASE='/api/v1/objects/IBM/agent_config_files'
MAX_HTTP_RETRY=5
SLEEP_SECONDS_BETWEEN_RETRY=15
CURL_RETRY_PARMS="--retry 5 --retry-connrefused --retry-max-time 120"
SEMVER_REGEX='^[0-9]+\.[0-9]+(\.[0-9]+)+' # matches a version like 1.2.3 (must be at least 3 fields). Also allows a bld num on the end like: 1.2.3-RC1
# The following variable will need to have the $ARCH prepended to it before it can be used
DEFAULT_AGENT_IMAGE_TAR_FILE='_anax.tar.gz'
INSTALLED_AGENT_CFG_FILE="/etc/default/horizon"
AGENT_CONTAINER_PORT_BASE=8080
# edge cluster agent deployment
DEFAULT_AGENT_NAMESPACE="openhorizon-agent"
SERVICE_ACCOUNT_NAME="agent-service-account"
CLUSTER_ROLE_BINDING_NAME="openhorizon-agent-cluster-rule"
DEPLOYMENT_NAME="agent"
SECRET_NAME="openhorizon-agent-secrets"
CRONJOB_AUTO_UPGRADE_NAME="auto-upgrade-cronjob"
IMAGE_REGISTRY_SECRET_NAME="openhorizon-agent-secrets-docker-cert"
CONFIGMAP_NAME="openhorizon-agent-config"
PVC_NAME="openhorizon-agent-pvc"
GET_RESOURCE_MAX_TRY=5
POD_ID=""
HZN_ENV_FILE="/tmp/agent-install-horizon-env"
DEFAULT_OCP_INTERNAL_URL_FOR_EDGE_CLUSTER_REGISTRY="image-registry.openshift-image-registry.svc:5000"
EDGE_CLUSTER_TAR_FILE_NAME='horizon-agent-edge-cluster-files.tar.gz'
# The following variables will need to have the $ARCH prepended before they can be used
DEFAULT_AGENT_K8S_IMAGE_TAR_FILE='_anax_k8s.tar.gz'
DEFAULT_CRONJOB_AUTO_UPGRADE_K8S_TAR_FILE='_auto-upgrade-cronjob_k8s.tar.gz'
# agent upgrade types. To update the certificate only, just do "-G cert" or set AGENT_UPGRADE_TYPES="cert"
UPGRADE_TYPE_SW="software"
UPGRADE_TYPE_CERT="cert"
UPGRADE_TYPE_CFG="config"
# Type of container engine to use; RedHat might have podman
DOCKER_ENGINE="docker"
#0 - not initialized, 1 - supported, 2 - not supported
AGENT_FILE_VERSIONS_STATUS=0
# Script usage info
function usage() {
local exit_code=$1
cat <<EndOfMessage
${0##*/} <options>
Install the Horizon agent on an edge device or edge cluster.
Required Input Variables (via flag, environment, or config file):
HZN_EXCHANGE_URL, HZN_FSS_CSSURL, HZN_ORG_ID, either HZN_EXCHANGE_USER_AUTH or HZN_EXCHANGE_NODE_AUTH
Options/Flags:
-c Path to a certificate file. Default: ./$AGENT_CERT_FILE_DEFAULT, if present. If the argument begins with 'css:' (e.g. css:, css:<version>, css:<path>), it will download the certificate file from the MMS. If only 'css:' is specified, the path for the highest certificate file version $CSS_OBJ_AGENT_CERT_BASE-<version> will be added if it can be found. Otherwise the default path $CSS_OBJ_PATH_DEFAULT will be added. (This flag is equivalent to AGENT_CERT_FILE or HZN_MGMT_HUB_CERT_PATH)
-k Path to a configuration file. Default: ./$AGENT_CFG_FILE_DEFAULT, if present. If the argument begins with 'css:' (e.g. css:, css:<version>, css:<path>), it will download the config file from the MMS. If only 'css:' is specified, the path for the highest config file version $CSS_OBJ_AGENT_CONFIG_BASE-<version> will be added if it can be found. Otherwise the default path $CSS_OBJ_PATH_DEFAULT will be added. All other variables for this script can be specified in the config file, except for INPUT_FILE_PATH (and HZN_ORG_ID if -i css: is specified). (This flag is equivalent to AGENT_CFG_FILE)
-i Installation packages/files location (default: current directory). If the argument is the URL of an anax git repo release (e.g. https://github.com/open-horizon/anax/releases/download/v1.2.3) it will download the appropriate packages/files from there. If it is anax: or https://github.com/open-horizon/anax/releases , it will default to the latest release. Otherwise, if the argument begins with 'http' or 'https', it will be used as an APT repository (for debian hosts). If the argument begins with 'css:' (e.g. css:, css:<version>, css:<path>), it will download the appropriate files/packages from the MMS. If only 'css:' is specified, the path for the highest package file version $CSS_OBJ_AGENT_SOFTWARE_BASE-<version> will be added if it can be found. Otherwise the default path $CSS_OBJ_PATH_DEFAULT will be added. (This flag is equivalent to INPUT_FILE_PATH)
-z The name of your agent installation tar file. Default: ./agent-install-files.tar.gz (This flag is equivalent to AGENT_INSTALL_ZIP)
-j File location for the public key for an APT repository specified with '-i' (This flag is equivalent to PKG_APT_KEY)
-t Branch to use in the APT repo specified with -i. Default is 'updates' (This flag is equivalent to APT_REPO_BRANCH)
-O The exchange organization id (This flag is equivalent to HZN_ORG_ID)
-u Exchange user authorization credentials (This flag is equivalent to HZN_EXCHANGE_USER_AUTH)
-a Exchange node authorization credentials (This flag is equivalent to HZN_EXCHANGE_NODE_AUTH)
-d The id to register this node with (This flag is equivalent to HZN_NODE_ID, NODE_ID or HZN_DEVICE_ID. NODE_ID is deprecated)
-p Pattern name to register this edge node with. Default: registers node with policy. (This flag is equivalent to HZN_EXCHANGE_PATTERN)
-n Path to a node policy file (This flag is equivalent to HZN_NODE_POLICY)
-w Wait for this edge service to start executing on this node before this script exits. If using a pattern, this value can be '*'. (This flag is equivalent to AGENT_WAIT_FOR_SERVICE)
-T Timeout value (in seconds) for how long to wait for the service to start (This flag is equivalent to AGENT_REGISTRATION_TIMEOUT)
-o Specify an org id for the service specified with '-w'. Defaults to the value of HZN_ORG_ID. (This flag is equivalent to AGENT_WAIT_FOR_SERVICE_ORG)
-s Skip registration, only install the agent (This flag is equivalent to AGENT_SKIP_REGISTRATION)
-D Node type of agent being installed: device, cluster. Default: device. (This flag is equivalent to AGENT_DEPLOY_TYPE)
-U Internal url for edge cluster registry. If not specified, this script will auto-detect the value if it is a small, single-node cluster (e.g. k3s or microk8s). For OCP use: image-registry.openshift-image-registry.svc:5000. (This flag is equivalent to INTERNAL_URL_FOR_EDGE_CLUSTER_REGISTRY)
-l Logging verbosity level. Display messages at this level and lower: 1: error, 2: warning, 3: info (default), 4: verbose, 5: debug. Default is 3, info. (This flag is equivalent to AGENT_VERBOSITY)
-f Install older version of the horizon agent and CLI packages. (This flag is equivalent to AGENT_OVERWRITE)
-b Skip any prompts for user input (This flag is equivalent to AGENT_SKIP_PROMPT)
-C Install only the horizon-cli package, not the full agent (This flag is equivalent to AGENT_ONLY_CLI)
-G A comma separated list of upgrade types. Supported types are 'software', 'cert' and 'config'. The default is 'software,cert,config'. It is used togetther with --auto-upgrade flag to perform partial agent upgrade. (This flag is equivalent to AGENT_UPGRADE_TYPES)
--ha-group Specify the HA group this node will be added to during the node registration, if -s is not specified. (This flag is equivalent to HZN_HA_GROUP)
--auto-upgrade Auto agent upgrade. It is used internally by the agent auto upgrade process. (This flag is equivalent to AGENT_AUTO_UPGRADE)
--container Install the agent in a container. This is the default behavior for MacOS installations. (This flag is equivalent to AGENT_IN_CONTAINER)
-N The container number to be upgraded. The default is 1 which means the container name is horizon1. It is used for upgrade only, the HORIZON_URL setting in /etc/horizon/hzn.json will not be changed. (This flag is equivalent to AGENT_CONTAINER_NUMBER)
-h --help This usage
Additional Variables (in environment or config file):
HZN_AGBOT_URL: The URL that is used for the 'hzn agbot ...' commands.
HZN_SDO_SVC_URL: The URL that is used for the 'hzn voucher ...' and 'hzn sdo ...' commands. Or,
HZN_FDO_SVC_URL: The URL that is used for the 'hzn fdo ...' commands.
Additional Edge Device Variables (in environment or config file):
NODE_ID_MAPPING_FILE: File to map hostname or IP to node id, for bulk install. Default: node-id-mapping.csv
AGENT_IMAGE_TAR_FILE: the file name of the device agent docker image in tar.gz format. Default: \${ARCH}$DEFAULT_AGENT_IMAGE_TAR_FILE
AGENT_WAIT_MAX_SECONDS: Maximum seconds to wait for the Horizon agent to start or stop. Default: 30
Optional Edge Device Environment Variables For Testing New Distros - Not For Production Use
SUPPORTED_DEBIAN_VARIANTS_APPEND: a debian variant that should be added to the default list: ${SUPPORTED_DEBIAN_VARIANTS[*]}
SUPPORTED_DEBIAN_VERSION_APPEND: a debian version that should be added to the default list: ${SUPPORTED_DEBIAN_VERSION[*]}
SUPPORTED_DEBIAN_ARCH_APPEND: a debian architecture that should be added to the default list: ${SUPPORTED_DEBIAN_ARCH[*]}
SUPPORTED_REDHAT_VARIANTS_APPEND: a Red Hat variant that should be added to the default list: ${SUPPORTED_REDHAT_VARIANTS[*]}
SUPPORTED_REDHAT_VERSION_APPEND: a Red Hat version that should be added to the default list: ${SUPPORTED_REDHAT_VERSION[*]}
SUPPORTED_REDHAT_ARCH_APPEND: a Red Hat architecture that should be added to the default list: ${SUPPORTED_REDHAT_ARCH[*]}
Additional Edge Cluster Variables (in environment or config file):
IMAGE_ON_EDGE_CLUSTER_REGISTRY: override the agent image path (without tag) if you want it to be different from what this script will default it to
CRONJOB_AUTO_UPGRADE_IMAGE_ON_EDGE_CLUSTER_REGISTRY: override the auto-upgrade-cronjob cronjob image path (without tag) if you want it to be different from what this script will default it to
EDGE_CLUSTER_REGISTRY_USERNAME: specify this value if the edge cluster registry requires authentication
EDGE_CLUSTER_REGISTRY_TOKEN: specify this value if the edge cluster registry requires authentication
EDGE_CLUSTER_STORAGE_CLASS: the storage class to use for the agent and edge services. Default: gp2
AGENT_NAMESPACE: The namespace the agent should run in. Default: openhorizon-agent
AGENT_WAIT_MAX_SECONDS: Maximum seconds to wait for the Horizon agent to start or stop. Default: 30
AGENT_DEPLOYMENT_STATUS_TIMEOUT_SECONDS: Maximum seconds to wait for the agent deployment rollout status to be successful. Default: 75
AGENT_K8S_IMAGE_TAR_FILE: the file name of the edge cluster agent docker image in tar.gz format. Default: \${ARCH}$DEFAULT_AGENT_K8S_IMAGE_TAR_FILE
CRONJOB_AUTO_UPGRADE_K8S_TAR_FILE: the file name of the edge cluster auto-upgrade-cronjob cronjob docker image in tar.gz format. Default: \${ARCH}$DEFAULT_CRONJOB_AUTO_UPGRADE_K8S_TAR_FILE
AGENT_NAMESPACE: The cluster namespace that the agent will be installed in
NAMESPACE_SCOPED: specify this value if the edge cluster agent is namespace-scoped agent
EndOfMessage
exit $exit_code
}
function now() {
echo $(date '+%Y-%m-%d %H:%M:%S')
}
# Get cmd line args. Each arg corresponds to an env var. The arg value will be stored in ARG_<envvar>. Then the get_variable function will choose the highest precedence variable set.
# Note: could not put this in a function, because getopts would only process the function args
AGENT_VERBOSITY=3 # default until we get it from all of the possible places
if [[ $AGENT_VERBOSITY -ge $VERB_DEBUG ]]; then echo $(now) "getopts begin"; fi
all_args=("$@")
while getopts "c:i:j:p:k:u:d:z:hl:n:sfbw:o:O:T:t:D:a:U:CG:N:-:" opt; do
case $opt in
-)
case "${OPTARG}" in
ha-group)
ARG_HZN_HA_GROUP=${all_args[$OPTIND-1]}
;;
container)
ARG_AGENT_IN_CONTAINER=true
;;
auto-upgrade)
ARG_AGENT_AUTO_UPGRADE=true
;;
# namespace)
# ARG_AGENT_NAMESPACE=${all_args[$OPTIND-1]}
# ;;
help)
usage 0
;;
*) echo "Invalid option: --$OPTARG"
usage 1
;;
esac
;;
c) ARG_AGENT_CERT_FILE="$OPTARG"
;;
k) ARG_AGENT_CFG_FILE="$OPTARG"
;;
i) ARG_INPUT_FILE_PATH="$OPTARG"
;;
z) ARG_AGENT_INSTALL_ZIP="$OPTARG"
;;
j) ARG_PKG_APT_KEY="$OPTARG"
;;
t) ARG_APT_REPO_BRANCH="$OPTARG"
;;
O) ARG_HZN_ORG_ID="$OPTARG"
;;
u) ARG_HZN_EXCHANGE_USER_AUTH="$OPTARG"
;;
a) ARG_HZN_EXCHANGE_NODE_AUTH="$OPTARG"
;;
d) ARG_HZN_NODE_ID="$OPTARG"
;;
p) ARG_HZN_EXCHANGE_PATTERN="$OPTARG"
;;
n) ARG_HZN_NODE_POLICY="$OPTARG"
;;
w) ARG_AGENT_WAIT_FOR_SERVICE="$OPTARG"
;;
o) ARG_AGENT_WAIT_FOR_SERVICE_ORG="$OPTARG"
;;
T) ARG_AGENT_REGISTRATION_TIMEOUT="$OPTARG"
;;
s) ARG_AGENT_SKIP_REGISTRATION=true
;;
D) ARG_AGENT_DEPLOY_TYPE="$OPTARG"
;;
U) ARG_INTERNAL_URL_FOR_EDGE_CLUSTER_REGISTRY="$OPTARG"
;;
l) ARG_AGENT_VERBOSITY="$OPTARG"
;;
f) ARG_AGENT_OVERWRITE=true
;;
b) ARG_AGENT_SKIP_PROMPT=true
;;
C) ARG_AGENT_ONLY_CLI=true
;;
G) ARG_AGENT_UPGRADE_TYPES="$OPTARG"
;;
N) ARG_AGENT_CONTAINER_NUMBER="$OPTARG"
;;
h) usage 0
;;
\?) echo "Invalid option: -$OPTARG"
usage 1
;;
:) echo "Option -$OPTARG requires an argument"
usage 1
;;
esac
done
if [[ $AGENT_VERBOSITY -ge $VERB_DEBUG ]]; then echo $(now) "getopts end"; fi
#====================== User Input Gathering Functions ======================
function log_fatal() {
: ${1:?} ${2:?}
local exitCode=$1
local msg="$2"
if [[ $AGENT_AUTO_UPGRADE == 'true' ]]; then
# output to both stdout and stderr
echo $(now) "ERROR: $msg" | tee /dev/stderr # we always show fatal error msgs
else
echo $(now) "ERROR: $msg" # we always show fatal error msgs
fi
exit $exitCode
}
function log_error() {
if [[ $AGENT_AUTO_UPGRADE == 'true' ]]; then
# output to both stdout and stderr
log $VERB_ERROR "ERROR: $1" | tee /dev/stderr
else
log $VERB_ERROR "ERROR: $1"
fi
}
function log_warning() {
log $VERB_WARNING "WARNING: $1"
}
function log_info() {
local msg="$1"
local nonewline=$2 # optionally 'nonewline'
if [[ $nonewline == 'nonewline' ]]; then
printf "$(now) $msg"
else
log $VERB_INFO "$msg"
fi
}
function log_verbose() {
log $VERB_VERBOSE "VERBOSE: $1"
}
function log_debug() {
log $VERB_DEBUG "DEBUG: $1"
}
function log() {
local log_level=$1
local msg="$2"
if [[ $AGENT_VERBOSITY -ge $log_level ]]; then
echo $(now) "$msg"
fi
}
# Get the value that has been specified by the user for this variable. Precedence: 1) cli flag, 2) env variable, 3) config file, 4) default.
# The side-effect of this function is that it will set the global variable named var_name.
# This function should be called after processing all of the cli args into ARG_<envvarname> and the cfg file values into CFG_<envvarname>
function get_variable() {
log_debug "get_variable() begin"
local var_name="$1" # the name of the env var (not its value)
local default_value="$2"
local is_required=${3:-false} # if set to true, normally default_value will be empty, and it means the user must specify via cli flag, env var, or cfg file
# These are indirect variable references (http://mywiki.wooledge.org/BashFAQ/006#Indirection) and used because associative arrays are only support in bash 4 or above (macos is currently bash 3)
local arg_name="ARG_$var_name"
local cfg_name="CFG_$var_name"
local from # where we found the value
# Look for the value in precedence order, and then set the indirect variable $var_name via the read statement
if [[ -n ${!arg_name} ]]; then
IFS= read -r "$var_name" <<<"${!arg_name}"
from='command line flag'
elif [[ -n ${!var_name} ]]; then
: # env var is already set
from='environment variable'
elif [[ -n ${!cfg_name} ]]; then
IFS= read -r "$var_name" <<<"${!cfg_name}"
from='configuration file'
else
IFS= read -r "$var_name" <<<"$default_value"
from='default value'
fi
if [[ -z ${!var_name} && $is_required == 'true' ]]; then
log_fatal 1 "A value for $var_name must be specified"
fi
if [[ ( $var_name == *"AUTH"* || $var_name == *"TOKEN"* ) && -n ${!var_name} ]]; then
varValue='******'
else
varValue="${!var_name}"
fi
if [[ ( $var_name == "HZN_EXCHANGE_URL" ) && -n ${!var_name} ]]; then
local TMP_HZN_EXCHANGE_URL=$HZN_EXCHANGE_URL
if [[ "$TMP_HZN_EXCHANGE_URL" != "" ]]; then
LAST_CHAR=(${TMP_HZN_EXCHANGE_URL: -1})
# If this URL ends with "/" the curl commands will fail so remove the trailing / if it exists
if [[ "$LAST_CHAR" == "/" ]]; then
TMP_HZN_EXCHANGE_URL=${TMP_HZN_EXCHANGE_URL%?}
log_debug "Changing variable $var_name from ${!var_name} to ${TMP_HZN_EXCHANGE_URL}"
export HZN_EXCHANGE_URL=${TMP_HZN_EXCHANGE_URL}
varValue="${!var_name}"
fi
fi
fi
log_info "${var_name}: $varValue (from $from)"
log_debug "get_variable() end"
}
# Get the correct css obj download path for the software packages if 'css:version' is specified.
# The path is $CSS_OBJ_AGENT_SOFTWARE_BASE-version
# The input is 'css:', 'css:version' or 'css:path'.
# Please do not add debug messages.
function get_input_file_css_path() {
local __resultvar=$1
local input_file_path
if [[ $INPUT_FILE_PATH == css:* ]]; then
# split the input into 2 parts
local part2=${INPUT_FILE_PATH#"css:"}
if [[ -n $part2 ]]; then
if [[ $part2 == /* ]]; then
input_file_path=$INPUT_FILE_PATH
else
# new path with version
input_file_path="css:${CSS_OBJ_AGENT_SOFTWARE_BASE}-${part2}"
fi
else
# 'css:' case - need to use AgentFileVersion to decide if we can get the latest cert
get_agent_file_versions
if [[ $AGENT_FILE_VERSIONS_STATUS -eq 1 ]] && [ ${#AGENT_SW_VERSIONS[@]} -gt 0 ]; then
# new way
input_file_path="css:${CSS_OBJ_AGENT_SOFTWARE_BASE}-${AGENT_SW_VERSIONS[0]}"
else
# fall back to old default way
input_file_path="css:$CSS_OBJ_PATH_DEFAULT"
fi
fi
fi
eval $__resultvar="'${input_file_path}'"
}
# If INPUT_FILE_PATH is a short-hand value, turn it into the long-hand value. There are several variants of INPUT_FILE_PATH. See the -i flag in the usage.
# Side-effect: INPUT_FILE_PATH
function adjust_input_file_path() {
log_debug "adjust_input_file_path() begin"
local save_input_file_path=$INPUT_FILE_PATH
INPUT_FILE_PATH="${INPUT_FILE_PATH%/}" # remove trailing / if there
if [[ $INPUT_FILE_PATH == css:* ]]; then
:
elif [[ $INPUT_FILE_PATH == 'anax:' ]]; then
INPUT_FILE_PATH='https://github.com/open-horizon/anax/releases/latest/download'
elif [[ $INPUT_FILE_PATH == https://github.com/open-horizon/anax/releases* ]]; then
if [[ $INPUT_FILE_PATH == 'https://github.com/open-horizon/anax/releases' ]]; then
INPUT_FILE_PATH="$INPUT_FILE_PATH/latest/download" # default to the latest release
elif [[ $INPUT_FILE_PATH == https://github.com/open-horizon/anax/releases/tag/* ]]; then
# They probably right-clicked a release and gave us like: https://github.com/open-horizon/anax/releases/tag/v2.27.0-110
local rel_ver=${INPUT_FILE_PATH#https://github.com/open-horizon/anax/releases/tag/}
if [[ -n $rel_ver ]]; then
INPUT_FILE_PATH="https://github.com/open-horizon/anax/releases/download/$rel_ver"
else
INPUT_FILE_PATH="https://github.com/open-horizon/anax/releases/latest/download" # default to the latest release
fi
fi
elif [[ $INPUT_FILE_PATH == http* ]]; then
log_info "Using INPUT_FILE_PATH value $INPUT_FILE_PATH as an APT repository"
PKG_APT_REPO="$INPUT_FILE_PATH"
INPUT_FILE_PATH='.' # not sure this is necessary
elif [[ ! -d $INPUT_FILE_PATH ]]; then
log_fatal 1 "INPUT_FILE_PATH directory '$INPUT_FILE_PATH' does not exist"
fi
#else we treat it as a local dir that contains the pkgs
if [[ -z $PKG_APT_REPO ]]; then
if [[ $INPUT_FILE_PATH != $save_input_file_path ]];then
log_info "INPUT_FILE_PATH adjusted to: $INPUT_FILE_PATH"
fi
fi
log_debug "adjust_input_file_path() end"
}
# Return what we should use as AGENT_CFG_FILE default if it is not specified: AGENT_CFG_FILE_DEFAULT if it exists, else blank
function get_cfg_file_default() {
if [[ -f $AGENT_CFG_FILE_DEFAULT ]]; then
echo "$AGENT_CFG_FILE_DEFAULT"
fi
# else return empty string
}
# Returns version number extracted from the anax/releases path, or empty string if can't find it
# Note: this should be called after adjust_input_file_path()
function get_anax_release_version() {
local input_file_path=${1:?}
if [[ $input_file_path == https://github.com/open-horizon/anax/releases/latest/download* ]]; then
echo 'latest'
elif [[ $input_file_path == https://github.com/open-horizon/anax/releases/download/* ]]; then
local rel_ver=${input_file_path#https://github.com/open-horizon/anax/releases/download/}
rel_ver=${rel_ver#v} # our convention is to add a 'v' at the beginning of releases, so remove it
if [[ $rel_ver =~ $SEMVER_REGEX ]]; then
echo "$rel_ver"
fi
fi
#else return empty string, meaning we couldn't find it (so they should probably just use latest)
}
# get the exchange AgentFileVersion object.
function get_agent_file_versions() {
log_debug "get_agent_file_versions() begin"
# make sure it is only called once
if [ $AGENT_FILE_VERSIONS_STATUS -ne 0 ]; then
return 0
fi
# input checking requires either user creds or node creds
local exch_creds cert_flag
if [[ -n $HZN_EXCHANGE_USER_AUTH ]]; then exch_creds="$HZN_ORG_ID/$HZN_EXCHANGE_USER_AUTH"
elif [[ -n $HZN_EXCHANGE_NODE_AUTH ]]; then exch_creds="$HZN_ORG_ID/$HZN_EXCHANGE_NODE_AUTH"
else
# no creds available to get the agent file versions
log_debug "No user or node credentials available to get the agent file versions"
AGENT_FILE_VERSIONS_STATUS=2
return 0
fi
# make sure HZN_EXCHANGE_URL is set
if [[ -z $HZN_EXCHANGE_URL ]]; then
log_fatal 1 "HZN_EXCHANGE_URL is not set."
fi
if [[ -n $AGENT_CERT_FILE && -f $AGENT_CERT_FILE ]]; then
cert_flag="--cacert $AGENT_CERT_FILE"
elif [[ -z $AGENT_CERT_FILE && -f $PERMANENT_CERT_PATH ]]; then
# using cert from a previous install, see if that works
cert_flag="--cacert $PERMANENT_CERT_PATH"
else
cert_flag="--insecure"
fi
local exch_output=$(curl -sSL -w "%{http_code}" ${CURL_RETRY_PARMS} ${cert_flag} ${HZN_EXCHANGE_URL}/orgs/IBM/AgentFileVersion -u ${exch_creds} 2>&1) || true
log_debug "GET AgentFileVersion: $exch_output"
if [[ -n $exch_output ]]; then
local http_code="${exch_output: -3}"
local len=${#exch_output}
local output=${exch_output:0: len - 3}
if [[ $http_code -eq 200 ]]; then
# The outpit of AgentFileVersion has the following format:
# {
# "agentSoftwareVersions": ["2.30.0", "2.25.4", "1.4.5-123"],
# "agentConfigVersions": ["0.0.4", "0.0.3"],
# "agentCertVersions": ["0.0.15"],
# }
OLDIFS=${IFS}
IFS=' '
local tmp=$(echo $output |jq -r '.agentSoftwareVersions[]' | sort -rV |tr '\n' ' ')
read -a AGENT_SW_VERSIONS <<< $tmp
tmp=$(echo $output |jq -r '.agentConfigVersions[]' | sort -rV |tr '\n' ' ')
read -a AGENT_CONFIG_VERSIONS <<< $tmp
tmp=$(echo $output |jq -r '.agentCertVersions[]' | sort -rV |tr '\n' ' ')
read -a AGENT_CERT_VERSIONS <<< $tmp
#0 - not initialized, 1 - supported, 2 - not supported
AGENT_FILE_VERSIONS_STATUS=1
IFS=${OLDIFS}
elif [[ $http_code -eq 404 ]]; then
# exchange-api version 2.98.0 and older does not support AgentFileVersion API
AGENT_FILE_VERSIONS_STATUS=2
else
log_fatal 1 "Failed to get AgentFileVersion from the exchange. $exch_output"
fi
fi
log_debug "AGENT_FILE_VERSIONS_STATUS: $AGENT_FILE_VERSIONS_STATUS"
log_debug "AGENT_SW_VERSIONS: ${AGENT_SW_VERSIONS[@]} sizs=${#AGENT_SW_VERSIONS[@]}"
log_debug "AGENT_CERT_VERSIONS: ${AGENT_CERT_VERSIONS[@]} sizs=${#AGENT_CERT_VERSIONS[@]}"
log_debug "AGENT_CONFIG_VERSIONS: ${AGENT_CONFIG_VERSIONS[@]} sizs=${#AGENT_CONFIG_VERSIONS[@]}"
log_debug "get_agent_file_versions() end"
}
# Download the certificate file from CSS if not present
function get_certificate() {
log_debug "get_certificate() begin"
local css_cert_path
get_cert_file_css_path css_cert_path
if [[ -n $css_cert_path ]]; then
download_css_file "$css_cert_path"
fi
#todo: support the case in which the mgmt hub is using a CA-trusted cert, so we don't need to use a cert at all
log_debug "get_certificate() end"
}
# get the cert file path beased on the value in AGENT_CERT_FILE_CSS and INPUT_FILE_PATH, will set AGENT_CERT_VERSION
function get_cert_file_css_path() {
log_debug "get_cert_file_css_path() begin"
local __resultvar=$1
local css_path
local need_latest_cert=false
if [[ $AGENT_CERT_FILE_CSS == css:* ]]; then
local part2=${AGENT_CERT_FILE_CSS#"css:"}
if [[ -n $part2 ]]; then
if [[ $part2 == /* ]]; then
# new or old with css path
css_path=$AGENT_CERT_FILE_CSS
else
# new with version
css_path="css:${CSS_OBJ_AGENT_CERT_BASE}-${part2}"
AGENT_CERT_VERSION=${part2}
fi
else
# 'css:' case - need to use AgentFileVersion to decide if we can get the latest csert
need_latest_cert=true
fi
elif [[ $INPUT_FILE_PATH == css:* ]]; then
if [[ -n $AGENT_CERT_FILE && ! -f $AGENT_CERT_FILE ]]; then
local part2=${INPUT_FILE_PATH#"css:"}
if [[ -n $part2 ]]; then
if [[ $part2 == /* ]]; then
if [[ "$INPUT_FILE_PATH" == "css:$CSS_OBJ_PATH_DEFAULT" ]]; then
# old way with css default path
css_path=$INPUT_FILE_PATH
else
# INPUT_FILE_PATH new way with css path, get the latest cert
need_latest_cert=true
fi
else
# new with version
need_latest_cert=true
fi
else
# 'css:' case - need to use AgentFileVersion to decide if we can get the latest csert
need_latest_cert=true
fi
fi
fi
if [ $need_latest_cert == true ]; then
# get the latest cert versions from AgentFileVersion exchange API
get_agent_file_versions
if [[ $AGENT_FILE_VERSIONS_STATUS -eq 1 ]] && [ ${#AGENT_CERT_VERSIONS[@]} -gt 0 ]; then
# new way
css_path="css:${CSS_OBJ_AGENT_CERT_BASE}-${AGENT_CERT_VERSIONS[0]}"
AGENT_CERT_VERSION=${AGENT_CERT_VERSIONS[0]}
else
# fall back to old default way
css_path="css:$CSS_OBJ_PATH_DEFAULT"
fi
fi
css_path="$css_path/$AGENT_CERT_FILE_DEFAULT"
echo "css_path=$css_path, AGENT_CERT_VERSION=$AGENT_CERT_VERSION"
eval $__resultvar="'${css_path}'"
log_debug "get_cert_file_css_path() end"
}
# Download a file from the specified CSS path
function download_css_file() {
log_debug "download_css_file() begin"
local css_path=$1 # should be like: css:/api/v1/objects/IBM/agent_files/<file>
local remote_path="${css_path/#css:/${HZN_FSS_CSSURL%/}}/data" # replace css: with the value of HZN_FSS_CSSURL and add /data on the end
local local_file="${css_path##*/}" # get base name
# Set creds flag
local exch_creds cert_flag
if [[ -z $HZN_FSS_CSSURL ]]; then
log_fatal 1 "HZN_FSS_CSSURL must be specified"
fi
if [[ -z $HZN_ORG_ID ]]; then
log_fatal 1 "HZN_ORG_ID must be specified"
fi
if [[ -n $HZN_EXCHANGE_USER_AUTH ]]; then
exch_creds="$HZN_ORG_ID/$HZN_EXCHANGE_USER_AUTH"
elif [[ -n $HZN_EXCHANGE_NODE_AUTH ]]; then
exch_creds="$HZN_ORG_ID/$HZN_EXCHANGE_NODE_AUTH"
else
log_fatal 1 "Either HZN_EXCHANGE_USER_AUTH or HZN_EXCHANGE_NODE_AUTH must be specified"
fi
# Set cert flag. This is a special case, because sometimes the cert we need is coming from CSS. In that case be creative to try to get it.
if [[ -n $AGENT_CERT_FILE && -f $AGENT_CERT_FILE ]]; then
# Either we have already downloaded it, or they gave it to us separately
cert_flag="--cacert $AGENT_CERT_FILE"
fi
local remote_cert_path
if [[ -z $cert_flag && -f $PERMANENT_CERT_PATH ]]; then
# get the cert file path
local css_cert_path
get_cert_file_css_path css_cert_path
remote_cert_path="${css_cert_path/#css:/${HZN_FSS_CSSURL%/}}/data"
# Cert from a previous install, see if that works
log_info "Attempting to download file $remote_cert_path using $PERMANENT_CERT_PATH ..."
httpCode=$(curl -sSL -w "%{http_code}" ${CURL_RETRY_PARMS} -u "$exch_creds" --cacert "$PERMANENT_CERT_PATH" -o "$AGENT_CERT_FILE" $remote_cert_path 2>/dev/null || true)
if [[ $? -eq 0 && $httpCode -eq 200 ]]; then
cert_flag="--cacert $AGENT_CERT_FILE" # we got it
fi
fi
if [[ -z $cert_flag && $HZN_FSS_CSSURL == https:* ]]; then #todo: this check still doesn't account for a CA-trusted cert
# Still didn't find a valid cert. Get the cert from CSS by disabling cert checking
rm -f "$AGENT_CERT_FILE" # this probably has the error msg from the previous curl in it
# get the cert file path
if [[ -z $remote_cert_path ]]; then
local css_cert_path
get_cert_file_css_path css_cert_path
remote_cert_path="${css_cert_path/#css:/${HZN_FSS_CSSURL%/}}/data"
fi
log_info "Downloading file $remote_cert_path using --insecure ..."
#echo "DEBUG: curl -sSL -w \"%{http_code}\" -u \"$exch_creds\" --insecure -o \"$AGENT_CERT_FILE\" $remote_cert_path || true" # log_debug isn't set up yet
httpCode=$(curl -sSL -w "%{http_code}" ${CURL_RETRY_PARMS} -u "$exch_creds" --insecure -o "$AGENT_CERT_FILE" $remote_cert_path || true)
if [[ $? -ne 0 || $httpCode -ne 200 ]]; then
local err_msg=$(cat $AGENT_CERT_FILE 2>/dev/null)
rm -f "$AGENT_CERT_FILE" # this probably has the error msg from the previous curl in it
log_fatal 3 "could not download $remote_cert_path: $err_msg"
fi
cert_flag="--cacert $AGENT_CERT_FILE" # we got it
fi
# Get the file they asked for
if [[ $local_file != $AGENT_CERT_FILE ]]; then # if they asked for the cert, we already got that
log_info "Downloading file $remote_path ..."
download_with_retry $remote_path $local_file "$cert_flag" $exch_creds
fi
if [[ -n $AGENT_CERT_FILE && -f $AGENT_CERT_FILE ]]; then
local version_from_cert_file
getCertVersionFromCertFile version_from_cert_file
if [[ -n $AGENT_CERT_VERSION ]]; then
if is_linux; then # Skip writing comment to cert file for MacOS since it failed on M1 machine in mac_trust_cert step
if [[ -z $version_from_cert_file ]]; then
# write AGENT_CERT_VERSION in file comment as ------OpenHorizon Version x.x.x-----
version_to_add="-----OpenHorizon Version $AGENT_CERT_VERSION-----"
log_debug "add this line $version_to_add to cert file: $AGENT_CERT_FILE"
echo "-----OpenHorizon Version $AGENT_CERT_VERSION-----" > tmp-agent-install.crt
cat $AGENT_CERT_FILE >> tmp-agent-install.crt
mv tmp-agent-install.crt $AGENT_CERT_FILE
elif [[ "$AGENT_CERT_VERSION" != "$version_from_cert_file" ]]; then
# if version in cert != version in css filename, overwrite to use version in css filename
sed -i "s#$version_from_cert_file#${AGENT_CERT_VERSION}#g" $AGENT_CERT_FILE
fi
fi
fi
fi
log_debug "download_css_file() end"
}
function download_with_retry() {
log_debug "download_with_retry() begin"
local url=$1
local outputFile=$2
local certFlag=$3
local cred=$4
retry=0
set +e
while [[ $retry -le $MAX_HTTP_RETRY ]]; do
if [[ -n "$cred" && -n "$outputFile" ]]; then
# download from CSS
httpCode=$(curl -sSL -w "%{http_code}" -u "$cred" $certFlag -o "$outputFile" $url 2>/dev/null)
else
# download from github release
httpCode=$(curl -sSLO -w "%{http_code}" $url 2>/dev/null)
fi
curlCode=$?
if [[ $curlCode -ne 0 || $httpCode =~ .*(503|504).* ]]; then
log_debug "retry downloading $retry because curlCode is $curlCode, httpCode is $httpCode..."
count=$((retry + 1))
retry=$count
sleep $SLEEP_SECONDS_BETWEEN_RETRY
continue
else
break
fi
done
set -e
chkHttp $curlCode $httpCode 200 "downloading $url" $outputFile
log_debug "download_with_retry() end"
}
# returns the cert version from certificate file
function getCertVersionFromCertFile() {
log_debug "getCertVersionFromCertFile() begin"
local __resultvar=$1
local cert_ver_from_file
while read -r line || [[ -n "$line" ]]; do
if [[ -z $line || ${line:0:1} != '-' ]]; then continue; fi # only find the line start with "-"
content=$(echo $line | sed 's/-----\(.*\)-----/\1/') # extract the part between ----- and -----
if [[ -n $content && $content == *"OpenHorizon Version"* ]]; then
log_debug "cert contains OpenHorizon Version: $content"
cert_ver_from_file=${content##* }
else
continue
fi
done < "$AGENT_CERT_FILE"
log_debug "cert_ver_from_file=$cert_ver_from_file"
eval $__resultvar="'${cert_ver_from_file}'"
log_debug "getCertVersionFromCertFile() end"
}
function download_anax_release_file() {
log_debug "download_anax_release_file() begin"
local anax_release_path=$1 # should be like: https://github.com/open-horizon/anax/releases/latest/download/<file>
local local_file="${anax_release_path##*/}" # get base name
log_info "Downloading file $anax_release_path ..."
download_with_retry $anax_release_path $local_file
log_debug "download_anax_release_file() end"
}
# If necessary, download the cfg file from CSS.
# The input_file_path is either AGENT_CFG_FILE or INPUT_FILE_PATH, the second
# parameter tells which one it is: 1 for AGENT_CFG_FILE, 0 for INPUT_FILE_PATH.
# this function sets AGENT_CONFIG_VERSION
function download_config_file() {
log_debug "download_config_file() begin"
local input_file_path=$1 # normally the value of INPUT_FILE_PATH or AGENT_CFG_FILE
local is_config_path=$2
if [[ $input_file_path == css:* ]]; then
local css_path
local need_latest_cfg=false
local part2=${input_file_path#"css:"}
if [[ -n $part2 ]]; then
if [[ $part2 == /* ]]; then
if [[ $is_config_path -eq 1 ]]; then
# AGENT_CFG_FILE contains path css path, use it
css_path=$input_file_path
else
# INPUT_FILE_PATH contains the path, only use it when it is the old default way
need_latest_cfg=true
if [[ "$input_file_path" == "css:$CSS_OBJ_PATH_DEFAULT" ]]; then
# old way with css default path
css_path=$input_file_path
else
# INPUT_FILE_PATH new way with css path, get the latest config
need_latest_cfg=true
fi
fi
else
if [[ $is_config_path -eq 1 ]]; then
# AGENT_CFG_FILE contains the version, use it
css_path="css:${CSS_OBJ_AGENT_CONFIG_BASE}-${part2}"
AGENT_CONFIG_VERSION=${part2}
else
# INPUT_FILE_PATH contains the version, cannot use it
need_latest_cfg=true
fi
fi
else
# 'css:' case - need to use AgentFileVersion to decide if we can get the latest csert
need_latest_cfg=true
fi
if [ $need_latest_cfg == true ]; then
# get the latest config versions from AgentFileVersion exchange API
get_agent_file_versions
if [[ $AGENT_FILE_VERSIONS_STATUS -eq 1 ]] && [ ${#AGENT_CONFIG_VERSIONS[@]} -gt 0 ]; then
# new way
css_path="css:${CSS_OBJ_AGENT_CONFIG_BASE}-${AGENT_CONFIG_VERSIONS[0]}"
AGENT_CONFIG_VERSION=${AGENT_CONFIG_VERSIONS[0]}
else
# fall back to old default way
css_path="css:$CSS_OBJ_PATH_DEFAULT"
fi
fi
# now do the downloading
if [[ -n $css_path ]]; then
download_css_file "$css_path/$AGENT_CFG_FILE_DEFAULT"
fi
fi
echo "AGENT_CONFIG_VERSION=$AGENT_CONFIG_VERSION"
# the cfg is specific to the instance of the cluster, so not available from anax/release
#elif [[ $input_file_path == https://github.com/open-horizon/anax/releases* ]]; then
# download_anax_release_file "$input_file_path/$AGENT_CFG_FILE_DEFAULT"
log_debug "download_config_file() end"
}
# Read the configuration file and put each value in CFG_<envvarname>, so each later can be applied with the correct precedence
# Side-effect: sets or adjusts AGENT_CFG_FILE
function read_config_file() {
log_debug "read_config_file() begin"
# Get/locate cfg file
if [[ -n $AGENT_CFG_FILE && -f $AGENT_CFG_FILE ]]; then
: # just fall thru this if-else to read the config file
elif using_remote_input_files 'cfg'; then
if [[ $AGENT_CFG_FILE == css:* ]]; then
download_config_file "$AGENT_CFG_FILE" 1 # in this case AGENT_CFG_FILE is the css object path NOT including the last part (agent-install.cfg)
else
if [[ -n $AGENT_CFG_FILE && $AGENT_CFG_FILE != $AGENT_CFG_FILE_DEFAULT ]]; then
log_fatal 1 "Can not specify both -k (AGENT_CFG_FILE) and -i (INPUT_FILE_PATH)"
fi
download_config_file "$INPUT_FILE_PATH" 0
fi
AGENT_CFG_FILE=$AGENT_CFG_FILE_DEFAULT # this is where download_config_file() will put it
elif [[ -z $AGENT_CFG_FILE ]]; then
if [[ -f $AGENT_CFG_FILE_DEFAULT ]]; then
AGENT_CFG_FILE=$AGENT_CFG_FILE_DEFAULT # Only apply this default if the file is actually there
else
log_info "Configuration file not specified. All required input variables must be set via command arguments or the environment."
return
fi
elif [[ ! -f "$AGENT_CFG_FILE" ]]; then
log_fatal 1 "Configuration file $AGENT_CFG_FILE not found."
fi
log_debug "Start to get config version from AGENT_CFG_FILE: $AGENT_CFG_FILE"
set +e # Need to disable for the following command so script doesn't terminate
config_in_file=$( cat ${AGENT_CFG_FILE} | grep "HZN_CONFIG_VERSION" )
config_version_in_file=${config_in_file#*=}
set -e
log_debug "config_version_in_file: $config_version_in_file"
# Add config version into config file
if [[ -n $AGENT_CONFIG_VERSION ]]; then
# write or replace AGENT_CERT_VERSION in file comment as config_version=x.x.x
if [[ -z $config_in_file ]]; then
# add
echo "HZN_CONFIG_VERSION=$AGENT_CONFIG_VERSION" >> $AGENT_CFG_FILE
elif [[ "$AGENT_CONFIG_VERSION" != "$config_version_in_file" ]]; then
# replace, overwrite with the agent config file version in css filename
sed -i -e "s#HZN_CONFIG_VERSION=${config_version_in_file}#HZN_CONFIG_VERSION=${AGENT_CONFIG_VERSION}#g" $AGENT_CFG_FILE
fi
fi
# Read/parse the config file. Note: omitting IFS= because we want leading and trailing whitespace trimmed. Also -n $line handles the case where there is not a newline at the end of the last line.
log_verbose "Using configuration file: $AGENT_CFG_FILE"
while read -r line || [[ -n "$line" ]]; do
if [[ -z $line || ${line:0:1} == '#' ]]; then continue; fi # ignore empty or commented lines
#echo "'$line'"
local var_name="CFG_${line%%=*}" # the variable name is the line with everything after the 1st = removed
IFS= read -r "$var_name" <<<"${line#*=}" # set the variable to the line with everything before the 1st = removed
done < "$AGENT_CFG_FILE"
log_debug "read_config_file() end"
}
# make sure that the given input file types has correct values.
# Side-effect: AGENT_CFG_FILE and/or AGENT_CERT_FILE changes to horizon default
# if -G or AGENT_UPGRADE_TYPES are specified and 'config' or 'cert'
# is not included.
function varify_upgrade_types() {
log_debug "varify_upgrade_types() begin"
# validate the input values
for t in ${AGENT_UPGRADE_TYPES//,/ }
do
if [ "$t" != "$UPGRADE_TYPE_SW" ] && [ "$t" != "$UPGRADE_TYPE_CERT" ] && [ "$t" != "$UPGRADE_TYPE_CFG" ]; then
log_fatal 1 "Invalid value in AGENT_UPGRADE_TYPES or -G flag: $AGENT_UPGRADE_TYPES"
fi
done
# use installed config file and certification file if they are not specified
if ! has_upgrade_type_cfg; then
if [ -f $INSTALLED_AGENT_CFG_FILE ]; then
# remove the HZN_MGMT_HUB_CERT_PATH line so that the provided cert file can be used (if any)
local tmp_dir=$(get_tmp_dir)
AGENT_CFG_FILE="${tmp_dir}/${AGENT_CERT_FILE_DEFAULT}"
sed '/HZN_MGMT_HUB_CERT_PATH/d' $INSTALLED_AGENT_CFG_FILE > $AGENT_CFG_FILE
log_info "AGENT_CFG_FILE is set to $AGENT_CFG_FILE"
else
log_fatal 1 "$INSTALLED_AGENT_CFG_FILE file does not exist when'$UPGRADE_TYPE_CFG' is not specified in AGENT_UPGRADE_TYPES or -G flag. Please make sure the agent is installed."
fi
fi
if ! has_upgrade_type_cert; then
if [ -f $INSTALLED_AGENT_CFG_FILE ]; then
local horizon_default_cert_file=$(grep -E '^HZN_MGMT_HUB_CERT_PATH=' $INSTALLED_AGENT_CFG_FILE || true)
horizon_default_cert_file=$(trim_variable "${horizon_default_cert_file#*=}")
AGENT_CERT_FILE=$horizon_default_cert_file
log_info "AGENT_CERT_FILE is set to $horizon_default_cert_file"
else
log_fatal 1 "$INSTALLED_AGENT_CFG_FILE file does not exist when'$UPGRADE_TYPE_CERT' is not specified in AGENT_UPGRADE_TYPES or -G flag. Please make sure the agent is installed."
fi
fi
log_debug "varify_upgrade_types() end"
}
# check if the upgrade type contains "software"
function has_upgrade_type_sw() {
for t in ${AGENT_UPGRADE_TYPES//,/ }
do
if [ "$t" == "$UPGRADE_TYPE_SW" ]; then
return 0
fi
done
return 1
}
# check if the upgrade type contains "cert"
function has_upgrade_type_cert() {
for t in ${AGENT_UPGRADE_TYPES//,/ }
do
if [ "$t" == "$UPGRADE_TYPE_CERT" ]; then
return 0
fi
done
return 1
}
# check if the upgrade type contains "configuration"
function has_upgrade_type_cfg() {
for t in ${AGENT_UPGRADE_TYPES//,/ }
do
if [ "$t" == "$UPGRADE_TYPE_CFG" ]; then
return 0
fi
done
return 1
}
# Create a temp directory for the agent.
# For anax-in-container case, the directory is /tmp/horizon{i}, where i is the container number.
# For native case, the directory is /tmp
function get_tmp_dir() {
local container_num=$(get_agent_container_number)