From 260689d7aa4b1c82d12ad952433a294df27d5bc2 Mon Sep 17 00:00:00 2001 From: James Pattinson Date: Fri, 3 Oct 2025 05:09:37 -0400 Subject: [PATCH] first commit --- README.md | 0 oracle_funcs.sh | 368 ++++++++++++++++++++++++++++++++++++++++++++++++ oracle_mount.sh | 287 +++++++++++++++++++++++++++++++++++++ 3 files changed, 655 insertions(+) create mode 100644 README.md create mode 100644 oracle_funcs.sh create mode 100644 oracle_mount.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/oracle_funcs.sh b/oracle_funcs.sh new file mode 100644 index 0000000..17d5d44 --- /dev/null +++ b/oracle_funcs.sh @@ -0,0 +1,368 @@ +#!/bin/bash +# +# Oracle shell script support functions +# v0.2 - James Pattinson - March 2022 + +nowait=0 + +LOGFILE=/tmp/rubrik_oracle.log +tabwidth=25 + +os=$(uname -o) +if [ $os == "Solaris" ]; then + # Use the GNU version of date binary + DATE=/usr/gnu/bin/date +else + DATE=$(which date) +fi + +echo "`$DATE` -$$-: CALLED $0 $@" >> $LOGFILE + +trap ctrl_c INT + +function ctrl_c () { + echo "`$DATE` -$$-: TRAPPED CTRL-C - EXITING" >> $LOGFILE + exit_with_error +} + +function ctrl_c_inhibit () { + echo "`$DATE` -$$-: TRAPPED CTRL-C - CONTINUING" >> $LOGFILE +} + +exit_with_error () { +# if [ $usingsatoken ]; then +# ENDPOINT="https://$RUBRIK_IP/api/v1/session/me" +# rest_api_delete +# check_http_error +# fi + rm -f /tmp/rbkresponse.$$ + rm -f /tmp/mountedDBs.$$ + echo Aborting Script! + echo "`$DATE` -$$-: EXITED WITH ERROR $0 $@" >> $LOGFILE + 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 +} + +resolve_db () { + +read name db_id sla_id dg_type dg_id RBK_HOST num_instances grp_name rac_name last_snap isrelic < <(echo $(cat /tmp/rbkresponse.$$ | jq -r --arg ID "OracleDatabase:::$id" '.data[] | select(.id==$ID) | .name, .id, .effectiveSlaDomainId, .dataGuardType, .dataGuardGroupId, .instances[0].hostName, .numInstances, .dataGuardGroupName, .racName, .lastSnapshotTime, .isRelic')) +if [ "$dg_id" != "null" ]; then + if [ "$last_snap" != "null" ]; then + [[ $rac_name != "null" ]] && string=$rac_name || string=$RBK_HOST + echo "WARNING: DG member on $string has snapshots created when DB was protected as standalone (non DG)" + echo "WARNING: Latest standalone snapshot taken $last_snap. Use -h $string to view or utilise them" + fi + id=$(echo $dg_id | cut -d: -f 4) + if [[ ! " ${DGDBs[*]} " =~ " ${id} " ]]; then + DGDBs+=("$id") + fi +else + actualDBs+=("$id") +fi + +} + +show_all_dbs () { + +liveDBs=() +liveDBsWithSnaps=() + +for id in "${actualDBs[@]}"; do +# cat /tmp/rbkresponse.$$ | jq -r + read name db_id sla_id dg_type dg_id RBK_HOST num_instances grp_name rac_name isrelic standaloneHostName last_snap db_unique_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, .racName, .isRelic, .standaloneHostName, .lastSnapshotTime, .dbUniqueName')) + echo -n "WARNING: Object ID $id on " + [[ $standaloneHostName != "null" ]] && echo -n "host $standaloneHostName " + [[ $rac_name != "null" ]] && echo -n "RAC $rac_name " + [[ $grp_name != "null" ]] && echo "DG ID: $grp_name" + [[ $isrelic = "true" ]] && echo -n "(Relic)" || liveDBs+=("$id") + [[ $last_snap != "null" ]] && [[ $isrelic = "false" ]] && liveDBsWithSnaps+=("$id") + echo +done + +#declare -p liveDBs +#declare -p liveDBsWithSnaps + +for id in "${DGDBs[@]}"; do + echo -n "WARNING: Object ID $id on DG Group " + ENDPOINT="https://$RUBRIK_IP/api/v1/oracle/db/OracleDatabase:::$id" + rest_api_get_2 + dgname=$(cat /tmp/rbkresponse2.$$ | jq -r '.dbUniqueName') + rm -f /tmp/rbkresponse2.$$ + echo $dgname +done + +} + +select_db () { + +# We have more than one matching DB. Select the best one +if [ "${#DGDBs[@]}" -eq 1 ]; then + echo WARNING: Selecting Data Guard DB ${DGDBs[0]} + id="${DGDBs[0]}" +elif [ "${#liveDBs[@]}" -eq 1 ]; then + echo WARNING: Selecting object ID ${liveDBs[0]} as it is not a Relic + id="${liveDBs[0]}" +elif [ "${#liveDBsWithSnaps[@]}" -eq 1 ]; then + echo WARNING: Selecting object ID ${liveDBsWithSnaps[0]} as it is not a Relic and has snapshots + id="${liveDBsWithSnaps[0]}" +else + echo "ERROR: Unable to determine unique DB. Please specify one of the above" + exit_with_error +fi + +read name db_id sla_id dg_type dg_id RBK_HOST num_instances grp_name rac_name isrelic standaloneHostName last_snap < <(echo $(cat /tmp/rbkresponse.$$ | jq -r --arg ID "OracleDatabase:::$id" '.data[] | select(.id==$ID or .dataGuardGroupId==$ID) | .name, .id, .effectiveSlaDomainId, .dataGuardType, .dataGuardGroupId, .instances[0].hostName, .numInstances, .dataGuardGroupName, .racName, .isRelic, .standaloneHostName, .lastSnapshotTime')) + +#exit_with_error + + +} + +# Given RBK_SID return $db_id of matching database +find_database () { + + specifiedhost=$RBK_HOST + + # 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 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) | .id' | sort | uniq) + myDGs=$(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.name==$SID) | .dataGuardGroupId' | sort | uniq) + + for db in $myDBs $myDGs; do + id=$(echo $db | cut -d: -f 4) + if grep -q $id /tmp/mountedDBs.$$; then + continue + else + break + fi + done + + myDBs=( $(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.name==$SID) | .id' | sort | uniq) ) + myDGs=( $(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" '.data[] | select(.name==$SID) | .dataGuardGroupId' | sort | uniq) ) + actualDBs=() + DGDBs=() + + for db in "${myDBs[@]}"; do + id=$(echo $db | cut -d: -f 4) + resolve_db + done + if [ "$(( ${#actualDBs[@]} + ${#DGDBs[@]} ))" -gt 1 ]; then + echo "WARNING: There are multiple instances of $RBK_SID. Please re run the script with the -h option" + echo "WARNING: to interact with them. Script will attempt to select the correct DB." + show_all_dbs + select_db + else + id="${actualDBs[0]}" + fi + + + else + # Host was specified + hostspecified=true + read name db_id sla_id dg_type dg_id RBK_HOST racname num_instances grp_name < <(echo $(cat /tmp/rbkresponse.$$ | jq -r --arg SID "$RBK_SID" --arg HOST "$RBK_HOST" '.data[] | select(.name==$SID and (.infraPath[0].name==$HOST or .dataGuardGroupName==$HOST)) | .name, .id, .effectiveSlaDomainId, .dataGuardType, .dataGuardGroupId, .standaloneHostName, .racName, .numInstances, .dataGuardGroupName')) + fi + + if [ "$RBK_HOST" = "null" ] && [ "$racname" != "null" ]; then + RBK_HOST=$racname + fi + + if [ "$dg_type" == "DataGuardMember" ] && [ "$hostspecified" != "true" ] || [[ "$specifiedhost" == DG_GROUP* ]]; 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 + locate_mv_db + fi + + if [ -z "$db_id" ]; then + echo FATAL: No DB found with SID $RBK_SID on host / cluster $RBK_HOST + exit_with_error + fi +} + +locate_mv_db () { + + # Look for a pair of MVs with names like $RBK_SID_data and $RBK_SID_logs + + # Get list of MVs + ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume" + rest_api_get + + mvData=$(cat /tmp/rbkresponse.$$ | jq -r --arg NAME ${RBK_SID}_data '.data[] | select(.name==$NAME)| .id') + mvLogs=$(cat /tmp/rbkresponse.$$ | jq -r --arg NAME ${RBK_SID}_logs '.data[] | select(.name==$NAME)| .id') + + if [ -n "$mvData" ] && [ -n "$mvLogs" ]; then + echo "INFO: MV found (Solaris Database)" + db_id=ManagedVolume + fi + +} + +check_get_token () { + + if [ -z "${AUTH_TOKEN}" ]; then + + 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 -d $expiration) -lt $(( $($DATE +%s) + 7200 )) ]; then + echo "`$DATE` -$$-: AUTH TOKEN EXPIRED" >> $LOGFILE + get_token + else + AUTH_TOKEN=$token + fi + else + get_token + fi + fi +} + +get_token () { + + trap '' INT + echo "`$DATE` -$$-: AUTH USER $ID" >> $LOGFILE + 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 "`$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 +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") + echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE + echo "`$DATE` -$$-: REST API GET: RESPONSE STARTS" >> $LOGFILE + cat /tmp/rbkresponse.$$ >> $LOGFILE + echo >> $LOGFILE + echo "`$DATE` -$$-: REST API GET: RESPONSE ENDS" >> $LOGFILE + check_http_error +} + +rest_api_get_2 () { + 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") + echo "`$DATE` -$$-: REST API GET: ENDPOINT $ENDPOINT" >> $LOGFILE + echo "`$DATE` -$$-: REST API GET: RESPONSE STARTS" >> $LOGFILE + cat /tmp/rbkresponse2.$$ >> $LOGFILE + echo >> $LOGFILE + echo "`$DATE` -$$-: REST API GET: RESPONSE ENDS" >> $LOGFILE + 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) + echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: PAYLOAD $PAYLOAD" >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: RESPONSE STARTS" >> $LOGFILE + cat /tmp/rbkresponse.$$ >> $LOGFILE + echo >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: RESPONSE ENDS" >> $LOGFILE + 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") + echo "`$DATE` -$$-: REST API POST: ENDPOINT $ENDPOINT" >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: PAYLOAD " >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: RESPONSE STARTS" >> $LOGFILE + cat /tmp/rbkresponse.$$ >> $LOGFILE + echo >> $LOGFILE + echo "`$DATE` -$$-: REST API POST: RESPONSE ENDS" >> $LOGFILE + 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") + echo "`$DATE` -$$-: REST API PATCH: ENDPOINT $ENDPOINT" >> $LOGFILE + echo "`$DATE` -$$-: REST API PATCH: PAYLOAD $PAYLOAD" >> $LOGFILE + echo "`$DATE` -$$-: REST API PATCH: RESPONSE STARTS" >> $LOGFILE + cat /tmp/rbkresponse.$$ >> $LOGFILE + echo >> $LOGFILE + echo "`$DATE` -$$-: REST API PATCH: RESPONSE ENDS" >> $LOGFILE + 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") + echo "`$DATE` -$$-: REST API DELETE: $http_response: ENDPOINT $ENDPOINT" >> $LOGFILE + check_http_error +} + +# 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" ]; then + echo Status is $status, checking in 30 seconds + else + if [ $status != "SUCCEEDED" ]; then + echo OPERATION FAILED WITH STATUS $status + exit_with_error + else + echo OPERATION SUCCEEDED + return + fi + fi + sleep 30 + done + else + # Show the Job ID + JOB_ID=$(cat /tmp/rbkresponse.$$ | jq -r '.id') + echo "Job submittsed. For more details of the job run:" + echo "oracle_jobs.sh -d $RBK_SID -j $JOB_ID" + echo "RMAN logs, if applioable, will be in /var/log/rubrik/script_logs/" + fi +} + +cleanup () { +# if [ $usingsatoken ]; then +# ENDPOINT="https://$RUBRIK_IP/api/v1/session/me" +# rest_api_delete +# fi + echo "`$DATE` -$$-: EXITED $0 $@" >> $LOGFILE + rm -f /tmp/mountedDBs.$$ + rm -f /tmp/rbkresponse.$$ +} diff --git a/oracle_mount.sh b/oracle_mount.sh new file mode 100644 index 0000000..d321bd7 --- /dev/null +++ b/oracle_mount.sh @@ -0,0 +1,287 @@ +#!/bin/bash +# +# Perform a Live Mount of an Oracle DB +# v0.2 - James Pattinson - August 2021 +# +# usage: oracle_mount.sh [-h ] [-d [-f] <"timestamp"> +# +# -d specify $ORACLE_HOME on target - needed for mount of Data Guard DBs +# default is to performing a files-only mount +# -l mount and create DB Live Mount +# +# Timestamp YYYY-MM-DD HH:MM:SS +# Time is passed to 'date' on THIS machine, will use local timezone + +MYDIR="$(dirname "$(realpath "$0")")" +source $MYDIR/rbk_api.conf +source $MYDIR/oracle_funcs.sh + +# Local commands to mount and unmount NFS volumes +MOUNT="sudo /usr/local/sysadmin/utils/manage_rubrik_restore_mvs.ksh" +UMOUNT="sudo /usr/local/sysadmin/utils/manage_rubrik_restore_mvs.ksh" + +usage() { echo "Usage: $0 <-d DBNAME> <-t \"timestamp\"> <-g tgthost || -r rachost> [-h ] [-o ] [-m [-l|-n]" 1>&2; exit 1; } + +filesonly=true + +while getopts "d:t:g:r:m:h:o:ln" o; do + case "${o}" in + d) + RBK_SID=${OPTARG} + ;; + t) + datestring=${OPTARG} + ;; + g) + RBK_TGT=${OPTARG} + ;; + r) + RAC_TGT=${OPTARG} + ;; + m) + mountpoint=${OPTARG} + ;; + h) + RBK_HOST=${OPTARG} + ;; + o) + oraclehome=${OPTARG} + ;; + l) + filesonly=false + ;; + n) + nowait=true + ;; + + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +if [ -z "${RBK_SID}" ] || [ -z "${datestring}" ]; then + usage +fi + +#if [ -z "${RAC_TGT}" ] && [ -z "${RBK_TGT}" ]; then +# usage +#fi + +if [ -n "${RBK_TGT}" ] && [ -n "${RAC_TGT}" ]; then + echo "ERROR: Specify either -g or -r, not both" + usage +fi + +if [ -z "${mountpoint}" ]; then + mountpoint=/rbk +fi + +echo Connecting to Rubrik with IP $RUBRIK_IP + +# API call to list Oracle DBs +find_database + +mount_mv () { + + utctime=$($DATE -d"$datestring" +"%Y-%m-%d %H:%M:%S") + if [ $? -ne 0 ]; then + echo ERROR: Unable to convert supplied timestamp to UTC time + exit_with_error + fi + echo INFO: Requested time is $datestring which is $utctime in UTC + + ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume/$mvData/snapshot" + rest_api_get + + # Select snapshot of data volume with timestamp before requested time + read mvDataSnap dtDataSnap < <(echo $(jq -r --arg t "$utctime" ' + [($t) | strptime("%Y-%m-%d %H:%M:%S")] as $r + | .data | map(select( + (.date[:19] | strptime("%Y-%m-%dT%H:%M:%S")) as $d + | $d <= $r[0] + )) | sort_by(.date) | last | "\(.id) \(.date)"' /tmp/rbkresponse.$$)) + + echo Snapshot ID to mount is $mvDataSnap from $dtDataSnap + + # List MVs for logs volume + ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume/$mvLogs/snapshot" + rest_api_get + + # Select snapshot of logs volume with timestamp after requested time + read mvLogsSnap dtLogsSnap < <(echo $(jq -r --arg t "$utctime" ' + [($t) | strptime("%Y-%m-%d %H:%M:%S")] as $r + | .data | map(select( + (.date[:19] | strptime("%Y-%m-%dT%H:%M:%S")) as $d + | $d >= $r[0] + )) | sort_by(.date) | first | "\(.id) \(.date)"' /tmp/rbkresponse.$$)) + + echo Snapshot ID of Logs Volume to mount is $mvLogsSnap from $dtLogsSnap + + if [ -z "${RBK_TGT}" ]; then + clients=$(hostname) + echo INFO: hostname $clients is not fully qualified, adding domain name to it. Use -g flag to override client name pattern + clients=$(hostname).$(domainname) + else + clients=${RBK_TGT} + fi + + PAYLOAD="{\"hostPatterns\":[\"$clients\"]}" + + ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume/snapshot/$mvDataSnap/export" + rest_api_post + DATA_ENDPOINT=$(cat /tmp/rbkresponse.$$ | jq -r '.links[0].href') + + ENDPOINT="https://$RUBRIK_IP/api/internal/managed_volume/snapshot/$mvLogsSnap/export" + rest_api_post + LOGS_ENDPOINT=$(cat /tmp/rbkresponse.$$ | jq -r '.links[0].href') + + datajobdone=0 + logsjobdone=0 + + while true; do + if [ $datajobdone -eq 0 ]; then + ENDPOINT=$DATA_ENDPOINT + rest_api_get + datastatus=$(cat /tmp/rbkresponse.$$ | jq -r '.status') + echo "INFO: Data Mount status is $datastatus" + if [[ $datastatus =~ SUCCEEDED|FAILED|CANCELED ]]; then + datajobdone=1 + dataExport=$(cat /tmp/rbkresponse.$$ | jq -r ' .links | .[] | select(.rel=="result") .href') + fi + fi + + if [ $logsjobdone -eq 0 ]; then + ENDPOINT=$LOGS_ENDPOINT + rest_api_get + logsstatus=$(cat /tmp/rbkresponse.$$ | jq -r '.status') + echo "INFO: Logs Mount status is $logsstatus" + if [[ $logsstatus =~ SUCCEEDED|FAILED|CANCELED ]]; then + logsjobdone=1 + logsExport=$(cat /tmp/rbkresponse.$$ | jq -r ' .links | .[] | select(.rel=="result") .href') + fi + fi + + if [ $logsjobdone -eq 1 ] && [ $datajobdone -eq 1 ]; then + echo Data Export details + ENDPOINT=$dataExport + rest_api_get + dataMounts=$(cat /tmp/rbkresponse.$$ | jq -r '.channels[] | ( .ipAddress + ":" + .mountPoint)') + ENDPOINT=$logsExport + rest_api_get + logMounts=$(cat /tmp/rbkresponse.$$ | jq -r '.channels[] | ( .ipAddress + ":" + .mountPoint)') + for mountPath in $dataMounts $logMounts; do + leaf=$(echo $mountPath | cut -d/ -f4) + echo creating folder and mounting $mountPath at $mountpoint/$RBK_SID/$leaf + mkdir -p $mountpoint/$RBK_SID/$leaf + $MOUNT $mountPath $mountpoint/$RBK_SID/$leaf + done + + cleanup + exit + else + sleep 10 + fi + done + +} + +mount_snappable () { + + if [ "$dg_type" == "DataGuardMember" ]; then + echo Initiating mount from source $RBK_SID \($grp_name\) + else + [[ $rac_name != "null" ]] && [[ -n "$rac_name" ]] && string=$rac_name || string=$RBK_HOST + echo Initiating mount from source $RBK_SID on $string + fi + + if [ -n "${RBK_TGT}" ]; then + # API call to get the host ID of the target + ENDPOINT="https://$RUBRIK_IP/api/internal/oracle/host?name=$RBK_TGT" + rest_api_get + + total=$(cat /tmp/rbkresponse.$$ | jq -r .total) + if [ $total -ne 1 ]; then + echo ERROR: Target host name of $RBK_TGT does not map to a single host. + echo ERROR: Matching hosts are listed here. Please re-run using one of the following: + cat /tmp/rbkresponse.$$ | jq -r '.data[].name' + exit_with_error + fi + + target_id=$(cat /tmp/rbkresponse.$$ | jq -r '.data[0].id') + else + # API call to get the host ID of the target + ENDPOINT="https://$RUBRIK_IP/api/internal/oracle/rac?name=$RAC_TGT" + rest_api_get + + total=$(cat /tmp/rbkresponse.$$ | jq -r .total) + if [ $total -ne 1 ]; then + echo ERROR: Target RAC Cluster name of $RAC_TGT does not map to a single entity: + echo ERROR: Matching clusters are listed here. Please re-run using one of the following: + cat /tmp/rbkresponse.$$ | jq -r '.data[].name' + exit_with_error + fi + + target_id=$(cat /tmp/rbkresponse.$$ | jq -r '.data[0].id') + fi + + # convert datestamp from string into milliseconds + echo requested timestamp is $datestring + + ts=$(date -d"$datestring" +%s) + if [ $? -ne 0 ]; then + echo Problem with timestamp + exit_with_error + fi + ((millis = $ts * 1000)) + + if [ ! -z ${oraclehome+x} ]; then + configmap="\"ORACLE_HOME\":\"$oraclehome\"" + fi + + # API call to perform the mount + PAYLOAD="{\"recoveryPoint\":{\"timestampMs\":$millis},\"targetOracleHostOrRacId\":\"$target_id\",\"targetMountPath\":\"$mountpoint\",\"shouldMountFilesOnly\":$filesonly,\"advancedRecoveryConfigMap\":{$configmap}}" + ENDPOINT="https://$RUBRIK_IP/api/internal/oracle/db/$db_id/mount" + + rest_api_post + + ENDPOINT=$(cat /tmp/rbkresponse.$$ | jq -r '.links[0].href') + LOOP=0 + while true; do + rest_api_get + status=$(cat /tmp/rbkresponse.$$ | jq -r '.status') + if [ $status != "SUCCEEDED" ] && [ $status != "FAILED" ]; then + echo Status is $status, checking in 15 seconds + if [ $status = "RUNNING" ] && [ ${LOOP} -ne 1 ] ; then + LOOP=1 + sleep 5 + save=$ENDPOINT + ENDPOINT="https://$RUBRIK_IP/api/internal/oracle/db/mount?source_database_name=$dbname" + rest_api_get + RBK_ID_LV=$(cat /tmp/rbkresponse.$$ | jq -r '.data[] | select(.status=="Mounting") | .id') + ENDPOINT=$save + fi + else + if [ $status != "SUCCEEDED" ]; then + echo LIVE MOUNT FAILED WITH STATUS $status + exit_with_error + else + echo LIVE MOUNT SUCCEEDED + echo "The live mount id is: ${RBK_ID_LV}" + # cat /tmp/rbkresponse.$$ | jq -r ' ' + cleanup + exit 0 + fi + fi + sleep 15 + done +} + +if [ "$db_id" == "ManagedVolume" ]; then + mount_mv +else + mount_snappable +fi + +cleanup