class IDRAC::Session
def base_url
def base_url protocol = use_ssl ? 'https' : 'http' "#{protocol}://#{host}:#{port}" end
def basic_auth_headers
def basic_auth_headers { 'Authorization' => "Basic #{Base64.strict_encode64("#{username}:#{password}")}", 'Content-Type' => 'application/json' } end
def connection
def connection @connection ||= Faraday.new(url: base_url, ssl: { verify: verify_ssl }) do |faraday| faraday.request :multipart faraday.request :url_encoded faraday.adapter Faraday.default_adapter end end
def create
def create # Skip if we're in direct mode if @direct_mode puts "Skipping Redfish session creation (direct mode)".light_yellow return false end url = '/redfish/v1/SessionService/Sessions' payload = { "UserName" => username, "Password" => password } # Try creation methods in sequence return true if create_session_with_content_type(url, payload) return true if create_session_with_basic_auth(url, payload) return true if handle_max_sessions_and_retry(url, payload) return true if create_session_with_form_urlencoded(url, payload) # If all attempts fail, switch to direct mode @direct_mode = true false end
def create_session_with_basic_auth(url, payload)
def create_session_with_basic_auth(url, payload) begin response = request_with_basic_auth(:post, url, payload.to_json) if process_session_response(response) puts "Redfish session created successfully with Basic Auth".green return true elsif response.status == 400 && response.body.include?("maximum number of user sessions") puts "Maximum sessions reached during Redfish session creation".light_red @sessions_maxed = true return false else puts "Failed to create Redfish session: #{response.status} - #{response.body}".red return false end rescue => e puts "Error during Redfish session creation with Basic Auth: #{e.message}".red.bold return false end end
def create_session_with_content_type(url, payload)
def create_session_with_content_type(url, payload) begin response = connection.post(url) do |req| req.headers['Content-Type'] = 'application/json' req.body = payload.to_json end if process_session_response(response) puts "Redfish session created successfully".green return true end rescue => e puts "First session creation attempt failed: #{e.message}".light_red end false end
def create_session_with_form_urlencoded(url, payload)
def create_session_with_form_urlencoded(url, payload) # Only try with form-urlencoded if we had a 415 error previously begin puts "Trying with form-urlencoded content type".light_cyan response = connection.post(url) do |req| req.headers['Content-Type'] = 'application/x-www-form-urlencoded' req.headers['Authorization'] = "Basic #{Base64.strict_encode64("#{username}:#{password}")}" req.body = "UserName=#{URI.encode_www_form_component(username)}&Password=#{URI.encode_www_form_component(password)}" end if process_session_response(response) puts "Redfish session created successfully with form-urlencoded".green return true else puts "Failed with form-urlencoded too: #{response.status} - #{response.body}".red return false end rescue => e puts "Error during form-urlencoded session creation: #{e.message}".red.bold return false end end
def delete
def delete return unless @x_auth_token && @session_location begin puts "Deleting Redfish session...".light_cyan # Use the X-Auth-Token for authentication headers = { 'X-Auth-Token' => @x_auth_token } response = connection.delete(@session_location) do |req| req.headers.merge!(headers) end if response.status == 200 || response.status == 204 puts "Redfish session deleted successfully".green @x_auth_token = nil @session_location = nil return true else puts "Failed to delete Redfish session: #{response.status} - #{response.body}".red return false end rescue => e puts "Error during Redfish session deletion: #{e.message}".red.bold return false end end
def delete_all_sessions_with_basic_auth
def delete_all_sessions_with_basic_auth puts "Attempting to delete all sessions using Basic Authentication...".light_cyan # First, get the list of sessions sessions_url = '/redfish/v1/SessionService/Sessions' begin # Get the list of sessions response = request_with_basic_auth(:get, sessions_url) if response.status != 200 puts "Failed to get sessions list: #{response.status} - #{response.body}".red return false end # Parse the response to get session IDs begin sessions_data = JSON.parse(response.body) if sessions_data['Members'] && sessions_data['Members'].any? puts "Found #{sessions_data['Members'].count} active sessions".light_yellow # Delete each session success = true sessions_data['Members'].each do |session| session_url = session['@odata.id'] # Skip if no URL next unless session_url # Delete the session delete_response = request_with_basic_auth(:delete, session_url) if delete_response.status == 200 || delete_response.status == 204 puts "Successfully deleted session: #{session_url}".green else puts "Failed to delete session #{session_url}: #{delete_response.status}".red success = false end # Small delay between deletions sleep(1) end return success else puts "No active sessions found".light_yellow return true end rescue JSON::ParserError => e puts "Error parsing sessions response: #{e.message}".red.bold return false end rescue => e puts "Error during session deletion with Basic Auth: #{e.message}".red.bold return false end end
def force_clear_sessions
def force_clear_sessions puts "Attempting to force clear all sessions...".light_cyan if delete_all_sessions_with_basic_auth puts "Successfully cleared sessions using Basic Auth".green true else puts "Failed to clear sessions using Basic Auth".red false end end
def handle_max_sessions_and_retry(url, payload)
def handle_max_sessions_and_retry(url, payload) return false unless @sessions_maxed && @auto_delete_sessions puts "Auto-delete sessions is enabled, attempting to clear sessions".light_cyan if force_clear_sessions puts "Successfully cleared sessions, trying to create a new session".green # Try one more time after clearing response = request_with_basic_auth(:post, url, payload.to_json) if process_session_response(response) puts "Redfish session created successfully after clearing sessions".green return true else puts "Failed to create Redfish session after clearing sessions: #{response.status} - #{response.body}".red return false end else puts "Failed to clear sessions, switching to direct mode".light_yellow return false end end
def initialize(client)
def initialize(client) @client = client @host = client.host @username = client.username @password = client.password @port = client.port @use_ssl = client.use_ssl @verify_ssl = client.verify_ssl @x_auth_token = nil @session_location = nil @direct_mode = client.direct_mode @sessions_maxed = false @auto_delete_sessions = client.auto_delete_sessions end
def process_session_response(response)
def process_session_response(response) if response.status == 201 || response.status == 200 @x_auth_token = response.headers['X-Auth-Token'] @session_location = response.headers['Location'] @sessions_maxed = false true else false end end
def request_with_basic_auth(method, url, body = nil)
def request_with_basic_auth(method, url, body = nil) connection.send(method, url) do |req| req.headers.merge!(basic_auth_headers) req.body = body if body end rescue => e puts "Error during #{method} request with Basic Auth: #{e.message}".red.bold raise e end