radfish-idrac 0.1.3 → 0.1.5
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 +4 -4
- data/lib/radfish/idrac/version.rb +1 -1
- data/lib/radfish/idrac_adapter.rb +453 -57
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd2c3bf25651e2968b2bbb5646abfe3be4af7679d750f1f5d958a8440db7762a
|
4
|
+
data.tar.gz: e6235fd71297dc9ef3feea51d9d30e8ad80e645e4b37e8000a396be45fa628ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8a449130e8451cf9eacb9fc5cccbba1d8180ce874933488426b8ae1c589313a8ba6f725115351b40b2cf8c334869b6973c2d076231fe3347cbe96eed2727fb5
|
7
|
+
data.tar.gz: 8835042ad7199c7a88965099f2e5473101db5e5c7597ba09a195b1b790743aee2f2c2f7a1ba1110697094ac3dd8737154123e3c84f4bded61ea1f036c842888f
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'radfish'
|
4
4
|
require 'idrac'
|
5
|
+
require 'ostruct'
|
5
6
|
|
6
7
|
module Radfish
|
7
8
|
class IdracAdapter < Core::BaseClient
|
@@ -63,30 +64,95 @@ module Radfish
|
|
63
64
|
@idrac_client.get_power_state
|
64
65
|
end
|
65
66
|
|
66
|
-
def power_on
|
67
|
-
@idrac_client.power_on
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
def power_on(wait: true)
|
68
|
+
result = @idrac_client.power_on
|
69
|
+
|
70
|
+
if wait && result
|
71
|
+
# Wait for power on to complete
|
72
|
+
max_attempts = 30
|
73
|
+
attempts = 0
|
74
|
+
while attempts < max_attempts
|
75
|
+
sleep 2
|
76
|
+
begin
|
77
|
+
status = power_state
|
78
|
+
break if status == "On"
|
79
|
+
rescue => e
|
80
|
+
# BMC might be temporarily unavailable during power operations
|
81
|
+
debug "Waiting for BMC to respond: #{e.message}", 1, :yellow
|
82
|
+
end
|
83
|
+
attempts += 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
result
|
73
88
|
end
|
74
89
|
|
75
|
-
def
|
76
|
-
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
#
|
81
|
-
|
90
|
+
def power_off(type: "GracefulShutdown", wait: true)
|
91
|
+
# Use the type parameter directly - it already uses Redfish standard values
|
92
|
+
result = @idrac_client.power_off(kind: type)
|
93
|
+
|
94
|
+
if wait && result
|
95
|
+
# Wait for power off to complete
|
96
|
+
max_attempts = 30
|
97
|
+
attempts = 0
|
98
|
+
while attempts < max_attempts
|
99
|
+
sleep 2
|
100
|
+
begin
|
101
|
+
status = power_state
|
102
|
+
break if status == "Off"
|
103
|
+
rescue => e
|
104
|
+
# BMC might be temporarily unavailable during power operations
|
105
|
+
debug "Waiting for BMC to respond: #{e.message}", 1, :yellow
|
106
|
+
end
|
107
|
+
attempts += 1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
result
|
112
|
+
end
|
113
|
+
|
114
|
+
def reboot(type: "GracefulRestart", wait: true)
|
115
|
+
# Use the type parameter - iDRAC's power_off can handle restart types
|
116
|
+
begin
|
117
|
+
result = @idrac_client.power_off(kind: type)
|
118
|
+
rescue => e
|
119
|
+
# If graceful restart fails, fall back to force restart
|
120
|
+
if type == "GracefulRestart"
|
121
|
+
debug "Graceful restart failed, using force restart", 1, :yellow
|
122
|
+
result = @idrac_client.reboot # This is ForceRestart
|
123
|
+
else
|
124
|
+
raise e
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if wait && result
|
129
|
+
# Wait for system to go down then come back up
|
130
|
+
max_attempts = 60
|
131
|
+
attempts = 0
|
132
|
+
went_down = false
|
133
|
+
|
134
|
+
while attempts < max_attempts
|
135
|
+
sleep 2
|
136
|
+
begin
|
137
|
+
status = power_state
|
138
|
+
went_down = true if status == "Off" && !went_down
|
139
|
+
break if went_down && status == "On"
|
140
|
+
rescue => e
|
141
|
+
# BMC might be temporarily unavailable during reboot
|
142
|
+
debug "Waiting for BMC during reboot: #{e.message}", 1, :yellow
|
143
|
+
end
|
144
|
+
attempts += 1
|
145
|
+
end
|
82
146
|
end
|
147
|
+
|
148
|
+
result
|
83
149
|
end
|
84
150
|
|
85
|
-
def power_cycle
|
86
|
-
#
|
87
|
-
power_off
|
151
|
+
def power_cycle(wait: true)
|
152
|
+
# Power cycle: turn off then on
|
153
|
+
power_off(type: "ForceOff", wait: wait)
|
88
154
|
sleep 5
|
89
|
-
power_on
|
155
|
+
power_on(wait: wait)
|
90
156
|
end
|
91
157
|
|
92
158
|
def reset_type_allowed
|
@@ -97,35 +163,123 @@ module Radfish
|
|
97
163
|
# System information
|
98
164
|
|
99
165
|
def system_info
|
100
|
-
|
166
|
+
# iDRAC gem returns string keys, convert to symbols for radfish
|
167
|
+
info = @idrac_client.system_info
|
168
|
+
|
169
|
+
# Dell servers always have "Dell Inc." as manufacturer
|
170
|
+
# Normalize for consistency
|
171
|
+
manufacturer = "Dell"
|
172
|
+
|
173
|
+
model = info["model"]
|
174
|
+
model = model&.gsub(/^PowerEdge\s+/i, '') if model # Strip PowerEdge prefix
|
175
|
+
|
176
|
+
{
|
177
|
+
service_tag: info["service_tag"],
|
178
|
+
manufacturer: manufacturer,
|
179
|
+
make: manufacturer,
|
180
|
+
model: model,
|
181
|
+
serial: info["service_tag"], # Dell uses service tag as serial
|
182
|
+
serial_number: info["service_tag"],
|
183
|
+
firmware_version: info["firmware_version"],
|
184
|
+
idrac_version: info["idrac_version"],
|
185
|
+
is_dell: info["is_dell"]
|
186
|
+
}.compact
|
187
|
+
end
|
188
|
+
|
189
|
+
# Individual accessor methods for Core::System interface
|
190
|
+
def service_tag
|
191
|
+
@service_tag ||= @idrac_client.system_info["service_tag"]
|
192
|
+
end
|
193
|
+
|
194
|
+
def make
|
195
|
+
"Dell"
|
196
|
+
end
|
197
|
+
|
198
|
+
def model
|
199
|
+
@model ||= begin
|
200
|
+
model = @idrac_client.system_info["model"]
|
201
|
+
model&.gsub(/^PowerEdge\s+/i, '') if model # Strip PowerEdge prefix
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def serial
|
206
|
+
@serial ||= @idrac_client.system_info["service_tag"] # Dell uses service tag as serial
|
101
207
|
end
|
102
208
|
|
103
209
|
def cpus
|
104
|
-
|
210
|
+
# The idrac gem returns a summary hash, but radfish expects an array of CPU objects
|
211
|
+
# For Dell servers, typically all CPUs are identical, so we create objects based on the summary
|
212
|
+
cpu_summary = @idrac_client.cpus
|
213
|
+
|
214
|
+
# Create CPU objects that support dot notation
|
215
|
+
count = cpu_summary["count"] || 0
|
216
|
+
return [] if count == 0
|
217
|
+
|
218
|
+
# For each CPU socket, create an object
|
219
|
+
# Dell typically has identical CPUs, so we use the summary data for each
|
220
|
+
(1..count).map do |socket_num|
|
221
|
+
OpenStruct.new(
|
222
|
+
socket: socket_num,
|
223
|
+
manufacturer: "Intel", # Dell servers typically use Intel
|
224
|
+
model: cpu_summary["model"],
|
225
|
+
speed_mhz: nil, # Not provided in summary
|
226
|
+
cores: cpu_summary["cores"] ? (cpu_summary["cores"] / count) : nil,
|
227
|
+
threads: cpu_summary["threads"] ? (cpu_summary["threads"] / count) : nil,
|
228
|
+
health: cpu_summary["status"]
|
229
|
+
)
|
230
|
+
end
|
105
231
|
end
|
106
232
|
|
107
233
|
def memory
|
108
|
-
@idrac_client.memory
|
234
|
+
mem_data = @idrac_client.memory
|
235
|
+
return [] unless mem_data
|
236
|
+
|
237
|
+
# Convert to OpenStruct for dot notation access
|
238
|
+
mem_data.map { |m| OpenStruct.new(m) }
|
109
239
|
end
|
110
240
|
|
111
241
|
def nics
|
112
|
-
@idrac_client.nics
|
242
|
+
nic_data = @idrac_client.nics
|
243
|
+
return [] unless nic_data
|
244
|
+
|
245
|
+
# Convert to OpenStruct for dot notation access, including nested ports
|
246
|
+
nic_data.map do |nic|
|
247
|
+
if nic["ports"]
|
248
|
+
nic["ports"] = nic["ports"].map { |port| OpenStruct.new(port) }
|
249
|
+
end
|
250
|
+
OpenStruct.new(nic)
|
251
|
+
end
|
113
252
|
end
|
114
253
|
|
115
254
|
def fans
|
116
|
-
|
255
|
+
# Convert hash array to OpenStruct objects for dot notation access
|
256
|
+
fan_data = @idrac_client.fans
|
257
|
+
|
258
|
+
fan_data.map do |fan|
|
259
|
+
OpenStruct.new(fan)
|
260
|
+
end
|
117
261
|
end
|
118
262
|
|
119
263
|
def temperatures
|
120
|
-
|
264
|
+
# iDRAC doesn't provide a dedicated temperatures method
|
265
|
+
# Return empty array to satisfy the interface
|
266
|
+
[]
|
121
267
|
end
|
122
268
|
|
123
269
|
def psus
|
124
|
-
|
270
|
+
# Convert hash array to OpenStruct objects for dot notation access
|
271
|
+
psu_data = @idrac_client.psus
|
272
|
+
|
273
|
+
psu_data.map do |psu|
|
274
|
+
OpenStruct.new(psu)
|
275
|
+
end
|
125
276
|
end
|
126
277
|
|
127
278
|
def power_consumption
|
128
|
-
|
279
|
+
# Return a hash with power consumption data for radfish
|
280
|
+
{
|
281
|
+
consumed_watts: @idrac_client.get_power_usage_watts
|
282
|
+
}
|
129
283
|
end
|
130
284
|
|
131
285
|
def power_consumption_watts
|
@@ -135,19 +289,69 @@ module Radfish
|
|
135
289
|
# Storage
|
136
290
|
|
137
291
|
def storage_controllers
|
138
|
-
|
292
|
+
# Convert hash array to OpenStruct objects for dot notation access
|
293
|
+
# Note: idrac gem uses 'controllers' not 'storage_controllers'
|
294
|
+
controller_data = @idrac_client.controllers
|
295
|
+
|
296
|
+
controller_data.map do |controller|
|
297
|
+
# Convert drives array to OpenStruct objects if present
|
298
|
+
if controller["drives"]
|
299
|
+
controller["drives"] = controller["drives"].map { |drive| OpenStruct.new(drive) }
|
300
|
+
end
|
301
|
+
OpenStruct.new(controller)
|
302
|
+
end
|
139
303
|
end
|
140
304
|
|
141
|
-
def drives
|
142
|
-
|
305
|
+
def drives(controller_id)
|
306
|
+
# The iDRAC gem requires a controller_id
|
307
|
+
raise ArgumentError, "Controller ID is required" unless controller_id
|
308
|
+
|
309
|
+
drive_data = @idrac_client.drives(controller_id)
|
310
|
+
|
311
|
+
# Convert to OpenStruct for consistency
|
312
|
+
drive_data.map { |drive| OpenStruct.new(drive) }
|
143
313
|
end
|
144
314
|
|
145
|
-
def volumes
|
146
|
-
|
315
|
+
def volumes(controller_id)
|
316
|
+
# The iDRAC gem requires a controller_id
|
317
|
+
raise ArgumentError, "Controller ID is required" unless controller_id
|
318
|
+
|
319
|
+
volume_data = @idrac_client.volumes(controller_id)
|
320
|
+
|
321
|
+
# Convert to OpenStruct for consistency
|
322
|
+
volume_data.map { |volume| OpenStruct.new(volume) }
|
147
323
|
end
|
148
324
|
|
149
325
|
def storage_summary
|
150
|
-
|
326
|
+
# The iDRAC gem doesn't have a storage_summary method
|
327
|
+
# We need to build it from controllers, drives, and volumes
|
328
|
+
begin
|
329
|
+
controllers = @idrac_client.controllers
|
330
|
+
total_drives = 0
|
331
|
+
total_volumes = 0
|
332
|
+
|
333
|
+
controllers.each do |controller|
|
334
|
+
if controller["@odata.id"]
|
335
|
+
drives = @idrac_client.drives(controller["@odata.id"]) rescue []
|
336
|
+
volumes = @idrac_client.volumes(controller["@odata.id"]) rescue []
|
337
|
+
total_drives += drives.size
|
338
|
+
total_volumes += volumes.size
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
{
|
343
|
+
"controller_count" => controllers.size,
|
344
|
+
"drive_count" => total_drives,
|
345
|
+
"volume_count" => total_volumes
|
346
|
+
}
|
347
|
+
rescue => e
|
348
|
+
puts "Error fetching storage summary: #{e.message}" if @debug
|
349
|
+
{
|
350
|
+
"controller_count" => 0,
|
351
|
+
"drive_count" => 0,
|
352
|
+
"volume_count" => 0
|
353
|
+
}
|
354
|
+
end
|
151
355
|
end
|
152
356
|
|
153
357
|
# Virtual Media
|
@@ -156,12 +360,41 @@ module Radfish
|
|
156
360
|
@idrac_client.virtual_media
|
157
361
|
end
|
158
362
|
|
159
|
-
def insert_virtual_media(iso_url, device:
|
363
|
+
def insert_virtual_media(iso_url, device: nil)
|
364
|
+
# Default to "CD" for iDRAC if not specified
|
365
|
+
device ||= "CD"
|
160
366
|
@idrac_client.insert_virtual_media(iso_url, device: device)
|
367
|
+
rescue Idrac::Error => e
|
368
|
+
# Translate iDRAC errors to Radfish errors with context
|
369
|
+
error_message = e.message
|
370
|
+
|
371
|
+
if error_message.include?("connection refused") || error_message.include?("unreachable")
|
372
|
+
raise Radfish::VirtualMediaConnectionError, "BMC cannot reach ISO server: #{error_message}"
|
373
|
+
elsif error_message.include?("already attached") || error_message.include?("in use")
|
374
|
+
raise Radfish::VirtualMediaBusyError, "Virtual media device busy: #{error_message}"
|
375
|
+
elsif error_message.include?("not found") || error_message.include?("does not exist")
|
376
|
+
raise Radfish::VirtualMediaNotFoundError, "Virtual media device not found: #{error_message}"
|
377
|
+
elsif error_message.include?("timeout")
|
378
|
+
raise Radfish::TaskTimeoutError, "Virtual media operation timed out: #{error_message}"
|
379
|
+
else
|
380
|
+
# Generic virtual media error
|
381
|
+
raise Radfish::VirtualMediaError, error_message
|
382
|
+
end
|
383
|
+
rescue StandardError => e
|
384
|
+
# Catch any other errors and wrap them
|
385
|
+
raise Radfish::VirtualMediaError, "Virtual media insertion failed: #{e.message}"
|
161
386
|
end
|
162
387
|
|
163
388
|
def eject_virtual_media(device: "CD")
|
164
389
|
@idrac_client.eject_virtual_media(device: device)
|
390
|
+
rescue Idrac::Error => e
|
391
|
+
if e.message.include?("not found") || e.message.include?("does not exist")
|
392
|
+
raise Radfish::VirtualMediaNotFoundError, "Virtual media device not found: #{e.message}"
|
393
|
+
else
|
394
|
+
raise Radfish::VirtualMediaError, "Failed to eject virtual media: #{e.message}"
|
395
|
+
end
|
396
|
+
rescue StandardError => e
|
397
|
+
raise Radfish::VirtualMediaError, "Failed to eject virtual media: #{e.message}"
|
165
398
|
end
|
166
399
|
|
167
400
|
def virtual_media_status
|
@@ -188,12 +421,24 @@ module Radfish
|
|
188
421
|
|
189
422
|
# Boot configuration
|
190
423
|
|
424
|
+
def boot_config
|
425
|
+
# Return hash for consistent data structure
|
426
|
+
@idrac_client.boot_config
|
427
|
+
end
|
428
|
+
|
429
|
+
# Shorter alias for convenience
|
430
|
+
def boot
|
431
|
+
boot_config
|
432
|
+
end
|
433
|
+
|
191
434
|
def boot_options
|
192
|
-
|
435
|
+
# Return array of OpenStructs for boot options
|
436
|
+
options = @idrac_client.boot_options
|
437
|
+
options.map { |opt| OpenStruct.new(opt) }
|
193
438
|
end
|
194
439
|
|
195
|
-
def set_boot_override(target,
|
196
|
-
@idrac_client.set_boot_override(target,
|
440
|
+
def set_boot_override(target, enabled: "Once", mode: nil)
|
441
|
+
@idrac_client.set_boot_override(target, enabled: enabled, mode: mode)
|
197
442
|
end
|
198
443
|
|
199
444
|
def clear_boot_override
|
@@ -208,24 +453,45 @@ module Radfish
|
|
208
453
|
@idrac_client.get_boot_devices
|
209
454
|
end
|
210
455
|
|
211
|
-
def boot_to_pxe
|
212
|
-
@idrac_client.boot_to_pxe
|
456
|
+
def boot_to_pxe(enabled: "Once", mode: nil)
|
457
|
+
@idrac_client.boot_to_pxe(enabled: enabled, mode: mode)
|
458
|
+
end
|
459
|
+
|
460
|
+
def boot_to_disk(enabled: "Once", mode: nil)
|
461
|
+
@idrac_client.boot_to_disk(enabled: enabled, mode: mode)
|
213
462
|
end
|
214
463
|
|
215
|
-
def
|
216
|
-
@idrac_client.
|
464
|
+
def boot_to_cd(enabled: "Once", mode: nil)
|
465
|
+
@idrac_client.boot_to_cd(enabled: enabled, mode: mode)
|
217
466
|
end
|
218
467
|
|
219
|
-
def
|
220
|
-
@idrac_client.
|
468
|
+
def boot_to_usb(enabled: "Once", mode: nil)
|
469
|
+
@idrac_client.boot_to_usb(enabled: enabled, mode: mode)
|
221
470
|
end
|
222
471
|
|
223
|
-
def
|
224
|
-
@idrac_client.
|
472
|
+
def boot_to_bios_setup(enabled: "Once", mode: nil)
|
473
|
+
@idrac_client.boot_to_bios_setup(enabled: enabled, mode: mode)
|
474
|
+
end
|
475
|
+
|
476
|
+
# PCI Devices
|
477
|
+
|
478
|
+
def pci_devices
|
479
|
+
devices = @idrac_client.pci_devices
|
480
|
+
return [] unless devices
|
481
|
+
|
482
|
+
# Convert to OpenStruct for dot notation access
|
483
|
+
devices.map { |device| OpenStruct.new(device) }
|
225
484
|
end
|
226
485
|
|
227
|
-
def
|
228
|
-
@idrac_client.
|
486
|
+
def nics_with_pci_info
|
487
|
+
nics = @idrac_client.nics
|
488
|
+
pci = pci_devices
|
489
|
+
|
490
|
+
# Use the existing nics_to_pci method from idrac gem
|
491
|
+
nics_with_pci = @idrac_client.nics_to_pci(nics, pci.map(&:to_h))
|
492
|
+
|
493
|
+
# Convert to OpenStruct
|
494
|
+
nics_with_pci.map { |nic| OpenStruct.new(nic) }
|
229
495
|
end
|
230
496
|
|
231
497
|
# Jobs
|
@@ -246,14 +512,112 @@ module Radfish
|
|
246
512
|
@idrac_client.cancel_job(job_id)
|
247
513
|
end
|
248
514
|
|
249
|
-
def
|
250
|
-
@idrac_client.clear_jobs
|
515
|
+
def clear_jobs!
|
516
|
+
@idrac_client.clear_jobs!
|
251
517
|
end
|
252
518
|
|
253
519
|
def jobs_summary
|
254
520
|
jobs
|
255
521
|
end
|
256
522
|
|
523
|
+
# BMC Management
|
524
|
+
|
525
|
+
def ensure_vendor_specific_bmc_ready!
|
526
|
+
# For iDRAC, ensure the Lifecycle Controller is enabled
|
527
|
+
@idrac_client.ensure_lifecycle_controller!
|
528
|
+
end
|
529
|
+
|
530
|
+
# BIOS Configuration
|
531
|
+
|
532
|
+
def bios_error_prompt_disabled?
|
533
|
+
@idrac_client.bios_error_prompt_disabled?
|
534
|
+
end
|
535
|
+
|
536
|
+
def bios_hdd_placeholder_enabled?
|
537
|
+
@idrac_client.bios_hdd_placeholder_enabled?
|
538
|
+
end
|
539
|
+
|
540
|
+
def bios_os_power_control_enabled?
|
541
|
+
@idrac_client.bios_os_power_control_enabled?
|
542
|
+
end
|
543
|
+
|
544
|
+
def ensure_uefi_boot
|
545
|
+
@idrac_client.ensure_uefi_boot
|
546
|
+
end
|
547
|
+
|
548
|
+
def set_one_time_boot_to_virtual_media
|
549
|
+
# Use iDRAC's existing method for setting one-time boot to virtual media
|
550
|
+
@idrac_client.set_one_time_virtual_media_boot
|
551
|
+
end
|
552
|
+
|
553
|
+
def set_boot_order_hd_first
|
554
|
+
# Use iDRAC's existing method for setting boot order to HD first
|
555
|
+
@idrac_client.set_boot_order_hd_first
|
556
|
+
end
|
557
|
+
|
558
|
+
def ensure_sensible_bios!(options = {})
|
559
|
+
# Check current state
|
560
|
+
if bios_error_prompt_disabled? &&
|
561
|
+
bios_hdd_placeholder_enabled? &&
|
562
|
+
bios_os_power_control_enabled?
|
563
|
+
puts "BIOS settings already configured correctly".green
|
564
|
+
return { changes_made: false }
|
565
|
+
end
|
566
|
+
|
567
|
+
puts "Configuring BIOS settings...".yellow
|
568
|
+
|
569
|
+
# Build the System Configuration Profile (SCP)
|
570
|
+
scp = {}
|
571
|
+
|
572
|
+
# Disable error prompt (don't halt on errors)
|
573
|
+
if !bios_error_prompt_disabled?
|
574
|
+
scp = @idrac_client.merge_scp(scp, {
|
575
|
+
"BIOS.Setup.1-1" => {
|
576
|
+
"ErrPrompt" => "Disabled"
|
577
|
+
}
|
578
|
+
})
|
579
|
+
end
|
580
|
+
|
581
|
+
# Enable HDD placeholder for boot order control
|
582
|
+
if !bios_hdd_placeholder_enabled?
|
583
|
+
scp = @idrac_client.merge_scp(scp, {
|
584
|
+
"BIOS.Setup.1-1" => {
|
585
|
+
"HddPlaceholder" => "Enabled"
|
586
|
+
}
|
587
|
+
})
|
588
|
+
end
|
589
|
+
|
590
|
+
# Enable OS power control
|
591
|
+
if !bios_os_power_control_enabled?
|
592
|
+
scp = @idrac_client.merge_scp(scp, {
|
593
|
+
"BIOS.Setup.1-1" => {
|
594
|
+
"ProcCStates" => "Enabled",
|
595
|
+
"SysProfile" => "PerfPerWattOptimizedOs",
|
596
|
+
"ProcPwrPerf" => "OsDbpm"
|
597
|
+
}
|
598
|
+
})
|
599
|
+
end
|
600
|
+
|
601
|
+
# Set UEFI boot mode
|
602
|
+
scp = @idrac_client.merge_scp(scp, {
|
603
|
+
"BIOS.Setup.1-1" => {
|
604
|
+
"BootMode" => "Uefi"
|
605
|
+
}
|
606
|
+
})
|
607
|
+
|
608
|
+
# Disable host header check for better compatibility
|
609
|
+
scp = @idrac_client.merge_scp(scp, {
|
610
|
+
"iDRAC.Embedded.1" => {
|
611
|
+
"WebServer.1#HostHeaderCheck" => "Disabled"
|
612
|
+
}
|
613
|
+
})
|
614
|
+
|
615
|
+
# Apply the configuration
|
616
|
+
@idrac_client.set_system_configuration_profile(scp)
|
617
|
+
|
618
|
+
{ changes_made: true }
|
619
|
+
end
|
620
|
+
|
257
621
|
# Utility
|
258
622
|
|
259
623
|
def sel_log
|
@@ -296,18 +660,50 @@ module Radfish
|
|
296
660
|
@idrac_client.get_firmware_version
|
297
661
|
end
|
298
662
|
|
299
|
-
|
663
|
+
def bmc_info
|
664
|
+
# Map iDRAC gem data to radfish format
|
665
|
+
info = {}
|
666
|
+
|
667
|
+
# Get firmware version from idrac gem
|
668
|
+
info[:firmware_version] = @idrac_client.get_firmware_version
|
669
|
+
|
670
|
+
# Get iDRAC generation (7/8/9) from idrac gem's license_version method
|
671
|
+
info[:license_version] = @idrac_client.license_version&.to_s
|
672
|
+
|
673
|
+
# Get Redfish version from idrac gem
|
674
|
+
info[:redfish_version] = @idrac_client.redfish_version
|
675
|
+
|
676
|
+
# Get network info for MAC and IP
|
677
|
+
network = @idrac_client.get_bmc_network
|
678
|
+
if network.is_a?(Hash)
|
679
|
+
info[:mac_address] = network["mac"]
|
680
|
+
info[:ip_address] = network["ipv4"]
|
681
|
+
info[:hostname] = network["hostname"] || network["fqdn"]
|
682
|
+
end
|
683
|
+
|
684
|
+
# Get health status from system info
|
685
|
+
system = @idrac_client.system_info
|
686
|
+
if system.is_a?(Hash)
|
687
|
+
info[:health] = system.dig("Status", "Health") || system.dig("Status", "HealthRollup")
|
688
|
+
end
|
689
|
+
|
690
|
+
info
|
691
|
+
end
|
300
692
|
|
301
|
-
def
|
302
|
-
|
693
|
+
def system_health
|
694
|
+
# Convert hash to OpenStruct for dot notation access
|
695
|
+
health_data = @idrac_client.system_health
|
696
|
+
OpenStruct.new(health_data)
|
303
697
|
end
|
304
698
|
|
305
|
-
|
306
|
-
|
699
|
+
# Additional iDRAC-specific methods
|
700
|
+
|
701
|
+
def screenshot
|
702
|
+
@idrac_client.screenshot
|
307
703
|
end
|
308
704
|
|
309
705
|
def license_info
|
310
|
-
@idrac_client.license_info
|
706
|
+
@idrac_client.license_info
|
311
707
|
end
|
312
708
|
|
313
709
|
# Network management
|
@@ -316,12 +712,12 @@ module Radfish
|
|
316
712
|
@idrac_client.get_bmc_network
|
317
713
|
end
|
318
714
|
|
319
|
-
def set_bmc_network(
|
715
|
+
def set_bmc_network(ipv4: nil, mask: nil, gateway: nil,
|
320
716
|
dns_primary: nil, dns_secondary: nil, hostname: nil,
|
321
717
|
dhcp: false)
|
322
718
|
@idrac_client.set_bmc_network(
|
323
|
-
|
324
|
-
|
719
|
+
ipv4: ipv4,
|
720
|
+
mask: mask,
|
325
721
|
gateway: gateway,
|
326
722
|
dns_primary: dns_primary,
|
327
723
|
dns_secondary: dns_secondary,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: radfish-idrac
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Siegel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: radfish
|
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
87
|
requirements: []
|
88
|
-
rubygems_version: 3.
|
88
|
+
rubygems_version: 3.5.22
|
89
89
|
signing_key:
|
90
90
|
specification_version: 4
|
91
91
|
summary: Dell iDRAC adapter for Radfish
|