Class: IDRAC::Client
- Inherits:
-
Object
- Object
- IDRAC::Client
- Includes:
- Boot, Debuggable, Jobs, License, Lifecycle, Power, SessionUtils, Storage, System, SystemConfig, Utility, VirtualMedia
- Defined in:
- lib/idrac/client.rb
Instance Attribute Summary collapse
-
#auto_delete_sessions ⇒ Object
readonly
Returns the value of attribute auto_delete_sessions.
-
#direct_mode ⇒ Object
Returns the value of attribute direct_mode.
-
#host ⇒ Object
readonly
Returns the value of attribute host.
-
#password ⇒ Object
readonly
Returns the value of attribute password.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#retry_count ⇒ Object
Returns the value of attribute retry_count.
-
#retry_delay ⇒ Object
Returns the value of attribute retry_delay.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#use_ssl ⇒ Object
readonly
Returns the value of attribute use_ssl.
-
#username ⇒ Object
readonly
Returns the value of attribute username.
-
#verbosity ⇒ Object
Returns the value of attribute verbosity.
-
#verify_ssl ⇒ Object
readonly
Returns the value of attribute verify_ssl.
-
#web ⇒ Object
readonly
Returns the value of attribute web.
Instance Method Summary collapse
-
#authenticated_request(method, path, options = {}) ⇒ Object
Send an authenticated request to the iDRAC.
- #base_url ⇒ Object
- #connection ⇒ Object
- #get(path:, headers: {}) ⇒ Object
- #get_firmware_version ⇒ Object
-
#handle_location(location) ⇒ Object
Handle location header and determine whether to use wait_for_job or wait_for_task.
- #handle_response(response) ⇒ Object
-
#initialize(host:, username:, password:, port: 443, use_ssl: true, verify_ssl: false, direct_mode: false, auto_delete_sessions: true, retry_count: 3, retry_delay: 1) ⇒ Client
constructor
A new instance of Client.
-
#login ⇒ Object
Login to iDRAC.
-
#logout ⇒ Object
Logout from iDRAC.
- #redfish_version ⇒ Object
- #screenshot ⇒ Object
-
#wait_for_task(task_id) ⇒ Object
Wait for a task to complete.
-
#with_retries(max_retries = nil, initial_delay = nil, error_classes = nil) { ... } ⇒ Object
Execute a block with automatic retries.
Methods included from Utility
Methods included from Debuggable
Methods included from SystemConfig
#get_system_configuration_profile, #hash_to_scp, #make_scp, #merge_scp, #normalize_enabled_value, #scp_to_hash, #set_idrac_ip, #set_scp_attribute, #set_system_configuration_profile, #usable_scp
Methods included from License
#license_info, #license_version
Methods included from Boot
#bios_error_prompt_disabled?, #bios_hdd_placeholder_enabled?, #bios_os_power_control_enabled?, #configure_bios_settings, #create_scp_for_bios, #ensure_uefi_boot, #get_bios_boot_options, #get_idrac_version, #import_system_configuration, #override_boot_source, #scp_boot_mode_uefi, #set_bios, #set_bios_ignore_errors, #set_bios_os_power_control, #set_boot_order_hd_first, #set_uefi_boot_cd_once_then_hd
Methods included from VirtualMedia
#eject_virtual_media, #get_boot_source_override, #insert_virtual_media, #set_one_time_virtual_media_boot, #virtual_media
Methods included from System
#clear_system_event_logs, #cpus, #fans, #get_basic_system_info, #get_system_config, #get_system_summary, #idrac_interface, #idrac_network, #memory, #nics, #nics_to_pci, #pci_devices, #psus, #system_event_logs, #system_health, #system_info, #total_memory_human
Methods included from Storage
#all_seds?, #controller_encryption_capable?, #controller_encryption_enabled?, #controllers, #create_virtual_disk, #create_virtual_disk_scp, #delete_volume, #disable_local_key_management, #drives, #dump_drive_data, #enable_local_key_management, #fastpath_good?, #find_controller, #sed_ready?, #volumes
Methods included from Lifecycle
#clear_lifecycle!, #clear_system_event_logs!, #ensure_lifecycle_controller!, #get_lifecycle_status, #get_lifecycle_status_from_registry, #get_lifecycle_status_from_scp, #get_lifecycle_status_modern_firmware, #get_system_event_logs, #set_lifecycle_status, #update_status_message
Methods included from Jobs
#clear_jobs!, #force_clear_jobs!, #jobs, #jobs_detail, #tasks, #wait_for_job
Methods included from SessionUtils
#delete_all_sessions_with_basic_auth, #force_clear_sessions
Methods included from Power
#get_power_state, #get_power_usage_watts, #power_off, #power_on, #reboot
Constructor Details
#initialize(host:, username:, password:, port: 443, use_ssl: true, verify_ssl: false, direct_mode: false, auto_delete_sessions: true, retry_count: 3, retry_delay: 1) ⇒ Client
Returns a new instance of Client.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/idrac/client.rb', line 28 def initialize(host:, username:, password:, port: 443, use_ssl: true, verify_ssl: false, direct_mode: false, auto_delete_sessions: true, retry_count: 3, retry_delay: 1) @host = host @username = username @password = password @port = port @use_ssl = use_ssl @verify_ssl = verify_ssl @direct_mode = direct_mode @auto_delete_sessions = auto_delete_sessions @verbosity = 0 @retry_count = retry_count @retry_delay = retry_delay # Initialize the session and web classes @session = Session.new(self) @web = Web.new(self) end |
Instance Attribute Details
#auto_delete_sessions ⇒ Object (readonly)
Returns the value of attribute auto_delete_sessions.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def auto_delete_sessions @auto_delete_sessions end |
#direct_mode ⇒ Object
Returns the value of attribute direct_mode.
13 14 15 |
# File 'lib/idrac/client.rb', line 13 def direct_mode @direct_mode end |
#host ⇒ Object (readonly)
Returns the value of attribute host.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def host @host end |
#password ⇒ Object (readonly)
Returns the value of attribute password.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def password @password end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def port @port end |
#retry_count ⇒ Object
Returns the value of attribute retry_count.
13 14 15 |
# File 'lib/idrac/client.rb', line 13 def retry_count @retry_count end |
#retry_delay ⇒ Object
Returns the value of attribute retry_delay.
13 14 15 |
# File 'lib/idrac/client.rb', line 13 def retry_delay @retry_delay end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def session @session end |
#use_ssl ⇒ Object (readonly)
Returns the value of attribute use_ssl.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def use_ssl @use_ssl end |
#username ⇒ Object (readonly)
Returns the value of attribute username.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def username @username end |
#verbosity ⇒ Object
Returns the value of attribute verbosity.
13 14 15 |
# File 'lib/idrac/client.rb', line 13 def verbosity @verbosity end |
#verify_ssl ⇒ Object (readonly)
Returns the value of attribute verify_ssl.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def verify_ssl @verify_ssl end |
#web ⇒ Object (readonly)
Returns the value of attribute web.
12 13 14 |
# File 'lib/idrac/client.rb', line 12 def web @web end |
Instance Method Details
#authenticated_request(method, path, options = {}) ⇒ Object
Send an authenticated request to the iDRAC
89 90 91 92 93 |
# File 'lib/idrac/client.rb', line 89 def authenticated_request(method, path, = {}) with_retries do _perform_authenticated_request(method, path, ) end end |
#base_url ⇒ Object
292 293 294 295 |
# File 'lib/idrac/client.rb', line 292 def base_url protocol = use_ssl ? 'https' : 'http' "#{protocol}://#{host}:#{port}" end |
#connection ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/idrac/client.rb', line 46 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 # Add request/response logging based on verbosity if @verbosity > 0 faraday.response :logger, Logger.new(STDOUT), bodies: @verbosity >= 2 do |logger| logger.filter(/(Authorization: Basic )([^,\n]+)/, '\1[FILTERED]') logger.filter(/(Password"=>"?)([^,"]+)/, '\1[FILTERED]') end end end end |
#get(path:, headers: {}) ⇒ Object
95 96 97 98 99 |
# File 'lib/idrac/client.rb', line 95 def get(path:, headers: {}) with_retries do _perform_get(path: path, headers: headers) end end |
#get_firmware_version ⇒ Object
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/idrac/client.rb', line 307 def get_firmware_version response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1?$select=FirmwareVersion") if response.status == 200 begin data = JSON.parse(response.body) return data["FirmwareVersion"] rescue JSON::ParserError raise Error, "Failed to parse firmware version response: #{response.body}" end else # Try again without the $select parameter for older firmware response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1") if response.status == 200 begin data = JSON.parse(response.body) return data["FirmwareVersion"] rescue JSON::ParserError raise Error, "Failed to parse firmware version response: #{response.body}" end else raise Error, "Failed to get firmware version. Status code: #{response.status}" end end end |
#handle_location(location) ⇒ Object
Handle location header and determine whether to use wait_for_job or wait_for_task
441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/idrac/client.rb', line 441 def handle_location(location) return nil if location.nil? || location.empty? # Extract the ID from the location id = location.split("/").last # Determine if it's a task or job based on the URL pattern if location.include?("/TaskService/Tasks/") wait_for_task(id) else # Assuming it's a job wait_for_job(id) end end |
#handle_response(response) ⇒ Object
426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/idrac/client.rb', line 426 def handle_response(response) # First see if there is a location header if response.headers["location"] return handle_location(response.headers["location"]) end # If there is no location header, check the status code if response.status.between?(200, 299) return response.body else raise Error, "Failed to #{response.status} - #{response.body}" end end |
#login ⇒ Object
Login to iDRAC
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/idrac/client.rb', line 62 def login # If we're in direct mode, skip login attempts if @direct_mode debug "Using direct mode (Basic Auth) for all requests", 1, :light_yellow return true end # Try to create a Redfish session if session.create debug "Successfully logged in to iDRAC using Redfish session", 1, :green return true else debug "Failed to create Redfish session, falling back to direct mode", 1, :light_yellow @direct_mode = true return true end end |
#logout ⇒ Object
Logout from iDRAC
81 82 83 84 85 86 |
# File 'lib/idrac/client.rb', line 81 def logout session.delete if session.x_auth_token web.logout if web.session_id debug "Logged out from iDRAC", 1, :green return true end |
#redfish_version ⇒ Object
297 298 299 300 301 302 303 304 305 |
# File 'lib/idrac/client.rb', line 297 def redfish_version response = authenticated_request(:get, "/redfish/v1") if response.status == 200 data = JSON.parse(response.body) data["RedfishVersion"] else raise Error, "Failed to get Redfish version: #{response.status} - #{response.body}" end end |
#screenshot ⇒ Object
288 289 290 |
# File 'lib/idrac/client.rb', line 288 def screenshot web.capture_screenshot end |
#wait_for_task(task_id) ⇒ Object
Wait for a task to complete
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/idrac/client.rb', line 363 def wait_for_task(task_id) task = nil begin loop do task_response = authenticated_request(:get, "/redfish/v1/TaskService/Tasks/#{task_id}") case task_response.status # 200-299 when 200..299 task = JSON.parse(task_response.body) if task["TaskState"] != "Running" break end # Extract percentage complete if available percent_complete = nil if task["Oem"] && task["Oem"]["Dell"] && task["Oem"]["Dell"]["PercentComplete"] percent_complete = task["Oem"]["Dell"]["PercentComplete"] debug "Task progress: #{percent_complete}% complete", 1 end debug "Waiting for task to complete...: #{task["TaskState"]} #{task["TaskStatus"]}", 1 sleep 5 else return { status: :failed, error: "Failed to check task status: #{task_response.status} - #{task_response.body}" } end end # Check final task state if task["TaskState"] == "Completed" && task["TaskStatus"] == "OK" debugger return { status: :success } elsif task["SystemConfiguration"] # SystemConfigurationProfile requests yield a 202 with a SystemConfiguration key return task else # For debugging purposes debug task.inspect, 1, :yellow # Extract any messages from the response = [] if task["Messages"] && task["Messages"].is_a?(Array) = task["Messages"].map { |m| m["Message"] }.compact end return { status: :failed, task_state: task["TaskState"], task_status: task["TaskStatus"], messages: , error: .first || "Task failed with state: #{task["TaskState"]}" } end rescue => e debugger return { status: :error, error: "Exception monitoring task: #{e.}" } end end |
#with_retries(max_retries = nil, initial_delay = nil, error_classes = nil) { ... } ⇒ Object
Execute a block with automatic retries
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/idrac/client.rb', line 340 def with_retries(max_retries = nil, initial_delay = nil, error_classes = nil) # Use instance variables if not specified max_retries ||= @retry_count initial_delay ||= @retry_delay error_classes ||= [StandardError] retries = 0 begin yield rescue *error_classes => e retries += 1 if retries <= max_retries delay = initial_delay * (retries ** 1.5).to_i # Exponential backoff debug "RETRY: #{e.} - Attempt #{retries}/#{max_retries}, waiting #{delay}s", 1, :yellow sleep delay retry else debug "MAX RETRIES REACHED: #{e.} after #{max_retries} attempts", 1, :red raise e end end end |