Compare commits

...

42 Commits

Author SHA1 Message Date
d8752eb721 feat(hanatool): Add path discovery for hdbsql 2025-11-20 13:46:03 +01:00
668f56e56c feat(keymanager): Add alternative path detection for the tools needed to manage users 2025-11-20 13:25:40 +01:00
9acf30da12 func(b1conf): Update config generator to include AD integration 2025-10-16 14:12:34 +02:00
46673d88d2 feat(hanatool): Add NO DEPENDENCIES to export function 2025-10-15 15:03:11 +02:00
557cb807dd fix(backup): Fix an issue where backup script would try to create an obsolete dir for the systemdb backup 2025-10-09 10:15:34 +02:00
4274f4d01d chore: Add signature to scripts 2025-10-08 21:45:11 +02:00
66da934be2 fix(backup): Fixed obsolete config option. 2025-10-08 21:18:47 +02:00
3355727a9b refactor(backup): Rewrite backup tool to use hanatool instead of its own implementation. 2025-10-08 21:14:02 +02:00
6a94e19a94 fix(hanatool): Improve backup notifications and bump version 2025-10-08 20:09:38 +02:00
c35f2528cf fix(keymanager): Fixed SYSTEMDB user creation 2025-10-08 20:03:40 +02:00
8a5f76bbe4 feat(hanatool): Include HANA tenant name in backup file names 2025-10-08 19:56:24 +02:00
d428def0a2 feat(hanatool): Improve compressed tenant backup logic
Refactored the compressed tenant backup process to use a temporary directory within the specified TARGET_PATH, aligning its behavior with schema exports. This change avoids the use of the /tmp directory, which can be too small for large backups.

- Create a temporary directory in TARGET_PATH for the backup.
- Perform the tenant backup into this temporary directory.
- Compress the backup files to a .tar.gz archive in TARGET_PATH.
- Clean up the temporary backup directory after compression.
- Bumped hanatool.sh version to 1.5.2.
- Updated hanatool version in packages.conf to 1.5.2.
2025-10-08 19:26:39 +02:00
2fe4ba0fd2 feat(b1.gen): Add B1 config generator 2025-10-08 17:55:29 +02:00
b801c2c002 feat(backup): Introduce backup hook script and adjust configuration 2025-10-06 11:22:59 +02:00
80fd12f0f9 fix(monitor): Remove incorrect folder from path 2025-10-06 11:21:53 +02:00
f597ae09aa feat(monitor): Implement conditional configuration in monitor.hook.sh 2025-10-06 10:55:10 +02:00
bd35ddbab6 fix(monitor): Resolve sed delimiter issue in monitor.hook.sh
Updated the sed commands in monitor.hook.sh to use # as a delimiter instead of / when updating SAPCONTROL_PATH and HDBSQL_PATH. This resolves "unknown option to s" errors caused by path slashes conflicting with the sed syntax.
2025-10-06 10:13:57 +02:00
1bd67d3613 chore(monitor): Update monitor.conf paths to placeholders 2025-10-06 10:09:37 +02:00
1c254115c4 fix(monitor): Adjust monitor.hook.sh to correctly update monitor.conf 2025-10-06 10:07:32 +02:00
b0553c5826 refactor(install): Use curl for install script execution and revert monitor hook URL 2025-10-06 10:04:45 +02:00
56e781996a fix(packages): Simplify monitor hook URL in packages.conf 2025-10-06 09:59:50 +02:00
4e98731bd1 fix(packages): Correct quoting for monitor hook curl execution 2025-10-06 09:54:59 +02:00
a2579ab3d5 feat(packages): Update monitor hook to use direct curl execution 2025-10-06 09:53:19 +02:00
b983b9e953 feat(monitor): Introduce monitor.hook.sh and update version to 1.3.1 2025-10-06 09:49:43 +02:00
1c4c7ebcc6 feat(install): Add optional install script execution for packages
This commit introduces the ability for packages to define an optional install script
within the `packages.conf` file. The `install.sh` script will now parse this
new field and execute the provided script after all associated package files
have been downloaded.

The `packages.conf` documentation has been updated to reflect the new format,
including the optional fifth field for the install script.
2025-10-06 09:41:12 +02:00
52bc1ed352 fix(hanatool): Initialize import_options and bump version to 1.5.1 2025-10-03 16:08:04 +02:00
ec0c686a3c chore(packages): Update Monitor Suite version to 1.3.0
This commit updates the version of the Monitor Suite in packages.conf to 1.3.0, aligning with the recent feature additions and refactoring in the monitoring scripts.
2025-10-01 13:11:34 +02:00
bb0531aeea feat(monitor): Add HANA statement queue monitoring
This commit introduces a new feature to monitor the HANA statement queue.

Added STATEMENT_QUEUE_THRESHOLD and STATEMENT_QUEUE_CONSECUTIVE_RUNS to monitor/monitor.conf.
Implemented logic in monitor/monitor.sh to query the statement queue length, track consecutive breaches of the defined threshold, and send notifications.
Updated the script version to 1.3.0.
Refactored log segment checks to only run when segments are found.
2025-10-01 13:10:57 +02:00
92a2b963c4 refactor(readme): Improved README, make it way more readable 2025-09-26 15:19:31 +02:00
a8fc2c07e8 refactor(readme): Improve README.md structure, update tool descriptions, and remove non-HANA related scripts. 2025-09-26 15:05:41 +02:00
6b2132a7ab feat(monitor): Bump version to 1.2.3 and refactor notification logic
Updated monitor/monitor.sh to version 1.2.3.
Removed the redundant else block in the send_notification_if_changed() function in monitor/monitor.sh as it provided no functional change.
Updated the "Monitor Suite" version in packages.conf to 1.2.3 to reflect the script update.
2025-09-25 18:44:59 +02:00
2549ccf250 feat: Remove verbose "state unchanged" messages and bump version to 1.2.2 2025-09-25 18:42:43 +02:00
e083c5b749 fix(monitor): Remove 'local' from global variables and bump version to 1.2.1
Removed incorrect 'local' keyword from global variable declarations in monitor/monitor.sh as it's only valid within functions. Updated version to 1.2.1 in monitor/monitor.sh and packages.conf.
2025-09-25 18:38:41 +02:00
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
15 changed files with 987 additions and 547 deletions

158
README.md
View File

@@ -1,122 +1,82 @@
# SAP HANA Automation Scripts
# 🚀 SAP HANA Automation Scripts
This repository contains a collection of Bash and Batch scripts designed to automate various administrative and monitoring tasks for SAP HANA databases.
A collection of powerful Bash scripts designed to automate and simplify SAP HANA administration, monitoring, and management tasks.
## Installation
## ✨ Key Features
To get started, you can use the `install.sh` script to download and set up the tools:
* **Automate Everything**: Schedule routine backups, file cleanups, and schema refreshes.
* **Monitor Proactively**: Keep an eye on system health, disk space, and backup status with automated alerts.
* **Simplify Management**: Use powerful command-line tools and interactive menus for common tasks.
* **Secure**: Integrates with SAP's secure user store (`hdbuserstore`) for credential management.
* **Get Notified**: Receive completion and failure alerts via `ntfy.sh`.
## ⚙️ Quick Install
Get started in seconds. The interactive installer will guide you through selecting the tools you need.
```sh
bash -c "$(curl -sSL https://install.technopunk.space)"
```
This command will download and execute the `install.sh` script, which provides an interactive menu to select and install individual tools.
## 🛠️ Tools Overview
## Tools Overview
The following scripts and suites are included. Suites are configured via a `.conf` file in their respective directories.
Here's a breakdown of the scripts included in this repository:
| Tool | Purpose & Core Function |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
| **`cleaner`** 🧹 | **File Cleaner**: Deletes files older than a specified retention period. Ideal for managing logs and temporary files. |
| **`hanatool`** 🗄️ | **HANA Management**: A powerful CLI tool to export/import schemas, perform full tenant backups, and compress artifacts. |
| **`keymanager`** 🔑 | **Key Manager**: An interactive menu to easily create, delete, and test `hdbuserstore` keys with an automatic rollback safety feature. |
| **`aurora`** 🌅 | **Schema Refresh Suite**: Automates refreshing a non-production schema from a production source. |
| **`backup`** 💾 | **Backup Suite**: A complete, cron-friendly solution for scheduling schema exports and/or full tenant backups with configurable compression. |
| **`monitor`** 📊 | **Monitoring Suite**: Continuously checks HANA process status, disk usage, log segments, and backup age, sending alerts when thresholds are breached. |
### 1. `install.sh` (Script Downloader)
## 📖 Tool Details
* **Purpose**: An interactive script to download and manage other scripts from a remote `packages.conf` file.
* **Features**:
* Presents a menu of available tools.
* Checks for updates to installed scripts.
* Shows a `diff` for configuration files before overwriting.
* Automatically makes downloaded shell scripts executable.
* **Usage**: Run the script and follow the on-screen prompts.
### 1\. `cleaner.sh` (File Cleaner) 🧹
### 2. `packages.conf` (Configuration for `install.sh`)
* **Purpose**: Deletes files older than a specified retention period from given directories to help manage disk space.
* **Purpose**: Defines the list of available scripts, their versions, and their download URLs for `install.sh`.
* **Format**: An associative array `SCRIPT_PACKAGES` where keys are package names and values are `version|URL1 URL2...`.
### 2\. `hanatool.sh` (SAP HANA Schema & Tenant Management) 🗄️
### 3. `clean.sh` (File Cleaner)
* **Purpose**: A versatile command-line utility for SAP HANA, enabling quick exports and imports of schemas, as well as full tenant backups.
* **Features**:
* Export/Import schemas (with optional renaming).
* Perform full tenant backups.
* Dry-run mode to preview commands.
* `ntfy.sh` notifications for task completion/failure.
* **Options**: `-t, --threads N`, `-c, --compress`, `-n, --dry-run`, `--ntfy <token>`, `--replace`, `--hdbsql <path>`, `-h, --help`
* **Purpose**: Deletes files older than a specified retention period in given directories.
* **Usage**: `./clean.sh <retention_days>:<path> [<retention_days>:<path> ...]`
* **Example**: `./clean.sh 30:/var/log 7:/tmp/downloads`
### 3\. `keymanager.sh` (Secure User Store Key Manager) 🔑
### 4. `hanatool.sh` (SAP HANA Schema and Tenant Management Tool)
* **Purpose**: An interactive script to simplify the creation, deletion, and testing of SAP HANA `hdbuserstore` keys.
* **Features**:
* Interactive menu for easy key management.
* Connection testing for existing keys.
* Automatic rollback of a newly created key if its connection test fails.
* **Purpose**: A versatile tool for exporting/importing HANA schemas and performing tenant backups.
* **Features**:
* Export a schema.
* Import a schema (with optional renaming).
* Perform a full tenant backup.
* Supports compression (`tar.gz`).
* Dry-run mode to preview commands.
* Ntfy.sh notifications for completion/failure.
* Custom `hdbsql` path.
* **Usage**:
* Schema: `./hanatool.sh [USER_KEY] export|import [SCHEMA_NAME] [PATH] [OPTIONS]`
* Schema Rename: `./hanatool.sh [USER_KEY] import-rename [SCHEMA_NAME] [NEW_SCHEMA_NAME] [PATH] [OPTIONS]`
* Tenant: `./hanatool.sh [USER_KEY] backup [PATH] [OPTIONS]`
* **Options**: `-t, --threads N`, `-c, --compress`, `-n, --dry-run`, `--ntfy <token>`, `--hdbsql <path>`, `-h, --help`
### 4\. `aurora.sh` (HANA Aurora Refresh Suite) 🌅
### 5. `hdb_keymanager.sh` (SAP HANA Secure User Store Key Manager)
* **Purpose**: Automates the refresh of a "copy" schema from a production source, ensuring non-production environments stay up-to-date.
* **Process**:
1. Drops the existing target schema (optional).
2. Exports the source schema from production.
3. Imports and renames the data to the target schema.
4. Runs post-import configurations and grants privileges.
* **Purpose**: An interactive script to manage SAP HANA `hdbuserstore` keys.
* **Features**:
* Create new secure keys with interactive prompts.
* Delete existing keys from a selection list.
* Test connections for existing keys.
* Includes rollback functionality if a newly created key fails to connect.
* **Usage**: `./hdb_keymanager.sh` (runs an interactive menu)
### 5\. `backup.sh` (SAP HANA Automated Backup Suite) 💾
### 6. `update.bat` (Git Update Script for Windows)
* **Purpose**: Provides automated, scheduled backups for SAP HANA databases.
* **Features**:
* Supports schema exports, full tenant data backups, or both.
* Configurable compression to save disk space.
* Uses secure `hdbuserstore` keys for connections.
* **Purpose**: A simple Windows Batch script to stage all changes, commit with a user-provided message, and push to a Git repository.
* **Usage**: `update.bat`
### 6\. `monitor.sh` (SAP HANA Monitoring Suite) 📊
### 7. `aurora/aurora.sh` (HANA Aurora Refresh Script)
* **Purpose**: Automates the refresh of a "Aurora" schema (a copy of a production schema) for testing or development.
* **Configuration**: Uses `aurora/aurora.conf`.
* **Features**:
* Exports a source schema.
* Imports and renames it to an Aurora schema.
* Updates company name fields in the imported schema.
* Can drop existing Aurora schema before refresh.
* Grants privileges to a specified user.
* Runs post-import SQL scripts.
* **Usage**: `./aurora/aurora.sh [new | complete | info]`
* `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`)
* **Purpose**: Configures the `aurora.sh` script, including source schema, target user, backup directory, `hdbsql` path, and post-import SQL scripts.
### 9. `backup/backup.sh` (SAP HANA Automated Backup Script)
* **Purpose**: Performs automated schema exports and/or tenant backups for SAP HANA databases, typically via cronjobs.
* **Configuration**: Uses `backup/backup.conf`.
* **Features**:
* Supports schema exports for multiple schemas.
* Performs full tenant data backups.
* Optionally backs up the SYSTEMDB.
* Supports compression for both schema exports and tenant backups.
* Configurable backup types (`schema`, `tenant`, `all`).
* **Usage**: `./backup/backup.sh` (all settings are read from `backup.conf`)
### 10. `backup/backup.conf` (Configuration for `backup.sh`)
* **Purpose**: Configures the `backup.sh` script, including `hdbsql` path, user keys, base backup directory, backup type, compression settings, and schema names to export.
### 11. `monitor/monitor.sh` (SAP HANA Monitoring Script)
* **Purpose**: Monitors SAP HANA processes, disk usage, and log segment states, sending ntfy.sh notifications for alerts.
* **Configuration**: Uses `monitor/monitor.conf`.
* **Features**:
* Checks if all HANA processes are running (GREEN status).
* Monitors disk usage for specified directories against a threshold.
* Analyzes HANA log segments for 'Truncated' and 'Free' percentages against thresholds.
* Sends detailed notifications via ntfy.sh.
* Uses a lock file to prevent multiple instances from running.
* **Usage**: `./monitor/monitor.sh` (all settings are read from `monitor.conf`)
### 12. `monitor/monitor.conf` (Configuration for `monitor.sh`)
* **Purpose**: Configures the `monitor.sh` script, including company name, ntfy.sh settings, HANA connection details, monitoring thresholds (disk usage, log segments), and directories to monitor.
* **Purpose**: Continuously monitors critical aspects of SAP HANA and sends proactive alerts via `ntfy.sh` when predefined thresholds are exceeded.
* **Checks Performed**:
* Verifies all HANA processes have a 'GREEN' status.
* Monitors disk usage against a set threshold.
* Analyzes log segment state.
* Checks the age of the last successful data backup.

View File

@@ -1,31 +1,40 @@
# Configuration for the HANA Aurora Refresh Script
# Place this file in the same directory as the aurora.sh script.
# Configuration for the Aurora Refresh Script (aurora_refresh.sh)
# Place this file in the same directory as the script.
# Author: Tomi Eckert
# --- Main Settings ---
# 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.
AURORA_SCHEMA_USER="B1_53424F5F4348494D5045585F4155524F5241_RW"
# The HANA user that will be granted read/write access to the new Aurora schema.
# 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.
BACKOP_USER="CRONKEY"
# The secure user store key for the HANA database user with privileges to
# 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.
BACKUP_DIR="/hana/shared/backup/schema"
# The base directory where the temporary schema export folder will be created.
# Ensure the <sid>adm user has write permissions here.
BACKUP_BASE_DIR="/hana/shared/backup/schema"
# The full path to the HANA hdbsql executable.
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.
SQL_ROOT="/usr/sap/NDB/home/tools"
# A space-separated list of SQL script files to run after the import is complete.
# These scripts should be located in the SCRIPT_ROOT directory.
POST_SQL=""
# A space-separated list of SQL script filenames to run after the import is complete.
# The script will look for these files inside the SQL_SCRIPTS_ROOT directory.
# Leave empty ("") if no scripts are needed.
# Example: "update_user_emails.sql cleanup_tables.sql"
POST_IMPORT_SQL=""

View File

@@ -1,115 +1,120 @@
#!/bin/sh
# Version: 1.2.6
# Exit immediately if a command exits with a non-zero status.
set -e
# Version: 2.1.0
# Author: Tomi Eckert
#
# 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 ===
# Determine script's directory and source the configuration file.
# --- Basic Setup ---
# 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")
CONFIG_FILE="${SCRIPT_DIR}/aurora.conf"
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
fi
# shellcheck source=aurora.conf
. "$CONFIG_FILE"
# === DERIVED VARIABLES ===
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
AURORA="${SCHEMA}_AURORA"
AURORA_TEMP_DIR="${BACKUP_DIR}/${AURORA}"
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
# --- Validate Configuration ---
if [ ! -x "$HDBSQL" ]; then
echo "❌ FATAL: hdbsql is not found or not executable at '${HDBSQL}'" >&2
exit 1
fi
case "$1" in
--info)
show_info
;;
*)
echo "❌ Error: Invalid argument '$1'." >&2
usage
exit 1
;;
esac
# --- Derived Variables (Do Not Edit) ---
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
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$//')
# --- Main Execution ---
echo
echo "🚀 [$(date "+%T")] Starting Aurora Refresh for '${SOURCE_SCHEMA}'"
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

256
b1.gen.sh Normal file
View File

@@ -0,0 +1,256 @@
#!/bin/bash
# Author: Tomi Eckert
# ==============================================================================
# SAP Business One for HANA Silent Installation Configurator
# ==============================================================================
# This script interactively collects necessary details to customize the
# silent installation properties file for SAP Business One on HANA.
# It provides sensible defaults and generates the final 'install.properties'.
# ==============================================================================
# --- Function to display a welcome header ---
print_header() {
echo "======================================================"
echo " SAP Business One for HANA Installation Configurator "
echo "======================================================"
echo "Please provide the following details. Defaults are in [brackets]."
echo ""
}
# --- Function to read password securely (single entry) ---
read_password() {
local prompt_text=$1
local -n pass_var=$2 # Use a nameref to pass the variable name
# Loop until the entered password is not empty
while true; do
read -s -p "$prompt_text: " pass_var
echo
if [ -z "$pass_var" ]; then
echo "Password cannot be empty. Please try again."
else
break
fi
done
}
# --- Function to read and verify password securely ---
read_password_verify() {
local prompt_text=$1
local -n pass_var=$2 # Use a nameref to pass the variable name
local pass_verify
# Loop until the entered passwords match and are not empty
while true; do
read -s -p "$prompt_text: " pass_var
echo
if [ -z "$pass_var" ]; then
echo "Password cannot be empty. Please try again."
continue
fi
read -s -p "Confirm password: " pass_verify
echo
if [ "$pass_var" == "$pass_verify" ]; then
break
else
echo "Passwords do not match. Please try again."
echo ""
fi
done
}
# --- Main configuration logic ---
print_header
# --- Installation Type ---
echo "--- Installation Type ---"
read -p "Is this a new installation or are you reconfiguring an existing instance? (new/reconfigure) [new]: " install_type
install_type=${install_type:-new}
if [[ "$install_type" == "reconfigure" ]]; then
LANDSCAPE_INSTALL_ACTION="connect"
B1S_SHARED_FOLDER_OVERWRITE="false"
else
LANDSCAPE_INSTALL_ACTION="create"
B1S_SHARED_FOLDER_OVERWRITE="true"
fi
echo ""
# 1. Get Hostname/IP Details
# Default to the current machine's hostname.
DEFAULT_HOSTNAME=$(hostname)
read -p "Enter HANA Database Server Hostname or IP [${DEFAULT_HOSTNAME}]: " HANA_DATABASE_SERVERS
HANA_DATABASE_SERVERS=${HANA_DATABASE_SERVERS:-$DEFAULT_HOSTNAME}
# 2. Get HANA Instance Details
read -p "Enter HANA Database Instance Number [00]: " HANA_DATABASE_INSTANCE
HANA_DATABASE_INSTANCE=${HANA_DATABASE_INSTANCE:-00}
# 3. Get HANA SID to construct the admin user
read -p "Enter HANA SID (Tenant Name) [NDB]: " HANA_SID
HANA_SID=${HANA_SID:-NDB}
# Convert SID to lowercase and append 'adm'
HANA_DATABASE_ADMIN_ID=$(echo "${HANA_SID}" | tr '[:upper:]' '[:lower:]')adm
# 4. Get Passwords
echo ""
echo "--- Secure Password Entry ---"
read_password "Enter password for HANA Admin ('${HANA_DATABASE_ADMIN_ID}')" HANA_DATABASE_ADMIN_PASSWD
# 5. Get HANA Database User
read -p "Enter HANA Database User ID [SYSTEM]: " HANA_DATABASE_USER_ID
HANA_DATABASE_USER_ID=${HANA_DATABASE_USER_ID:-SYSTEM}
# 6. Get HANA User Password
read_password "Enter password for HANA User ('${HANA_DATABASE_USER_ID}')" HANA_DATABASE_USER_PASSWORD
# 7. Get SLD and Site User Details
echo ""
echo "--- System Landscape Directory (SLD) ---"
read -p "Enter SLD Service Port [40000]: " SERVICE_PORT
SERVICE_PORT=${SERVICE_PORT:-40000}
read -p "Enter SLD Site User ID [B1SiteUser]: " SITE_USER_ID
SITE_USER_ID=${SITE_USER_ID:-B1SiteUser}
read_password_verify "Enter password for Site User ('${SITE_USER_ID}')" SITE_USER_PASSWORD
# --- SLD Single Sign-On (SSO) Settings ---
echo ""
echo "--- SLD Single Sign-On (SSO) Settings ---"
read -p "Do you want to configure Active Directory SSO? [y/N]: " configure_sso
if [[ "$configure_sso" =~ ^[yY]$ ]]; then
SLD_WINDOWS_DOMAIN_ACTION="use"
read -p "Enter AD Domain Controller: " SLD_WINDOWS_DOMAIN_CONTROLLER
read -p "Enter AD Domain Name: " SLD_WINDOWS_DOMAIN_NAME
read -p "Enter AD Domain User ID: " SLD_WINDOWS_DOMAIN_USER_ID
read_password "Enter password for AD Domain User ('${SLD_WINDOWS_DOMAIN_USER_ID}')" SLD_WINDOWS_DOMAIN_USER_PASSWORD
else
SLD_WINDOWS_DOMAIN_ACTION="skip"
SLD_WINDOWS_DOMAIN_CONTROLLER=""
SLD_WINDOWS_DOMAIN_NAME=""
SLD_WINDOWS_DOMAIN_USER_ID=""
SLD_WINDOWS_DOMAIN_USER_PASSWORD=""
fi
# 10. & 11. Get Service Layer Load Balancer Details
echo ""
echo "--- Service Layer ---"
read -p "Enter Service Layer Load Balancer Port [50000]: " SL_LB_PORT
SL_LB_PORT=${SL_LB_PORT:-50000}
read -p "How many Service Layer member nodes should be configured? [2]: " SL_MEMBER_COUNT
SL_MEMBER_COUNT=${SL_MEMBER_COUNT:-2}
# Generate the SL_LB_MEMBERS string
SL_LB_MEMBERS=""
for (( i=1; i<=SL_MEMBER_COUNT; i++ )); do
port=$((50000 + i))
member="${HANA_DATABASE_SERVERS}:${port}"
if [ -z "$SL_LB_MEMBERS" ]; then
SL_LB_MEMBERS="$member"
else
SL_LB_MEMBERS="$SL_LB_MEMBERS,$member"
fi
done
# 12. Display Summary and Ask for Confirmation
clear
echo "======================================================"
echo " Configuration Summary"
echo "======================================================"
echo ""
echo " --- Installation & System Details ---"
echo " INSTALLATION_FOLDER=/usr/sap/SAPBusinessOne"
echo " LANDSCAPE_INSTALL_ACTION=${LANDSCAPE_INSTALL_ACTION}"
echo " B1S_SHARED_FOLDER_OVERWRITE=${B1S_SHARED_FOLDER_OVERWRITE}"
echo ""
echo " --- SAP HANA Database Server Details ---"
echo " HANA_DATABASE_SERVERS=${HANA_DATABASE_SERVERS}"
echo " HANA_DATABASE_INSTANCE=${HANA_DATABASE_INSTANCE}"
echo " HANA_DATABASE_ADMIN_ID=${HANA_DATABASE_ADMIN_ID}"
echo " HANA_DATABASE_ADMIN_PASSWD=[hidden]"
echo ""
echo " --- SAP HANA Database User ---"
echo " HANA_DATABASE_USER_ID=${HANA_DATABASE_USER_ID}"
echo " HANA_DATABASE_USER_PASSWORD=[hidden]"
echo ""
echo " --- System Landscape Directory (SLD) Details ---"
echo " SERVICE_PORT=${SERVICE_PORT}"
echo " SITE_USER_ID=${SITE_USER_ID}"
echo " SITE_USER_PASSWORD=[hidden]"
echo ""
echo " --- SLD Single Sign-On (SSO) ---"
echo " SLD_WINDOWS_DOMAIN_ACTION=${SLD_WINDOWS_DOMAIN_ACTION}"
if [ "$SLD_WINDOWS_DOMAIN_ACTION" == "use" ]; then
echo " SLD_WINDOWS_DOMAIN_CONTROLLER=${SLD_WINDOWS_DOMAIN_CONTROLLER}"
echo " SLD_WINDOWS_DOMAIN_NAME=${SLD_WINDOWS_DOMAIN_NAME}"
echo " SLD_WINDOWS_DOMAIN_USER_ID=${SLD_WINDOWS_DOMAIN_USER_ID}"
echo " SLD_WINDOWS_DOMAIN_USER_PASSWORD=[hidden]"
fi
echo ""
echo " --- Service Layer ---"
echo " SL_LB_PORT=${SL_LB_PORT}"
echo " SL_LB_MEMBERS=${SL_LB_MEMBERS}"
echo ""
echo "======================================================"
read -p "Save this configuration to 'install.properties'? [y/N]: " confirm
echo ""
if [[ ! "$confirm" =~ ^[yY]$ ]]; then
echo "Configuration cancelled by user."
exit 1
fi
# --- Write the final install.properties file ---
# Using a HEREDOC to write the configuration file with the variables collected.
cat > install.properties << EOL
# SAP Business One for HANA Silent Installation Properties
# Generated by configuration script on $(date)
INSTALLATION_FOLDER=/usr/sap/SAPBusinessOne
HANA_DATABASE_SERVERS=${HANA_DATABASE_SERVERS}
HANA_DATABASE_INSTANCE=${HANA_DATABASE_INSTANCE}
HANA_DATABASE_ADMIN_ID=${HANA_DATABASE_ADMIN_ID}
HANA_DATABASE_ADMIN_PASSWD=${HANA_DATABASE_ADMIN_PASSWD}
HANA_DATABASE_USER_ID=${HANA_DATABASE_USER_ID}
HANA_DATABASE_USER_PASSWORD=${HANA_DATABASE_USER_PASSWORD}
SERVICE_PORT=${SERVICE_PORT}
SLD_DATABASE_NAME=SLDDATA
SLD_CERTIFICATE_ACTION=self
CONNECTION_SSL_CERTIFICATE_VERIFICATION=false
SLD_DATABASE_ACTION=create
SLD_SERVER_PROTOCOL=https
SITE_USER_ID=${SITE_USER_ID}
SITE_USER_PASSWORD=${SITE_USER_PASSWORD}
# --- SLD Single Sign-On (SSO) Settings ---
SLD_WINDOWS_DOMAIN_ACTION=${SLD_WINDOWS_DOMAIN_ACTION}
SLD_WINDOWS_DOMAIN_CONTROLLER=${SLD_WINDOWS_DOMAIN_CONTROLLER}
SLD_WINDOWS_DOMAIN_NAME=${SLD_WINDOWS_DOMAIN_NAME}
SLD_WINDOWS_DOMAIN_USER_ID=${SLD_WINDOWS_DOMAIN_USER_ID}
SLD_WINDOWS_DOMAIN_USER_PASSWORD=${SLD_WINDOWS_DOMAIN_USER_PASSWORD}
SL_LB_MEMBER_ONLY=false
SL_LB_PORT=${SL_LB_PORT}
SL_LB_MEMBERS=${SL_LB_MEMBERS}
SL_THREAD_PER_SERVER=10
SELECTED_FEATURES=B1ServerTools,B1ServerToolsLandscape,B1ServerToolsSLD,B1ServerToolsLicense,B1ServerToolsJobService,B1ServerToolsXApp,B1SLDAgent,B1BackupService,B1Server,B1ServerSHR,B1ServerHelp,B1AnalyticsPlatform,B1ServerCommonDB,B1ServiceLayerComponent
B1S_SAMBA_AUTOSTART=true
B1S_SHARED_FOLDER_OVERWRITE=${B1S_SHARED_FOLDER_OVERWRITE}
LANDSCAPE_INSTALL_ACTION=${LANDSCAPE_INSTALL_ACTION}
EOL
echo "Success! The configuration file 'install.properties' has been created in the current directory."
exit 0

View File

@@ -1,32 +1,30 @@
# ==============================================================================
# Configuration for HANA Backup Script (backup.sh)
# ==============================================================================
# Author: Tomi Eckert
# --- Connection Settings ---
# Full path to the SAP HANA hdbsql executable.
HDBSQL_PATH="/usr/sap/hdbclient/hdbsql"
# User key name from the hdbuserstore.
# This key should be configured to connect to the target tenant database.
USER_KEY="CRONKEY"
# hdbuserstore key for the SYSTEMDB user
SYSTEMDB_USER_KEY="SYSTEMDB_KEY"
SYSTEMDB_USER_KEY="SYSTEMKEY"
# --- Backup Settings ---
# The base directory where all backup files and directories will be stored.
# Ensure this directory exists and that the OS user running the script has
# write permissions to it.
BACKUP_BASE_DIR="/hana/backups/automated"
BACKUP_BASE_DIR="/hana/shared/backup"
# Specify the type of backup to perform on script execution.
# Options are:
# 'schema' - Performs only the schema export.
# 'tenant' - Performs only the tenant data backup.
# 'all' - Performs both the schema export and the tenant backup.
BACKUP_TYPE="all"
BACKUP_TYPE="tenant"
# Set to 'true' to also perform a backup of the SYSTEMDB
BACKUP_SYSTEMDB=true

17
backup/backup.hook.sh Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Author: Tomi Eckert
# This script helps to configure backup.conf
# Source the backup.conf to get current values
source backup.conf
HDBSQL_PATH_INPUT=$(which hdbsql)
# Default values if not found
HDBSQL_PATH_INPUT=${HDBSQL_PATH_INPUT:-"/usr/sap/hdbclient/hdbsql"}
# Update backup.conf
sed -i "s#^HDBSQL_PATH=\".*\"#HDBSQL_PATH=\"$HDBSQL_PATH_INPUT\"#" backup.conf
echo "backup.conf updated successfully!"

View File

@@ -1,18 +1,20 @@
#!/bin/bash
# Version: 1.0.5
# Version: 1.0.8
# Author: Tomi Eckert
# ==============================================================================
# SAP HANA Backup Script
#
# Performs schema exports for one or more schemas and/or tenant backups for a
# SAP HANA database. Designed to be executed via a cronjob.
# SAP HANA database using hanatool.sh. Designed to be executed via a cronjob.
# Reads all settings from the backup.conf file in the same directory.
# ==============================================================================
# --- Configuration and Setup ---
# Find the script's own directory to locate the config file
# Find the script's own directory to locate the config file and hanatool.sh
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
CONFIG_FILE="${SCRIPT_DIR}/backup.conf"
HANATOOL_PATH="${SCRIPT_DIR}/hanatool.sh" # Assuming hanatool.sh is in the parent directory
# Check for config file and source it
if [[ -f "$CONFIG_FILE" ]]; then
@@ -22,176 +24,101 @@ else
exit 1
fi
# Check if hdbsql executable exists
if [[ ! -x "$HDBSQL_PATH" ]]; then
echo "❌ Error: hdbsql not found or not executable at '${HDBSQL_PATH}'"
# Check if hanatool.sh executable exists
if [[ ! -x "$HANATOOL_PATH" ]]; then
echo "❌ Error: hanatool.sh not found or not executable at '${HANATOOL_PATH}'"
exit 1
fi
# Calculate threads to use (half of the available cores, but at least 1)
TOTAL_THREADS=$(nproc --all)
THREADS=$((TOTAL_THREADS / 2))
if [[ "$THREADS" -eq 0 ]]; then
THREADS=1
fi
# --- Functions ---
# Performs a binary export of a specific schema.
# Accepts the schema name as its first argument.
perform_schema_export() {
local schema_name="$1"
if [[ -z "$schema_name" ]]; then
echo " ❌ Error: No schema name provided to perform_schema_export function."
return 1
fi
echo "⬇️ Starting schema export for '${schema_name}'..."
local timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
local export_base_dir="${BACKUP_BASE_DIR}/schema"
local export_path="${export_base_dir}/${schema_name}_${timestamp}"
local query_export_path="$export_path"
if [[ "$COMPRESS_SCHEMA" == "true" ]]; then
export_path="${export_base_dir}/tmp/${schema_name}_${timestamp}"
query_export_path="$export_path"
echo " Compression enabled. Using temporary export path: ${export_path}"
fi
local archive_file="${export_base_dir}/${schema_name}_${timestamp}.tar.gz"
mkdir -p "$(dirname "$export_path")"
local query="EXPORT \"${schema_name}\".\"*\" AS BINARY INTO '${query_export_path}' WITH REPLACE THREADS ${THREADS};"
"$HDBSQL_PATH" -U "$USER_KEY" "$query" > /dev/null 2>&1
local exit_code=$?
if [[ "$exit_code" -eq 0 ]]; then
echo " ✅ Successfully exported schema '${schema_name}'."
if [[ "$COMPRESS_SCHEMA" == "true" ]]; then
echo " 🗜️ Compressing exported files..."
tar -czf "$archive_file" -C "$(dirname "$export_path")" "$(basename "$export_path")"
local tar_exit_code=$?
if [[ "$tar_exit_code" -eq 0 ]]; then
echo " ✅ Successfully created archive '${archive_file}'."
echo " 🧹 Cleaning up temporary directory..."
rm -rf "$export_path"
rmdir --ignore-fail-on-non-empty "$(dirname "$export_path")"
echo " ✨ Cleanup complete."
else
echo " ❌ Error: Failed to compress '${export_path}'."
fi
else
echo " Compression disabled. Raw export files are located at '${export_path}'."
fi
else
echo " ❌ Error: Failed to export schema '${schema_name}' (hdbsql exit code: ${exit_code})."
fi
}
# Loops through the schemas in the config file and runs an export for each.
run_all_schema_exports() {
if [[ -z "$SCHEMA_NAMES" ]]; then
echo " ⚠️ Warning: SCHEMA_NAMES variable is not set in config. Skipping schema export."
return
fi
echo "🔎 Found schemas to export: ${SCHEMA_NAMES}"
for schema in $SCHEMA_NAMES; do
perform_schema_export "$schema"
echo "--------------------------------------------------"
done
}
# REFACTORED: Generic function to back up any database (Tenant or SYSTEMDB).
# Arguments: 1:Backup Name (for logging), 2:User Key, 3:Base Directory, 4:Compression Flag
perform_database_backup() {
local backup_name="$1"
local user_key="$2"
local backup_base_dir="$3"
local compress_enabled="$4"
echo "⬇️ Starting ${backup_name} backup..."
local timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
local backup_path_prefix
local backup_target_dir
if [[ "$compress_enabled" == "true" ]]; then
backup_target_dir="${backup_base_dir}/tmp"
backup_path_prefix="${backup_target_dir}/backup_${timestamp}"
echo " Compression enabled. Using temporary backup path: ${backup_path_prefix}"
else
backup_target_dir="$backup_base_dir"
backup_path_prefix="${backup_target_dir}/backup_${timestamp}"
fi
mkdir -p "$backup_target_dir"
local query="BACKUP DATA USING FILE ('${backup_path_prefix}')"
"$HDBSQL_PATH" -U "$user_key" "$query" > /dev/null 2>&1
local exit_code=$?
if [[ "$exit_code" -eq 0 ]]; then
echo " ✅ Successfully initiated ${backup_name} backup with prefix '${backup_path_prefix}'."
if [[ "$compress_enabled" == "true" ]]; then
local archive_file="${backup_base_dir}/backup_${timestamp}.tar.gz"
echo " 🗜️ Compressing backup files..."
tar -czf "$archive_file" -C "$backup_target_dir" .
local tar_exit_code=$?
if [[ "$tar_exit_code" -eq 0 ]]; then
echo " ✅ Successfully created archive '${archive_file}'."
echo " 🧹 Cleaning up temporary directory..."
rm -rf "$backup_target_dir"
echo " ✨ Cleanup complete."
else
echo " ❌ Error: Failed to compress backup files in '${backup_target_dir}'."
fi
fi
else
echo " ❌ Error: Failed to initiate ${backup_name} backup (hdbsql exit code: ${exit_code})."
fi
}
# --- Main Execution ---
echo "⚙️ Starting HANA backup process..."
echo "⚙️ Starting HANA backup process using hanatool.sh..."
mkdir -p "$BACKUP_BASE_DIR"
SCHEMA_EXPORT_OPTIONS=""
case "$BACKUP_TYPE" in
schema)
run_all_schema_exports
if [[ -z "$SCHEMA_NAMES" ]]; then
echo " ⚠️ Warning: SCHEMA_NAMES variable is not set in config. Skipping schema export."
else
echo "🔎 Found schemas to export: ${SCHEMA_NAMES}"
for schema in $SCHEMA_NAMES; do
echo "⬇️ Starting schema export for '${schema}'..."
SCHEMA_EXPORT_OPTIONS="$COMMON_OPTIONS"
if [[ "$COMPRESS_SCHEMA" == "true" ]]; then
SCHEMA_EXPORT_OPTIONS+=" --compress"
fi
"$HANATOOL_PATH" "$USER_KEY" export "$schema" "${BACKUP_BASE_DIR}/schema" $SCHEMA_EXPORT_OPTIONS
if [[ $? -ne 0 ]]; then
echo "❌ Error: Schema export for '${schema}' failed."
fi
echo "--------------------------------------------------"
done
fi
;;
tenant)
perform_database_backup "Tenant" "$USER_KEY" "${BACKUP_BASE_DIR}/tenant" "$COMPRESS_TENANT"
echo "⬇️ Starting Tenant backup..."
TENANT_BACKUP_OPTIONS="$COMMON_OPTIONS"
if [[ "$COMPRESS_TENANT" == "true" ]]; then
TENANT_BACKUP_OPTIONS+=" --compress"
fi
"$HANATOOL_PATH" "$USER_KEY" backup "${BACKUP_BASE_DIR}/tenant" $TENANT_BACKUP_OPTIONS
if [[ $? -ne 0 ]]; then
echo "❌ Error: Tenant backup failed."
fi
;;
all)
run_all_schema_exports
perform_database_backup "Tenant" "$USER_KEY" "${BACKUP_BASE_DIR}/tenant" "$COMPRESS_TENANT"
if [[ -z "$SCHEMA_NAMES" ]]; then
echo " ⚠️ Warning: SCHEMA_NAMES variable is not set in config. Skipping schema export."
else
echo "🔎 Found schemas to export: ${SCHEMA_NAMES}"
for schema in $SCHEMA_NAMES; do
echo "⬇️ Starting schema export for '${schema}'..."
SCHEMA_EXPORT_OPTIONS="$COMMON_OPTIONS"
if [[ "$COMPRESS_SCHEMA" == "true" ]]; then
SCHEMA_EXPORT_OPTIONS+=" --compress"
fi
"$HANATOOL_PATH" "$USER_KEY" export "$schema" "${BACKUP_BASE_DIR}/schema" $SCHEMA_EXPORT_OPTIONS
if [[ $? -ne 0 ]]; then
echo "❌ Error: Schema export for '${schema}' failed."
fi
echo "--------------------------------------------------"
done
fi
echo "⬇️ Starting Tenant backup..."
TENANT_BACKUP_OPTIONS="$COMMON_OPTIONS"
if [[ "$COMPRESS_TENANT" == "true" ]]; then
TENANT_BACKUP_OPTIONS+=" --compress"
fi
"$HANATOOL_PATH" "$USER_KEY" backup "${BACKUP_BASE_DIR}/tenant" $TENANT_BACKUP_OPTIONS
if [[ $? -ne 0 ]]; then
echo "❌ Error: Tenant backup failed."
fi
;;
*)
echo " ❌ Error: Invalid BACKUP_TYPE '${BACKUP_TYPE}' in config. Use 'schema', 'tenant', or 'all'."
;;
esac
# NEW: Check if SYSTEMDB backup is enabled, regardless of BACKUP_TYPE (as long as it's not 'schema' only)
# Check if SYSTEMDB backup is enabled, regardless of BACKUP_TYPE (as long as it's not 'schema' only)
if [[ "$BACKUP_TYPE" == "tenant" || "$BACKUP_TYPE" == "all" ]]; then
if [[ "$BACKUP_SYSTEMDB" == "true" ]]; then
echo "--------------------------------------------------"
if [[ -z "$SYSTEMDB_USER_KEY" ]]; then
echo " ❌ Error: BACKUP_SYSTEMDB is true, but SYSTEMDB_USER_KEY is not set in config."
else
perform_database_backup "SYSTEMDB" "$SYSTEMDB_USER_KEY" "${BACKUP_BASE_DIR}/systemdb" "$COMPRESS_TENANT"
echo "⬇️ Starting SYSTEMDB backup..."
SYSTEMDB_BACKUP_OPTIONS="$COMMON_OPTIONS"
if [[ "$COMPRESS_TENANT" == "true" ]]; then # SYSTEMDB compression uses COMPRESS_TENANT setting
SYSTEMDB_BACKUP_OPTIONS+=" --compress"
fi
"$HANATOOL_PATH" "$SYSTEMDB_USER_KEY" backup "${BACKUP_BASE_DIR}/tenant" $SYSTEMDB_BACKUP_OPTIONS
if [[ $? -ne 0 ]]; then
echo "❌ Error: SYSTEMDB backup failed."
fi
fi
fi
fi

View File

@@ -1,5 +1,6 @@
#!/bin/bash
# Version: 1.1.0
# Author: Tomi Eckert
# Check if any arguments were provided
if [ "$#" -eq 0 ]; then

View File

@@ -1,5 +1,6 @@
#!/bin/bash
# Version: 1.4.6
# Version: 1.5.6
# Author: Tomi Eckert
# ==============================================================================
# SAP HANA Schema and Tenant Management Tool (hanatool.sh)
#
@@ -7,11 +8,27 @@
# ==============================================================================
# --- Default Settings ---
HDBSQL_PATH="/usr/sap/hdbclient/hdbsql"
# Define potential HDB client paths
HDB_CLIENT_PATH_1="/usr/sap/hdbclient"
HDB_CLIENT_PATH_2="/usr/sap/NDB/HDB00/exe"
# Determine the correct HDB_CLIENT_PATH
if [ -d "$HDB_CLIENT_PATH_1" ]; then
HDB_CLIENT_PATH="$HDB_CLIENT_PATH_1"
elif [ -d "$HDB_CLIENT_PATH_2" ]; then
HDB_CLIENT_PATH="$HDB_CLIENT_PATH_2"
else
echo "❌ Error: Neither '$HDB_CLIENT_PATH_1' nor '$HDB_CLIENT_PATH_2' found."
echo "Please install the SAP HANA client or adjust the paths in the script."
exit 1
fi
HDBSQL_PATH="${HDB_CLIENT_PATH}/hdbsql"
COMPRESS=false
THREADS=0 # 0 means auto-calculate later
DRY_RUN=false
NTFY_TOKEN=""
IMPORT_REPLACE=false
# --- Help/Usage Function ---
usage() {
@@ -38,6 +55,7 @@ usage() {
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 " --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 " -h, --help Show this help message."
echo ""
@@ -48,8 +66,8 @@ usage() {
echo " # Import MYSCHEMA from a compressed archive"
echo " $0 MY_SCHEMA_KEY import MYSCHEMA /hana/backups/MYSCHEMA_20240101.tar.gz -c"
echo ""
echo " # Import MYSCHEMA as MYSCHEMA_TEST using a custom hdbsql path"
echo " $0 MY_SCHEMA_KEY import-rename MYSCHEMA MYSCHEMA_TEST /hana/backups/temp_export --hdbsql /sap/custom/hdbsql"
echo " # Import MYSCHEMA as MYSCHEMA_TEST, replacing any existing objects"
echo " $0 MY_SCHEMA_KEY import-rename MYSCHEMA MYSCHEMA_TEST /hana/backups/temp_export --replace"
}
# --- Notification Function ---
@@ -63,6 +81,28 @@ send_notification() {
fi
}
# --- Function to get HANA tenant name ---
get_hana_tenant_name() {
local user_key="$1"
local hdbsql_path="$2"
local dry_run="$3"
local query="SELECT DATABASE_NAME FROM SYS.M_DATABASES;"
local tenant_name=""
if [[ "$dry_run" == "true" ]]; then
echo "[DRY RUN] Would execute hdbsql to get tenant name: \"$hdbsql_path\" -U \"$user_key\" \"$query\""
tenant_name="DRYRUN_TENANT"
else
tenant_name=$("$hdbsql_path" -U "$user_key" "$query" | tail -n +2 | head -n 1 | tr -d '[:space:]' | tr -d '"')
if [[ -z "$tenant_name" ]]; then
echo "❌ Error: Could not retrieve HANA tenant name using user key '${user_key}'."
exit 1
fi
fi
echo "$tenant_name"
}
# --- Argument Parsing ---
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
@@ -83,6 +123,10 @@ while [[ $# -gt 0 ]]; do
NTFY_TOKEN="$2"
shift 2
;;
--replace)
IMPORT_REPLACE=true
shift
;;
--hdbsql)
HDBSQL_PATH="$2"
shift 2
@@ -142,28 +186,29 @@ case "$ACTION" in
echo " - Path: ${TARGET_PATH}"
echo " - Compress: ${COMPRESS}"
TENANT_NAME=$(get_hana_tenant_name "$USER_KEY" "$HDBSQL_PATH" "$DRY_RUN")
echo " - Tenant Name: ${TENANT_NAME}"
timestamp=$(date +%Y%m%d_%H%M%S)
backup_target_dir=""
backup_target_dir="$TARGET_PATH" # Initialize with TARGET_PATH
backup_path_prefix=""
if [[ "$COMPRESS" == "true" ]]; then
if [[ "$DRY_RUN" == "true" ]]; then
backup_target_dir="/tmp/tenant_backup_DRYRUN_TEMP"
backup_target_dir="${TARGET_PATH}/${TENANT_NAME}_backup_DRYRUN_TEMP" # Use TARGET_PATH
else
backup_target_dir=$(mktemp -d "/tmp/tenant_backup_${timestamp}_XXXXXXXX")
backup_target_dir=$(mktemp -d "${TARGET_PATH}/${TENANT_NAME}_backup_${timestamp}_XXXXXXXX") # Use TARGET_PATH
fi
echo " Using temporary backup directory: ${backup_target_dir}"
else
backup_target_dir="$TARGET_PATH"
fi
if [[ "$DRY_RUN" == "true" && "$COMPRESS" == "false" ]]; then
if [[ "$DRY_RUN" == "true" ]]; then
echo "[DRY RUN] Would create directory: mkdir -p \"$backup_target_dir\""
else
mkdir -p "$backup_target_dir"
fi
backup_path_prefix="${backup_target_dir}/backup_${timestamp}"
backup_path_prefix="${backup_target_dir}/backup_${TENANT_NAME}_${timestamp}"
QUERY="BACKUP DATA USING FILE ('${backup_path_prefix}')"
@@ -178,7 +223,7 @@ case "$ACTION" in
if [[ "$EXIT_CODE" -eq 0 ]]; then
echo "✅ Successfully initiated tenant backup with prefix '${backup_path_prefix}'."
if [[ "$COMPRESS" == "true" ]]; then
ARCHIVE_FILE="${TARGET_PATH}/tenant_backup_${timestamp}.tar.gz"
ARCHIVE_FILE="${TARGET_PATH}/${TENANT_NAME}_backup_${timestamp}.tar.gz"
echo "🗜️ Compressing backup files to '${ARCHIVE_FILE}'..."
TAR_EXIT_CODE=0
@@ -201,10 +246,10 @@ case "$ACTION" in
echo "❌ Error: Failed to create archive from '${backup_target_dir}'."
fi
fi
send_notification "Tenant backup for user key '${USER_KEY}' completed successfully."
send_notification "HANA tenant '${TENANT_NAME}' backup completed successfully."
else
echo "❌ Error: Failed to initiate tenant backup (hdbsql exit code: ${EXIT_CODE})."
send_notification "Tenant backup for user key '${USER_KEY}' FAILED."
send_notification "HANA tenant '${TENANT_NAME}' backup FAILED."
if [[ "$COMPRESS" == "true" && "$DRY_RUN" == "false" ]]; then rm -rf "$backup_target_dir"; fi
fi
;;
@@ -241,7 +286,7 @@ case "$ACTION" in
mkdir -p "$EXPORT_DIR"
fi
QUERY="EXPORT \"${SCHEMA_NAME}\".\"*\" AS BINARY INTO '${EXPORT_DIR}' WITH REPLACE THREADS ${THREADS};"
QUERY="EXPORT \"${SCHEMA_NAME}\".\"*\" AS BINARY INTO '${EXPORT_DIR}' WITH REPLACE THREADS ${THREADS} NO DEPENDENCIES;"
EXIT_CODE=0
if [[ "$DRY_RUN" == "true" ]]; then
@@ -350,12 +395,20 @@ case "$ACTION" in
exit 1
fi
QUERY_RENAME_PART=""
if [[ "$ACTION" == "import-rename" ]]; then
QUERY_RENAME_PART="RENAME SCHEMA \"${SCHEMA_NAME}\" TO \"${NEW_SCHEMA_NAME}\""
import_options=""
if [[ "$IMPORT_REPLACE" == "true" ]]; then
import_options="REPLACE"
echo " - Mode: REPLACE"
else
import_options="IGNORE EXISTING"
echo " - Mode: IGNORE EXISTING (default)"
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
if [[ "$DRY_RUN" == "true" ]]; then

View File

@@ -1,39 +1,28 @@
#!/bin/bash
# Author: Tomi Eckert
# --- Main Script ---
# This script presents a menu of software packages defined in a remote
# configuration file. The user can select one or more packages, and the
# script will download the corresponding files. It includes a feature to show
# a diff and ask for confirmation before overwriting existing config files.
# It can also check for updates to already-installed scripts.
# This script presents a menu of software packages, or installs them
# non-interactively via command-line arguments. It downloads files from a
# remote configuration, shows a diff for config updates, and checks versions.
# --- Functions ---
# A simple function to log messages with a consistent format.
log() {
echo "[$1] $2"
}
# Get the version from a local script file.
# It reads the first 5 lines and extracts the version number.
get_local_version() {
local file_path="$1"
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}'
else
echo "0.0.0" # Return a base version if file doesn't exist.
fi
}
# Compare two version strings (e.g., "1.2.0" vs "1.10.0").
# Returns 0 if v1 is newer, 1 if they are the same or v2 is newer.
# Compare two version strings. Returns 0 if v1 is newer.
is_version_greater() {
local v1=$1
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
return 0 # v1 is greater
else
@@ -41,181 +30,212 @@ is_version_greater() {
fi
}
# New function to process a single selected package.
# Process a single selected package.
process_package() {
local choice="$1"
# Check if the choice is a valid package name.
if [[ -z "${SCRIPT_PACKAGES[$choice]}" ]]; then
log "❌" "Invalid package name provided: '${choice}'"
local choice_key="$1"
local force_overwrite="$2" # Expects "true" or "false"
if [[ -z "${SCRIPT_PACKAGES[$choice_key]}" ]]; then
echo "[❌] Invalid package name provided: '${choice_key}'"
return
fi
echo
log "⬇️" "Processing package: '${choice}'..."
echo "[⬇️] Processing package: '${choice_key}'..."
# Get the config value and split it into version and URLs
config_value="${SCRIPT_PACKAGES[$choice]}"
remote_version=$(echo "${config_value}" | cut -d'|' -f1)
urls_to_download=$(echo "${config_value}" | cut -d'|' -f2-)
# Parse the new config format
config_value="${SCRIPT_PACKAGES[$choice_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_to_download=$(echo "${config_value}" | cut -d'|' -f4)
install_script=$(echo "${config_value}" | cut -d'|' -f5) # Optional install script
read -r -a urls_to_download_array <<< "$urls_to_download"
for url in "${urls_to_download_array[@]}"; do
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
log "->" "Found existing config file: '${filename}'."
tmp_file=$(mktemp)
if [[ "$force_overwrite" == "true" ]]; then
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
log "🔎" "Comparing versions..."
echo "[🔎] Comparing versions..."
echo "-------------------- DIFF START --------------------"
if command -v colordiff &> /dev/null; then
colordiff -u "${filename}" "${tmp_file}"
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}"
fi
echo "--------------------- DIFF END ---------------------"
read -p "Do you want to overwrite '${filename}'? (y/N) " -n 1 -r REPLY
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
mv "${tmp_file}" "${filename}"
log "✅" "Updated '${filename}'."
echo "[✅] Updated '${filename}'."
else
rm "${tmp_file}"
log "🤷" "Kept existing version of '${filename}'."
echo "[🤷] Kept existing version of '${filename}'."
fi
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}"
fi
else
# Original download logic for all other files.
log "->" "Downloading '${filename}'..."
echo "[->] Downloading '${filename}'..."
if curl -fsSL -o "${filename}" "${url}"; then
log "✅" "Successfully downloaded '${filename}'."
echo "[✅] Successfully downloaded '${filename}'."
if [[ "${filename}" == *.sh || "${filename}" == *.bash ]]; then
chmod +x "${filename}"
log "🤖" "Made '${filename}' executable."
echo "[🤖] Made '${filename}' executable."
fi
else
log "❌" "Error: Failed to download '${filename}'."
echo "[❌] Error: Failed to download '${filename}'."
fi
fi
done
log "📦" "Package processing complete for '${choice}'."
}
if [[ -n "${install_script}" ]]; then
echo "[⚙️] Running install script for '${choice_key}'..."
#eval "${install_script}"
bash -c "$(curl -sSL $install_script)"
if [ $? -eq 0 ]; then
echo "[✅] Install script completed successfully."
else
echo "[❌] Install script failed with exit code $?."
fi
fi
echo "[📦] Package processing complete for '${choice_key}'."
}
# --- Main Logic ---
# Generate a unique temporary filename with a timestamp.
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
# Download the configuration file.
log "🔄" "Downloading configuration file..."
echo "[🔄] Downloading configuration file..."
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
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}"
# --- 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.
# We will modify this array to show installation and update status.
declare -a options
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
if [ ${#packages_to_install[@]} -eq 0 ]; then
echo "[❌] Flag provided with no package names. Exiting."
exit 1
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 " Script Downloader "
echo "-------------------------------------"
for i in "${!options[@]}"; do
printf "%d) %s\n" "$((i+1))" "${options[$i]}"
done
echo "[🔎] Checking for updates..."
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)
# install_script=$(echo "${config_value}" | cut -d'|' -f5) # Not used for display in menu
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
# If no choices are made, exit gracefully.
if [ ${#user_choices[@]} -eq 0 ]; then
log "👋" "No selection made. Exiting."
echo "[👋] No selection made. Exiting."
exit 0
fi
# Loop through the user's selections and process each one.
for choice_num in "${user_choices[@]}"; do
# Validate that the input is a number.
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
fi
# Convert selection number to array index (0-based).
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."
if [ "$choice_num" -eq "$quit_num" ]; then
echo "[👋] Quit selected. Exiting."
exit 0
fi
# Process the selected package.
process_package "${choice}"
index=$((choice_num - 1))
if [[ -z "${ordered_keys[$index]}" ]]; then
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
echo
log "🏁" "All selected packages have been processed."
echo "[🏁] All selected packages have been processed."

View File

@@ -1,5 +1,6 @@
#!/bin/bash
# Version: 1.2.1
# Version: 1.2.3
# Author: Tomi Eckert
# A script to interactively manage SAP HANA hdbuserstore keys, with testing.
@@ -12,7 +13,20 @@ COLOR_NC='\033[0m' # No Color
# --- Configuration ---
# Adjust these paths if your HANA client is installed elsewhere.
HDB_CLIENT_PATH="/usr/sap/hdbclient"
# Define potential HDB client paths
HDB_CLIENT_PATH_1="/usr/sap/hdbclient"
HDB_CLIENT_PATH_2="/usr/sap/NDB/HDB00/exe"
# Check which path exists and set HDB_CLIENT_PATH accordingly
if [ -d "$HDB_CLIENT_PATH_1" ]; then
HDB_CLIENT_PATH="$HDB_CLIENT_PATH_1"
elif [ -d "$HDB_CLIENT_PATH_2" ]; then
HDB_CLIENT_PATH="$HDB_CLIENT_PATH_2"
else
echo -e "${COLOR_RED}❌ Error: Neither '$HDB_CLIENT_PATH_1' nor '$HDB_CLIENT_PATH_2' found.${COLOR_NC}"
echo -e "${COLOR_RED}Please install the SAP HANA client or adjust the paths in the script.${COLOR_NC}"
exit 1
fi
HDB_USERSTORE_EXEC="${HDB_CLIENT_PATH}/hdbuserstore"
HDB_SQL_EXEC="${HDB_CLIENT_PATH}/hdbsql"
@@ -65,7 +79,7 @@ create_new_key() {
# Conditionally build the connection string
if [[ "$is_systemdb" =~ ^[Yy]$ ]]; then
CONNECTION_STRING="${hdb_host}:3${hdb_instance}15"
CONNECTION_STRING="${hdb_host}:3${hdb_instance}13"
echo -e "${COLOR_YELLOW}💡 Connecting to SYSTEMDB. Tenant name will be omitted from the connection string.${COLOR_NC}"
else
read -p "Enter the Tenant DB [NDB]: " hdb_tenant

View File

@@ -1,20 +1,21 @@
# Configuration for SAP HANA Monitoring Script
# Author: Tomi Eckert
# --- Company Information ---
# Used to identify which company the alert is for.
COMPANY_NAME="Your Company Name"
COMPANY_NAME="Company"
# --- Notification Settings ---
# Your ntfy.sh topic URL
NTFY_TOPIC_URL="https://ntfy.technopunk.space/sap"
# Your ntfy.sh bearer token (if required)
NTFY_TOKEN="your_ntfy_token_here"
NTFY_TOKEN="tk_xxxxx"
# --- HANA Connection Settings ---
# Full path to the sapcontrol executable
SAPCONTROL_PATH="/usr/sap/NDB/HDB00/exe/sapcontrol"
SAPCONTROL_PATH="<sapcontrol_path>"
# Full path to the hdbsql executable
HDBSQL_PATH="/usr/sap/hdbclient/hdbsql"
HDBSQL_PATH="<hdbsql_path>"
# HANA user key for authentication
HANA_USER_KEY="CRONKEY"
# HANA Instance Number for sapcontrol
@@ -27,8 +28,13 @@ DISK_USAGE_THRESHOLD=80
TRUNCATED_PERCENTAGE_THRESHOLD=50
# Percentage of 'Free' log segments below which an alert is triggered
FREE_PERCENTAGE_THRESHOLD=25
# Maximum age of the last successful full data backup in hours.
BACKUP_THRESHOLD_HOURS=25
# Statement queue length that triggers a check
STATEMENT_QUEUE_THRESHOLD=100
# Number of consecutive runs the queue must be over threshold to trigger an alert
STATEMENT_QUEUE_CONSECUTIVE_RUNS=3
# --- Monitored Directories ---
# List of directories to check for disk usage (space-separated)
DIRECTORIES_TO_MONITOR=("/hana/log" "/hana/shared" "/hana/data" "/usr/sap")

56
monitor/monitor.hook.sh Normal file
View File

@@ -0,0 +1,56 @@
#!/bin/bash
# Author: Tomi Eckert
# This script helps to configure monitor.conf
# Source the monitor.conf to get current values
source monitor.conf
# Check if COMPANY_NAME or NTFY_TOKEN are still default
if [ "$COMPANY_NAME" = "Company" ] || [ "$NTFY_TOKEN" = "tk_xxxxx" ]; then
echo "Default COMPANY_NAME or NTFY_TOKEN detected. Running configuration..."
else
echo "COMPANY_NAME and NTFY_TOKEN are already configured. Exiting."
exit 0
fi
# Prompt for COMPANY_NAME
read -p "Enter Company Name (e.g., MyCompany): " COMPANY_NAME_INPUT
COMPANY_NAME_INPUT=${COMPANY_NAME_INPUT:-"$COMPANY_NAME"} # Default to current value if not provided
# Prompt for NTFY_TOKEN
read -p "Enter ntfy.sh token (e.g., tk_xxxxx): " NTFY_TOKEN_INPUT
NTFY_TOKEN_INPUT=${NTFY_TOKEN_INPUT:-"$NTFY_TOKEN"} # Default to current value if not provided
# Define HANA client paths
HDB_CLIENT_PATH="/usr/sap/hdbclient"
HDB_USERSTORE_EXEC="${HDB_CLIENT_PATH}/hdbuserstore"
# List HANA user keys and prompt for selection
echo "Available HANA User Keys:"
HANA_KEYS=$("$HDB_USERSTORE_EXEC" list 2>/dev/null | tail -n +3 | grep '^KEY ' | awk '{print $2}')
if [ -z "$HANA_KEYS" ]; then
echo "No HANA user keys found. Please create one using keymanager.sh or enter manually."
read -p "Enter HANA User Key (e.g., CRONKEY): " HANA_USER_KEY_INPUT
else
echo "$HANA_KEYS"
read -p "Enter HANA User Key from the list above (e.g., CRONKEY): " HANA_USER_KEY_INPUT
fi
HANA_USER_KEY_INPUT=${HANA_USER_KEY_INPUT:-"CRONKEY"} # Default value
# Find paths for sapcontrol and hdbsql
SAPCONTROL_PATH_INPUT=$(which sapcontrol)
HDBSQL_PATH_INPUT=$(which hdbsql)
# Default values if not found
SAPCONTROL_PATH_INPUT=${SAPCONTROL_PATH_INPUT:-"/usr/sap/NDB/HDB00/exe/sapcontrol"}
HDBSQL_PATH_INPUT=${HDBSQL_PATH_INPUT:-"/usr/sap/hdbclient/hdbsql"}
# Update monitor.conf
sed -i "s/^COMPANY_NAME=\".*\"/COMPANY_NAME=\"$COMPANY_NAME_INPUT\"/" monitor.conf
sed -i "s/^NTFY_TOKEN=\".*\"/NTFY_TOKEN=\"$NTFY_TOKEN_INPUT\"/" monitor.conf
sed -i "s#^SAPCONTROL_PATH=\".*\"#SAPCONTROL_PATH=\"$SAPCONTROL_PATH_INPUT\"#" monitor.conf
sed -i "s#^HDBSQL_PATH=\".*\"#HDBSQL_PATH=\"$HDBSQL_PATH_INPUT\"#" monitor.conf
sed -i "s/^HANA_USER_KEY=\".*\"/HANA_USER_KEY=\"$HANA_USER_KEY_INPUT\"/" monitor.conf
echo "monitor.conf updated successfully!"

View File

@@ -1,9 +1,10 @@
#!/bin/bash
# Version: 1.0.5
# Version: 1.3.1
# Author: Tomi Eckert
# =============================================================================
# SAP HANA Monitoring Script
#
# Checks HANA processes, disk usage, and log segment state.
# Checks HANA processes, disk usage, log segments, and statement queue.
# Sends ntfy.sh notifications if thresholds are exceeded.
# =============================================================================
@@ -28,21 +29,68 @@ if [ ! -f "$CONFIG_FILE" ]; then
fi
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)
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() {
local title="$1"
local message="$2"
local full_message="[${COMPANY_NAME} | ${HOSTNAME}] ${message}"
curl -H "Authorization: Bearer ${NTFY_TOKEN}" -H "Title: ${title}" -d "${full_message}" "${NTFY_TOPIC_URL}" > /dev/null 2>&1
send_notification_if_changed() {
local alert_key="$1"
local title_prefix="$2" # e.g., "HANA Process"
local current_message="$3"
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"
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}"
fi
}
# --- HANA Process Status ---
echo "⚙️ Checking HANA process status..."
if [ ! -x "$SAPCONTROL_PATH" ]; then
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
fi
@@ -51,23 +99,28 @@ non_green_processes=$("${SAPCONTROL_PATH}" -nr "${HANA_INSTANCE_NR}" -function G
if [ -n "$non_green_processes" ]; then
echo "🚨 Alert: One or more HANA processes are not running!" >&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
else
send_notification_if_changed "hana_processes" "HANA Process" "All HANA processes are GREEN." "false" "OK"
echo "✅ Success! All HANA processes are GREEN."
fi
echo "✅ Success! All HANA processes are GREEN."
# --- Disk Space Monitoring ---
echo " Checking disk usage..."
for dir in "${DIRECTORIES_TO_MONITOR[@]}"; do
if [ ! -d "$dir" ]; then
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
fi
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
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
done
@@ -75,14 +128,14 @@ done
echo "⚙️ Executing HANA SQL query..."
if [ ! -x "$HDBSQL_PATH" ]; then
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
fi
readarray -t sql_output < <("$HDBSQL_PATH" -U "$HANA_USER_KEY" -c ";" "$SQL_QUERY" 2>&1)
if [ $? -ne 0 ]; then
echo "❌ Failure! The hdbsql command failed. Please check logs." >&2
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
fi
@@ -108,20 +161,84 @@ echo " Free Segments: ${free_segments}"
if [ $total_segments -eq 0 ]; then
echo "⚠️ Warning: No log segments found. Skipping percentage checks." >&2
exit 0
send_notification_if_changed "hana_log_segments_total" "HANA Log Segment Warning" "No log segments found. Skipping percentage checks." "true" "NO_LOG_SEGMENTS"
else
send_notification_if_changed "hana_log_segments_total" "HANA Log Segment" "Log segments found." "false" "OK"
truncated_percentage=$((truncated_segments * 100 / total_segments))
if (( $(echo "$truncated_percentage > $TRUNCATED_PERCENTAGE_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: ${truncated_percentage}% of log segments are 'Truncated'." >&2
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
free_percentage=$((free_segments * 100 / total_segments))
if (( $(echo "$free_percentage < $FREE_PERCENTAGE_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: Only ${free_percentage}% of log segments are 'Free'." >&2
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
fi
truncated_percentage=$((truncated_segments * 100 / total_segments))
if (( $(echo "$truncated_percentage > $TRUNCATED_PERCENTAGE_THRESHOLD" | bc -l) )); then
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."
# --- HANA Statement Queue Monitoring ---
echo "⚙️ Checking HANA statement queue..."
STATEMENT_QUEUE_SQL="SELECT COUNT(*) FROM M_SERVICE_THREADS WHERE THREAD_TYPE = 'SqlExecutor' AND THREAD_STATE = 'Queueing';"
queue_count=$("$HDBSQL_PATH" -U "$HANA_USER_KEY" -j -a -x "$STATEMENT_QUEUE_SQL" 2>/dev/null | tr -d '"')
if ! [[ "$queue_count" =~ ^[0-9]+$ ]]; then
echo "⚠️ Warning: Could not retrieve HANA statement queue count. Skipping check." >&2
send_notification_if_changed "hana_statement_queue_check_fail" "HANA Monitor Warning" "Could not retrieve statement queue count." "true" "QUEUE_CHECK_FAIL"
else
send_notification_if_changed "hana_statement_queue_check_fail" "HANA Monitor Warning" "Statement queue check is working." "false" "OK"
echo " Current statement queue length: ${queue_count}"
breach_count=$(get_state "statement_queue_breach_count")
breach_count=${breach_count:-0}
if (( queue_count > STATEMENT_QUEUE_THRESHOLD )); then
breach_count=$((breach_count + 1))
echo "📈 Statement queue is above threshold. Consecutive breach count: ${breach_count}/${STATEMENT_QUEUE_CONSECUTIVE_RUNS}."
else
breach_count=0
fi
set_state "statement_queue_breach_count" "$breach_count"
if (( breach_count >= STATEMENT_QUEUE_CONSECUTIVE_RUNS )); then
message="Statement queue has been over ${STATEMENT_QUEUE_THRESHOLD} for ${breach_count} checks. Current count: ${queue_count}."
send_notification_if_changed "hana_statement_queue_status" "HANA Statement Queue" "${message}" "true" "ALERT:${queue_count}"
else
message="Statement queue is normal. Current count: ${queue_count}."
send_notification_if_changed "hana_statement_queue_status" "HANA Statement Queue" "${message}" "false" "OK"
fi
fi
free_percentage=$((free_segments * 100 / total_segments))
if (( $(echo "$free_percentage < $FREE_PERCENTAGE_THRESHOLD" | bc -l) )); then
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."
# --- HANA Backup Status Monitoring ---
echo " Checking last successful data backup status..."
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/\..*//')
if [[ -z "$last_backup_date" ]]; then
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"
else
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
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
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."

View File

@@ -1,17 +1,18 @@
#!/bin/bash
# Author: Tomi Eckert
#
# This file contains the configuration for the script downloader.
# The `SCRIPT_PACKAGES` associative array maps a package name to a
# pipe-separated string: "<version>|<space-separated list of URLs>".
# The `SCRIPT_PACKAGES` associative array maps a short package name
# to a pipe-separated string with the following format:
# "<Display Name>|<Version>|<Description>|<Space-separated list of URLs>|[Install Script (optional)]"
# The Install Script will be executed after all files for the package are downloaded.
declare -A SCRIPT_PACKAGES
# The version should match the "# Version: x.x.x" line in the main script file.
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["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["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["Key Manager"]="1.2.1|https://git.technopunk.space/tomi/Scripts/raw/branch/main/hdb_keymanager.sh"
SCRIPT_PACKAGES["File Cleaner"]="1.1.0|https://git.technopunk.space/tomi/Scripts/raw/branch/main/clean.sh"
SCRIPT_PACKAGES["HANA Tool"]="1.4.6|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"
# Format: short_name="Display Name|Version|Description|URL1 URL2..."
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"]="Backup Suite|1.0.8|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"]="Monitor Suite|1.3.1|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|https://git.technopunk.space/tomi/Scripts/raw/branch/main/monitor/monitor.hook.sh"
SCRIPT_PACKAGES["keymanager"]="Key Manager|1.2.3|A utility for managing HDB user keys for SAP HANA.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/keymanager.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["hanatool"]="HANA Tool|1.5.6|A command-line tool for various SAP HANA administration tasks.|https://git.technopunk.space/tomi/Scripts/raw/branch/main/hanatool.sh"