idrac 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c859d5dbe93470744821ac95422ad8e4a1ac065a0bf643b7c6a717b8488da996
4
- data.tar.gz: '019a9d9999f1fa8d5c0e1c88783e7ccbf9d8f10b6a32cc11bd38c83a94e5815e'
3
+ metadata.gz: 04a47e02d37a42167e7007aa92fc8f1d1b4023a52d44bb65ed1132a2035c110a
4
+ data.tar.gz: d17c640f8c8c238a6ea6aa4c037f39d2a9c2bfeaaebc478b1a464c75a648bbc4
5
5
  SHA512:
6
- metadata.gz: 483e33a17932027f62dc688b6e9c101f337d9b25cebdaa0e6c150072d934b3950c39c43ff8cab5cc9532c34765d0740ba26ecfbe4a5a3f34a35c96888386495f
7
- data.tar.gz: 79c1135bd0ecb5be85fbc746bd20862203b01b0b8d75a2e3444f7496850b870c3b467a5dfe00e77d8c84cd8aae2a0250db916c166a7c3eec6753667eb95bfe98
6
+ metadata.gz: a64a9f69bf757578c9d3fb6d95aeb54b33b4a6604ba432a0b52cdca1e0fdbb2451b19191e2ebbe2468a025648a985a8e5122559f04063db7be8fb20b9a997759
7
+ data.tar.gz: 867beff66c1896abe949e87bf65b0c5df5ce65bda9d5e443f31a490792db7a63c737fe1295ea7a85c70a4f43af01ee1d6cc545b43939b581b76ade5b6cd641d1
data/lib/idrac/client.rb CHANGED
@@ -286,6 +286,16 @@ module IDRAC
286
286
  web.capture_screenshot
287
287
  end
288
288
 
289
+ # Parse JSON string and convert to OpenStruct
290
+ # @param json [String] JSON string
291
+ # @param use_ostruct [Boolean] Whether to convert to OpenStruct (default: true)
292
+ # @return [OpenStruct, Hash] Parsed response
293
+ def parse_json(json, use_ostruct = true)
294
+ parsed = JSON.parse(json)
295
+ use_ostruct ? IDRAC::Util.to_ostruct(parsed) : parsed
296
+ end
297
+
298
+ # Kept for backward compatibility
289
299
  def base_url
290
300
  protocol = use_ssl ? 'https' : 'http'
291
301
  "#{protocol}://#{host}:#{port}"
@@ -294,8 +304,8 @@ module IDRAC
294
304
  def redfish_version
295
305
  response = authenticated_request(:get, "/redfish/v1")
296
306
  if response.status == 200
297
- data = JSON.parse(response.body)
298
- data["RedfishVersion"]
307
+ data = parse_json(response.body)
308
+ data.RedfishVersion
299
309
  else
300
310
  raise Error, "Failed to get Redfish version: #{response.status} - #{response.body}"
301
311
  end
data/lib/idrac/power.rb CHANGED
@@ -30,9 +30,9 @@ module IDRAC
30
30
  break
31
31
  when 409
32
32
  begin
33
- error_data = JSON.parse(response.body)
34
- if error_data["error"] && error_data["error"]["@Message.ExtendedInfo"] &&
35
- error_data["error"]["@Message.ExtendedInfo"].any? { |m| m["Message"] =~ /Server is already powered ON/ }
33
+ error_data = parse_json(response.body)
34
+ if error_data.error && error_data.error['@Message.ExtendedInfo'] &&
35
+ error_data.error['@Message.ExtendedInfo'].any? { |m| m.Message =~ /Server is already powered ON/ }
36
36
  puts "Server is already powered ON.".yellow
37
37
  return false
38
38
  else
@@ -84,9 +84,9 @@ module IDRAC
84
84
  when 409
85
85
  # Conflict -- Server is already off
86
86
  begin
87
- error_data = JSON.parse(response.body)
88
- if error_data["error"] && error_data["error"]["@Message.ExtendedInfo"] &&
89
- error_data["error"]["@Message.ExtendedInfo"].any? { |m| m["Message"] =~ /Server is already powered OFF/ }
87
+ error_data = parse_json(response.body)
88
+ if error_data.error && error_data.error['@Message.ExtendedInfo'] &&
89
+ error_data.error['@Message.ExtendedInfo'].any? { |m| m.Message =~ /Server is already powered OFF/ }
90
90
  puts "Server is already powered OFF.".yellow
91
91
  return false
92
92
  else
@@ -98,8 +98,8 @@ module IDRAC
98
98
  else
99
99
  error_message = "Failed to power off server. Status code: #{response.status}"
100
100
  begin
101
- error_data = JSON.parse(response.body)
102
- error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
101
+ error_data = parse_json(response.body)
102
+ error_message += ", Message: #{error_data.error.message}" if error_data.error && error_data.error.message
103
103
  rescue
104
104
  # Ignore JSON parsing errors
105
105
  end
@@ -137,8 +137,8 @@ module IDRAC
137
137
  else
138
138
  error_message = "Failed to reboot server. Status code: #{response.status}"
139
139
  begin
140
- error_data = JSON.parse(response.body)
141
- error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
140
+ error_data = parse_json(response.body)
141
+ error_message += ", Message: #{error_data.error.message}" if error_data.error && error_data.error.message
142
142
  rescue
143
143
  # Ignore JSON parsing errors
144
144
  end
@@ -156,8 +156,8 @@ module IDRAC
156
156
 
157
157
  if response.status == 200
158
158
  begin
159
- system_data = JSON.parse(response.body)
160
- return system_data["PowerState"]
159
+ system_data = parse_json(response.body)
160
+ return system_data.PowerState
161
161
  rescue JSON::ParserError
162
162
  raise Error, "Failed to parse power state response: #{response.body}"
163
163
  end
@@ -174,8 +174,8 @@ module IDRAC
174
174
 
175
175
  if response.status == 200
176
176
  begin
177
- data = JSON.parse(response.body)
178
- watts = data["PowerControl"][0]["PowerConsumedWatts"]
177
+ data = parse_json(response.body)
178
+ watts = data.PowerControl[0].PowerConsumedWatts
179
179
  # puts "Power usage: #{watts} watts".light_cyan
180
180
  return watts.to_f
181
181
  rescue JSON::ParserError
@@ -184,8 +184,8 @@ module IDRAC
184
184
  else
185
185
  error_message = "Failed to get power usage. Status code: #{response.status}"
186
186
  begin
187
- error_data = JSON.parse(response.body)
188
- error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
187
+ error_data = parse_json(response.body)
188
+ error_message += ", Message: #{error_data.error.message}" if error_data.error && error_data.error.message
189
189
  rescue
190
190
  # Ignore JSON parsing errors
191
191
  end
data/lib/idrac/system.rb CHANGED
@@ -9,21 +9,21 @@ module IDRAC
9
9
 
10
10
  if response.status == 200
11
11
  begin
12
- data = JSON.parse(response.body)
13
- memory = data["Members"].map do |m|
14
- dimm_name = m["Name"] # e.g. DIMM A1
12
+ data = parse_json(response.body)
13
+ memory = data.Members.map do |m|
14
+ dimm_name = m.Name # e.g. DIMM A1
15
15
  bank, index = /DIMM ([A-Z])(\d+)/.match(dimm_name).captures rescue [nil, nil]
16
16
 
17
- puts "DIMM: #{m["Model"]} #{m["Name"]} > #{m["CapacityMiB"]}MiB > #{m["Status"]["Health"]} > #{m["OperatingSpeedMhz"]}MHz > #{m["PartNumber"]} / #{m["SerialNumber"]}"
17
+ puts "DIMM: #{m.Model} #{m.Name} > #{m.CapacityMiB}MiB > #{m.Status.Health} > #{m.OperatingSpeedMhz}MHz > #{m.PartNumber} / #{m.SerialNumber}"
18
18
 
19
19
  {
20
- "model" => m["Model"],
21
- "name" => m["Name"],
22
- "capacity_bytes" => m["CapacityMiB"].to_i.megabyte,
23
- "health" => m["Status"]["Health"] ? m["Status"]["Health"] : "N/A",
24
- "speed_mhz" => m["OperatingSpeedMhz"],
25
- "part_number" => m["PartNumber"],
26
- "serial" => m["SerialNumber"],
20
+ "model" => m.Model,
21
+ "name" => m.Name,
22
+ "capacity_bytes" => m.CapacityMiB.to_i.megabyte,
23
+ "health" => m.Status.Health ? m.Status.Health : "N/A",
24
+ "speed_mhz" => m.OperatingSpeedMhz,
25
+ "part_number" => m.PartNumber,
26
+ "serial" => m.SerialNumber,
27
27
  "bank" => bank,
28
28
  "index" => index.to_i
29
29
  }
@@ -44,20 +44,20 @@ module IDRAC
44
44
 
45
45
  if response.status == 200
46
46
  begin
47
- data = JSON.parse(response.body)
47
+ data = parse_json(response.body)
48
48
  puts "Power Supplies".green
49
49
 
50
- psus = data["PowerSupplies"].map do |psu|
51
- puts "PSU: #{psu["Name"]} > #{psu["PowerInputWatts"]}W > #{psu["Status"]["Health"]}"
50
+ psus = data.PowerSupplies.map do |psu|
51
+ puts "PSU: #{psu.Name} > #{psu.PowerInputWatts}W > #{psu.Status.Health}"
52
52
  {
53
- "name" => psu["Name"],
54
- "voltage" => psu["LineInputVoltage"],
55
- "voltage_human" => psu["LineInputVoltageType"], # AC240V
56
- "watts" => psu["PowerInputWatts"],
57
- "part" => psu["PartNumber"],
58
- "model" => psu["Model"],
59
- "serial" => psu["SerialNumber"],
60
- "status" => psu["Status"]["Health"],
53
+ "name" => psu.Name,
54
+ "voltage" => psu.LineInputVoltage,
55
+ "voltage_human" => psu.LineInputVoltageType, # AC240V
56
+ "watts" => psu.PowerInputWatts,
57
+ "part" => psu.PartNumber,
58
+ "model" => psu.Model,
59
+ "serial" => psu.SerialNumber,
60
+ "status" => psu.Status.Health,
61
61
  }
62
62
  end
63
63
 
@@ -80,15 +80,15 @@ module IDRAC
80
80
  response = authenticated_request(:get, "/redfish/v1/Chassis/System.Embedded.1/Thermal?$expand=*($levels=1)")
81
81
 
82
82
  if response.status == 200
83
- data = JSON.parse(response.body)
83
+ data = parse_json(response.body)
84
84
 
85
- fans = data["Fans"].map do |fan|
86
- puts "Fan: #{fan["Name"]} > #{fan["Reading"]} > #{fan["Status"]["Health"]}"
85
+ fans = data.Fans.map do |fan|
86
+ puts "Fan: #{fan.Name} > #{fan.Reading} > #{fan.Status.Health}"
87
87
  {
88
- "name" => fan["Name"],
89
- "rpm" => fan["Reading"],
90
- "serial" => fan["SerialNumber"],
91
- "status" => fan["Status"]["Health"]
88
+ "name" => fan.Name,
89
+ "rpm" => fan.Reading,
90
+ "serial" => fan.SerialNumber,
91
+ "status" => fan.Status.Health
92
92
  }
93
93
  end
94
94
 
@@ -96,7 +96,7 @@ module IDRAC
96
96
  elsif response.status.between?(400, 499)
97
97
  # Check if system is powered off
98
98
  power_response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1?$select=PowerState")
99
- if power_response.status == 200 && JSON.parse(power_response.body)["PowerState"] == "Off"
99
+ if power_response.status == 200 && parse_json(power_response.body).PowerState == "Off"
100
100
  puts "WARN: System is off. Fans are not available.".yellow
101
101
  return []
102
102
  end
@@ -120,12 +120,12 @@ module IDRAC
120
120
 
121
121
  if response.status == 200
122
122
  begin
123
- adapters_data = JSON.parse(response.body)
123
+ adapters_data = parse_json(response.body)
124
124
 
125
125
  # Determine iDRAC version for different port paths
126
126
  idrac_version_response = authenticated_request(:get, "/redfish/v1")
127
- idrac_version_data = JSON.parse(idrac_version_response.body)
128
- server = idrac_version_data["RedfishVersion"] || idrac_version_response.headers["server"]
127
+ idrac_version_data = parse_json(idrac_version_response.body)
128
+ server = idrac_version_data.RedfishVersion || idrac_version_response.headers["server"]
129
129
 
130
130
  is_idrac9 = case server.to_s.downcase
131
131
  when /idrac\/9/
@@ -141,32 +141,32 @@ module IDRAC
141
141
 
142
142
  port_part = is_idrac9 ? 'Ports' : 'NetworkPorts'
143
143
 
144
- nics = adapters_data["Members"].map do |adapter|
145
- path = "#{adapter["@odata.id"].split("v1/").last}/#{port_part}?$expand=*($levels=1)"
144
+ nics = adapters_data.Members.map do |adapter|
145
+ path = "#{adapter['@odata.id'].split("v1/").last}/#{port_part}?$expand=*($levels=1)"
146
146
  ports_response = authenticated_request(:get, "/redfish/v1/#{path}")
147
147
 
148
148
  if ports_response.status == 200
149
- ports_data = JSON.parse(ports_response.body)
149
+ ports_data = parse_json(ports_response.body)
150
150
 
151
- ports = ports_data["Members"].map do |nic|
151
+ ports = ports_data.Members.map do |nic|
152
152
  if is_idrac9
153
- link_speed_mbps = nic['CurrentSpeedGbps'].to_i * 1000
154
- mac_addr = nic['Ethernet']['AssociatedMACAddresses'].first
155
- port_num = nic['PortId']
156
- network_technology = nic['LinkNetworkTechnology']
157
- link_status = nic['LinkStatus'] =~ /up/i ? "Up" : "Down"
153
+ link_speed_mbps = nic.CurrentSpeedGbps.to_i * 1000
154
+ mac_addr = nic.Ethernet.AssociatedMACAddresses.first
155
+ port_num = nic.PortId
156
+ network_technology = nic.LinkNetworkTechnology
157
+ link_status = nic.LinkStatus =~ /up/i ? "Up" : "Down"
158
158
  else # iDRAC 8
159
- link_speed_mbps = nic["SupportedLinkCapabilities"].first["LinkSpeedMbps"]
160
- mac_addr = nic["AssociatedNetworkAddresses"].first
161
- port_num = nic["PhysicalPortNumber"]
162
- network_technology = nic["SupportedLinkCapabilities"].first["LinkNetworkTechnology"]
163
- link_status = nic['LinkStatus']
159
+ link_speed_mbps = nic.SupportedLinkCapabilities.first.LinkSpeedMbps
160
+ mac_addr = nic.AssociatedNetworkAddresses.first
161
+ port_num = nic.PhysicalPortNumber
162
+ network_technology = nic.SupportedLinkCapabilities.first.LinkNetworkTechnology
163
+ link_status = nic.LinkStatus
164
164
  end
165
165
 
166
- puts "NIC: #{nic["Id"]} > #{mac_addr} > #{link_status} > #{port_num} > #{link_speed_mbps}Mbps"
166
+ puts "NIC: #{nic.Id} > #{mac_addr} > #{link_status} > #{port_num} > #{link_speed_mbps}Mbps"
167
167
 
168
168
  {
169
- "name" => nic["Id"],
169
+ "name" => nic.Id,
170
170
  "status" => link_status,
171
171
  "mac" => mac_addr,
172
172
  "port" => port_num,
@@ -176,21 +176,21 @@ module IDRAC
176
176
  end
177
177
 
178
178
  {
179
- "name" => adapter["Id"],
180
- "manufacturer" => adapter["Manufacturer"],
181
- "model" => adapter["Model"],
182
- "part_number" => adapter["PartNumber"],
183
- "serial" => adapter["SerialNumber"],
179
+ "name" => adapter.Id,
180
+ "manufacturer" => adapter.Manufacturer,
181
+ "model" => adapter.Model,
182
+ "part_number" => adapter.PartNumber,
183
+ "serial" => adapter.SerialNumber,
184
184
  "ports" => ports
185
185
  }
186
186
  else
187
187
  # Return adapter info without ports if we can't get port details
188
188
  {
189
- "name" => adapter["Id"],
190
- "manufacturer" => adapter["Manufacturer"],
191
- "model" => adapter["Model"],
192
- "part_number" => adapter["PartNumber"],
193
- "serial" => adapter["SerialNumber"],
189
+ "name" => adapter.Id,
190
+ "manufacturer" => adapter.Manufacturer,
191
+ "model" => adapter.Model,
192
+ "part_number" => adapter.PartNumber,
193
+ "serial" => adapter.SerialNumber,
194
194
  "ports" => []
195
195
  }
196
196
  end
@@ -211,17 +211,17 @@ module IDRAC
211
211
 
212
212
  if response.status == 200
213
213
  begin
214
- data = JSON.parse(response.body)
214
+ data = parse_json(response.body)
215
215
 
216
216
  idrac = {
217
- "name" => data["Id"],
218
- "status" => data["Status"]["Health"] == 'OK' ? 'Up' : 'Down',
219
- "mac" => data["MACAddress"],
220
- "mask" => data["IPv4Addresses"].first["SubnetMask"],
221
- "ipv4" => data["IPv4Addresses"].first["Address"],
222
- "origin" => data["IPv4Addresses"].first["AddressOrigin"], # DHCP or Static
217
+ "name" => data.Id,
218
+ "status" => data.Status.Health == 'OK' ? 'Up' : 'Down',
219
+ "mac" => data.MACAddress,
220
+ "mask" => data.IPv4Addresses.first.SubnetMask,
221
+ "ipv4" => data.IPv4Addresses.first.Address,
222
+ "origin" => data.IPv4Addresses.first.AddressOrigin, # DHCP or Static
223
223
  "port" => nil,
224
- "speed_mbps" => data["SpeedMbps"],
224
+ "speed_mbps" => data.SpeedMbps,
225
225
  "kind" => "ethernet"
226
226
  }
227
227
 
@@ -240,32 +240,32 @@ module IDRAC
240
240
 
241
241
  if response.status == 200
242
242
  begin
243
- data = JSON.parse(response.body)
243
+ data = parse_json(response.body)
244
244
 
245
- pci = data["Members"].map do |stub|
246
- manufacturer = stub["Manufacturer"]
245
+ pci = data.Members.map do |stub|
246
+ manufacturer = stub.Manufacturer
247
247
 
248
248
  # Get PCIe function details if available
249
249
  pcie_function = nil
250
- if stub.dig("Links", "PCIeFunctions", 0, "@odata.id")
251
- pcie_function_path = stub.dig("Links", "PCIeFunctions", 0, "@odata.id").split("v1/").last
250
+ if stub.dig(:Links, :PCIeFunctions, 0, :'@odata.id')
251
+ pcie_function_path = stub.dig(:Links, :PCIeFunctions, 0, :'@odata.id').split("v1/").last
252
252
  function_response = authenticated_request(:get, "/redfish/v1/#{pcie_function_path}")
253
253
 
254
254
  if function_response.status == 200
255
- pcie_function = JSON.parse(function_response.body)
255
+ pcie_function = parse_json(function_response.body)
256
256
  end
257
257
  end
258
258
 
259
259
  # Create device info with available data
260
260
  device_info = {
261
- device_class: pcie_function ? pcie_function["DeviceClass"] : nil,
261
+ device_class: pcie_function ? pcie_function.DeviceClass : nil,
262
262
  manufacturer: manufacturer,
263
- name: stub["Name"],
264
- description: stub["Description"],
265
- id: pcie_function ? pcie_function["Id"] : stub["Id"],
266
- slot_type: pcie_function ? pcie_function.dig("Oem", "Dell", "DellPCIeFunction", "SlotType") : nil,
267
- bus_width: pcie_function ? pcie_function.dig("Oem", "Dell", "DellPCIeFunction", "DataBusWidth") : nil,
268
- nic: pcie_function ? pcie_function.dig("Links", "EthernetInterfaces", 0, "@odata.id") : nil
263
+ name: stub.Name,
264
+ description: stub.Description,
265
+ id: pcie_function ? pcie_function.Id : stub.Id,
266
+ slot_type: pcie_function ? pcie_function.dig(:Oem, :Dell, :DellPCIeFunction, :SlotType) : nil,
267
+ bus_width: pcie_function ? pcie_function.dig(:Oem, :Dell, :DellPCIeFunction, :DataBusWidth) : nil,
268
+ nic: pcie_function ? pcie_function.dig(:Links, :EthernetInterfaces, 0, :'@odata.id') : nil
269
269
  }
270
270
 
271
271
  puts "PCI Device: #{device_info[:name]} > #{device_info[:manufacturer]} > #{device_info[:device_class]} > #{device_info[:description]} > #{device_info[:id]}"
@@ -331,15 +331,15 @@ module IDRAC
331
331
 
332
332
  if response.status == 200
333
333
  begin
334
- data = JSON.parse(response.body)
334
+ data = parse_json(response.body)
335
335
 
336
- logs = data["Members"].map do |log|
337
- puts "#{log['Id']} : #{log['Created']} : #{log['Message']} : #{log['Severity']}".yellow
336
+ logs = data.Members.map do |log|
337
+ puts "#{log.Id} : #{log.Created} : #{log.Message} : #{log.Severity}".yellow
338
338
  log
339
339
  end
340
340
 
341
341
  # Sort by creation date, newest first
342
- return logs.sort_by { |log| log['Created'] }.reverse
342
+ return logs.sort_by { |log| log.Created }.reverse
343
343
  rescue JSON::ParserError
344
344
  raise Error, "Failed to parse system event logs response: #{response.body}"
345
345
  end
@@ -364,7 +364,7 @@ module IDRAC
364
364
  error_message = "Failed to clear System Event Logs. Status code: #{response.status}"
365
365
 
366
366
  begin
367
- error_data = JSON.parse(response.body)
367
+ error_data = parse_json(response.body, false)
368
368
  error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
369
369
  rescue
370
370
  # Ignore JSON parsing errors
data/lib/idrac/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IDRAC
4
- VERSION = "0.3.3"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -9,31 +9,25 @@ module IDRAC
9
9
 
10
10
  if response.status == 200
11
11
  begin
12
- data = JSON.parse(response.body)
12
+ data = parse_json(response.body)
13
13
 
14
- media = data["Members"].map do |m|
15
- if m["Inserted"]
16
- puts "#{m["Name"]} #{m["ConnectedVia"]} #{m["Image"]}".green
17
- else
18
- puts "#{m["Name"]} #{m["ConnectedVia"]}".yellow
19
- end
20
-
21
- action_path = m.dig("Actions", "#VirtualMedia.InsertMedia", "target")
22
-
23
- {
24
- device: m["Id"],
25
- inserted: m["Inserted"],
26
- image: m["Image"] || m["ConnectedVia"],
27
- action_path: action_path
14
+ media = data.Members.map do |m|
15
+ {
16
+ "id" => m.Id,
17
+ "name" => m.Name,
18
+ "media_types" => m.MediaTypes,
19
+ "connected" => m.Inserted,
20
+ "image" => m.Image,
21
+ "write_protected" => m.WriteProtected
28
22
  }
29
23
  end
30
24
 
31
25
  return media
32
- rescue JSON::ParserError
33
- raise Error, "Failed to parse virtual media response: #{response.body}"
26
+ rescue => e
27
+ raise Error, "Failed to get virtual media status: #{e.message}"
34
28
  end
35
29
  else
36
- raise Error, "Failed to get virtual media. Status code: #{response.status}"
30
+ raise Error, "Failed to get virtual media status. Status code: #{response.status}"
37
31
  end
38
32
  end
39
33
 
data/lib/idrac.rb CHANGED
@@ -7,6 +7,7 @@ require 'faraday/multipart'
7
7
  require 'base64'
8
8
  require 'uri'
9
9
  require 'colorize'
10
+ require 'ostruct'
10
11
  # If dev, required debug
11
12
  require 'debug' if ENV['RUBY_ENV'] == 'development'
12
13
 
@@ -29,6 +30,23 @@ module IDRAC
29
30
  end
30
31
  end
31
32
 
33
+ # Utility methods for the IDRAC module
34
+ module Util
35
+ # Recursively converts a hash to an OpenStruct
36
+ # @param obj [Hash, Array, Object] The object to convert
37
+ # @return [OpenStruct, Array, Object] The converted object
38
+ def self.to_ostruct(obj)
39
+ case obj
40
+ when Hash
41
+ OpenStruct.new(obj.transform_values { |val| to_ostruct(val) })
42
+ when Array
43
+ obj.map { |item| to_ostruct(item) }
44
+ else
45
+ obj
46
+ end
47
+ end
48
+ end
49
+
32
50
  class Error < StandardError; end
33
51
 
34
52
  def self.new(options = {})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idrac
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel