Compare commits
8 Commits
024a31dc57
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| aa07962766 | |||
| 14b74e8ecd | |||
| b71ca508ea | |||
| 2fed2ded69 | |||
| 150f065349 | |||
| 7ed76ad0d3 | |||
| 185238e95d | |||
| 226ddb6ca0 |
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Configuration files with sensitive data
|
||||||
|
rsc.json
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
|
||||||
|
# Environment-specific files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# IDE/Editor files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
Thumbs.db
|
||||||
248
README.md
Normal file
248
README.md
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
# RSC Oracle Database Clone Script
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `rsc_clone.sh` script performs Oracle database clone operations using the Rubrik Security Cloud (RSC) GraphQL API. It allows you to create a clone of an existing Oracle database to a target host with customizable recovery points and advanced Oracle configuration options.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Rubrik Security Cloud (RSC) access with valid credentials
|
||||||
|
- Source Oracle database protected by Rubrik
|
||||||
|
- Target Oracle host configured and registered in RSC
|
||||||
|
- Required configuration files:
|
||||||
|
- `rsc.json` - RSC API credentials
|
||||||
|
- Oracle cloning options file
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### RSC API Configuration (`rsc.json`)
|
||||||
|
|
||||||
|
Download the JSON configuration file from RSC:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"client_id": "client|your-client-id-here",
|
||||||
|
"client_secret": "your-client-secret-here",
|
||||||
|
"name": "Your RSC Service Account Name",
|
||||||
|
"access_token_uri": "https://your-organization.my.rubrik.com/api/client_token"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Oracle Cloning Options File
|
||||||
|
|
||||||
|
Create a text file with Oracle-specific cloning parameters. Each line should contain `KEY=VALUE` pairs for Oracle initialization parameters:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example: SHED_to_SCLONE.txt
|
||||||
|
CONTROL_FILES='/u01/app/oracle/oradata/SCLONE/control01.ctl, /u01/app/oracle/fast_recovery_area/SCLONE/control02.ctl'
|
||||||
|
DB_CREATE_FILE_DEST=/u01/app/oracle/oradata/SCLONE/
|
||||||
|
AUDIT_FILE_DEST='/u01/app/oracle/admin/SCLONE/adump'
|
||||||
|
DB_FILE_NAME_CONVERT='SHED','SCLONE'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rsc_clone.sh -n <newname> -o <optionsfile> -h <targethost> [-s sourcehost] [-t "YYYY-MM-DD HH:MM:SS"] [-d] <srcdb>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required Parameters
|
||||||
|
|
||||||
|
- `-n <newname>` - Database name/SID for the cloned database
|
||||||
|
- `-o <optionsfile>` - Path to Oracle cloning options file
|
||||||
|
- `-h <targethost>` - Target host where the database will be cloned
|
||||||
|
- `<srcdb>` - Source database name to clone
|
||||||
|
|
||||||
|
### Optional Parameters
|
||||||
|
|
||||||
|
- `-s <sourcehost>` - Source host name (use when there are multiple databases with the same name on different hosts)
|
||||||
|
- `-t "YYYY-MM-DD HH:MM:SS"` - Recovery point timestamp (defaults to latest point-in-time)
|
||||||
|
- `-d` - Dry-run mode (shows mutation variables without executing)
|
||||||
|
- `-c <numChannels>` - Optional: configure number of RMAN channels for the clone; when provided the script adds `"numChannels": <numChannels>` to the `config` block in the GraphQL variables
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Basic Clone Operation
|
||||||
|
|
||||||
|
Clone database `SHED` to `SCLONE` on target host `pve-ora19c-3`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dry-Run Mode
|
||||||
|
|
||||||
|
Preview the clone operation without executing it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 -d SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
```
|
||||||
|
DEBUG: DB ID is b4194205-b7d6-5f0b-8360-e6f349b9fd82
|
||||||
|
INFO: No time specified, using latest PIT
|
||||||
|
Latest PIT (ISO8601): 2025-10-15T08:32:49.000Z
|
||||||
|
Latest PIT unixtime (ms): 1760517169000
|
||||||
|
Target Host ID is 26008fd4-9a96-582e-86b7-4da31584a7ad
|
||||||
|
|
||||||
|
=== DRY-RUN MODE ===
|
||||||
|
Would execute the following GraphQL mutation:
|
||||||
|
|
||||||
|
QUERY:
|
||||||
|
mutation OracleDatabaseExportMutation($input: ExportOracleDatabaseInput!) {
|
||||||
|
exportOracleDatabase(input: $input) {
|
||||||
|
id
|
||||||
|
links {
|
||||||
|
href
|
||||||
|
rel
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VARIABLES:
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"request": {
|
||||||
|
"id": "b4194205-b7d6-5f0b-8360-e6f349b9fd82",
|
||||||
|
"config": {
|
||||||
|
"targetOracleHostOrRacId": "26008fd4-9a96-582e-86b7-4da31584a7ad",
|
||||||
|
"shouldRestoreFilesOnly": false,
|
||||||
|
"recoveryPoint": {
|
||||||
|
"timestampMs": 1760517169000
|
||||||
|
},
|
||||||
|
"cloneDbName": "SCLONE",
|
||||||
|
"shouldAllowRenameToSource": true,
|
||||||
|
"shouldSkipDropDbInUndo": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advancedRecoveryConfigMap": [
|
||||||
|
{
|
||||||
|
"key": "CONTROL_FILES",
|
||||||
|
"value": "'/u01/app/oracle/oradata/SCLONE/control01.ctl, /u01/app/oracle/fast_recovery_area/SCLONE/control02.ctl'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DB_CREATE_FILE_DEST",
|
||||||
|
"value": "/u01/app/oracle/oradata/SCLONE/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "AUDIT_FILE_DEST",
|
||||||
|
"value": "'/u01/app/oracle/admin/SCLONE/adump'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "DB_FILE_NAME_CONVERT",
|
||||||
|
"value": "'SHED','SCLONE'"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=== END DRY-RUN ===
|
||||||
|
```
|
||||||
|
|
||||||
|
### Point-in-Time Recovery
|
||||||
|
|
||||||
|
Clone database to a specific point in time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 -t "2025-10-15 08:00:00" SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
### Specify Source Host
|
||||||
|
|
||||||
|
When multiple databases with the same name exist on different hosts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 -s pve-ora19c-1 SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Workflow
|
||||||
|
|
||||||
|
### Configuration (rsc.json)
|
||||||
|
|
||||||
|
The scripts read RSC credentials and endpoint details from `rsc.json` in the repository root. An example file `rsc.json.example` is included. The expected JSON fields are:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"client_id": "<your-client-id>",
|
||||||
|
"client_secret": "<your-client-secret>",
|
||||||
|
"access_token_uri": "https://<rsc-host>/api/client_token",
|
||||||
|
"name": "<optional-friendly-name>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Security note: `rsc.json` is listed in `.gitignore`. Ensure the file permissions are restricted (recommended `chmod 600 rsc.json`). If `rsc.json` was accidentally committed to git, consider purging it from history.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
- Basic dry-run with verbose output:
|
||||||
|
|
||||||
|
```
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 -d SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
- Execute clone and request 4 RMAN channels:
|
||||||
|
|
||||||
|
```
|
||||||
|
./rsc_clone.sh -n SCLONE -o SHED_to_SCLONE.txt -h pve-ora19c-3 -c 4 SHED
|
||||||
|
```
|
||||||
|
|
||||||
|
- Trigger an on-demand log backup with verbose logging:
|
||||||
|
|
||||||
|
```
|
||||||
|
./rsc_log_backup.sh <dbName>
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Parameter Validation** - Validates required parameters and options file
|
||||||
|
2. **Database Discovery** - Locates source database in RSC
|
||||||
|
3. **Host Resolution** - Resolves target host ID in RSC
|
||||||
|
4. **Recovery Point** - Determines recovery timestamp (latest or specified)
|
||||||
|
5. **Options Processing** - Converts options file to JSON format
|
||||||
|
6. **Clone Execution** - Submits GraphQL mutation to RSC API
|
||||||
|
7. **Job Monitoring** - Tracks clone job status until completion
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The script includes comprehensive error handling for:
|
||||||
|
|
||||||
|
- Missing required parameters
|
||||||
|
- Database not found or ambiguous matches
|
||||||
|
- Target host not found
|
||||||
|
- Invalid recovery timestamps
|
||||||
|
- RSC API errors
|
||||||
|
- Job failures
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- `rsc_ops.sh` - RSC API operations and utility functions
|
||||||
|
- `rsc.json` - RSC credentials configuration
|
||||||
|
- `jq` - JSON processing
|
||||||
|
- `curl` - HTTP requests
|
||||||
|
- `date`/`gdate` - Date/time operations
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Database not found** - Verify database name and use `-s` if multiple databases exist
|
||||||
|
2. **Host not found** - Check target host name is registered in RSC
|
||||||
|
3. **Permission errors** - Ensure RSC service account has sufficient privileges
|
||||||
|
4. **Invalid timestamp** - Use format "YYYY-MM-DD HH:MM:SS" for `-t` parameter
|
||||||
|
|
||||||
|
### Debug Information
|
||||||
|
|
||||||
|
The script provides debug output including:
|
||||||
|
- Source database ID
|
||||||
|
- Target host ID
|
||||||
|
- Recovery point details
|
||||||
|
- Job status updates
|
||||||
|
|
||||||
|
Use dry-run mode (`-d`) to validate configuration before executing actual clones.
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
- v0.1 - Initial release with basic clone functionality
|
||||||
|
- Added dry-run mode for validation
|
||||||
|
- Improved error handling and database selection logic
|
||||||
247
oracle_funcs.sh
247
oracle_funcs.sh
@@ -1,247 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
#--------------------------------------------------------------------------------------------------------
|
|
||||||
# Oracle shell script support functions
|
|
||||||
# v0.2 - James Pattinson - August 2021
|
|
||||||
# v0.3 - U701053 - 30.03.2022 - if database not found, try to search with the ENDPOINT datagurad
|
|
||||||
# v0.4 - James Pattinson 25/01/23 - Adding support for Service Accounts
|
|
||||||
#--------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
|
||||||
source $MYDIR/rbk_api.conf
|
|
||||||
|
|
||||||
# -- Mobi config ---------
|
|
||||||
#RBK_ENV=$OUTI/shell/rubrik/conf/rbk_env
|
|
||||||
# -- End Mobi config ----
|
|
||||||
|
|
||||||
# -- Mobi config -----------
|
|
||||||
#if [ -f "${RBK_ENV}" ] ; then
|
|
||||||
# source ${RBK_ENV}
|
|
||||||
#else
|
|
||||||
# echo "The ${RBK_ENV} file is not found ...."
|
|
||||||
# exit_with_error
|
|
||||||
#fi
|
|
||||||
# -- End Mobi config -------
|
|
||||||
|
|
||||||
nowait=0
|
|
||||||
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
||||||
DATE=gdate
|
|
||||||
else
|
|
||||||
DATE=date
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit_with_error () {
|
|
||||||
rm -f /tmp/rbkresponse.$$
|
|
||||||
echo Aborting Script!
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# for canceled status
|
|
||||||
exit_with_cancel () {
|
|
||||||
rm -f /tmp/rbkresponse.$$
|
|
||||||
echo Canceling Script!
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# for undoing status
|
|
||||||
exit_with_undoing () {
|
|
||||||
rm -f /tmp/rbkresponse.$$
|
|
||||||
echo undoing Script!
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
check_http_error () {
|
|
||||||
# All good responses start with a 2
|
|
||||||
if [ ${http_response:0:1} != "2" ]; then
|
|
||||||
echo FATAL: HTTP error from API call: $http_response. The server responded with:
|
|
||||||
cat /tmp/rbkresponse.$$ ; echo ; exit_with_error
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Given RBK_SID return $db_id of matching database
|
|
||||||
find_database () {
|
|
||||||
|
|
||||||
# First get IDs of all the mounted DBs for this SID
|
|
||||||
ENDPOINT="https://$RUBRIK_IP/api/internal/oracle/db/mount"
|
|
||||||
rest_api_get
|
|
||||||
|
|
||||||
cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.mountedDatabaseId!=null and .mountedDatabaseName==$SID) | .mountedDatabaseId' > /tmp/mountedDBs.$$
|
|
||||||
|
|
||||||
# Now get a list of Oracle DBs
|
|
||||||
ENDPOINT="https://$RUBRIK_IP/api/v1/oracle/db?name=$RBK_SID"
|
|
||||||
rest_api_get
|
|
||||||
|
|
||||||
# If no dtaabse is found, try with dataguard
|
|
||||||
if [ `cat /tmp/rbkresponse.$$ | grep "id\":" | wc -l` -eq 0 ]; then
|
|
||||||
echo " DB not found, try with dataguard..."
|
|
||||||
ENDPOINT="https://$RUBRIK_IP/api/v1/oracle/db?is_data_guard_group=true&is_relic=false&name=$RBK_SID"
|
|
||||||
rest_api_get
|
|
||||||
fi
|
|
||||||
|
|
||||||
#echo "================================="
|
|
||||||
#cat /tmp/rbkresponse.$$ | jq -r '.data[]' | tee /tmp/titi
|
|
||||||
#echo "================================="
|
|
||||||
#echo "cat /tmp/rbkresponse.$$ | jq -r '.data[]'"
|
|
||||||
|
|
||||||
|
|
||||||
# If no host is specified then just look for the DB with the right SID
|
|
||||||
if [ -z $RBK_HOST ]; then
|
|
||||||
|
|
||||||
# get list of DB IDs in scope (sid matches and not a relic)
|
|
||||||
myDBs=$(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.name==$SID and .isRelic==false) | .id' ; cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.name==$SID and .isRelic==false) | .dataGuardGroupId' | sort | uniq)
|
|
||||||
|
|
||||||
for db in $myDBs; do
|
|
||||||
id=$(echo $db | cut -d: -f 4)
|
|
||||||
if grep -q $id /tmp/mountedDBs.$$; then
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Get the details for the specific DB ID
|
|
||||||
read name db_id sla_id dg_type dg_id RBK_HOST num_instances grp_name < <(echo $(cat /tmp/rbkresponse.$$ | jq -r --arg ID "OracleDatabase:::$id" '.data[] | select(.id==$ID) | .name, .id, .effectiveSlaDomainId, .dataGuardType, .dataGuardGroupId, .instances[0].hostName, .numInstances, .dataGuardGroupName'))
|
|
||||||
|
|
||||||
# Host was specified
|
|
||||||
else
|
|
||||||
read name db_id sla_id dg_type dg_id RBK_HOST num_instances grp_name < <(echo $(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" --arg HOST "$RBK_HOST" '.data[] | select(.sid==$SID and .infraPath[0].name==$HOST and .isRelic==false) | .name, .id, .effectiveSlaDomainId, .dataGuardType, .dataGuardGroupId, .instances[0].hostName, .numInstances, .dataGuardGroupName'))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$dg_type" == "DataGuardMember" ]; then
|
|
||||||
db_id=$dg_id
|
|
||||||
# Now find SLA of the DG GROUP not just the DB (which will be unprotected)
|
|
||||||
ENDPOINT="https://$RUBRIK_IP/api/v1/oracle/db/$db_id"
|
|
||||||
rest_api_get
|
|
||||||
sla_id=$(cat /tmp/rbkresponse.$$ | jq -r '.effectiveSlaDomainId')
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$db_id" ]; then
|
|
||||||
echo FATAL: No DB found with SID $RBK_SID on host $RBK_HOST
|
|
||||||
if [ "${SCRIPT}" = "check_recoverable_range.sh" ] ; then
|
|
||||||
export ret=11
|
|
||||||
else
|
|
||||||
exit_with_error
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo " db_id is: $db_id"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_get_token () {
|
|
||||||
|
|
||||||
if [ -z "${AUTH_TOKEN}" ]; then
|
|
||||||
|
|
||||||
if [[ "${ID}" =~ ^client ]]; then
|
|
||||||
# Looks like an RSC service account
|
|
||||||
id_string=$(echo $ID | cut -d\| -f 2)
|
|
||||||
else
|
|
||||||
# Not an RSC service account
|
|
||||||
id_string=$(echo $ID | cut -d: -f 4)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If there is a cached credential file, use it
|
|
||||||
if [ -f ~/.rbksession.$id_string ]; then
|
|
||||||
read expiration token < <(echo $(cat ~/.rbksession.$id_string))
|
|
||||||
# If token expires within 30 min, get a new one
|
|
||||||
if [ $($DATE +%s -d $expiration) -lt $(( $($DATE +%s) + 1800 )) ]; then
|
|
||||||
get_token
|
|
||||||
else
|
|
||||||
AUTH_TOKEN=$token
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
get_token
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
get_token () {
|
|
||||||
|
|
||||||
MYENDPOINT="https://$RUBRIK_IP/api/v1/service_account/session"
|
|
||||||
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)
|
|
||||||
check_http_error
|
|
||||||
|
|
||||||
AUTH_TOKEN=$(cat /tmp/rbkresponse.$$ | jq -r '.token')
|
|
||||||
SESSION=$(cat /tmp/rbkresponse.$$ | jq -r '.sessionId')
|
|
||||||
EXPIRATION=$(cat /tmp/rbkresponse.$$ | jq -r '.expirationTime')
|
|
||||||
echo "$EXPIRATION $AUTH_TOKEN" > ~/.rbksession.$id_string
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTP GET: Given $ENDPOINT write output to file
|
|
||||||
rest_api_get () {
|
|
||||||
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")
|
|
||||||
check_http_error
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTP POST: Given $ENDPOINT and $PAYLOAD write output to file
|
|
||||||
rest_api_post () {
|
|
||||||
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)
|
|
||||||
check_http_error
|
|
||||||
}
|
|
||||||
|
|
||||||
rest_api_post_empty () {
|
|
||||||
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")
|
|
||||||
check_http_error
|
|
||||||
}
|
|
||||||
|
|
||||||
rest_api_patch () {
|
|
||||||
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)
|
|
||||||
check_http_error
|
|
||||||
}
|
|
||||||
|
|
||||||
rest_api_delete () {
|
|
||||||
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")
|
|
||||||
check_http_error
|
|
||||||
}
|
|
||||||
|
|
||||||
get_cluster_uuid () {
|
|
||||||
ENDPOINT="https://$RUBRIK_IP/api/v1/cluster/me"
|
|
||||||
rest_api_get
|
|
||||||
cluster_uuid=$(cat /tmp/rbkresponse.$$ | jq -r .id)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Given an ENDPOINT of an async job, monitor it
|
|
||||||
check_status () {
|
|
||||||
if [ $nowait -ne 1 ]; then
|
|
||||||
# Check the status in a loop
|
|
||||||
while true; do
|
|
||||||
rest_api_get
|
|
||||||
status=$(cat /tmp/rbkresponse.$$ | jq -r '.status')
|
|
||||||
if [ $status != "SUCCEEDED" ] && [ $status != "FAILED" ] && [ $status != "CANCELED" ] && [ $status != "UNDOING" ]; then
|
|
||||||
echo Status is $status, checking in 30 seconds
|
|
||||||
else
|
|
||||||
if [ $status != "SUCCEEDED" ]; then
|
|
||||||
|
|
||||||
if [ $status = "CANCELED" ] ; then
|
|
||||||
echo OPERATION FAILED WITH STATUS $status
|
|
||||||
exit_with_cancel
|
|
||||||
elif [ $status = "UNDOING" ] ; then
|
|
||||||
echo OPERATION FAILED WITH STATUS $status
|
|
||||||
exit_with_undoing
|
|
||||||
else
|
|
||||||
echo OPERATION FAILED WITH STATUS $status
|
|
||||||
exit_with_error
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo OPERATION SUCCEEDED
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
sleep 30
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup () {
|
|
||||||
rm -f /tmp/mountedDBs.$$
|
|
||||||
rm -f /tmp/rbkresponse.$$
|
|
||||||
rm -f /tmp/payload.$$
|
|
||||||
}
|
|
||||||
11
rbk_api.conf
11
rbk_api.conf
@@ -1,11 +0,0 @@
|
|||||||
# IP Address (or DNS name) of Rubrik CDM
|
|
||||||
RUBRIK_IP=192.168.10.76
|
|
||||||
|
|
||||||
#AUTH_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0NjlmMGUzNS00OWQxLTQ2NTEtOGY1ZS00MjA5OTU0MTU3NmUiLCJpc01mYVJlbWVtYmVyVG9rZW4iOmZhbHNlLCJpc3MiOiJmZWU2MDYzNy05Y2Q4LTRjMmItOTM4NS1hNjljMjViNTA0YmUiLCJpc1JlZHVjZWRTY29wZSI6ZmFsc2UsImlhdCI6MTY3NDYzNjAzNiwianRpIjoiZGQ5MjhmYzQtODM3Mi00ZWE4LWIzMDQtNzg4MjY4MDNkYjc3In0.2-ZQQvm0TmmujVQxJEEB8w8xjhowx5GjBfdBeDkiPVw
|
|
||||||
|
|
||||||
ID="client|d332d008-a86b-4943-b5c4-b3d9720b1960"
|
|
||||||
SECRET=HsVg6hsgJwqkVsXarQEFIxjFaMeUOADGuSpYeLC2MI0TQEigK4HGvxppbLvUV_X9
|
|
||||||
|
|
||||||
RSC_HOST=rubrik-rbkpso20.my.rubrik.com
|
|
||||||
RSC_ID="client|d332d008-a86b-4943-b5c4-b3d9720b1960"
|
|
||||||
RSC_SECRET=HsVg6hsgJwqkVsXarQEFIxjFaMeUOADGuSpYeLC2MI0TQEigK4HGvxppbLvUV_X9
|
|
||||||
6
rsc.json.example
Normal file
6
rsc.json.example
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"client_id": "client|your-client-id-here",
|
||||||
|
"client_secret": "your-client-secret-here",
|
||||||
|
"name": "Your RSC Service Account Name",
|
||||||
|
"access_token_uri": "https://your-organization.my.rubrik.com/api/client_token"
|
||||||
|
}
|
||||||
173
rsc_clone.sh
173
rsc_clone.sh
@@ -3,9 +3,9 @@
|
|||||||
# Example RSC API call script
|
# Example RSC API call script
|
||||||
# v0.1 - James Pattinson - August 2025
|
# v0.1 - James Pattinson - August 2025
|
||||||
#
|
#
|
||||||
# Perfoms a database clone operation
|
# Performs a database clone operation
|
||||||
#
|
#
|
||||||
# usage: rsc_clone.sh -n <newname> -o <optionsfile> -h <targethost> [-s sourcehost] [-t "YYYY-MM-DD HH:MM:SS"] <srcdb>
|
# usage: rsc_clone.sh -n <newname> -o <optionsfile> -h <targethost> [-s sourcehost] [-t "YYYY-MM-DD HH:MM:SS"] [-d] [-c numChannels] [-p customPfilePath] <srcdb>
|
||||||
#
|
#
|
||||||
# Options:
|
# Options:
|
||||||
# -n <newname> : db_name / SID of the new cloned database
|
# -n <newname> : db_name / SID of the new cloned database
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
# -h <targethost> : Target host where the cloned database will be created
|
# -h <targethost> : Target host where the cloned database will be created
|
||||||
# -s <sourcehost> : Source host where the original database is located (optional, use when there is ambiguity)
|
# -s <sourcehost> : Source host where the original database is located (optional, use when there is ambiguity)
|
||||||
# -t "YYYY-MM-DD HH:MM:SS" : Optional timestamp for the recovery point, defaults to latest PIT
|
# -t "YYYY-MM-DD HH:MM:SS" : Optional timestamp for the recovery point, defaults to latest PIT
|
||||||
|
# -d : Dry-run mode - show mutation variables without executing the clone
|
||||||
|
# -c <numChannels> : Optional - number of RMAN channels to configure for the clone
|
||||||
|
# -p <customPfilePath> : Optional - custom pfile path for the clone
|
||||||
# <srcdb> : Source database name or RSC dbid (if known, can be used directly)
|
# <srcdb> : Source database name or RSC dbid (if known, can be used directly)
|
||||||
#
|
#
|
||||||
# Example options file content:
|
# Example options file content:
|
||||||
@@ -22,14 +25,13 @@
|
|||||||
# DB_CREATE_FILE_DEST=/u01/app/oracle/oradata/NEWNAME/
|
# DB_CREATE_FILE_DEST=/u01/app/oracle/oradata/NEWNAME/
|
||||||
# AUDIT_FILE_DEST='/u01/app/oracle/admin/NEWNAME/adump'
|
# AUDIT_FILE_DEST='/u01/app/oracle/admin/NEWNAME/adump'
|
||||||
|
|
||||||
usage() { echo "Usage: $0 -n <newname> -o <optionsfile> -h <targethost> [-s sourcehost] [-t "YYYY-MM-DD HH:MM:SS"] <srcdb>" 1>&2; exit 1; }
|
usage() { log_error "Usage: $0 -n <newname> -o <optionsfile> -h <targethost> [-s sourcehost] [-t \"YYYY-MM-DD HH:MM:SS\"] [-d] [-c numChannels] [-p customPfilePath] <srcdb>"; exit 1; }
|
||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
MYDIR="$(dirname "$(realpath "$0")")"
|
||||||
|
|
||||||
source $MYDIR/oracle_funcs.sh
|
|
||||||
source $MYDIR/rsc_ops.sh
|
source $MYDIR/rsc_ops.sh
|
||||||
|
|
||||||
while getopts "n:o:t:h:s:" o; do
|
while getopts "n:o:t:h:s:dc:p:" o; do
|
||||||
case "${o}" in
|
case "${o}" in
|
||||||
n)
|
n)
|
||||||
newName=${OPTARG}
|
newName=${OPTARG}
|
||||||
@@ -46,6 +48,25 @@ while getopts "n:o:t:h:s:" o; do
|
|||||||
s)
|
s)
|
||||||
node_name=${OPTARG}
|
node_name=${OPTARG}
|
||||||
;;
|
;;
|
||||||
|
d)
|
||||||
|
dryrun=true
|
||||||
|
;;
|
||||||
|
c)
|
||||||
|
numChannels=${OPTARG}
|
||||||
|
# Validate numChannels is a positive integer
|
||||||
|
if ! [[ "$numChannels" =~ ^[0-9]+$ && "$numChannels" -gt 0 ]]; then
|
||||||
|
log_error "-c requires a positive integer value"
|
||||||
|
exit_with_error
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
p)
|
||||||
|
customPfilePath=${OPTARG}
|
||||||
|
# Basic validation - ensure it's an absolute path
|
||||||
|
if [[ ! "$customPfilePath" =~ ^/ ]]; then
|
||||||
|
log_error "-p requires an absolute path (starting with /)"
|
||||||
|
exit_with_error
|
||||||
|
fi
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
@@ -61,7 +82,7 @@ fi
|
|||||||
|
|
||||||
# Check if optionsFile exists
|
# Check if optionsFile exists
|
||||||
if [[ ! -f "$optionsFile" ]]; then
|
if [[ ! -f "$optionsFile" ]]; then
|
||||||
echo "ERROR: Options file '$optionsFile' does not exist."
|
log_error "Options file '$optionsFile' does not exist."
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -135,8 +156,9 @@ get_latest_pit() {
|
|||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
# Get latest endTime
|
# Get latest endTime
|
||||||
latest_endtime=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleRecoverableRanges.data[] | .endTime' | sort -r | head -n 1)
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
echo "Latest PIT (ISO8601): $latest_endtime"
|
latest_endtime=$(echo "$response_content" | jq -r '.data.oracleRecoverableRanges.data[] | .endTime' | sort -r | head -n 1)
|
||||||
|
log_info "Latest PIT (ISO8601): $latest_endtime"
|
||||||
|
|
||||||
# Convert to unixtime in milliseconds
|
# Convert to unixtime in milliseconds
|
||||||
latest_unixtime_ms=$(date -d "$latest_endtime" +%s 2>/dev/null)
|
latest_unixtime_ms=$(date -d "$latest_endtime" +%s 2>/dev/null)
|
||||||
@@ -145,11 +167,11 @@ get_latest_pit() {
|
|||||||
latest_unixtime_ms=$(gdate -d "$latest_endtime" +%s 2>/dev/null)
|
latest_unixtime_ms=$(gdate -d "$latest_endtime" +%s 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
if [[ -z "$latest_unixtime_ms" ]]; then
|
if [[ -z "$latest_unixtime_ms" ]]; then
|
||||||
echo "ERROR: Unable to convert $latest_endtime to unixtime"
|
log_error "Unable to convert $latest_endtime to unixtime"
|
||||||
exit 5
|
exit 5
|
||||||
fi
|
fi
|
||||||
latest_unixtime_ms=$((latest_unixtime_ms * 1000))
|
latest_unixtime_ms=$((latest_unixtime_ms * 1000))
|
||||||
echo "Latest PIT unixtime (ms): $latest_unixtime_ms"
|
log_info "Latest PIT unixtime (ms): $latest_unixtime_ms"
|
||||||
|
|
||||||
export latest_unixtime_ms
|
export latest_unixtime_ms
|
||||||
}
|
}
|
||||||
@@ -182,11 +204,12 @@ get_oracle_host_id() {
|
|||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
# Get all matching host IDs (portable, no mapfile)
|
# Get all matching host IDs (portable, no mapfile)
|
||||||
host_ids=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleTopLevelDescendants.nodes[] | .id')
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
|
host_ids=$(echo "$response_content" | jq -r '.data.oracleTopLevelDescendants.nodes[] | .id')
|
||||||
host_count=$(echo "$host_ids" | grep -c .)
|
host_count=$(echo "$host_ids" | grep -c .)
|
||||||
if [[ $host_count -ne 1 ]]; then
|
if [[ $host_count -ne 1 ]]; then
|
||||||
echo "ERROR: Multiple hosts found for '$1':"
|
log_error "Multiple hosts found for '$1':"
|
||||||
cat /tmp/rbkresponse.$$ | jq -r '.data.oracleTopLevelDescendants.nodes[] | "\(.name) \(.id)"'
|
echo "$response_content" | jq -r '.data.oracleTopLevelDescendants.nodes[] | "\(.name) \(.id)"'
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
# Set the first match (or empty if none)
|
# Set the first match (or empty if none)
|
||||||
@@ -196,7 +219,7 @@ get_oracle_host_id() {
|
|||||||
# If $1 looks like a dbid (contains hyphens), use it directly and skip DB lookup
|
# If $1 looks like a dbid (contains hyphens), use it directly and skip DB lookup
|
||||||
if [[ "$1" == *-* ]]; then
|
if [[ "$1" == *-* ]]; then
|
||||||
dbid="$1"
|
dbid="$1"
|
||||||
echo "INFO: Using provided dbid: $dbid"
|
log_info "Using provided dbid: $dbid"
|
||||||
|
|
||||||
gql_lookupCdmId='query OracleDatabase($fid: UUID!) {
|
gql_lookupCdmId='query OracleDatabase($fid: UUID!) {
|
||||||
oracleDatabase(fid: $fid) {
|
oracleDatabase(fid: $fid) {
|
||||||
@@ -212,12 +235,13 @@ if [[ "$1" == *-* ]]; then
|
|||||||
gqlVars="$(echo $variables)"
|
gqlVars="$(echo $variables)"
|
||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
cdmId=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabase.cluster.id')
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
|
cdmId=$(echo "$response_content" | jq -r '.data.oracleDatabase.cluster.id')
|
||||||
if [[ -z "$cdmId" ]]; then
|
if [[ -z "$cdmId" ]]; then
|
||||||
echo "ERROR: Could not find CDM ID for dbid '$dbid'"
|
log_error "Could not find CDM ID for dbid '$dbid'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "CDM ID is $cdmId"
|
log_info "CDM ID is $cdmId"
|
||||||
|
|
||||||
else
|
else
|
||||||
gql_DBListQuery='query OracleDatabases($filter: [Filter!]) {
|
gql_DBListQuery='query OracleDatabases($filter: [Filter!]) {
|
||||||
@@ -258,32 +282,55 @@ oracleDatabases(filter: $filter) {
|
|||||||
gqlVars="$(echo $variables)"
|
gqlVars="$(echo $variables)"
|
||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
dbid=$(cat /tmp/rbkresponse.$$ | jq -r --arg NODE "$node_name" '.data.oracleDatabases.nodes[] | select(.logicalPath[]?.name | test("^" + $NODE + "(\\.|$)")) | .id')
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
cdmId=$(cat /tmp/rbkresponse.$$ | jq -r --arg NODE "$node_name" '.data.oracleDatabases.nodes[] | select(.logicalPath[]?.name | test("^" + $NODE + "(\\.|$)")) | .cluster.id')
|
|
||||||
|
if [[ -n "$node_name" ]]; then
|
||||||
|
# Filter by source host if specified
|
||||||
|
dbid=$(echo "$response_content" | jq -r --arg NODE "$node_name" '.data.oracleDatabases.nodes[] | select(.logicalPath[]?.name | test("^" + $NODE + "(\\.|$)")) | .id')
|
||||||
|
cdmId=$(echo "$response_content" | jq -r --arg NODE "$node_name" '.data.oracleDatabases.nodes[] | select(.logicalPath[]?.name | test("^" + $NODE + "(\\.|$)")) | .cluster.id')
|
||||||
|
|
||||||
dbid_count=$(echo "$dbid" | grep -c .)
|
dbid_count=$(echo "$dbid" | grep -c .)
|
||||||
if [[ "$dbid_count" -ne 1 || -z "$dbid" ]]; then
|
if [[ "$dbid_count" -ne 1 || -z "$dbid" ]]; then
|
||||||
echo "ERROR: Expected exactly one database running on node '$node_name', found $dbid_count:"
|
log_error "Expected exactly one database running on node '$node_name', found $dbid_count:"
|
||||||
cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabases.nodes[] | "\(.dbUniqueName) \(.logicalPath[0].name) \(.id)"'
|
echo "$response_content" | jq -r '.data.oracleDatabases.nodes[] | "\(.dbUniqueName) \(.logicalPath[0].name) \(.id)"'
|
||||||
cleanup
|
cleanup
|
||||||
exit 4
|
exit 4
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
# No source host specified, get all matching databases
|
||||||
|
dbid=$(echo "$response_content" | jq -r '.data.oracleDatabases.nodes[].id')
|
||||||
|
cdmId=$(echo "$response_content" | jq -r '.data.oracleDatabases.nodes[].cluster.id')
|
||||||
|
|
||||||
|
dbid_count=$(echo "$dbid" | grep -c .)
|
||||||
|
if [[ "$dbid_count" -ne 1 || -z "$dbid" ]]; then
|
||||||
|
log_error "Expected exactly one database with name '$1', found $dbid_count:"
|
||||||
|
echo "$response_content" | jq -r '.data.oracleDatabases.nodes[] | "\(.dbUniqueName) \(.logicalPath[0].name) \(.id)"'
|
||||||
|
cleanup
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "DEBUG: DB ID is $dbid"
|
echo "DEBUG: DB ID is $dbid"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Only run UTC conversion if -t was used
|
# Only run UTC conversion if -t was used
|
||||||
if [[ -n "${datestring:-}" ]]; then
|
if [[ -n "${datestring:-}" ]]; then
|
||||||
utctime=$($DATE -d"$datestring" +"%Y-%m-%d %H:%M:%S")
|
# Try date first, then gdate for macOS compatibility
|
||||||
if [ $? -ne 0 ]; then
|
if ! utctime=$(date -d"$datestring" +"%Y-%m-%d %H:%M:%S" 2>/dev/null); then
|
||||||
echo ERROR: Unable to convert supplied timestamp to UTC time
|
if ! utctime=$(gdate -d"$datestring" +"%Y-%m-%d %H:%M:%S" 2>/dev/null); then
|
||||||
|
log_error "Unable to convert supplied timestamp to UTC time: $datestring"
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
unixtime=$($DATE -d"$datestring" +%s)
|
fi
|
||||||
|
|
||||||
|
# Get unixtime using the same date command that worked
|
||||||
|
if ! unixtime=$(date -d"$datestring" +%s 2>/dev/null); then
|
||||||
|
unixtime=$(gdate -d"$datestring" +%s 2>/dev/null)
|
||||||
|
fi
|
||||||
unixtime_ms=$((unixtime * 1000))
|
unixtime_ms=$((unixtime * 1000))
|
||||||
echo INFO: Requested time is $datestring which is $utctime in UTC, unixtime is $unixtime
|
log_info "Requested time is $datestring which is $utctime in UTC, unixtime is $unixtime"
|
||||||
else
|
else
|
||||||
echo INFO: No time specified, using latest PIT
|
log_info "No time specified, using latest PIT"
|
||||||
get_latest_pit
|
get_latest_pit
|
||||||
unixtime_ms=$latest_unixtime_ms
|
unixtime_ms=$latest_unixtime_ms
|
||||||
fi
|
fi
|
||||||
@@ -292,20 +339,36 @@ fi
|
|||||||
get_oracle_host_id "$targetHost"
|
get_oracle_host_id "$targetHost"
|
||||||
|
|
||||||
if [[ -z "$targetHostId" ]]; then
|
if [[ -z "$targetHostId" ]]; then
|
||||||
echo "ERROR: Could not resolve target host ID for '$targetHost'"
|
log_error "Could not resolve target host ID for '$targetHost'"
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo Target Host ID is $targetHostId
|
log_info "Target Host ID is $targetHostId"
|
||||||
|
|
||||||
cloningOptions=$(template_to_json $optionsFile)
|
cloningOptions=$(template_to_json $optionsFile)
|
||||||
|
|
||||||
|
# Optionally include numChannels in the config
|
||||||
|
if [[ -n "${numChannels:-}" ]]; then
|
||||||
|
numChannelsPart="\"numChannels\": $numChannels,"
|
||||||
|
else
|
||||||
|
numChannelsPart=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally include customPfilePath in the config
|
||||||
|
if [[ -n "${customPfilePath:-}" ]]; then
|
||||||
|
customPfilePathPart="\"customPfilePath\": \"$customPfilePath\","
|
||||||
|
else
|
||||||
|
customPfilePathPart=""
|
||||||
|
fi
|
||||||
|
|
||||||
variables="
|
variables="
|
||||||
{
|
{
|
||||||
\"input\": {
|
\"input\": {
|
||||||
\"request\": {
|
\"request\": {
|
||||||
\"id\": \"$dbid\",
|
\"id\": \"$dbid\",
|
||||||
\"config\": {
|
\"config\": {
|
||||||
|
$numChannelsPart
|
||||||
|
$customPfilePathPart
|
||||||
\"targetOracleHostOrRacId\": \"$targetHostId\",
|
\"targetOracleHostOrRacId\": \"$targetHostId\",
|
||||||
\"shouldRestoreFilesOnly\": false,
|
\"shouldRestoreFilesOnly\": false,
|
||||||
\"recoveryPoint\": {
|
\"recoveryPoint\": {
|
||||||
@@ -334,13 +397,29 @@ gqlClone='mutation OracleDatabaseExportMutation($input: ExportOracleDatabaseInpu
|
|||||||
|
|
||||||
gqlQuery="$(echo $gqlClone)"
|
gqlQuery="$(echo $gqlClone)"
|
||||||
gqlVars="$(echo $variables)"
|
gqlVars="$(echo $variables)"
|
||||||
rsc_gql_query
|
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
|
||||||
|
|
||||||
|
if [ "$dryrun" = true ]; then
|
||||||
|
echo "=== DRY-RUN MODE ==="
|
||||||
|
echo "Would execute the following GraphQL mutation:"
|
||||||
|
echo
|
||||||
|
echo "QUERY:"
|
||||||
|
echo "$gqlQuery"
|
||||||
|
echo
|
||||||
|
echo "VARIABLES:"
|
||||||
|
echo "$gqlVars" | jq .
|
||||||
|
echo
|
||||||
|
echo "=== END DRY-RUN ==="
|
||||||
|
cleanup
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
rsc_gql_query
|
||||||
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
|
echo "$response_content" | jq
|
||||||
|
|
||||||
# Save the id from the response
|
# Save the id from the response
|
||||||
job_id=$(cat /tmp/rbkresponse.$$ | jq -r '.data.exportOracleDatabase.id')
|
job_id=$(echo "$response_content" | jq -r '.data.exportOracleDatabase.id')
|
||||||
echo "DEBUG: Job id is $job_id"
|
log_info "Job id is $job_id"
|
||||||
|
|
||||||
gqlCheckStatus='query OracleDatabaseAsyncRequestDetails($input: GetOracleAsyncRequestStatusInput!) {
|
gqlCheckStatus='query OracleDatabaseAsyncRequestDetails($input: GetOracleAsyncRequestStatusInput!) {
|
||||||
oracleDatabaseAsyncRequestDetails(input: $input) {
|
oracleDatabaseAsyncRequestDetails(input: $input) {
|
||||||
@@ -368,33 +447,27 @@ gqlVars="$(echo $variables)"
|
|||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
status=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.status')
|
response_content=$(cat /tmp/rbkresponse.$$)
|
||||||
progress=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.progress')
|
status=$(echo "$response_content" | jq -r '.data.oracleDatabaseAsyncRequestDetails.status')
|
||||||
|
progress=$(echo "$response_content" | jq -r '.data.oracleDatabaseAsyncRequestDetails.progress')
|
||||||
|
|
||||||
echo "Job status: $status $progress percent"
|
log_info "Job status: $status $progress percent"
|
||||||
if [[ "$status" == "FAILED" ]]; then
|
if [[ "$status" == "FAILED" ]]; then
|
||||||
echo "Database clone FAILED"
|
log_error "Database clone FAILED"
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
echo "$response_content" | jq
|
||||||
cleanup
|
cleanup
|
||||||
exit 2
|
exit 2
|
||||||
elif [[ "$status" == "CANCELLED" ]]; then
|
elif [[ "$status" == "CANCELLED" ]]; then
|
||||||
echo "Database clone CANCELLED"
|
log_warn "Database clone CANCELLED"
|
||||||
|
cleanup
|
||||||
exit 3
|
exit 3
|
||||||
elif [[ "$status" == "SUCCEEDED" ]]; then
|
elif [[ "$status" == "SUCCEEDED" ]]; then
|
||||||
echo "Database clone SUCCEEDED"
|
log_info "Database clone SUCCEEDED"
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
echo "$response_content" | jq
|
||||||
cleanup
|
cleanup
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
sleep 15
|
sleep 15
|
||||||
|
|
||||||
done
|
|
||||||
echo "Database clone SUCCEEDED"
|
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
|
||||||
cleanup
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
sleep 15
|
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
# Options:
|
# Options:
|
||||||
# <targethost> : Host to perform refresh job
|
# <targethost> : Host to perform refresh job
|
||||||
|
|
||||||
usage() { echo "Usage: $0 <host>" 1>&2; exit 1; }
|
usage() { echo "Usage: $0 <host>" >&2; exit 1; }
|
||||||
|
|
||||||
if [[ -z "$1" ]]; then
|
if [[ -z "$1" ]]; then
|
||||||
usage
|
usage
|
||||||
@@ -18,14 +18,15 @@ fi
|
|||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
MYDIR="$(dirname "$(realpath "$0")")"
|
||||||
|
|
||||||
source $MYDIR/oracle_funcs.sh
|
# No verbose flag: log_info prints by default
|
||||||
|
|
||||||
source $MYDIR/rsc_ops.sh
|
source $MYDIR/rsc_ops.sh
|
||||||
|
|
||||||
RBK_HOST=$1
|
RBK_HOST=$1
|
||||||
|
|
||||||
rsc_get_host_id
|
rsc_get_host_id
|
||||||
|
|
||||||
echo "Host ID: $targetHostId"
|
log_info "Host ID: $targetHostId"
|
||||||
|
|
||||||
gql_refreshHost='mutation RefreshHost($input: RefreshHostInput!) {
|
gql_refreshHost='mutation RefreshHost($input: RefreshHostInput!) {
|
||||||
refreshHost(input: $input) {
|
refreshHost(input: $input) {
|
||||||
@@ -49,9 +50,9 @@ variables="{
|
|||||||
gqlQuery="$(echo $gql_refreshHost)"
|
gqlQuery="$(echo $gql_refreshHost)"
|
||||||
gqlVars="$(echo $variables)"
|
gqlVars="$(echo $variables)"
|
||||||
|
|
||||||
echo "Refreshing host $RBK_HOST (ID: $targetHostId)"
|
log_info "Refreshing host $RBK_HOST (ID: $targetHostId)"
|
||||||
|
|
||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
echo "Response:"
|
log_info "Response:"
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
cat /tmp/rbkresponse.$$ | jq
|
||||||
@@ -7,11 +7,12 @@
|
|||||||
#
|
#
|
||||||
# usage: rsc_list_slas.sh [filter]
|
# usage: rsc_list_slas.sh [filter]
|
||||||
|
|
||||||
usage() { echo "Usage: $0 [filter]" 1>&2; exit 1; }
|
usage() { echo "Usage: $0 [filter]" >&2; exit 1; }
|
||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
MYDIR="$(dirname "$(realpath "$0")")"
|
||||||
|
# log_info prints by default now; no verbose flag
|
||||||
|
|
||||||
# source $MYDIR/rbk_api.conf
|
# source $MYDIR/rbk_api.conf
|
||||||
source $MYDIR/oracle_funcs.sh
|
|
||||||
source $MYDIR/rsc_ops.sh
|
source $MYDIR/rsc_ops.sh
|
||||||
|
|
||||||
gql_SLAListQuery='query SLAListQuery($after: String, $first: Int, $filter: [GlobalSlaFilterInput!], $sortBy: SlaQuerySortByField, $sortOrder: SortOrder) {
|
gql_SLAListQuery='query SLAListQuery($after: String, $first: Int, $filter: [GlobalSlaFilterInput!], $sortBy: SlaQuerySortByField, $sortOrder: SortOrder) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
# usage: rsc_log_backup.sh [filter]
|
# usage: rsc_log_backup.sh [filter]
|
||||||
|
|
||||||
usage() { echo "Usage: $0 [filter]" 1>&2; exit 1; }
|
usage() { echo "Usage: $0 [filter]" >&2; exit 1; }
|
||||||
|
|
||||||
if [[ -z "$1" ]]; then
|
if [[ -z "$1" ]]; then
|
||||||
usage
|
usage
|
||||||
@@ -15,8 +15,8 @@ fi
|
|||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
MYDIR="$(dirname "$(realpath "$0")")"
|
||||||
|
|
||||||
|
# log_info prints by default now; no verbose flag
|
||||||
# source $MYDIR/rbk_api.conf
|
# source $MYDIR/rbk_api.conf
|
||||||
source $MYDIR/oracle_funcs.sh
|
|
||||||
source $MYDIR/rsc_ops.sh
|
source $MYDIR/rsc_ops.sh
|
||||||
|
|
||||||
gql_DBListQuery='query OracleDatabases($filter: [Filter!]) {
|
gql_DBListQuery='query OracleDatabases($filter: [Filter!]) {
|
||||||
@@ -58,13 +58,13 @@ cdmId=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabases.nodes[] | .cluste
|
|||||||
# Check for multiple dbids
|
# Check for multiple dbids
|
||||||
dbid_count=$(echo "$dbid" | wc -l)
|
dbid_count=$(echo "$dbid" | wc -l)
|
||||||
if [[ "$dbid_count" -ne 1 || -z "$dbid" ]]; then
|
if [[ "$dbid_count" -ne 1 || -z "$dbid" ]]; then
|
||||||
echo "ERROR: Expected exactly one database match! found:"
|
log_error "Expected exactly one database match! found:"
|
||||||
cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabases.nodes[] | .dbUniqueName'
|
cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabases.nodes[] | .dbUniqueName'
|
||||||
cleanup
|
cleanup
|
||||||
exit 4
|
exit 4
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "DEBUG: DB ID is $dbid"
|
log_info "DB ID is $dbid"
|
||||||
variables="{
|
variables="{
|
||||||
\"input\": {
|
\"input\": {
|
||||||
\"id\": \"$dbid\"
|
\"id\": \"$dbid\"
|
||||||
@@ -82,8 +82,8 @@ gqlVars="$(echo $variables)"
|
|||||||
rsc_gql_query
|
rsc_gql_query
|
||||||
|
|
||||||
# Save the id from the response
|
# Save the id from the response
|
||||||
|
log_info "Log backup job id: $(cat /tmp/rbkresponse.$$ | jq -r '.data.takeOnDemandOracleLogSnapshot.id')"
|
||||||
log_backup_id=$(cat /tmp/rbkresponse.$$ | jq -r '.data.takeOnDemandOracleLogSnapshot.id')
|
log_backup_id=$(cat /tmp/rbkresponse.$$ | jq -r '.data.takeOnDemandOracleLogSnapshot.id')
|
||||||
echo "DEBUG: Job id is $log_backup_id"
|
|
||||||
|
|
||||||
gqlCheckStatus='query OracleDatabaseAsyncRequestDetails($input: GetOracleAsyncRequestStatusInput!) {
|
gqlCheckStatus='query OracleDatabaseAsyncRequestDetails($input: GetOracleAsyncRequestStatusInput!) {
|
||||||
oracleDatabaseAsyncRequestDetails(input: $input) {
|
oracleDatabaseAsyncRequestDetails(input: $input) {
|
||||||
@@ -114,17 +114,17 @@ while true; do
|
|||||||
status=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.status')
|
status=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.status')
|
||||||
progress=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.progress')
|
progress=$(cat /tmp/rbkresponse.$$ | jq -r '.data.oracleDatabaseAsyncRequestDetails.progress')
|
||||||
|
|
||||||
echo "Job status: $status $progress percent"
|
log_info "Job status: $status $progress percent"
|
||||||
if [[ "$status" == "FAILED" ]]; then
|
if [[ "$status" == "FAILED" ]]; then
|
||||||
echo "Log backup FAILED"
|
log_error "Log backup FAILED"
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
cat /tmp/rbkresponse.$$ | jq
|
||||||
cleanup
|
cleanup
|
||||||
exit 2
|
exit 2
|
||||||
elif [[ "$status" == "CANCELLED" ]]; then
|
elif [[ "$status" == "CANCELLED" ]]; then
|
||||||
echo "Log backup CANCELLED"
|
log_warn "Log backup CANCELLED"
|
||||||
exit 3
|
exit 3
|
||||||
elif [[ "$status" == "SUCCEEDED" ]]; then
|
elif [[ "$status" == "SUCCEEDED" ]]; then
|
||||||
echo "Log backup SUCCEEDED"
|
log_info "Log backup SUCCEEDED"
|
||||||
cat /tmp/rbkresponse.$$ | jq
|
cat /tmp/rbkresponse.$$ | jq
|
||||||
cleanup
|
cleanup
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
128
rsc_ops.sh
128
rsc_ops.sh
@@ -8,15 +8,97 @@
|
|||||||
#--------------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
MYDIR="$(dirname "$(realpath "$0")")"
|
MYDIR="$(dirname "$(realpath "$0")")"
|
||||||
#source $MYDIR/rbk_api.conf
|
|
||||||
|
# Logging helpers
|
||||||
|
log_info() {
|
||||||
|
echo "INFO: $*"
|
||||||
|
}
|
||||||
|
log_warn() {
|
||||||
|
echo "WARN: $*" >&2
|
||||||
|
}
|
||||||
|
log_error() {
|
||||||
|
echo "ERROR: $*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure required commands are available
|
||||||
|
require_cmds() {
|
||||||
|
local miss=0
|
||||||
|
for cmd in jq curl; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
log_error "Required command '$cmd' not found in PATH"
|
||||||
|
miss=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$miss" -ne 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
require_cmds
|
||||||
|
|
||||||
|
# Load and validate RSC configuration from rsc.json
|
||||||
|
if [ -f "$MYDIR/rsc.json" ]; then
|
||||||
|
RSC_ID=$(jq -r '.client_id // empty' "$MYDIR/rsc.json")
|
||||||
|
RSC_SECRET=$(jq -r '.client_secret // empty' "$MYDIR/rsc.json")
|
||||||
|
ACCESS_TOKEN_URI=$(jq -r '.access_token_uri // empty' "$MYDIR/rsc.json")
|
||||||
|
|
||||||
|
if [ -z "${RSC_ID}" ] || [ -z "${RSC_SECRET}" ] || [ -z "${ACCESS_TOKEN_URI}" ]; then
|
||||||
|
log_error "rsc.json is missing required fields: client_id, client_secret or access_token_uri"
|
||||||
|
log_error "Please populate $MYDIR/rsc.json (see rsc.json.example)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Derive host from access token URI and normalize
|
||||||
|
RSC_HOST=$(echo "$ACCESS_TOKEN_URI" | sed 's|https://||' | sed 's|/api/client_token||')
|
||||||
|
|
||||||
|
# Restrict config file permissions
|
||||||
|
if [ -f "$MYDIR/rsc.json" ]; then
|
||||||
|
chmod 600 "$MYDIR/rsc.json" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Loaded RSC configuration for host: $RSC_HOST"
|
||||||
|
else
|
||||||
|
log_error "rsc.json configuration file not found at $MYDIR/rsc.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set DATE command based on available binaries (prefer gdate if installed)
|
||||||
|
if command -v gdate >/dev/null 2>&1; then
|
||||||
|
DATE=gdate
|
||||||
|
else
|
||||||
|
DATE=date
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Utility functions
|
||||||
|
exit_with_error () {
|
||||||
|
rm -f /tmp/rbkresponse.$$
|
||||||
|
echo Aborting Script!
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup () {
|
||||||
|
rm -f /tmp/mountedDBs.$$
|
||||||
|
rm -f /tmp/rbkresponse.$$
|
||||||
|
rm -f /tmp/payload.$$
|
||||||
|
}
|
||||||
|
|
||||||
|
check_http_error () {
|
||||||
|
# All good responses start with a 2
|
||||||
|
if [ ${http_response:0:1} != "2" ]; then
|
||||||
|
log_error "HTTP error from API call: $http_response"
|
||||||
|
# Show a short excerpt of the response body for debugging
|
||||||
|
head -c 4096 /tmp/rbkresponse.$$ 2>/dev/null || true
|
||||||
|
echo
|
||||||
|
exit_with_error
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
check_get_rsc_token () {
|
check_get_rsc_token () {
|
||||||
|
|
||||||
if [ -z "${RSC_AUTH_TOKEN}" ]; then
|
if [ -z "${RSC_AUTH_TOKEN}" ]; then
|
||||||
|
|
||||||
if [[ "${ID}" =~ ^client ]]; then
|
if [[ "${RSC_ID}" =~ ^client ]]; then
|
||||||
# Looks like an RSC service account
|
# Looks like an RSC service account
|
||||||
id_string=$(echo $ID | cut -d\| -f 2)
|
id_string=$(echo $RSC_ID | cut -d\| -f 2)
|
||||||
else
|
else
|
||||||
# Not an RSC service account
|
# Not an RSC service account
|
||||||
exit_with_error
|
exit_with_error
|
||||||
@@ -40,7 +122,7 @@ check_get_rsc_token () {
|
|||||||
get_rsc_token () {
|
get_rsc_token () {
|
||||||
|
|
||||||
MYENDPOINT="https://${RSC_HOST}/api/client_token"
|
MYENDPOINT="https://${RSC_HOST}/api/client_token"
|
||||||
MYPAYLOAD="{\"client_id\":\"$ID\",\"client_secret\":\"$SECRET\"}"
|
MYPAYLOAD="{\"client_id\":\"$RSC_ID\",\"client_secret\":\"$RSC_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
|
||||||
@@ -48,8 +130,11 @@ get_rsc_token () {
|
|||||||
RSC_AUTH_TOKEN=$(cat /tmp/rbkresponse.$$ | jq -r '.access_token')
|
RSC_AUTH_TOKEN=$(cat /tmp/rbkresponse.$$ | jq -r '.access_token')
|
||||||
SECONDS=$(cat /tmp/rbkresponse.$$ | jq -r '.expires_in')
|
SECONDS=$(cat /tmp/rbkresponse.$$ | jq -r '.expires_in')
|
||||||
EXPIRATION=$($DATE +%s -d "+${SECONDS} seconds")
|
EXPIRATION=$($DATE +%s -d "+${SECONDS} seconds")
|
||||||
#cat /tmp/rbkresponse.$$ | jq
|
# Save session securely
|
||||||
echo "$EXPIRATION $RSC_AUTH_TOKEN" > ~/.rbkRscsession.$id_string
|
umask 077
|
||||||
|
printf '%s %s\n' "$EXPIRATION" "$RSC_AUTH_TOKEN" > ~/.rbkRscsession.$id_string
|
||||||
|
chmod 600 ~/.rbkRscsession.$id_string 2>/dev/null || true
|
||||||
|
log_info "Cached RSC session to ~/.rbkRscsession.$id_string"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +184,11 @@ EOF
|
|||||||
#cat /tmp/payload.$$ | jq -r
|
#cat /tmp/payload.$$ | jq -r
|
||||||
error=$(cat /tmp/rbkresponse.$$ | jq -r '.errors // empty')
|
error=$(cat /tmp/rbkresponse.$$ | jq -r '.errors // empty')
|
||||||
if [ "$error" ]; then
|
if [ "$error" ]; then
|
||||||
echo "ERROR: The last GraphQL API call returned an error"
|
log_error "The last GraphQL API call returned an error"
|
||||||
echo
|
echo
|
||||||
echo "PAYLOAD:"
|
log_error "PAYLOAD:"
|
||||||
cat /tmp/payload.$$ | jq -r
|
cat /tmp/payload.$$ | jq -r
|
||||||
echo "RESPONSE:"
|
log_error "RESPONSE:"
|
||||||
cat /tmp/rbkresponse.$$ | jq -r '.errors'
|
cat /tmp/rbkresponse.$$ | jq -r '.errors'
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
@@ -131,12 +216,21 @@ rsc_get_host_id() {
|
|||||||
# Get all matching host IDs (portable, no mapfile)
|
# Get all matching host IDs (portable, no mapfile)
|
||||||
host_ids=$(cat /tmp/rbkresponse.$$ | jq -r '.data.physicalHosts.nodes[] | .id')
|
host_ids=$(cat /tmp/rbkresponse.$$ | jq -r '.data.physicalHosts.nodes[] | .id')
|
||||||
host_count=$(echo "$host_ids" | grep -c .)
|
host_count=$(echo "$host_ids" | grep -c .)
|
||||||
if [[ $host_count -ne 1 ]]; then
|
|
||||||
echo "ERROR: Multiple hosts found for '$1':"
|
if [[ $host_count -eq 0 ]]; then
|
||||||
cat /tmp/rbkresponse.$$ | jq -r '.data.physicalHosts.nodes[] | "\(.name) \(.id)"'
|
log_error "Host '$RBK_HOST' not found by exact match (this script requires an exact host name)."
|
||||||
|
log_error "Please re-run with the exact host name as stored in RSC."
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
# Set the first match (or empty if none)
|
|
||||||
|
if [[ $host_count -gt 1 ]]; then
|
||||||
|
log_error "Multiple hosts found for '$RBK_HOST':"
|
||||||
|
cat /tmp/rbkresponse.$$ | jq -r '.data.physicalHosts.nodes[] | "\(.name) \(.id)"'
|
||||||
|
log_error "Please re-run with the exact host name to disambiguate."
|
||||||
|
exit_with_error
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Exactly one match: set the first match
|
||||||
targetHostId=$(echo "$host_ids" | head -n 1)
|
targetHostId=$(echo "$host_ids" | head -n 1)
|
||||||
|
|
||||||
#cat /tmp/rbkresponse.$$ | jq -r
|
#cat /tmp/rbkresponse.$$ | jq -r
|
||||||
@@ -153,7 +247,7 @@ rsc_find_database () {
|
|||||||
get_cluster_uuid
|
get_cluster_uuid
|
||||||
#echo Cluster UUID is $cluster_uuid
|
#echo Cluster UUID is $cluster_uuid
|
||||||
else
|
else
|
||||||
echo Cluster UUID was already $cluster_uuid
|
log_info "Cluster UUID was already $cluster_uuid"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
variables="{
|
variables="{
|
||||||
@@ -319,7 +413,7 @@ if [ $num -eq 1 ]; then
|
|||||||
read name rsc_db_id < <(echo $(cat /tmp/rbkresponse.$$ | jq -r '.data.globalSearchResults.edges[] | select (.node.objectType=="ORACLE_DATA_GUARD_GROUP" and .node.isRelic==false)| .node.name, .node.id'))
|
read name rsc_db_id < <(echo $(cat /tmp/rbkresponse.$$ | jq -r '.data.globalSearchResults.edges[] | select (.node.objectType=="ORACLE_DATA_GUARD_GROUP" and .node.isRelic==false)| .node.name, .node.id'))
|
||||||
database_type="Data Guard"
|
database_type="Data Guard"
|
||||||
elif [ $num -gt 1 ]; then
|
elif [ $num -gt 1 ]; then
|
||||||
echo "ERROR: There were $num entries returned for Data Guard databases with name $RBK_SID"
|
log_error "There were $num entries returned for Data Guard databases with name $RBK_SID"
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -333,7 +427,7 @@ if [ -z "$rsc_db_id" ]; then
|
|||||||
database_type="Standalone"
|
database_type="Standalone"
|
||||||
#echo Good, There is just one Standalone DB with name $name and RSC ID $rsc_db_id
|
#echo Good, There is just one Standalone DB with name $name and RSC ID $rsc_db_id
|
||||||
else
|
else
|
||||||
echo "ERROR: There were $num entries returned from JQ for DB with name $RBK_SID on host $RBK_HOST"
|
log_error "There were $num entries returned from JQ for DB with name $RBK_SID on host $RBK_HOST"
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -343,7 +437,7 @@ if [ -z "$rsc_db_id" ]; then
|
|||||||
database_type="Standalone"
|
database_type="Standalone"
|
||||||
#echo Good, There is just one Standalone DB with name $name on ${RBK_HOST} and RSC ID $rsc_db_id
|
#echo Good, There is just one Standalone DB with name $name on ${RBK_HOST} and RSC ID $rsc_db_id
|
||||||
else
|
else
|
||||||
echo "ERROR: There were $num entries returned from for DB with name $RBK_SID on host $RBK_HOST"
|
log_error "There were $num entries returned from for DB with name $RBK_SID on host $RBK_HOST"
|
||||||
exit_with_error
|
exit_with_error
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user