Compare commits

...

9 Commits

Author SHA1 Message Date
04d946aa00 Get env from oratab not oraenv 2025-11-11 09:06:47 -05:00
bd7d5da70e HP/UX changes after site testing 2025-11-11 06:02:54 -05:00
c2ef3e05e3 Minor tweaks 2025-11-06 06:15:44 -05:00
14b1d29384 gitignore 2025-10-28 12:22:56 -04:00
024d06a827 Adding simple tests 2025-10-28 12:22:46 -04:00
09fd3b2c67 more little fixes 2025-10-28 12:21:11 -04:00
6c1f8c926e HP/UX fixes 2025-10-28 11:02:06 -04:00
67050cf3a0 Convert to use ksh 2025-10-28 07:25:18 -04:00
ab2e15d717 hpux updates 2025-10-24 12:39:08 -04:00
12 changed files with 744 additions and 278 deletions

5
.gitignore vendored
View File

@@ -6,6 +6,7 @@ __pycache__/
env/ env/
venv/ venv/
ENV/ ENV/
SCRATCH
# macOS system files # macOS system files
.DS_Store .DS_Store
@@ -16,7 +17,11 @@ ENV/
# Exclude Rubrik API config files # Exclude Rubrik API config files
rbk_api.conf rbk_api.conf
rubrik.conf
*.json
# Other common ignores # Other common ignores
*.swp *.swp
*.swo *.swo
releases/

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

82
check_date.ksh Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/ksh
echo "Checking date command availability and date arithmetic support..."
# Check for date commands
echo "Available date commands:"
if command -v date >/dev/null 2>&1; then
echo " date: $(which date)"
DATE_CMD="date"
else
echo " date: NOT FOUND"
fi
if command -v gdate >/dev/null 2>&1; then
echo " gdate: $(which gdate)"
if [ -z "$DATE_CMD" ]; then
DATE_CMD="gdate"
fi
else
echo " gdate: NOT FOUND in PATH"
# Check common HP-UX locations for gdate
echo " Checking common HP-UX locations for gdate..."
for gdate_path in /usr/local/bin/gdate /opt/gnu/bin/gdate /usr/contrib/bin/gdate /opt/coreutils/bin/gdate; do
if [ -x "$gdate_path" ]; then
echo " gdate: FOUND at $gdate_path"
if [ -z "$DATE_CMD" ]; then
DATE_CMD="$gdate_path"
fi
break
fi
done
if [ -z "$DATE_CMD" ] || [ "$DATE_CMD" = "date" ]; then
echo " gdate: NOT FOUND in common locations"
fi
fi
if command -v perl >/dev/null 2>&1; then
echo " perl: $(which perl)"
PERL_AVAILABLE=1
else
echo " perl: NOT FOUND"
PERL_AVAILABLE=0
fi
if [ -z "$DATE_CMD" ]; then
echo "ERROR: No date command found!"
exit 1
fi
echo ""
echo "Testing date arithmetic with: $DATE_CMD"
# Test basic date
echo "Basic date output:"
$DATE_CMD +"%Y-%m-%d %H:%M:%S"
# Test date arithmetic like used in rman_db.ksh
echo ""
echo "Testing date arithmetic: '$DATE_CMD +%m-%d-%Y\ %H:%M:%S -d \"-1 hour\"'"
if $DATE_CMD -d "-1 hour" >/dev/null 2>&1; then
RESULT=$($DATE_CMD +%m-%d-%Y\ %H:%M:%S -d '-1 hour')
echo "SUCCESS: Date arithmetic works"
echo "Result: $RESULT"
else
echo "ERROR: Date arithmetic (-d option) not supported"
echo "This system may need GNU date (gdate) installed"
fi
# Test perl-based date arithmetic as fallback
if [ $PERL_AVAILABLE -eq 1 ]; then
echo ""
echo "Testing perl-based date arithmetic fallback:"
echo "Command: perl -e 'use POSIX qw(strftime); \$time = time() - 3600; print strftime(\"%m-%d-%Y %H:%M:%S\", localtime(\$time))'"
PERL_RESULT=$(perl -e 'use POSIX qw(strftime); $time = time() - 3600; print strftime("%m-%d-%Y %H:%M:%S", localtime($time))')
echo "SUCCESS: Perl date arithmetic works"
echo "Result: $PERL_RESULT"
else
echo ""
echo "WARNING: Perl not available - no fallback for date arithmetic"
fi
echo ""
echo "Test complete."

61
list_mv.ksh Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/ksh
#
# List MVs using API call to RSC, for diagnostic purposes
# Written for HCL / Nokia
# v1.1 - James Pattinson - October 2025
#
# usage: list_mv.ksh
_SCRIPT_="$0"
get_script_dir() {
script="$1"
case "$script" in
/*) abs_path="$script" ;;
*) abs_path="$PWD/$script" ;;
esac
while [ -L "$abs_path" ]; do
link=$(readlink "$abs_path")
case "$link" in
/*) abs_path="$link" ;;
*) abs_path="$(dirname "$abs_path")/$link" ;;
esac
done
script_dir=$(dirname "$abs_path")
cd "$script_dir" 2>/dev/null && pwd
}
MYDIR=$(get_script_dir "$_SCRIPT_")
. $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
# Script starts here
echo "Service account in use is $ID"
echo "Managed Volumes visible to this account:"
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume"
rest_api_get
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

@@ -1,32 +0,0 @@
#!/bin/bash
#
# List MVs using API call to CDM, for diagnostic purposes
# Written for HCL / Nokia
# v1.1 - James Pattinson - October 2025
#
# usage: list_mv.sh
MYDIR="$(dirname "$(readlink -f "$0")")"
source $MYDIR/rbk_api.conf
source $MYDIR/oracle_funcs.sh
# Script starts here
echo Service account in use is $ID
echo ALL MVs
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume"
rest_api_get
grep -Eo '"name"[^,]*' /tmp/rbkresponse.$$
echo NonRelic MVs
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?is_relic=false"
rest_api_get
grep -Eo '"name"[^,]*' /tmp/rbkresponse.$$
cleanup

View File

@@ -1,8 +1,8 @@
#!/bin/bash #!/usr/bin/ksh
# #
# Oracle shell script support functions # Oracle shell script support functions
# Written for HCL / Nokia # Written for HCL / Nokia
# v1.0 - James Pattinson - October 2025 # v1.0 - James Pattinson - November 2025
nowait=0 nowait=0
@@ -10,73 +10,105 @@ LOGFILE=$API_LOG_DIR/api_calls.log
mkdir -p $API_LOG_DIR mkdir -p $API_LOG_DIR
tabwidth=25 tabwidth=25
HOST=$(hostname -s)
os=$(uname -o) # Portable short hostname function
if [ $os == "Solaris" ]; then get_short_hostname() {
# Use the GNU version of date binary # Check OS type first - HP-UX hostname doesn't support -s
DATE=/usr/gnu/bin/date os_type=$(uname -s)
else if [ "$os_type" = "HP-UX" ]; then
DATE=$(which date) hostname | awk -F. '{print $1}'
fi else
# Try -s flag on other systems
if hostname -s >/dev/null 2>&1; then
hostname -s
else
hostname | awk -F. '{print $1}'
fi
fi
}
HOST=$(get_short_hostname)
# Detect OS and set DATE variable appropriately
os_name=$(uname -s)
case "$os_name" in
Linux)
DATE=$(which date)
;;
SunOS)
# Solaris
DATE=/usr/gnu/bin/date
;;
HP-UX)
# HP/UX: try gdate, fallback to date with warning
if command -v gdate >/dev/null 2>&1; then
DATE=$(command -v gdate)
else
DATE=$(command -v date)
fi
;;
*)
DATE=$(which date)
;;
esac
echo "`$DATE` -$$-: CALLED $0 $@" >> $LOGFILE echo "`$DATE` -$$-: CALLED $0 $@" >> $LOGFILE
trap ctrl_c INT trap ctrl_c INT
function ctrl_c () { ctrl_c() {
echo "`$DATE` -$$-: TRAPPED CTRL-C - EXITING" >> $LOGFILE echo "`$DATE` -$$-: TRAPPED CTRL-C - EXITING" >> $LOGFILE
exit_with_error exit_with_error
} }
function ctrl_c_inhibit () { ctrl_c_inhibit() {
echo "`$DATE` -$$-: TRAPPED CTRL-C - CONTINUING" >> $LOGFILE echo "`$DATE` -$$-: TRAPPED CTRL-C - CONTINUING" >> $LOGFILE
} }
exit_with_error () { exit_with_error() {
# if [ $usingsatoken ]; then ENDPOINT="https://$RUBRIK_IP/api/v1/session/me"
# ENDPOINT="https://$RUBRIK_IP/api/v1/session/me" rest_api_delete
# rest_api_delete check_http_error
# check_http_error
# fi
cat /tmp/rbkresponse.$$ | mailx -s "Backup error on ${HOST} for ${ORACLE_SID}. Please investigate" $ALERT_EMAILS 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 /tmp/mountedDBs.$$
rm -f $PIDFILE rm -f $PIDFILE
echo Aborting Script! echo Aborting Script!
echo "`$DATE` -$$-: EXITED WITH ERROR $0 $@" >> $LOGFILE echo "`$DATE` -$$-: EXITED WITH ERROR $0 $@" >> $LOGFILE
exit 1 exit 1
} }
check_http_error () { check_http_error() {
# All good responses start with a 2 # All good responses start with a 2
if [ ${http_response:0:1} != "2" ]; then first_char=$(echo "$http_response" | cut -c1)
echo FATAL: HTTP error from API call: $http_response. The server responded with: if [ "$first_char" != "2" ]; then
cat /tmp/rbkresponse.$$ ; echo ; exit_with_error echo FATAL: HTTP error from API call: $http_response. The server responded with:
fi cat /tmp/rbkresponse.$$ ; echo ; exit_with_error
fi
} }
check_pid () { check_pid() {
if [ -f $PIDFILE ] if [ -f $PIDFILE ]
then then
PID=$(cat $PIDFILE) PID=$(cat $PIDFILE)
ps -p $PID > /dev/null 2>&1 if ps -p $PID > /dev/null 2>&1; then
if [ $? -eq 0 ] echo "ERROR: MV already being used by process ID $PID"
then if ps -fp $PID > /dev/null 2>&1; then
echo "ERROR: MV already being used by process ID $PID" ps -fp $PID
ps -fp $PID else
exit_with_error ps -ef | awk -v pid=$PID '$2==pid'
else fi
## Process not found assume not running exit_with_error
echo $$ > $PIDFILE else
if [ $? -ne 0 ] ## Process not found assume not running
then echo $$ > $PIDFILE
echo "ERROR: Could not create mvLock file" if [ $? -ne 0 ]
exit_with_error then
fi echo "ERROR: Could not create mvLock file"
fi exit_with_error
fi
fi
else else
echo $$ > $PIDFILE echo $$ > $PIDFILE
if [ $? -ne 0 ] if [ $? -ne 0 ]
@@ -88,53 +120,31 @@ check_pid () {
} }
check_get_token () {
if [ -z "${AUTH_TOKEN}" ]; then # Get a new token only if AUTH_TOKEN is not already set
check_get_token() {
# RSC if [ -z "$AUTH_TOKEN" ]; then
id_string=$(echo $ID | cut -d\| -f 2) get_token
# CDM fi
id_string=$(echo $ID | cut -d: -f 4)
if [ -f ~/.rbksession.$id_string ]; then
echo "`$DATE` -$$-: AUTH SESSION FILE EXISTS" >> $LOGFILE
read expiration token < <(echo $(cat ~/.rbksession.$id_string))
if [ $($DATE +%s -u -d $expiration) -lt $(( $($DATE +%s) + 1800 )) ]; then
echo "`$DATE` -$$-: AUTH TOKEN EXPIRED" >> $LOGFILE
get_token
else
AUTH_TOKEN=$token
fi
else
get_token
fi
fi
} }
get_token () { get_token() {
trap '' INT echo "`$DATE` -$$-: AUTH USER $ID" >> $LOGFILE
echo "`$DATE` -$$-: AUTH USER $ID" >> $LOGFILE MYENDPOINT="https://$RUBRIK_IP/api/v1/service_account/session"
MYENDPOINT="https://$RUBRIK_IP/api/v1/service_account/session" MYPAYLOAD='{"serviceAccountId":"'$ID'","secret":"'$SECRET'"}'
MYPAYLOAD="{\"serviceAccountId\":\"$ID\",\"secret\":\"$SECRET\"}"
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $MYENDPOINT -H "accept: application/json" -H "Content-Type: application/json" -d $MYPAYLOAD) http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $MYENDPOINT -H "accept: application/json" -H "Content-Type: application/json" -d "$MYPAYLOAD")
check_http_error check_http_error
AUTH_TOKEN=$(grep -Eo '"token"[^,]*' /tmp/rbkresponse.$$ | grep -Eo '[^:]*$' | sed 's/\"//g') AUTH_TOKEN=$(cat /tmp/rbkresponse.$$ | awk '{match($0, /"token":"[^"]*"/); if (RSTART > 0) {print substr($0, RSTART+9, RLENGTH-10);}}')
SESSION=$(grep -Eo '"sessionId"[^,]*' /tmp/rbkresponse.$$ | grep -Eo '[^:]*$' | sed 's/\"//g')
EXPIRATION=$(grep -Eo '"expirationTime"[^,]*' /tmp/rbkresponse.$$ | cut -d: -f 2-4 | sed 's/\"//g' | sed 's/.000Z//;s/T/Z/') echo "`$DATE` -$$-: AUTH SESSION $SESSION" >> $LOGFILE
echo "`$DATE` -$$-: AUTH SESSION $SESSION" >> $LOGFILE
echo "`$DATE` -$$-: SAVING TOKEN TO FILE" >> $LOGFILE
echo "$EXPIRATION $AUTH_TOKEN" > ~/.rbksession.$id_string
usingsatoken=1
trap ctrl_c INT
} }
# HTTP GET: Given $ENDPOINT write output to file # HTTP GET: Given $ENDPOINT write output to file
rest_api_get () { rest_api_get() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X GET $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN") http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X GET $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN")
echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE
@@ -145,7 +155,7 @@ rest_api_get () {
check_http_error check_http_error
} }
rest_api_get_2 () { rest_api_get_2() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse2.$$ -w "%{http_code}" -X GET $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN") http_response=$(curl -s -k -o /tmp/rbkresponse2.$$ -w "%{http_code}" -X GET $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN")
echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE
@@ -157,7 +167,7 @@ rest_api_get_2 () {
} }
# HTTP POST: Given $ENDPOINT and $PAYLOAD write output to file # HTTP POST: Given $ENDPOINT and $PAYLOAD write output to file
rest_api_post () { rest_api_post() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d $PAYLOAD) http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d $PAYLOAD)
echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE
@@ -169,7 +179,7 @@ rest_api_post () {
check_http_error check_http_error
} }
rest_api_post_empty () { rest_api_post_empty() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json") http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X POST $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json")
echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE
@@ -181,7 +191,7 @@ rest_api_post_empty () {
check_http_error check_http_error
} }
rest_api_patch () { rest_api_patch() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X PATCH $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD") http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X PATCH $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN" -H "Content-Type: application/json" -d "$PAYLOAD")
echo "`$DATE` -$$-: REST API PATCH: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API PATCH: ENDPOINT $ENDPOINT" >> $LOGFILE
@@ -193,80 +203,90 @@ rest_api_patch () {
check_http_error check_http_error
} }
rest_api_delete () { rest_api_delete() {
check_get_token check_get_token
http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X DELETE $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN") http_response=$(curl -s -k -o /tmp/rbkresponse.$$ -w "%{http_code}" -X DELETE $ENDPOINT -H "accept: application/json" -H "Authorization: Bearer $AUTH_TOKEN")
echo "`$DATE` -$$-: REST API DELETE: $http_response: ENDPOINT $ENDPOINT" >> $LOGFILE echo "`$DATE` -$$-: REST API DELETE: $http_response: ENDPOINT $ENDPOINT" >> $LOGFILE
check_http_error check_http_error
} }
get_mv () { get_mv() {
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false" ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false"
rest_api_get rest_api_get
mvId=$(grep -Eo '"id"[^,]*' /tmp/rbkresponse.$$ | grep -Eo 'ManagedVolume:::[a-z0-9-]*') mvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/rbkresponse.$$)
numChannels=$(grep -Eo '"numChannels"[^,]*' /tmp/rbkresponse.$$ | cut -d: -f2) numChannels=$(awk '{match($0, /"numChannels":[ ]*[0-9]+/); if (RSTART > 0) {val=substr($0, RSTART, RLENGTH); sub(/.*:[ ]*/, "", val); print val}}' /tmp/rbkresponse.$$)
if [[ $mvId == "" ]]; then if [ -z "$mvId" ]; then
echo ERROR: MV with name $mv_name was not found echo ERROR: MV with name $mv_name was not found
exit_with_error exit_with_error
fi fi
} }
get_data_mv () { get_data_mv() {
mv_name=${HOST}_${ORACLE_SID}_data mv_name=${HOST}_${ORACLE_SID}_Data
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false" ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false"
rest_api_get rest_api_get
mvId=$(grep -Eo '"id"[^,]*' /tmp/rbkresponse.$$ | grep -Eo 'ManagedVolume:::[a-z0-9-]*') mvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/rbkresponse.$$)
numChannels=$(grep -Eo '"numChannels"[^,]*' /tmp/rbkresponse.$$ | cut -d: -f2) numChannels=$(awk '{match($0, /"numChannels":[ ]*[0-9]+/); if (RSTART > 0) {val=substr($0, RSTART, RLENGTH); sub(/.*:[ ]*/, "", val); print val}}' /tmp/rbkresponse.$$)
if [[ $mvId == "" ]]; then if [ -z "$mvId" ]; then
echo ERROR: MV with name $mv_name was not found echo ERROR: MV with name $mv_name was not found
exit_with_error exit_with_error
fi fi
} }
get_log_mv () { get_log_mv() {
# Look for a log volume. If not present, return the data volume # Look for a log volume. If not present, return the data volume
mv_name=${HOST}_${ORACLE_SID}_log mv_name=${HOST}_${ORACLE_SID}_Log
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false" ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false"
rest_api_get rest_api_get
logMvId=$(grep -Eo '"id"[^,]*' /tmp/rbkresponse.$$ | grep -Eo 'ManagedVolume:::[a-z0-9-]*') logMvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/rbkresponse.$$)
if [[ $logMvId == "" ]]; then if [ -z "$logMvId" ]; then
echo "INFO: Log volume ($mv_name) not found. Logs will be written to DB volume" echo "INFO: Log volume ($mv_name) not found. Logs will be written to DB volume"
logMvPresent=0 logMvPresent=0
mv_name=${HOST}_${ORACLE_SID}_data mv_name=${HOST}_${ORACLE_SID}_Data
ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false" ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume?name=$mv_name&is_relic=false"
rest_api_get rest_api_get
mvId=$(grep -Eo '"id"[^,]*' /tmp/rbkresponse.$$ | grep -Eo 'ManagedVolume:::[a-z0-9-]*') mvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/rbkresponse.$$)
numChannels=$(grep -Eo '"numChannels"[^,]*' /tmp/rbkresponse.$$ | cut -d: -f2) numChannels=$(awk '{match($0, /"numChannels":[ ]*[0-9]+/); if (RSTART > 0) {val=substr($0, RSTART, RLENGTH); sub(/.*:[ ]*/, "", val); print val}}' /tmp/rbkresponse.$$)
if [[ $mvId == "" ]]; then if [ -z "$mvId" ]; then
echo ERROR: MV with name $mv_name was not found echo ERROR: MV with name $mv_name was not found
exit_with_error exit_with_error
fi fi
else else
mvId=$(grep -Eo '"id"[^,]*' /tmp/rbkresponse.$$ | grep -Eo 'ManagedVolume:::[a-z0-9-]*') mvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/rbkresponse.$$)
numChannels=$(grep -Eo '"numChannels"[^,]*' /tmp/rbkresponse.$$ | cut -d: -f2) numChannels=$(awk '{match($0, /"numChannels":[ ]*[0-9]+/); if (RSTART > 0) {val=substr($0, RSTART, RLENGTH); sub(/.*:[ ]*/, "", val); print val}}' /tmp/rbkresponse.$$)
logMvPresent=1 logMvPresent=1
echo "INFO: Log volume ($mv_name) exists with $numChannels channels" echo "INFO: Log volume ($mv_name) exists with $numChannels channels"
fi fi
} }
open_mv () { set_oracle_env() {
ORACLE_HOME=$(awk -F: '$1 == "'$1'" {print $2}' /etc/oratab)
PATH=$PATH:$ORACLE_HOME/bin
ORACLE_SID=$1
if [ -z "$ORACLE_HOME" ]; then
echo "ERROR: SID $1 not found in /etc/oratab"
exit_with_error
fi
}
open_mv() {
PIDFILE=/tmp/mvLock_${mv_name}.pid PIDFILE=/tmp/mvLock_${mv_name}.pid
check_pid check_pid
@@ -276,7 +296,7 @@ open_mv () {
} }
close_mv () { close_mv() {
if [ -z "${SLANAME}" ]; then if [ -z "${SLANAME}" ]; then
echo Closing MV $mv_name using default assigned SLA echo Closing MV $mv_name using default assigned SLA
@@ -292,13 +312,10 @@ close_mv () {
} }
cleanup () { cleanup() {
# if [ $usingsatoken ]; then ENDPOINT="https://$RUBRIK_IP/api/v1/session/me"
# ENDPOINT="https://$RUBRIK_IP/api/v1/session/me" rest_api_delete
# rest_api_delete echo "`$DATE` -$$-: EXITED $0 $@" >> $LOGFILE
# fi
echo "`$DATE` -$$-: EXITED $0 $@" >> $LOGFILE
rm -f /tmp/mountedDBs.$$
rm -f /tmp/rbkresponse.$$ rm -f /tmp/rbkresponse.$$
rm -f $PIDFILE rm -f $PIDFILE
} }

View File

@@ -1,48 +1,56 @@
#!/bin/bash #!/usr/bin/ksh
# #
# RMAN DB backup with incremental Merge # RMAN DB backup with incremental Merge
# Written for HCL / Nokia # Written for HCL / Nokia
# v1.0 - James Pattinson - October 2025 # v1.0 - James Pattinson - November 2025
# #
# usage: rman_db.sh <ORACLE_SID> # usage: rman_db.ksh <ORACLE_SID>
MYDIR="$(dirname "$(readlink -f "$0")")" _SCRIPT_="$0"
export ORACLE_SID=$1 get_script_dir() {
script="$1"
case "$script" in
/*) abs_path="$script" ;;
*) abs_path="$PWD/$script" ;;
esac
while [ -L "$abs_path" ]; do
link=$(readlink "$abs_path")
case "$link" in
/*) abs_path="$link" ;;
*) abs_path="$(dirname "$abs_path")/$link" ;;
esac
done
script_dir=$(dirname "$abs_path")
cd "$script_dir" 2>/dev/null && pwd
}
. $HOME/.profile MYDIR=$(get_script_dir "$_SCRIPT_")
export ORAENV_ASK=NO . $MYDIR/rubrik.conf
export ORACLE_SID=$1 . $MYDIR/oracle_funcs.ksh
. oraenv set_oracle_env $1
export ORAENV_ASK=YES export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
source $MYDIR/rbk_api.conf usage() {
source $MYDIR/oracle_funcs.sh echo "Usage: $0 <DBNAME>]" 1>&2
exit 1
#ORACLE_SID=$1 }
usage() { echo "Usage: $0 <DBNAME>]" 1>&2; exit 1; }
if [ -z "${ORACLE_SID}" ]; then if [ -z "${ORACLE_SID}" ]; then
usage usage
fi fi
#ORAENV_ASK=NO MOUNTPOINT=$MOUNTPOINT_PREFIX/$ORACLE_SID/data
#. oraenv
export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
MOUNTPOINT=$MOUNTPOINT_PREFIX$ORACLE_SID
mkdir -p $RMAN_LOG_DIR/$ORACLE_SID/ mkdir -p $RMAN_LOG_DIR/$ORACLE_SID/
RMAN_LOG=$RMAN_LOG_DIR/$ORACLE_SID/rman_${ORACLE_SID}_DB_$(date +%d%m%y).log RMAN_LOG=$RMAN_LOG_DIR/$ORACLE_SID/rman_${ORACLE_SID}_DB_$(date +%d%m%y).log
# Disk space check # Disk space check
dusage=$(df -Ph | grep -E "$MOUNTPOINT" | sed s/%//g | awk -v spaceWarn=$MV_SPACE_WARN '{ if($5 >= spaceWarn) print $0;}') dusage=$(df -Pk | grep -E "$MOUNTPOINT" | sed s/%//g | awk -v spaceWarn=$MV_SPACE_WARN '{ if($5 >= spaceWarn) print $0;}')
if [ "$dusage" != "" ]; then if [ "$dusage" != "" ]; then
echo "WARNING: Disk Space Alert - sending email" echo "WARNING: Disk Space Alert - sending email"
echo "$dusage" | mailx -s "WARNING: Rubrik MV Disk Space Alert On $(hostname) at $(date)" $ALERT_EMAILS echo "$dusage" | mailx -s "WARNING: Rubrik MV Disk Space Alert On $(hostname) at $(date)" $ALERT_EMAILS
@@ -53,6 +61,8 @@ fi
get_data_mv get_data_mv
open_mv open_mv
echo "DEBUG: numChannels=$numChannels, MOUNTPOINT=$MOUNTPOINT"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo ERROR: Unable to open MV, aborting echo ERROR: Unable to open MV, aborting
exit_with_error exit_with_error
@@ -61,22 +71,35 @@ fi
echo Running RMAN with log to $RMAN_LOG 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';" allocate="allocate channel 'ch1' device type disk format '$MOUNTPOINT/%U';"
release="release channel ch1;" release="release channel ch1;"
channel0="$MOUNTPOINT" channel0="$MOUNTPOINT"
else else
allocate=""
for i in $(seq 0 $(($numChannels - 1))); do release=""
allocate+="allocate channel 'c$i' device type disk format '$MOUNTPOINT/c$i/%U';" i=0
release+="release channel c$i;" 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 done
channel0="$MOUNTPOINT/c0" channel0="$MOUNTPOINT/c0"
fi fi
# Save the current time (minus one hour) to ensure we catch all archive logs # 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 # RMAN Part Here
############################################################################### ###############################################################################
@@ -84,10 +107,12 @@ startTime=$(date +%m-%d-%Y\ %H:%M:%S -d '-1 hour')
# Now perform the backup and merge # Now perform the backup and merge
rman nocatalog log $RMAN_LOG append > /dev/null <<EOF rman nocatalog log $RMAN_LOG append > /dev/null <<EOF
#cat <<EOF
connect target / connect target /
set echo on; set echo on;
configure retention policy to recovery window of 1 days; configure retention policy to recovery window of 1 days;
run { run {
CONFIGURE BACKUP OPTIMIZATION OFF;
set controlfile autobackup format for device type disk to '$channel0/cf_%F'; set controlfile autobackup format for device type disk to '$channel0/cf_%F';
$allocate $allocate
backup incremental level 1 for recover of copy with tag 'rubrik_snap' database; backup incremental level 1 for recover of copy with tag 'rubrik_snap' database;
@@ -100,7 +125,7 @@ allocate channel for maintenance device type disk;
crosscheck backup; crosscheck backup;
crosscheck copy; crosscheck copy;
delete noprompt obsolete device type disk; delete noprompt obsolete device type disk;
delete noprompt backup of archivelog all completed before 'sysdate-3' tag rubrik_snap_logs; delete noprompt backup of archivelog all completed before 'sysdate-2' tag rubrik_snap_logs;
release channel; release channel;
EOF EOF
############################################################################### ###############################################################################
@@ -116,6 +141,6 @@ elif [ $EMAIL_SUCCESS -eq 1 ]; then
fi fi
# Change permission of backup files to enable alternate host restore # Change permission of backup files to enable alternate host restore
find $MOUNTPOINT -type f -exec chmod 644 -- {} + 2>/dev/null find $MOUNTPOINT -type f -exec chmod 644 {} \; 2>/dev/null
close_mv close_mv

View File

@@ -1,59 +1,69 @@
#!/bin/bash #!/usr/bin/ksh
# #
# RMAN Log backup # RMAN Log backup
# Written for HCL / Nokia # Written for HCL / Nokia
# v1.1 - James Pattinson - October 2025 # v1.1 - James Pattinson - November 2025
# #
# usage: rman_logs.sh <ORACLE_SID> # usage: rman_logs.ksh <ORACLE_SID>
MYDIR="$(dirname "$(readlink -f "$0")")" _SCRIPT_="$0"
export ORACLE_SID=$1
. $HOME/.profile get_script_dir() {
script="$1"
case "$script" in
/*) abs_path="$script" ;;
*) abs_path="$PWD/$script" ;;
esac
while [ -L "$abs_path" ]; do
link=$(readlink "$abs_path")
case "$link" in
/*) abs_path="$link" ;;
*) abs_path="$(dirname "$abs_path")/$link" ;;
esac
done
script_dir=$(dirname "$abs_path")
cd "$script_dir" 2>/dev/null && pwd
}
export ORAENV_ASK=NO MYDIR=$(get_script_dir "$_SCRIPT_")
export ORACLE_SID=$1
. oraenv . $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
export ORAENV_ASK=YES set_oracle_env $1
source $MYDIR/rbk_api.conf export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
source $MYDIR/oracle_funcs.sh export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
#ORACLE_SID=$1 usage() {
echo "Usage: $0 <DBNAME>]" 1>&2
usage() { echo "Usage: $0 <DBNAME>]" 1>&2; exit 1; } exit 1
}
if [ -z "${ORACLE_SID}" ]; then if [ -z "${ORACLE_SID}" ]; then
usage usage
fi fi
#ORAENV_ASK=NO
#. oraenv
export NLS_DATE_FORMAT='mm-dd-yyyy hh24:mi:ss'
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
mkdir -p $RMAN_LOG_DIR/$ORACLE_SID/ mkdir -p $RMAN_LOG_DIR/$ORACLE_SID/
RMAN_LOG=$RMAN_LOG_DIR/$ORACLE_SID/rman_${ORACLE_SID}_LOG_$(date +%d%m%y).log RMAN_LOG=$RMAN_LOG_DIR/$ORACLE_SID/rman_${ORACLE_SID}_LOG_$(date +%d%m%y).log
get_log_mv get_log_mv
open_mv open_mv
if [ -z "$numChannels" ]; then
echo "WARNING: numChannels not found, setting to 1"
numChannels=1
fi
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo ERROR: Unable to open MV, aborting echo ERROR: Unable to open MV, aborting
exit_with_error exit_with_error
fi fi
if [[ $logMvPresent -eq 1 ]] && [[ $numChannels -eq 1 ]] ; then MOUNTPOINT=$MOUNTPOINT_PREFIX/$ORACLE_SID/log
MOUNTPOINT=$MOUNTPOINT_PREFIX${ORACLE_SID}_log
else
MOUNTPOINT=$MOUNTPOINT_PREFIX$ORACLE_SID
fi
# Disk space check # Disk space check
dusage=$(df -Ph | grep -E "$MOUNTPOINT" | sed s/%//g | awk -v spaceWarn=$MV_SPACE_WARN '{ if($5 >= spaceWarn) print $0;}') dusage=$(df -Pk | grep -E "$MOUNTPOINT" | sed s/%//g | awk -v spaceWarn=$MV_SPACE_WARN '{ if($5 >= spaceWarn) print $0;}')
if [ "$dusage" != "" ]; then if [ "$dusage" != "" ]; then
echo "WARNING: Disk Space Alert - sending email" echo "WARNING: Disk Space Alert - sending email"
echo "$dusage" | mailx -s "WARNING: Rubrik MV Disk Space Alert On $(hostname) at $(date)" $ALERT_EMAILS echo "$dusage" | mailx -s "WARNING: Rubrik MV Disk Space Alert On $(hostname) at $(date)" $ALERT_EMAILS
@@ -63,20 +73,33 @@ fi
echo Running RMAN with log to $RMAN_LOG 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';" allocate="allocate channel 'ch1' device type disk format '$MOUNTPOINT/%U';"
release="release channel ch1;" release="release channel ch1;"
channel0="$MOUNTPOINT" channel0="$MOUNTPOINT"
else else
allocate=""
for i in $(seq 0 $(($numChannels - 1))); do release=""
allocate+="allocate channel 'c$i' device type disk format '$MOUNTPOINT/log_c$i/%U';" i=0
release+="release channel c$i;" 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 done
channel0="$MOUNTPOINT/log_c0" channel0="$MOUNTPOINT/c0"
fi fi
# RMAN Part Here # RMAN Part Here
############################################################################### ###############################################################################
rman nocatalog log $RMAN_LOG append > /dev/null <<EOF rman nocatalog log $RMAN_LOG append > /dev/null <<EOF
@@ -85,13 +108,14 @@ set echo on;
show all; show all;
crosscheck backup; crosscheck backup;
run { run {
CONFIGURE BACKUP OPTIMIZATION OFF;
set controlfile autobackup format for device type disk to '$channel0/cf_%F'; set controlfile autobackup format for device type disk to '$channel0/cf_%F';
$allocate $allocate
backup archivelog all not backed up 1 times tag 'RUBRIK_LOGS'; backup archivelog all not backed up 1 times tag 'rubrik_pit_logs';
$release $release
} }
allocate channel for maintenance device type disk; allocate channel for maintenance device type disk;
delete noprompt backup of archivelog all completed before 'sysdate-3' tag RUBRIK_LOGS; delete noprompt backup of archivelog all completed before 'sysdate-2' tag rubrik_pit_logs;
release channel; release channel;
EOF EOF
############################################################################### ###############################################################################
@@ -107,11 +131,12 @@ elif [ $EMAIL_SUCCESS -eq 1 ]; then
fi fi
# Change permission of backup files to enable alternate host restore # Change permission of backup files to enable alternate host restore
find $MOUNTPOINT -type f -exec chmod 644 -- {} + 2>/dev/null find $MOUNTPOINT -type f -exec chmod 644 {} \; 2>/dev/null
close_mv close_mv
if [[ $HOSTLOGRET -gt 0 ]]; then
if [ $HOSTLOGRET -gt 0 ]; then
echo "Starting post-backup RMAN log purge" echo "Starting post-backup RMAN log purge"

View File

@@ -13,6 +13,11 @@ HOSTLOGRET=2
# Percentage threshold to warn if an MV filesystem is getting full # Percentage threshold to warn if an MV filesystem is getting full
MV_SPACE_WARN=75 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 # Logging directories
# API calls # API calls
@@ -23,4 +28,4 @@ RMAN_LOG_DIR=/tmp/rubrik/rman
# List of email addresses to send failure alerts to # List of email addresses to send failure alerts to
ALERT_EMAILS=root,oracle ALERT_EMAILS=root,oracle
# Set to 1 to enable email alert on success also # Set to 1 to enable email alert on success also
EMAIL_SUCCESS=1 EMAIL_SUCCESS=0

110
rubrik_mv_op.ksh Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/ksh
#
# Open and Close MV using API call to CDM
# Written for AvonHCL / Nokia
# v1.0 - James Pattinson - October 2025
#
# usage: rubrik_mv_op.ksh -d <DBNAME> -v <logs|data> -o <open|close>
#
# -d Oracle DBNAME
# -v Volume to operate on, logs or data
# -o Operation to perform - open or close the MV
_SCRIPT_="$0"
get_script_dir() {
script="$1"
case "$script" in
/*) abs_path="$script" ;;
*) abs_path="$PWD/$script" ;;
esac
while [ -L "$abs_path" ]; do
link=$(readlink "$abs_path")
case "$link" in
/*) abs_path="$link" ;;
*) abs_path="$(dirname "$abs_path")/$link" ;;
esac
done
script_dir=$(dirname "$abs_path")
cd "$script_dir" 2>/dev/null && pwd
}
MYDIR=$(get_script_dir "$_SCRIPT_")
. $MYDIR/rubrik.conf
. $MYDIR/oracle_funcs.ksh
usage() {
echo "Usage: $0 -d <DBNAME> -v <logs|data> -o <open|close>"
echo " $0 -n <MV_NAME> -o <open|close>"
echo " -d Oracle DBNAME"
echo " -v Volume to operate on, logs or data"
echo " -o Operation to perform - open or close the MV"
echo " -n Specify MV name directly (use only with -o)"
exit 1
}
force=0
MVNAME=""
while getopts "d:v:o:n:" o; do
case "${o}" in
d)
DBNAME=${OPTARG}
;;
v)
VOLUME=${OPTARG}
;;
o)
OPCODE=${OPTARG}
;;
n)
MVNAME=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
# Validate options
if [ -n "$MVNAME" ]; then
# Direct MV name mode: require -n and -o only
if [ -z "$OPCODE" ]; then
usage
fi
mv_name="$MVNAME"
elif [ -n "$DBNAME" ] && [ -n "$VOLUME" ] && [ -n "$OPCODE" ]; then
# Standard mode: require -d, -v, -o
mv_name=$(get_short_hostname)_${DBNAME}_${VOLUME}
else
usage
fi
# Script starts here
get_short_hostname() {
# Check OS type first - HP-UX hostname doesn't support -s
os_type=$(uname -s)
if [ "$os_type" = "HP-UX" ]; then
hostname | awk -F. '{print $1}'
else
# Try -s flag on other systems
if hostname -s >/dev/null 2>&1; then
hostname -s
else
hostname | awk -F. '{print $1}'
fi
fi
}
get_mv
case $OPCODE in
open) open_mv ;;
close) close_mv ;;
*) echo "ERROR: Invalid opcode. Specify open or close" ; exit_with_error
esac
cleanup

View File

@@ -1,54 +0,0 @@
#!/bin/bash
#
# Open and Close MV using API call to CDM
# Written for AvonHCL / Nokia
# v1.0 - James Pattinson - October 2025
#
# usage: rubrik_mv_op.sh -d <DBNAME> -v <logs|data> -o <open|close>
#
# -d Oracle DBNAME
# -v Volume to operate on, logs or data
# -o Operation to perform - open or close the MV
MYDIR="$(dirname "$(readlink -f "$0")")"
source $MYDIR/rbk_api.conf
source $MYDIR/oracle_funcs.sh
usage() { echo "Usage: $0 -d <DBNAME> -v <logs|data> -o <open|close>" 1>&2; exit 1; }
force=0
while getopts "d:v:o:" o; do
case "${o}" in
d)
DBNAME=${OPTARG}
;;
v)
VOLUME=${OPTARG}
;;
o)
OPCODE=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
if [ -z "${DBNAME}" ] || [ -z "${VOLUME}" ] || [ -z "${OPCODE}" ]; then
usage
fi
# Script starts here
mv_name=$(hostname -s)_${DBNAME}_${VOLUME}
get_mv
case $OPCODE in
open) open_mv ;;
close) close_mv ;;
*) echo "ERROR: Invalid opcode. Specify open or close" ; exit_with_error
esac
cleanup

50
test.ksh Executable file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/ksh
echo "Testing HP-UX compatibility for Rubrik scripts..."
# Check for required commands
for cmd in ksh awk readlink egrep date dfsdf expr mkdir; do
if ! command -v $cmd >/dev/null 2>&1; then
echo "ERROR: $cmd not found in PATH"
else
echo "OK: $cmd found"
fi
done
# Test awk JSON extraction for numChannels
echo '{"numChannels": 4, "foo": "bar"}' > /tmp/testjson.$$
numChannels=$(awk '{match($0, /"numChannels":[ ]*[0-9]+/); if (RSTART > 0) {val=substr($0, RSTART, RLENGTH); sub(/.*:[ ]*/, "", val); print val}}' /tmp/testjson.$$)
if [ "$numChannels" = "4" ]; then
echo "OK: awk numChannels extraction works"
else
echo "ERROR: awk numChannels extraction failed (got '$numChannels')"
fi
# Test awk JSON extraction for ManagedVolume
echo '{"id":"ManagedVolume:::abc-123-xyz"}' > /tmp/testjson.$$
mvId=$(awk '{match($0, /ManagedVolume:::[a-z0-9-]*/); if (RSTART > 0) {id=substr($0, RSTART, RLENGTH); sub(/"$/, "", id); print id}}' /tmp/testjson.$$)
if [ "$mvId" = "ManagedVolume:::abc-123-xyz" ]; then
echo "OK: awk ManagedVolume extraction works"
else
echo "ERROR: awk ManagedVolume extraction failed (got '$mvId')"
fi
# Test readlink
ln -s /tmp/testjson.$$ /tmp/testlink.$$
linkres=$(readlink /tmp/testlink.$$ 2>/dev/null)
if [ "$linkres" = "/tmp/testjson.$$" ]; then
echo "OK: readlink works"
else
echo "WARNING: readlink did not return expected result (got '$linkres')"
fi
rm -f /tmp/testjson.$$ /tmp/testlink.$$
# Test expr arithmetic
i=0
i=$(expr $i + 1)
if [ "$i" = "1" ]; then
echo "OK: expr arithmetic works"
else
echo "ERROR: expr arithmetic failed"
fi
echo "Testing complete."