diff --git a/.gitignore b/.gitignore index a58ff20..5646207 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Ignore Rubrik API config (contains secrets) -rbk_api.conf +*.conf # Ignore example config if you want to keep it local only #rbk_api.conf.example @@ -7,6 +7,7 @@ rbk_api.conf *.tmp *.swp *.swo +*.log *~ # Ignore session and response files diff --git a/oracle_clone.sh b/oracle_clone.sh index 87f902b..2279d13 100755 --- a/oracle_clone.sh +++ b/oracle_clone.sh @@ -1,4 +1,5 @@ #!/bin/bash +ORIG_ARGS="$*" # # Perform a Clone of an Oracle DB # v1.3 - James Pattinson - October 2025 @@ -14,12 +15,29 @@ # -b Comma-separated list of PDBs to clone (include only these PDBs. PDB$SEED is always included) # -c Number of RMAN channels to use # -d Dry run mode - show API payload without executing +# -l Log all API calls (endpoints, payloads, responses) to # --refresh Refresh target database before cloning (if it exists) # # Time is passed to 'date' on THIS machine, will use local timezone + MYDIR="$(dirname "$(realpath "$0")")" -# source $MYDIR/rbk_api.conf + +# Argument parsing and RBK_API_LOG assignment happens below + +# After argument parsing, write the log header if enabled +# Debugging: Confirm if log header code is executed +if [ -n "$RBK_API_LOG" ]; then + echo "Debug: Writing log header to $RBK_API_LOG" >> /tmp/debug_oracle_clone.log + export RBK_API_LOG + { + echo "==== Rubrik Oracle Clone Log ====" + date + echo "Script: $0" + echo "Parameters: $ORIG_ARGS" + echo + } >> "$RBK_API_LOG" +fi source $MYDIR/oracle_funcs.sh # Set up cleanup trap to ensure temporary files are removed @@ -35,6 +53,7 @@ usage() { echo "Usage: $0 [options] " 1>&2 echo " -b Comma-separated list of PDBs to clone (include only these PDBs)" 1>&2 echo " -c Number of RMAN channels to use" 1>&2 echo " -d Dry run mode" 1>&2 + echo " -l Log all API calls (endpoints, payloads, responses) to " 1>&2 echo " --refresh Refresh target database before cloning (if it exists)" 1>&2 exit 1; } @@ -59,7 +78,8 @@ for arg in "$@"; do done set -- "${args[@]}" -while getopts "h:dt:n:p:a:b:c:" o; do +RBK_API_LOG="" +while getopts "h:dt:n:p:a:b:c:l:" o; do case "${o}" in h) RBK_HOST=${OPTARG} @@ -79,6 +99,9 @@ while getopts "h:dt:n:p:a:b:c:" o; do b) IFS=',' read -ra pdb_list <<< "${OPTARG}" ;; + l) + RBK_API_LOG="${OPTARG}" + ;; c) num_channels=${OPTARG} ;; diff --git a/oracle_funcs.sh b/oracle_funcs.sh index 9fa42e9..efe5bf9 100755 --- a/oracle_funcs.sh +++ b/oracle_funcs.sh @@ -169,19 +169,50 @@ get_token () { 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") + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [GET] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer " + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi 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) + 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") + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [POST] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer , Content-Type: application/json" + echo "-- Payload:" + echo "$PAYLOAD" | jq . 2>/dev/null || echo "$PAYLOAD" + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi check_http_error } rest_api_post_file () { 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" --data-binary @/tmp/payload.$$) + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [POST FILE] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer , Content-Type: application/json" + echo "-- Payload file: /tmp/payload.$$" + jq . < /tmp/payload.$$ 2>/dev/null || cat /tmp/payload.$$ + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi check_http_error rm -f /tmp/payload.$$ } @@ -189,18 +220,47 @@ rest_api_post_file () { 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") + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [POST EMPTY] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer , Content-Type: application/json" + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi 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) + 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") + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [PATCH] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer , Content-Type: application/json" + echo "-- Payload:" + echo "$PAYLOAD" | jq . 2>/dev/null || echo "$PAYLOAD" + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi 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") + if [ -n "$RBK_API_LOG" ]; then + { + echo "==== [DELETE] $ENDPOINT ====" + echo "-- Headers: accept: application/json, Authorization: Bearer " + echo "-- Response ($http_response):" + jq . < /tmp/rbkresponse.$$ 2>/dev/null || cat /tmp/rbkresponse.$$ + echo + } >> "$RBK_API_LOG" + fi check_http_error } diff --git a/oracle_list_db.sh b/oracle_list_db.sh index a881f4f..39a617c 100755 --- a/oracle_list_db.sh +++ b/oracle_list_db.sh @@ -1,4 +1,5 @@ #!/bin/bash +ORIG_ARGS="$*" # # Example API call script for Die Mobiliar # v0.2 - James Pattinson - August 2021 @@ -6,22 +7,49 @@ # Lists the registered DBs for a given Oracle Host or RAC # and their assigned SLAs # -# usage: oracle_list_db.sh +# usage: oracle_list_db.sh [-l ] + + MYDIR="$(dirname "$(realpath "$0")")" # source $MYDIR/rbk_api.conf + +RBK_API_LOG="" +if [ "$1" = "-l" ]; then + if [ -z "$2" ] || [ -z "$3" ]; then + echo "Usage: $0 [-l ] " + exit 1 + fi + RBK_API_LOG="$2" + export RBK_API_LOG + RBK_HOST="$3" + shift 3 +else + if [ $# -ne 1 ]; then + echo "Usage: $0 [-l ] " + exit 1 + fi + RBK_HOST=$1 + shift 1 +fi + +# Now RBK_API_LOG is set, so write the log header if enabled +if [ -n "$RBK_API_LOG" ]; then + { + echo "==== Rubrik Oracle List DB Log ====" + date + echo "Script: $0" + echo "Parameters: $ORIG_ARGS" + echo + } >> "$RBK_API_LOG" +fi + source $MYDIR/oracle_funcs.sh # Set up cleanup trap to ensure temporary files are removed + trap 'rm -f /tmp/rbkdata.$$; cleanup' EXIT INT TERM -if [ $# -ne 1 ]; then - echo "Usage: $0 " - exit 1 -fi - -RBK_HOST=$1 - echo "Connecting to Rubrik with IP $RUBRIK_IP" # API call to list Oracle DBs @@ -45,7 +73,7 @@ fi if ! jq -r --arg HOST "$RBK_HOST" ' .data[] | select(.infraPath[0].name==$HOST and .isRelic==false) | - "\(.sid)|\(.effectiveSlaDomainName)|\(.isArchiveLogModeEnabled)|\(.dataGuardType)|\(.dataGuardGroupName)" + "\(.sid)|\(.effectiveSlaDomainName)|\(.isArchiveLogModeEnabled)|\(.dataGuardType)|\(.dataGuardGroupName)|\(.isDbLocalToTheCluster)" ' /tmp/rbkresponse.$$ > /tmp/rbkdata.$$; then echo "ERROR: Failed to process API response with jq" cleanup @@ -60,15 +88,26 @@ if [ -s /tmp/rbkdata.$$ ]; then col3_width=14 # ArchivelogMode col4_width=7 # DG Type col5_width=8 # DG Group + col6_width=8 # Location # Calculate actual maximum widths needed - while IFS='|' read -r sid sla archlog dgtype dggroup || [ -n "$sid" ]; do + while IFS='|' read -r sid sla archlog dgtype dggroup islocal || [ -n "$sid" ]; do # Handle null values and empty strings [ "$sid" = "null" ] && sid="" [ "$sla" = "null" ] && sla="" [ "$archlog" = "null" ] && archlog="" [ "$dgtype" = "null" ] && dgtype="" [ "$dggroup" = "null" ] && dggroup="" + [ "$islocal" = "null" ] && islocal="" + + # Convert boolean to Location text + if [ "$islocal" = "true" ]; then + location="Local" + elif [ "$islocal" = "false" ]; then + location="Remote" + else + location="" + fi # Update column widths if current data is longer [ ${#sid} -gt $col1_width ] && col1_width=${#sid} @@ -76,31 +115,43 @@ if [ -s /tmp/rbkdata.$$ ]; then [ ${#archlog} -gt $col3_width ] && col3_width=${#archlog} [ ${#dgtype} -gt $col4_width ] && col4_width=${#dgtype} [ ${#dggroup} -gt $col5_width ] && col5_width=${#dggroup} + [ ${#location} -gt $col6_width ] && col6_width=${#location} done < /tmp/rbkdata.$$ # Print headers with proper spacing - printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s\n" \ - "SID" "SLA" "ArchivelogMode" "DG Type" "DG Group" + printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s %-${col6_width}s\n" \ + "SID" "SLA" "ArchivelogMode" "DG Type" "DG Group" "Location" # Print separator line - printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s\n" \ + printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s %-${col6_width}s\n" \ "$(printf '%*s' $col1_width | tr ' ' '-')" \ "$(printf '%*s' $col2_width | tr ' ' '-')" \ "$(printf '%*s' $col3_width | tr ' ' '-')" \ "$(printf '%*s' $col4_width | tr ' ' '-')" \ - "$(printf '%*s' $col5_width | tr ' ' '-')" + "$(printf '%*s' $col5_width | tr ' ' '-')" \ + "$(printf '%*s' $col6_width | tr ' ' '-')" # Print data rows with proper spacing - while IFS='|' read -r sid sla archlog dgtype dggroup || [ -n "$sid" ]; do + while IFS='|' read -r sid sla archlog dgtype dggroup islocal || [ -n "$sid" ]; do # Handle null values and empty strings [ "$sid" = "null" ] && sid="" [ "$sla" = "null" ] && sla="" [ "$archlog" = "null" ] && archlog="" [ "$dgtype" = "null" ] && dgtype="" [ "$dggroup" = "null" ] && dggroup="" + [ "$islocal" = "null" ] && islocal="" - printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s\n" \ - "$sid" "$sla" "$archlog" "$dgtype" "$dggroup" + # Convert boolean to Location text + if [ "$islocal" = "true" ]; then + location="Local" + elif [ "$islocal" = "false" ]; then + location="Remote" + else + location="" + fi + + printf "%-${col1_width}s %-${col2_width}s %-${col3_width}s %-${col4_width}s %-${col5_width}s %-${col6_width}s\n" \ + "$sid" "$sla" "$archlog" "$dgtype" "$dggroup" "$location" done < /tmp/rbkdata.$$ else echo "No Oracle databases found for host $RBK_HOST" diff --git a/rbk_api.conf b/rbk_api.conf index ac16859..f3a52f1 100644 --- a/rbk_api.conf +++ b/rbk_api.conf @@ -1,5 +1,5 @@ # IP Address (or DNS name) of Rubrik CDM -RUBRIK_IP=jp-edge-proxmox.pattinson.org +RUBRIK_IP=jp-edge-dr.pattinson.org ID="client|673af632-150d-47e0-908e-66a6d71fe621" SECRET=lIHYPGMjmDLf3jflRRHtl1Oqf0YlfY7z0YNdwLG0VetfKuiVkIl_SsD4QAjAhEOb \ No newline at end of file