...
Code Block | ||
---|---|---|
| ||
#!/bin/bash # ----------------------------------------------------------------------------------------------------------------------------- # Script: castor-change-log-level.sh # ----------------------------------------------------------------------------------------------------------------------------- # Description: # This script changes the log level for the Castor cluster or node(s) using the Swarm API. # The script supports changing the log level for the entire cluster or individual node(s). # The script can run in a detachable session using 'screen' or 'tmux'. # ----------------------------------------------------------------------------------------------------------------------------- # Written by Milton Suen (milton.suen@datacore.com) Oct 31, 2024 # Revision History: # v1.0.0 - Update to support running the script in a detachable session using screen or tmux. # v1.1.0 - 2025-02-20 Add support node(s) level log level change. # v1.2.0 - 2025-02-26 SUPSCR-208: # - Enforced proper credential formatting: credentials must be in the username:password format. # - Fixed help message shows script name without hard code it. # v1.2.1 - 2025-02-26 SUPSCR-209: Auto detect CSN or SCS to adjust castor.log file path. # v1.2.12 - 2025-02-2627 Address the issue of the script not display correct when the castor.log file is rotated. # v1.2.23 - 2025-02-26 SUPSCR-209: Enforced proper credential formatting: credentials must be in the username:password format27 Address the issue of log level not display correct within detach session. # ----------------------------------------------------------------------------------------------------------------------------- # Current Version: 1.2.23 # ----------------------------------------------------------------------------------------------------------------------------- # KB: https://perifery.atlassian.net/wiki/spaces/public/pages/3872161835/Setting+and+Managing+Swarm+Log+Levels+with+script # ----------------------------------------------------------------------------------------------------------------------------- # Define colors RED='\033[0;31m' BOLD_RED='\033[1;31m' GREEN='\033[0;32m' BOLD_GREEN='\033[1;32m' UNDERLINE_BOLD_GREEN='\033[4;32m' YELLOW='\033[0;33m' BOLD_YELLOW='\033[1;33m' BLUE='\033[0;34m' BOLD_BLUE='\033[1;34m' MAGENTA='\033[0;35m' BOLD_MAGENTA='\033[1;35m' CYAN='\033[0;36m' BOLD_CYAN='\033[1;36m' RESET='\033[0m' # Reset color to default SCRIPT_NAME=$(basename "$0") # Function to display usage information usage() { echo "Usage: ./castor-change-log-level10.sh$SCRIPT_NAME -d swarm_ip -p admin:password [-i new_log_level | -L new_node_log_level] [-t duration_in_seconds] [-D]" echo " -d, --swarm_ip IP address of the Swarm API endpoint. Supports single or multiple IPs separated by \",\", \";\" or \" \"." echo " If multiple IPs are provided, the script will update the log level for all nodes." echo " (Alternatively, set the SCSP_HOST environment variable to the Swarm IP.)" echo " -p, --credentials Credentials in the format admin:password" echo " -i, --log.level New cluster log level to set (5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)" echo " -L, --node.log.level New node log level to set (0, 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)" echo " **Either -i or -L must be specified, but not both.**" echo " -t, --time (Optional) Duration in seconds to keep the new log level (must be greater than 0)" echo " -D, --detach (Optional) Detach the script from the current terminal and run in a detachable session using screen or tmux" exit 1 } # Default options detachable=false debug=false output_log="scriptcastor-change-log-level_output.log" # Log file for capturing detachable session output log_level_type="cluster" # Default log level type default_log_level=30 # Default log level log_file="/var/log/datacore/castor.log" # Default log file location SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) JQLOCATION=$SCRIPTDIR/jq # Global associative array for log levels declare -A log_levels=( [5]="chatter" [10]="debug" [15]="audit" [20]="info" [30]="warning" [40]="error" [45]="defect" [50]="critical" [60]="announce" [30]="default" ) # Global associative array for log level names declare -A log_level_names=( ["chatter"]=5 ["debug"]=10 ["audit"]=15 ["info"]=20 ["warning"]=30 ["error"]=40 ["defect"]=45 ["critical"]=50 ["announce"]=60 ["default"]=30 ) # Function to displayget debugthe messagescurrent if debug mode is enabled debug_msgtimestamp timestamp() { if $debug; date +"%Y-%m-%d_%H:%M:%S.%4N" } # Function to display debug messages if debug mode is enabled debug_msg() { if $debug; then local caller_line=${BASH_LINENO[0]:-unknown} # Fallback to "unknown" if empty echo -e "$(timestamp) [DEBUG] $1" >> "$output_log(Line $caller_line) $*" fi } # Function to check if either 'screen' or 'tmux' is installed check_screen_or_tmux() { if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/null; then echo "Error: Neither 'screen' nor 'tmux' is installed. Cannot run in detachable mode." detachable=false # Disable detachable session debug_msg "detachable=${YELLOW}false${RESET}" fi } # Function to format file size format_size() { local size=$1 if (( size >= 1073741824 )); then echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")" elif (( size >= 1048576 )); then echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")" elif (( size >= 1024 )); then echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")" else echo "${size}B" fi } # Function to format duration format_duration() { local duration=$1 local hours=$((duration / 3600)) local minutes=$(( (duration % 3600) / 60 )) local seconds=$((duration % 60)) printf "%02d:%02d:%02d" $hours $minutes $seconds } # Function to check if jq is available and set up JSON parsing method check_jq() { if [[ -x "/usr/local/bin/jq" ]]; then echo "/usr/local/bin/jq" elif [[ -x "$(pwd)/jq" ]]; then echo "$(pwd)/jq" elif command -v jq &>/dev/null; then echo "jq" else echo "grep" fi } if [[ -f "$JQLOCATION" ]]; then jq_or_grep=$($JQLOCATION else jq_or_grep=$(check_jq) fi debug_msg "jq_or_grep: $jq_or_grep" #jq_or_grep=$(check_jq) # Function to determine the log file path determine_log_file() { if [[ -f "/var/log/datacore/castor.log" ]]; then echo "/var/log/datacore/castor.log" elif [[ -f "/var/log/caringo/castor.log" ]]; then echo "/var/log/caringo/castor.log" else echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log" exit 1 fi } log_file=$(determine_log_file) # ParseFunction inputto argumentscheck whileif [[ "$#" -gt 0 ]]; docredentials are valid check_credentials() { local case CREDENTIALS="$1" in -d|--swarm_ip) swarm_iplocal SWARM_IP="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;; Credentials: $CREDENTIALS" debug_msg "Swarm IP: $SWARM_IP" -p|--credentials) # API endpoint for validating user credentials local credentials="$2VALIDATE_URL="http://${SWARM_IP}:91/api/validateUser" # Make the API request if ! [[ "$credentials" =~ ^[^:]+:[^:]+$ ]]; then RESPONSE=$(curl -s -u "$CREDENTIALS" -X GET "$VALIDATE_URL" -H 'Content-Type: application/json') debug_msg "Validate User Response: $RESPONSE" echo -e "" # Check if the response contains "isValid": true if echo -e "Error: Credentials must be in the format ${BOLD_GREEN}username:password${RESET}" exit 1 "$RESPONSE" | "$jq_or_grep" -e '.isValid == true' > /dev/null 2>&1; then return 0 fi# Success elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid if [[ "$credentials" =~ [^a-zA-Z0-9:] ]]== false' > /dev/null 2>&1; then debug_msg "Authentication failed for user '${CREDENTIALS%%:*}'" echo -e "" return 1 # Failure else echo -edebug_msg "WarningError: PasswordUnable containsto specialvalidate characterscredentials. Please check encloseyour theinputs." credentials with single quotes (${BOLD_YELLOW}'${BOLD_GREEN}username:password${RESET}${BOLD_YELLOW}'${RESET})." return 1 # Failure fi } # exitParse 1input arguments while [[ "$#" -gt 0 ]]; do ficase $1 in -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set credentialsswarm_ip to $swarm_ip"; shift 2 ;; -ip|--log.level)credentials) credentials="$2" if ! [[ -n "$new_log_level" "$credentials" =~ ^[^:]+:[^:]+$ ]]; then echo -e "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."" echo -e "Error: Credentials must be in the format ${BOLD_GREEN}username:password${RESET}" exit usage1 fi if [[ ${log_level_names[$2]}"$credentials" =~ [^a-zA-Z0-9:] ]]; then new_log_level=${log_level_names[$2]} echo -e "" elif [[ ${log_levels[$2]} ]]; then echo -e "Warning: Password contains special characters. Please enclose the credentials with single new_log_level=$2quotes (${BOLD_YELLOW}'${BOLD_GREEN}username:password${RESET}${BOLD_YELLOW}'${RESET})." else exit 1 echo "Invalidfi log level: $2" debug_msg "Set credentials"; shift 2 ;; exit 1 -i|--log.level) fi if [[ new_log_level_name=${log_levels[-n "$new_log_level" ]]}; then log_level_type="cluster" echo "Error: Options -i (cluster log leve) default_log_level=30 and -L (node log level) cannot be used together." debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)" usage shift 2 fi ;; if -L|--node.log.level)[[ ${log_level_names[$2]} ]]; then if [[ -n "$new_ new_log_level=${log_level" ]]; then_names[$2]} elif [[ ${log_levels[$2]} ]]; then echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together." new_log_level=$2 else usage echo "Invalid log level: $2" fi if [[ ${log_level_names[$2]} ]]; then exit 1 fi new_log_level_name=${log_levels[$new_log_level_names[$2]} elif [[ ${log_levels[$2]} || $2 -eq 0 ]]; then_level_type="cluster" newdefault_log_level=$230 debug_msg "Set new_log_level newto $new_log_level ($new_log_level_name="default)" elseshift 2 ;; echo "Invalid log level: $2" -L|--node.log.level) if [[ exit 1 -n "$new_log_level" ]]; then fi echo "Error: Options -i (cluster log leve) and -L (node log_level_type="node" level) cannot be used together." default_log_level=0 usage debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)" fi shift 2 if [[ ${log_level_names[$2]} ]]; then ;; -t|--time)new_log_level=${log_level_names[$2]} ifelif [[ -n "$2" && "$2" != -* && "$2" -gt ${log_levels[$2]} || $2 -eq 0 ]]; then durationnew_log_level="$2" debug_msg "Set duration to $duration"new_log_level_name="default" else shift 2 echo "Invalid log level: $2" else exit 1 echo "Error: Duration must be a number greater than 0." fi exit 1new_log_level_name=${log_levels[$new_log_level]} log_level_type="node" fi default_log_level=0 ;; -D|--detach) detachable=true; debug_msg "Set detachablenew_log_level to true"; shift ;; $new_log_level ($new_log_level_name)" --debug) debug=true; debug_msg "Set debug toshift true";2 shift ;; *) usage ;; esac done debug_msg "Set log_level_type to ${YELLOW}$log_level_type${RESET}" # Set default values if not provided-t|--time) if [[ -z "$new_log_level"n "$2" && "$2" != -* && "$2" -gt 0 ]]; then if [[ "$log_level_type" == "cluster" ]]; then duration="$2" new_log_level=$default_log_level elsedebug_msg "Set duration to $duration" new_log_level=0 fi new_log_level_name="default" shift 2 new_log_level_name=${log_levels[$new_log_level]} debug_msg "Set default new_log_level to $new_log_level ($new_log_level_name)" fi # Check if 'screen' or 'tmux' is installed check_screen_or_tmux # If swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -z "$swarm_ip" ]]; then else echo "Error: Duration must be a number greater than 0." if [[ -n "$SCSP_HOST" ]]; then exit 1 swarm_ip="$SCSP_HOST" debug "Usingfi Swarm IP from SCSP_HOST: $swarm_ip" else ;; echo "Error: swarm_ip not provided and SCSP_HOST is not set." -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;; usage --debug) debug=true; debug_msg "Set fidebug fito true # Check if required arguments are provided if [[ -z "$credentials" || -z "$new_log_level" ]]; thenwith ${YELLOW}--debug${RESET}"; shift ;; *) usage ;; esac usagedone fi debug_msg # Split the swarm_ip into an array of IP addresses if it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip" # Retrieve cluster name and handle JSON parsing using the first IP address debug_msg "Retrieving the cluster name from Swarm API using IP: ${ip_array[0]}" if [[ "$jq_or_grep" == "grep" ]]; then clusterName=$(curl --user "$credentials" -sS ""Set log_level_type to ${YELLOW}$log_level_type${RESET}" # Set default values if not provided if [[ -z "$new_log_level" ]]; then if [[ "$log_level_type" == "cluster" ]]; then new_log_level=$default_log_level else new_log_level=0 fi new_log_level_name="default" new_log_level_name=${log_levels[$new_log_level]} debug_msg "Set default new_log_level to $new_log_level ($new_log_level_name)" fi # Check if 'screen' or 'tmux' is installed check_screen_or_tmux # If swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -z "$swarm_ip" ]]; then if [[ -n "$SCSP_HOST" ]]; then swarm_ip="$SCSP_HOST" debug "Using Swarm IP from SCSP_HOST: $swarm_ip" else echo "Error: swarm_ip not provided and SCSP_HOST is not set." usage fi fi # Check if required arguments are provided if [[ -z "$credentials" || -z "$new_log_level" ]]; then usage fi # Split the swarm_ip into an array of IP addresses if it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip" # Validate credentials before proceeding debug_msg "Validating credentials..." if ! check_credentials "$credentials" "${ip_array[0]}"; then echo -e "" echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}. Please check your username and password in the format ${GREEN}username:password${RESET}." echo -e "" usage exit 1 fi # Retrieve cluster name and handle JSON parsing using the first IP address debug_msg "Retrieving the cluster name from Swarm API using IP: ${ip_array[0]}" if [[ "$jq_or_grep" == "grep" ]]; then clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+') else clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name') fi if [[ -z "$clusterName" ]]; then echo "Failed to retrieve the cluster name. Please check your inputs." exit 1 fi debug_msg "Cluster Name: $clusterName" # Main logic function to run the script tasks main_script() { local swarm_ip="$1" local credentials="$2" local new_log_level="$3" local new_log_level_name="$4" local duration="$5" local log_level_type="$6" #local log_file="/var/log/datacore/castor.log" if [[ -z "$log_file" ]]; then log_file=$(determine_log_file) fi local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0) local current_log_level local clusterName="$7" local jq_or_grep="$8" local detachable="$9" if [[ "$detachable" ]]; then local debug="${10}" eval "$(echo "${11}" | sed 's/declare -A/declare -A/')" eval "$(echo "${12}" | sed 's/declare -A/declare -A/')" fi debug_msg "**********************************************************" debug_msg "local variables" debug_msg "Swarm IP: $swarm_ip" debug_msg "Credentials: $credentials" debug_msg "New Log Level: $new_log_level" debug_msg "New log Level Name: $new_log_level_name" debug_msg "Duration: $duration" debug_msg "Log Level Type: $log_level_type" debug_msg "Log File: $log_file" debug_msg "Initial Log File Size: $initial_size" debug_msg "Current Log Level: $current_log_level" debug_msg "Cluster Name: $clusterName" debug_msg "jq_or_grep: $jq_or_grep" debug_msg "Detach: $detachable" debug_msg "Debug: $debug" debug_msg "**********************************************************" # Split the swarm_ip into an array of IP addresses IFS=';, ' read -r -a ip_array <<< "$swarm_ip" debug_msg "IP Array: ${ip_array[*]}" # Display initial information if [[ "$log_level_type" == "cluster" ]]; then echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}" else echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}" fi # echo -e "Swarm IP: ${GREEN}$swarm_ip${RESET}" echo -e "Credentials: ${GREEN}[hidden for security]${RESET}" echo -e "Cluster Name: ${GREEN}$clusterName${RESET}" debug_msg "Starting main_script function..." debug_msg "Log level type: $log_level_type" # Store the original log levels declare -A original_log_levels declare -A original_log_level_names if [[ $log_level_type == "cluster" ]]; then debug_msg "Setting cluster log level to $new_log_level ($new_log_level_name)" # Retrieve current log level if [[ "$jq_or_grep" == "grep" ]]; then current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"namevalue":\s*"\K[^"0-9]+') else clusterName current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '._embedded.clusters[0].name') fi if [[ -z "$clusterName" ]]; then echo "Failed to retrieve the cluster name. Please check your inputs." exit 1 fi debug_msg "Cluster Name: $clusterName" # Main logic function to run the script tasks main_script() { local swarm_ip="$1value') fi current_log_level_name=${log_levels[$current_log_level]} debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}" debug_msg "Current log level name: ${BOLD_GREEN}$current_log_level_name${RESET}" echo -e "" echo -e "New cluster log level: ${BOLD_GREEN}$new_log_level_name${RESET}" local credentials="$2" echo local new_log_level="$3" local new-e "Current cluster log level is ${GREEN}$current_log_level_name="$4".${RESET}" local duration="$5" # Skip update if localnew log_level_type="$6" # local log_file="/var/log/datacore/castor.log"level matches the current level if local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)[[ "$current_log_level" -eq "$new_log_level" ]]; then local current_log_level localecho clusterName="$7" local jq_or_grep="$8" echo local-e debug="$9"Cluster log level is debug_msg "**********************************************************"already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made." debug_msg "local variables" return debug_msg "Swarm IP: $swarm_ip" fi debug_msg "Credentials: $credentials" debug_msg "New Log Level: $new_log_level ($new_log_level_name)" debug_msg "Duration: $duration"# Update the cluster log level using PUT debug_msg "Log Level Type: $logUpdating cluster log level to $new_log_level_typename" debug_msg "LogCluster FileName: $log_file$clusterName" debug_msg "Initial Log File Size: $initial_size" debug_msg "Current Log Level: $current_log_level" debug_msg "Cluster Name: $clusterName"response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ debug_msg "jq_or_grep: $jq_or_grep"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ debug_msg "Debug: $debug" debug_msg "**********************************************************"-d "{\"value\": $new_log_level}") # Split the swarm_ip into an array of IP addressesdebug_msg "Response: $response" if IFS=';, ' read -r -a ip_array <<< "$swarm_ip"[[ "$jq_or_grep" == "grep" ]]; then debug_msg "IP Array: ${ip_array[*]}"updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') else # Display initial information if [[ "$log_level_type" == "cluster" ]]; then updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value') fi echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}" else debug_msg "Updated cluster log level: $updated_log_level" echoif -e[[ "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}"$updated_log_level" -eq "$new_log_level" ]]; then fi # echo -e "Swarm IP:Log level changed successfully from ${GREEN}$current_log_level${RESET} → ${BOLD_GREEN}$swarm$new_log_ip$level${RESET}." echo -e "Credentials: ${GREEN}[hidden for security]${RESET}" else echo -e "Cluster NameFailed to update log level. Response: ${GREENRED}$clusterName$$response${RESET}" debug_msg "Starting main_script function..." debug_msg "Log level type: $log_level_type"exit 1 # Store the original log levelsfi declare -A original_log_levels # Countdown declareand -Arevert original_log_level_names level if [[ $log_level_type == "cluster" -n "$duration" && "$duration" -gt 0 ]]; then echo debug_msg-e "Setting clusterKeeping log level toat ${YELLOW}$new_log_level_name${RESET} ($new_log_level_name)"for ${YELLOW}$duration${RESET} second(s)..." # Retrieve current log levelecho -e "" for ((i=duration; i>0; i--)); do if [[ "$jq_or_grep" == "grep" ]]; then printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+'))) $((i%60)) echo else-ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '.value') sleep 1 fi done current_log_level_name=${log_levels[$current_log_level]} echo debug_msg-e "Current cluster\n\nTime's up! Reverting log level: back to ${BOLD_GREEN}$current_log_level${RESET}..." debug_msg "Current # Revert the log level: ${BOLD_GREEN}$current_log_level_name${RESET}" back to the original value response=$(curl --user "$credentials" echo-sS -X PUT -eH "Content-Type: application/json" \ echo -e "New cluster log level"http: //${BOLD_GREEN}$new_log_level_name${RESET}"ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ echo -e "Current cluster log level is-d ${GREEN}"{\"value\": $current_log_level_name.${RESET}") # Skip update if new level matches the current leveldebug_msg "Response: $response" if [[ "$current$jq_logor_levelgrep" -eq== "$new_log_levelgrep" ]]; then echo "" reverted_log_level=$(echo "$response" echo| grep -eoP "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."'"value":\s*\K[0-9]+') else return reverted_log_level=$(echo "$response" | "$jq_or_grep" fi-r '.value') # Update the clusterfi log level using PUT debug_msg "UpdatingReverted cluster log level: to $new$reverted_log_level_name" " final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0) debug_msg "Cluster NameInitial log file size: $clusterName$initial_size" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \debug_msg "Final log file size: $final_size" "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ size_diff=$(( final_size - initial_size )) -d "{\"value\": $new_log_level}") size_diff_formatted=$(format_size "$size_diff") debug_msg "Response: $response" duration_formatted=$(format_duration "$duration") if [[ "$jq_or_grep" == "grep" ]](( size_diff < 0 )); then echo -e "castor.log file was rotated." else updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') echo -e else updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value') "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level${RESET}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted." fi debug_msg "Updated cluster log level: $updated_log_level" if [[ "$updated$reverted_log_level" -eq "$new$current_log_level" ]]; then echo -e "Log level changedreverted successfully from ${GREEN}$current_log_level${RESET} →back to ${BOLD_GREEN}$new$current_log_level${RESET}." else echo -e "Failed to update log level. Response: ${RED}$response${RESET}" exit 1 revert log level. Response: ${RED}$response${RESET}" fi #exit Countdown1 and revert log level iffi [[ -n "$duration" && "$duration" -gt 0 ]]; thenelse echo -e "KeepingLog loglevel levelchange at ${YELLOW}$new_log_level${RESET} for ${YELLOW}$duration${RESET} second(s)..."is permanent until manually modified." fi elif echo -e[[ "$log_level_type" == "node" ]]; then # First for ((i=duration; i>0; i--)); do loop: Change the node log level for ip in "${ip_array[@]}"; do printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) # Retrieve current node log level echo -nedebug_msg "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" Retrieving current node log level for IP: $ip" sleep 1debug_msg "curl -s -u \"$credentials\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\"" done echo -e "\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level${RESET}..." current_log_level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value') # Revert thedebug_msg "Current log level backfor toIP the original value $ip: $current_log_level" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ original_log_levels["$ip"]=$current_log_level debug_msg "Original log level for IP "http$ip:// ${iporiginal_log_arraylevels[0"$ip"]}:91/api/storage/clusters/$clusterName/settings/log.level" \ if -d "{\"value\": [[ "$current_log_level}") == "0" ]]; then debug_msg "Response: $response" current_log_level_name="default" if [[ "$jq_or_grep" == "grep" ]]; thenelse revertedcurrent_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')_name=${log_levels[$current_log_level]} fi elseoriginal_log_level_names["$ip"]=$current_log_level_name debug_msg "Original log level name: reverted${original_log_level=$(echo "$response_names["$ip"]}" | "$jq_or_grep" -r '.value') if [[ "$new_log_level" == fi "0" ]]; then debug_msg "Reverted cluster log level: $revertednew_log_level_name="default" else final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0) size_diff=$(( final_size - initial_size ))new_log_level_name=${log_levels[$new_log_level]} size_diff_formatted=$(format_size "$size_diff")fi duration_formatted=$(format_duration "$duration") if (( size_diff < 0 )); then echo -e "castor.log file was rotated." else debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)" echo "" echo -e "ApproximateNew node log level: ${BOLD_GREEN}$size$new_log_difflevel_formatted$name${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level${RESET}. Current castor.log size" echo -e "Current node log level for IP $ip is ${BOLD_GREEN}$(format_size "$final_size")$current_log_level_name.${RESET} after $duration_formatted." fi " # Skip update if new level matches the current level if [[ "$reverted$current_log_level" -eq "$current$new_log_level" ]]; then echo "" echo -e "LogNode log level reverted successfully backfor IP $ip is already set to ${BOLD_GREEN}$current$new_log_level_level$name${RESET}. No changes made." continue else fi echo -e# "FailedUpdate tothe revertnode log level. Response: ${RED}$response${RESET}" using PUT debug_msg "Updating node log level to exit 1$new_log_level_name for IP $ip..." debug_msg fi"curl --user \"$credentials\" -sS -X PUT -H \"Content-Type: elseapplication/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"" echo "Log level change is permanent until manually modified."response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ fi elif [[ "$log_level_type" == "node" ]]; then "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level") # First loopdebug_msg "Response: Change$response" the node log level for ipif in[[ "${ip_array[@]}"; do $jq_or_grep" == "grep" ]]; then # Retrieve current node log level debug_msg "Retrieving current node log level for IP: $ip"updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') debug_msgelse "curl -s -u \"$credentials\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\"" currentupdated_log_level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | echo "$response" | "$jq_or_grep" -r '.value') fi original_log_levels["$ip"]=$current_log_level debug_msg "Updated log if [[ "$currentlevel for IP $ip: $updated_log_level" == "0" ]]; then if [[ "$updated_log_level" current-eq "$new_log_level_name="default" ]]; then else echo -e "Node log level for IP $ip changed successfully from current${GREEN}$current_log_level_name=name${RESET} → ${log_levels[$currentBOLD_GREEN}$new_log_level]}_name${RESET}." fi original_log_level_names["$ip"]=$current_log_level_nameelse ifecho [[-e "$new_log_level" == "0" ]]; then Failed to update node log level for IP $ip. Response: ${RED}$response${RESET}" new_log_level_name="default" exit 1 else fi done new_log_level_name=${log_levels[$new_log_level]} # Second loop: Countdown if fiduration is provided if debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)"[[ -n "$duration" && "$duration" -gt 0 ]]; then echo -e "" echo -e "NewKeeping node(s) log level: at ${BOLD_GREENYELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} second(s)..." echo -e "Current node log level for IP $ip is ${GREEN}$current_log_level_name.${RESET}" # Skip update if new level matches the current level"" for ((i=duration; i>0; i--)); do printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" if [[ "$current_log_level" -eq "$new_log_level" ]]; then sleep 1 echo "" done echo -e "Node\n\nTime's up! Reverting node log level forback IPto $ip is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."original levels..." # Third loop: Revert the node log level continue for ip fi in "${ip_array[@]}"; do # Update the node current_log level using PUT_level=${original_log_levels["$ip"]} debug_msg "Updating node current_log level to $new_level_name=${original_log_level_name for IP $ip..."names["$ip"]} debug_msg "curl --user \"$credentials\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"" debug_msg "Reverting node log level back to $current_log_level_name for IP $ip..." response=$(debug_msg "curl --user \"$credentials\" -sS -X PUT -H \"Content-Type: application/json\" \ "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level") debug_msg "Response: $response" if [[ "$jq_or_grep" == "grep" ]]; then/settings/log.nodeLogLevel?value=$current_log_level\"" updated_log_levelresponse=$(echocurl --user "$response$credentials" | grep-sS -X PUT -oPH '"value":\s*\K[0-9]+') Content-Type: application/json" \ else updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value') "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level") fi debug_msg "Updated log level for IP $ip: $updated_log_level"Response: $response" if [[ "$updated$jq_logor_levelgrep" -eq== "$new_log_levelgrep" ]]; then echo -e "Node reverted_log _level for IP $ip changed successfully from ${GREEN}$current_log_level_name${RESET} → ${BOLD_GREEN}$new_log_level_name${RESET}."=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') else echo -e "Failed to update node log level for IP $ip. Response: ${RED}$response${RESET}" reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value') fi exit 1 final_size=$(stat -c%s "$log_file" fi2>/dev/null || echo 0) done size_diff=$(( final_size - # Second loop: Countdown if duration is providedinitial_size )) if [[ -n "$duration" && "$duration" -gt 0 ]]; then debug_msg "Initial log file size: $initial_size" echo -e "" debug_msg "Final log file size: $final_size" echo -e "Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} second(s)..."size_diff_formatted=$(format_size "$size_diff") echo -e duration_formatted=$(format_duration "" $duration") for ((i=duration; i>0; i--)); do if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) echo -e "Node log level for IP $ip reverted successfully echoback -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"to ${BOLD_GREEN}${current_log_level_name}${RESET}." else sleep 1 echo -e done"Failed to revert node log level for IP $ip. Response: ${RED}$response${RESET}" echo -e "\n\nTime's up! Reverting node log level back to original levels..." exit 1 # Third loop: Revert the node log level fi for ip in "${ip_array[@]}"; do done # Combine current_log_level=${original_log_levels["$ip"]} the log output for multiple IP addresses into a single summary if (( current_log_level_name=${original_log_level_names["$ip"]} size_diff < 0 )); then echo -e "castor.log file was rotated." else debug_msg "Reverting node log level back to $current_log_level_name for IP $ip..." echo -e "" debug_msg "curl --user \"$credentials\" -sS -X PUT -Hecho \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\"" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted." fi else "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level") echo "Log level change is permanent until debug_msg "Response: $response"manually modified." fi fi } # Run ifin [[detachable "$jq_or_grep" == "grep" ]]directly if $detachable; then # Pass the main_script function to the screen session and store the output in a reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') file debug_msg "**********************************************************" | tee -a "$output_log" debug_msg "Detach mode - Parameters passed elseto main_script:" | tee -a "$output_log" debug_msg " Swarm reverted_log_level=$(echo "$responseIP: $swarm_ip" | tee -a "$jq$output_or_greplog" -r '.value') debug_msg " Credentials: $credentials" | tee -a "$output_log" fi debug_msg " New Log Level: $new_log_level" | tee -a "$output_log" final_size=$(stat -c%s "$logdebug_filemsg " 2>/dev/null || echo 0) New log Level Name: $new_log_level_name" | tee -a "$output_log" debug_msg " size_diff=$(( final_size - initial_size )) Duration: $duration" | tee -a "$output_log" debug_msg " Log Level size_diff_formatted=$(format_size "$size_diff")Type: $log_level_type" | tee -a "$output_log" debug_msg " Log File: $log_file" | tee -a duration_formatted=$(format_duration "$duration")"$output_log" debug_msg " Initial Log File Size: $initial_size" | if [[tee -a "$reverted$output_log_level" -eq "" debug_msg " Current Log Level: $current_log_level" ]];| thentee -a "$output_log" debug_msg " Cluster Name: $clusterName" | tee echo -ea "$output_log"Node log level for IPdebug_msg $ip" reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET}." jq_or_grep: $jq_or_grep" | tee -a "$output_log" debug_msg " else Detach: $detachable" | tee -a "$output_log" debug_msg " Debug: $debug" | echotee -ea "Failed$output_log" to revert node log level for IP $ip. Response: ${RED}$response${RESET}debug_msg "**********************************************************" | tee -a "$output_log" # Convert associative arrays to strings and pass them to the exitscreen 1session log_levels_string=$(declare -p log_levels) log_level_names_string=$(declare -p log_level_names) fi debug_msg "log_levels_string: $log_levels_string" | tee -a "$output_log" done debug_msg "log_level_names_string: $log_level_names_string" | tee -a "$output_log" if command #-v Combine the log output for multiple IP addresses into a single summary if (( size_diff < 0 )); then echo -e "castor.log file was rotated." else screen &>/dev/null; then echo -e "Running in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log" # if [[ "$debug" ]]; then # echo -e ""Debug mode enabled. Check the output log for debug messages." echo -e# "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted." sleep 5 # fi fi screen -dmS indexer_script bash -c else echo "Log level change is permanent until manually modified." "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" | tee \"$output_log\"" fi screen fi }-r indexer_script # Run in detachable or directly if $detachable;# thenWait for # Pass the main_scriptscreen functionsession to thecomplete screenand sessionthen and storedisplay the output in a filelog if command -v screen &>/dev/null; then sleep 1 #while screen -dmSlist indexer_script| bashgrep -cq "$(declare -f main_script format_size format_duration check_jq debug); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" | tee \"$output_log\"""indexer_script"; do sleep 1 done screen -dmS indexer_scriptelif bashcommand -c "$(declare -f main_script debug_msg format_size format_duration check_jq); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$debug\" | tee \"$output_log\""v tmux &>/dev/null; then echo -e "Running in ${YELLOW}tmux${RESET} detachable mode..." | tee -a "$output_log" # if [[ screen -r indexer_script"$debug" ]]; then elif command -v tmux &>/dev/null; then # echo -e "Debug mode enabled. #Check tmuxthe new-session -d -s indexer_script "$(declare -f main_script format_size format_duration check_jq debug); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" | tee \"$output_log\""output log for debug messages." # sleep 5 # fi tmux new-session -d -s indexer_script "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" | tee \"$output_log${log_levels_string}\"" tmux attach-session -t indexer_script else echo "Error: Neither screen nor tmux available. Run without --detachable." \"${log_level_names_string}\" | tee \"$output_log\"" exit 1 tmux attach-session -t fiindexer_script # Wait for the screen session to complete and then display the output log sleep 1 while screen -list | grep -q "indexer_script"; doelse echo "Error: Neither screen nor tmux available. Run without --detachable." sleepexit 1 donefi echo "" cat "$output_log" else # main_script "$swarm_ip" "$credentials" "$new_log_level" "$duration" "$clusterName" "$jq_or_grep" | tee "$output_log" debug_msg "**********************************************************" debug_msg "Parameters passed to main_script:" debug_msg "Swarm IP: $swarm_ip" debug_msg "Credentials: $credentials" debug_msg "New Log Level: $new_log_level" debug_msg "Duration: $duration" debug_msg "Cluster Name: $clusterName" debug_msg "jq_or_grep: $jq_or_grep" debug_msg "**********************************************************" debug_msg "Running main_script function..." main_script "$swarm_ip" "$credentials" "$new_log_level" "$new_log_level_name" "$duration" "$log_level_type" "$clusterName" "$jq_or_grep" | tee "$output_log" fi |
...