idrac 0.4.5 → 0.5.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 +4 -4
- data/README.md +26 -0
- data/bin/idrac +117 -0
- data/lib/idrac/client.rb +1 -0
- data/lib/idrac/license.rb +63 -0
- data/lib/idrac/storage.rb +2 -1
- data/lib/idrac/system.rb +104 -0
- data/lib/idrac/version.rb +1 -1
- data/lib/idrac.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32086f37bcf1f9d8bfaf3bf5a54e4159cc2db5ed3b97bc5021203f266e62e7aa
|
4
|
+
data.tar.gz: c107965b24d8edc018f44c42da5f6ddd978d978a4ed83eea51304e7b80dc5f40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45d74e3ba6b18f6a86e6f644932a20b4316814814a4c37961b54092f6bfe018bfbadc3d9cade70c160dd43c7adb80d7e86e30468e88152a32631b0883b94e09d
|
7
|
+
data.tar.gz: b84528baa1d901c687107ea00dc08a1668ad5f60d258cbfb0f9fc69bcbe5efa6530d5c9c2614270f7c3044dd2cd99665168b7f6eadab53d2c4d7b17b1a88fb33
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ A Ruby client for the Dell iDRAC API. This gem provides a command-line interface
|
|
15
15
|
- Job queue management (clear, monitor, list)
|
16
16
|
- Lifecycle log and System Event Log (SEL) management
|
17
17
|
- Lifecycle Controller status management
|
18
|
+
- Return values as RecursiveOpenStruct objects for convenient attribute access
|
18
19
|
|
19
20
|
## Installation
|
20
21
|
|
@@ -170,6 +171,25 @@ client.clear_lifecycle!
|
|
170
171
|
# Clear System Event Logs
|
171
172
|
client.clear_system_event_logs!
|
172
173
|
|
174
|
+
# Working with RecursiveOpenStruct objects
|
175
|
+
# Many methods return data as RecursiveOpenStruct objects for easier property access
|
176
|
+
|
177
|
+
# Get memory information
|
178
|
+
memory_modules = client.memory
|
179
|
+
memory_modules.each do |dimm|
|
180
|
+
# Access properties directly as methods
|
181
|
+
puts "#{dimm.name}: #{dimm.capacity_bytes / (1024**3)}GB, Speed: #{dimm.speed_mhz}MHz"
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get storage information
|
185
|
+
controller = client.controller
|
186
|
+
volumes = client.volumes(controller)
|
187
|
+
volumes.each do |volume|
|
188
|
+
# Access properties via dot notation
|
189
|
+
puts "#{volume.name} (#{volume.raid_level}): #{volume.capacity_bytes / (1024**3)}GB"
|
190
|
+
puts " Health: #{volume.health}, FastPath: #{volume.fastpath}"
|
191
|
+
end
|
192
|
+
|
173
193
|
# Create a client with auto_delete_sessions disabled
|
174
194
|
client = IDRAC.new(
|
175
195
|
host: '192.168.1.100',
|
@@ -187,6 +207,12 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
187
207
|
|
188
208
|
## Changelog
|
189
209
|
|
210
|
+
### Version 0.1.40
|
211
|
+
- **Enhanced Return Values**: Methods that return system components now provide RecursiveOpenStruct objects
|
212
|
+
- Memory, drives, volumes, PSUs, and fans now support convenient dot notation for attribute access
|
213
|
+
- Improved object structure with consistent property naming across different component types
|
214
|
+
- Better code organization and readability when working with returned objects
|
215
|
+
|
190
216
|
### Version 0.1.39
|
191
217
|
- **Added Job Management**: New methods for managing iDRAC jobs
|
192
218
|
- List jobs using `jobs` and `jobs_detail`
|
data/bin/idrac
CHANGED
@@ -456,6 +456,37 @@ module IDRAC
|
|
456
456
|
end
|
457
457
|
end
|
458
458
|
|
459
|
+
desc "license_info", "Display license information"
|
460
|
+
map "license:info" => :license_info
|
461
|
+
def license_info
|
462
|
+
with_idrac_client do |client|
|
463
|
+
license = client.license_info
|
464
|
+
if license
|
465
|
+
puts "\nLicense Information:".green.bold
|
466
|
+
puts "Description: #{license['Description']}".cyan
|
467
|
+
puts "License Type: #{license['LicenseType']}".cyan
|
468
|
+
puts "License Version: #{client.license_version || 'Unknown'}".cyan
|
469
|
+
puts "Removable: #{license['Removable']}".cyan
|
470
|
+
puts "Status: #{license.dig('Status', 'Health') || 'Unknown'}".cyan
|
471
|
+
else
|
472
|
+
puts "No license information available".yellow
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
desc "license_version", "Display the iDRAC license version number"
|
478
|
+
map "license:version" => :license_version
|
479
|
+
def license_version
|
480
|
+
with_idrac_client do |client|
|
481
|
+
version = client.license_version
|
482
|
+
if version
|
483
|
+
puts version
|
484
|
+
else
|
485
|
+
puts "Unknown license version"
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
459
490
|
desc "test:all", "Run tests for all major functionality areas"
|
460
491
|
map "test" => :test_all
|
461
492
|
option :quiet, type: :boolean, default: false, desc: "Minimize output, just show pass/fail"
|
@@ -472,6 +503,8 @@ module IDRAC
|
|
472
503
|
# Basic information
|
473
504
|
{ name: "System Summary", method: -> (c) { c.summary } },
|
474
505
|
{ name: "Redfish Version", method: -> (c) { c.redfish_version } },
|
506
|
+
{ name: "License Version", method: -> (c) { c.license_version } },
|
507
|
+
{ name: "System Health", method: -> (c) { c.system_health } },
|
475
508
|
|
476
509
|
# Power methods
|
477
510
|
{ name: "Power State", method: -> (c) { c.get_power_state } },
|
@@ -488,6 +521,7 @@ module IDRAC
|
|
488
521
|
|
489
522
|
# System components
|
490
523
|
{ name: "Memory Info", method: -> (c) { c.memory } },
|
524
|
+
{ name: "CPU Info", method: -> (c) { c.cpus } },
|
491
525
|
{ name: "PSU Info", method: -> (c) { c.psus } },
|
492
526
|
{ name: "Fan Info", method: -> (c) { c.fans } },
|
493
527
|
{ name: "NIC Info", method: -> (c) { c.nics } },
|
@@ -863,6 +897,27 @@ module IDRAC
|
|
863
897
|
end
|
864
898
|
end
|
865
899
|
|
900
|
+
desc "system_cpus", "Get processor/CPU information"
|
901
|
+
map "system:cpus" => :system_cpus
|
902
|
+
def system_cpus
|
903
|
+
with_idrac_client do |client|
|
904
|
+
cpus = client.cpus
|
905
|
+
|
906
|
+
puts "\nProcessor Summary:".green.bold
|
907
|
+
puts "=" * 50
|
908
|
+
|
909
|
+
health_color = cpus[:status] == "OK" ? :green : :red
|
910
|
+
|
911
|
+
puts "Processor Model:".ljust(25) + cpus[:model].to_s.light_cyan
|
912
|
+
puts "Processor Count:".ljust(25) + cpus[:count].to_s.light_cyan
|
913
|
+
puts "Physical Cores:".ljust(25) + cpus[:cores].to_s.light_cyan
|
914
|
+
puts "Logical Cores:".ljust(25) + cpus[:threads].to_s.light_cyan
|
915
|
+
puts "Status:".ljust(25) + cpus[:status].to_s.send(health_color)
|
916
|
+
|
917
|
+
puts "=" * 50
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
866
921
|
desc "system_psus", "Get power supply information"
|
867
922
|
map "system:psus" => :system_psus
|
868
923
|
def system_psus
|
@@ -1103,6 +1158,68 @@ module IDRAC
|
|
1103
1158
|
end
|
1104
1159
|
end
|
1105
1160
|
|
1161
|
+
desc "system_info", "Get detailed system identification information"
|
1162
|
+
map "system:info" => :system_info
|
1163
|
+
def system_info
|
1164
|
+
with_idrac_client do |client|
|
1165
|
+
info = client.system_info
|
1166
|
+
|
1167
|
+
if info[:is_dell]
|
1168
|
+
puts "Dell iDRAC System:".green.bold
|
1169
|
+
puts " Service Tag: #{info[:service_tag]}".cyan
|
1170
|
+
puts " Model: #{info[:model]}".cyan
|
1171
|
+
puts " iDRAC Version: #{info[:idrac_version]}".cyan
|
1172
|
+
puts " Firmware Version: #{info[:firmware_version]}".cyan
|
1173
|
+
else
|
1174
|
+
puts "Not a Dell iDRAC system".yellow
|
1175
|
+
puts " Product: #{info[:product]}".cyan
|
1176
|
+
if info[:is_ancient_dell]
|
1177
|
+
puts " Ancient Dell System detected. Update firmware.".yellow
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
desc "system_config", "Get complete system configuration"
|
1184
|
+
map "system:config" => :system_config
|
1185
|
+
def system_config
|
1186
|
+
with_idrac_client do |client|
|
1187
|
+
response = client.authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1?$expand=*($levels=1)")
|
1188
|
+
if response.status == 200
|
1189
|
+
config = JSON.parse(response.body)
|
1190
|
+
puts JSON.pretty_generate(config)
|
1191
|
+
else
|
1192
|
+
puts "Failed to retrieve system configuration: #{response.status}".red
|
1193
|
+
end
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
desc "system_health", "Get system health status"
|
1198
|
+
map "system:health" => :system_health
|
1199
|
+
def system_health
|
1200
|
+
with_idrac_client do |client|
|
1201
|
+
health = client.system_health
|
1202
|
+
|
1203
|
+
puts "\nSystem Health Status:".green.bold
|
1204
|
+
puts "=" * 50
|
1205
|
+
|
1206
|
+
# Display overall health with color coding
|
1207
|
+
overall_color = health[:overall] == "OK" ? :green : :red
|
1208
|
+
system_color = health[:system] == "OK" ? :green : :red
|
1209
|
+
processor_color = health[:processor] == "OK" ? :green : :red
|
1210
|
+
memory_color = health[:memory] == "OK" ? :green : :red
|
1211
|
+
storage_color = health[:storage] == "OK" ? :green : (health[:storage].nil? ? :yellow : :red)
|
1212
|
+
|
1213
|
+
puts "Overall Health:".ljust(25) + health[:overall].to_s.send(overall_color)
|
1214
|
+
puts "System Health:".ljust(25) + health[:system].to_s.send(system_color)
|
1215
|
+
puts "Processor Health:".ljust(25) + health[:processor].to_s.send(processor_color)
|
1216
|
+
puts "Memory Health:".ljust(25) + health[:memory].to_s.send(memory_color)
|
1217
|
+
puts "Storage Health:".ljust(25) + (health[:storage] || "Unknown").to_s.send(storage_color)
|
1218
|
+
|
1219
|
+
puts "=" * 50
|
1220
|
+
end
|
1221
|
+
end
|
1222
|
+
|
1106
1223
|
# Test commands
|
1107
1224
|
desc "test_live", "Test all major functionality of the gem on a real system"
|
1108
1225
|
map "test:live" => :test_live
|
data/lib/idrac/client.rb
CHANGED
@@ -21,6 +21,7 @@ module IDRAC
|
|
21
21
|
include System
|
22
22
|
include VirtualMedia
|
23
23
|
include Boot
|
24
|
+
include License
|
24
25
|
|
25
26
|
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)
|
26
27
|
@host = host
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module IDRAC
|
2
|
+
module License
|
3
|
+
# Gets the license information from the iDRAC
|
4
|
+
# @return [Hash] License details
|
5
|
+
def license_info
|
6
|
+
response = authenticated_request(:get, "/redfish/v1/LicenseService/Licenses")
|
7
|
+
if response.status != 200
|
8
|
+
debug "Failed to retrieve licenses list: #{response.status}", 1, :red
|
9
|
+
return nil
|
10
|
+
end
|
11
|
+
|
12
|
+
license_data = JSON.parse(response.body)
|
13
|
+
debug "License collection: #{license_data}", 2
|
14
|
+
|
15
|
+
# Check if there are any license entries
|
16
|
+
if !license_data["Members"] || license_data["Members"].empty?
|
17
|
+
debug "No licenses found", 1, :yellow
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the first license in the list
|
22
|
+
license_uri = license_data["Members"][0]["@odata.id"]
|
23
|
+
debug "Using license URI: #{license_uri}", 2
|
24
|
+
|
25
|
+
# Get detailed license information
|
26
|
+
license_response = authenticated_request(:get, license_uri)
|
27
|
+
if license_response.status != 200
|
28
|
+
debug "Failed to retrieve license details: #{license_response.status}", 1, :red
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
license_details = JSON.parse(license_response.body)
|
33
|
+
debug "License details: #{license_details}", 2
|
34
|
+
|
35
|
+
return license_details
|
36
|
+
end
|
37
|
+
|
38
|
+
# Extracts the iDRAC version from the license description
|
39
|
+
# @return [Integer, nil] The license version (e.g. 9) or nil if not found
|
40
|
+
def license_version
|
41
|
+
license = license_info
|
42
|
+
return nil unless license
|
43
|
+
|
44
|
+
# Check the Description field, which often contains the version
|
45
|
+
# Example: "iDRAC9 Enterprise License"
|
46
|
+
if license["Description"] && license["Description"].match(/iDRAC(\d+)/i)
|
47
|
+
version = license["Description"].match(/iDRAC(\d+)/i)[1].to_i
|
48
|
+
debug "Found license version from Description: #{version}", 1
|
49
|
+
return version
|
50
|
+
end
|
51
|
+
|
52
|
+
# Try alternative fields if Description didn't work
|
53
|
+
if license["Name"] && license["Name"].match(/iDRAC(\d+)/i)
|
54
|
+
version = license["Name"].match(/iDRAC(\d+)/i)[1].to_i
|
55
|
+
debug "Found license version from Name: #{version}", 1
|
56
|
+
return version
|
57
|
+
end
|
58
|
+
|
59
|
+
debug "Could not determine license version from license info", 1, :yellow
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/idrac/storage.rb
CHANGED
@@ -50,7 +50,8 @@ module IDRAC
|
|
50
50
|
encryption_capability: controller.dig("Oem", "Dell", "DellController", "EncryptionCapability"),
|
51
51
|
controller_type: controller.dig("Oem", "Dell", "DellController", "ControllerType"),
|
52
52
|
pci_slot: controller.dig("Oem", "Dell", "DellController", "PCISlot"),
|
53
|
-
raw: controller
|
53
|
+
raw: controller,
|
54
|
+
odata_id: controller["@odata.id"]
|
54
55
|
}
|
55
56
|
|
56
57
|
RecursiveOpenStruct.new(controller_data, recurse_over_arrays: true)
|
data/lib/idrac/system.rb
CHANGED
@@ -332,6 +332,110 @@ module IDRAC
|
|
332
332
|
return nics_with_pci
|
333
333
|
end
|
334
334
|
|
335
|
+
# Get system identification information
|
336
|
+
def system_info
|
337
|
+
response = authenticated_request(:get, "/redfish/v1")
|
338
|
+
|
339
|
+
if response.status == 200
|
340
|
+
begin
|
341
|
+
data = JSON.parse(response.body)
|
342
|
+
|
343
|
+
# Initialize return hash with defaults
|
344
|
+
info = {
|
345
|
+
is_dell: false,
|
346
|
+
is_ancient_dell: false,
|
347
|
+
product: data["Product"] || "Unknown",
|
348
|
+
service_tag: nil,
|
349
|
+
model: nil,
|
350
|
+
idrac_version: data["RedfishVersion"],
|
351
|
+
firmware_version: nil
|
352
|
+
}
|
353
|
+
|
354
|
+
# Check if it's a Dell iDRAC
|
355
|
+
if data["Product"] == "Integrated Dell Remote Access Controller"
|
356
|
+
info[:is_dell] = true
|
357
|
+
|
358
|
+
# Get service tag from Dell OEM data
|
359
|
+
info[:service_tag] = data.dig("Oem", "Dell", "ServiceTag")
|
360
|
+
|
361
|
+
# Get firmware version - try both common locations
|
362
|
+
info[:firmware_version] = data["FirmwareVersion"] || data.dig("Oem", "Dell", "FirmwareVersion")
|
363
|
+
|
364
|
+
# Get additional system information
|
365
|
+
system_response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1")
|
366
|
+
if system_response.status == 200
|
367
|
+
system_data = JSON.parse(system_response.body)
|
368
|
+
info[:model] = system_data["Model"]
|
369
|
+
end
|
370
|
+
|
371
|
+
return info
|
372
|
+
else
|
373
|
+
# Try to handle ancient Dell models where Product is null or non-standard
|
374
|
+
if data["Product"].nil? || data.dig("Oem", "Dell")
|
375
|
+
info[:is_ancient_dell] = true
|
376
|
+
return info
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
return info
|
381
|
+
rescue JSON::ParserError
|
382
|
+
raise Error, "Failed to parse system information: #{response.body}"
|
383
|
+
end
|
384
|
+
else
|
385
|
+
raise Error, "Failed to get system information. Status code: #{response.status}"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
# Get processor/CPU information
|
390
|
+
def cpus
|
391
|
+
response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1?$expand=*($levels=1)")
|
392
|
+
|
393
|
+
if response.status == 200
|
394
|
+
begin
|
395
|
+
data = JSON.parse(response.body)
|
396
|
+
|
397
|
+
summary = {
|
398
|
+
count: data.dig("ProcessorSummary", "Count"),
|
399
|
+
model: data.dig("ProcessorSummary", "Model"),
|
400
|
+
cores: data.dig("ProcessorSummary", "CoreCount"),
|
401
|
+
threads: data.dig("ProcessorSummary", "LogicalProcessorCount"),
|
402
|
+
status: data.dig("ProcessorSummary", "Status", "Health")
|
403
|
+
}
|
404
|
+
|
405
|
+
return summary
|
406
|
+
rescue JSON::ParserError
|
407
|
+
raise Error, "Failed to parse processor information: #{response.body}"
|
408
|
+
end
|
409
|
+
else
|
410
|
+
raise Error, "Failed to get processor information. Status code: #{response.status}"
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# Get system health status
|
415
|
+
def system_health
|
416
|
+
response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1?$expand=*($levels=1)")
|
417
|
+
|
418
|
+
if response.status == 200
|
419
|
+
begin
|
420
|
+
data = JSON.parse(response.body)
|
421
|
+
|
422
|
+
health = {
|
423
|
+
overall: data.dig("Status", "HealthRollup"),
|
424
|
+
system: data.dig("Status", "Health"),
|
425
|
+
processor: data.dig("ProcessorSummary", "Status", "Health"),
|
426
|
+
memory: data.dig("MemorySummary", "Status", "Health"),
|
427
|
+
storage: data.dig("Storage", "Status", "Health")
|
428
|
+
}
|
429
|
+
|
430
|
+
return health
|
431
|
+
rescue JSON::ParserError
|
432
|
+
raise Error, "Failed to parse system health information: #{response.body}"
|
433
|
+
end
|
434
|
+
else
|
435
|
+
raise Error, "Failed to get system health. Status code: #{response.status}"
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
335
439
|
# Get system event logs
|
336
440
|
def system_event_logs
|
337
441
|
response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1/Logs/Sel?$expand=*($levels=1)")
|
data/lib/idrac/version.rb
CHANGED
data/lib/idrac.rb
CHANGED
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.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Siegel
|
@@ -241,6 +241,7 @@ files:
|
|
241
241
|
- lib/idrac/firmware.rb
|
242
242
|
- lib/idrac/firmware_catalog.rb
|
243
243
|
- lib/idrac/jobs.rb
|
244
|
+
- lib/idrac/license.rb
|
244
245
|
- lib/idrac/lifecycle.rb
|
245
246
|
- lib/idrac/power.rb
|
246
247
|
- lib/idrac/session.rb
|