lib/idrac/web.rb
require 'httparty' require 'nokogiri' require 'uri' require 'colorize' module IDRAC class Web attr_reader :client, :session_id, :cookies def initialize(client) @client = client @session_id = nil @cookies = nil @tried_clearing_sessions = false end # Login to the WebUI def login(retry_count = 0) # Limit retries to prevent infinite loops if retry_count >= 3 puts "Maximum retry count reached for WebUI login".red return false end # Skip if we already have a session ID return true if @session_id begin puts "Logging in to WebUI...".light_cyan # Create the login URL login_url = "#{base_url}/data/login" # Create the login payload payload = { 'user' => client.username, 'password' => client.password } # Make the login request response = HTTParty.post( login_url, body: payload, verify: client.verify_ssl, headers: { 'Content-Type' => 'application/x-www-form-urlencoded' } ) # Check if the login was successful if response.code == 200 # Extract the session ID from the response if response.body.include?('ST2') @session_id = response.body.match(/ST2=([^;]+)/)[1] @cookies = response.headers['set-cookie'] puts "WebUI login successful".green return response.body else puts "WebUI login failed: No session ID found in response".red return false end elsif response.code == 400 && response.body.include?("maximum number of user sessions") puts "Maximum sessions reached during WebUI login".light_red # Try to clear sessions if auto_delete_sessions is enabled if client.auto_delete_sessions && !@tried_clearing_sessions puts "Auto-delete sessions is enabled, attempting to clear sessions".light_cyan @tried_clearing_sessions = true if client.session.force_clear_sessions puts "Successfully cleared sessions, trying WebUI login again".green return login(retry_count + 1) else puts "Failed to clear sessions for WebUI login".red return false end else puts "Auto-delete sessions is disabled or already tried clearing".light_yellow return false end else puts "WebUI login failed: #{response.code} - #{response.body}".red return false end rescue => e puts "Error during WebUI login: #{e.message}".red.bold return false end end # Logout from the WebUI def logout return unless @session_id begin puts "Logging out from WebUI...".light_cyan # Create the logout URL logout_url = "#{base_url}/data/logout" # Make the logout request response = HTTParty.get( logout_url, verify: client.verify_ssl, headers: { 'Cookie' => @cookies } ) # Check if the logout was successful if response.code == 200 puts "WebUI logout successful".green @session_id = nil @cookies = nil return true else puts "WebUI logout failed: #{response.code} - #{response.body}".red return false end rescue => e puts "Error during WebUI logout: #{e.message}".red.bold return false end end # Capture a screenshot def capture_screenshot # Login to get the forward URL and cookies forward_url = login return nil unless forward_url # Extract the key-value pairs from the forward URL (format: index?ST1=ABC,ST2=DEF) tokens = forward_url.split("?").last.split(",").inject({}) do |acc, kv| k, v = kv.split("=") acc[k] = v acc end # Generate a timestamp for the request timestamp_ms = (Time.now.to_f * 1000).to_i # First request to trigger the screenshot capture path = "data?get=consolepreview[manual%20#{timestamp_ms}]" res = get(path: path, headers: tokens) raise Error, "Failed to trigger screenshot capture." unless res.code.between?(200, 299) # Wait for the screenshot to be generated sleep 2 # Second request to get the actual screenshot image path = "capconsole/scapture0.png?#{timestamp_ms}" res = get(path: path, headers: tokens) raise Error, "Failed to retrieve screenshot image." unless res.code.between?(200, 299) # Save the screenshot to a file filename = "idrac_screenshot_#{timestamp_ms}.png" File.open(filename, "wb") { |f| f.write(res.body) } # Return the filename filename end # HTTP GET request for WebUI operations def get(path:, headers: {}) headers_to_use = { "User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36", "Accept-Encoding" => "deflate, gzip" } if @cookies headers_to_use["Cookie"] = @cookies elsif client.direct_mode # In direct mode, use Basic Auth headers_to_use["Authorization"] = "Basic #{Base64.strict_encode64("#{client.username}:#{client.password}")}" end HTTParty.get( "#{base_url}/#{path}", headers: headers_to_use.merge(headers), verify: false ) end private def base_url protocol = client.use_ssl ? 'https' : 'http' "#{protocol}://#{client.host}:#{client.port}" end end end