Compare commits

...

2 Commits

Author SHA1 Message Date
09fd3b2c67 more little fixes 2025-10-28 12:21:11 -04:00
6c1f8c926e HP/UX fixes 2025-10-28 11:02:06 -04:00
7 changed files with 286 additions and 96 deletions

172
README.md Normal file
View File

@@ -0,0 +1,172 @@
# Rubrik Oracle Backup Scripts for HP-UX
This collection of Korn shell (ksh) scripts provides automated backup solutions for Oracle databases using Rubrik Managed Volumes (MVs) on HP-UX systems. The scripts are designed to be HP-UX compatible and handle RMAN backups with incremental merge functionality.
## Prerequisites
- **Operating System**: HP-UX 11i or later (also works on Linux/Solaris/AIX)
- **Shell**: Korn shell (ksh) - standard on HP-UX
- **Tools**: curl, awk, egrep, date, expr, mkdir, hostname, ps, find, chmod
- **Oracle**: Oracle Database with RMAN configured
- **Rubrik**: Access to Rubrik CDM with Managed Volumes configured
- **Permissions**: Scripts should be run as the Oracle user
## RMAN Configuration
The script will
## Configuration
1. Copy `rbk_api.conf.example` to `rbk_api.conf`
2. Edit `rbk_api.conf` with your Rubrik settings:
```bash
# Rubrik API Configuration
ID="your-service-account-id"
SECRET="your-service-account-secret"
RUBRIK_IP="your-rubrik-cluster-ip"
# Mount point prefix for Managed Volumes
MOUNTPOINT_PREFIX="/rubrik_"
# Log retention settings
HOSTLOGRET=2
MV_SPACE_WARN=75
# Number of RMAN channels to allocate per NFS mount
RMAN_CHANNELS_PER_MOUNT=1
# Logging directories
API_LOG_DIR=/tmp/rubrik
RMAN_LOG_DIR=/tmp/rubrik/rman
# Alert settings
ALERT_EMAILS="admin@example.com"
EMAIL_SUCCESS=1
```
## Scripts Overview
### oracle_funcs.ksh
Shared functions library containing:
- API authentication and REST calls
- Managed Volume operations (open/close)
- Error handling and logging
- OS detection and date handling
### list_mv.ksh
Lists all Managed Volumes visible to the configured service account, showing each MV's name and `isWritable` status.
**Usage:**
```bash
./list_mv.ksh
```
**Output:**
```
Service account in use is client|...
Managed Volumes visible to this account:
mv_name_1: isWritable=true
mv_name_2: isWritable=false
```
### rubrik_mv_op.ksh
Opens or closes a Managed Volume for backup operations.
**Usage:**
```bash
./rubrik_mv_op.ksh -d <DBNAME> -v <logs|data> -o <open|close>
```
**Examples:**
```bash
# Open data volume for ORCL database
./rubrik_mv_op.ksh -d ORCL -v data -o open
# Close logs volume for ORCL database
./rubrik_mv_op.ksh -d ORCL -v logs -o close
```
### rman_db.ksh
Performs RMAN database backup with incremental merge to Rubrik Managed Volume.
**Usage:**
```bash
./rman_db.ksh <ORACLE_SID>
```
**Features:**
- Incremental level 1 backup with merge
- Automatic MV open/close
- Configurable RMAN channels per NFS mount (RMAN_CHANNELS_PER_MOUNT)
- Disk space monitoring
- Email alerts on failure/success
- Archive log backup
### rman_logs.ksh
Performs RMAN archive log backup to Rubrik Managed Volume.
**Usage:**
```bash
./rman_logs.ksh <ORACLE_SID>
```
**Features:**
- Backs up all not-backed-up archive logs
- Configurable RMAN channels per NFS mount (RMAN_CHANNELS_PER_MOUNT)
- Automatic MV open/close
- Disk space monitoring
- Optional host-side log purging
- Email alerts
## HP-UX Compatibility Notes
These scripts are specifically designed for HP-UX compatibility:
- Uses `ksh` instead of `bash`
- Avoids GNU-specific commands (`grep -o`, `readlink`)
- Portable `awk` for JSON parsing
- HP-UX date handling with fallback to GNU date
- No reliance on symlinks for script location detection
## Logging
- API calls are logged to `$API_LOG_DIR/api_calls.log`
- RMAN operations are logged to `$RMAN_LOG_DIR/$ORACLE_SID/`
- Use `tail -f` on log files for monitoring
## Troubleshooting
### Common Issues
1. **"readlink not found"**: Scripts use portable directory detection
2. **JSON parsing errors**: Ensure Rubrik API returns expected format
3. **MV not found**: Check MV naming convention: `${HOST}_${ORACLE_SID}_data/logs`
4. **Permission denied**: Run as Oracle user, ensure MV mount points are accessible
5. **Curl errors**: Check network connectivity to Rubrik cluster
### Debug Mode
Add debug output by modifying scripts to show raw API responses.
### Testing Compatibility
Run the included `test.ksh` script to verify HP-UX compatibility of required tools.
## Security Notes
- Store `rbk_api.conf` securely with appropriate permissions
- Service account should have minimal required permissions
- Avoid logging secrets in log files
## Support
For issues specific to Rubrik CDM or Oracle integration, consult:
- Rubrik documentation
- Oracle RMAN documentation
- HP-UX system administration guides
## Version History
- v1.1: Enhanced list_mv.ksh with isWritable status, HP-UX compatibility improvements
- v1.0: Initial release with basic RMAN backup functionality

View File

@@ -6,43 +6,42 @@
#
# usage: list_mv.ksh
get_script_dir() {
# Portable way to get script directory for Linux and HP/UX (ksh compatible)
src="$0"
while [ -h "$src" ]; do
dir=$(cd -P $(dirname "$src") >/dev/null 2>&1 && pwd)
src=$(readlink "$src")
case $src in
/*) ;; # absolute path
*) src="$dir/$src";;
esac
done
cd -P $(dirname "$src") >/dev/null 2>&1 && pwd
dir=$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)
echo "$dir"
}
MYDIR=$(get_script_dir)
. $MYDIR/rbk_api.conf
. $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
# Script starts here
echo "Service account in use is $ID"
echo "Managed Volumes"
echo "Managed Volumes visible to this account:"
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume"
rest_api_get
awk '{
pos = 1
while (match(substr($0, pos), /"name":"[^"]*"/)) {
name = substr($0, pos + RSTART + 7, RLENGTH - 8)
# Remove any trailing quote if present
sub(/"$/, "", name)
print name
pos += RSTART + RLENGTH - 1
}
}' /tmp/rbkresponse.$$
awk '
{
line = $0
pos = 1
while (match(substr(line, pos), /"name":"[^"]*"/)) {
start = pos + RSTART + 7
len = RLENGTH - 9
name = substr(line, start, len)
pos += RSTART + RLENGTH - 1
if (match(substr(line, pos), /"isWritable":[ ]*(true|false)/)) {
start_w = pos + RSTART + 12
len_w = RLENGTH - 13
writable = substr(line, start_w, len_w)
print name ": isWritable=" writable
pos += RSTART + RLENGTH - 1
}
}
}
' /tmp/rbkresponse.$$
cleanup

View File

@@ -21,7 +21,6 @@ get_short_hostname() {
}
HOST=$(get_short_hostname)
# Detect OS and set DATE variable appropriately
os_name=$(uname -s)
case "$os_name" in
@@ -38,7 +37,6 @@ case "$os_name" in
DATE=$(command -v gdate)
else
DATE=$(command -v date)
echo "WARNING: GNU date (gdate) not found. Date arithmetic may not work on HP/UX." >&2
fi
;;
*)
@@ -50,28 +48,24 @@ echo "`$DATE` -$$-: CALLED $0 $@" >> $LOGFILE
trap ctrl_c INT
ctrl_c() {
echo "`$DATE` -$$-: TRAPPED CTRL-C - EXITING" >> $LOGFILE
exit_with_error
}
ctrl_c_inhibit() {
echo "`$DATE` -$$-: TRAPPED CTRL-C - CONTINUING" >> $LOGFILE
}
exit_with_error() {
# if [ $usingsatoken ]; then
# ENDPOINT="https://$RUBRIK_IP/api/internal/session/me"
# rest_api_delete
# check_http_error
# fi
ENDPOINT="https://$RUBRIK_IP/api/v1/session/me"
rest_api_delete
check_http_error
cat /tmp/rbkresponse.$$ | mailx -s "Backup error on ${HOST} for ${ORACLE_SID}. Please investigate" $ALERT_EMAILS
#rm -f /tmp/rbkresponse.$$
rm -f /tmp/rbkresponse.$$
rm -f /tmp/mountedDBs.$$
rm -f $PIDFILE
rm -f $PIDFILE
echo Aborting Script!
echo "`$DATE` -$$-: EXITED WITH ERROR $0 $@" >> $LOGFILE
exit 1
@@ -301,12 +295,9 @@ close_mv() {
}
cleanup() {
# if [ $usingsatoken ]; then
# ENDPOINT="https://$RUBRIK_IP/api/internal/session/me"
# rest_api_delete
# fi
echo "`$DATE` -$$-: EXITED $0 $@" >> $LOGFILE
#rm -f /tmp/mountedDBs.$$
#rm -f /tmp/rbkresponse.$$
ENDPOINT="https://$RUBRIK_IP/api/v1/session/me"
rest_api_delete
echo "`$DATE` -$$-: EXITED $0 $@" >> $LOGFILE
rm -f /tmp/rbkresponse.$$
rm -f $PIDFILE
}

View File

@@ -7,17 +7,9 @@
# usage: rman_db.ksh <ORACLE_SID>
get_script_dir() {
# Portable way to get script directory for Linux and HP/UX (ksh compatible)
src="$0"
while [ -h "$src" ]; do
dir=$(cd -P $(dirname "$src") >/dev/null 2>&1 && pwd)
src=$(readlink "$src")
case $src in
/*) ;; # absolute path
*) src="$dir/$src";;
esac
done
cd -P $(dirname "$src") >/dev/null 2>&1 && pwd
dir=$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)
echo "$dir"
}
MYDIR=$(get_script_dir)
@@ -32,7 +24,7 @@ export ORACLE_SID=$1
export ORAENV_ASK=YES
. $MYDIR/rbk_api.conf
. $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
#ORACLE_SID=$1
@@ -46,9 +38,6 @@ if [ -z "${ORACLE_SID}" ]; then
usage
fi
#ORAENV_ASK=NO
#. oraenv
export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
@@ -79,7 +68,12 @@ fi
echo Running RMAN with log to $RMAN_LOG
if [ $numChannels -eq 1 ]; then
# Default RMAN channels per mount if not set
RMAN_CHANNELS_PER_MOUNT=${RMAN_CHANNELS_PER_MOUNT:-1}
total_channels=$(expr $numChannels \* $RMAN_CHANNELS_PER_MOUNT)
if [ $total_channels -eq 1 ]; then
allocate="allocate channel 'ch1' device type disk format '$MOUNTPOINT/%U';"
release="release channel ch1;"
channel0="$MOUNTPOINT"
@@ -88,15 +82,21 @@ else
release=""
i=0
while [ $i -lt $numChannels ]; do
allocate="$allocate allocate channel 'c$i' device type disk format '$MOUNTPOINT/c$i/%U';"
release="$release release channel c$i;"
j=0
while [ $j -lt $RMAN_CHANNELS_PER_MOUNT ]; do
suffix=$(echo $j | tr '0123456789' 'abcdefghijklmnopqrstuvwxyz')
allocate="$allocate allocate channel 'c${i}${suffix}' device type disk format '$MOUNTPOINT/c$i/%U';"
release="$release release channel c${i}${suffix};"
j=$(expr $j + 1)
done
i=$(expr $i + 1)
done
channel0="$MOUNTPOINT/c0"
fi
# Save the current time (minus one hour) to ensure we catch all archive logs
startTime=$(date +%m-%d-%Y\ %H:%M:%S -d '-1 hour')
startTime=$(perl -e 'use POSIX qw(strftime); $time = time() - 3600; print strftime("%m-%d-%Y %H:%M:%S", localtime($time))')
# RMAN Part Here
###############################################################################
@@ -109,6 +109,7 @@ connect target /
set echo on;
configure retention policy to recovery window of 1 days;
run {
CONFIGURE BACKUP OPTIMIZATION OFF;
set controlfile autobackup format for device type disk to '$channel0/cf_%F';
$allocate
backup incremental level 1 for recover of copy with tag 'rubrik_snap' database;

View File

@@ -7,17 +7,9 @@
# usage: rman_logs.ksh <ORACLE_SID>
get_script_dir() {
# Portable way to get script directory for Linux and HP/UX (ksh compatible)
src="$0"
while [ -h "$src" ]; do
dir=$(cd -P $(dirname "$src") >/dev/null 2>&1 && pwd)
src=$(readlink "$src")
case $src in
/*) ;; # absolute path
*) src="$dir/$src";;
esac
done
cd -P $(dirname "$src") >/dev/null 2>&1 && pwd
dir=$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)
echo "$dir"
}
MYDIR=$(get_script_dir)
export ORACLE_SID=$1
@@ -31,11 +23,9 @@ export ORACLE_SID=$1
export ORAENV_ASK=YES
. $MYDIR/rbk_api.conf
. $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
#ORACLE_SID=$1
usage() {
echo "Usage: $0 <DBNAME>]" 1>&2
exit 1
@@ -45,9 +35,6 @@ if [ -z "${ORACLE_SID}" ]; then
usage
fi
#ORAENV_ASK=NO
#. oraenv
export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
@@ -75,15 +62,31 @@ fi
echo Running RMAN with log to $RMAN_LOG
allocate=""
release=""
i=0
while [ $i -lt $numChannels ]; do
allocate="$allocate allocate channel 'c$i' device type disk format '$MOUNTPOINT/c$i/%U';"
release="$release release channel c$i;"
i=$(expr $i + 1)
done
channel0="$MOUNTPOINT/c0"
# Default RMAN channels per mount if not set
RMAN_CHANNELS_PER_MOUNT=${RMAN_CHANNELS_PER_MOUNT:-1}
total_channels=$(expr $numChannels \* $RMAN_CHANNELS_PER_MOUNT)
if [ $total_channels -eq 1 ]; then
allocate="allocate channel 'ch1' device type disk format '$MOUNTPOINT/%U';"
release="release channel ch1;"
channel0="$MOUNTPOINT"
else
allocate=""
release=""
i=0
while [ $i -lt $numChannels ]; do
j=0
while [ $j -lt $RMAN_CHANNELS_PER_MOUNT ]; do
suffix=$(echo $j | tr '0123456789' 'abcdefghijklmnopqrstuvwxyz')
allocate="$allocate allocate channel 'c${i}${suffix}' device type disk format '$MOUNTPOINT/c$i/%U';"
release="$release release channel c${i}${suffix};"
j=$(expr $j + 1)
done
i=$(expr $i + 1)
done
channel0="$MOUNTPOINT/c0"
fi
# RMAN Part Here
@@ -94,6 +97,7 @@ set echo on;
show all;
crosscheck backup;
run {
CONFIGURE BACKUP OPTIMIZATION OFF;
set controlfile autobackup format for device type disk to '$channel0/cf_%F';
$allocate
backup archivelog all not backed up 1 times tag 'rubrik_pit_logs';

31
rubrik.conf.example Executable file
View File

@@ -0,0 +1,31 @@
# ID and Key for RSC Service Account (starts with client|) (use single quotes)
ID='client|xxxxxxxxxxxxxxxxxxx'
SECRET=xxxxxxxxxxxxxxxxxxxxxxxx
# DNS name of Rubrik CDM
RUBRIK_IP=<CDM address>
# Oracle Settings
MOUNTPOINT_PREFIX=/rubrik_
# How many hours of archivelog to keep on host. 0 means do not purge logs
HOSTLOGRET=2
# Percentage threshold to warn if an MV filesystem is getting full
MV_SPACE_WARN=75
# Number of RMAN channels to allocate per MV channel
# NOTE: This is not a TOTAL. Total number of RMAN channels will be
# this multipled by the number of channels of the Managed Volume
RMAN_CHANNELS_PER_MOUNT=1
# Logging directories
# API calls
API_LOG_DIR=/tmp/rubrik
# RMAN sessions
RMAN_LOG_DIR=/tmp/rubrik/rman
# List of email addresses to send failure alerts to
ALERT_EMAILS=root,oracle
# Set to 1 to enable email alert on success also
EMAIL_SUCCESS=1

View File

@@ -11,17 +11,9 @@
# -o Operation to perform - open or close the MV
get_script_dir() {
# Portable way to get script directory for Linux and HP/UX (ksh compatible)
src="$0"
while [ -h "$src" ]; do
dir=$(cd -P $(dirname "$src") >/dev/null 2>&1 && pwd)
src=$(readlink "$src")
case $src in
/*) ;; # absolute path
*) src="$dir/$src";;
esac
done
cd -P $(dirname "$src") >/dev/null 2>&1 && pwd
dir=$(cd -P "$(dirname "$src")" >/dev/null 2>&1 && pwd)
echo "$dir"
}
MYDIR=$(get_script_dir)
. $MYDIR/rbk_api.conf