idrac 0.5.6 → 0.5.7

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: 7c4df0e2ba5dc5fb8bed2bfd514d2ee6ce8587cad0bf8f138021bff201c14887
4
- data.tar.gz: b1cad50c169305b1369345c5bf1ee0d18d4b4c6c1f3e46c97b413e3009b295d0
3
+ metadata.gz: bffa45c5c7e0b67861ef0218cc20c2ff5884ed4b4ebb63a21c58ce1001c0acd5
4
+ data.tar.gz: 2403bede70f81efe014454654f5babe73bc2c7706902b96d1d2fdea5b763a4ff
5
5
  SHA512:
6
- metadata.gz: c1dd008ed19fb33410d9ccc564bba643b2000f2a5de701568ff2ddb2cd34605a80736745745d56286e8940d37a7d06a348b9cb33227529430d7a26757a2f05a7
7
- data.tar.gz: b1037ced078ac07b9629c76d00694d887b5979686fc942d105904d0c96279bc9d2d33c0cc2e863e25f5d6df1fdaa277cffb8159b18019e7303692dc431a09461
6
+ metadata.gz: 4ecf2f515abc4e780a4f4f302ce0dd408f95ff6ee4a73bd91df609d7fdc01aebd65ea060400225adb676f8731d4f401ee0cf9db75a106f99a70cff0ab64e4675
7
+ data.tar.gz: 3fd76fda921f9e1c9a0483c5302a6e64f4f3bc1231c2ad2a2849d3a16290a4270378511c96b1ffce7b545957455008a8b99fa7f259444eec82bcfb323c556632
data/bin/idrac CHANGED
@@ -581,17 +581,17 @@ module IDRAC
581
581
  puts "-" * 80
582
582
 
583
583
  controllers.each do |controller|
584
- puts "Controller: #{controller.name}".cyan.bold
585
- puts " Model: #{controller.model}"
586
- puts " Status: #{controller.status}"
587
- puts " Drives: #{controller.drives_count}"
588
- puts " Firmware: #{controller.firmware_version}"
589
- puts " Type: #{controller.controller_type}"
590
- puts " PCI Slot: #{controller.pci_slot}"
584
+ puts "Controller: #{controller[:name]}".cyan.bold
585
+ puts " Model: #{controller[:model]}"
586
+ puts " Status: #{controller[:status]}"
587
+ puts " Drives: #{controller[:drives_count]}"
588
+ puts " Firmware: #{controller[:firmware_version]}"
589
+ puts " Type: #{controller[:controller_type]}"
590
+ puts " PCI Slot: #{controller[:pci_slot]}"
591
591
 
592
- if controller.encryption_capability
593
- puts " Encryption: #{controller.encryption_capability}"
594
- puts " Encryption Mode: #{controller.encryption_mode || 'Disabled'}"
592
+ if controller[:encryption_capability]
593
+ puts " Encryption: #{controller[:encryption_capability]}"
594
+ puts " Encryption Mode: #{controller[:encryption_mode] || 'Disabled'}"
595
595
  end
596
596
 
597
597
  puts
@@ -675,7 +675,7 @@ module IDRAC
675
675
  confirmation = $stdin.gets.chomp.downcase
676
676
 
677
677
  if confirmation == 'y'
678
- client.create_virtual_disk(controller.odata_id, drives, name: options[:name], raid_type: options[:raid])
678
+ client.create_virtual_disk(controller.odata_Id, drives, name: options[:name], raid_type: options[:raid])
679
679
  puts "Volume created successfully".green
680
680
  else
681
681
  puts "Operation cancelled".yellow
data/lib/idrac/storage.rb CHANGED
@@ -82,8 +82,7 @@ module IDRAC
82
82
  def drives(controller)
83
83
  raise Error, "Controller not provided" unless controller
84
84
 
85
- odata_id_path = controller["@odata.id"] || controller["odata_id"]
86
- controller_path = odata_id_path.split("v1/").last
85
+ controller_path = controller["@odata.id"].split("v1/").last
87
86
  response = authenticated_request(:get, "/redfish/v1/#{controller_path}?$expand=*($levels=1)")
88
87
 
89
88
  if response.status == 200
@@ -108,7 +107,7 @@ module IDRAC
108
107
  operation_name: body.dig("Oem", "Dell", "DellPhysicalDisk", "OperationName"),
109
108
  operation_progress: body.dig("Oem", "Dell", "DellPhysicalDisk", "OperationPercentCompletePercent"),
110
109
  encryption_ability: body["EncryptionAbility"],
111
- odata_id: body["@odata.id"]
110
+ "@odata.id": body["@odata.id"]
112
111
  }
113
112
 
114
113
  RecursiveOpenStruct.new(drive_data, recurse_over_arrays: true)
@@ -129,8 +128,8 @@ module IDRAC
129
128
 
130
129
  puts "Volumes (e.g. Arrays)".green
131
130
 
132
- odata_id_path = controller.dig("Volumes", "odata_id") || controller.volumes.odata_id
133
- path = odata_id_path.split("v1/").last
131
+ v = controller["Volumes"]
132
+ path = v["@odata.id"].split("v1/").last
134
133
  response = authenticated_request(:get, "/redfish/v1/#{path}?$expand=*($levels=1)")
135
134
 
136
135
  if response.status == 200
@@ -404,278 +403,4 @@ module IDRAC
404
403
  end
405
404
  end
406
405
  end
407
- end
408
- =begin
409
- def controller_encryption_capable?
410
- self.meta.dig("controller", "Oem", "Dell", "DellController", "EncryptionCapability") =~ /localkey/i # "LocalKeyManagementAndSecureEnterpriseKeyManagerCapable"
411
- end
412
- def controller_encryption_enabled?
413
- self.meta.dig("controller", "Oem", "Dell", "DellController", "EncryptionMode") =~ /localkey/i
414
- end
415
- def drives
416
- # Get the drives
417
- controller_path = self.controller["@odata.id"].split("v1/").last
418
- json = get(path: "#{controller_path}?$expand=*($levels=1)")["body"]["Drives"]
419
- # drives = self.controller["Drives"].collect
420
- idrac_drives = json.map do |body|
421
- # path = d["@odata.id"].split("v1/").last
422
- # body = self.get(path: path)["body"]
423
- serial = body["SerialNumber"]
424
- serial = body["Identifiers"].first["DurableName"] if serial.blank?
425
- {
426
- serial: serial,
427
- model: body["Model"],
428
- name: body["Name"],
429
- capacity_bytes: body["CapacityBytes"],
430
- # Health is nil when powered off...
431
- health: body["Status"]["Health"] ? body["Status"]["Health"] : "N/A",
432
- speed_gbp: body["CapableSpeedGbs"],
433
- manufacturer: body["Manufacturer"],
434
- media_type: body["MediaType"],
435
- failure_predicted: body["FailurePredicted"],
436
- life_left_percent: body["PredictedMediaLifeLeftPercent"],
437
- certified: body.dig("Oem", "Dell", "DellPhysicalDisk", "Certified"),
438
- raid_status: body.dig("Oem", "Dell", "DellPhysicalDisk", "RaidStatus"),
439
- operation_name: body.dig("Oem", "Dell", "DellPhysicalDisk", "OperationName"),
440
- operation_progress: body.dig("Oem", "Dell", "DellPhysicalDisk", "OperationPercentCompletePercent"),
441
- encryption_ability: body["EncryptionAbility"],
442
- "@odata.id": body["@odata.id"]
443
- }
444
- end
445
- self.meta["drives"] = idrac_drives.sort_by { |d| d[:name] }
446
- if self.save
447
- self.meta["drives"]
448
- else
449
- false
450
- end
451
- end
452
- def volumes
453
- puts "Volumes (e.g. Arrays)".green
454
- # {"@odata.id"=>"/redfish/v1/Systems/System.Embedded.1/Storage/RAID.Integrated.1-1/Volumes"}
455
-
456
- v = self.controller["Volumes"]
457
- path = v["@odata.id"].split("v1/").last
458
- vols = self.get(path: path+"?$expand=*($levels=1)")["body"]
459
- volumes = vols["Members"].collect do |vol|
460
- drives = vol["Links"]["Drives"]
461
- volume = {
462
- name: vol["Name"],
463
- capacity_bytes: vol["CapacityBytes"],
464
- volume_type: vol["VolumeType"],
465
- drives: drives,
466
- write_cache_policy: vol.dig("Oem", "Dell", "DellVirtualDisk", "WriteCachePolicy"),
467
- read_cache_policy: vol.dig("Oem", "Dell", "DellVirtualDisk", "ReadCachePolicy"),
468
- stripe_size: vol.dig("Oem", "Dell", "DellVirtualDisk", "StripeSize"),
469
- raid_level: vol["RAIDType"],
470
- encrypted: vol["Encrypted"],
471
- lock_status: vol.dig("Oem", "Dell", "DellVirtualDisk", "LockStatus"),
472
- # "Operations"=>[{"OperationName"=>"Background Initialization", "PercentageComplete"=>0}],
473
- "@odata.id": vol["@odata.id"]
474
- }
475
- if !self.modern_firmware?
476
- # Unfortunately for older idracs, to get the drive cache policies we need to do a
477
- # system_configuration_profile call AND we still don't get the right stripe size.
478
- scp ||= self.get_system_configuration_profile(target: "RAID")
479
- controller = self.meta["controller"]
480
- scp_vol = scp["SystemConfiguration"]["Components"]
481
- .find { |comp| comp["FQDD"] == controller['Id'] }["Components"]
482
- .find { |comp| comp["FQDD"] == vol["Id"] }["Attributes"]
483
- # .find { |attr| attr["Name"] == "RAIDdefaultWritePolicy" }["Value"]
484
- volume[:write_cache_policy] = scp_vol.find { |attr| attr["Name"] == "RAIDdefaultWritePolicy" }["Value"]
485
- volume[:read_cache_policy] = scp_vol.find { |attr| attr["Name"] == "RAIDdefaultReadPolicy" }["Value"]
486
- end
487
-
488
-
489
- # Dell-specific high-performance settings for PERC:
490
- # [Read more](https://www.dell.com/support/manuals/en-us/perc-h755/perc11_ug/fastpath?guid=guid-a9e90946-a41f-48ab-88f1-9ce514b4c414&lang=en-us)
491
- volume[:fastpath] = self.fastpath_good?(volume)
492
-
493
- # Not built yet:
494
- # "Status"=>{"Health"=>nil, "HealthRollup"=>nil, "State"=>"Enabled"},
495
- # Dunno
496
- # "Status"=>{"Health"=>"OK", "HealthRollup"=>"OK", "State"=>"Enabled"},
497
- # In progress:
498
- # "Operations"=>[{"OperationName"=>"Background Initialization", "PercentageComplete"=>0}],
499
- # "Status"=>{"Health"=>nil, "HealthRollup"=>nil, "State"=>"Enabled"},
500
- if vol["Operations"].any?
501
- volume[:health] = vol["Status"]["Health"] ? vol["Status"]["Health"] : "N/A"
502
- volume[:progress] = vol["Operations"].first["PercentageComplete"]
503
- volume[:message] = vol["Operations"].first["OperationName"]
504
- elsif vol["Status"]["Health"] == "OK"
505
- volume[:health] = "OK"
506
- volume[:progress] = nil
507
- volume[:message] = nil
508
- else
509
- volume[:health] = "?"
510
- volume[:progress] = nil
511
- volume[:message] = nil
512
- end
513
- volume
514
- end
515
- self.meta["volumes"] = volumes.sort_by { |d| d[:name] }
516
- self.save
517
- end
518
- def memory
519
- expected = expected_memory
520
- mem = self.get(path: "Systems/System.Embedded.1/Memory?$expand=*($levels=1)")["body"]
521
- memory = mem["Members"].map do |m|
522
- dimm_name = m["Name"] # e.g. DIMM A1
523
- bank, index = /DIMM ([A-Z])(\d+)/.match(dimm_name).captures
524
- # We expect one of our configurations:
525
- # 32GB DIMMS x 32 = 1TB # Gen III, less memory issues (we've experienced too many bad 64GB DIMMS)
526
- # 64GB DIMMS x 24 = 1.5TB # Gen II
527
- # 64GB DIMMS x 32 = 2TB # Gen I
528
- expected.delete(dimm_name) if expected[dimm_name] == m["CapacityMiB"] * 1.megabyte || expected[dimm_name] == m["CapacityMiB"] * 1.megabyte * 2
529
- puts "DIMM: #{m["Model"]} #{m["Name"]} > #{m["CapacityMiB"]}MiB > #{m["Status"]["Health"]} > #{m["OperatingSpeedMhz"]}MHz > #{m["PartNumber"]} / #{m["SerialNumber"]}"
530
- {
531
- "model" => m["Model"],
532
- "name" => m["Name"],
533
- "capacity_bytes" => m["CapacityMiB"].to_i * 1.megabyte,
534
- "health" => m["Status"]["Health"] ? m["Status"]["Health"] : "N/A",
535
- "speed_mhz" => m["OperatingSpeedMhz"],
536
- "part_number" => m["PartNumber"],
537
- "serial" => m["SerialNumber"],
538
- "bank" => bank,
539
- "index" => index.to_i
540
- }
541
- end
542
- self.meta["memory"] = memory.sort_by { |a| [a["bank"], a["index"]] }
543
- if expected.any?
544
- log("Missing DIMMs: #{expected.keys.join(", ")}".red)
545
- puts "Missing DIMMs: #{expected.keys.join(", ")}".red
546
- end
547
- self.save
548
- end
549
- def pci(force: false)
550
- # If we've already found two Mellanox cards, let's not refresh by default
551
- if !force && (2 == self.meta["pci"]&.select { |p| p['manufacturer'] =~ /Mellanox/ }&.size)
552
- puts "[PCI] 2 x Mellanox NICs already found. Skipping.".yellow
553
- return
554
- end
555
- # /redfish/v1/Chassis/System.Embedded.1/PCIeDevices/59-0/PCIeFunctions/59-0-0
556
- # Look at all the PCI slots and ideally identify the Mellanox cards
557
- # Then match them to the
558
- devices = self.get(path: "Chassis/System.Embedded.1/PCIeDevices?$expand=*($levels=1)")["body"]
559
- pci = devices["Members"].map do |stub|
560
- manufacturer = stub["Manufacturer"]
561
- pcie_function_path = stub.dig("Links", "PCIeFunctions", 0, "@odata.id")
562
- device = self.get(path: pcie_function_path)["body"]
563
-
564
- # If it's a network device, we can chcek the link to its PCIe details and then
565
- # NetworkController
566
- puts "PCI Device: #{device["Name"]} > #{manufacturer} > #{device["DeviceClass"]} > #{device["Description"]} > #{device["Id"]}"
567
- { device_class: device["DeviceClass"], # e.g. NetworkController
568
- manufacturer: manufacturer,
569
- name: device["Name"],
570
- description: device["Description"],
571
- id: device["Id"], # This is the BUS: e.g. 59-0-0 => 3b
572
- slot_type: device.dig("Oem", "Dell", "DellPCIeFunction", "SlotType"),
573
- bus_width: device.dig("Oem", "Dell", "DellPCIeFunction", "DataBusWidth"),
574
- nic: device.dig("Links", "EthernetInterfaces", 0, "@odata.id")
575
- }
576
- end
577
- self.meta['pci'] = pci
578
- self.save
579
- end
580
- # Finds Mellanox cards on the bus and their NICs.
581
- # [{:bus_id=>"59", :nic=>"NIC.Slot.1-1-1"}, {:bus_id=>"94", :nic=>"NIC.Slot.2-1-1"}]
582
- def nics_to_pci
583
- self.nics if self.meta['nics'].blank?
584
- self.pci if self.meta['pci'].blank?
585
- hsh = self.meta['pci']&.select { |n| n['device_class'] =~ /NetworkController/ && n['manufacturer'] =~ /Mellanox/ }&.inject({}) do |acc,v|
586
- nic = (v['nic'] =~ /.*\/([^\/\-]+-\d+)/; $1) # e.g. NIC.Slot.1-1 # Drop one -1 for consistency with other iDRAC
587
- pci = (v['id'] =~ /^(\d+)-\d+-\d/; $1) # e.g. 59
588
- acc[nic] = pci
589
- acc
590
- end
591
- self.meta['nics'].each do |nic|
592
- nic['ports'].each do |port|
593
- pci_bus = hsh[port['name']]
594
- if pci_bus
595
- port['pci'] = pci_bus
596
- port['linux_device'] = "enp#{pci_bus}s0np0" # e.g. enp3s0np0
597
- end
598
- end
599
- end
600
- hsh
601
- end
602
- def nics
603
- # There can be multiple NIC adapters, so first we enumerate them:
604
- adapters = self.get(path: "Systems/System.Embedded.1/NetworkAdapters?$expand=*($levels=1)")["body"]
605
- nics = adapters["Members"].map do |adapter|
606
- port_part = self.idrac_license_version.to_i == 9 ? 'Ports' : 'NetworkPorts'
607
- path = "#{adapter["@odata.id"].split("v1/").last}/#{port_part}?$expand=*($levels=1)"
608
- res = self.get(path: path)["body"]
609
- ports = res["Members"].collect do |nic|
610
- link_speed_mbps, mac_addr, link_status = nil, nil, nil
611
- if self.idrac_license_version.to_i == 9
612
- link_speed_mbps = nic['CurrentSpeedGbps'].to_i * 1000
613
- mac_addr = nic['Ethernet']['AssociatedMACAddresses'].first
614
- port_num = nic['PortId']
615
- network_technology = nic['LinkNetworkTechnology']
616
- link_status = nic['LinkStatus'] =~ /up/i ? "Up" : "Down" # Lovely, iDRAC now uses LinkUp instead of Up. :shrug:
617
- else # iDRAC 8
618
- link_speed_mbps = nic["SupportedLinkCapabilities"].first["LinkSpeedMbps"]
619
- mac_addr = nic["AssociatedNetworkAddresses"].first
620
- port_num = nic["PhysicalPortNumber"]
621
- network_technology = nic["SupportedLinkCapabilities"].first["LinkNetworkTechnology"]
622
- link_status = nic['LinkStatus']
623
- end
624
- puts "NIC: #{nic["Id"]} > #{mac_addr} > #{link_status} > #{port_num} > #{link_speed_mbps}Mbps"
625
- {
626
- "name" => nic["Id"],
627
- "status" => link_status,
628
- "mac" => mac_addr,
629
- "port" => port_num,
630
- "speed_mbps" => link_speed_mbps,
631
- "kind" => network_technology&.downcase
632
- }
633
- end
634
- {
635
- "name" => adapter["Id"], # "NIC.Integrated.1-1",
636
- "manufacturer" => adapter["Manufacturer"], # "Mellanox Technologies",
637
- "model" => adapter["Model"], # "MLNX 100GbE 2P ConnectX6 Adpt"
638
- "part_number" => adapter["PartNumber"], # "08AAAA",
639
- "serial" => adapter["SerialNumber"], # "TW78AAAAAAAAAA",
640
- "ports" => ports
641
- }
642
- end
643
- # Now let's parse the NICs and make sure we have a PORT for each one.
644
- # Note that we set the MAC address for the MANAGEMENT port by a heuristic!!!
645
- # If we ever see a 1000 Mbps port in the NIC.Integrated or NIC.Embedded, that's the Managament Port!
646
- nics.each do |nic|
647
- # puts nic.inspect
648
- nic["ports"].each do |port|
649
- # puts port.inspect
650
- if port["speed_mbps"] == 1000 &&
651
- (port["name"] =~ /NIC.Integrated/ || nic["name"] =~ /NIC.Embedded/) &&
652
- port['status'] == 'Up' &&
653
- port['kind'] == 'ethernet' &&
654
- port['mac'] =~ /([0-9a-fA-F]{2}[:-]){5}([0-9a-fA-F]{2})/
655
- Rails.logger.debug "Identified Management Port: #{port['name']} #{port['mac']}".blue
656
- self.management_port.update(mac_addr: port["mac"])
657
- end
658
- end
659
- end
660
- self.meta["nics"] = nics
661
- self.save
662
- end
663
- # Kind of like a NIC, but serves a different purpose.
664
- def idrac
665
- body = self.get(path: "Managers/iDRAC.Embedded.1/EthernetInterfaces/iDRAC.Embedded.1%23NIC.1")["body"]
666
- idrac = {
667
- "name" => body["Id"],
668
- "status" => body["Status"]["Health"] == 'OK' ? 'Up' : 'Down',
669
- "mac" => body["MACAddress"],
670
- "mask" => body["IPv4Addresses"].first["SubnetMask"],
671
- "ipv4" => body["IPv4Addresses"].first["Address"],
672
- "origin" => body["IPv4Addresses"].first["AddressOrigin"], # DHCP or Static
673
- "port" => nil,
674
- "speed_mbps" => body["SpeedMbps"],
675
- "kind" => "ethernet"
676
- }
677
- self.meta["idrac"] = idrac
678
- self.save
679
- end
680
-
681
- =end
406
+ end
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.5.6"
4
+ VERSION = "0.5.7"
5
5
  end
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.5.6
4
+ version: 0.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel