Dell iDRAC Session Management & Troubleshooting Guide 2025: Complete Connection Control & Monitoring
Dell iDRAC session management is critical for maintaining reliable remote access to PowerEdge servers. This comprehensive guide covers session troubleshooting, automated monitoring, connection pooling, enterprise-scale management strategies, and prevention techniques for session exhaustion issues.
Understanding iDRAC Session Architecture
iDRAC Session Fundamentals
Session Types and Limits
Dell iDRAC supports multiple concurrent session types, each with specific limits:
- GUI Sessions: Web interface connections (typically 6-12 concurrent)
- SSH Sessions: Command-line access (typically 4-6 concurrent)
- Virtual Console: Remote KVM sessions (typically 2-4 concurrent)
- Redfish API: RESTful API connections (varies by model)
- IPMI Sessions: Out-of-band management (typically 4-8 concurrent)
Common Session Issues
- Session Exhaustion: All available slots consumed
- Stuck Sessions: Improperly closed connections
- Ghost Sessions: Sessions persisting after client disconnect
- Authentication Failures: Failed login attempts consuming slots
- Network Timeouts: Sessions held open due to network issues
iDRAC Session Architecture
[Client Applications]
↓
[Network Layer]
↓
[iDRAC Controller]
├── Session Manager
├── Authentication Module
├── Resource Allocator
└── Timeout Handler
Advanced Session Management Techniques
Comprehensive Session Management Script
#!/bin/bash
# Enterprise iDRAC Session Management System
# Configuration
IDRAC_CONFIG_FILE="/etc/idrac-manager/servers.conf"
SESSION_LOG_DIR="/var/log/idrac-sessions"
ALERT_THRESHOLD=80 # Alert when 80% of sessions are used
CHECK_INTERVAL=300 # Check every 5 minutes
# Create required directories
sudo mkdir -p "$(dirname "$IDRAC_CONFIG_FILE")" "$SESSION_LOG_DIR"
# Logging function
log_message() {
local level="$1"
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$SESSION_LOG_DIR/session-manager.log"
}
# Server configuration structure
create_server_config() {
cat > "$IDRAC_CONFIG_FILE" << 'EOF'
# iDRAC Server Configuration
# Format: name|ip|username|password|model|max_sessions|description
# Production servers
prod-r740-01|10.1.1.101|root|calvin|iDRAC9|12|Production DB Server
prod-r740-02|10.1.1.102|root|calvin|iDRAC9|12|Production App Server
prod-r640-01|10.1.1.103|root|calvin|iDRAC9|8|Production Web Server
# Development servers
dev-r630-01|10.2.1.101|root|calvin|iDRAC8|6|Development Server
dev-r640-01|10.2.1.102|root|calvin|iDRAC9|8|Test Environment
# Infrastructure servers
infra-r750-01|10.3.1.101|root|calvin|iDRAC10|16|VMware Host 1
infra-r750-02|10.3.1.102|root|calvin|iDRAC10|16|VMware Host 2
EOF
}
# Get current session information
get_session_info() {
local idrac_ip="$1"
local username="$2"
local password="$3"
# SSH to iDRAC and get session info
sshpass -p "$password" ssh -o StrictHostKeyChecking=no \
-o ConnectTimeout=10 "$username@$idrac_ip" \
"racadm getssninfo" 2>/dev/null
}
# Parse session data
parse_session_data() {
local session_data="$1"
local active_sessions=0
local session_details=""
# Skip header lines and count active sessions
while IFS= read -r line; do
if [[ "$line" =~ ^[0-9]+ ]]; then
((active_sessions++))
session_details+="$line"$'\n'
fi
done <<< "$session_data"
echo "$active_sessions|$session_details"
}
# Monitor single iDRAC
monitor_idrac_sessions() {
local server_name="$1"
local idrac_ip="$2"
local username="$3"
local password="$4"
local model="$5"
local max_sessions="$6"
local description="$7"
log_message "INFO" "Checking sessions on $server_name ($idrac_ip)"
# Get current session information
local session_data=$(get_session_info "$idrac_ip" "$username" "$password")
if [[ -z "$session_data" ]]; then
log_message "ERROR" "Failed to connect to $server_name ($idrac_ip)"
return 1
fi
# Parse session data
IFS='|' read -r active_sessions session_details <<< "$(parse_session_data "$session_data")"
# Calculate usage percentage
local usage_percent=$((active_sessions * 100 / max_sessions))
# Log session status
log_message "INFO" "$server_name: $active_sessions/$max_sessions sessions ($usage_percent%)"
# Check if threshold exceeded
if [[ $usage_percent -ge $ALERT_THRESHOLD ]]; then
log_message "WARN" "$server_name exceeds session threshold: $usage_percent%"
send_session_alert "$server_name" "$idrac_ip" "$active_sessions" "$max_sessions" "$session_details"
fi
# Store session data
store_session_data "$server_name" "$idrac_ip" "$active_sessions" "$max_sessions" "$session_details"
return 0
}
# Store session data for analysis
store_session_data() {
local server_name="$1"
local idrac_ip="$2"
local active_sessions="$3"
local max_sessions="$4"
local session_details="$5"
local data_file="$SESSION_LOG_DIR/session_data_${server_name}.json"
local timestamp=$(date -Iseconds)
# Create JSON data
cat > "$data_file.tmp" <<EOF
{
"timestamp": "$timestamp",
"server_name": "$server_name",
"idrac_ip": "$idrac_ip",
"active_sessions": $active_sessions,
"max_sessions": $max_sessions,
"usage_percent": $((active_sessions * 100 / max_sessions)),
"sessions": [
EOF
# Add session details
local first=true
while IFS= read -r line; do
if [[ "$line" =~ ^([0-9]+)[[:space:]]+([A-Z]+)[[:space:]]+([a-zA-Z0-9_-]+)[[:space:]]+([0-9.]+)[[:space:]]+(.+)$ ]]; then
local ssn_id="${BASH_REMATCH[1]}"
local ssn_type="${BASH_REMATCH[2]}"
local ssn_user="${BASH_REMATCH[3]}"
local ssn_ip="${BASH_REMATCH[4]}"
local ssn_time="${BASH_REMATCH[5]}"
if [[ "$first" != "true" ]]; then
echo "," >> "$data_file.tmp"
fi
first=false
cat >> "$data_file.tmp" <<EOF
{
"session_id": "$ssn_id",
"type": "$ssn_type",
"user": "$ssn_user",
"client_ip": "$ssn_ip",
"login_time": "$ssn_time"
}
EOF
fi
done <<< "$session_details"
echo "" >> "$data_file.tmp"
echo " ]" >> "$data_file.tmp"
echo "}" >> "$data_file.tmp"
mv "$data_file.tmp" "$data_file"
}
# Send alert for high session usage
send_session_alert() {
local server_name="$1"
local idrac_ip="$2"
local active_sessions="$3"
local max_sessions="$4"
local session_details="$5"
local alert_file="$SESSION_LOG_DIR/alert_${server_name}_$(date +%Y%m%d_%H%M%S).txt"
cat > "$alert_file" <<EOF
iDRAC SESSION ALERT
===================
Server: $server_name ($idrac_ip)
Time: $(date)
Sessions: $active_sessions / $max_sessions ($(( active_sessions * 100 / max_sessions ))%)
Active Sessions:
$session_details
Action Required: Review and close unnecessary sessions
EOF
# Send email alert if configured
if [[ -n "${ALERT_EMAIL:-}" ]]; then
mail -s "iDRAC Session Alert: $server_name" "$ALERT_EMAIL" < "$alert_file"
fi
# Log to syslog
logger -t idrac-sessions -p warning "High session usage on $server_name: $active_sessions/$max_sessions"
}
# Close specific session
close_idrac_session() {
local idrac_ip="$1"
local username="$2"
local password="$3"
local session_id="$4"
log_message "INFO" "Closing session $session_id on $idrac_ip"
local result=$(sshpass -p "$password" ssh -o StrictHostKeyChecking=no \
-o ConnectTimeout=10 "$username@$idrac_ip" \
"racadm closessn -i $session_id" 2>&1)
if [[ "$result" =~ "closed successfully" ]]; then
log_message "INFO" "Session $session_id closed successfully on $idrac_ip"
return 0
else
log_message "ERROR" "Failed to close session $session_id on $idrac_ip: $result"
return 1
fi
}
# Automatic session cleanup
auto_cleanup_sessions() {
local server_name="$1"
local idrac_ip="$2"
local username="$3"
local password="$4"
local max_age_hours="${5:-24}" # Default: close sessions older than 24 hours
log_message "INFO" "Starting auto-cleanup for $server_name"
# Get current session information
local session_data=$(get_session_info "$idrac_ip" "$username" "$password")
if [[ -z "$session_data" ]]; then
log_message "ERROR" "Failed to connect to $server_name for cleanup"
return 1
fi
local current_timestamp=$(date +%s)
local closed_count=0
# Process each session
while IFS= read -r line; do
if [[ "$line" =~ ^([0-9]+)[[:space:]]+([A-Z]+)[[:space:]]+([a-zA-Z0-9_-]+)[[:space:]]+([0-9.]+)[[:space:]]+([0-9/]+)[[:space:]]+([0-9:]+)$ ]]; then
local ssn_id="${BASH_REMATCH[1]}"
local ssn_type="${BASH_REMATCH[2]}"
local ssn_user="${BASH_REMATCH[3]}"
local ssn_date="${BASH_REMATCH[5]}"
local ssn_time="${BASH_REMATCH[6]}"
# Convert session time to timestamp
local session_timestamp=$(date -d "$ssn_date $ssn_time" +%s 2>/dev/null)
if [[ -n "$session_timestamp" ]]; then
local age_hours=$(( (current_timestamp - session_timestamp) / 3600 ))
if [[ $age_hours -gt $max_age_hours ]]; then
log_message "INFO" "Session $ssn_id is $age_hours hours old - closing"
if close_idrac_session "$idrac_ip" "$username" "$password" "$ssn_id"; then
((closed_count++))
fi
fi
fi
fi
done <<< "$session_data"
log_message "INFO" "Auto-cleanup completed for $server_name: $closed_count sessions closed"
}
# Monitor all configured servers
monitor_all_servers() {
log_message "INFO" "Starting session monitoring cycle"
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
monitor_idrac_sessions "$name" "$ip" "$username" "$password" "$model" "$max_sessions" "$description"
done < "$IDRAC_CONFIG_FILE"
log_message "INFO" "Session monitoring cycle completed"
}
# Continuous monitoring daemon
monitoring_daemon() {
log_message "INFO" "Starting iDRAC session monitoring daemon"
while true; do
monitor_all_servers
sleep "$CHECK_INTERVAL"
done
}
# Generate session report
generate_session_report() {
local report_type="${1:-summary}"
local output_file="${2:-$SESSION_LOG_DIR/session_report_$(date +%Y%m%d_%H%M%S).txt}"
{
echo "iDRAC Session Report"
echo "===================="
echo "Generated: $(date)"
echo ""
case "$report_type" in
"summary")
echo "Session Summary by Server:"
echo "--------------------------"
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
local data_file="$SESSION_LOG_DIR/session_data_${name}.json"
if [[ -f "$data_file" ]]; then
local usage=$(jq -r '.usage_percent' "$data_file" 2>/dev/null)
local active=$(jq -r '.active_sessions' "$data_file" 2>/dev/null)
local max=$(jq -r '.max_sessions' "$data_file" 2>/dev/null)
local timestamp=$(jq -r '.timestamp' "$data_file" 2>/dev/null)
printf "%-20s: %2d/%-2d sessions (%3d%%) - Last check: %s\n" \
"$name" "$active" "$max" "$usage" "$timestamp"
else
printf "%-20s: No data available\n" "$name"
fi
done < "$IDRAC_CONFIG_FILE"
;;
"detailed")
echo "Detailed Session Information:"
echo "-----------------------------"
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
echo ""
echo "Server: $name ($ip)"
echo "Model: $model - $description"
local data_file="$SESSION_LOG_DIR/session_data_${name}.json"
if [[ -f "$data_file" ]]; then
echo "Sessions:"
jq -r '.sessions[] | " ID: \(.session_id) | Type: \(.type) | User: \(.user) | IP: \(.client_ip) | Time: \(.login_time)"' \
"$data_file" 2>/dev/null
else
echo " No session data available"
fi
done < "$IDRAC_CONFIG_FILE"
;;
"alerts")
echo "Recent Alerts:"
echo "--------------"
find "$SESSION_LOG_DIR" -name "alert_*.txt" -mtime -7 -exec basename {} \; | \
sort -r | head -20 | while read alert_file; do
echo ""
echo "Alert: $alert_file"
head -5 "$SESSION_LOG_DIR/$alert_file"
echo "..."
done
;;
esac
} > "$output_file"
echo "Report saved to: $output_file"
}
# Interactive session manager
interactive_session_manager() {
echo "iDRAC Session Manager"
echo "===================="
PS3="Select option: "
options=(
"View all sessions"
"Monitor specific server"
"Close session"
"Auto-cleanup old sessions"
"Generate report"
"Start monitoring daemon"
"Exit"
)
select opt in "${options[@]}"; do
case $REPLY in
1)
monitor_all_servers
;;
2)
echo "Available servers:"
awk -F'|' '!/^#/ && NF {print NR". "$1" ("$2")"}' "$IDRAC_CONFIG_FILE"
read -p "Select server number: " server_num
server_info=$(sed -n "${server_num}p" "$IDRAC_CONFIG_FILE")
if [[ -n "$server_info" ]]; then
IFS='|' read -r name ip username password model max_sessions description <<< "$server_info"
monitor_idrac_sessions "$name" "$ip" "$username" "$password" "$model" "$max_sessions" "$description"
fi
;;
3)
read -p "Enter iDRAC IP: " idrac_ip
read -p "Enter username: " username
read -s -p "Enter password: " password
echo
# Show current sessions
session_data=$(get_session_info "$idrac_ip" "$username" "$password")
echo "$session_data"
read -p "Enter session ID to close: " session_id
close_idrac_session "$idrac_ip" "$username" "$password" "$session_id"
;;
4)
read -p "Enter maximum session age in hours (default 24): " max_age
max_age="${max_age:-24}"
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
auto_cleanup_sessions "$name" "$ip" "$username" "$password" "$max_age"
done < "$IDRAC_CONFIG_FILE"
;;
5)
echo "Report types: summary, detailed, alerts"
read -p "Enter report type: " report_type
generate_session_report "$report_type"
;;
6)
echo "Starting monitoring daemon (press Ctrl+C to stop)..."
monitoring_daemon
;;
7)
echo "Goodbye!"
exit 0
;;
*)
echo "Invalid option"
;;
esac
echo ""
read -p "Press Enter to continue..."
done
}
# Main execution
if [[ ! -f "$IDRAC_CONFIG_FILE" ]]; then
echo "Creating default configuration file..."
create_server_config
fi
# Handle command line arguments
case "${1:-}" in
"monitor")
monitor_all_servers
;;
"daemon")
monitoring_daemon
;;
"cleanup")
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
auto_cleanup_sessions "$name" "$ip" "$username" "$password" "${2:-24}"
done < "$IDRAC_CONFIG_FILE"
;;
"report")
generate_session_report "${2:-summary}"
;;
"interactive"|"")
interactive_session_manager
;;
*)
echo "Usage: $0 {monitor|daemon|cleanup|report|interactive}"
echo " monitor - Check all servers once"
echo " daemon - Run continuous monitoring"
echo " cleanup - Clean old sessions"
echo " report - Generate session report"
echo " interactive - Interactive menu"
exit 1
;;
esac
Enterprise Session Management Strategies
Session Pool Management
#!/bin/bash
# iDRAC Session Pool Manager
# Configuration
POOL_CONFIG="/etc/idrac-manager/session-pool.conf"
POOL_STATE_DIR="/var/lib/idrac-manager/pool-state"
# Create directories
sudo mkdir -p "$(dirname "$POOL_CONFIG")" "$POOL_STATE_DIR"
# Session pool configuration
create_pool_config() {
cat > "$POOL_CONFIG" << 'EOF'
# Session Pool Configuration
# Pool policies by server type
[DEFAULT]
max_gui_sessions=4
max_ssh_sessions=2
max_console_sessions=1
session_timeout=3600
cleanup_interval=300
[PRODUCTION]
max_gui_sessions=2
max_ssh_sessions=1
max_console_sessions=1
session_timeout=1800
strict_cleanup=true
[DEVELOPMENT]
max_gui_sessions=6
max_ssh_sessions=3
max_console_sessions=2
session_timeout=7200
strict_cleanup=false
[MAINTENANCE]
max_gui_sessions=8
max_ssh_sessions=4
max_console_sessions=2
session_timeout=14400
strict_cleanup=false
EOF
}
# Session reservation system
reserve_session() {
local server_name="$1"
local session_type="$2"
local user="$3"
local purpose="$4"
local duration="${5:-3600}"
local reservation_file="$POOL_STATE_DIR/${server_name}_reservations.json"
local reservation_id="RES_$(date +%s)_$$"
local expiry=$(($(date +%s) + duration))
# Create reservation
local reservation=$(cat <<EOF
{
"id": "$reservation_id",
"server": "$server_name",
"type": "$session_type",
"user": "$user",
"purpose": "$purpose",
"created": $(date +%s),
"expiry": $expiry,
"status": "active"
}
EOF
)
# Add to reservation file
if [[ -f "$reservation_file" ]]; then
# Append to existing reservations
jq ". += [$reservation]" "$reservation_file" > "${reservation_file}.tmp"
mv "${reservation_file}.tmp" "$reservation_file"
else
# Create new reservation file
echo "[$reservation]" > "$reservation_file"
fi
echo "$reservation_id"
}
# Check session availability
check_session_availability() {
local server_name="$1"
local session_type="$2"
local server_config="$3"
# Get server's pool policy
local pool_policy=$(get_server_pool_policy "$server_config")
# Load pool limits
source <(grep -E "^(max_.*_sessions|session_timeout)" "$POOL_CONFIG" | \
sed -n "/\[$pool_policy\]/,/\[/p" | \
grep -v "^\[")
# Get current session count
local current_sessions=$(count_active_sessions "$server_name" "$session_type")
# Get max sessions for type
local max_var="max_${session_type}_sessions"
local max_sessions="${!max_var:-1}"
if [[ $current_sessions -lt $max_sessions ]]; then
echo "AVAILABLE"
return 0
else
echo "FULL"
return 1
fi
}
# Get server pool policy
get_server_pool_policy() {
local server_config="$1"
# Extract server type from config
local server_type=$(echo "$server_config" | awk -F'|' '{print $7}')
case "$server_type" in
*prod*|*production*)
echo "PRODUCTION"
;;
*dev*|*development*|*test*)
echo "DEVELOPMENT"
;;
*maint*|*maintenance*)
echo "MAINTENANCE"
;;
*)
echo "DEFAULT"
;;
esac
}
# Count active sessions
count_active_sessions() {
local server_name="$1"
local session_type="$2"
# Get session data from monitoring
local data_file="$SESSION_LOG_DIR/session_data_${server_name}.json"
if [[ -f "$data_file" ]]; then
case "$session_type" in
"gui")
jq '[.sessions[] | select(.type == "GUI")] | length' "$data_file" 2>/dev/null || echo "0"
;;
"ssh")
jq '[.sessions[] | select(.type == "SSH")] | length' "$data_file" 2>/dev/null || echo "0"
;;
"console")
jq '[.sessions[] | select(.type == "CONSOLE")] | length' "$data_file" 2>/dev/null || echo "0"
;;
*)
echo "0"
;;
esac
else
echo "0"
fi
}
# Session queue management
manage_session_queue() {
local queue_file="$POOL_STATE_DIR/session_queue.json"
# Process queue
if [[ -f "$queue_file" ]]; then
local processed_requests=()
# Read each queued request
while IFS= read -r request; do
local server=$(echo "$request" | jq -r '.server')
local type=$(echo "$request" | jq -r '.type')
local user=$(echo "$request" | jq -r '.user')
# Check if session is now available
if check_session_availability "$server" "$type" >/dev/null; then
log_message "INFO" "Processing queued request for $user on $server ($type)"
# Grant session access
local reservation_id=$(reserve_session "$server" "$type" "$user" "Queued request")
# Notify user
notify_user "$user" "Session available on $server" "$reservation_id"
# Mark as processed
processed_requests+=("$(echo "$request" | jq -r '.id')")
fi
done < <(jq -c '.[]' "$queue_file" 2>/dev/null)
# Remove processed requests from queue
for request_id in "${processed_requests[@]}"; do
jq "map(select(.id != \"$request_id\"))" "$queue_file" > "${queue_file}.tmp"
mv "${queue_file}.tmp" "$queue_file"
done
fi
}
# Session usage analytics
analyze_session_usage() {
local analysis_period="${1:-7}" # Days
local report_file="$SESSION_LOG_DIR/usage_analysis_$(date +%Y%m%d).json"
echo "Analyzing session usage for past $analysis_period days..."
# Collect usage data
local usage_data=$(cat <<EOF
{
"analysis_date": "$(date -Iseconds)",
"period_days": $analysis_period,
"servers": {}
}
EOF
)
# Analyze each server
while IFS='|' read -r name ip username password model max_sessions description; do
[[ "$name" =~ ^#.*$ ]] && continue
[[ -z "$name" ]] && continue
# Calculate usage statistics
local avg_sessions=$(calculate_average_sessions "$name" "$analysis_period")
local peak_sessions=$(calculate_peak_sessions "$name" "$analysis_period")
local avg_duration=$(calculate_average_duration "$name" "$analysis_period")
# Add to report
usage_data=$(echo "$usage_data" | jq \
--arg server "$name" \
--arg avg "$avg_sessions" \
--arg peak "$peak_sessions" \
--arg duration "$avg_duration" \
'.servers[$server] = {
"average_sessions": ($avg | tonumber),
"peak_sessions": ($peak | tonumber),
"average_duration_minutes": ($duration | tonumber)
}')
done < "$IDRAC_CONFIG_FILE"
# Generate recommendations
usage_data=$(echo "$usage_data" | jq '. + {
"recommendations": [
"Consider increasing session limits for servers with >80% average usage",
"Implement stricter timeout policies for development servers",
"Review long-running sessions for potential optimization"
]
}')
echo "$usage_data" | jq '.' > "$report_file"
echo "Analysis complete. Report saved to: $report_file"
}
Automated Session Prevention
#!/bin/bash
# Proactive session exhaustion prevention
# Session prevention configuration
PREVENTION_CONFIG="/etc/idrac-manager/prevention.conf"
cat > "$PREVENTION_CONFIG" << 'EOF'
# Session Exhaustion Prevention Rules
# Warning thresholds (percentage)
WARNING_THRESHOLD_GUI=60
WARNING_THRESHOLD_SSH=70
WARNING_THRESHOLD_CONSOLE=50
# Critical thresholds (percentage)
CRITICAL_THRESHOLD_GUI=80
CRITICAL_THRESHOLD_SSH=85
CRITICAL_THRESHOLD_CONSOLE=75
# Auto-cleanup policies
AUTO_CLEANUP_IDLE_TIME=1800 # 30 minutes
AUTO_CLEANUP_MAX_AGE=86400 # 24 hours
AUTO_CLEANUP_ORPHANED=true
AUTO_CLEANUP_DUPLICATES=true
# Prevention actions
ACTION_WARNING="alert,log"
ACTION_CRITICAL="alert,cleanup,restrict"
EOF
# Proactive session monitoring
proactive_session_monitor() {
local server_name="$1"
local server_config="$2"
# Load prevention config
source "$PREVENTION_CONFIG"
# Get current session data
local session_data=$(get_current_session_data "$server_name")
# Check each session type
for session_type in gui ssh console; do
local current_count=$(echo "$session_data" | jq -r ".${session_type}_count")
local max_count=$(echo "$session_data" | jq -r ".max_${session_type}")
local usage_percent=$((current_count * 100 / max_count))
# Get thresholds
local warning_var="WARNING_THRESHOLD_${session_type^^}"
local critical_var="CRITICAL_THRESHOLD_${session_type^^}"
local warning_threshold="${!warning_var:-60}"
local critical_threshold="${!critical_var:-80}"
# Check thresholds
if [[ $usage_percent -ge $critical_threshold ]]; then
handle_critical_threshold "$server_name" "$session_type" "$usage_percent"
elif [[ $usage_percent -ge $warning_threshold ]]; then
handle_warning_threshold "$server_name" "$session_type" "$usage_percent"
fi
done
}
# Handle critical threshold
handle_critical_threshold() {
local server_name="$1"
local session_type="$2"
local usage_percent="$3"
log_message "CRITICAL" "$server_name: $session_type sessions at $usage_percent%"
# Execute critical actions
IFS=',' read -ra actions <<< "$ACTION_CRITICAL"
for action in "${actions[@]}"; do
case "$action" in
"alert")
send_critical_alert "$server_name" "$session_type" "$usage_percent"
;;
"cleanup")
execute_aggressive_cleanup "$server_name" "$session_type"
;;
"restrict")
enable_session_restrictions "$server_name" "$session_type"
;;
esac
done
}
# Aggressive cleanup for critical situations
execute_aggressive_cleanup() {
local server_name="$1"
local session_type="$2"
log_message "INFO" "Executing aggressive cleanup for $server_name ($session_type)"
# Get server connection info
local server_info=$(grep "^$server_name|" "$IDRAC_CONFIG_FILE")
IFS='|' read -r name ip username password model max_sessions description <<< "$server_info"
# Get all sessions
local sessions=$(get_session_info "$ip" "$username" "$password")
# Priority-based cleanup
local cleanup_priorities=(
"duplicate_user_sessions"
"idle_sessions"
"old_sessions"
"non_critical_sessions"
)
for priority in "${cleanup_priorities[@]}"; do
case "$priority" in
"duplicate_user_sessions")
cleanup_duplicate_sessions "$ip" "$username" "$password" "$sessions"
;;
"idle_sessions")
cleanup_idle_sessions "$ip" "$username" "$password" "$sessions"
;;
"old_sessions")
cleanup_old_sessions "$ip" "$username" "$password" "$sessions" 8
;;
"non_critical_sessions")
cleanup_non_critical_sessions "$ip" "$username" "$password" "$sessions"
;;
esac
# Check if we've freed enough sessions
local new_usage=$(get_session_usage "$server_name" "$session_type")
if [[ $new_usage -lt 70 ]]; then
log_message "INFO" "Cleanup successful - usage reduced to $new_usage%"
break
fi
done
}
# Cleanup duplicate user sessions
cleanup_duplicate_sessions() {
local idrac_ip="$1"
local username="$2"
local password="$3"
local sessions="$4"
# Find users with multiple sessions
local user_sessions=$(echo "$sessions" | awk '$2 ~ /GUI|SSH/ {print $3}' | sort | uniq -c | sort -rn)
while read -r count user; do
if [[ $count -gt 1 ]]; then
log_message "INFO" "User $user has $count sessions - cleaning duplicates"
# Keep newest session, close others
local user_session_ids=$(echo "$sessions" | awk -v user="$user" '$3 == user {print $1}' | tail -n +2)
for session_id in $user_session_ids; do
close_idrac_session "$idrac_ip" "$username" "$password" "$session_id"
done
fi
done <<< "$user_sessions"
}
# Session restriction enforcement
enable_session_restrictions() {
local server_name="$1"
local session_type="$2"
local restriction_file="$POOL_STATE_DIR/${server_name}_restrictions.json"
local restriction=$(cat <<EOF
{
"server": "$server_name",
"type": "$session_type",
"enabled": true,
"start_time": $(date +%s),
"reason": "Critical threshold reached",
"allowed_users": ["admin", "root", "emergency"],
"max_duration": 1800
}
EOF
)
echo "$restriction" > "$restriction_file"
log_message "WARN" "Session restrictions enabled for $server_name ($session_type)"
}
# Check session restrictions
check_session_restrictions() {
local server_name="$1"
local session_type="$2"
local user="$3"
local restriction_file="$POOL_STATE_DIR/${server_name}_restrictions.json"
if [[ -f "$restriction_file" ]]; then
local enabled=$(jq -r '.enabled' "$restriction_file")
local allowed_users=$(jq -r '.allowed_users[]' "$restriction_file")
if [[ "$enabled" == "true" ]]; then
# Check if user is allowed
if echo "$allowed_users" | grep -q "^$user$"; then
return 0
else
log_message "WARN" "Session denied for $user due to restrictions on $server_name"
return 1
fi
fi
fi
return 0
}
Session Monitoring and Alerting
Real-time Session Dashboard
#!/bin/bash
# Real-time iDRAC session monitoring dashboard
# Dashboard configuration
DASHBOARD_PORT=8080
DASHBOARD_UPDATE_INTERVAL=10
DASHBOARD_DATA_DIR="/var/lib/idrac-dashboard"
# Create dashboard directories
sudo mkdir -p "$DASHBOARD_DATA_DIR"/{data,logs,web}
# Generate dashboard HTML
generate_dashboard_html() {
cat > "$DASHBOARD_DATA_DIR/web/index.html" << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>iDRAC Session Monitor</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
background-color: #333;
color: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
}
.server-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.server-card {
background-color: white;
border-radius: 5px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.server-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.session-bar {
width: 100%;
height: 30px;
background-color: #e0e0e0;
border-radius: 3px;
overflow: hidden;
margin: 5px 0;
}
.session-fill {
height: 100%;
background-color: #4CAF50;
transition: width 0.3s ease;
display: flex;
align-items: center;
padding-left: 10px;
color: white;
font-size: 14px;
}
.session-fill.warning {
background-color: #ff9800;
}
.session-fill.critical {
background-color: #f44336;
}
.session-details {
margin-top: 10px;
font-size: 14px;
}
.refresh-time {
text-align: right;
color: #666;
font-size: 12px;
margin-top: 20px;
}
.alert-banner {
background-color: #f44336;
color: white;
padding: 10px;
margin-bottom: 20px;
border-radius: 5px;
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>iDRAC Session Monitor</h1>
<p>Real-time session usage across all servers</p>
</div>
<div id="alert-banner" class="alert-banner"></div>
<div id="server-grid" class="server-grid">
<!-- Server cards will be inserted here -->
</div>
<div class="refresh-time">
Last updated: <span id="last-update">Never</span>
</div>
</div>
<script>
// Auto-refresh dashboard
function updateDashboard() {
fetch('/api/sessions')
.then(response => response.json())
.then(data => {
updateServerGrid(data.servers);
updateAlerts(data.alerts);
document.getElementById('last-update').textContent = new Date().toLocaleString();
})
.catch(error => console.error('Error updating dashboard:', error));
}
function updateServerGrid(servers) {
const grid = document.getElementById('server-grid');
grid.innerHTML = '';
servers.forEach(server => {
const card = createServerCard(server);
grid.appendChild(card);
});
}
function createServerCard(server) {
const card = document.createElement('div');
card.className = 'server-card';
const percentage = (server.active_sessions / server.max_sessions) * 100;
let barClass = 'session-fill';
if (percentage >= 80) barClass += ' critical';
else if (percentage >= 60) barClass += ' warning';
card.innerHTML = `
<div class="server-name">${server.name}</div>
<div class="session-info">
<div>GUI Sessions:</div>
<div class="session-bar">
<div class="${barClass}" style="width: ${percentage}%">
${server.active_sessions}/${server.max_sessions}
</div>
</div>
</div>
<div class="session-details">
<div>Model: ${server.model}</div>
<div>IP: ${server.ip}</div>
<div>Status: ${server.status}</div>
</div>
`;
return card;
}
function updateAlerts(alerts) {
const banner = document.getElementById('alert-banner');
if (alerts && alerts.length > 0) {
banner.style.display = 'block';
banner.innerHTML = '<strong>Alerts:</strong> ' + alerts.join(' | ');
} else {
banner.style.display = 'none';
}
}
// Update every 10 seconds
setInterval(updateDashboard, 10000);
updateDashboard();
</script>
</body>
</html>
EOF
}
# Dashboard API endpoint
create_dashboard_api() {
cat > "$DASHBOARD_DATA_DIR/api.py" << 'EOF'
#!/usr/bin/env python3
import json
import os
import glob
from http.server import HTTPServer, BaseHTTPRequestHandler
from datetime import datetime
class DashboardHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.serve_file('index.html', 'text/html')
elif self.path == '/api/sessions':
self.serve_session_data()
else:
self.send_error(404)
def serve_file(self, filename, content_type):
try:
with open(f'/var/lib/idrac-dashboard/web/{filename}', 'rb') as f:
content = f.read()
self.send_response(200)
self.send_header('Content-type', content_type)
self.end_headers()
self.wfile.write(content)
except:
self.send_error(404)
def serve_session_data(self):
# Collect session data from JSON files
session_files = glob.glob('/var/log/idrac-sessions/session_data_*.json')
servers = []
alerts = []
for file in session_files:
try:
with open(file, 'r') as f:
data = json.load(f)
server_info = {
'name': data['server_name'],
'ip': data['idrac_ip'],
'active_sessions': data['active_sessions'],
'max_sessions': data['max_sessions'],
'usage_percent': data['usage_percent'],
'model': 'iDRAC', # Could be parsed from config
'status': 'OK' if data['usage_percent'] < 80 else 'WARNING'
}
servers.append(server_info)
if data['usage_percent'] >= 80:
alerts.append(f"{data['server_name']} at {data['usage_percent']}% capacity")
except Exception as e:
print(f"Error reading {file}: {e}")
response = {
'servers': servers,
'alerts': alerts,
'timestamp': datetime.now().isoformat()
}
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(response).encode())
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 8080), DashboardHandler)
print('Dashboard running on http://localhost:8080')
server.serve_forever()
EOF
chmod +x "$DASHBOARD_DATA_DIR/api.py"
}
# Create systemd service for dashboard
create_dashboard_service() {
sudo tee /etc/systemd/system/idrac-dashboard.service << EOF
[Unit]
Description=iDRAC Session Monitor Dashboard
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 $DASHBOARD_DATA_DIR/api.py
WorkingDirectory=$DASHBOARD_DATA_DIR
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable idrac-dashboard
sudo systemctl start idrac-dashboard
}
# Setup monitoring dashboard
setup_monitoring_dashboard() {
echo "Setting up iDRAC session monitoring dashboard..."
generate_dashboard_html
create_dashboard_api
create_dashboard_service
echo "Dashboard available at http://localhost:$DASHBOARD_PORT"
}
Advanced Alerting System
#!/bin/bash
# Multi-channel alerting for iDRAC sessions
# Alert configuration
ALERT_CONFIG="/etc/idrac-manager/alerts.conf"
cat > "$ALERT_CONFIG" << 'EOF'
# Alert Configuration
ALERT_CHANNELS="email,slack,teams,pagerduty"
# Email settings
EMAIL_ENABLED=true
EMAIL_RECIPIENTS="ops-team@example.com,admin@example.com"
EMAIL_FROM="idrac-monitor@example.com"
EMAIL_SMTP_SERVER="smtp.example.com"
EMAIL_SMTP_PORT=587
# Slack settings
SLACK_ENABLED=true
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
SLACK_CHANNEL="#infrastructure-alerts"
# Microsoft Teams settings
TEAMS_ENABLED=true
TEAMS_WEBHOOK_URL="https://outlook.office.com/webhook/YOUR/WEBHOOK/URL"
# PagerDuty settings
PAGERDUTY_ENABLED=true
PAGERDUTY_INTEGRATION_KEY="YOUR_INTEGRATION_KEY"
PAGERDUTY_SERVICE_ID="YOUR_SERVICE_ID"
# Alert severity levels
SEVERITY_INFO="email"
SEVERITY_WARNING="email,slack"
SEVERITY_CRITICAL="email,slack,teams,pagerduty"
EOF
# Multi-channel alert dispatcher
send_multi_channel_alert() {
local severity="$1"
local title="$2"
local message="$3"
local details="$4"
# Load alert configuration
source "$ALERT_CONFIG"
# Get channels for severity
local severity_var="SEVERITY_${severity^^}"
local channels="${!severity_var:-email}"
# Send to each channel
IFS=',' read -ra channel_list <<< "$channels"
for channel in "${channel_list[@]}"; do
case "$channel" in
"email")
send_email_alert "$severity" "$title" "$message" "$details"
;;
"slack")
send_slack_alert "$severity" "$title" "$message" "$details"
;;
"teams")
send_teams_alert "$severity" "$title" "$message" "$details"
;;
"pagerduty")
send_pagerduty_alert "$severity" "$title" "$message" "$details"
;;
esac
done
}
# Email alert function
send_email_alert() {
local severity="$1"
local title="$2"
local message="$3"
local details="$4"
if [[ "$EMAIL_ENABLED" != "true" ]]; then
return
fi
local email_body="
iDRAC Session Alert
===================
Severity: $severity
Time: $(date)
$title
$message
Details:
$details
--
This alert was generated by the iDRAC Session Management System
"
echo "$email_body" | mail -s "[iDRAC Alert] $severity: $title" \
-r "$EMAIL_FROM" \
"$EMAIL_RECIPIENTS"
}
# Slack alert function
send_slack_alert() {
local severity="$1"
local title="$2"
local message="$3"
local details="$4"
if [[ "$SLACK_ENABLED" != "true" ]]; then
return
fi
local color
case "$severity" in
"CRITICAL") color="danger" ;;
"WARNING") color="warning" ;;
*) color="good" ;;
esac
local payload=$(cat <<EOF
{
"channel": "$SLACK_CHANNEL",
"username": "iDRAC Monitor",
"icon_emoji": ":server:",
"attachments": [
{
"color": "$color",
"title": "$title",
"text": "$message",
"fields": [
{
"title": "Severity",
"value": "$severity",
"short": true
},
{
"title": "Time",
"value": "$(date '+%Y-%m-%d %H:%M:%S')",
"short": true
}
],
"footer": "iDRAC Session Monitor",
"ts": $(date +%s)
}
]
}
EOF
)
curl -X POST -H 'Content-type: application/json' \
--data "$payload" "$SLACK_WEBHOOK_URL" >/dev/null 2>&1
}
# Teams alert function
send_teams_alert() {
local severity="$1"
local title="$2"
local message="$3"
local details="$4"
if [[ "$TEAMS_ENABLED" != "true" ]]; then
return
fi
local theme_color
case "$severity" in
"CRITICAL") theme_color="FF0000" ;;
"WARNING") theme_color="FFA500" ;;
*) theme_color="00FF00" ;;
esac
local payload=$(cat <<EOF
{
"@type": "MessageCard",
"@context": "http://schema.org/extensions",
"themeColor": "$theme_color",
"summary": "$title",
"sections": [{
"activityTitle": "iDRAC Session Alert",
"activitySubtitle": "$severity",
"facts": [{
"name": "Alert",
"value": "$title"
}, {
"name": "Details",
"value": "$message"
}, {
"name": "Time",
"value": "$(date)"
}],
"markdown": true
}]
}
EOF
)
curl -X POST -H 'Content-type: application/json' \
--data "$payload" "$TEAMS_WEBHOOK_URL" >/dev/null 2>&1
}
# PagerDuty alert function
send_pagerduty_alert() {
local severity="$1"
local title="$2"
local message="$3"
local details="$4"
if [[ "$PAGERDUTY_ENABLED" != "true" ]] || [[ "$severity" != "CRITICAL" ]]; then
return
fi
local event_action="trigger"
local dedup_key="idrac_session_$(echo "$title" | md5sum | cut -d' ' -f1)"
local payload=$(cat <<EOF
{
"routing_key": "$PAGERDUTY_INTEGRATION_KEY",
"event_action": "$event_action",
"dedup_key": "$dedup_key",
"payload": {
"summary": "$title",
"source": "idrac-monitor",
"severity": "error",
"custom_details": {
"message": "$message",
"details": "$details",
"time": "$(date)"
}
}
}
EOF
)
curl -X POST https://events.pagerduty.com/v2/enqueue \
-H 'Content-Type: application/json' \
--data "$payload" >/dev/null 2>&1
}
# Alert aggregation and rate limiting
manage_alert_queue() {
local alert_queue_dir="$POOL_STATE_DIR/alert_queue"
mkdir -p "$alert_queue_dir"
# Process alert queue with rate limiting
local max_alerts_per_minute=5
local alert_count=0
for alert_file in "$alert_queue_dir"/*.json; do
[[ -f "$alert_file" ]] || continue
if [[ $alert_count -lt $max_alerts_per_minute ]]; then
# Send alert
local alert_data=$(cat "$alert_file")
local severity=$(echo "$alert_data" | jq -r '.severity')
local title=$(echo "$alert_data" | jq -r '.title')
local message=$(echo "$alert_data" | jq -r '.message')
local details=$(echo "$alert_data" | jq -r '.details')
send_multi_channel_alert "$severity" "$title" "$message" "$details"
# Remove sent alert
rm -f "$alert_file"
((alert_count++))
else
# Rate limit reached, wait
sleep 60
alert_count=0
fi
done
}
This comprehensive guide provides enterprise-level knowledge for managing Dell iDRAC sessions, including advanced monitoring, automated cleanup, prevention strategies, and multi-channel alerting systems to ensure reliable remote server access.