require'json'require'colorize'moduleIDRACmoduleVirtualMedia# Get current virtual media statusdefvirtual_mediaresponse=authenticated_request(:get,"/redfish/v1/Managers/iDRAC.Embedded.1/VirtualMedia?$expand=*($levels=1)")ifresponse.status==200begindata=JSON.parse(response.body)media=data["Members"].mapdo|m|# Check if media is inserted based on multiple indicatorsis_inserted=m["Inserted"]||(!m["Image"].nil?&&!m["Image"].empty?)||(m["ConnectedVia"]&&m["ConnectedVia"]!="NotConnected")||(m["ImageName"]&&!m["ImageName"].empty?)# Indicate which field is used for this iDRAC version and print itputs"ImageName is used for this iDRAC version".yellowifm["ImageName"]puts"Image is used for this iDRAC version".yellowifm["Image"]puts"ConnectedVia is used for this iDRAC version".yellowifm["ConnectedVia"]puts"Inserted is used for this iDRAC version".yellowifm["Inserted"]ifis_insertedputs"#{m["Name"]}#{m["ConnectedVia"]}#{m["Image"]||m["ImageName"]}".greenelseputs"#{m["Name"]}#{m["ConnectedVia"]}".yellowendaction_path=m.dig("Actions","#VirtualMedia.InsertMedia","target"){device: m["Id"],inserted: is_inserted,image: m["Image"]||m["ImageName"]||m["ConnectedVia"],action_path: action_path}endreturnmediarescueJSON::ParserErrorraiseError,"Failed to parse virtual media response: #{response.body}"endelseraiseError,"Failed to get virtual media. Status code: #{response.status}"endend# Eject virtual media from a devicedefeject_virtual_media(device: "CD")media_list=virtual_media# Find the device to ejectmedia_to_eject=media_list.find{|m|m[:device]==device&&m[:inserted]}ifmedia_to_eject.nil?puts"No media #{device} to eject".yellowreturnfalseendputs"Ejecting #{media_to_eject[:device]}#{media_to_eject[:image]}".yellow# Use the action path from the media object if availablepath=ifmedia_to_eject[:action_path]media_to_eject[:action_path].sub(/^\/redfish\/v1\//,"").sub(/InsertMedia$/,"EjectMedia")else"Managers/iDRAC.Embedded.1/VirtualMedia/#{device}/Actions/VirtualMedia.EjectMedia"endresponse=authenticated_request(:post,"/redfish/v1/#{path}",body: {}.to_json,headers: {'Content-Type':'application/json'})handle_response(response)response.status.between?(200,299)end# Insert virtual media (ISO)definsert_virtual_media(iso_url,device: "CD")raiseError,"Device must be CD or RemovableDisk"unless["CD","RemovableDisk"].include?(device)# First eject any inserted mediaeject_virtual_media(device: device)# Firmware version determines which API to usefirmware_version=get_firmware_version.split(".")[0,2].join.to_iputs"Inserting media: #{iso_url}".yellowtries=0max_tries=10whiletries<max_triesbegin# Different endpoint based on firmware versionpath=iffirmware_version>=600"Systems/System.Embedded.1/VirtualMedia/1/Actions/VirtualMedia.InsertMedia"else"Managers/iDRAC.Embedded.1/VirtualMedia/#{device}/Actions/VirtualMedia.InsertMedia"endresponse=authenticated_request(:post,"/redfish/v1/#{path}",body: {"Image":iso_url,"Inserted":true,"WriteProtected":true}.to_json,headers: {'Content-Type':'application/json'})ifresponse.status==204||response.status==200puts"Inserted media successfully".greenreturntrueend# Handle error responseserror_message="Failed to insert media. Status code: #{response.status}"beginerror_data=JSON.parse(response.body)iferror_data["error"]&&error_data["error"]["@Message.ExtendedInfo"]error_info=error_data["error"]["@Message.ExtendedInfo"].firsterror_message+=", Message: #{error_info['Message']}"endrescue# Ignore JSON parsing errorsendputs"#{error_message}. Retrying (#{tries+1}/#{max_tries})...".redrescue=>eputs"Error during insert_virtual_media: #{e.message}. Retrying (#{tries+1}/#{max_tries})...".redendtries+=1sleep60# Wait before retryendraiseError,"Failed to insert virtual media after #{max_tries} attempts"end# Set boot to virtual media once, then boot from HDdefset_one_time_virtual_media_boot# Check firmware version to determine which API to usefirmware_version=get_firmware_version.split(".")[0,2].join.to_iiffirmware_version>=440# Modern iDRAC# Check current boot configurationboot_response=authenticated_request(:get,"/redfish/v1/Systems/System.Embedded.1")ifboot_response.status==200boot_data=JSON.parse(boot_response.body)enabled=boot_data['Boot']['BootSourceOverrideEnabled']target=boot_data['Boot']['BootSourceOverrideTarget']puts"Currently override is #{enabled} to boot from #{target}".yellowend# Set one-time boot to CDresponse=authenticated_request(:patch,"/redfish/v1/Systems/System.Embedded.1",body: {"Boot":{"BootSourceOverrideTarget":"Cd","BootSourceOverrideEnabled":"Once"}}.to_json,headers: {'Content-Type':'application/json'})ifresponse.status.between?(200,299)puts"One-time boot to virtual media configured".greenreturntrueelseerror_message="Failed to set one-time boot. Status code: #{response.status}"beginerror_data=JSON.parse(response.body)iferror_data["error"]&&error_data["error"]["@Message.ExtendedInfo"]error_info=error_data["error"]["@Message.ExtendedInfo"].firsterror_message+=", Message: #{error_info['Message']}"endrescue# Ignore JSON parsing errorsendraiseError,error_messageendelse# For older iDRAC, we need to use the iDRAC-specific methodpayload={"ServerBoot.1#BootOnce":"Enabled","ServerBoot.1#FirstBootDevice":"VCD-DVD"}response=authenticated_request(:patch,"/redfish/v1/Managers/iDRAC.Embedded.1/Attributes",body: payload.to_json,headers: {'Content-Type':'application/json'})ifresponse.status.between?(200,299)puts"One-time boot to virtual media configured".greenreturntrueelseerror_message="Failed to set one-time boot. Status code: #{response.status}"beginerror_data=JSON.parse(response.body)iferror_data["error"]&&error_data["error"]["@Message.ExtendedInfo"]error_info=error_data["error"]["@Message.ExtendedInfo"].firsterror_message+=", Message: #{error_info['Message']}"endrescue# Ignore JSON parsing errorsendraiseError,error_messageendendend# Get current boot source override settingsdefget_boot_source_overrideresponse=authenticated_request(:get,"/redfish/v1/Systems/System.Embedded.1")ifresponse.status==200begindata=JSON.parse(response.body)boot=data["Boot"]puts"Boot Source Override Configuration:".greenputs" Enabled: #{boot['BootSourceOverrideEnabled']}"puts" Target: #{boot['BootSourceOverrideTarget']}"puts" Mode: #{boot['BootSourceOverrideMode']}"ifboot['BootSourceOverrideMode']ifboot["BootSourceOverrideEnabled"]!="Once"||boot["BootSourceOverrideTarget"]=="None"return"None"elsereturn"#{boot['BootSourceOverrideMode']}#{boot['BootSourceOverrideTarget']}"endrescueJSON::ParserErrorraiseError,"Failed to parse boot source response: #{response.body}"endelseraiseError,"Failed to get boot source override. Status code: #{response.status}"endendprivateendend