Compare commits

...

9 Commits

Author SHA1 Message Date
eeb5b2eb7b feat(monitor): Implement state-based notifications to prevent alert spam
Introduces state management to 'monitor.sh' to send notifications only when a monitored status changes (e.g., from healthy to alert, or alert to resolved). This prevents repetitive alerts for persistent issues. Creates a 'monitor_state' directory for tracking. Updates script version to 1.2.0.
2025-09-25 18:34:40 +02:00
a6150467e5 fix(monitor): Correct hdbsql command in backup monitoring
Fixes an issue in 'monitor.sh' where the HANA backup monitoring used incorrect variable names ('HANA_USERKEY' instead of 'HANA_USER_KEY') and did not explicitly use the configured 'HDBSQL_PATH' for the 'hdbsql' command. Updates script version to 1.1.1.
2025-09-25 18:33:58 +02:00
2424d55426 feat(monitor): Add HANA data backup age monitoring
Introduces a new monitoring check in 'monitor.sh' to verify the age of the last successful SAP HANA data backup. Alerts are sent if the backup age exceeds a configurable 'BACKUP_THRESHOLD_HOURS'. Updates script version to 1.1.0.
2025-09-25 18:33:49 +02:00
408f2396da refactor: Rename cleaner.sh and keymanager.sh scripts
Renames 'clean.sh' to 'cleaner.sh' and 'hdb_keymanager.sh' to 'keymanager.sh' for consistency. Updates corresponding file paths in 'packages.conf'.
2025-09-25 18:33:37 +02:00
a16b8aa42b feat(installer): Rework install.sh for non-interactive mode and improved UX
Performs a major refactoring of 'install.sh' to introduce non-interactive installation via command-line arguments (e.g., '--overwrite-config'). Enhances the interactive menu with detailed package information (display name, description, version, update status) and improves config file handling with diff previews. Updates 'packages.conf' format to support new package metadata and uses short, lowercase keys.
2025-09-25 18:33:24 +02:00
d9760b9072 docs(readme): Update Aurora script usage to reflect automation
Updates 'README.md' to reflect the new, automated execution model of 'aurora.sh', removing references to manual 'new', 'complete', and 'info' arguments. The script is now configured via 'aurora.conf' and typically run via cron.
2025-09-25 18:33:09 +02:00
229683dfa5 feat(aurora): Dynamically fetch and update company name in refreshed schema
Enhances 'aurora.sh' to fetch the original company name from the source schema and use it to construct a descriptive company name for the new Aurora schema (e.g., "AURORA - [Original Name] - [Date]"). Updates script version to 2.1.0.
2025-09-25 18:31:51 +02:00
2d5d2dfa9c refactor(aurora): Complete rewrite of Aurora refresh script to v2.0.0
Performs a major refactoring of 'aurora.sh' and 'aurora.conf'. The script is rewritten for improved clarity, error handling, and a streamlined, single-purpose execution flow for automated HANA schema refreshes. Configuration variables are renamed for better understanding. Updates script version to 2.0.0.
2025-09-25 18:31:35 +02:00
61e44106e5 feat(hanatool): Add --replace flag for schema imports
Introduces a new '--replace' option to 'hanatool.sh' to allow replacing existing objects during schema import operations. Updates script version to 1.5.0.
2025-09-25 18:30:45 +02:00
10 changed files with 394 additions and 270 deletions

View File

@@ -80,10 +80,7 @@ Here's a breakdown of the scripts included in this repository:
* Can drop existing Aurora schema before refresh. * Can drop existing Aurora schema before refresh.
* Grants privileges to a specified user. * Grants privileges to a specified user.
* Runs post-import SQL scripts. * Runs post-import SQL scripts.
* **Usage**: `./aurora/aurora.sh [new | complete | info]` * **Usage**: The script runs automatically based on the settings in `aurora/aurora.conf`. It is typically scheduled via cron.
* `new`: Export, import, and rename (no privileges or post-scripts).
* `complete`: Drop, export, import, grant privileges, and run post-scripts.
* `info`: Show configuration information.
### 8. `aurora/aurora.conf` (Configuration for `aurora.sh`) ### 8. `aurora/aurora.conf` (Configuration for `aurora.sh`)

View File

@@ -1,31 +1,39 @@
# Configuration for the HANA Aurora Refresh Script # Configuration for the Aurora Refresh Script (aurora_refresh.sh)
# Place this file in the same directory as the aurora.sh script. # Place this file in the same directory as the script.
# --- Main Settings --- # --- Main Settings ---
# The source production schema to be copied. # The source production schema to be copied.
SCHEMA="SBO_DEMO" # Example: "SBO_COMPANY_PROD"
SOURCE_SCHEMA="SBODEMOHU"
# The user who will be granted privileges on the new Aurora schema. # The HANA user that will be granted read/write access to the new Aurora schema.
AURORA_SCHEMA_USER="B1_53424F5F4348494D5045585F4155524F5241_RW" # This is typically a technical user for the application.
# Example: "B1_..._RW"
AURORA_USER="B1_XXXXXXXXX_RW"
# The database user for performing backup and administrative tasks. # The secure user store key for the HANA database user with privileges to
BACKOP_USER="CRONKEY" # perform EXPORT, IMPORT, DROP SCHEMA, and GRANT commands (e.g., SYSTEM).
# Using a key (hdbuserstore) is more secure than hardcoding a password.
# Example: "CRONKEY"
DB_ADMIN_KEY="CRONKEY"
# --- Paths and Files --- # --- Paths ---
# The base directory for storing the temporary schema export. # The base directory where the temporary schema export folder will be created.
BACKUP_DIR="/hana/shared/backup/schema" # Ensure the <sid>adm user has write permissions here.
BACKUP_BASE_DIR="/hana/shared/backup/schema"
# The full path to the HANA hdbsql executable. # The full path to the HANA hdbsql executable.
HDBSQL="/usr/sap/NDB/HDB00/exe/hdbsql" HDBSQL="/usr/sap/NDB/HDB00/exe/hdbsql"
# The root directory where post-import SQL scripts are located.
SQL_SCRIPTS_ROOT="/usr/sap/NDB/home/tools/sql"
# --- Post-Import Scripts --- # --- Post-Import Scripts (Optional) ---
# The root directory where the SQL script and its associated files are located. # A space-separated list of SQL script filenames to run after the import is complete.
SQL_ROOT="/usr/sap/NDB/home/tools" # The script will look for these files inside the SQL_SCRIPTS_ROOT directory.
# Leave empty ("") if no scripts are needed.
# A space-separated list of SQL script files to run after the import is complete. # Example: "update_user_emails.sql cleanup_tables.sql"
# These scripts should be located in the SCRIPT_ROOT directory. POST_IMPORT_SQL=""
POST_SQL=""

View File

@@ -1,115 +1,119 @@
#!/bin/sh #!/bin/sh
# Version: 1.2.6 # Version: 2.1.0
# Exit immediately if a command exits with a non-zero status. #
set -e # Purpose: Performs an automated refresh of a SAP HANA schema. It exports a
# production schema and re-imports it under a new name ("Aurora")
# to create an up-to-date, non-production environment for testing.
# Designed to be run via cron, typically in the early morning.
#
# -----------------------------------------------------------------------------
# === SETUP === # --- Basic Setup ---
# Determine script's directory and source the configuration file. # Exit immediately if any command fails or if an unset variable is used.
set -eu
# --- Configuration ---
# Load the configuration file located in the same directory as the script.
SCRIPT_DIR=$(dirname "$0") SCRIPT_DIR=$(dirname "$0")
CONFIG_FILE="${SCRIPT_DIR}/aurora.conf" CONFIG_FILE="${SCRIPT_DIR}/aurora.conf"
if [ ! -f "$CONFIG_FILE" ]; then if [ ! -f "$CONFIG_FILE" ]; then
echo "Error: Configuration file not found at '${CONFIG_FILE}'" >&2 echo "FATAL: Configuration file not found at '${CONFIG_FILE}'" >&2
exit 1 exit 1
fi fi
# shellcheck source=aurora.conf # shellcheck source=aurora.conf
. "$CONFIG_FILE" . "$CONFIG_FILE"
# === DERIVED VARIABLES === # --- Validate Configuration ---
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S") if [ ! -x "$HDBSQL" ]; then
AURORA="${SCHEMA}_AURORA" echo "❌ FATAL: hdbsql is not found or not executable at '${HDBSQL}'" >&2
AURORA_TEMP_DIR="${BACKUP_DIR}/${AURORA}" exit 1
COMPNYNAME="${SCHEMA#SBO_}"
[[ "$COMPNYNAME" == *_PROD ]] && COMPNYNAME="${COMPNYNAME%_PROD}" # Remove _PROD suffix if it exists
# === FUNCTIONS ===
run_sql() {
echo " Executing: $1"
"$HDBSQL" -U "${BACKOP_USER}" "$1" >/dev/null
}
show_info() {
echo "Source Schema: ${SCHEMA}"
echo "Target Schema: ${AURORA}"
echo "Target Schema User: ${AURORA_SCHEMA_USER}"
echo "Company Name: ${COMPNYNAME}"
echo "Export Directory: ${AURORA_TEMP_DIR}"
}
usage() {
echo "Usage: $0 [--info]"
echo " --info : Show configuration information."
echo " (No argument) : Drop, export, import, grant privileges, and run post-scripts."
}
export_schema() {
echo "⬇️ Starting schema export for '${SCHEMA}'..."
mkdir -p "$AURORA_TEMP_DIR"
run_sql "EXPORT \"${SCHEMA}\".\"*\" AS BINARY INTO '$AURORA_TEMP_DIR' WITH REPLACE;"
echo "✅ Schema export completed."
}
import_and_rename() {
echo "⬆️ Starting import and rename to '${AURORA}'..."
run_sql "IMPORT \"${SCHEMA}\".\"*\" FROM '$AURORA_TEMP_DIR' WITH IGNORE EXISTING RENAME SCHEMA \"${SCHEMA}\" TO \"${AURORA}\";"
echo " Updating company name fields..."
"$HDBSQL" -U "${BACKOP_USER}" -c ";" -I - <<EOF
UPDATE \"${AURORA}\".CINF SET \"CompnyName\"='AURORA ${COMPNYNAME} ${TIMESTAMP}';
UPDATE \"${AURORA}\".OADM SET \"CompnyName\"='AURORA ${COMPNYNAME} ${TIMESTAMP}';
UPDATE \"${AURORA}\".OADM SET \"PrintHeadr\"='AURORA ${COMPNYNAME} ${TIMESTAMP}';
EOF
echo "✅ Import and rename completed."
}
grant_privileges() {
echo "🔑 Granting privileges on '${AURORA}' to '${AURORA_SCHEMA_USER}'..."
run_sql "GRANT ALL PRIVILEGES ON SCHEMA \"${AURORA}\" TO \"${AURORA_SCHEMA_USER}\";"
echo "✅ Privileges granted."
}
drop_aurora_schema() {
echo "🗑️ Dropping existing '${AURORA}' schema..."
run_sql "DROP SCHEMA \"${AURORA}\" CASCADE;" 2>/dev/null || echo "⚠️ Could not drop schema '${AURORA}'. It might not exist." >&2
echo "✅ Old schema dropped."
}
run_post_scripts() {
echo "⚙️ Running post-import SQL scripts: ${POST_SQL}..."
for sql_file in $POST_SQL; do
echo " - Running script: ${sql_file}"
"$HDBSQL" -U "${BACKOP_USER}" -I "${SCRIPT_ROOT}/${sql_file}"
done
echo "✅ All post-import scripts completed."
}
cleanup_exported_files() {
echo "🧹 Cleaning up exported files from '${AURORA_TEMP_DIR}'..."
rm -rf "$AURORA_TEMP_DIR"
echo "✅ Exported files cleaned up."
}
# === SCRIPT EXECUTION ===
if [ $# -eq 0 ]; then
echo "🚀 Starting 'complete' operation (default)..."
drop_aurora_schema
export_schema
import_and_rename
grant_privileges
run_post_scripts
cleanup_exported_files
echo "🎉 'Complete' operation finished successfully!"
exit 0
fi fi
case "$1" in # --- Derived Variables (Do Not Edit) ---
--info) TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
show_info AURORA_SCHEMA="${SOURCE_SCHEMA}_AURORA"
;; EXPORT_DIR="${BACKUP_BASE_DIR}/${AURORA_SCHEMA}_TEMP_EXPORT"
*) COMPANY_NAME_BASE=$(echo "${SOURCE_SCHEMA}" | sed 's/^SBO_//' | sed 's/_PROD$//')
echo "❌ Error: Invalid argument '$1'." >&2
usage # --- Main Execution ---
exit 1 echo
;; echo "🚀 [$(date "+%T")] Starting Aurora Refresh for '${SOURCE_SCHEMA}'"
esac echo "--------------------------------------------------------"
echo " Source Schema: ${SOURCE_SCHEMA}"
echo " Target Aurora Schema: ${AURORA_SCHEMA}"
echo " Temp Export Path: ${EXPORT_DIR}"
echo "--------------------------------------------------------"
# 1. Drop the old Aurora schema if it exists.
echo "🗑️ Dropping old schema '${AURORA_SCHEMA}' (if it exists)..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "DROP SCHEMA \"${AURORA_SCHEMA}\" CASCADE" >/dev/null 2>&1 || echo " -> Schema did not exist. Continuing."
# 2. Prepare the temporary export directory.
echo "📁 Preparing temporary export directory..."
rm -rf "$EXPORT_DIR"
mkdir -p "$EXPORT_DIR"
# 3. Export the source schema.
echo "⬇️ Exporting source schema '${SOURCE_SCHEMA}' to binary files..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "EXPORT \"${SOURCE_SCHEMA}\".\"*\" AS BINARY INTO '${EXPORT_DIR}' WITH REPLACE;" >/dev/null
echo " -> Export complete."
# 4. Import the data into the new Aurora schema.
echo "⬆️ Importing data and renaming schema to '${AURORA_SCHEMA}'..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "IMPORT \"${SOURCE_SCHEMA}\".\"*\" FROM '${EXPORT_DIR}' WITH IGNORE EXISTING RENAME SCHEMA \"${SOURCE_SCHEMA}\" TO \"${AURORA_SCHEMA}\";" >/dev/null
echo " -> Import complete."
# 5. Update company name in CINF and OADM tables.
echo "✍️ Updating company name fields in the new schema..."
# First, get the original company name from the source schema.
# The query returns a header and the name in quotes. sed gets the second line, tr removes the quotes, xargs trims whitespace.
echo " -> Fetching original company name from '${SOURCE_SCHEMA}'..."
ORIGINAL_COMPNY_NAME=$("$HDBSQL" -U "$DB_ADMIN_KEY" "SELECT \"CompnyName\" FROM \"${SOURCE_SCHEMA}\".\"CINF\"" | sed -n '2p' | tr -d '"' | xargs)
# Construct the new name in the desired format.
DATE_STAMP=$(date "+%Y-%m-%d")
NEW_COMPNY_NAME="AURORA - ${ORIGINAL_COMPNY_NAME} - ${DATE_STAMP}"
echo " -> New company name set to: '${NEW_COMPNY_NAME}'"
echo " -> Updating CINF table..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "UPDATE \"${AURORA_SCHEMA}\".CINF SET \"CompnyName\" = '${NEW_COMPNY_NAME}';" >/dev/null
echo " -> Updating OADM table..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "UPDATE \"${AURORA_SCHEMA}\".OADM SET \"CompnyName\" = '${NEW_COMPNY_NAME}', \"PrintHeadr\" = '${NEW_COMPNY_NAME}';" >/dev/null
echo " -> Company info updated."
# 6. Grant privileges to the read/write user.
echo "🔑 Granting ALL privileges on '${AURORA_SCHEMA}' to '${AURORA_USER}'..."
"$HDBSQL" -U "$DB_ADMIN_KEY" "GRANT ALL PRIVILEGES ON SCHEMA \"${AURORA_SCHEMA}\" TO \"${AURORA_USER}\";" >/dev/null
echo " -> Privileges granted."
# 7. Run post-import SQL scripts, if any are defined.
if [ -n "$POST_IMPORT_SQL" ]; then
echo "⚙️ Running post-import SQL scripts..."
# Use word splitting intentionally here
# shellcheck disable=SC2086
for sql_file in $POST_IMPORT_SQL; do
full_path="${SQL_SCRIPTS_ROOT}/${sql_file}"
if [ -f "$full_path" ]; then
echo " -> Executing: ${sql_file}"
"$HDBSQL" -U "$DB_ADMIN_KEY" -I "$full_path"
else
echo " -> ⚠️ WARNING: Script not found: ${full_path}" >&2
fi
done
else
echo " No post-import SQL scripts to run."
fi
# 8. Clean up the temporary export files.
echo "🧹 Cleaning up temporary directory '${EXPORT_DIR}'..."
rm -rf "$EXPORT_DIR"
echo " -> Cleanup complete."
echo "--------------------------------------------------------"
echo "✅ [$(date "+%T")] Aurora Refresh finished successfully!"
echo
exit 0

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Version: 1.4.6 # Version: 1.5.0
# ============================================================================== # ==============================================================================
# SAP HANA Schema and Tenant Management Tool (hanatool.sh) # SAP HANA Schema and Tenant Management Tool (hanatool.sh)
# #
@@ -12,6 +12,7 @@ COMPRESS=false
THREADS=0 # 0 means auto-calculate later THREADS=0 # 0 means auto-calculate later
DRY_RUN=false DRY_RUN=false
NTFY_TOKEN="" NTFY_TOKEN=""
IMPORT_REPLACE=false
# --- Help/Usage Function --- # --- Help/Usage Function ---
usage() { usage() {
@@ -38,6 +39,7 @@ usage() {
echo " -c, --compress Enable tar.gz compression for exports and backups." echo " -c, --compress Enable tar.gz compression for exports and backups."
echo " -n, --dry-run Show what commands would be executed without running them." echo " -n, --dry-run Show what commands would be executed without running them."
echo " --ntfy <token> Send a notification via ntfy.sh upon completion/failure." echo " --ntfy <token> Send a notification via ntfy.sh upon completion/failure."
echo " --replace Use the 'REPLACE' option for imports instead of 'IGNORE EXISTING'."
echo " --hdbsql <path> Specify a custom path for the hdbsql executable." echo " --hdbsql <path> Specify a custom path for the hdbsql executable."
echo " -h, --help Show this help message." echo " -h, --help Show this help message."
echo "" echo ""
@@ -48,8 +50,8 @@ usage() {
echo " # Import MYSCHEMA from a compressed archive" echo " # Import MYSCHEMA from a compressed archive"
echo " $0 MY_SCHEMA_KEY import MYSCHEMA /hana/backups/MYSCHEMA_20240101.tar.gz -c" echo " $0 MY_SCHEMA_KEY import MYSCHEMA /hana/backups/MYSCHEMA_20240101.tar.gz -c"
echo "" echo ""
echo " # Import MYSCHEMA as MYSCHEMA_TEST using a custom hdbsql path" echo " # Import MYSCHEMA as MYSCHEMA_TEST, replacing any existing objects"
echo " $0 MY_SCHEMA_KEY import-rename MYSCHEMA MYSCHEMA_TEST /hana/backups/temp_export --hdbsql /sap/custom/hdbsql" echo " $0 MY_SCHEMA_KEY import-rename MYSCHEMA MYSCHEMA_TEST /hana/backups/temp_export --replace"
} }
# --- Notification Function --- # --- Notification Function ---
@@ -83,6 +85,10 @@ while [[ $# -gt 0 ]]; do
NTFY_TOKEN="$2" NTFY_TOKEN="$2"
shift 2 shift 2
;; ;;
--replace)
IMPORT_REPLACE=true
shift
;;
--hdbsql) --hdbsql)
HDBSQL_PATH="$2" HDBSQL_PATH="$2"
shift 2 shift 2
@@ -350,12 +356,20 @@ case "$ACTION" in
exit 1 exit 1
fi fi
QUERY_RENAME_PART="" local import_options
if [[ "$ACTION" == "import-rename" ]]; then if [[ "$IMPORT_REPLACE" == "true" ]]; then
QUERY_RENAME_PART="RENAME SCHEMA \"${SCHEMA_NAME}\" TO \"${NEW_SCHEMA_NAME}\"" import_options="REPLACE"
echo " - Mode: REPLACE"
else
import_options="IGNORE EXISTING"
echo " - Mode: IGNORE EXISTING (default)"
fi fi
QUERY="IMPORT \"${SCHEMA_NAME}\".\"*\" AS BINARY FROM '${IMPORT_DIR}' WITH IGNORE EXISTING THREADS ${THREADS} ${QUERY_RENAME_PART};" if [[ "$ACTION" == "import-rename" ]]; then
import_options="${import_options} RENAME SCHEMA \"${SCHEMA_NAME}\" TO \"${NEW_SCHEMA_NAME}\""
fi
QUERY="IMPORT \"${SCHEMA_NAME}\".\"*\" AS BINARY FROM '${IMPORT_DIR}' WITH ${import_options} THREADS ${THREADS};"
EXIT_CODE=0 EXIT_CODE=0
if [[ "$DRY_RUN" == "true" ]]; then if [[ "$DRY_RUN" == "true" ]]; then

View File

@@ -2,38 +2,26 @@
# --- Main Script --- # --- Main Script ---
# This script presents a menu of software packages defined in a remote # This script presents a menu of software packages, or installs them
# configuration file. The user can select one or more packages, and the # non-interactively via command-line arguments. It downloads files from a
# script will download the corresponding files. It includes a feature to show # remote configuration, shows a diff for config updates, and checks versions.
# a diff and ask for confirmation before overwriting existing config files.
# It can also check for updates to already-installed scripts.
# --- Functions --- # --- Functions ---
# A simple function to log messages with a consistent format.
log() {
echo "[$1] $2"
}
# Get the version from a local script file. # Get the version from a local script file.
# It reads the first 5 lines and extracts the version number.
get_local_version() { get_local_version() {
local file_path="$1" local file_path="$1"
if [[ -f "${file_path}" ]]; then if [[ -f "${file_path}" ]]; then
# Grep for the version line, then use awk to get the last field.
head -n 5 "${file_path}" | grep -m 1 "^# Version:" | awk '{print $NF}' head -n 5 "${file_path}" | grep -m 1 "^# Version:" | awk '{print $NF}'
else else
echo "0.0.0" # Return a base version if file doesn't exist. echo "0.0.0" # Return a base version if file doesn't exist.
fi fi
} }
# Compare two version strings (e.g., "1.2.0" vs "1.10.0"). # Compare two version strings. Returns 0 if v1 is newer.
# Returns 0 if v1 is newer, 1 if they are the same or v2 is newer.
is_version_greater() { is_version_greater() {
local v1=$1 local v1=$1
local v2=$2 local v2=$2
# Use sort's version sorting capability to find the "highest" version.
# If the highest version is v1, then v1 > v2.
if [[ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n 1)" != "$v1" ]]; then if [[ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n 1)" != "$v1" ]]; then
return 0 # v1 is greater return 0 # v1 is greater
else else
@@ -41,181 +29,199 @@ is_version_greater() {
fi fi
} }
# New function to process a single selected package. # Process a single selected package.
process_package() { process_package() {
local choice="$1" local choice_key="$1"
# Check if the choice is a valid package name. local force_overwrite="$2" # Expects "true" or "false"
if [[ -z "${SCRIPT_PACKAGES[$choice]}" ]]; then
log "❌" "Invalid package name provided: '${choice}'" if [[ -z "${SCRIPT_PACKAGES[$choice_key]}" ]]; then
echo "[❌] Invalid package name provided: '${choice_key}'"
return return
fi fi
echo echo
log "⬇️" "Processing package: '${choice}'..." echo "[⬇️] Processing package: '${choice_key}'..."
# Get the config value and split it into version and URLs # Parse the new config format
config_value="${SCRIPT_PACKAGES[$choice]}" config_value="${SCRIPT_PACKAGES[$choice_key]}"
remote_version=$(echo "${config_value}" | cut -d'|' -f1) display_name=$(echo "${config_value}" | cut -d'|' -f1)
urls_to_download=$(echo "${config_value}" | cut -d'|' -f2-) remote_version=$(echo "${config_value}" | cut -d'|' -f2)
description=$(echo "${config_value}" | cut -d'|' -f3)
urls_to_download=$(echo "${config_value}" | cut -d'|' -f4-)
read -r -a urls_to_download_array <<< "$urls_to_download" read -r -a urls_to_download_array <<< "$urls_to_download"
for url in "${urls_to_download_array[@]}"; do for url in "${urls_to_download_array[@]}"; do
filename=$(basename "${url}") filename=$(basename "${url}")
# If it's a .conf file AND it already exists, ask to overwrite. # Handle config file overwrites
if [[ "${filename}" == *.conf && -f "${filename}" ]]; then if [[ "${filename}" == *.conf && -f "${filename}" ]]; then
log "->" "Found existing config file: '${filename}'." if [[ "$force_overwrite" == "true" ]]; then
tmp_file=$(mktemp) echo "[⚠️] Overwriting '${filename}' due to --overwrite-config flag."
if ! curl -fsSL -o "${filename}" "${url}"; then
echo "[❌] Error: Failed to download '${filename}'."
fi
continue
fi
echo "[->] Found existing config file: '${filename}'."
tmp_file=$(mktemp)
if curl -fsSL -o "${tmp_file}" "${url}"; then if curl -fsSL -o "${tmp_file}" "${url}"; then
log "🔎" "Comparing versions..." echo "[🔎] Comparing versions..."
echo "-------------------- DIFF START --------------------" echo "-------------------- DIFF START --------------------"
if command -v colordiff &> /dev/null; then if command -v colordiff &> /dev/null; then
colordiff -u "${filename}" "${tmp_file}" colordiff -u "${filename}" "${tmp_file}"
else else
# Attempt to use diff's color option, which is common.
diff --color=always -u "${filename}" "${tmp_file}" 2>/dev/null || diff -u "${filename}" "${tmp_file}" diff --color=always -u "${filename}" "${tmp_file}" 2>/dev/null || diff -u "${filename}" "${tmp_file}"
fi fi
echo "--------------------- DIFF END ---------------------" echo "--------------------- DIFF END ---------------------"
read -p "Do you want to overwrite '${filename}'? (y/N) " -n 1 -r REPLY read -p "Do you want to overwrite '${filename}'? (y/N) " -n 1 -r REPLY
echo echo
if [[ $REPLY =~ ^[Yy]$ ]]; then if [[ $REPLY =~ ^[Yy]$ ]]; then
mv "${tmp_file}" "${filename}" mv "${tmp_file}" "${filename}"
log "✅" "Updated '${filename}'." echo "[✅] Updated '${filename}'."
else else
rm "${tmp_file}" rm "${tmp_file}"
log "🤷" "Kept existing version of '${filename}'." echo "[🤷] Kept existing version of '${filename}'."
fi fi
else else
log "❌" "Error: Failed to download new version of '${filename}' for comparison." echo "[❌] Error downloading new version of '${filename}' for comparison."
rm -f "${tmp_file}" rm -f "${tmp_file}"
fi fi
else else
# Original download logic for all other files. # Original download logic for all other files.
log "->" "Downloading '${filename}'..." echo "[->] Downloading '${filename}'..."
if curl -fsSL -o "${filename}" "${url}"; then if curl -fsSL -o "${filename}" "${url}"; then
log "✅" "Successfully downloaded '${filename}'." echo "[✅] Successfully downloaded '${filename}'."
if [[ "${filename}" == *.sh || "${filename}" == *.bash ]]; then if [[ "${filename}" == *.sh || "${filename}" == *.bash ]]; then
chmod +x "${filename}" chmod +x "${filename}"
log "🤖" "Made '${filename}' executable." echo "[🤖] Made '${filename}' executable."
fi fi
else else
log "❌" "Error: Failed to download '${filename}'." echo "[❌] Error: Failed to download '${filename}'."
fi fi
fi fi
done done
log "📦" "Package processing complete for '${choice}'." echo "[📦] Package processing complete for '${choice_key}'."
} }
# --- Main Logic --- # --- Main Logic ---
# Generate a unique temporary filename with a timestamp.
conf_file="packages.conf.$(date +%Y%m%d%H%M%S)" conf_file="packages.conf.$(date +%Y%m%d%H%M%S)"
# Set up a trap to delete the temporary file on exit.
trap 'rm -f "${conf_file}"' EXIT trap 'rm -f "${conf_file}"' EXIT
# Download the configuration file. echo "[🔄] Downloading configuration file..."
log "🔄" "Downloading configuration file..."
if ! curl -fsSL -o "${conf_file}" "https://git.technopunk.space/tomi/Scripts/raw/branch/main/packages.conf"; then if ! curl -fsSL -o "${conf_file}" "https://git.technopunk.space/tomi/Scripts/raw/branch/main/packages.conf"; then
log "❌" "Error: Failed to download packages.conf. Exiting." echo "[❌] Error: Failed to download packages.conf. Exiting."
exit 1 exit 1
fi fi
log "✅" "Configuration file downloaded successfully." echo "[✅] Configuration file downloaded successfully."
# Source the configuration file to load the SCRIPT_PACKAGES associative array.
source "${conf_file}" source "${conf_file}"
# --- Update Check & User Interface --- # --- Argument Parsing for Non-Interactive Mode ---
if [ "$#" -gt 0 ]; then
declare -a packages_to_install
overwrite_configs=false
for arg in "$@"; do
case $arg in
--overwrite-config)
overwrite_configs=true
;;
-*)
echo "[❌] Unknown flag: $arg" >&2
exit 1
;;
*)
packages_to_install+=("$arg")
;;
esac
done
# Create an array of options from the package names. if [ ${#packages_to_install[@]} -eq 0 ]; then
# We will modify this array to show installation and update status. echo "[❌] Flag provided with no package names. Exiting."
declare -a options exit 1
package_keys=("${!SCRIPT_PACKAGES[@]}")
log "🔎" "Checking for updates..."
for key in "${package_keys[@]}"; do
# The config format is now "VERSION|URL1 URL2..."
config_value="${SCRIPT_PACKAGES[$key]}"
remote_version=$(echo "${config_value}" | cut -d'|' -f1)
# Get just the URLs and assume the first URL is the main script to check.
urls=$(echo "${config_value}" | cut -d'|' -f2-)
read -r -a url_array <<< "$urls"
main_script_filename=$(basename "${url_array[0]}")
# Get the local version of the main script file.
local_version=$(get_local_version "${main_script_filename}")
status=""
if [[ -f "${main_script_filename}" ]]; then
status=" (Installed: v${local_version})"
# Compare versions
if is_version_greater "$remote_version" "$local_version"; then
status+=" [Update available: v${remote_version}]"
fi
fi fi
options+=("${key}${status}")
done
options+=("Quit") # Add a Quit option to the menu. echo "[🚀] Running in non-interactive mode."
for pkg_key in "${packages_to_install[@]}"; do
if [[ -n "${SCRIPT_PACKAGES[$pkg_key]}" ]]; then
process_package "$pkg_key" "$overwrite_configs"
else
echo "[⚠️] Unknown package: '$pkg_key'. Skipping."
fi
done
echo "[🏁] Non-interactive run complete."
exit 0
fi
# --- User Interaction --- # --- Interactive Mode ---
declare -a ordered_keys
package_keys_sorted=($(for k in "${!SCRIPT_PACKAGES[@]}"; do echo $k; done | sort))
ordered_keys=("${package_keys_sorted[@]}")
# Manually display the options with numbers. # --- Display Menu ---
echo echo
echo "-------------------------------------" echo "-------------------------------------"
echo " Script Downloader " echo " Script Downloader "
echo "-------------------------------------" echo "-------------------------------------"
for i in "${!options[@]}"; do echo "[🔎] Checking for updates..."
printf "%d) %s\n" "$((i+1))" "${options[$i]}"
done
echo echo
# Prompt the user for one or more choices. for i in "${!ordered_keys[@]}"; do
key="${ordered_keys[$i]}"
config_value="${SCRIPT_PACKAGES[$key]}"
display_name=$(echo "${config_value}" | cut -d'|' -f1)
remote_version=$(echo "${config_value}" | cut -d'|' -f2)
description=$(echo "${config_value}" | cut -d'|' -f3)
urls=$(echo "${config_value}" | cut -d'|' -f4-)
read -r -a url_array <<< "$urls"
main_script_filename=$(basename "${url_array[0]}")
local_version=$(get_local_version "${main_script_filename}")
# Print main package line
echo -e "\033[1m$((i+1))) $key - $display_name (v$remote_version)\033[0m"
# Print description
echo " $description"
# Print status
if [[ -f "${main_script_filename}" ]]; then
if is_version_greater "$remote_version" "$local_version"; then
echo -e " \033[33m[Update available: v${local_version} -> v${remote_version}]\033[0m"
else
echo -e " \033[32m[Installed: v${local_version}]\033[0m"
fi
fi
echo
done
quit_num=$((${#ordered_keys[@]} + 1))
echo -e "\033[1m${quit_num}) Quit\033[0m"
echo
# --- Handle User Input ---
read -p "Please enter your choice(s) (e.g., 1 3 4), or press Enter to quit: " -r -a user_choices read -p "Please enter your choice(s) (e.g., 1 3 4), or press Enter to quit: " -r -a user_choices
# If no choices are made, exit gracefully.
if [ ${#user_choices[@]} -eq 0 ]; then if [ ${#user_choices[@]} -eq 0 ]; then
log "👋" "No selection made. Exiting." echo "[👋] No selection made. Exiting."
exit 0 exit 0
fi fi
# Loop through the user's selections and process each one.
for choice_num in "${user_choices[@]}"; do for choice_num in "${user_choices[@]}"; do
# Validate that the input is a number.
if ! [[ "$choice_num" =~ ^[0-9]+$ ]]; then if ! [[ "$choice_num" =~ ^[0-9]+$ ]]; then
log "⚠️" "Skipping invalid input: '${choice_num}'. Not a number." echo "[⚠️] Skipping invalid input: '${choice_num}'. Not a number."
continue continue
fi fi
if [ "$choice_num" -eq "$quit_num" ]; then
# Convert selection number to array index (0-based). echo "[👋] Quit selected. Exiting."
index=$((choice_num - 1))
# Validate that the index is within the bounds of the options array.
if [[ -z "${options[$index]}" ]]; then
log "⚠️" "Skipping invalid choice: '${choice_num}'. Out of range."
continue
fi
# Get the choice text from the array.
choice_with_status="${options[$index]}"
# Strip the status message to get the package key.
choice=$(echo "${choice_with_status}" | sed 's/ (.*//')
# Handle the "Quit" option.
if [[ "${choice}" == "Quit" ]]; then
log "👋" "Quit selected. Exiting now."
exit 0 exit 0
fi fi
index=$((choice_num - 1))
# Process the selected package. if [[ -z "${ordered_keys[$index]}" ]]; then
process_package "${choice}" echo "[⚠️] Skipping invalid choice: '${choice_num}'. Out of range."
continue
fi
choice_key="${ordered_keys[$index]}"
process_package "$choice_key" "false" # Never force overwrite in interactive mode
done done
echo echo
log "🏁" "All selected packages have been processed." echo "[🏁] All selected packages have been processed."

View File

@@ -2,13 +2,13 @@
# --- Company Information --- # --- Company Information ---
# Used to identify which company the alert is for. # Used to identify which company the alert is for.
COMPANY_NAME="Your Company Name" COMPANY_NAME="Company"
# --- Notification Settings --- # --- Notification Settings ---
# Your ntfy.sh topic URL # Your ntfy.sh topic URL
NTFY_TOPIC_URL="https://ntfy.technopunk.space/sap" NTFY_TOPIC_URL="https://ntfy.technopunk.space/sap"
# Your ntfy.sh bearer token (if required) # Your ntfy.sh bearer token (if required)
NTFY_TOKEN="your_ntfy_token_here" NTFY_TOKEN="tk_xxxxx"
# --- HANA Connection Settings --- # --- HANA Connection Settings ---
# Full path to the sapcontrol executable # Full path to the sapcontrol executable
@@ -27,6 +27,8 @@ DISK_USAGE_THRESHOLD=80
TRUNCATED_PERCENTAGE_THRESHOLD=50 TRUNCATED_PERCENTAGE_THRESHOLD=50
# Percentage of 'Free' log segments below which an alert is triggered # Percentage of 'Free' log segments below which an alert is triggered
FREE_PERCENTAGE_THRESHOLD=25 FREE_PERCENTAGE_THRESHOLD=25
# Maximum age of the last successful full data backup in hours.
BACKUP_THRESHOLD_HOURS=25
# --- Monitored Directories --- # --- Monitored Directories ---
# List of directories to check for disk usage (space-separated) # List of directories to check for disk usage (space-separated)

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Version: 1.0.5 # Version: 1.2.0
# ============================================================================= # =============================================================================
# SAP HANA Monitoring Script # SAP HANA Monitoring Script
# #
@@ -28,21 +28,71 @@ if [ ! -f "$CONFIG_FILE" ]; then
fi fi
source "$CONFIG_FILE" source "$CONFIG_FILE"
STATE_DIR="${SCRIPT_DIR}/monitor_state"
mkdir -p "${STATE_DIR}"
# Helper functions for state management
get_state() {
local key="$1"
if [ -f "${STATE_DIR}/${key}.state" ]; then
cat "${STATE_DIR}/${key}.state"
else
echo ""
fi
}
set_state() {
local key="$1"
local value="$2"
echo "$value" > "${STATE_DIR}/${key}.state"
}
HOSTNAME=$(hostname) HOSTNAME=$(hostname)
SQL_QUERY="SELECT b.host, b.service_name, a.state, count(*) FROM PUBLIC.M_LOG_SEGMENTS a JOIN PUBLIC.M_SERVICES b ON (a.host = b.host AND a.port = b.port) GROUP BY b.host, b.service_name, a.state;" SQL_QUERY="SELECT b.host, b.service_name, a.state, count(*) FROM PUBLIC.M_LOG_SEGMENTS a JOIN PUBLIC.M_SERVICES b ON (a.host = b.host AND a.port = b.port) GROUP BY b.host, b.service_name, a.state;"
send_notification() { send_notification_if_changed() {
local title="$1" local alert_key="$1"
local message="$2" local title_prefix="$2" # e.g., "HANA Process"
local full_message="[${COMPANY_NAME} | ${HOSTNAME}] ${message}" local current_message="$3"
curl -H "Authorization: Bearer ${NTFY_TOKEN}" -H "Title: ${title}" -d "${full_message}" "${NTFY_TOPIC_URL}" > /dev/null 2>&1 local is_alert_condition="$4" # "true" or "false"
local current_value="$5" # The value to store as state (e.g., "85%", "GREEN", "ALERT")
local previous_value=$(get_state "${alert_key}")
if [ "$current_value" != "$previous_value" ]; then
local full_title=""
local full_message=""
if [ "$is_alert_condition" == "true" ]; then
full_title="${title_prefix} Alert"
full_message="🚨 Critical: ${current_message}"
else
# Check if it was previously an alert (i.e., previous_value was not "OK")
if [ -n "$previous_value" ] && [ "$previous_value" != "OK" ]; then
full_title="${title_prefix} Resolved"
full_message="✅ Resolved: ${current_message}"
else
# No alert, and no previous alert to resolve, so just update state silently
set_state "${alert_key}" "$current_value"
echo " State for ${alert_key} updated to ${current_value}. No notification sent."
return
fi
fi
local final_message="[${COMPANY_NAME} | ${HOSTNAME}] ${full_message}"
curl -H "Authorization: Bearer ${NTFY_TOKEN}" -H "Title: ${full_title}" -d "${final_message}" "${NTFY_TOPIC_URL}" > /dev/null 2>&1
set_state "${alert_key}" "$current_value"
echo "🔔 Notification sent for ${alert_key}: ${full_message}"
else
echo " State for ${alert_key} unchanged. No notification sent."
fi
} }
# --- HANA Process Status --- # --- HANA Process Status ---
echo "⚙️ Checking HANA process status..." echo "⚙️ Checking HANA process status..."
if [ ! -x "$SAPCONTROL_PATH" ]; then if [ ! -x "$SAPCONTROL_PATH" ]; then
echo "❌ Error: sapcontrol not found or not executable at ${SAPCONTROL_PATH}" >&2 echo "❌ Error: sapcontrol not found or not executable at ${SAPCONTROL_PATH}" >&2
send_notification "HANA Monitor Error" "❌ Error: sapcontrol not found or not executable at ${SAPCONTROL_PATH}" send_notification_if_changed "hana_sapcontrol_path" "HANA Monitor Error" "sapcontrol not found or not executable at ${SAPCONTROL_PATH}" "true" "SAPCONTROL_ERROR"
exit 1 exit 1
fi fi
@@ -51,23 +101,28 @@ non_green_processes=$("${SAPCONTROL_PATH}" -nr "${HANA_INSTANCE_NR}" -function G
if [ -n "$non_green_processes" ]; then if [ -n "$non_green_processes" ]; then
echo "🚨 Alert: One or more HANA processes are not running!" >&2 echo "🚨 Alert: One or more HANA processes are not running!" >&2
echo "$non_green_processes" >&2 echo "$non_green_processes" >&2
send_notification "HANA Process Alert" "🚨 Critical: One or more HANA processes are not GREEN. Problem processes: ${non_green_processes}" send_notification_if_changed "hana_processes" "HANA Process" "One or more HANA processes are not GREEN. Problem processes: ${non_green_processes}" "true" "PROCESS_ALERT:${non_green_processes}"
exit 1 # Exit early as other checks might fail exit 1 # Exit early as other checks might fail
else
send_notification_if_changed "hana_processes" "HANA Process" "All HANA processes are GREEN." "false" "OK"
echo "✅ Success! All HANA processes are GREEN."
fi fi
echo "✅ Success! All HANA processes are GREEN."
# --- Disk Space Monitoring --- # --- Disk Space Monitoring ---
echo " Checking disk usage..." echo " Checking disk usage..."
for dir in "${DIRECTORIES_TO_MONITOR[@]}"; do for dir in "${DIRECTORIES_TO_MONITOR[@]}"; do
if [ ! -d "$dir" ]; then if [ ! -d "$dir" ]; then
echo "⚠️ Warning: Directory '$dir' not found. Skipping." >&2 echo "⚠️ Warning: Directory '$dir' not found. Skipping." >&2
send_notification_if_changed "disk_dir_not_found_${dir//\//_}" "HANA Disk Warning" "Directory '$dir' not found." "true" "DIR_NOT_FOUND"
continue continue
fi fi
usage=$(df -h "$dir" | awk 'NR==2 {print $5}' | sed 's/%//') usage=$(df -h "$dir" | awk 'NR==2 {print $5}' | sed 's/%//')
echo " - ${dir} is at ${usage}%" echo " - ${dir} is at ${usage}%"
if (( $(echo "$usage > $DISK_USAGE_THRESHOLD" | bc -l) )); then if (( $(echo "$usage > $DISK_USAGE_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: ${dir} usage is at ${usage}% which is above the ${DISK_USAGE_THRESHOLD}% threshold." >&2 echo "🚨 Alert: ${dir} usage is at ${usage}% which is above the ${DISK_USAGE_THRESHOLD}% threshold." >&2
send_notification "HANA Disk Alert" "🚨 Critical: Disk usage for ${dir} is at ${usage}%." send_notification_if_changed "disk_usage_${dir//\//_}" "HANA Disk" "Disk usage for ${dir} is at ${usage}%." "true" "${usage}%"
else
send_notification_if_changed "disk_usage_${dir//\//_}" "HANA Disk" "Disk usage for ${dir} is at ${usage}% (below threshold)." "false" "OK"
fi fi
done done
@@ -75,14 +130,14 @@ done
echo "⚙️ Executing HANA SQL query..." echo "⚙️ Executing HANA SQL query..."
if [ ! -x "$HDBSQL_PATH" ]; then if [ ! -x "$HDBSQL_PATH" ]; then
echo "❌ Error: hdbsql not found or not executable at ${HDBSQL_PATH}" >&2 echo "❌ Error: hdbsql not found or not executable at ${HDBSQL_PATH}" >&2
send_notification "HANA Monitor Error" "❌ Error: hdbsql not found or not executable at ${HDBSQL_PATH}" send_notification_if_changed "hana_hdbsql_path" "HANA Monitor Error" "hdbsql not found or not executable at ${HDBSQL_PATH}" "true" "HDBSQL_ERROR"
exit 1 exit 1
fi fi
readarray -t sql_output < <("$HDBSQL_PATH" -U "$HANA_USER_KEY" -c ";" "$SQL_QUERY" 2>&1) readarray -t sql_output < <("$HDBSQL_PATH" -U "$HANA_USER_KEY" -c ";" "$SQL_QUERY" 2>&1)
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "❌ Failure! The hdbsql command failed. Please check logs." >&2 echo "❌ Failure! The hdbsql command failed. Please check logs." >&2
error_message=$(printf '%s\n' "${sql_output[@]}") error_message=$(printf '%s\n' "${sql_output[@]}")
send_notification "HANA Monitor Error" "❌ Failure! The hdbsql command failed. Details: ${error_message}" send_notification_if_changed "hana_hdbsql_command" "HANA Monitor Error" "The hdbsql command failed. Details: ${error_message}" "true" "HDBSQL_COMMAND_FAILED"
exit 1 exit 1
fi fi
@@ -108,19 +163,58 @@ echo " Free Segments: ${free_segments}"
if [ $total_segments -eq 0 ]; then if [ $total_segments -eq 0 ]; then
echo "⚠️ Warning: No log segments found. Skipping percentage checks." >&2 echo "⚠️ Warning: No log segments found. Skipping percentage checks." >&2
send_notification_if_changed "hana_log_segments_total" "HANA Log Segment Warning" "No log segments found. Skipping percentage checks." "true" "NO_LOG_SEGMENTS"
exit 0 exit 0
else
send_notification_if_changed "hana_log_segments_total" "HANA Log Segment" "Log segments found." "false" "OK"
fi fi
truncated_percentage=$((truncated_segments * 100 / total_segments)) truncated_percentage=$((truncated_segments * 100 / total_segments))
if (( $(echo "$truncated_percentage > $TRUNCATED_PERCENTAGE_THRESHOLD" | bc -l) )); then if (( $(echo "$truncated_percentage > $TRUNCATED_PERCENTAGE_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: ${truncated_percentage}% of log segments are 'Truncated'." >&2 echo "🚨 Alert: ${truncated_percentage}% of log segments are 'Truncated'." >&2
send_notification "HANA Log Segment Alert" "🚨 Alert: ${truncated_percentage}% of HANA log segments are in 'Truncated' state." send_notification_if_changed "hana_log_truncated" "HANA Log Segment" "${truncated_percentage}% of HANA log segments are in 'Truncated' state." "true" "${truncated_percentage}%"
else
send_notification_if_changed "hana_log_truncated" "HANA Log Segment" "${truncated_percentage}% of HANA log segments are in 'Truncated' state (below threshold)." "false" "OK"
fi fi
free_percentage=$((free_segments * 100 / total_segments)) free_percentage=$((free_segments * 100 / total_segments))
if (( $(echo "$free_percentage < $FREE_PERCENTAGE_THRESHOLD" | bc -l) )); then if (( $(echo "$free_percentage < $FREE_PERCENTAGE_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: Only ${free_percentage}% of log segments are 'Free'." >&2 echo "🚨 Alert: Only ${free_percentage}% of log segments are 'Free'." >&2
send_notification "HANA Log Segment Alert" "🚨 Alert: Only ${free_percentage}% of HANA log segments are in 'Free' state." send_notification_if_changed "hana_log_free" "HANA Log Segment" "Only ${free_percentage}% of HANA log segments are in 'Free' state." "true" "${free_percentage}%"
else
send_notification_if_changed "hana_log_free" "HANA Log Segment" "Only ${free_percentage}% of HANA log segments are in 'Free' state (above threshold)." "false" "OK"
fi
echo " Checking last successful data backup status..."
# Query to get the start time of the most recent successful complete data backup
last_backup_date=$("$HDBSQL_PATH" -U "$HANA_USER_KEY" -j -a -x \
"SELECT TOP 1 SYS_START_TIME FROM M_BACKUP_CATALOG WHERE ENTRY_TYPE_NAME = 'complete data backup' AND STATE_NAME = 'successful' ORDER BY SYS_START_TIME DESC" 2>/dev/null | tr -d "\"" | sed 's/\..*//') # sed removes fractional seconds
if [[ -z "$last_backup_date" ]]; then
# No successful backup found at all
local message="No successful complete data backup found for ${COMPANY_NAME} HANA."
echo "🚨 Critical: ${message}"
send_notification_if_changed "hana_backup_status" "HANA Backup" "${message}" "true" "NO_BACKUP"
return
fi
# Convert dates to epoch seconds for comparison
last_backup_epoch=$(date -d "$last_backup_date" +%s)
current_epoch=$(date +%s)
threshold_seconds=$((BACKUP_THRESHOLD_HOURS * 3600))
age_seconds=$((current_epoch - last_backup_epoch))
age_hours=$((age_seconds / 3600))
if (( age_seconds > threshold_seconds )); then
local message="Last successful HANA backup for ${COMPANY_NAME} is ${age_hours} hours old, which exceeds the threshold of ${BACKUP_THRESHOLD_HOURS} hours. Last backup was on: ${last_backup_date}."
echo "🚨 Critical: ${message}"
send_notification_if_changed "hana_backup_status" "HANA Backup" "${message}" "true" "${age_hours}h"
else
local message="Last successful backup is ${age_hours} hours old (Threshold: ${BACKUP_THRESHOLD_HOURS} hours)."
echo "✅ Success! ${message}"
send_notification_if_changed "hana_backup_status" "HANA Backup" "${message}" "false" "OK"
fi fi
echo "✅ Success! HANA monitoring check complete." echo "✅ Success! HANA monitoring check complete."

View File

@@ -1,17 +1,16 @@
#!/bin/bash #!/bin/bash
# #
# This file contains the configuration for the script downloader. # This file contains the configuration for the script downloader.
# The `SCRIPT_PACKAGES` associative array maps a package name to a # The `SCRIPT_PACKAGES` associative array maps a short package name
# pipe-separated string: "<version>|<space-separated list of URLs>". # to a pipe-separated string with the following format:
# "<Display Name>|<Version>|<Description>|<Space-separated list of URLs>"
declare -A SCRIPT_PACKAGES declare -A SCRIPT_PACKAGES
# The version should match the "# Version: x.x.x" line in the main script file. # Format: short_name="Display Name|Version|Description|URL1 URL2..."
SCRIPT_PACKAGES["Aurora Suite"]="1.2.6|https://git.technopunk.space/tomi/Scripts/raw/branch/main/aurora/aurora.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/aurora/aurora.conf" SCRIPT_PACKAGES["aurora"]="Aurora Suite|2.1.0|A collection of scripts for managing Aurora database instances.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/aurora/aurora.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/aurora/aurora.conf"
SCRIPT_PACKAGES["Backup Suite"]="1.0.5|https://git.technopunk.space/tomi/Scripts/raw/branch/main/backup/backup.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/backup/backup.conf" SCRIPT_PACKAGES["backup"]="Backup Suite|1.0.5|A comprehensive script for backing up system files and databases.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/backup/backup.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/backup/backup.conf"
SCRIPT_PACKAGES["Monitor Suite"]="1.0.5|https://git.technopunk.space/tomi/Scripts/raw/branch/main/monitor/monitor.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/monitor/monitor.conf" SCRIPT_PACKAGES["monitor"]="Monitor Suite|1.2.0|Scripts for monitoring system health and performance metrics.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/monitor/monitor.sh https://git.technopunk.space/tomi/Scripts/raw/branch/main/monitor/monitor.conf"
SCRIPT_PACKAGES["Key Manager"]="1.2.1|https://git.technopunk.space/tomi/Scripts/raw/branch/main/hdb_keymanager.sh" SCRIPT_PACKAGES["keymanager"]="Key Manager|1.2.1|A utility for managing HDB user keys for SAP HANA.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/keymanager.sh"
SCRIPT_PACKAGES["File Cleaner"]="1.1.0|https://git.technopunk.space/tomi/Scripts/raw/branch/main/clean.sh" SCRIPT_PACKAGES["cleaner"]="File Cleaner|1.1.0|A simple script to clean up temporary files and logs.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/cleaner.sh"
SCRIPT_PACKAGES["HANA Tool"]="1.4.6|https://git.technopunk.space/tomi/Scripts/raw/branch/main/hanatool.sh" SCRIPT_PACKAGES["hanatool"]="HANA Tool|1.5.0|A command-line tool for various SAP HANA administration tasks.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/hanatool.sh"
# Example: Add a new script with its version.
# SCRIPT_PACKAGES["My Other Script"]="1.0.0|https://path/to/my-other-script.sh"