diff --git a/bin/airgap-include.sh b/bin/airgap-include.sh index b5c1f5e8..68db2a01 100644 --- a/bin/airgap-include.sh +++ b/bin/airgap-include.sh @@ -1,13 +1,15 @@ # Copyright © 2023-2024, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + # This file is not marked as executable as it is intended to be sourced # Current directory must be the root directory of the repo - if [ "$AIRGAP_SOURCED" == "" ]; then ## Check for AIRGAP_REGISTRY, if null/empty, error out. Otherwise set and create HELM_URL_BASE. - if [ -z $AIRGAP_REGISTRY ]; then + if [ -z "$AIRGAP_REGISTRY" ]; then log_error "AIRGAP_REGISTRY has not been set" log_error "Please provide the URL for the private image registry and try again" exit 1 @@ -16,31 +18,27 @@ if [ "$AIRGAP_SOURCED" == "" ]; then AIRGAP_IMAGE_PULL_SECRET_NAME=${AIRGAP_IMAGE_PULL_SECRET_NAME:-"v4m-image-pull-secret"} # Check for the image pull secret for the air gap environment - if [ -z "$(kubectl get secret -n $V4M_NS $AIRGAP_IMAGE_PULL_SECRET_NAME -o name --ignore-not-found)" ]; then - log_error "The image pull secret, [$AIRGAP_IMAGE_PULL_SECRET_NAME], was not detected" - log_error "Please add the image pull secret to the [$V4M_NS] namespace and run the deployment script again" - exit 1 + if [ -z "$(kubectl get secret -n "$V4M_NS" "$AIRGAP_IMAGE_PULL_SECRET_NAME" -o name --ignore-not-found)" ]; then + log_error "The image pull secret, [$AIRGAP_IMAGE_PULL_SECRET_NAME], was not detected" + log_error "Please add the image pull secret to the [$V4M_NS] namespace and run the deployment script again" + exit 1 fi AIRGAP_HELM_REPO=${AIRGAP_HELM_REPO:-"$AIRGAP_REGISTRY"} AIRGAP_HELM_FORMAT=${AIRGAP_HELM_FORMAT:-"oci"} if [ "$AIRGAP_HELM_FORMAT" == "tgz" ]; then - if [ ! -d "$AIRGAP_HELM_REPO" ]; then - log_error "When AIRGAP_HELM_FORMAT is 'tgz', AIRGAP_HELM_REPO is expected to be a directory." - log_error "The specified AIRGAP_HELM_REPO directory [$AIRGAP_HELM_REPO] does NOT exist." - exit 1 - else - log_debug "Confirmed AIRGAP_HELM_REPO [$AIRGAP_HELM_REPO] exists" - fi + if [ ! -d "$AIRGAP_HELM_REPO" ]; then + log_error "When AIRGAP_HELM_FORMAT is 'tgz', AIRGAP_HELM_REPO is expected to be a directory." + log_error "The specified AIRGAP_HELM_REPO directory [$AIRGAP_HELM_REPO] does NOT exist." + exit 1 + else + log_debug "Confirmed AIRGAP_HELM_REPO [$AIRGAP_HELM_REPO] exists" + fi fi fi log_info "Deploying into an 'air-gapped' cluster from private registry [$AIRGAP_REGISTRY]" - airgapDir="$TMP_DIR/airgap" - mkdir -p $airgapDir - export AIRGAP_SOURCED=true fi - diff --git a/bin/autogenerate-include.sh b/bin/autogenerate-include.sh index e3e7b0bf..8b94bd3e 100644 --- a/bin/autogenerate-include.sh +++ b/bin/autogenerate-include.sh @@ -1,10 +1,12 @@ # Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + # This file is not marked as executable as it is intended to be sourced # Current directory must be the root directory of the repo - function checkYqVersion { # confirm yq installed and correct version local goodver yq_version @@ -35,8 +37,8 @@ function create_ingress_certs { if [ -f "$certFile" ] && [ -f "$keyFile" ]; then kubectl delete secret "$secretName" --namespace "$namespace" --ignore-not-found kubectl create secret tls "$secretName" --namespace "$namespace" --key="$keyFile" --cert="$certFile" - kubectl -n $namespace label secret $secretName managed-by="v4m-es-script" - elif [ ! -z "$certFile$keyFile" ]; then + kubectl -n "$namespace" label secret "$secretName" managed-by="v4m-es-script" + elif [ -n "$certFile$keyFile" ]; then log_warn "Missing Ingress certificate file; specified Ingress cert [$certFile] and/or key [$keyFile] file is missing." log_warn "Create the missing Kubernetes secrets after deployment; use command: kubectl -create secret tls $secretName --namespace $namespace --key=cert_key_file --cert=cert_file" fi @@ -70,8 +72,12 @@ if [ -z "$AUTOGENERATE_SOURCED" ]; then exit 1 fi - #validate required inputs - BASE_DOMAIN="${BASE_DOMAIN}" + #validate required inputs: + # BASE_DOMAIN + # ROUTING + # INGRESS_CERT + # INGRESS_KEY + if [ -z "$BASE_DOMAIN" ]; then log_error "Required parameter [BASE_DOMAIN] not provided" exit 1 @@ -87,8 +93,6 @@ if [ -z "$AUTOGENERATE_SOURCED" ]; then exit 1 fi - INGRESS_CERT="${INGRESS_CERT}" - INGRESS_KEY="${INGRESS_KEY}" if [ "$INGRESS_CERT/$INGRESS_KEY" != "/" ]; then if [ ! -f "$INGRESS_CERT" ] || [ ! -f "$INGRESS_KEY" ]; then # Only WARN b/c missing cert doesn't prevent deployment and it can be created afterwards @@ -112,21 +116,15 @@ if [ -z "$AUTOGENERATE_SOURCED" ]; then if [ "$AUTOGENERATE_SMTP" == "true" ]; then - #required - # shellcheck disable=SC2269 - SMTP_HOST="${SMTP_HOST}" - # shellcheck disable=SC2269 - SMTP_PORT="${SMTP_PORT}" - # shellcheck disable=SC2269 - SMTP_FROM_ADDRESS="${SMTP_FROM_ADDRESS}" - # shellcheck disable=SC2269 - SMTP_FROM_NAME="${SMTP_FROM_NAME}" - - #optional - # shellcheck disable=SC2269 - SMTP_USER="${SMTP_USER}" - # shellcheck disable=SC2269 - SMTP_PASSWORD="${SMTP_PASSWORD}" + #required settings + # SMTP_HOST - no default + # SMTP_PORT - no default + # SMTP_FROM_ADDRESS - no default + # SMTP_FROM_NAME - no default + + #optional settings + # SMTP_USER - no default + # SMTP_PASSWORD - no default SMTP_USER_SECRET="${SMTP_USER_SECRET:-grafana-smtp-user}" SMTP_SKIP_VERIFY="${SMTP_SKIP_VERIFY:-false}" SMTP_TLS_CERT_FILE="${SMTP_TLS_CERT_FILE:-/cert/tls.crt}" @@ -159,7 +157,7 @@ if [ -z "$AUTOGENERATE_SOURCED" ]; then log_debug "Secret [$SMTP_USER_SECRET] exists; will use it for SMTP user credentials" elif [ -z "$SMTP_USER" ] && [ -z "$SMTP_PASSWORD" ]; then log_debug "Neither SMTP_USER nor SMTP_PASSWORD are set; skipping creation of secret [$SMTP_USER_SECRET]" - elif [ -z "$SMTP_USER" ] || [ -z "$SMTP_PASSWORD" ]; then + elif [ -z "$SMTP_USER" ] || [ -z "$SMTP_PASSWORD" ]; then log_error "Complete SMTP Credentials NOT provided; MUST provide BOTH [SMTP_USER] and [SMTP_PASSWORD]" log_info "SMTP_USER is set to [$SMTP_USER] and SMTP_PASSWORD is set to [$SMTP_PASSWORD]" exit 1 @@ -173,13 +171,12 @@ if [ -z "$AUTOGENERATE_SOURCED" ]; then export AUTOGENERATE_SOURCED="true" - elif [ "$AUTOGENERATE_SOURCED" == "NotNeeded" ]; then - log_debug "autogenerate-include.sh not needed" - else - log_debug "autogenerate-include.sh was already sourced [$AUTOGENERATE_SOURCED]" +elif [ "$AUTOGENERATE_SOURCED" == "NotNeeded" ]; then + log_debug "autogenerate-include.sh not needed" +else + log_debug "autogenerate-include.sh was already sourced [$AUTOGENERATE_SOURCED]" fi - function checkStorageClass { # input parms: $1 *Name of env var* identifying storageClass # input parms: $2 storageClass @@ -193,7 +190,8 @@ function checkStorageClass { log_error "Required parameter not provided. Either [$storageClassEnvVar] or [STORAGECLASS] MUST be provided." exit 1 else - if $(kubectl get storageClass "$storageClass" -o name &>/dev/null); then + # shellcheck disable=SC2091 + if $(kubectl get storageClass "$storageClass" -o name &> /dev/null); then log_debug "The specified StorageClass [$storageClass] exists" else log_error "The specified StorageClass [$storageClass] does NOT exist" diff --git a/bin/colors-include.sh b/bin/colors-include.sh index 61bfcdaa..b7287ef0 100644 --- a/bin/colors-include.sh +++ b/bin/colors-include.sh @@ -1,6 +1,9 @@ # Copyright © 2020, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + # Added background colors and functions # Colors @@ -34,67 +37,67 @@ lightbluebg="\033[46m" # Foregrounds function black { - echo -e "${black}${1}${end}" >&3 + echo -e "${black}${1}${end}" >&3 } function blackb { - echo -e "${blackb}${1}${end}" >&3 + echo -e "${blackb}${1}${end}" >&3 } function white { - echo -e "${white}${1}${end}" >&3 + echo -e "${white}${1}${end}" >&3 } function whiteb { - echo -e "${whiteb}${1}${end}" >&3 + echo -e "${whiteb}${1}${end}" >&3 } function red { - echo -e "${red}${1}${end}" >&3 + echo -e "${red}${1}${end}" >&3 } function redb { - echo -e "${redb}${1}${end}" >&3 + echo -e "${redb}${1}${end}" >&3 } function green { - echo -e "${green}${1}${end}" >&3 + echo -e "${green}${1}${end}" >&3 } function greenb { - echo -e "${greenb}${1}${end}" >&3 + echo -e "${greenb}${1}${end}" >&3 } function yellow { - echo -e "${yellow}${1}${end}" >&3 + echo -e "${yellow}${1}${end}" >&3 } function yellowb { - echo -e "${yellowb}${1}${end}" >&3 + echo -e "${yellowb}${1}${end}" >&3 } function blue { - echo -e "${blue}${1}${end}" >&3 + echo -e "${blue}${1}${end}" >&3 } function blueb { - echo -e "${blueb}${1}${end}" >&3 + echo -e "${blueb}${1}${end}" >&3 } function purple { - echo -e "${purple}${1}${end}" >&3 + echo -e "${purple}${1}${end}" >&3 } function purpleb { - echo -e "${purpleb}${1}${end}" >&3 + echo -e "${purpleb}${1}${end}" >&3 } function lightblue { - echo -e "${lightblue}${1}${end}" >&3 + echo -e "${lightblue}${1}${end}" >&3 } function lightblueb { - echo -e "${lightblueb}${1}${end}" >&3 + echo -e "${lightblueb}${1}${end}" >&3 } # Export all the things diff --git a/bin/common.sh b/bin/common.sh index 9b440491..ce173f47 100644 --- a/bin/common.sh +++ b/bin/common.sh @@ -1,3 +1,4 @@ +# shellcheck disable=SC2148 # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 @@ -5,31 +6,33 @@ # Current directory must be the root directory of the repo function trap_add() { - # based on https://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal - # but: prepends new cmd rather than append it, changed var names and eliminated messages - - local cmd_to_add signal - - cmd_to_add=$1; shift - for signal in "$@"; do - trap -- "$( - # print the new trap command - printf '%s\n' "${cmd_to_add}" - # helper fn to get existing trap command from output - # of trap -p - extract_trap_cmd() { printf '%s\n' "$3"; } - # print existing trap command with newline - eval "extract_trap_cmd $(trap -p "${signal}")" - )" "${signal}" - done + # based on https://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal + # but: prepends new cmd rather than append it, changed var names and eliminated messages + + local cmd_to_add signal + + cmd_to_add=$1 + shift + for signal in "$@"; do + trap -- "$( + # print the new trap command + printf '%s\n' "${cmd_to_add}" + # helper fn to get existing trap command from output + # of trap -p + # shellcheck disable=SC2329,SC2317 + extract_trap_cmd() { printf '%s\n' "$3"; } + # print existing trap command with newline + eval "extract_trap_cmd $(trap -p "${signal}")" + )" "${signal}" + done } function errexit_msg { - if [ -o errexit ]; then - log_error "Exiting script [`basename $0`] due to an error executing the command [$BASH_COMMAND]." - else - log_debug "Trap [ERR] triggered in [`basename $0`] while executing the command [$BASH_COMMAND]." - fi + if [ -o errexit ]; then + log_error "Exiting script [$(basename "$0")] due to an error executing the command [$BASH_COMMAND]." + else + log_debug "Trap [ERR] triggered in [$(basename "$0")] while executing the command [$BASH_COMMAND]." + fi } if [ "$SAS_COMMON_SOURCED" = "" ]; then @@ -41,9 +44,9 @@ if [ "$SAS_COMMON_SOURCED" = "" ]; then source bin/log-include.sh source bin/openshift-include.sh - if [ ! $(which sha256sum) ]; then - log_error "Missing required utility: sha256sum" - exit 1 + if [ ! "$(which sha256sum)" ]; then + log_error "Missing required utility: sha256sum" + exit 1 fi # Load component Helm chart version infomation @@ -52,32 +55,38 @@ if [ "$SAS_COMMON_SOURCED" = "" ]; then if [ -f "component_versions.env" ]; then userEnv=$(grep -v '^[[:blank:]]*$' component_versions.env | grep -v '^#' | xargs) if [ "$userEnv" != "" ]; then - log_debug "Loading global user environment file: component_versions.env" - if [ "$userEnv" != "" ]; then - export $userEnv - fi + log_debug "Loading global user environment file: component_versions.env" + if [ "$userEnv" != "" ]; then + # shellcheck disable=SC2163,SC2086 + export $userEnv + fi fi else log_debug "No component_versions.env file found" fi if [ "$V4M_OMIT_IMAGE_KEYS" == "true" ]; then - log_warn "******This feature is NOT intended for use outside the project maintainers*******" - log_warn "Environment variable V4M_OMIT_IMAGE_KEYS set to [true]; container image information from component_versions.env will be ignored." + log_warn "******This feature is NOT intended for use outside the project maintainers*******" + log_warn "Environment variable V4M_OMIT_IMAGE_KEYS set to [true]; container image information from component_versions.env will be ignored." fi export USER_DIR=${USER_DIR:-$(pwd)} if [ -d "$USER_DIR" ]; then - # Resolve full path - export USER_DIR=$(cd "$(dirname "$USER_DIR")"; pwd)/$(basename "$USER_DIR") + # Resolve full path + USER_DIR=$( + cd "$(dirname "$USER_DIR")" || exit + pwd + )/$(basename "$USER_DIR") + export USER_DIR fi if [ -f "$USER_DIR/user.env" ]; then - userEnv=$(grep -v '^[[:blank:]]*$' $USER_DIR/user.env | grep -v '^#' | xargs) + userEnv=$(grep -v '^[[:blank:]]*$' "$USER_DIR"/user.env | grep -v '^#' | xargs) if [ "$userEnv" != "" ]; then - log_debug "Loading global user environment file: $USER_DIR/user.env" - if [ "$userEnv" != "" ]; then - export $userEnv - fi + log_debug "Loading global user environment file: $USER_DIR/user.env" + if [ "$userEnv" != "" ]; then + # shellcheck disable=SC2163,SC2086 + export $userEnv + fi fi fi @@ -88,56 +97,56 @@ if [ "$SAS_COMMON_SOURCED" = "" ]; then CHECK_HELM=${CHECK_HELM:-true} if [ "$CHECK_HELM" == "true" ]; then - source bin/helm-include.sh - log_verbose "Helm client version: $HELM_VER_FULL" + source bin/helm-include.sh + log_verbose "Helm client version: $HELM_VER_FULL" fi CHECK_KUBERNETES=${CHECK_KUBERNETES:-true} if [ "$CHECK_KUBERNETES" == "true" ]; then - source bin/kube-include.sh - - log_verbose Kubernetes client version: "$KUBE_CLIENT_VER" - log_verbose Kubernetes server version: "$KUBE_SERVER_VER" - - # Check that the current KUBECONFIG has admin access - CHECK_ADMIN=${CHECK_ADMIN:-true} - if [ "$CHECK_ADMIN" == "true" ]; then - if [ "$(kubectl auth can-i create namespace --all-namespaces)" == "no" ]; then - ctx=$(kubectl config current-context) - log_error "The current kubectl context [$ctx] does not have cluster admin access" - exit 1 - else - log_debug "Cluster admin check OK" - fi - else - log_debug "Cluster admin check disabled" - fi + source bin/kube-include.sh + + log_verbose Kubernetes client version: "$KUBE_CLIENT_VER" + log_verbose Kubernetes server version: "$KUBE_SERVER_VER" + + # Check that the current KUBECONFIG has admin access + CHECK_ADMIN=${CHECK_ADMIN:-true} + if [ "$CHECK_ADMIN" == "true" ]; then + if [ "$(kubectl auth can-i create namespace --all-namespaces)" == "no" ]; then + ctx=$(kubectl config current-context) + log_error "The current kubectl context [$ctx] does not have cluster admin access" + exit 1 + else + log_debug "Cluster admin check OK" + fi + else + log_debug "Cluster admin check disabled" + fi fi # set TLS Cert Generator (cert-manager|openssl) export CERT_GENERATOR="${CERT_GENERATOR:-openssl}" - # Set default timeout for kubectl namespace delete command export KUBE_NAMESPACE_DELETE_TIMEOUT=${KUBE_NAMESPACE_DELETE_TIMEOUT:-5m} - export TMP_DIR=$(mktemp -d -t sas.mon.XXXXXXXX) + TMP_DIR=$(mktemp -d -t sas.mon.XXXXXXXX) + export TMP_DIR if [ ! -d "$TMP_DIR" ]; then - log_error "Could not create temporary directory [$TMP_DIR]" - exit 1 + log_error "Could not create temporary directory [$TMP_DIR]" + exit 1 fi log_debug "Temporary directory: [$TMP_DIR]" - echo "# This file intentionally empty" > $TMP_DIR/empty.yaml + echo "# This file intentionally empty" > "$TMP_DIR"/empty.yaml # Delete the temp directory on exit function cleanup { - KEEP_TMP_DIR=${KEEP_TMP_DIR:-false} - if [ "$KEEP_TMP_DIR" != "true" ]; then - rm -rf "$TMP_DIR" - log_debug "Deleted temporary directory: [$TMP_DIR]" - else - log_info "TMP_DIR [$TMP_DIR] was not removed" - fi + KEEP_TMP_DIR=${KEEP_TMP_DIR:-false} + if [ "$KEEP_TMP_DIR" != "true" ]; then + rm -rf "$TMP_DIR" + log_debug "Deleted temporary directory: [$TMP_DIR]" + else + log_info "TMP_DIR [$TMP_DIR] was not removed" + fi } trap_add cleanup EXIT @@ -148,104 +157,103 @@ fi function checkDefaultStorageClass { if [ -z "$defaultStorageClass" ]; then - # Check for kubernetes environment conflicts/requirements - defaultStorageClass=$(kubectl get storageclass -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.metadata.annotations..storageclass\.kubernetes\.io/is-default-class}{'\n'}{end}" | grep true | awk '{print $1}') - if [ "$defaultStorageClass" ]; then - log_debug "Found default storageClass: [$defaultStorageClass]" - else - # Try again with beta storageclass annotation key - defaultStorageClass=$(kubectl get storageclass -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.metadata.annotations..storageclass\.beta\.kubernetes\.io/is-default-class}{'\n'}{end}" | grep true | awk '{print $1}') + # Check for kubernetes environment conflicts/requirements + defaultStorageClass=$(kubectl get storageclass -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.metadata.annotations..storageclass\.kubernetes\.io/is-default-class}{'\n'}{end}" | grep true | awk '{print $1}') if [ "$defaultStorageClass" ]; then - log_debug "Found default storageClass: [$defaultStorageClass]" + log_debug "Found default storageClass: [$defaultStorageClass]" else - log_warn "This cluster does not have a default storageclass defined" - log_warn "This may cause errors unless storageclass values are explicitly defined" - defaultStorageClass=_NONE_ + # Try again with beta storageclass annotation key + defaultStorageClass=$(kubectl get storageclass -o jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.metadata.annotations..storageclass\.beta\.kubernetes\.io/is-default-class}{'\n'}{end}" | grep true | awk '{print $1}') + if [ "$defaultStorageClass" ]; then + log_debug "Found default storageClass: [$defaultStorageClass]" + else + log_warn "This cluster does not have a default storageclass defined" + log_warn "This may cause errors unless storageclass values are explicitly defined" + defaultStorageClass=_NONE_ + fi fi - fi fi } function validateTenantID { - tenantID=$1 - reservedNames=(default provider shared sharedservices spre uaa viya) - - CHECK_TENANT_NAME=${CHECK_TENANT_NAME:-true} - if [ "$CHECK_TENANT_NAME" == "true" ]; then - if [[ $tenantID =~ ^[a-z]([a-z0-9]){0,15}$ ]]; then - if [[ $tenantID =~ ^sas ]]; then - log_error "Tenant names cannot start with 'sas'" - exit 1 - fi - for n in ${reservedNames[@]}; do - if [ "$tenantID" == "$n" ]; then - log_error "The tenant name [$tenantID] is a reserved name" - exit 1 + tenantID=$1 + reservedNames=(default provider shared sharedservices spre uaa viya) + + CHECK_TENANT_NAME=${CHECK_TENANT_NAME:-true} + if [ "$CHECK_TENANT_NAME" == "true" ]; then + if [[ $tenantID =~ ^[a-z]([a-z0-9]){0,15}$ ]]; then + if [[ $tenantID =~ ^sas ]]; then + log_error "Tenant names cannot start with 'sas'" + exit 1 + fi + for n in "${reservedNames[@]}"; do + if [ "$tenantID" == "$n" ]; then + log_error "The tenant name [$tenantID] is a reserved name" + exit 1 + fi + done + else + log_error "[$tenantID] is not a valid tenant name" + exit 1 fi - done else - log_error "[$tenantID] is not a valid tenant name" - exit 1 + log_debug "Tenant name validation is disabled" fi - else - log_debug "Tenant name validation is disabled" - fi } - function validateNamespace { - local namespace - namespace="$1" - if [[ "$namespace" =~ ^[a-z0-9]([\-a-z0-9]*[a-z0-9])?$ ]]; then - log_debug "Namespace [$namespace] passes validation" - else - log_error "[$namespace] is not a valid namespace name" - exit 1 - fi + local namespace + namespace="$1" + if [[ $namespace =~ ^[a-z0-9]([\-a-z0-9]*[a-z0-9])?$ ]]; then + log_debug "Namespace [$namespace] passes validation" + else + log_error "[$namespace] is not a valid namespace name" + exit 1 + fi } - function randomPassword { - date +%s | sha256sum | base64 | head -c 32 ; echo + date +%s | sha256sum | base64 | head -c 32 + echo } function disable_sa_token_automount { - local ns sa_name should_disable - ns=$1 - sa_name=$2 - should_disable=${SEC_DISABLE_SA_TOKEN_AUTOMOUNT:-true} - - if [ "$should_disable" == "true" ]; then - if [ -n "$(kubectl -n "$ns" get serviceAccount "$sa_name" -o name 2>/dev/null)" ]; then - log_debug "Disabling automount of API tokens for serviceAccount [$ns/$sa_name]" - kubectl -n $ns patch serviceAccount $sa_name -p '{"automountServiceAccountToken":false}' + local ns sa_name should_disable + ns=$1 + sa_name=$2 + should_disable=${SEC_DISABLE_SA_TOKEN_AUTOMOUNT:-true} + + if [ "$should_disable" == "true" ]; then + if [ -n "$(kubectl -n "$ns" get serviceAccount "$sa_name" -o name 2> /dev/null)" ]; then + log_debug "Disabling automount of API tokens for serviceAccount [$ns/$sa_name]" + kubectl -n "$ns" patch serviceAccount "$sa_name" -p '{"automountServiceAccountToken":false}' + else + log_debug "ServiceAccount [$ns/$sa_name] not found. Skipping patch" + fi else - log_debug "ServiceAccount [$ns/$sa_name] not found. Skipping patch" + log_debug "NOT disabling token automount serviceAccount [$ns/$sa_name]; SEC_DISABLE_SA_TOKEN_AUTOMOUNT set to [$SEC_DISABLE_SA_TOKEN_AUTOMOUNT]" fi - else - log_debug "NOT disabling token automount serviceAccount [$ns/$sa_name]; SEC_DISABLE_SA_TOKEN_AUTOMOUNT set to [$SEC_DISABLE_SA_TOKEN_AUTOMOUNT]" - fi } function enable_pod_token_automount { - local ns resource_type resource_name should_disable - ns=$1 - resource_type=$2 - resource_name=$3 - should_disable=${SEC_DISABLE_SA_TOKEN_AUTOMOUNT:-true} - - if [ "$should_disable" == "true" ]; then - log_debug "Enabling automount of API tokens for pods deployed via [$resource_type/$resource_name]" - - if [ "$resource_type" == "daemonset" ] || [ "$resource_type" == "deployment" ]; then - kubectl -n $ns patch $resource_type $resource_name -p '{"spec": {"template": {"spec": {"automountServiceAccountToken":true}}}}' - else - log_error "Invalid request to function [${FUNCNAME[0]}]; unsupported resource_type [$resource_type]" - return 1 - fi - else - log_debug "NOT enabling token automount on pods for [$ns/$resource_type/$resource_name]; SEC_DISABLE_SA_TOKEN_AUTOMOUNT set to [$SEC_DISABLE_SA_TOKEN_AUTOMOUNT]" - fi + local ns resource_type resource_name should_disable + ns=$1 + resource_type=$2 + resource_name=$3 + should_disable=${SEC_DISABLE_SA_TOKEN_AUTOMOUNT:-true} + + if [ "$should_disable" == "true" ]; then + log_debug "Enabling automount of API tokens for pods deployed via [$resource_type/$resource_name]" + + if [ "$resource_type" == "daemonset" ] || [ "$resource_type" == "deployment" ]; then + kubectl -n "$ns" patch "$resource_type" "$resource_name" -p '{"spec": {"template": {"spec": {"automountServiceAccountToken":true}}}}' + else + log_error "Invalid request to function [${FUNCNAME[0]}]; unsupported resource_type [$resource_type]" + return 1 + fi + else + log_debug "NOT enabling token automount on pods for [$ns/$resource_type/$resource_name]; SEC_DISABLE_SA_TOKEN_AUTOMOUNT set to [$SEC_DISABLE_SA_TOKEN_AUTOMOUNT]" + fi } export -f checkDefaultStorageClass @@ -258,103 +266,102 @@ export -f disable_sa_token_automount export -f enable_pod_token_automount function parseFullImage { - fullImage="$1" - unset REGISTRY REPOS IMAGE VERSION FULL_IMAGE_ESCAPED - - if [[ "$1" =~ (.*)\/(.*)\/(.*)\:(.*) ]]; then - - REGISTRY="${BASH_REMATCH[1]}" - REPOS="${BASH_REMATCH[2]}" - IMAGE="${BASH_REMATCH[3]}" - VERSION="${BASH_REMATCH[4]}" - FULL_IMAGE_ESCAPED="$REGISTRY\/$REPOS\/$IMAGE\:$VERSION" - return 0 - else - log_warn "Invalid value for full container image; does not fit expected pattern [$1]." - return 1 - fi + # shellcheck disable=SC2034 + fullImage="$1" + unset REGISTRY REPOS IMAGE VERSION FULL_IMAGE_ESCAPED + + if [[ $1 =~ (.*)\/(.*)\/(.*)\:(.*) ]]; then + REGISTRY="${BASH_REMATCH[1]}" + REPOS="${BASH_REMATCH[2]}" + IMAGE="${BASH_REMATCH[3]}" + VERSION="${BASH_REMATCH[4]}" + # shellcheck disable=SC2034 + FULL_IMAGE_ESCAPED="$REGISTRY\/$REPOS\/$IMAGE\:$VERSION" + return 0 + else + log_warn "Invalid value for full container image; does not fit expected pattern [$1]." + return 1 + fi } - function v4m_replace { if echo "$OSTYPE" | grep 'darwin' > /dev/null 2>&1; then - sed -i '' "s;$1;$2;g" "$3" + sed -i '' "s;$1;$2;g" "$3" else - sed -i "s;$1;$2;g" "$3" + sed -i "s;$1;$2;g" "$3" fi } function generateImageKeysFile { - #arg1 Full container image - #arg2 name of template file - #arg3 prefix to insert in placeholders (optional; defaults to "") - #arg4 flag to override omit_image_key logic (optional; defaults to "false") - - #NOTE: arg4 is required to handle 2 initContainers (for OpenSearch and Fluent Bit) - # for which the template file contains settings other than image specs - - local pullsecret_text - - if ! parseFullImage "$1"; then - log_error "Unable to parse full image [$1]" - return 1 - fi - - prefix=${3:-""} - ignoreOmitImageKeys=${4:-"false"} - - imageKeysFile="$TMP_DIR/imageKeysFile.yaml" - template_file=$2 - - if [ "$template_file" != "$imageKeysFile" ]; then - rm -f $imageKeysFile - cp $template_file $imageKeysFile - else - log_debug "Modifying an existing imageKeysFile" - fi - - if [ "$V4M_OMIT_IMAGE_KEYS" == "true" ] && [ "$ignoreOmitImageKeys" != "true" ]; then - cp $TMP_DIR/empty.yaml $imageKeysFile - return 0 - fi - - if [ "$AIRGAP_DEPLOYMENT" == "true" ]; then - GLOBAL_REGISTRY_OSBUG="$AIRGAP_REGISTRY" - GLOBAL_REGISTRY="$AIRGAP_REGISTRY" - REGISTRY="$AIRGAP_REGISTRY" - - if [ -n "$AIRGAP_IMAGE_PULL_SECRET_NAME" ]; then - pullsecrets_text="[name: ""$AIRGAP_IMAGE_PULL_SECRET_NAME""]" - pullsecret_text="$AIRGAP_IMAGE_PULL_SECRET_NAME" - else - pullsecrets_text="[]" - pullsecret_text="null" - fi - else - GLOBAL_REGISTRY_OSBUG='""' - GLOBAL_REGISTRY="null" - pullsecrets_text="[]" - pullsecret_text="null" - fi - - v4m_pullPolicy=${V4M_PULL_POLICY:-"IfNotPresent"} - - v4m_replace "__${prefix}GLOBAL_REGISTRY_OSBUG__" "$GLOBAL_REGISTRY_OSBUG" "$imageKeysFile" - v4m_replace "__${prefix}GLOBAL_REGISTRY__" "$GLOBAL_REGISTRY" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_REGISTRY__" "$REGISTRY" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_REPO_3LEVEL__" "$REGISTRY\/$REPOS\/$IMAGE" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_REPO_2LEVEL__" "$REPOS\/$IMAGE" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE__" "$IMAGE" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_TAG__" "$VERSION" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_PULL_POLICY__" "$v4m_pullPolicy" "$imageKeysFile" - v4m_replace "__${prefix}IMAGE_PULL_SECRET__" "$pullsecret_text" "$imageKeysFile" #Handle Charts Accepting a Single Image Pull Secret - v4m_replace "__${prefix}IMAGE_PULL_SECRETS__" "$pullsecrets_text" "$imageKeysFile" #Handle Charts Accepting Multiple Image Pull Secrets - - return 0 -} + #arg1 Full container image + #arg2 name of template file + #arg3 prefix to insert in placeholders (optional; defaults to "") + #arg4 flag to override omit_image_key logic (optional; defaults to "false") + #NOTE: arg4 is required to handle 2 initContainers (for OpenSearch and Fluent Bit) + # for which the template file contains settings other than image specs + + local pullsecret_text + + if ! parseFullImage "$1"; then + log_error "Unable to parse full image [$1]" + return 1 + fi + + prefix=${3:-""} + ignoreOmitImageKeys=${4:-"false"} + + imageKeysFile="$TMP_DIR/imageKeysFile.yaml" + template_file=$2 + + if [ "$template_file" != "$imageKeysFile" ]; then + rm -f "$imageKeysFile" + cp "$template_file" "$imageKeysFile" + else + log_debug "Modifying an existing imageKeysFile" + fi + + if [ "$V4M_OMIT_IMAGE_KEYS" == "true" ] && [ "$ignoreOmitImageKeys" != "true" ]; then + cp "$TMP_DIR"/empty.yaml "$imageKeysFile" + return 0 + fi + + if [ "$AIRGAP_DEPLOYMENT" == "true" ]; then + GLOBAL_REGISTRY_OSBUG="$AIRGAP_REGISTRY" + GLOBAL_REGISTRY="$AIRGAP_REGISTRY" + REGISTRY="$AIRGAP_REGISTRY" + + if [ -n "$AIRGAP_IMAGE_PULL_SECRET_NAME" ]; then + pullsecrets_text="[name: ""$AIRGAP_IMAGE_PULL_SECRET_NAME""]" + pullsecret_text="$AIRGAP_IMAGE_PULL_SECRET_NAME" + else + pullsecrets_text="[]" + pullsecret_text="null" + fi + else + GLOBAL_REGISTRY_OSBUG='""' + GLOBAL_REGISTRY="null" + pullsecrets_text="[]" + pullsecret_text="null" + fi + + v4m_pullPolicy=${V4M_PULL_POLICY:-"IfNotPresent"} + + v4m_replace "__${prefix}GLOBAL_REGISTRY_OSBUG__" "$GLOBAL_REGISTRY_OSBUG" "$imageKeysFile" + v4m_replace "__${prefix}GLOBAL_REGISTRY__" "$GLOBAL_REGISTRY" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_REGISTRY__" "$REGISTRY" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_REPO_3LEVEL__" "$REGISTRY\/$REPOS\/$IMAGE" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_REPO_2LEVEL__" "$REPOS\/$IMAGE" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE__" "$IMAGE" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_TAG__" "$VERSION" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_PULL_POLICY__" "$v4m_pullPolicy" "$imageKeysFile" + v4m_replace "__${prefix}IMAGE_PULL_SECRET__" "$pullsecret_text" "$imageKeysFile" #Handle Charts Accepting a Single Image Pull Secret + v4m_replace "__${prefix}IMAGE_PULL_SECRETS__" "$pullsecrets_text" "$imageKeysFile" #Handle Charts Accepting Multiple Image Pull Secrets + + return 0 +} export -f parseFullImage export -f v4m_replace diff --git a/bin/configure_nodeport.sh b/bin/configure_nodeport.sh index eb4f4b59..206863e1 100755 --- a/bin/configure_nodeport.sh +++ b/bin/configure_nodeport.sh @@ -1,9 +1,9 @@ #! /bin/bash -# Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# Copyright ©2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -cd "$(dirname $BASH_SOURCE)/.." +cd "$(dirname "$BASH_SOURCE")/.." || exit source logging/bin/common.sh #TO DO: Should be done in bin/common? @@ -12,102 +12,90 @@ export MON_NS="${MON_NS:-monitoring}" # Confirm NOT on OpenShift if [ "$OPENSHIFT_CLUSTER" == "true" ]; then - if [ "${CHECK_OPENSHIFT_CLUSTER:-true}" == "true" ]; then - log_error "This script should NOT be run on OpenShift clusters" - log_error "Run 'logging/bin/create_openshift_route.sh' instead" - exit 1 - fi + if [ "${CHECK_OPENSHIFT_CLUSTER:-true}" == "true" ]; then + log_error "This script should NOT be run on OpenShift clusters" + log_error "Run 'logging/bin/create_openshift_route.sh' instead" + exit 1 + fi fi set -e app=${1} -arg1=$(echo "$arg1"| tr '[:lower:]' '[:upper:]') +arg1=$(echo "$arg1" | tr '[:lower:]' '[:upper:]') arg2=${2} -arg2=$(echo "$arg2"| tr '[:lower:]' '[:upper:]') +arg2=$(echo "$arg2" | tr '[:lower:]' '[:upper:]') -if [[ "$arg2" -ge 30000 ]] && [[ "$arg2" -le 32767 ]]; then - log_debug "Requested port [$target_port] is within valid range" - target_port="$arg2" +if [[ $arg2 -ge 30000 ]] && [[ $arg2 -le 32767 ]]; then + log_debug "Requested port [$target_port] is within valid range" + target_port="$arg2" elif [ "$arg2" == "0" ]; then - log_debug "Random port requested" - target_port="0" + log_debug "Random port requested" + target_port="0" elif [ "$arg2" == "DISABLE" ] || [ -z "$arg2" ]; then - log_debug "2nd argument: $arg2" + log_debug "2nd argument: $arg2" else - log_error "Invalid 2nd argument provided." - log_error "Value must be: a port number between 30000 and 32767, 0 (a random port will be assigned) or DISABLE (disable the current nodePort). " - exit 1 + log_error "Invalid 2nd argument provided." + log_error "Value must be: a port number between 30000 and 32767, 0 (a random port will be assigned) or DISABLE (disable the current nodePort). " + exit 1 fi -app=$(echo "$app"| tr '[:lower:]' '[:upper:]') +app=$(echo "$app" | tr '[:lower:]' '[:upper:]') case "$app" in - "OPENSEARCH"|"OS") - namespace=$LOG_NS - servicename=$ES_SERVICENAME - appname="OpenSearch" - target_port="${target_port:-0}" - ;; - "ELASTICSEARCH"|"ES") - namespace=$LOG_NS - servicename=$ES_SERVICENAME - appname="ELASTICSEARCH" - target_port="${target_port:-0}" - ;; - "OPENSEARCHDASHBOARDS"|"DASHBOARDS"|"OSD") - namespace=$LOG_NS - servicename=$KB_SERVICENAME - appname="OpenSearchDashboards" - target_port="${target_port:-31033}" - ;; - "KIBANA"|"KB") - namespace=$LOG_NS - servicename=$KB_SERVICENAME - appname="KIBANA" - target_port="${target_port:-31033}" - ;; - "ALERTMANAGER"|"AM") - namespace=$MON_NS - appname="AlertManager" - servicename="v4m-alertmanager" - target_port="${target_port:-31091}" - ;; - "PROMETHEUS"|"PROM"|"PRO"|"PR") - namespace=$MON_NS - appname="Prometheus" - servicename="v4m-prometheus" - target_port="${target_port:-31090}" - ;; - "GRAFANA"|"GRAF"|"GR") - namespace=$MON_NS - appname="Grafana" - servicename="v4m-grafana" - target_port="${target_port:-31100}" - ;; - ""|*) - log_error "Application name is invalid or missing." - log_error "The APPLICATION NAME is required; valid values are:" - log_error "OPENSEARCH, OPENSEARCHDASHBOARDS, GRAFANA, PROMETHEUS or ALERTMANAGER" - exit 1 - ;; +"OPENSEARCH" | "OS") + namespace=$LOG_NS + servicename=$ES_SERVICENAME + appname="OpenSearch" + target_port="${target_port:-0}" + ;; +"OPENSEARCHDASHBOARDS" | "DASHBOARDS" | "OSD") + namespace=$LOG_NS + servicename=$KB_SERVICENAME + appname="OpenSearchDashboards" + target_port="${target_port:-31033}" + ;; +"ALERTMANAGER" | "AM") + namespace=$MON_NS + appname="Alertmanager" + servicename="v4m-alertmanager" + target_port="${target_port:-31091}" + ;; +"PROMETHEUS" | "PROM" | "PRO" | "PR") + namespace=$MON_NS + appname="Prometheus" + servicename="v4m-prometheus" + target_port="${target_port:-31090}" + ;; +"GRAFANA" | "GRAF" | "GR") + namespace=$MON_NS + appname="Grafana" + servicename="v4m-grafana" + target_port="${target_port:-31100}" + ;; +"" | *) + log_error "Application name is invalid or missing." + log_error "The APPLICATION NAME is required; valid values are:" + log_error "OPENSEARCH, OPENSEARCHDASHBOARDS, GRAFANA, PROMETHEUS or ALERTMANAGER" + exit 1 + ;; esac -if [ "$arg2" == "DISABLE" ];then - log_info "Removing NodePort for [$servicename] in [$LOG_NS]" - kubectl -n "$namespace" patch svc "$servicename" --type='json' -p '[{"op":"replace","path":"/spec/type","value":"ClusterIP"}]' - exit +if [ "$arg2" == "DISABLE" ]; then + log_info "Removing NodePort for [$servicename] in [$LOG_NS]" + kubectl -n "$namespace" patch svc "$servicename" --type='json' -p '[{"op":"replace","path":"/spec/type","value":"ClusterIP"}]' + exit elif [ "$target_port" != "0" ]; then - log_info "Making [$servicename] in [$namespace] namespace available on port [$target_port]" - echo + log_info "Making [$servicename] in [$namespace] namespace available on port [$target_port]" + echo else - log_debug "No specific port was provided, will make [$servicename] available on a random port" + log_debug "No specific port was provided, will make [$servicename] available on a random port" fi kubectl -n "$namespace" patch svc "$servicename" --type='json' -p '[{"op":"replace","path":"/spec/type","value":"NodePort"}]' -kubectl -n "$namespace" patch svc "$servicename" --type='json' -p '[{"op":"replace","path":"/spec/ports/0/nodePort","value":'${target_port}'}]' +kubectl -n "$namespace" patch svc "$servicename" --type='json' -p '[{"op":"replace","path":"/spec/ports/0/nodePort","value":'"${target_port}"'}]' show_url="${SHOW_URL:-true}" if [ "$show_url" == "true" ]; then - bin/show_app_url.sh $appname + bin/show_app_url.sh $appname fi diff --git a/bin/helm-include.sh b/bin/helm-include.sh index d0bdd3b4..fff94d0f 100644 --- a/bin/helm-include.sh +++ b/bin/helm-include.sh @@ -1,18 +1,19 @@ -#!/bin/bash - # Copyright © 2020, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 # This script is not intended to be run directly + # Assumes bin/common.sh has been sourced -if [ ! $(which helm) ]; then - echo "helm not found on the current PATH" - exit 1 +if [ ! "$(which helm)" ]; then + echo "helm not found on the current PATH" + exit 1 fi -helmVer=$(helm version --short 2>/dev/null) -hver=( $(echo ${helmVer//[^0-9]/ }) ) +helmVer=$(helm version --short 2> /dev/null) +# shellcheck disable=SC2116,SC2086,SC2207 +hver=($(echo ${helmVer//[^0-9]/ })) HELM_VER_MAJOR=${hver[0]} HELM_VER_MINOR=${hver[1]} HELM_VER_PATCH=${hver[2]} @@ -24,116 +25,117 @@ if [ "$HELM_VER_MAJOR" == "2" ]; then exit 1 fi -if [ "$V4M_HELM_USE_LATEST" == "true" ]; then - log_warn "******This feature is NOT intended for use outside the project maintainers*******" - log_warn "Environment variable V4M_HELM_USE_LATEST set; deploying *latest* version of all Helm charts" +if [ "$V4M_HELM_USE_LATEST" == "true" ]; then + log_warn "******This feature is NOT intended for use outside the project maintainers*******" + log_warn "Environment variable V4M_HELM_USE_LATEST set; deploying *latest* version of all Helm charts" fi function helm2ReleaseExists { - release=$1 - log_debug "Checking for Helm 2.x release of [$release]" - releases=$(kubectl get configmap --all-namespaces -l "OWNER=TILLER" -o name) - if [[ $releases =~ configmap/$release\.v[0-9]+ ]]; then - log_debug "A Helm 2.x release of [$release] exists" - return 0 - else - return 1 - fi + release=$1 + log_debug "Checking for Helm 2.x release of [$release]" + releases=$(kubectl get configmap --all-namespaces -l "OWNER=TILLER" -o name) + if [[ $releases =~ configmap/$release\.v[0-9]+ ]]; then + log_debug "A Helm 2.x release of [$release] exists" + return 0 + else + return 1 + fi } function helm3ReleaseExists { - release=$1 - namespace=$2 - log_debug "Checking for Helm 3.x release of [$release]" - releases=$(kubectl get secret -n $namespace -l name=$release,owner=helm -o name) - if [[ $releases =~ secret/sh\.helm\.release\.v1\.$release\.v[0-9]+ ]]; then - log_debug "A Helm 3.x release of [$release] exists" - return 0 - else - return 1 - fi + release=$1 + namespace=$2 + log_debug "Checking for Helm 3.x release of [$release]" + releases=$(kubectl get secret -n "$namespace" -l name="$release",owner=helm -o name) + if [[ $releases =~ secret/sh\.helm\.release\.v1\.$release\.v[0-9]+ ]]; then + log_debug "A Helm 3.x release of [$release] exists" + return 0 + else + return 1 + fi } function helm2ReleaseCheck { - if [ "$HELM_RELEASE_CHECK" != "false" ]; then - release=$1 - if helm2ReleaseExists $release; then - log_error "A Helm 2.x release of [$release] already exists" - log_error "Helm [$HELM_VER_FULL] cannot manage the Helm 2.x release of [$release]" - exit 1 + if [ "$HELM_RELEASE_CHECK" != "false" ]; then + release=$1 + if helm2ReleaseExists "$release"; then + log_error "A Helm 2.x release of [$release] already exists" + log_error "Helm [$HELM_VER_FULL] cannot manage the Helm 2.x release of [$release]" + exit 1 + fi fi - fi } function helmRepoAdd { - repo=$1 - repoURL=$2 - - ## If this is an air gap deployment, do nothing - if [ "$AIRGAP_DEPLOYMENT" == "true" ]; then - return 0 - fi - - HELM_FORCE_REPO_UPDATE=${HELM_FORCE_REPO_UPDATE:-true} - if [[ ! $(helm repo list 2>/dev/null) =~ $repo[[:space:]] ]]; then - log_info "Adding [$repo] helm repository" - helm repo add $repo $repoURL - else - log_debug "The helm repo [$repo] already exists" - if [ "$HELM_FORCE_REPO_UPDATE" == "true" ]; then - log_debug "Forcing update of [$repo] helm repo to [$repoURL]" - - # Helm 3.3.2 changed 'repo add' behavior and added the --force-update flag - # https://github.com/helm/helm/releases/tag/v3.3.2 - if [[ $HELM_VER_MINOR -lt 3 || ( $HELM_VER_MINOR -eq 3 && $HELM_VER_PATCH -lt 2) ]]; then - helm repo add $repo $repoURL - else - helm repo add --force-update $repo $repoURL - fi + repo=$1 + repoURL=$2 + ## If this is an air gap deployment, do nothing + if [ "$AIRGAP_DEPLOYMENT" == "true" ]; then + return 0 + fi + + HELM_FORCE_REPO_UPDATE=${HELM_FORCE_REPO_UPDATE:-true} + # shellcheck disable=SC1087 + if [[ ! $(helm repo list 2> /dev/null) =~ $repo[[:space:]] ]]; then + log_info "Adding [$repo] helm repository" + helm repo add "$repo" "$repoURL" + else + log_debug "The helm repo [$repo] already exists" + if [ "$HELM_FORCE_REPO_UPDATE" == "true" ]; then + log_debug "Forcing update of [$repo] helm repo to [$repoURL]" + + # Helm 3.3.2 changed 'repo add' behavior and added the --force-update flag + # https://github.com/helm/helm/releases/tag/v3.3.2 + if [[ $HELM_VER_MINOR -lt 3 || ($HELM_VER_MINOR -eq 3 && $HELM_VER_PATCH -lt 2) ]]; then + helm repo add "$repo" "$repoURL" + else + helm repo add --force-update "$repo" "$repoURL" + fi + fi fi - fi } function get_helmchart_reference { - local chart_repository chart_name chart_version - - chart_repository=$1 - chart_name=$2 - chart_version=$3 - - if [ -z "$chart_repository" ]; then - echo "'ERROR: Helm chart repository not specified'" - return 1 - elif [ -z "$chart_name" ]; then - echo "'ERROR: Helm chart name not specified'" - return 1 - elif [ -z "$chart_version" ]; then - echo "'ERROR: Helm chart version not specified'" - return 1 - else - #all parms have values - : - fi - - if [ "$AIRGAP_HELM_FORMAT" == "tgz" ]; then - echo "${AIRGAP_HELM_REPO}/${chart_name}-${chart_version}.tgz" - elif [ "$AIRGAP_HELM_FORMAT" == "oci" ]; then - echo "oci://${AIRGAP_HELM_REPO}/${chart_repository}/${chart_name}" - else - echo "${chart_repository}/${chart_name}" - fi + local chart_repository chart_name chart_version + + chart_repository=$1 + chart_name=$2 + chart_version=$3 + + if [ -z "$chart_repository" ]; then + echo "'ERROR: Helm chart repository not specified'" + return 1 + elif [ -z "$chart_name" ]; then + echo "'ERROR: Helm chart name not specified'" + return 1 + elif [ -z "$chart_version" ]; then + echo "'ERROR: Helm chart version not specified'" + return 1 + else + #all parms have values + : + fi + + if [ "$AIRGAP_HELM_FORMAT" == "tgz" ]; then + echo "${AIRGAP_HELM_REPO}/${chart_name}-${chart_version}.tgz" + elif [ "$AIRGAP_HELM_FORMAT" == "oci" ]; then + echo "oci://${AIRGAP_HELM_REPO}/${chart_repository}/${chart_name}" + else + echo "${chart_repository}/${chart_name}" + fi } function get_helm_versionstring { - if [ "$V4M_HELM_USE_LATEST" == "true" ]; then - : # return null string + if [ "$V4M_HELM_USE_LATEST" == "true" ]; then + : # return null string else - # Explicitly use printf instead of echo to avoid quote issues - printf -- "--version %s" "$1" + # Explicitly use printf instead of echo to avoid quote issues + printf -- "--version %s" "$1" fi return } + export HELM_VER_FULL HELM_VER_MAJOR HELM_VER_MINOR HELM_VER_PATCH export -f helm2ReleaseExists export -f helm3ReleaseExists diff --git a/bin/kube-include.sh b/bin/kube-include.sh index b7f6cf15..2ac3c7ab 100644 --- a/bin/kube-include.sh +++ b/bin/kube-include.sh @@ -1,8 +1,8 @@ -#!/bin/bash - # Copyright © 2024,2020, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 + # This script is not intended to be run directly # Assumes bin/common.sh has been sourced diff --git a/bin/log-include.sh b/bin/log-include.sh index 1fcc237d..baef3d6b 100644 --- a/bin/log-include.sh +++ b/bin/log-include.sh @@ -1,6 +1,9 @@ # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + # Logging helper functions LOG_COLOR_ENABLE=${LOG_COLOR_ENABLE:-true} @@ -10,120 +13,120 @@ LOG_VERBOSE_ENABLE=${LOG_VERBOSE_ENABLE:-true} # This must be run without 'set -e' being set # So it has to be done up here and not within log_notice -if [ -z "$TERM" ] || ! tput cols >/dev/null 2>&1 ; then - # Non-interactive shell - LOG_COLOR_ENABLE=false - noticeColWidth=${LOG_NOTICE_COL_WIDTH:-100} +if [ -z "$TERM" ] || ! tput cols > /dev/null 2>&1; then + # Non-interactive shell + LOG_COLOR_ENABLE=false + noticeColWidth=${LOG_NOTICE_COL_WIDTH:-100} else - # Terminal width should be accessible - noticeColWidth=${LOG_NOTICE_COL_WIDTH:-$(tput cols)} - if [ "$noticeColWidth" == "" ]; then - noticeColWidth=100 - fi + # Terminal width should be accessible + noticeColWidth=${LOG_NOTICE_COL_WIDTH:-$(tput cols)} + if [ "$noticeColWidth" == "" ]; then + noticeColWidth=100 + fi fi if [ "$LOG_VERBOSE_ENABLE" != "true" ]; then - # Send stdout to /dev/null - # All non-error command output (kubectl, helm, etc.) will be suppressed - # for non-verbose mode. log_* calls will funtion normally since they are - # sent to &3, which is a copy of stdout - exec 1>/dev/null + # Send stdout to /dev/null + # All non-error command output (kubectl, helm, etc.) will be suppressed + # for non-verbose mode. log_* calls will funtion normally since they are + # sent to &3, which is a copy of stdout + exec 1> /dev/null fi function add_notice { - echo $* >> $TMP_DIR/notices.txt + echo "$*" >> "$TMP_DIR"/notices.txt } function display_notices { - if [ -f "$TMP_DIR/notices.txt" ]; then - local IFS='' - cat $TMP_DIR/notices.txt | while read line || [[ -n "$line" ]]; - do - log_notice "$line" - done - fi + if [ -f "$TMP_DIR/notices.txt" ]; then + while IFS= read -r line || [[ -n $line ]]; do log_notice "$line"; done < "$TMP_DIR"/notices.txt + fi } function log_notice { - width=$noticeColWidth - n=$(($width - $(echo "$1" | wc -c))) - if [ $n -lt 0 ]; then - n=0 - fi - # Fill remaining characters with spaces - text="$*$(printf %$(eval 'echo $n')s |tr ' ' ' ')" - - if [ "$LOG_COLOR_ENABLE" = "true" ]; then - whiteb "${bluebg}$text" - else - echo "$text" >&3 - fi + local msg + msg=$1 + width=$noticeColWidth + + n=$((width - ${#msg} - 1)) + if [ $n -lt 0 ]; then + n=0 + fi + # Fill remaining characters with spaces + # shellcheck disable=SC2046 + text="$*$(printf %$(eval 'echo $n')s | tr ' ' ' ')" + + if [ "$LOG_COLOR_ENABLE" = "true" ]; then + whiteb "${bluebg}$text" + else + echo "$text" >&3 + fi } function log_message { - echo "$*" >&3 + echo "$*" >&3 } function log_debug { - if [ "$LOG_DEBUG_ENABLE" = "true" ]; then + if [ "$LOG_DEBUG_ENABLE" = "true" ]; then + if [ "$LOG_LEVEL_ENABLE" = "true" ]; then + level="DEBUG " + else + level="" + fi + if [ "$LOG_COLOR_ENABLE" = "true" ]; then + echo -e "${whiteb}${level}${white}$*${end}" >&3 + else + echo "${level}$*" >&3 + fi + fi +} + +function log_info { if [ "$LOG_LEVEL_ENABLE" = "true" ]; then - level="DEBUG " + level="INFO " else level="" fi if [ "$LOG_COLOR_ENABLE" = "true" ]; then - echo -e "${whiteb}${level}${white}$*${end}" >&3 + echo -e "${greenb}${level}${whiteb}$*${end}" >&3 else echo "${level}$*" >&3 fi - fi -} - -function log_info { - if [ "$LOG_LEVEL_ENABLE" = "true" ]; then - level="INFO " - else - level="" - fi - if [ "$LOG_COLOR_ENABLE" = "true" ]; then - echo -e "${greenb}${level}${whiteb}$*${end}" >&3 - else - echo "${level}$*" >&3 - fi } # Verbose messages are basically optional, more detailed INFO messages # The value of LOG_VERBOSE_ENABLE determines whether they are displayed function log_verbose { - if [ "$LOG_VERBOSE_ENABLE" == "true" ]; then - log_info $* >&3 - fi + if [ "$LOG_VERBOSE_ENABLE" == "true" ]; then + log_info "$*" >&3 + fi } function log_warn { - if [ "$LOG_LEVEL_ENABLE" = "true" ]; then - level="WARN " - else - level="" - fi - if [ "$LOG_COLOR_ENABLE" = "true" ]; then - echo -e "${black}${yellowbg}${level}$*${end}" >&3 - else - echo "${level}$*" >&3 - fi + if [ "$LOG_LEVEL_ENABLE" = "true" ]; then + level="WARN " + else + level="" + fi + if [ "$LOG_COLOR_ENABLE" = "true" ]; then + echo -e "${black}${yellowbg}${level}$*${end}" >&3 + else + echo "${level}$*" >&3 + fi } function log_error { - if [ "$LOG_LEVEL_ENABLE" = "true" ]; then - level="ERROR " - else - level="" - fi - if [ "$LOG_COLOR_ENABLE" = "true" ]; then - echo -e "${whiteb}${redbg}${level}$*${end}" >&3 - else - echo "${level}$*" >&3 - fi + if [ "$LOG_LEVEL_ENABLE" = "true" ]; then + level="ERROR " + else + level="" + fi + if [ "$LOG_COLOR_ENABLE" = "true" ]; then + echo -e "${whiteb}${redbg}${level}$*${end}" >&3 + else + echo "${level}$*" >&3 + fi } export -f log_notice log_message log_debug log_info log_warn log_error add_notice display_notices log_verbose diff --git a/bin/openshift-include.sh b/bin/openshift-include.sh index c579230b..0368a950 100644 --- a/bin/openshift-include.sh +++ b/bin/openshift-include.sh @@ -1,3 +1,4 @@ +# shellcheck disable=SC2148 # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 @@ -5,117 +6,119 @@ # Assumes bin/common.sh has been sourced function ocVersionCheck { - origIFS=$IFS - IFS=$'\n' + origIFS=$IFS + IFS=$'\n' - allArr=($(oc version 2>/dev/null)) - IFS=$origIFS + # shellcheck disable=SC2207 + allArr=($(oc version 2> /dev/null)) + IFS=$origIFS - for (( i=0; i<${#allArr[@]}; i++ )); do - # Split the line into an array - verArr=(${allArr[$i]}) - if [ ${#verArr[@]} -eq 3 ]; then - verType="${verArr[0]}" - ver="${verArr[2]}" - if [ "$verType" == "Client" ]; then - ver="${verArr[2]}" - if [[ $ver =~ v?(([0-9]+)\.([0-9]+)\.([0-9]+)) ]]; then - OC_FULL_VERSION=${BASH_REMATCH[1]} - OC_MAJOR_VERSION=${BASH_REMATCH[2]} - OC_MINOR_VERSION=${BASH_REMATCH[3]} - OC_PATCH_VERSION=${BASH_REMATCH[4]} - else - echo "Unable to parse client version: [$ver]" - fi - elif [ "$verType" == "Server" ]; then - ver="${verArr[2]}" - if [[ $ver =~ (([0-9]+)\.([0-9]+)\.([0-9]+)) ]]; then - OSHIFT_FULL_VERSION=${BASH_REMATCH[1]} - OSHIFT_MAJOR_VERSION=${BASH_REMATCH[2]} - OSHIFT_MINOR_VERSION=${BASH_REMATCH[3]} - OSHIFT_PATCH_VERSION=${BASH_REMATCH[4]} - else - echo "Unable to parse server version: [$ver]" - fi - fi - fi - done - log_info "OpenShift client version: $OC_FULL_VERSION" - log_info "OpenShift server version: $OSHIFT_FULL_VERSION" - - # Version enforcement - if [ "$OPENSHIFT_VERSION_CHECK" == "true" ]; then - ## Server Version - ### Openshift versions that do not start with a 4 should produce an error. - if (( "$OSHIFT_MAJOR_VERSION" != 4 )); then - log_error "Unsupported OpenShift server version: $OSHIFT_FULL_VERSION" - log_error "Version 4.12+ is required" - exit 1 - ### 21FEB24: Openshift 4 versions earlier than 4.12 should produce an error. - elif (( "$OSHIFT_MINOR_VERSION" < 12 )); then - log_error "Unsupported OpenShift server version: $OSHIFT_FULL_VERSION" - log_error "Version 4.12+ is required" - exit 1 - else - log_debug "OpenShift server version check OK" - fi + for ((i = 0; i < ${#allArr[@]}; i++)); do + # Split the line into an array + # shellcheck disable=SC2206 + verArr=(${allArr[$i]}) + if [ ${#verArr[@]} -eq 3 ]; then + verType="${verArr[0]}" + ver="${verArr[2]}" + if [ "$verType" == "Client" ]; then + ver="${verArr[2]}" + if [[ $ver =~ v?(([0-9]+)\.([0-9]+)\.([0-9]+)) ]]; then + OC_FULL_VERSION=${BASH_REMATCH[1]} + OC_MAJOR_VERSION=${BASH_REMATCH[2]} + OC_MINOR_VERSION=${BASH_REMATCH[3]} + OC_PATCH_VERSION=${BASH_REMATCH[4]} + else + echo "Unable to parse client version: [$ver]" + fi + elif [ "$verType" == "Server" ]; then + ver="${verArr[2]}" + if [[ $ver =~ (([0-9]+)\.([0-9]+)\.([0-9]+)) ]]; then + OSHIFT_FULL_VERSION=${BASH_REMATCH[1]} + OSHIFT_MAJOR_VERSION=${BASH_REMATCH[2]} + OSHIFT_MINOR_VERSION=${BASH_REMATCH[3]} + OSHIFT_PATCH_VERSION=${BASH_REMATCH[4]} + else + echo "Unable to parse server version: [$ver]" + fi + fi + fi + done + log_info "OpenShift client version: $OC_FULL_VERSION" + log_info "OpenShift server version: $OSHIFT_FULL_VERSION" - ## Client Version - ### Openshift versions that do not start with a 4 should produce an error. - if (( "$OC_MAJOR_VERSION" != 4 )); then - log_error "Unsupported OpenShift client version: $OC_FULL_VERSION" - log_error "Version 4.11+ is required" - exit 1 - ### Openshift 4 client version must be w/in 1 minor releases of server minimum. - elif (( "$OC_MINOR_VERSION" < 11 )); then - log_error "Unsupported OpenShift client version: $OC_FULL_VERSION" - log_error "Version 4.11+ is required" - exit 1 - else - log_debug "OpenShift client version check OK" + # Version enforcement + if [ "$OPENSHIFT_VERSION_CHECK" == "true" ]; then + ## Server Version + ### Openshift versions that do not start with a 4 should produce an error. + if ((OSHIFT_MAJOR_VERSION != 4)); then + log_error "Unsupported OpenShift server version: $OSHIFT_FULL_VERSION" + log_error "Version 4.12+ is required" + exit 1 + ### 21FEB24: Openshift 4 versions earlier than 4.12 should produce an error. + elif ((OSHIFT_MINOR_VERSION < 12)); then + log_error "Unsupported OpenShift server version: $OSHIFT_FULL_VERSION" + log_error "Version 4.12+ is required" + exit 1 + else + log_debug "OpenShift server version check OK" + fi + + ## Client Version + ### Openshift versions that do not start with a 4 should produce an error. + if ((OC_MAJOR_VERSION != 4)); then + log_error "Unsupported OpenShift client version: $OC_FULL_VERSION" + log_error "Version 4.11+ is required" + exit 1 + ### Openshift 4 client version must be w/in 1 minor releases of server minimum. + elif ((OC_MINOR_VERSION < 11)); then + log_error "Unsupported OpenShift client version: $OC_FULL_VERSION" + log_error "Version 4.11+ is required" + exit 1 + else + log_debug "OpenShift client version check OK" + fi fi - fi } OPENSHIFT_VERSION_CHECK=${OPENSHIFT_VERSION_CHECK:-true} if [ "$SAS_OPENSHIFT_SOURCED" != "true" ]; then - if [ "$OPENSHIFT_CLUSTER" == "" ]; then - # Detect OpenShift cluster - if kubectl get ns openshift 2>/dev/null 1>&2; then - log_debug "OpenShift detected" - OPENSHIFT_CLUSTER="true" + if [ "$OPENSHIFT_CLUSTER" == "" ]; then + # Detect OpenShift cluster + if kubectl get ns openshift 2> /dev/null 1>&2; then + log_debug "OpenShift detected" + OPENSHIFT_CLUSTER="true" + else + log_debug "OpenShift not detected" + OPENSHIFT_CLUSTER="false" + fi else - log_debug "OpenShift not detected" - OPENSHIFT_CLUSTER="false" + log_debug "Skipping OpenShift detection. OPENSHIFT_CLUSTER=[$OPENSHIFT_CLUSTER]" fi - else - log_debug "Skipping OpenShift detection. OPENSHIFT_CLUSTER=[$OPENSHIFT_CLUSTER]" - fi - if [ "$OPENSHIFT_CLUSTER" == "true" ]; then - if [ "${OPENSHIFT_OC_CHECK:-true}" == "true" ]; then - if [ ! $(which oc) ]; then - echo "'oc' is required for OpenShift and not found on the current PATH" - exit 1 - fi - ocVersionCheck + if [ "$OPENSHIFT_CLUSTER" == "true" ]; then + if [ "${OPENSHIFT_OC_CHECK:-true}" == "true" ]; then + if ! which oc 1> /dev/null; then + echo "'oc' is required for OpenShift and not found on the current PATH" + exit 1 + fi + ocVersionCheck - # Get base OpenShift route hostname - OPENSHIFT_ROUTE_DOMAIN=${OPENSHIFT_ROUTE_DOMAIN:-$(oc get route -n openshift-console console -o 'jsonpath={.spec.host}' | cut -c 27-)} - if [ "$OPENSHIFT_ROUTE_DOMAIN" != "" ]; then - log_debug "OpenShift route host is [$OPENSHIFT_ROUTE_DOMAIN]" - else - log_error "Unable to determine OpenShift route host. Set OPENSHIFT_ROUTE_DOMAIN if necessary." - exit 1 - fi + # Get base OpenShift route hostname + OPENSHIFT_ROUTE_DOMAIN=${OPENSHIFT_ROUTE_DOMAIN:-$(oc get route -n openshift-console console -o 'jsonpath={.spec.host}' | cut -c 27-)} + if [ "$OPENSHIFT_ROUTE_DOMAIN" != "" ]; then + log_debug "OpenShift route host is [$OPENSHIFT_ROUTE_DOMAIN]" + else + log_error "Unable to determine OpenShift route host. Set OPENSHIFT_ROUTE_DOMAIN if necessary." + exit 1 + fi - export OPENSHIFT_ROUTE_DOMAIN - export OC_MAJOR_VERSION OC_MINOR_VERSION OC_PATCH_VERSION - export OSHIFT_MAJOR_VERSION OSHIFT_MINOR_VERSION OSHIFT_PATCH_VERSION + export OPENSHIFT_ROUTE_DOMAIN + export OC_MAJOR_VERSION OC_MINOR_VERSION OC_PATCH_VERSION + export OSHIFT_MAJOR_VERSION OSHIFT_MINOR_VERSION OSHIFT_PATCH_VERSION + fi + else + log_debug "OpenShift not detected. Skipping 'oc' checks." fi - else - log_debug "OpenShift not detected. Skipping 'oc' checks." - fi - export OPENSHIFT_CLUSTER - export SAS_OPENSHIFT_SOURCED="true" + export OPENSHIFT_CLUSTER + export SAS_OPENSHIFT_SOURCED="true" fi diff --git a/bin/renew-tls-certs.sh b/bin/renew-tls-certs.sh index 9714d82f..33247e22 100755 --- a/bin/renew-tls-certs.sh +++ b/bin/renew-tls-certs.sh @@ -1,9 +1,9 @@ #! /bin/bash -# Copyright © 2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# Copyright ©2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -cd "$(dirname $BASH_SOURCE)/.." +cd "$(dirname "$BASH_SOURCE")/.." || exit source bin/common.sh source bin/tls-include.sh @@ -14,44 +14,44 @@ export MON_NS="${MON_NS:-monitoring}" set -e function restart-resources { - app=$1 - case "$app" in - "OPENSEARCH"|"OS") + app=$1 + case "$app" in + "OPENSEARCH" | "OS") namespace=$LOG_NS resourceName=${OS_RESOURCENAME:-"v4m-search"} log_info "Restarting [OpenSearch]" kubectl rollout restart statefulset "$resourceName" -n "$namespace" ;; - "OPENSEARCHDASHBOARDS"|"DASHBOARDS"|"OSD") + "OPENSEARCHDASHBOARDS" | "DASHBOARDS" | "OSD") namespace=$LOG_NS resourceName=${OSD_RESOURCENAME:-"v4m-osd"} log_info "Restarting [OpenSearch Dashboards]" kubectl rollout restart deployment "$resourceName" -n "$namespace" ;; - "ALERTMANAGER"|"AM") + "ALERTMANAGER" | "AM") namespace=$MON_NS resourceName=${AM_RESOURCENAME:-"alertmanager-v4m-alertmanager"} log_info "Restarting [Alertmanager]" kubectl rollout restart statefulset "$resourceName" -n "$namespace" ;; - "PROMETHEUS"|"PROM"|"PRO"|"PR") + "PROMETHEUS" | "PROM" | "PRO" | "PR") namespace=$MON_NS resourceName=${PROM_RESOURCENAME:-"prometheus-v4m-prometheus"} log_info "Restarting [Prometheus]" kubectl rollout restart statefulset "$resourceName" -n "$namespace" ;; - "GRAFANA"|"GRAF"|"GR") + "GRAFANA" | "GRAF" | "GR") namespace=$MON_NS resourceName=${GR_RESOURCENAME:-"v4m-grafana"} log_info "Restarting [Grafana]" kubectl rollout restart deployment "$resourceName" -n "$namespace" ;; - "ALL-MON") + "ALL-MON") namespace=$MON_NS alertmanagerResourceName=${AM_RESOURCENAME:-"alertmanager-v4m-alertmanager"} prometheusResourceName=${PROM_RESOURCENAME:-"prometheus-v4m-prometheus"} @@ -62,7 +62,7 @@ function restart-resources { kubectl rollout restart statefulset "$prometheusResourceName" -n "$namespace" kubectl rollout restart deployment "$grafanaResourceName" -n "$namespace" ;; - "ALL-LOG") + "ALL-LOG") namespace=$LOG_NS osdResourceName=${OSD_RESOURCENAME:-"v4m-osd"} osResourceName=${OS_RESOURCENAME:-"v4m-search"} @@ -71,7 +71,7 @@ function restart-resources { kubectl rollout restart deployment "$osdResourceName" -n "$namespace" kubectl rollout restart statefulset "$osResourceName" -n "$namespace" ;; - "ALL") + "ALL") logNamespace=$LOG_NS osdResourceName=${OSD_RESOURCENAME:-"v4m-osd"} osResourceName=${OS_RESOURCENAME:-"v4m-search"} @@ -90,31 +90,31 @@ function restart-resources { kubectl rollout restart statefulset "$prometheusResourceName" -n "$monNamespace" kubectl rollout restart deployment "$grafanaResourceName" -n "$monNamespace" ;; - ""|*) + "" | *) log_error "Must Specify which resources to restart" log_error "Valid values are:" log_error "[OPENSEARCH, OPENSEARCHDASHBOARDS, GRAFANA, PROMETHEUS, ALERTMANAGER, ALL-MON, ALL-LOG, or ALL]" exit 1 ;; - esac + esac } function renew-certs { - app=$1 - case "$app" in - "ALL-MON") + app=$1 + case "$app" in + "ALL-MON") log_info "Generating new certs for [Alertmanager, Prometheus, Grafana]" log_info "Deleting existing secrets for [Alertmanager, Prometheus, Grafana]" for secretName in prometheus-tls-secret alertmanager-tls-secret grafana-tls-secret v4m-root-ca-tls-secret; do - if [ -n "$(kubectl get secret -n $MON_NS $secretName -o name 2>/dev/null)" ]; then - if (tls_cert_managed_by_v4m "$MON_NS" "$secretName") then - kubectl delete secret -n "$MON_NS" $secretName - else - log_error "[$secretName] is not managed by SAS Viya Monitoring. Delete certs not managed by SAS Viya Monitoring or update certs and restart applications by re-running this script using the [-r] flag" - exit 1 + if [ -n "$(kubectl get secret -n "$MON_NS" "$secretName" -o name 2> /dev/null)" ]; then + if (tls_cert_managed_by_v4m "$MON_NS" "$secretName"); then + kubectl delete secret -n "$MON_NS" $secretName + else + log_error "[$secretName] is not managed by SAS Viya Monitoring. Delete certs not managed by SAS Viya Monitoring or update certs and restart applications by re-running this script using the [-r] flag" + exit 1 + fi fi - fi done log_info "Generating new certs for [Alertmanager, Prometheus, Grafana]" @@ -122,19 +122,19 @@ function renew-certs { restart-resources "ALL-MON" # WIP: Move restarts to create_tls_certs_openssl function? ;; - "ALL-LOG") - log_info "Generating new certs for [OpenSearch, OpenSearch Dashboards]" - log_info "Deleting existing secrets for [OpenSearch, OpenSearch Dashboards]" + "ALL-LOG") + log_info "Generating new certs for [OpenSearch, OpenSearch Dashboards]" + log_info "Deleting existing secrets for [OpenSearch, OpenSearch Dashboards]" for secretName in kibana-tls-secret es-transport-tls-secret es-rest-tls-secret es-admin-tls-secret v4m-root-ca-tls-secret; do - if [ -n "$(kubectl get secret -n $LOG_NS $secretName -o name 2>/dev/null)" ]; then - if (tls_cert_managed_by_v4m "$LOG_NS" "$secretName") then - kubectl delete secret -n "$LOG_NS" $secretName - else - log_error "[$secretName] is not managed by SAS Viya Monitoring. Delete certs not managed by SAS Viya Monitoring or update certs and restart applications by re-running this script using the [-r] flag" - exit 1 + if [ -n "$(kubectl get secret -n "$LOG_NS" "$secretName" -o name 2> /dev/null)" ]; then + if (tls_cert_managed_by_v4m "$LOG_NS" "$secretName"); then + kubectl delete secret -n "$LOG_NS" $secretName + else + log_error "[$secretName] is not managed by SAS Viya Monitoring. Delete certs not managed by SAS Viya Monitoring or update certs and restart applications by re-running this script using the [-r] flag" + exit 1 + fi fi - fi done log_info "Generating new certs for [OpenSearch and OpenSearch Dashboards]" @@ -142,48 +142,47 @@ function renew-certs { restart-resources "ALL-LOG" # WIP: Move restarts to create_tls_certs_openssl function? ;; - ""|*) + "" | *) log_error "Valid target values for certificate renewal:" log_error "[ALL-MON] or [ALL-LOG]" exit 1 ;; - esac + esac } restartOnly=false while getopts 't:rh' OPTION; do - case "$OPTION" in + case "$OPTION" in t) - targetOpt=$OPTARG - log_info "Target resources: $targetOpt" - ;; + targetOpt=$OPTARG + log_info "Target resources: $targetOpt" + ;; r) - # Restart resource without renewing certs - restartOnly=true - log_info "Restarting the target resources without renewing certs" - ;; + # Restart resource without renewing certs + restartOnly=true + log_info "Restarting the target resources without renewing certs" + ;; h) - log_message "script usage: ./bin/renew-tls-certs.sh [-t [REQUIRED](target resource)] [-r]" - log_message "-t (REQUIRED) Options: [ALL-MON, ALL-LOG]" - log_message "-r Only restarts the target resources and does not generate new certs. Useful for those managing their own certs" - log_message "Running with [-r] allows the following targets [-t]: [OPENSEARCH, OPENSEARCHDASHBOARDS, GRAFANA, PROMETHEUS, ALERTMANAGER, ALL-MON, ALL-LOG, or ALL]" - ;; + log_message "script usage: ./bin/renew-tls-certs.sh [-t [REQUIRED](target resource)] [-r]" + log_message "-t (REQUIRED) Options: [ALL-MON, ALL-LOG]" + log_message "-r Only restarts the target resources and does not generate new certs. Useful for those managing their own certs" + log_message "Running with [-r] allows the following targets [-t]: [OPENSEARCH, OPENSEARCHDASHBOARDS, GRAFANA, PROMETHEUS, ALERTMANAGER, ALL-MON, ALL-LOG, or ALL]" + ;; ?) - log_error "script usage: ./bin/renew-tls-certs.sh [-t [REQUIRED](target resource)] [-r]" >&2 - exit 1 - ;; - esac + log_error "script usage: ./bin/renew-tls-certs.sh [-t [REQUIRED](target resource)] [-r]" >&2 + exit 1 + ;; + esac done -shift "$(($OPTIND -1))" +shift "$((OPTIND - 1))" if ! [ "$targetOpt" ]; then - log_error "Missing required target option, use [-h] to see how to use this script" + log_error "Missing required target option, use [-h] to see how to use this script" fi if [ $restartOnly == true ]; then - restart-resources "$targetOpt" + restart-resources "$targetOpt" else - renew-certs "$targetOpt" + renew-certs "$targetOpt" fi - diff --git a/bin/service-url-include.sh b/bin/service-url-include.sh index 4ee2a4bd..93254158 100644 --- a/bin/service-url-include.sh +++ b/bin/service-url-include.sh @@ -1,8 +1,9 @@ -#!/bin/bash - # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + source bin/common.sh # k8s object: ingress @@ -22,205 +23,205 @@ json_route_path='{.spec.path}' json_route_tls='{.spec.tls.termination}' function get_k8s_info { - local namespace object jsonpath info rc + local namespace object jsonpath info - namespace=$1 - object=$2 - jsonpath=$3 + namespace=$1 + object=$2 + jsonpath=$3 - info=$(kubectl -n "$namespace" get "$object" -o=jsonpath=$jsonpath 2>/dev/null) - rc=$? + info=$(kubectl -n "$namespace" get "$object" -o=jsonpath="$jsonpath" 2> /dev/null) - if [ ! -z "$info" ]; then - echo "$info" - else - v4m_rc=1 - echo "" - fi + if [ -n "$info" ]; then + echo "$info" + else + v4m_rc=1 + echo "" + fi } function get_ingress_ports { - if [ -z "$ingress_http_port" ]; then + if [ -z "$ingress_http_port" ]; then - ingress_namespace="${NGINX_NS:-ingress-nginx}" + ingress_namespace="${NGINX_NS:-ingress-nginx}" - ingress_service="service/${NGINX_SVCNAME:-ingress-nginx-controller}" + ingress_service="service/${NGINX_SVCNAME:-ingress-nginx-controller}" - ingress_http_port=$(get_k8s_info "$ingress_namespace" "$ingress_service" "$json_service_http_port") - if [ "$ingress_http_port" == "80" ]; then - ingress_http_port="" - fi + ingress_http_port=$(get_k8s_info "$ingress_namespace" "$ingress_service" "$json_service_http_port") + if [ "$ingress_http_port" == "80" ]; then + ingress_http_port="" + fi - ingress_https_port=$(get_k8s_info "$ingress_namespace" "$ingress_service" "$json_service_https_port") - if [ "$ingress_https_port" == "443" ]; then - ingress_https_port="" - fi - fi + ingress_https_port=$(get_k8s_info "$ingress_namespace" "$ingress_service" "$json_service_https_port") + if [ "$ingress_https_port" == "443" ]; then + ingress_https_port="" + fi + fi } function get_ingress_url { - local namespace name host path tls_info rc port porttxt protocol - - namespace=$1 - name=$2 - - if [ ! "$(kubectl -n $namespace get ingress/$name 2>/dev/null)" ]; then - # ingress object does not exist - v4m_rc=1 - echo "" - return - fi - - host=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_host") - if [ -z "$host" ]; then - v4m_rc=1 - echo "" - return - fi - - path=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_path") - if [ -z "$path" ]; then - v4m_rc=1 - echo "" - return - fi - - tls_info=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_tls") - if [ -n "$tls_info" ]; then - port=$ingress_https_port - protocol=https - else - port=$ingress_http_port - protocol=http - fi - - if [ -n "$port" ]; then - porttxt=":$port" - fi - - url="$protocol://${host}${porttxt}${path}" - - url="${url%/}" # strip any trailing "/" - echo "$url" -} + local namespace name host path tls_info port porttxt protocol -function get_route_url { - local host tls_enabled protocol url + namespace=$1 + name=$2 - namespace=$1 - service=$2 + if [ ! "$(kubectl -n "$namespace" get ingress/"$name" 2> /dev/null)" ]; then + # ingress object does not exist + v4m_rc=1 + echo "" + return + fi - host=$(get_k8s_info "$namespace" "route/$service" "$json_route_host") - if [ -z "$host" ]; then - v4m_rc=1 - echo "" - return - fi + host=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_host") + if [ -z "$host" ]; then + v4m_rc=1 + echo "" + return + fi - # OK if path is empty - path=$(get_k8s_info "$namespace" "route/$service" "$json_route_path") + path=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_path") + if [ -z "$path" ]; then + v4m_rc=1 + echo "" + return + fi - tls_mode=$(get_k8s_info "$namespace" "route/$service" "$json_route_tls") - if [ -z "$tls_mode" ]; then - protocol="http" - else - protocol="https" - fi + tls_info=$(get_k8s_info "$namespace" "ingress/$name" "$json_ingress_tls") + if [ -n "$tls_info" ]; then + port=$ingress_https_port + protocol=https + else + port=$ingress_http_port + protocol=http + fi - url="$protocol://$host$path" - url="${url%/}" # strip any trailing "/" + if [ -n "$port" ]; then + porttxt=":$port" + fi - echo "$url" -} + url="$protocol://${host}${porttxt}${path}" -function get_nodeport_url { - local host tls_enabled port porttxt protocol - - namespace=$1 - service=$2 - tls_enabled=$3 - - if [ ! "$(kubectl -n $namespace get service/$service 2>/dev/null)" ]; then - # ingress object does not exist - v4m_rc=1 - echo "" - return - fi - - host="$(kubectl get node --selector='node-role.kubernetes.io/master' | awk 'NR==2 { print $1 }')" - if [ -z "$host" ]; then - host=$(kubectl get nodes | awk 'NR==2 { print $1 }') # use first node - fi - - port=$(get_k8s_info "$namespace" "service/$service" "$json_service_nodeport") - - if [ "$tls_enabled" == "true" ]; then - protocol=https - else - protocol=http - fi - - if [ ! -z "$port" ]; then - porttxt=":$port" - fi - - url="$protocol://${host}${porttxt}" - echo "$url" + url="${url%/}" # strip any trailing "/" + echo "$url" } -function get_service_url { - local namespace service use_tls ingress service_type url - - namespace=$1 - service=$2 # name of service - use_tls=$3 # (optional - NodePort only) use http or https (ingress properties over-ride) - ingress=${4:-${service}} # (optional) name of ingress/route object (default: $service) +function get_route_url { + local host tls_enabled protocol url - # is a route defined for this service? - if [ "$OPENSHIFT_CLUSTER" == "true" ] && [ "$(kubectl -n $namespace get route/$service 2>/dev/null)" ]; then - url=$(get_route_url $namespace $service) + namespace=$1 + service=$2 - if [ -z "$url" ]; then + host=$(get_k8s_info "$namespace" "route/$service" "$json_route_host") + if [ -z "$host" ]; then v4m_rc=1 echo "" return - else - echo "$url" - return - fi - fi + fi - # determine nodePort or clusterPort (ingress) - service_type=$(get_k8s_info "$namespace" "service/$service" "$json_service_type") + # OK if path is empty + path=$(get_k8s_info "$namespace" "route/$service" "$json_route_path") + + tls_mode=$(get_k8s_info "$namespace" "route/$service" "$json_route_tls") + if [ -z "$tls_mode" ]; then + protocol="http" + else + protocol="https" + fi + + url="$protocol://$host$path" + url="${url%/}" # strip any trailing "/" + + echo "$url" +} - if [ "$service_type" == "ClusterIP" ]; then - get_ingress_ports +function get_nodeport_url { + local host tls_enabled port porttxt protocol - url=$(get_ingress_url $namespace $ingress) + namespace=$1 + service=$2 + tls_enabled=$3 - if [ -z "$url" ]; then + if [ ! "$(kubectl -n "$namespace" get service/"$service" 2> /dev/null)" ]; then + # ingress object does not exist v4m_rc=1 echo "" return - else - echo "$url" - fi - elif [ "$service_type" == "NodePort" ]; then - url=$(get_nodeport_url $namespace $service $use_tls) + fi + + host="$(kubectl get node --selector='node-role.kubernetes.io/master' | awk 'NR==2 { print $1 }')" + if [ -z "$host" ]; then + host=$(kubectl get nodes | awk 'NR==2 { print $1 }') # use first node + fi + + port=$(get_k8s_info "$namespace" "service/$service" "$json_service_nodeport") + + if [ "$tls_enabled" == "true" ]; then + protocol=https + else + protocol=http + fi - if [ -z "$url" ]; then + if [ -n "$port" ]; then + porttxt=":$port" + fi + + url="$protocol://${host}${porttxt}" + echo "$url" +} + +function get_service_url { + local namespace service use_tls ingress service_type url + + namespace=$1 + service=$2 # name of service + use_tls=$3 # (optional - NodePort only) use http or https (ingress properties over-ride) + ingress=${4:-${service}} # (optional) name of ingress/route object (default: $service) + + # is a route defined for this service? + if [ "$OPENSHIFT_CLUSTER" == "true" ] && [ "$(kubectl -n "$namespace" get route/"$service" 2> /dev/null)" ]; then + url=$(get_route_url "$namespace" "$service") + + if [ -z "$url" ]; then + v4m_rc=1 + echo "" + return + else + echo "$url" + return + fi + fi + + # determine nodePort or clusterPort (ingress) + service_type=$(get_k8s_info "$namespace" "service/$service" "$json_service_type") + + if [ "$service_type" == "ClusterIP" ]; then + get_ingress_ports + + url=$(get_ingress_url "$namespace" "$ingress") + + if [ -z "$url" ]; then + v4m_rc=1 + echo "" + return + else + echo "$url" + fi + elif [ "$service_type" == "NodePort" ]; then + url=$(get_nodeport_url "$namespace" "$service" "$use_tls") + + if [ -z "$url" ]; then + v4m_rc=1 + echo "" + return + else + echo "$url" + fi + else + # uh-oh, how what? + # shellcheck disable=SC2034 v4m_rc=1 echo "" return - else - echo "$url" - fi - else - # uh-oh, how what? - v4m_rc=1 - echo "" - return - fi + fi } # USAGE NOTES diff --git a/bin/show_app_url.sh b/bin/show_app_url.sh index 64cd1a6e..2369929f 100755 --- a/bin/show_app_url.sh +++ b/bin/show_app_url.sh @@ -3,11 +3,11 @@ # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -cd "$(dirname $BASH_SOURCE)/.." +cd "$(dirname "$BASH_SOURCE")/.." || exit source bin/common.sh source bin/service-url-include.sh -this_script=`basename "$0"` +this_script=$(basename "$0") log_debug "Script [$this_script] has started [$(date)]" @@ -24,126 +24,86 @@ add_notice "**Accessing the monitoring applications**" add_notice "" #start looping through services -servicelist=${@:-"ALL"} -servicelist=$(echo "$servicelist"| tr '[:lower:]' '[:upper:]') +servicelist=${*:-"ALL"} +servicelist=$(echo "$servicelist" | tr '[:lower:]' '[:upper:]') if [ "$servicelist" == "ALL" ]; then - servicelist="GRAFANA OS OSD" + servicelist="GRAFANA OS OSD" fi log_debug "Application URLs requested for [$servicelist]" -for service in $servicelist -do - case "$service" in - OPENSEARCHDASHBOARDS|OPENSEARCHDASHBOARD|OSD) - if [ "$LOG_SEARCH_BACKEND" != "OPENSEARCH" ];then - reset_search_backend="true" - LOG_SEARCH_BACKEND="OPENSEARCH" - fi - +for service in $servicelist; do + case "$service" in + OPENSEARCHDASHBOARDS | OPENSEARCHDASHBOARD | OSD) service="OpenSearch Dashboards" namespace=${LOG_NS:-"logging"} servicename="v4m-osd" ingressname="v4m-osd" - tls_flag="$(kubectl -n $namespace get secret v4m-osd-tls-enabled -o=jsonpath={.data.enable_tls} |base64 --decode)" + tls_flag=$(kubectl -n "$namespace" get secret v4m-osd-tls-enabled -o=jsonpath="{.data.enable_tls}" --ignore-not-found | base64 --decode) ;; - OPENSEARCH|OS) - if [ "$LOG_SEARCH_BACKEND" != "OPENSEARCH" ];then - reset_search_backend="true" - LOG_SEARCH_BACKEND="OPENSEARCH" - fi + OPENSEARCH | OS) service="OpenSearch" namespace=${LOG_NS:-"logging"} servicename="v4m-search" ingressname="v4m-search" tls_flag="true" ;; - KIBANA|KB) - if [ "$LOG_SEARCH_BACKEND" != "ODFE" ];then - reset_search_backend="true" - LOG_SEARCH_BACKEND="ODFE" - fi - - namespace=${LOG_NS:-"logging"} - service="Kibana" - servicename="v4m-es-kibana-svc" - ingressname="v4m-es-kibana-ing" - tls_flag="$(kubectl -n $namespace get pod -l role=kibana -o=jsonpath='{.items[*].metadata.annotations.tls_required}')" - log_debug "TLS required to connect to Kibana? [$tls_flag]" - ;; - ELASTICSEARCH|ES) - if [ "$LOG_SEARCH_BACKEND" != "ODFE" ];then - reset_search_backend="true" - LOG_SEARCH_BACKEND="ODFE" - fi - - namespace=${LOG_NS:-"logging"} - service="Elasticsearch" - servicename="v4m-es-client-service" - ingressname="" - tls_flag="true" - ;; - GRAFANA|GRAF|GR) + GRAFANA | GRAF | GR) namespace=${MON_NS:-"monitoring"} service="Grafana" servicename="v4m-grafana" ingressname="v4m-grafana" tls_flag="$TLS_ENABLE" ;; - PROMETHEUS|PROM|PR) + PROMETHEUS | PROM | PR) namespace=${MON_NS:-"monitoring"} service="Prometheus" servicename="v4m-prometheus" ingressname="v4m-prometheus" tls_flag="$TLS_ENABLE" ;; - ALERTMANAGER|AM) + ALERTMANAGER | AM) namespace=${MON_NS:-"monitoring"} - service="AlertManager" + service="Alertmanager" servicename="v4m-alertmanager" ingressname="v4m-alertmanager" tls_flag="$TLS_ENABLE" ;; - *) + *) log_error "Invalid application [$service] specified". - log_error "Valid values are [GRAFANA, OPENSEARCH, OPENSEARCHDASHBOARDS, KIBANA, ELASTICSEARCH or ALL(does not inc. KIBANA or ELASTICSEARCH)]" + log_error "Valid values are [GRAFANA, OPENSEARCH, OPENSEARCHDASHBOARDS or ALL]" exit 1 ;; - esac - - # get URLs for requested services - log_debug "Function call: get_service_url $namespace $servicename $tls_flag $ingressname" - - service_url=$(get_service_url "$namespace" "$servicename" "$tls_flag" "$ingressname") - - if [ "$reset_search_backend" == "true" ]; then - LOG_SEARCH_BACKEND="OPENSEARCH" - fi - - # Print URLs - # add_notice "*** $service ***" - if [ ! -z "$service_url" ]; then - add_notice " You can access $service via the following URL:" - add_notice " $service_url" - add_notice "" - else - add_notice " It was not possible to determine the URL needed to access $service" - add_notice "" - fi + esac + + # get URLs for requested services + log_debug "Function call: get_service_url $namespace $servicename $tls_flag $ingressname" + + service_url=$(get_service_url "$namespace" "$servicename" "$tls_flag" "$ingressname") + + # Print URLs + # add_notice "*** $service ***" + if [ -n "$service_url" ]; then + add_notice " You can access $service via the following URL:" + add_notice " $service_url" + add_notice "" + else + add_notice " It was not possible to determine the URL needed to access $service" + add_notice "" + fi done - add_notice " Note: The URL might be incorrect if your Ingress configuration, another network" add_notice " configuration, or both include options that this script does not process." add_notice "" LOGGING_DRIVER=${LOGGING_DRIVER:-false} if [ "$LOGGING_DRIVER" != "true" ]; then - echo "" - display_notices - echo "" + echo "" + display_notices + echo "" fi log_debug "Script [$this_script] has completed [$(date)]" diff --git a/bin/tls-include.sh b/bin/tls-include.sh index d0091d91..58f3eab7 100644 --- a/bin/tls-include.sh +++ b/bin/tls-include.sh @@ -1,141 +1,144 @@ # Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + # Helper functions for TLS support # Determine if cert-manager is available -if [ "$(kubectl get crd certificates.cert-manager.io -o name 2>/dev/null)" ]; then - certManagerAvailable="true" +if [ "$(kubectl get crd certificates.cert-manager.io -o name 2> /dev/null)" ]; then + # shellcheck disable=SC2034 + certManagerAvailable="true" else - certManagerAvailable="false" + # shellcheck disable=SC2034 + certManagerAvailable="false" fi function verify_cert_manager { - if [ "$cert_manager_ok" == "true" ]; then - return 0 - elif [ "$cert_manager_ok" == "false" ]; then - return 1 - fi - - if [ "$(kubectl get crd certificates.cert-manager.io -o name 2>/dev/null)" ]; then - cert_manager_ok="true" - return 0 - else - cert_manager_ok="false" - return 1 - fi -} + if [ "$cert_manager_ok" == "true" ]; then + return 0 + elif [ "$cert_manager_ok" == "false" ]; then + return 1 + fi + if [ "$(kubectl get crd certificates.cert-manager.io -o name 2> /dev/null)" ]; then + cert_manager_ok="true" + return 0 + else + cert_manager_ok="false" + return 1 + fi +} function deploy_issuers { - namespace=$1 - context=$2 - - contextDir=${TLS_CONTEXT_DIR:-$context/tls} - - if [ "TLS_DEPLOY_SELFSIGNED_ISSUERS" == "false" ]; then - return 0 - fi - - # Create issuers if needed - # Issuers honor USER_DIR for overrides/customizations - if [ -z "$(kubectl get issuer -n $namespace selfsigning-issuer -o name 2>/dev/null)" ]; then - log_info "Creating selfsigning-issuer for the [$namespace] namespace..." - selfsignIssuer=$context/tls/selfsigning-issuer.yaml - if [ -f "$USER_DIR/$context/tls/selfsigning-issuer.yaml" ]; then - selfsignIssuer="$USER_DIR/$context/tls/selfsigning-issuer.yaml" + namespace=$1 + context=$2 + + contextDir=${TLS_CONTEXT_DIR:-$context/tls} + + if [ "$TLS_DEPLOY_SELFSIGNED_ISSUERS" == "false" ]; then + return 0 + fi + + # Create issuers if needed + # Issuers honor USER_DIR for overrides/customizations + if [ -z "$(kubectl get issuer -n "$namespace" selfsigning-issuer -o name 2> /dev/null)" ]; then + log_info "Creating selfsigning-issuer for the [$namespace] namespace..." + selfsignIssuer=$context/tls/selfsigning-issuer.yaml + if [ -f "$USER_DIR/$context/tls/selfsigning-issuer.yaml" ]; then + selfsignIssuer="$USER_DIR/$context/tls/selfsigning-issuer.yaml" + fi + log_debug "Self-sign issuer yaml is [$selfsignIssuer]" + kubectl apply -n "$namespace" -f "$selfsignIssuer" + sleep 5 + else + log_debug "Using existing $namespace/selfsigning-issuer" fi - log_debug "Self-sign issuer yaml is [$selfsignIssuer]" - kubectl apply -n $namespace -f "$selfsignIssuer" - sleep 5 - else - log_debug "Using existing $namespace/selfsigning-issuer" - fi - if [ -z "$(kubectl get secret -n $namespace ca-certificate-secret -o name 2>/dev/null)" ]; then - log_info "Creating self-signed CA certificate for the [$namespace] namespace..." - caCert=$context/tls/ca-certificate.yaml - if [ -f "$USER_DIR/$context/tls/ca-certificate.yaml" ]; then - caCert="$USER_DIR/$context/tls/ca-certificate.yaml" + if [ -z "$(kubectl get secret -n "$namespace" ca-certificate-secret -o name 2> /dev/null)" ]; then + log_info "Creating self-signed CA certificate for the [$namespace] namespace..." + caCert=$context/tls/ca-certificate.yaml + if [ -f "$USER_DIR/$context/tls/ca-certificate.yaml" ]; then + caCert="$USER_DIR/$context/tls/ca-certificate.yaml" + fi + log_debug "CA cert yaml file is [$caCert]" + kubectl apply -n "$namespace" -f "$caCert" + sleep 5 + else + log_debug "Using existing $namespace/ca-certificate-secret" fi - log_debug "CA cert yaml file is [$caCert]" - kubectl apply -n $namespace -f "$caCert" - sleep 5 - else - log_debug "Using existing $namespace/ca-certificate-secret" - fi - if [ -z "$(kubectl get issuer -n $namespace namespace-issuer -o name 2>/dev/null)" ]; then - log_info "Creating namespace-issuer for the [$namespace] namespace..." - namespaceIssuer=$context/tls/namespace-issuer.yaml - if [ -f "$USER_DIR/$context/tls/namespace-issuer.yaml" ]; then - namespaceIssuer="$USER_DIR/$context/tls/namespace-issuer.yaml" + if [ -z "$(kubectl get issuer -n "$namespace" namespace-issuer -o name 2> /dev/null)" ]; then + log_info "Creating namespace-issuer for the [$namespace] namespace..." + namespaceIssuer=$context/tls/namespace-issuer.yaml + if [ -f "$USER_DIR/$context/tls/namespace-issuer.yaml" ]; then + namespaceIssuer="$USER_DIR/$context/tls/namespace-issuer.yaml" + fi + log_debug "Namespace issuer yaml is [$namespaceIssuer]" + kubectl apply -n "$namespace" -f "$namespaceIssuer" + sleep 5 + else + log_debug "Using existing $namespace/namespace-issuer" fi - log_debug "Namespace issuer yaml is [$namespaceIssuer]" - kubectl apply -n $namespace -f "$namespaceIssuer" - sleep 5 - else - log_debug "Using existing $namespace/namespace-issuer" - fi } function deploy_app_cert { - namespace=$1 - context=$2 - app=$3 - - contextDir=${TLS_CONTEXT_DIR:-$context/tls} - - # Create the certificate using cert-manager - certyaml=$contextDir/$app-tls-cert.yaml - if [ -f "$USER_DIR/$context/tls/$app-tls-cert.yaml" ]; then - certyaml="$USER_DIR/$context/tls/$app-tls-cert.yaml" - fi - log_debug "Creating cert-manager certificate custom resource for [$app] using [$certyaml]" - kubectl apply -n $namespace -f "$certyaml" + namespace=$1 + context=$2 + app=$3 + + contextDir=${TLS_CONTEXT_DIR:-$context/tls} + + # Create the certificate using cert-manager + certyaml=$contextDir/$app-tls-cert.yaml + if [ -f "$USER_DIR/$context/tls/$app-tls-cert.yaml" ]; then + certyaml="$USER_DIR/$context/tls/$app-tls-cert.yaml" + fi + log_debug "Creating cert-manager certificate custom resource for [$app] using [$certyaml]" + kubectl apply -n "$namespace" -f "$certyaml" } function create_tls_certs_cm { - namespace=$1 - context=$2 - shift 2 - apps=("$@") + namespace=$1 + context=$2 + shift 2 + apps=("$@") - deployedIssuers="false" + deployedIssuers="false" # Certs honor USER_DIR for overrides/customizations - for app in "${apps[@]}"; do - # Only create the secrets if they do not exist - TLS_SECRET_NAME=$app-tls-secret - if [ -z "$(kubectl get secret -n $namespace $TLS_SECRET_NAME -o name 2>/dev/null)" ]; then - if [ "$deployedIssuers" == "false" ]; then - deploy_issuers $namespace $context - deployedIssuers="true" + for app in "${apps[@]}"; do + # Only create the secrets if they do not exist + TLS_SECRET_NAME=$app-tls-secret + if [ -z "$(kubectl get secret -n "$namespace" "$TLS_SECRET_NAME" -o name 2> /dev/null)" ]; then + if [ "$deployedIssuers" == "false" ]; then + deploy_issuers "$namespace" "$context" + deployedIssuers="true" + fi + deploy_app_cert "$namespace" "$context" "$app" + else + log_debug "Using existing $TLS_SECRET_NAME for [$app]" fi - deploy_app_cert "$namespace" "$context" "$app" - else - log_debug "Using existing $TLS_SECRET_NAME for [$app]" - fi - done + done } function create_tls_certs { - local namespace context apps - namespace=$1 - context=$2 - shift 2 - apps=("$@") - - if [ "$CERT_GENERATOR" == "cert-manager" ]; then - create_tls_certs_cm $namespace $context ${apps[@]} - elif [ "$CERT_GENERATOR" == "openssl" ]; then - create_tls_certs_openssl $namespace ${apps[@]} - else - log_error "Unknown TLS Certificate Generator [$cert-generator] requested." - return 1 - fi -} + local namespace context apps + namespace=$1 + context=$2 + shift 2 + apps=("$@") + if [ "$CERT_GENERATOR" == "cert-manager" ]; then + create_tls_certs_cm "$namespace" "$context" "${apps[@]}" + elif [ "$CERT_GENERATOR" == "openssl" ]; then + create_tls_certs_openssl "$namespace" "${apps[@]}" + else + log_error "Unknown TLS Certificate Generator [$cert-generator] requested." + return 1 + fi +} -function do_all_secrets_already_exist { +function do_all_secrets_already_exist { namespace="$1" shift apps=("$@") @@ -143,83 +146,84 @@ function do_all_secrets_already_exist { all_secrets_exist="true" for app in "${apps[@]}"; do - secretName=$app-tls-secret - if [ -z "$(kubectl get secret -n $namespace $secretName -o name 2>/dev/null)" ]; then - log_debug "Secret [$namespace/$secretName] not found. Certificate generation is required." - all_secrets_exist="false" - break - else - log_debug "Found existing secret $namespace/$secretName" - fi + secretName=$app-tls-secret + if [ -z "$(kubectl get secret -n "$namespace" "$secretName" -o name 2> /dev/null)" ]; then + log_debug "Secret [$namespace/$secretName] not found. Certificate generation is required." + all_secrets_exist="false" + break + else + log_debug "Found existing secret $namespace/$secretName" + fi done - if [ "$all_secrets_exist" == "false" ]; then - return 1 - else - return 0 - fi + if [ "$all_secrets_exist" == "false" ]; then + return 1 + else + return 0 + fi } function verify_cert_generator { - if [ "$TLS_ENABLE" != "true" ]; then - log_debug "TLS is disabled. Skipping verification of certificate generator." - return 0 - fi - - if [ "$cert_generator_ok" == "true" ]; then - return 0 - elif [ "$cert_generator_ok" == "false" ]; then - return 1 - fi - - if do_all_secrets_already_exist $@; then - log_debug "All required secrets exist. Skipping check for certificate generator check." - cert_generator_ok="true" - return 0 - else - cert_generator_ok="false" - fi - - if [ "$CERT_GENERATOR" == "cert-manager" ]; then - verify_cert_manager - rc=$? - elif [ "$CERT_GENERATOR" == "openssl" ]; then - verify_openssl - rc=$? - else - log_error "No TLS certificate generation mechanism defined" - return 1 - fi - - if [ "$rc" == "0" ]; then - cert_generator_ok="true" - else - cert_generator_ok="false" - fi - return $rc + if [ "$TLS_ENABLE" != "true" ]; then + log_debug "TLS is disabled. Skipping verification of certificate generator." + return 0 + fi + + if [ "$cert_generator_ok" == "true" ]; then + return 0 + elif [ "$cert_generator_ok" == "false" ]; then + return 1 + fi + + if do_all_secrets_already_exist "$@"; then + log_debug "All required secrets exist. Skipping check for certificate generator check." + cert_generator_ok="true" + return 0 + else + cert_generator_ok="false" + fi + + if [ "$CERT_GENERATOR" == "cert-manager" ]; then + verify_cert_manager + rc=$? + elif [ "$CERT_GENERATOR" == "openssl" ]; then + verify_openssl + rc=$? + else + log_error "No TLS certificate generation mechanism defined" + return 1 + fi + + if [ "$rc" == "0" ]; then + cert_generator_ok="true" + else + cert_generator_ok="false" + fi + return $rc } function verify_openssl { - if [ "$openssl_ok" == "true" ]; then - return 0 - elif [ "$openssl_ok" == "false" ]; then - return 1 - else - openssl_version="$(which openssl)" 2>/dev/null - openssl_available="$?" - - if [ "$openssl_available" == "0" ]; then - log_debug "OpenSSL is available to generate missing required certs" - openssl_ok="true" + if [ "$openssl_ok" == "true" ]; then return 0 - else - log_error "OpenSSL is NOT available to generate missing required certs" - openssl_ok="false" + elif [ "$openssl_ok" == "false" ]; then return 1 - fi + else + # shellcheck disable=SC2034 + openssl_version="$(which openssl)" 2> /dev/null + openssl_available="$?" + + if [ "$openssl_available" == "0" ]; then + log_debug "OpenSSL is available to generate missing required certs" + openssl_ok="true" + return 0 + else + log_error "OpenSSL is NOT available to generate missing required certs" + openssl_ok="false" + return 1 + fi - fi + fi } function create_cert_secret { @@ -229,53 +233,52 @@ function create_cert_secret { secretName="$3" if [ -z "$secretName" ]; then - secretName="${app}-tls-secret" + secretName="${app}-tls-secret" fi log_debug "Storing TLS Cert for [$app] in secret [$secretName] in namespace [$namespace]" - expiration_date=$(openssl x509 -enddate -noout -in $TMP_DIR/${app}.pem | awk -F "=" '{print $2}') + expiration_date=$(openssl x509 -enddate -noout -in "$TMP_DIR"/"${app}".pem | awk -F "=" '{print $2}') # Secret Type: TLS (two sub-parts: cert + key) - #kubectl -n $namespace create secret tls $secretName --cert $TMP_DIR/${app}.pem --key $TMP_DIR/${app}-key.pem + #kubectl -n "$namespace" create secret tls $secretName --cert $TMP_DIR/${app}.pem --key $TMP_DIR/${app}-key.pem # Secret Type: GENERIC (3 sub-parts: cert + key + CACert) - kubectl -n $namespace create secret generic $secretName --from-file=tls.crt=$TMP_DIR/${app}.pem --from-file=tls.key=$TMP_DIR/${app}-key.pem --from-file=ca.crt=$TMP_DIR/root-ca.pem - kubectl -n $namespace annotate secret $secretName expiration="$expiration_date" - kubectl -n $namespace label secret $secretName managed-by="v4m" cert-generator="openssl" + kubectl -n "$namespace" create secret generic "$secretName" --from-file=tls.crt="$TMP_DIR"/"${app}".pem --from-file=tls.key="$TMP_DIR"/"${app}"-key.pem --from-file=ca.crt="$TMP_DIR"/root-ca.pem + kubectl -n "$namespace" annotate secret "$secretName" expiration="$expiration_date" + kubectl -n "$namespace" label secret "$secretName" managed-by="v4m" cert-generator="openssl" } # Checks if tls cert is or will expire within TLS_CERT_RENEW_WINDOW timeframe # Return 1: cert is still valid and will not expire with the given timeframe # Return 0: cert is expired or will expire within the given timeframe -function tls_cert_expired () { - namespace="$1" - app="$2" - secretName="$3" - - cert_window=$((${TLS_CERT_RENEW_WINDOW:-7} * 86400)) - - if kubectl get secret -n $namespace $secretName -o "jsonpath={.data['tls\.crt']}" | base64 -d | openssl x509 -checkend $cert_window -noout 2>/dev/null - then - return 1 - else - return 0 - fi +function tls_cert_expired() { + namespace="$1" + app="$2" + secretName="$3" + + cert_window=$((${TLS_CERT_RENEW_WINDOW:-7} * 86400)) + + if kubectl get secret -n "$namespace" "$secretName" -o "jsonpath={.data['tls\.crt']}" | base64 -d | openssl x509 -checkend $cert_window -noout 2> /dev/null; then + return 1 + else + return 0 + fi } # Checks if tls cert is generated and managed by V4M # Return 0: TLS cert is managed by V4M -# Return 1: TLS cert is not managed by V4M -function tls_cert_managed_by_v4m () { - namespace="$1" - secretName="$3" - - if [[ "$(kubectl get secret -n $namespace $secretName --show-labels)" == *"managed-by=v4m"* ]]; then - log_debug "TLS Certs are managed by SAS Viya Monitoring" - return 0 - else - log_debug "TLS Certs are not managed by SAS Viya Monitoring" - return 1 - fi +# Return 1: TLS cert is not managed by V4M +function tls_cert_managed_by_v4m() { + namespace="$1" + secretName="$2" + + if [[ "$(kubectl get secret -n "$namespace" "$secretName" --show-labels)" == *"managed-by=v4m"* ]]; then + log_debug "TLS Certs are managed by SAS Viya Monitoring" + return 0 + else + log_debug "TLS Certs are not managed by SAS Viya Monitoring" + return 1 + fi } function create_tls_certs_openssl { @@ -287,61 +290,59 @@ function create_tls_certs_openssl { cert_life=${OPENSSL_CERT_LIFE:-550} for app in "${apps[@]}"; do - secretName="${app}-tls-secret" - - if [ -n "$(kubectl get secret -n "$namespace" "$secretName" -o name 2>/dev/null)" ]; then - if (tls_cert_managed_by_v4m "$namespace" "$secretName") then - if ! (tls_cert_expired "$namespace" "$app" "$secretName") then - log_debug "TLS Secret for [$app] already exists and cert is not expired; skipping TLS certificate generation." - continue - else - log_info "TLS Secret for [$app] exists but cert has expired or will do so within ${TLS_CERT_RENEW_WINDOW:-7} days" - log_info "Renew cert using: renew-tls-certs.sh" - # TODO: When certs are expired: - # Delete secret and allow cert generation - # Get the resource restarted by calling func in renew-tls-certs.sh - # kubectl delete secret -n $namespace $secretName - continue - fi - else - # Cert not managed by SAS Viya Monitoring - continue + secretName="${app}-tls-secret" + + if [ -n "$(kubectl get secret -n "$namespace" "$secretName" -o name 2> /dev/null)" ]; then + if (tls_cert_managed_by_v4m "$namespace" "$secretName"); then + if ! (tls_cert_expired "$namespace" "$app" "$secretName"); then + log_debug "TLS Secret for [$app] already exists and cert is not expired; skipping TLS certificate generation." + continue + else + log_info "TLS Secret for [$app] exists but cert has expired or will do so within ${TLS_CERT_RENEW_WINDOW:-7} days" + log_info "Renew cert using: renew-tls-certs.sh" + # TODO: When certs are expired: + # Delete secret and allow cert generation + # Get the resource restarted by calling func in renew-tls-certs.sh + # kubectl delete secret -n "$namespace" $secretName + continue + fi + else + # Cert not managed by SAS Viya Monitoring + continue + fi fi - fi - if [ ! -f $TMP_DIR/root-ca-key.pem ]; then + if [ ! -f "$TMP_DIR"/root-ca-key.pem ]; then - if [ -n "$(kubectl get secret -n $namespace v4m-root-ca-tls-secret -o name 2>/dev/null)" ]; then - log_debug "Extracting Root CA cert from secret [v4m-root-ca-tls-secret]" - kubectl -n $namespace get secret v4m-root-ca-tls-secret -o=jsonpath="{.data.tls\.crt}" |base64 --decode > $TMP_DIR/root-ca.pem - kubectl -n $namespace get secret v4m-root-ca-tls-secret -o=jsonpath="{.data.tls\.key}" |base64 --decode > $TMP_DIR/root-ca-key.pem - else - log_debug "Creating Root CA cert using OpenSSL" - cert_subject="/O=v4m/CN=rootca" - openssl genrsa -out $TMP_DIR/root-ca-key.pem 4096 2>/dev/null - openssl req -new -x509 -sha256 -key $TMP_DIR/root-ca-key.pem -subj "$cert_subject" -out $TMP_DIR/root-ca.pem -days $cert_life + if [ -n "$(kubectl get secret -n "$namespace" v4m-root-ca-tls-secret -o name 2> /dev/null)" ]; then + log_debug "Extracting Root CA cert from secret [v4m-root-ca-tls-secret]" + kubectl -n "$namespace" get secret v4m-root-ca-tls-secret -o=jsonpath="{.data.tls\.crt}" | base64 --decode > "$TMP_DIR"/root-ca.pem + kubectl -n "$namespace" get secret v4m-root-ca-tls-secret -o=jsonpath="{.data.tls\.key}" | base64 --decode > "$TMP_DIR"/root-ca-key.pem + else + log_debug "Creating Root CA cert using OpenSSL" + cert_subject="/O=v4m/CN=rootca" + openssl genrsa -out "$TMP_DIR"/root-ca-key.pem 4096 2> /dev/null + openssl req -new -x509 -sha256 -key "$TMP_DIR"/root-ca-key.pem -subj "$cert_subject" -out "$TMP_DIR"/root-ca.pem -days "$cert_life" - create_cert_secret $namespace root-ca v4m-root-ca-tls-secret - fi + create_cert_secret "$namespace" root-ca v4m-root-ca-tls-secret + fi - else - log_debug "Using existing Root CA cert" - fi + else + log_debug "Using existing Root CA cert" + fi - log_debug "Creating TLS Cert for [$app] using OpenSSL" - cert_subject="/O=v4m/CN=$app" - openssl genrsa -out $TMP_DIR/${app}-key-temp.pem 4096 2>/dev/null - openssl pkcs8 -inform PEM -outform PEM -in $TMP_DIR/${app}-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out $TMP_DIR/${app}-key.pem - openssl req -new -key $TMP_DIR/${app}-key.pem -subj "$cert_subject" -out $TMP_DIR/${app}.csr - openssl x509 -req -in $TMP_DIR/${app}.csr -CA $TMP_DIR/root-ca.pem -CAkey $TMP_DIR/root-ca-key.pem -CAcreateserial -CAserial $TMP_DIR/ca.srl -sha256 -out $TMP_DIR/${app}.pem -days $cert_life 2>/dev/null + log_debug "Creating TLS Cert for [$app] using OpenSSL" + cert_subject="/O=v4m/CN=$app" + openssl genrsa -out "$TMP_DIR"/"${app}"-key-temp.pem 4096 2> /dev/null + openssl pkcs8 -inform PEM -outform PEM -in "$TMP_DIR"/"${app}"-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out "$TMP_DIR"/"${app}"-key.pem + openssl req -new -key "$TMP_DIR"/"${app}"-key.pem -subj "$cert_subject" -out "$TMP_DIR"/"${app}".csr + openssl x509 -req -in "$TMP_DIR"/"${app}".csr -CA "$TMP_DIR"/root-ca.pem -CAkey "$TMP_DIR"/root-ca-key.pem -CAcreateserial -CAserial "$TMP_DIR"/ca.srl -sha256 -out "$TMP_DIR"/"${app}".pem -days "$cert_life" 2> /dev/null - create_cert_secret $namespace $app + create_cert_secret "$namespace" "$app" done - } - export -f verify_cert_manager deploy_issuers deploy_app_cert create_tls_certs_cm export -f do_all_secrets_already_exist verify_cert_generator verify_openssl create_cert_secret create_tls_certs_openssl create_tls_certs diff --git a/bin/version-include.sh b/bin/version-include.sh index 37a4bc7c..9e9638ae 100644 --- a/bin/version-include.sh +++ b/bin/version-include.sh @@ -1,154 +1,160 @@ # Copyright © 2021, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +# shellcheck disable=SC2148 +# This script is not intended to be run directly + function populateValuesYAML() { - v4mValuesYAML=$1 - rm -f "$v4mValuesYAML" - touch "$v4mValuesYAML" - - # Attempt to obtain current git commit hash - gitCommit=$(git rev-parse --short HEAD 2>/dev/null) - if [ -n "$gitCommit" ]; then - echo "gitCommit: $gitCommit" >> "$v4mValuesYAML" - gitStatus=$(git status -s | sed 's/^ M/M/' | sed 's/^/ /') - if [ -n "$gitStatus" ]; then - echo "gitStatus: |" >> "$v4mValuesYAML" - echo "$gitStatus" >> "$v4mValuesYAML" - fi - fi - - # List contents of USER_DIR - if ! [[ "$USER_DIR" -ef "$(pwd)" ]]; then - if [ -d "$USER_DIR" ]; then - echo '"user_dir":' >> "$v4mValuesYAML" - echo " path: $USER_DIR" >> "$v4mValuesYAML" - echo ' files: |' >> "$v4mValuesYAML" - l=($(find "$USER_DIR" -type f|sort)) - for (( i=0; i<${#l[@]}; i++ )); do - fullPath=${l[i]} - path=${fullPath#"$USER_DIR/"} - echo " $path" >> "$v4mValuesYAML" - done - fi - - # Top-level user.env contents - if [ -f "$USER_DIR/user.env" ]; then - echo ' "user.env": |' >> "$v4mValuesYAML" - cat "$USER_DIR/user.env" | sed 's/^/ /' >> "$v4mValuesYAML" + v4mValuesYAML=$1 + rm -f "$v4mValuesYAML" + touch "$v4mValuesYAML" + + # Attempt to obtain current git commit hash + gitCommit=$(git rev-parse --short HEAD 2> /dev/null) + if [ -n "$gitCommit" ]; then + echo "gitCommit: $gitCommit" >> "$v4mValuesYAML" + gitStatus=$(git status -s | sed 's/^ M/M/' | sed 's/^/ /') + if [ -n "$gitStatus" ]; then + echo "gitStatus: |" >> "$v4mValuesYAML" + echo "$gitStatus" >> "$v4mValuesYAML" + fi fi - # Monitoring user.env contents - if [ -f "$USER_DIR/monitoring/user.env" ]; then - echo ' "monitoring_user.env": |' >> "$v4mValuesYAML" - cat "$USER_DIR/monitoring/user.env" | sed 's/^/ /' >> "$v4mValuesYAML" + + # List contents of USER_DIR + if ! [[ $USER_DIR -ef "$(pwd)" ]]; then + if [ -d "$USER_DIR" ]; then + # shellcheck disable=SC2129 + echo '"user_dir":' >> "$v4mValuesYAML" + echo " path: $USER_DIR" >> "$v4mValuesYAML" + echo ' files: |' >> "$v4mValuesYAML" + # shellcheck disable=SC2207 + l=($(find "$USER_DIR" -type f | sort)) + for ((i = 0; i < ${#l[@]}; i++)); do + fullPath=${l[i]} + path=${fullPath#"$USER_DIR/"} + echo " $path" >> "$v4mValuesYAML" + done + fi + + # Top-level user.env contents + if [ -f "$USER_DIR/user.env" ]; then + echo ' "user.env": |' >> "$v4mValuesYAML" + sed 's/^/ /' "$USER_DIR/user.env" >> "$v4mValuesYAML" + fi + # Monitoring user.env contents + if [ -f "$USER_DIR/monitoring/user.env" ]; then + echo ' "monitoring_user.env": |' >> "$v4mValuesYAML" + sed 's/^/ /' "$USER_DIR/monitoring/user.env" >> "$v4mValuesYAML" + fi + # Logging user.env contents + if [ -f "$USER_DIR/logging/user.env" ]; then + echo ' "logging_user.env": |' >> "$v4mValuesYAML" + sed 's/^/ /' "$USER_DIR/logging/user.env" >> "$v4mValuesYAML" + fi fi - # Logging user.env contents - if [ -f "$USER_DIR/logging/user.env" ]; then - echo ' "logging_user.env": |' >> "$v4mValuesYAML" - cat "$USER_DIR/logging/user.env" | sed 's/^/ /' >> "$v4mValuesYAML" + + # Encrypt passwords stored in V4M Helm Chart + if echo "$OSTYPE" | grep 'darwin' > /dev/null 2>&1; then + sed -i '' "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=***/g" "$v4mValuesYAML" + sed -i '' "s/ES_ADMIN_PASSWD=.*/ES_ADMIN_PASSWD=***/g" "$v4mValuesYAML" + sed -i '' "s/LOG_LOGADM_PASSWD=.*/LOG_LOGADM_PASSWD=***/g" "$v4mValuesYAML" + else + sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=***/g" "$v4mValuesYAML" + sed -i "s/ES_ADMIN_PASSWD=.*/ES_ADMIN_PASSWD=***/g" "$v4mValuesYAML" + sed -i "s/LOG_LOGADM_PASSWD=.*/LOG_LOGADM_PASSWD=***/g" "$v4mValuesYAML" fi - fi - - # Encrypt passwords stored in V4M Helm Chart - if echo "$OSTYPE" | grep 'darwin' > /dev/null 2>&1; then - sed -i '' "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=***/g" "$v4mValuesYAML" - sed -i '' "s/ES_ADMIN_PASSWD=.*/ES_ADMIN_PASSWD=***/g" "$v4mValuesYAML" - sed -i '' "s/LOG_LOGADM_PASSWD=.*/LOG_LOGADM_PASSWD=***/g" "$v4mValuesYAML" - else - sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=***/g" "$v4mValuesYAML" - sed -i "s/ES_ADMIN_PASSWD=.*/ES_ADMIN_PASSWD=***/g" "$v4mValuesYAML" - sed -i "s/LOG_LOGADM_PASSWD=.*/LOG_LOGADM_PASSWD=***/g" "$v4mValuesYAML" - fi } function deployV4MInfo() { - NS=$1 - releaseName=${2:-'v4m'} - if [ -z "$NS" ]; then - log_error "No namespace specified for deploying SAS Viya Monitoring for Kubernetes version information" - return 1 - fi - - valuesYAML=$TMP_DIR/v4mValues.yaml - populateValuesYAML "$valuesYAML" - - log_info "Updating SAS Viya Monitoring for Kubernetes version information" - helm upgrade --install \ - -n "$NS" \ - --values $valuesYAML \ - $releaseName ./v4m-chart - - getHelmReleaseVersion "$NS" "$releaseName" + NS=$1 + releaseName=${2:-'v4m'} + if [ -z "$NS" ]; then + log_error "No namespace specified for deploying SAS Viya Monitoring for Kubernetes version information" + return 1 + fi + + valuesYAML=$TMP_DIR/v4mValues.yaml + populateValuesYAML "$valuesYAML" + + log_info "Updating SAS Viya Monitoring for Kubernetes version information" + # shellcheck disable=SC2086 + helm upgrade --install \ + -n "$NS" \ + --values $valuesYAML \ + $releaseName ./v4m-chart + + getHelmReleaseVersion "$NS" "$releaseName" } function removeV4MInfo() { - NS=$1 - releaseName=${2:-'v4m'} - if [ -z "$NS" ]; then - log_error "No namespace specified for removing SAS Viya Monitoring for Kubernetes version information" - return 1 - fi - - if [ ! -z $(helm list -n "$NS" --filter "^$releaseName\$" -q) ]; then - log_info "Removing SAS Viya Monitoring for Kubernetes version information" - helm uninstall -n "$NS" "$releaseName" - fi + NS=$1 + releaseName=${2:-'v4m'} + if [ -z "$NS" ]; then + log_error "No namespace specified for removing SAS Viya Monitoring for Kubernetes version information" + return 1 + fi + + if [ -n "$(helm list -n "$NS" --filter "^$releaseName\$" -q)" ]; then + log_info "Removing SAS Viya Monitoring for Kubernetes version information" + helm uninstall -n "$NS" "$releaseName" + fi } function getHelmReleaseVersion() { - NS=$1 - releaseName=${2:-'v4m'} - - releaseVersionFull="" - releaseVersionMajor="" - releaseVersionMinor="" - releaseVersionPatch="" - releaseStatus="" - - origIFS=$IFS - IFS=$'\n' v4mHelmVersionLines=($(helm list -n "$NS" --filter "^$releaseName\$" -o yaml)) - IFS=$origIFS - if [ -z "$v4mHelmVersionLines" ]; then - log_debug "No [$releaseName] release found in [$NS]" - else - for (( i=0; i<${#v4mHelmVersionLines[@]}; i++ )); do - line=${v4mHelmVersionLines[$i]} - vre='app_version: (([0-9]+).([[0-9]+).([0-9]+)\.?(-.+)?)' - sre='status: (.+)' - if [[ $line =~ $vre ]]; then - # Set - releaseVersionFull=${BASH_REMATCH[1]} - releaseVersionMajor=${BASH_REMATCH[2]} - releaseVersionMinor=${BASH_REMATCH[3]} - releaseVersionPatch=${BASH_REMATCH[4]} - elif [[ "$line" =~ $sre ]]; then - releaseStatus=${BASH_REMATCH[1]} - fi - done - - fi - - export releaseVersionFull releaseVersionMajor releaseVersionMinor releaseVersionPatch releaseStatus + NS=$1 + releaseName=${2:-'v4m'} + + releaseVersionFull="" + releaseVersionMajor="" + releaseVersionMinor="" + releaseVersionPatch="" + releaseStatus="" + + origIFS=$IFS + # shellcheck disable=SC2207 + IFS=$'\n' v4mHelmVersionLines=($(helm list -n "$NS" --filter "^$releaseName\$" -o yaml)) + IFS=$origIFS + if [ -z "$v4mHelmVersionLines" ]; then + log_debug "No [$releaseName] release found in [$NS]" + else + for ((i = 0; i < ${#v4mHelmVersionLines[@]}; i++)); do + line=${v4mHelmVersionLines[$i]} + vre='app_version: (([0-9]+).([[0-9]+).([0-9]+)\.?(-.+)?)' + sre='status: (.+)' + if [[ $line =~ $vre ]]; then + # Set + releaseVersionFull=${BASH_REMATCH[1]} + releaseVersionMajor=${BASH_REMATCH[2]} + releaseVersionMinor=${BASH_REMATCH[3]} + releaseVersionPatch=${BASH_REMATCH[4]} + elif [[ $line =~ $sre ]]; then + releaseStatus=${BASH_REMATCH[1]} + fi + done + + fi + + export releaseVersionFull releaseVersionMajor releaseVersionMinor releaseVersionPatch releaseStatus } if [ -z "$V4M_VERSION_INCLUDE" ]; then - getHelmReleaseVersion "$V4M_NS" - - V4M_CURRENT_VERSION_FULL=$releaseVersionFull - V4M_CURRENT_VERSION_MAJOR=$releaseVersionMajor - V4M_CURRENT_VERSION_MINOR=$releaseVersionMinor - V4M_CURRENT_VERSION_PATCH=$releaseVersionPatch - V4M_CURRENT_STATUS=$releaseStatus - - log_debug "V4M_CURRENT_VERSION_FULL=$V4M_CURRENT_VERSION_FULL" - log_debug "V4M_CURRENT_VERSION_MAJOR=$V4M_CURRENT_VERSION_MAJOR" - log_debug "V4M_CURRENT_VERSION_MINOR=$V4M_CURRENT_VERSION_MINOR" - log_debug "V4M_CURRENT_VERSION_PATCH=$V4M_CURRENT_VERSION_PATCH" - log_debug "V4M_CURRENT_STATUS=$V4M_CURRENT_STATUS" - - export V4M_CURRENT_VERSION_FULL V4M_CURRENT_VERSION_MAJOR V4M_CURRENT_VERSION_MINOR V4M_CURRENT_VERSION_PATCH - export V4M_CURRENT_STATUS - - export -f deployV4MInfo removeV4MInfo getHelmReleaseVersion - export V4M_VERSION_INCLUDE=true -fi + getHelmReleaseVersion "$V4M_NS" + + V4M_CURRENT_VERSION_FULL=$releaseVersionFull + V4M_CURRENT_VERSION_MAJOR=$releaseVersionMajor + V4M_CURRENT_VERSION_MINOR=$releaseVersionMinor + V4M_CURRENT_VERSION_PATCH=$releaseVersionPatch + V4M_CURRENT_STATUS=$releaseStatus + + log_debug "V4M_CURRENT_VERSION_FULL=$V4M_CURRENT_VERSION_FULL" + log_debug "V4M_CURRENT_VERSION_MAJOR=$V4M_CURRENT_VERSION_MAJOR" + log_debug "V4M_CURRENT_VERSION_MINOR=$V4M_CURRENT_VERSION_MINOR" + log_debug "V4M_CURRENT_VERSION_PATCH=$V4M_CURRENT_VERSION_PATCH" + log_debug "V4M_CURRENT_STATUS=$V4M_CURRENT_STATUS" + export V4M_CURRENT_VERSION_FULL V4M_CURRENT_VERSION_MAJOR V4M_CURRENT_VERSION_MINOR V4M_CURRENT_VERSION_PATCH + export V4M_CURRENT_STATUS + + export -f deployV4MInfo removeV4MInfo getHelmReleaseVersion + export V4M_VERSION_INCLUDE=true +fi