Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@
* [UPGRADE] OpenSearch Data Source Plugin to Grafana upgraded from 2.28.0 to 2.29.1

* **Metrics**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to link to docs in the last sentence?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with the proper link.

* [CHANGE] The Grafana alerts targeting SAS Viya that previously were provided by default have been moved to the samples directory. Given the variability of SAS Viya environments, these alerts are now optional. They can be copied to USER_DIR/monitoring/alerting and customized to fit the SAS Viya environment prior to deployment. They have also been split into separate files for easier customization. See the [Alerting Samples README](samples/alerts/README.md) for more details.
* [FEATURE] Automatically define the SMTP server configuration to permit Grafana to send e-mails.
If enabled (by setting `AUTOGENERATE_SMTP` to 'true'), this optional feature allows admins to define
email-based contact points for alerts. Users need to provide connection information via the environment
variables: `SMTP_SERVER, SMTP_PORT`, `SMTP_FROM_ADDRESS` and `SMTP_FROM_NAME`. See [Configure Email Settings for Grafana Alerts](documentation.sas.com/doc/en/obsrvcdc/v_003/obsrvdply/n0auhd4hutsf7xn169hfvriysz4e.htm#p1fql9ekyxckamn1jtlujeauhy72)
for more information.
* [CHANGE] The Grafana alerts targeting SAS Viya that previously were provided by default have been moved
to the samples directory. Given the variability of SAS Viya environments, these alerts are now optional.
They can be copied to USER_DIR/monitoring/alerting and customized to fit the SAS Viya environment prior
to deployment. They have also been split into separate files for easier customization. See the [Alerting Samples README](samples/alerts/README.md) for more details.


## Version 1.2.41 (19AUG2025)
* **Metrics**
Expand Down
269 changes: 163 additions & 106 deletions bin/autogenerate-include.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,118 +6,177 @@


function checkYqVersion {
# confirm yq installed and correct version
local goodver yq_version
goodver="yq \(.+mikefarah.+\) version (v)?(4\.(3[2-9]|[4-9][0-9])\..+)"
yq_version=$(yq --version)
if [ "$?" == "1" ]; then
log_error "Required component [yq] not available."
return 1
elif [[ ! $yq_version =~ $goodver ]]; then
log_error "Incorrect version [$yq_version] found; version 4.32.2+ required."
return 1
else
log_debug "A valid version [$yq_version] of yq detected"
return 0
fi
# confirm yq installed and correct version
local goodver yq_version
goodver="yq \(.+mikefarah.+\) version (v)?(4\.(3[2-9]|[4-9][0-9])\..+)"
yq_version=$(yq --version)
if [ "$?" == "1" ]; then
log_error "Required component [yq] not available."
return 1
elif [[ ! $yq_version =~ $goodver ]]; then
log_error "Incorrect version [$yq_version] found; version 4.32.2+ required."
return 1
else
log_debug "A valid version [$yq_version] of yq detected"
return 0
fi
}

export -f checkYqVersion

function create_ingress_certs {
local certFile keyFile namespace secretName

namespace="$1"
secretName="$2"
certFile="${3:-$INGRESS_CERT}"
keyFile="${4:-$INGRESS_KEY}"

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
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
local certFile keyFile namespace secretName

namespace="$1"
secretName="$2"
certFile="${3:-$INGRESS_CERT}"
keyFile="${4:-$INGRESS_KEY}"

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
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
}

export -f create_ingress_certs

AUTOGENERATE_INGRESS="${AUTOGENERATE_INGRESS:-false}"
AUTOGENERATE_STORAGECLASS="${AUTOGENERATE_STORAGECLASS:-false}"
AUTOGENERATE_SMTP="${AUTOGENERATE_SMTP:-false}"

if [ "$AUTOGENERATE_INGRESS" != "true" ] && [ "$AUTOGENERATE_STORAGECLASS" != "true" ]; then
log_debug "No autogeneration of YAML enabled"
export AUTOGENERATE_SOURCED="NotNeeded"
if [ "$AUTOGENERATE_INGRESS" != "true" ] && [ "$AUTOGENERATE_STORAGECLASS" != "true" ] && [ "$AUTOGENERATE_SMTP" != "true" ]; then
log_debug "No autogeneration of YAML enabled"
export AUTOGENERATE_SOURCED="NotNeeded"
fi

if [ -z "$AUTOGENERATE_SOURCED" ]; then

if ! checkYqVersion; then
exit 1
fi

if [ "$AUTOGENERATE_INGRESS" == "true" ]; then

# Confirm NOT on OpenShift
if [ "$OPENSHIFT_CLUSTER" == "true" ]; then
log_error "Setting AUTOGENERATE_INGRESS to 'true' is not valid on OpenShift clusters."
log_error "Web applications will be made accessible via OpenShift routes instead (if enabled)."

export AUTOGENERATE_INGRESS="false"
exit 1
fi


#validate required inputs
BASE_DOMAIN="${BASE_DOMAIN}"
if [ -z "$BASE_DOMAIN" ]; then
log_error "Required parameter [BASE_DOMAIN] not provided"
exit 1
fi

ROUTING="${ROUTING:-host}"

if [ "$ROUTING" == "path" ]; then
export MON_TLS_PATH_INGRESS="true"
log_debug "Path ingress requested, setting MON_TLS_PATH_INGRESS to 'true'"
elif [ "$ROUTING" != "host" ] && [ "$ROUTING" != "path" ]; then
log_error "Invalid ROUTING value, valid values are 'host' or 'path'"
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
log_warn "Missing Ingress certificate file; specified Ingress cert [$INGRESS_CERT] and/or key [$INGRESS_KEY] file is missing."
log_warn "You can create the missing Kubernetes secrets after deployment. See Enable TLS for Ingress topic in Help Center documentation."
#unset variable values to prevent further attempted use
unset INGRESS_CERT
unset INGRESS_KEY
else
log_debug "Ingress cert [$INGRESS_CERT] and key [$INGRESS_KEY] files exist."
fi
fi

log_info "Autogeneration of Ingress definitions has been enabled"

fi

if [ "$AUTOGENERATE_STORAGECLASS" == "true" ]; then

log_info "Autogeneration of StorageClass specfication has been enabled"

fi

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]"
if ! checkYqVersion; then
exit 1
fi

if [ "$AUTOGENERATE_INGRESS" == "true" ]; then

# Confirm NOT on OpenShift
if [ "$OPENSHIFT_CLUSTER" == "true" ]; then
log_error "Setting AUTOGENERATE_INGRESS to 'true' is not valid on OpenShift clusters."
log_error "Web applications will be made accessible via OpenShift routes instead (if enabled)."

export AUTOGENERATE_INGRESS="false"
exit 1
fi

#validate required inputs
BASE_DOMAIN="${BASE_DOMAIN}"
if [ -z "$BASE_DOMAIN" ]; then
log_error "Required parameter [BASE_DOMAIN] not provided"
exit 1
fi

ROUTING="${ROUTING:-host}"

if [ "$ROUTING" == "path" ]; then
export MON_TLS_PATH_INGRESS="true"
log_debug "Path ingress requested, setting MON_TLS_PATH_INGRESS to 'true'"
elif [ "$ROUTING" != "host" ] && [ "$ROUTING" != "path" ]; then
log_error "Invalid ROUTING value, valid values are 'host' or 'path'"
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
log_warn "Missing Ingress certificate file; specified Ingress cert [$INGRESS_CERT] and/or key [$INGRESS_KEY] file is missing."
log_warn "You can create the missing Kubernetes secrets after deployment. See Enable TLS for Ingress topic in Help Center documentation."
#unset variable values to prevent further attempted use
unset INGRESS_CERT
unset INGRESS_KEY
else
log_debug "Ingress cert [$INGRESS_CERT] and key [$INGRESS_KEY] files exist."
fi
fi

log_info "Autogeneration of Ingress definitions has been enabled"

fi

if [ "$AUTOGENERATE_STORAGECLASS" == "true" ]; then
log_info "Autogeneration of StorageClass specfication has been enabled"
fi

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}"
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}"
SMTP_TLS_KEY_FILE="${SMTP_TLS_KEY_FILE:-/cert/tls.key}"

log_info "Autogeneration of SMTP Configuration has been enabled"

if [ -z "$SMTP_HOST" ]; then
log_error "Required parameter [SMTP_HOST] not provided"
exit 1
fi

if [ -z "$SMTP_PORT" ]; then
log_error "Required parameter [SMTP_PORT] not provided"
exit 1
fi

if [ -z "$SMTP_FROM_ADDRESS" ]; then
log_error "Required parameter [SMTP_FROM_ADDRESS] not provided"
exit 1
fi

if [ -z "$SMTP_FROM_NAME" ]; then
log_error "Required parameter [SMTP_FROM_NAME] not provided"
exit 1
fi

# Handle SMTP user credentials
if [ -n "$(kubectl get secret -n "$MON_NS" "$SMTP_USER_SECRET" --ignore-not-found -o name 2> /dev/null)" ]; 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
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
else
log_debug "Secret [$MON_NS/$SMTP_USER_SECRET] will need to be created later."
# shellcheck disable=SC2034
smtpCreateUserSecret="true"
fi

fi

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]"
fi


Expand All @@ -131,19 +190,17 @@ function checkStorageClass {
storageClass="${2:-$STORAGECLASS}"

if [ -z "$storageClass" ]; then
log_error "Required parameter not provided. Either [$storageClassEnvVar] or [STORAGECLASS] MUST be provided."
exit 1
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
log_debug "The specified StorageClass [$storageClass] exists"
else
log_error "The specified StorageClass [$storageClass] does NOT exist"
exit 1
fi
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"
exit 1
fi
fi

}



export -f checkStorageClass
46 changes: 46 additions & 0 deletions monitoring/bin/deploy_monitoring_cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,52 @@ if [ -z "$(kubectl get ns "$MON_NS" -o name 2> /dev/null)" ]; then
disable_sa_token_automount "$MON_NS" default
fi

AUTOGENERATE_SMTP="${AUTOGENERATE_SMTP:-false}"

if [ "$AUTOGENERATE_SMTP" == "true" ]; then

if [ ! -f "$autogeneratedYAMLFile" ]; then
log_debug "Creating file [$autogeneratedYAMLFile]"
touch "$autogeneratedYAMLFile"
else
log_debug "File [$autogeneratedYAMLFile] already exists"
fi

smtpHost="${SMTP_HOST}"
smtpPort="${SMTP_PORT}"
smtpFromAddress="${SMTP_FROM_ADDRESS}"
smtpFromName="${SMTP_FROM_NAME}"
smtpUserSecret="${SMTP_USER_SECRET}"
smtpSkipVerify="${SMTP_SKIP_VERIFY:-false}"
smtpTLSCertFile="${SMTP_TLS_CERT_FILE:-/cert/tls.crt}"
smtpTLSKeyFile="${SMTP_TLS_KEY_FILE:-/cert/tls.key}"

# Create secret to hold SMTP user credentials
if [ "$smtpCreateUserSecret" == "true" ]; then
log_debug "Creating secret [$MON_NS/$SMTP_USER_SECRET] from supplied user [$SMTP_USER] and password."
kubectl create secret generic "$SMTP_USER_SECRET" -n "$MON_NS" --from-literal=user="$SMTP_USER" --from-literal=password="$SMTP_PASSWORD"
fi

yq -i '.grafana."grafana.ini".smtp.enabled=true' "$autogeneratedYAMLFile"

value="$smtpHost:$smtpPort" yq -i '.grafana."grafana.ini".smtp.host=env(value)' "$autogeneratedYAMLFile"

value="$smtpFromAddress" yq -i '.grafana."grafana.ini".smtp.from_address=env(value)' "$autogeneratedYAMLFile"
value="$smtpFromName" yq -i '.grafana."grafana.ini".smtp.from_name=env(value)' "$autogeneratedYAMLFile"

if [ -n "$smtpUserSecret" ]; then
value="$smtpUserSecret" yq -i '.grafana.smtp.existingSecret=env(value)' "$autogeneratedYAMLFile"
fi

value="$smtpSkipVerify" yq -i '.grafana."grafana.ini".smtp.skip_verify=env(value)' "$autogeneratedYAMLFile"

value="$smtpTLSCertFile" yq -i '.grafana."grafana.ini".smtp.cert_file=env(value)' "$autogeneratedYAMLFile"
value="$smtpTLSKeyFile" yq -i '.grafana."grafana.ini".smtp.key_file=env(value)' "$autogeneratedYAMLFile"

else
log_debug "Auto-generation of SMTP not enabled; skipping Grafana SMTP server configuration"
fi

#Generate yaml file with all container-related keys
generateImageKeysFile "$PROMOP_FULL_IMAGE" "monitoring/prom-operator_container_image.template"
if [ -z "$PROM_OPERATOR_CRD_VERSION" ]; then
Expand Down