Module: IDRAC::VirtualMedia

Included in:
Client
Defined in:
lib/idrac/virtual_media.rb

Instance Method Summary collapse

Instance Method Details

#eject_virtual_media(device: "CD") ⇒ Object

Eject virtual media from a device



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/idrac/virtual_media.rb', line 53

def eject_virtual_media(device: "CD")
  media_list = virtual_media
  
  # Find the device to eject
  media_to_eject = media_list.find { |m| m[:device] == device && m[:inserted] }
  
  if media_to_eject.nil?
    puts "No media #{device} to eject".yellow
    return false
  end
  
  puts "Ejecting #{media_to_eject[:device]} #{media_to_eject[:image]}".yellow
  
  # Use the action path from the media object if available
  path = if media_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"
         end
  
  response = authenticated_request(
    :post, 
    "/redfish/v1/#{path}",
    body: {}.to_json,
    headers: { 'Content-Type': 'application/json' }
  )

  handle_response(response)
  response.status.between?(200, 299)
end

#get_boot_source_overrideObject

Get current boot source override settings



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/idrac/virtual_media.rb', line 219

def get_boot_source_override
  response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1")
  
  if response.status == 200
    begin
      data = JSON.parse(response.body)
      boot = data["Boot"]
      
      puts "Boot Source Override Configuration:".green
      puts "  Enabled: #{boot['BootSourceOverrideEnabled']}"
      puts "  Target: #{boot['BootSourceOverrideTarget']}"
      puts "  Mode: #{boot['BootSourceOverrideMode']}" if boot['BootSourceOverrideMode']
      
      if boot["BootSourceOverrideEnabled"] != "Once" || boot["BootSourceOverrideTarget"] == "None"
        return "None"
      else
        return "#{boot['BootSourceOverrideMode']} #{boot['BootSourceOverrideTarget']}"
      end
    rescue JSON::ParserError
      raise Error, "Failed to parse boot source response: #{response.body}"
    end
  else
    raise Error, "Failed to get boot source override. Status code: #{response.status}"
  end
end

#insert_virtual_media(iso_url, device: "CD") ⇒ Object

Insert virtual media (ISO)

Raises:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/idrac/virtual_media.rb', line 85

def insert_virtual_media(iso_url, device: "CD")
  raise Error, "Device must be CD or RemovableDisk" unless ["CD", "RemovableDisk"].include?(device)
  
  # First eject any inserted media
  eject_virtual_media(device: device)
  
  # Firmware version determines which API to use
  firmware_version = get_firmware_version.split(".")[0,2].join.to_i
  
  puts "Inserting media: #{iso_url}".yellow
  
  tries = 0
  max_tries = 10
  
  while tries < max_tries
    begin
      # Different endpoint based on firmware version
      path = if firmware_version >= 600
              "Systems/System.Embedded.1/VirtualMedia/1/Actions/VirtualMedia.InsertMedia" 
             else
              "Managers/iDRAC.Embedded.1/VirtualMedia/#{device}/Actions/VirtualMedia.InsertMedia"
             end
      
      response = authenticated_request(
        :post, 
        "/redfish/v1/#{path}",
        body: { "Image": iso_url, "Inserted": true, "WriteProtected": true }.to_json,
        headers: { 'Content-Type': 'application/json' }
      )
      
      if response.status == 204 || response.status == 200
        puts "Inserted media successfully".green
        return true
      end
      
      # Handle error responses
      error_message = "Failed to insert media. Status code: #{response.status}"
      begin
        error_data = JSON.parse(response.body)
        if error_data["error"] && error_data["error"]["@Message.ExtendedInfo"]
          error_info = error_data["error"]["@Message.ExtendedInfo"].first
          error_message += ", Message: #{error_info['Message']}"
        end
      rescue
        # Ignore JSON parsing errors
      end
      
      puts "#{error_message}. Retrying (#{tries + 1}/#{max_tries})...".red
    rescue => e
      puts "Error during insert_virtual_media: #{e.message}. Retrying (#{tries + 1}/#{max_tries})...".red
    end
    
    tries += 1
    sleep 60 # Wait before retry
  end
  
  raise Error, "Failed to insert virtual media after #{max_tries} attempts"
end

#set_one_time_virtual_media_bootObject

Set boot to virtual media once, then boot from HD



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/idrac/virtual_media.rb', line 145

def set_one_time_virtual_media_boot
  # Check firmware version to determine which API to use
  firmware_version = get_firmware_version.split(".")[0,2].join.to_i
  
  if firmware_version >= 440 # Modern iDRAC
    # Check current boot configuration
    boot_response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1")
    if boot_response.status == 200
      boot_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}".yellow
    end
    
    # Set one-time boot to CD
    response = authenticated_request(
      :patch, 
      "/redfish/v1/Systems/System.Embedded.1",
      body: { "Boot": { "BootSourceOverrideTarget": "Cd", "BootSourceOverrideEnabled": "Once" } }.to_json,
      headers: { 'Content-Type': 'application/json' }
    )
    
    if response.status.between?(200, 299)
      puts "One-time boot to virtual media configured".green
      return true
    else
      error_message = "Failed to set one-time boot. Status code: #{response.status}"
      begin
        error_data = JSON.parse(response.body)
        if error_data["error"] && error_data["error"]["@Message.ExtendedInfo"]
          error_info = error_data["error"]["@Message.ExtendedInfo"].first
          error_message += ", Message: #{error_info['Message']}"
        end
      rescue
        # Ignore JSON parsing errors
      end
      
      raise Error, error_message
    end
  else
    # For older iDRAC, we need to use the iDRAC-specific method
    payload = { 
      "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' }
    )
    
    if response.status.between?(200, 299)
      puts "One-time boot to virtual media configured".green
      return true
    else
      error_message = "Failed to set one-time boot. Status code: #{response.status}"
      begin
        error_data = JSON.parse(response.body)
        if error_data["error"] && error_data["error"]["@Message.ExtendedInfo"]
          error_info = error_data["error"]["@Message.ExtendedInfo"].first
          error_message += ", Message: #{error_info['Message']}"
        end
      rescue
        # Ignore JSON parsing errors
      end
      
      raise Error, error_message
    end
  end
end

#virtual_mediaObject

Get current virtual media status



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/idrac/virtual_media.rb', line 7

def virtual_media
  response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1/VirtualMedia?$expand=*($levels=1)")
  
  if response.status == 200
    begin
      data = JSON.parse(response.body)
      
      media = data["Members"].map do |m|
        # Check if media is inserted based on multiple indicators
        is_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 it
        puts "ImageName is used for this iDRAC version".yellow if m["ImageName"]
        puts "Image is used for this iDRAC version".yellow if m["Image"]
        puts "ConnectedVia is used for this iDRAC version".yellow if m["ConnectedVia"]
        puts "Inserted is used for this iDRAC version".yellow if m["Inserted"]

        if is_inserted
          puts "#{m["Name"]} #{m["ConnectedVia"]} #{m["Image"] || m["ImageName"]}".green
        else
          puts "#{m["Name"]} #{m["ConnectedVia"]}".yellow
        end
        
        action_path = m.dig("Actions", "#VirtualMedia.InsertMedia", "target")
        
        { 
          device: m["Id"], 
          inserted: is_inserted, 
          image: m["Image"] || m["ImageName"] || m["ConnectedVia"],
          action_path: action_path
        }
      end
      
      return media
    rescue JSON::ParserError
      raise Error, "Failed to parse virtual media response: #{response.body}"
    end
  else
    raise Error, "Failed to get virtual media. Status code: #{response.status}"
  end
end