idrac 0.1.92 → 0.3.1

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.
data/bin/idrac CHANGED
@@ -23,6 +23,8 @@ module IDRAC
23
23
  class_option :no_ssl, type: :boolean, default: false, desc: "Disable SSL"
24
24
  class_option :verify_ssl, type: :boolean, default: false, desc: "Enable SSL verification (not recommended for iDRAC's self-signed certificates)"
25
25
  class_option :auto_delete_sessions, type: :boolean, default: true, desc: "Automatically delete sessions when maximum sessions are reached"
26
+ class_option :retries, type: :numeric, default: 3, desc: "Number of retries for API calls"
27
+ class_option :retry_delay, type: :numeric, default: 1, desc: "Initial delay in seconds between retries (increases exponentially)"
26
28
  class_option :verbose, type: :boolean, default: false, aliases: '-v', desc: "Enable verbose output"
27
29
  class_option :very_verbose, type: :boolean, default: false, aliases: '-vv', desc: "Enable very verbose output with detailed headers and requests"
28
30
  class_option :debug, type: :boolean, default: false, aliases: '-vvv', desc: "Enable debug output with detailed stack traces and SSL info"
@@ -454,6 +456,752 @@ module IDRAC
454
456
  end
455
457
  end
456
458
 
459
+ # Storage commands
460
+ desc "storage_controller", "Get storage controller information"
461
+ map "storage:controller" => :storage_controller
462
+ def storage_controller
463
+ with_idrac_client do |client|
464
+ controller = client.controller
465
+ puts "\nStorage Controller Summary:".green.bold
466
+ puts "Name: #{controller['Name']}".cyan
467
+ puts "Model: #{controller['Model']}".cyan
468
+ puts "Health: #{controller['Status']['Health']}".cyan
469
+ puts "Manufacturer: #{controller['Manufacturer']}".cyan
470
+
471
+ if client.controller_encryption_capable?(controller)
472
+ puts "Encryption Capable: Yes".green
473
+ puts "Encryption Enabled: #{client.controller_encryption_enabled?(controller) ? 'Yes'.green : 'No'.yellow}"
474
+ else
475
+ puts "Encryption Capable: No".yellow
476
+ end
477
+ end
478
+ end
479
+
480
+ desc "storage_drives", "Get physical drive information"
481
+ map "storage:drives" => :storage_drives
482
+ def storage_drives
483
+ with_idrac_client do |client|
484
+ controller = client.controller
485
+ drives = client.drives(controller)
486
+
487
+ puts "\nPhysical Drives (#{drives.size}):".green.bold
488
+ drives.each do |drive|
489
+ capacity_gb = drive[:capacity_bytes].to_f / (1024**3)
490
+ health_color = drive[:health] == "OK" ? :green : :red
491
+
492
+ puts "#{drive[:name]}:".bold
493
+ puts " Model: #{drive[:model]}".cyan
494
+ puts " Health: #{drive[:health].send(health_color)}"
495
+ puts " Capacity: #{capacity_gb.round(2)} GB".cyan
496
+ puts " Media Type: #{drive[:media_type]}".cyan
497
+ puts " Serial: #{drive[:serial]}".cyan
498
+ if drive[:encryption_ability]
499
+ puts " Encryption: #{drive[:encryption_ability]}".cyan
500
+ end
501
+ puts ""
502
+ end
503
+ end
504
+ end
505
+
506
+ desc "storage_volumes", "Get virtual disk information"
507
+ map "storage:volumes" => :storage_volumes
508
+ def storage_volumes
509
+ with_idrac_client do |client|
510
+ controller = client.controller
511
+ volumes = client.volumes(controller)
512
+
513
+ puts "\nVirtual Disks (#{volumes.size}):".green.bold
514
+ volumes.each do |volume|
515
+ capacity_gb = volume[:capacity_bytes].to_f / (1024**3)
516
+ health_color = volume[:health] == "OK" ? :green : :yellow
517
+
518
+ puts "#{volume[:name]}:".bold
519
+ puts " RAID Type: #{volume[:raid_level] || volume[:volume_type]}".cyan
520
+ puts " Health: #{volume[:health].send(health_color)}"
521
+ puts " Capacity: #{capacity_gb.round(2)} GB".cyan
522
+ puts " Stripe Size: #{volume[:stripe_size]}".cyan
523
+ puts " Read Cache: #{volume[:read_cache_policy]}".cyan
524
+ puts " Write Cache: #{volume[:write_cache_policy]}".cyan
525
+ puts " FastPath: #{volume[:fastpath] == 'enabled' ? 'Enabled'.green : 'Disabled'.yellow}"
526
+ puts " Encrypted: #{volume[:encrypted] ? 'Yes'.green : 'No'.yellow}" if volume[:encrypted] != nil
527
+
528
+ if volume[:progress]
529
+ puts " Progress: #{volume[:progress]}%".cyan
530
+ puts " Operation: #{volume[:message]}".cyan
531
+ end
532
+ puts ""
533
+ end
534
+ end
535
+ end
536
+
537
+ desc "storage_create_volume", "Create a new virtual disk"
538
+ map "storage:create_volume" => :storage_create_volume
539
+ method_option :name, type: :string, default: "vssd0", desc: "Volume name"
540
+ method_option :raid, type: :string, default: "RAID5", desc: "RAID type (RAID0, RAID1, RAID5, RAID6, RAID10)"
541
+ def storage_create_volume
542
+ with_idrac_client do |client|
543
+ controller = client.controller
544
+ drives = client.drives(controller)
545
+
546
+ # Confirm with the user before proceeding
547
+ puts "This will create a new #{options[:raid]} volume named '#{options[:name]}' using #{drives.size} drives.".yellow
548
+ puts "All data on these drives will be lost!".red.bold
549
+
550
+ print "Do you want to continue? (y/n): "
551
+ confirmation = $stdin.gets.chomp.downcase
552
+
553
+ if confirmation == 'y'
554
+ client.create_virtual_disk(controller['Id'], drives, name: options[:name], raid_type: options[:raid])
555
+ puts "Volume created successfully".green
556
+ else
557
+ puts "Operation cancelled".yellow
558
+ end
559
+ end
560
+ end
561
+
562
+ desc "storage_delete_volume", "Delete a virtual disk"
563
+ map "storage:delete_volume" => :storage_delete_volume
564
+ def storage_delete_volume
565
+ with_idrac_client do |client|
566
+ controller = client.controller
567
+ volumes = client.volumes(controller)
568
+
569
+ if volumes.empty?
570
+ puts "No volumes found to delete".yellow
571
+ return
572
+ end
573
+
574
+ puts "Available volumes:".green
575
+ volumes.each_with_index do |vol, idx|
576
+ puts "#{idx+1}. #{vol[:name]} (#{vol[:raid_level] || vol[:volume_type]}, #{(vol[:capacity_bytes].to_f / (1024**3)).round(2)} GB)"
577
+ end
578
+
579
+ print "Enter the number of the volume to delete (or 'q' to quit): "
580
+ input = $stdin.gets.chomp
581
+
582
+ if input.downcase == 'q'
583
+ puts "Operation cancelled".yellow
584
+ return
585
+ end
586
+
587
+ index = input.to_i - 1
588
+ if index >= 0 && index < volumes.size
589
+ volume = volumes[index]
590
+
591
+ puts "You are about to delete '#{volume[:name]}'. All data will be lost!".red.bold
592
+ print "Type the volume name to confirm deletion: "
593
+ confirm = $stdin.gets.chomp
594
+
595
+ if confirm == volume[:name]
596
+ client.delete_volume(volume[:"@odata.id"])
597
+ puts "Volume deleted successfully".green
598
+ else
599
+ puts "Volume name did not match. Operation cancelled".yellow
600
+ end
601
+ else
602
+ puts "Invalid selection".red
603
+ end
604
+ end
605
+ end
606
+
607
+ desc "storage_encryption_enable", "Enable Self-Encrypting Drive (SED) support"
608
+ map "storage:encryption_enable" => :storage_encryption_enable
609
+ method_option :passphrase, type: :string, desc: "Encryption passphrase"
610
+ method_option :keyid, type: :string, desc: "Key identifier"
611
+ def storage_encryption_enable
612
+ with_idrac_client do |client|
613
+ controller = client.controller
614
+ drives = client.drives(controller)
615
+
616
+ if !client.controller_encryption_capable?(controller)
617
+ puts "This controller does not support encryption".red
618
+ return
619
+ end
620
+
621
+ if client.controller_encryption_enabled?(controller)
622
+ puts "Encryption is already enabled on this controller".yellow
623
+ return
624
+ end
625
+
626
+ if !client.all_seds?(drives)
627
+ puts "Not all drives are Self-Encrypting Drives (SEDs)".red
628
+ return
629
+ end
630
+
631
+ # Get passphrase if not provided
632
+ passphrase = options[:passphrase]
633
+ if passphrase.nil?
634
+ print "Enter encryption passphrase (min 8 characters): "
635
+ passphrase = $stdin.noecho(&:gets).chomp
636
+ puts
637
+ end
638
+
639
+ # Get keyid if not provided
640
+ keyid = options[:keyid] || "RAID-Key-#{Time.now.strftime('%Y%m%d')}"
641
+
642
+ client.enable_local_key_management(controller['Id'], passphrase: passphrase, keyid: keyid)
643
+ puts "Encryption enabled successfully".green
644
+ end
645
+ end
646
+
647
+ desc "storage_encryption_disable", "Disable Self-Encrypting Drive (SED) support"
648
+ map "storage:encryption_disable" => :storage_encryption_disable
649
+ def storage_encryption_disable
650
+ with_idrac_client do |client|
651
+ controller = client.controller
652
+
653
+ if !client.controller_encryption_enabled?(controller)
654
+ puts "Encryption is not enabled on this controller".yellow
655
+ return
656
+ end
657
+
658
+ puts "WARNING: Disabling encryption may prevent access to encrypted data!".red.bold
659
+ print "Type 'DISABLE' to confirm: "
660
+ confirmation = $stdin.gets.chomp
661
+
662
+ if confirmation == 'DISABLE'
663
+ client.disable_local_key_management(controller['Id'])
664
+ puts "Encryption disabled successfully".green
665
+ else
666
+ puts "Operation cancelled".yellow
667
+ end
668
+ end
669
+ end
670
+
671
+ # System component commands
672
+ desc "system_memory", "Get memory/DIMM information"
673
+ map "system:memory" => :system_memory
674
+ def system_memory
675
+ with_idrac_client do |client|
676
+ memory = client.memory
677
+
678
+ puts "\nMemory Modules (#{memory.size}):".green.bold
679
+ memory.each do |dimm|
680
+ capacity_gb = dimm["capacity_bytes"].to_f / (1024**3)
681
+ health_color = dimm["health"] == "OK" ? :green : :red
682
+
683
+ puts "#{dimm['name']}:".bold
684
+ puts " Model: #{dimm['model']}".cyan
685
+ puts " Health: #{dimm['health'].send(health_color)}"
686
+ puts " Capacity: #{capacity_gb.round(2)} GB".cyan
687
+ puts " Speed: #{dimm['speed_mhz']} MHz".cyan
688
+ puts " Serial: #{dimm['serial']}".cyan
689
+ puts ""
690
+ end
691
+
692
+ # Show total memory
693
+ puts "Total Memory: #{client.total_memory_human(memory)}".green.bold
694
+ end
695
+ end
696
+
697
+ desc "system_psus", "Get power supply information"
698
+ map "system:psus" => :system_psus
699
+ def system_psus
700
+ with_idrac_client do |client|
701
+ psus = client.psus
702
+
703
+ puts "\nPower Supplies (#{psus.size}):".green.bold
704
+ psus.each do |psu|
705
+ health_color = psu["status"] == "OK" ? :green : :red
706
+
707
+ puts "#{psu['name']}:".bold
708
+ puts " Model: #{psu['model']}".cyan
709
+ puts " Health: #{psu['status'].send(health_color)}"
710
+ puts " Input: #{psu['voltage']} V (#{psu['voltage_human']})".cyan
711
+ puts " Output: #{psu['watts']} W".cyan
712
+ puts " Serial: #{psu['serial']}".cyan
713
+ puts ""
714
+ end
715
+ end
716
+ end
717
+
718
+ desc "system_fans", "Get fan information"
719
+ map "system:fans" => :system_fans
720
+ def system_fans
721
+ with_idrac_client do |client|
722
+ fans = client.fans
723
+
724
+ if fans.empty?
725
+ puts "No fan information available (system might be powered off)".yellow
726
+ return
727
+ end
728
+
729
+ puts "\nFans (#{fans.size}):".green.bold
730
+ fans.each do |fan|
731
+ health_color = fan["status"] == "OK" ? :green : :red
732
+
733
+ puts "#{fan['name']}:".bold
734
+ puts " Health: #{fan['status'].send(health_color)}"
735
+ puts " Speed: #{fan['rpm']} RPM".cyan
736
+ puts ""
737
+ end
738
+ end
739
+ end
740
+
741
+ desc "system_nics", "Get network adapter information"
742
+ map "system:nics" => :system_nics
743
+ def system_nics
744
+ with_idrac_client do |client|
745
+ nics = client.nics
746
+ pci = client.pci_devices
747
+ nics_with_pci = client.nics_to_pci(nics, pci)
748
+
749
+ puts "\nNetwork Adapters (#{nics_with_pci.size}):".green.bold
750
+ nics_with_pci.each do |nic|
751
+ puts "#{nic['name']}:".bold
752
+ puts " Manufacturer: #{nic['manufacturer']}".cyan
753
+ puts " Model: #{nic['model']}".cyan
754
+
755
+ if nic['ports'] && nic['ports'].any?
756
+ puts " Ports:".cyan
757
+ nic['ports'].each do |port|
758
+ status_color = port["status"] == "Up" ? :green : :yellow
759
+
760
+ puts " #{port['name']}:".bold
761
+ puts " Status: #{port['status'].send(status_color)}"
762
+ puts " MAC: #{port['mac']}".cyan
763
+ puts " Speed: #{port['speed_mbps']} Mbps".cyan
764
+ if port['pci']
765
+ puts " PCI Bus: #{port['pci']}".cyan
766
+ puts " Linux Device: #{port['linux_device']}".cyan
767
+ end
768
+ puts ""
769
+ end
770
+ end
771
+ puts ""
772
+ end
773
+ end
774
+ end
775
+
776
+ desc "system_idrac_network", "Get iDRAC network configuration"
777
+ map "system:idrac_network" => :system_idrac_network
778
+ def system_idrac_network
779
+ with_idrac_client do |client|
780
+ idrac = client.idrac_network
781
+
782
+ puts "\niDRAC Network Configuration:".green.bold
783
+ puts "Status: #{idrac['status']}".cyan
784
+ puts "IPv4: #{idrac['ipv4']}".cyan
785
+ puts "Subnet Mask: #{idrac['mask']}".cyan
786
+ puts "MAC Address: #{idrac['mac']}".cyan
787
+ puts "Origin: #{idrac['origin']}".cyan
788
+ puts "Speed: #{idrac['speed_mbps']} Mbps".cyan
789
+ end
790
+ end
791
+
792
+ desc "system_events", "Get system event logs"
793
+ map "system:events" => :system_events
794
+ def system_events
795
+ with_idrac_client do |client|
796
+ events = client.system_event_logs
797
+
798
+ puts "\nSystem Events (#{events.size}):".green.bold
799
+ events.each do |event|
800
+ severity_color = case event[:severity]
801
+ when "Critical" then :red
802
+ when "Warning" then :yellow
803
+ else :cyan
804
+ end
805
+
806
+ puts "#{event[:id]} - #{event[:created]} - #{event[:severity].send(severity_color)} - #{event[:message]}"
807
+ end
808
+ end
809
+ end
810
+
811
+ # Virtual media commands
812
+ desc "vmedia_status", "Get virtual media status"
813
+ map "vmedia:status" => :vmedia_status
814
+ def vmedia_status
815
+ with_idrac_client do |client|
816
+ media = client.virtual_media
817
+
818
+ puts "\nVirtual Media Status:".green.bold
819
+
820
+ if media.empty?
821
+ puts "No virtual media devices found".yellow
822
+ return
823
+ end
824
+
825
+ media.each do |m|
826
+ status = m[:inserted] ? "Inserted: #{m[:image]}".green : "Not Inserted".yellow
827
+ puts "#{m[:device]}: #{status}"
828
+ end
829
+ end
830
+ end
831
+
832
+ desc "vmedia_insert URL", "Insert virtual media from URL"
833
+ map "vmedia:insert" => :vmedia_insert
834
+ method_option :device, type: :string, default: "CD", desc: "Device type (CD or RemovableDisk)"
835
+ def vmedia_insert(url)
836
+ with_idrac_client do |client|
837
+ puts "Inserting media from #{url} into #{options[:device]}..."
838
+ client.insert_virtual_media(url, device: options[:device])
839
+ end
840
+ end
841
+
842
+ desc "vmedia_eject", "Eject virtual media"
843
+ map "vmedia:eject" => :vmedia_eject
844
+ method_option :device, type: :string, default: "CD", desc: "Device to eject (CD or RemovableDisk)"
845
+ def vmedia_eject
846
+ with_idrac_client do |client|
847
+ client.eject_virtual_media(device: options[:device])
848
+ end
849
+ end
850
+
851
+ desc "vmedia_boot_once", "Set system to boot from virtual media once"
852
+ map "vmedia:boot_once" => :vmedia_boot_once
853
+ def vmedia_boot_once
854
+ with_idrac_client do |client|
855
+ client.set_one_time_virtual_media_boot
856
+ puts "System configured to boot from virtual media on next restart"
857
+ end
858
+ end
859
+
860
+ # Boot management commands
861
+ desc "boot_options", "Get current boot options"
862
+ map "boot:options" => :boot_options
863
+ def boot_options
864
+ with_idrac_client do |client|
865
+ options = client.get_bios_boot_options
866
+
867
+ if options == false
868
+ puts "Failed to get boot options. System may not be in UEFI mode.".red
869
+ return
870
+ end
871
+
872
+ puts "\nBoot Options:".green.bold
873
+
874
+ # Display enabled boot options (current boot order)
875
+ puts "Current Boot Order:".cyan
876
+ options[:boot_order].each_with_index do |opt, idx|
877
+ puts " #{idx+1}. #{opt}"
878
+ end
879
+
880
+ # Display all available boot options
881
+ puts "\nAvailable Boot Options:".cyan
882
+ options[:boot_options].each do |opt|
883
+ enabled = options[:boot_order].include?(opt)
884
+ status = enabled ? "Enabled".green : "Disabled".yellow
885
+ puts " #{opt}: #{status}"
886
+ end
887
+ end
888
+ end
889
+
890
+ desc "boot_enable_uefi", "Enable UEFI boot mode"
891
+ map "boot:enable_uefi" => :boot_enable_uefi
892
+ def boot_enable_uefi
893
+ with_idrac_client do |client|
894
+ client.ensure_uefi_boot
895
+ end
896
+ end
897
+
898
+ desc "boot_set_hd_first", "Set boot order with hard drive first"
899
+ map "boot:set_hd_first" => :boot_set_hd_first
900
+ def boot_set_hd_first
901
+ with_idrac_client do |client|
902
+ client.set_boot_order_hd_first
903
+ end
904
+ end
905
+
906
+ desc "boot_ignore_errors", "Configure BIOS to ignore boot errors"
907
+ map "boot:ignore_errors" => :boot_ignore_errors
908
+ method_option :enable, type: :boolean, default: true, desc: "Enable or disable ignoring boot errors"
909
+ def boot_ignore_errors
910
+ with_idrac_client do |client|
911
+ client.set_bios_ignore_errors(options[:enable])
912
+ if options[:enable]
913
+ puts "BIOS configured to ignore boot errors".green
914
+ else
915
+ puts "BIOS configured to halt on boot errors".green
916
+ end
917
+ end
918
+ end
919
+
920
+ desc "boot_power_optimization", "Configure BIOS for OS-controlled power management"
921
+ map "boot:power_optimization" => :boot_power_optimization
922
+ def boot_power_optimization
923
+ with_idrac_client do |client|
924
+ client.set_bios_os_power_control
925
+ puts "BIOS configured for OS power management optimization".green
926
+ end
927
+ end
928
+
929
+ desc "boot_source_override", "Get current boot source override settings"
930
+ map "boot:source_override" => :boot_source_override
931
+ def boot_source_override
932
+ with_idrac_client do |client|
933
+ client.get_boot_source_override
934
+ end
935
+ end
936
+
937
+ # Test commands
938
+ desc "test_live", "Test all major functionality of the gem on a real system"
939
+ map "test:live" => :test_live
940
+ method_option :timeout, type: :numeric, default: 10, desc: "Connection timeout in seconds"
941
+ def test_live
942
+ test_results = {}
943
+
944
+ puts "Running comprehensive live test of idrac gem functionality...".green.bold
945
+ puts "=" * 80
946
+ puts "This will test all read-only operations of the gem. No changes will be made to your system.".yellow
947
+ puts "Using connection timeout of #{options[:timeout]} seconds (use --timeout=X to change)".yellow
948
+ puts "=" * 80
949
+
950
+ with_idrac_client do |client|
951
+ # Set higher verbosity temporarily for comprehensive logging
952
+ original_verbosity = client.verbosity
953
+
954
+ # Configure verbosity level based on user options
955
+ if options[:very_verbose] || options[:debug]
956
+ client.verbosity = options[:debug] ? 3 : 2
957
+ puts "HTTP request/response details will be shown (verbosity level: #{client.verbosity})".cyan
958
+ else
959
+ client.verbosity = options[:verbose] ? 1 : 0
960
+ puts "HTTP request/response details hidden (use -vv or -vvv for details)".cyan
961
+
962
+ # Silence Faraday logging for lower verbosity levels
963
+ if defined?(Faraday.default_connection) && Faraday.default_connection
964
+ begin
965
+ Faraday.default_connection.builder.handlers.each do |handler|
966
+ if defined?(Faraday::Response::Logger) && handler.klass == Faraday::Response::Logger &&
967
+ handler.instance_variable_defined?(:@logger) && handler.instance_variable_get(:@logger)
968
+ handler.instance_variable_get(:@logger).level = Logger::WARN
969
+ end
970
+ end
971
+ rescue => e
972
+ puts "Warning: Unable to configure logging: #{e.message}".yellow if options[:verbose]
973
+ end
974
+ end
975
+
976
+ # Also try to silence the built-in logger in the client
977
+ if client.respond_to?(:connection) && client.connection.respond_to?(:builder)
978
+ begin
979
+ client.connection.builder.handlers.each do |handler|
980
+ if defined?(Faraday::Response::Logger) && handler.klass == Faraday::Response::Logger &&
981
+ handler.instance_variable_defined?(:@logger) && handler.instance_variable_get(:@logger)
982
+ handler.instance_variable_get(:@logger).level = Logger::WARN
983
+ end
984
+ end
985
+ rescue => e
986
+ puts "Warning: Unable to configure client logging: #{e.message}".yellow if options[:verbose]
987
+ end
988
+ end
989
+ end
990
+
991
+ # Set timeout for connection - modify the connection object if it's available
992
+ begin
993
+ if client.respond_to?(:connection) && client.connection.respond_to?(:options)
994
+ client.connection.options.timeout = options[:timeout]
995
+ client.connection.options.open_timeout = options[:timeout]
996
+ end
997
+ rescue => e
998
+ puts "Warning: Unable to set timeout options: #{e.message}".yellow
999
+ end
1000
+
1001
+ begin
1002
+ # Establish a session that will be used for all tests
1003
+ # Force the creation of a new session and test it works
1004
+ if client.session.respond_to?(:delete)
1005
+ client.session.delete rescue nil
1006
+ end
1007
+
1008
+ session_created = client.session.create
1009
+ if !session_created && !client.direct_mode
1010
+ puts "Failed to establish a session, falling back to direct mode".yellow
1011
+ client.direct_mode = true
1012
+ end
1013
+
1014
+ # Basic connection test
1015
+ puts "\n[TEST] Basic connection".cyan.bold
1016
+ begin
1017
+ version = client.redfish_version
1018
+ puts "✓ Connection successful, Redfish version: #{version}".green
1019
+ test_results["connection"] = { status: "PASS", message: "Connected to iDRAC successfully" }
1020
+ rescue Faraday::TimeoutError => e
1021
+ puts "✗ Connection timed out after #{options[:timeout]} seconds. Check host and network.".red
1022
+ test_results["connection"] = { status: "FAIL", message: "Connection timeout: #{e.message}" }
1023
+ puts "No further tests will be run until connection is established.".red
1024
+ break
1025
+ rescue => e
1026
+ puts "✗ Connection failed: #{e.message}".red
1027
+ test_results["connection"] = { status: "FAIL", message: e.message }
1028
+ puts "No further tests will be run until connection is established.".red
1029
+ break
1030
+ end
1031
+
1032
+ # System info test
1033
+ puts "\n[TEST] System information".cyan.bold
1034
+ begin
1035
+ response = client.authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1")
1036
+ system_info = JSON.parse(response.body)
1037
+ puts "✓ System info: #{system_info['Model']} (#{system_info['SKU']})".green
1038
+ test_results["system_info"] = { status: "PASS", message: "Retrieved system information successfully" }
1039
+ rescue => e
1040
+ puts "✗ System info failed: #{e.message}".red
1041
+ test_results["system_info"] = { status: "FAIL", message: e.message }
1042
+ # If we can't get basic system info, stop testing
1043
+ break
1044
+ end
1045
+
1046
+ # Power tests
1047
+ puts "\n[TEST] Power management".cyan.bold
1048
+ begin
1049
+ power_state = client.get_power_state
1050
+ puts "✓ Power state: #{power_state}".green
1051
+
1052
+ watts = client.get_power_usage_watts
1053
+ puts "✓ Power usage: #{watts} watts".green
1054
+ test_results["power"] = { status: "PASS", message: "Retrieved power information successfully" }
1055
+ rescue => e
1056
+ puts "✗ Power tests failed: #{e.message}".red
1057
+ test_results["power"] = { status: "FAIL", message: e.message }
1058
+ end
1059
+
1060
+ # Storage tests
1061
+ puts "\n[TEST] Storage management".cyan.bold
1062
+ begin
1063
+ controller = client.controller
1064
+ puts "✓ Storage controller: #{controller['Name']} (#{controller['Model']})".green
1065
+
1066
+ drives = client.drives(controller)
1067
+ puts "✓ Found #{drives.size} physical drives".green
1068
+
1069
+ volumes = client.volumes(controller)
1070
+ puts "✓ Found #{volumes.size} virtual disks".green
1071
+ test_results["storage"] = { status: "PASS", message: "Retrieved storage information successfully" }
1072
+ rescue => e
1073
+ puts "✗ Storage tests failed: #{e.message}".red
1074
+ test_results["storage"] = { status: "FAIL", message: e.message }
1075
+ end
1076
+
1077
+ # System component tests
1078
+ puts "\n[TEST] System components".cyan.bold
1079
+ begin
1080
+ begin
1081
+ memory = client.memory
1082
+ puts "✓ Memory: #{client.total_memory_human(memory)}".green
1083
+ memory_test_status = "PASS"
1084
+ memory_test_message = "Retrieved memory information successfully"
1085
+ rescue => e
1086
+ puts "✗ Memory test failed: #{e.message}".red
1087
+ memory_test_status = "FAIL"
1088
+ memory_test_message = e.message
1089
+ end
1090
+
1091
+ begin
1092
+ psus = client.psus
1093
+ puts "✓ Found #{psus.size} power supplies".green
1094
+ psu_test_status = "PASS"
1095
+ psu_test_message = "Retrieved PSU information successfully"
1096
+ rescue => e
1097
+ puts "✗ PSU test failed: #{e.message}".red
1098
+ psu_test_status = "FAIL"
1099
+ psu_test_message = e.message
1100
+ end
1101
+
1102
+ begin
1103
+ fans = client.fans
1104
+ puts "✓ Found #{fans.size} fans".green
1105
+ fan_test_status = "PASS"
1106
+ fan_test_message = "Retrieved fan information successfully"
1107
+ rescue => e
1108
+ puts "✗ Fan test failed: #{e.message}".red
1109
+ fan_test_status = "FAIL"
1110
+ fan_test_message = e.message
1111
+ end
1112
+
1113
+ begin
1114
+ nics = client.nics
1115
+ puts "✓ Found #{nics.size} network interfaces".green
1116
+ nic_test_status = "PASS"
1117
+ nic_test_message = "Retrieved NIC information successfully"
1118
+ rescue => e
1119
+ puts "✗ NIC test failed: #{e.message}".red
1120
+ nic_test_status = "FAIL"
1121
+ nic_test_message = e.message
1122
+ end
1123
+
1124
+ test_results["memory"] = { status: memory_test_status, message: memory_test_message }
1125
+ test_results["psus"] = { status: psu_test_status, message: psu_test_message }
1126
+ test_results["fans"] = { status: fan_test_status, message: fan_test_message }
1127
+ test_results["nics"] = { status: nic_test_status, message: nic_test_message }
1128
+ rescue => e
1129
+ puts "✗ System component tests failed: #{e.message}".red
1130
+ test_results["system_components"] = { status: "FAIL", message: e.message }
1131
+ end
1132
+
1133
+ # Virtual media tests
1134
+ puts "\n[TEST] Virtual media".cyan.bold
1135
+ begin
1136
+ media = client.virtual_media
1137
+ puts "✓ Found #{media.size} virtual media devices".green
1138
+ test_results["virtual_media"] = { status: "PASS", message: "Retrieved virtual media information successfully" }
1139
+ rescue => e
1140
+ puts "✗ Virtual media test failed: #{e.message}".red
1141
+ test_results["virtual_media"] = { status: "FAIL", message: e.message }
1142
+ end
1143
+
1144
+ # Boot management tests
1145
+ puts "\n[TEST] Boot management".cyan.bold
1146
+ begin
1147
+ boot_options = client.get_bios_boot_options
1148
+ puts "✓ Retrieved BIOS boot options".green
1149
+
1150
+ boot_override = client.get_boot_source_override
1151
+ puts "✓ Boot source override: #{boot_override}".green
1152
+ test_results["boot"] = { status: "PASS", message: "Retrieved boot information successfully" }
1153
+ rescue => e
1154
+ puts "✗ Boot management test failed: #{e.message}".red
1155
+ test_results["boot"] = { status: "FAIL", message: e.message }
1156
+ end
1157
+
1158
+ # Jobs and tasks
1159
+ puts "\n[TEST] Jobs and tasks".cyan.bold
1160
+ begin
1161
+ jobs = client.jobs
1162
+ puts "✓ Retrieved job queue information".green
1163
+ test_results["jobs"] = { status: "PASS", message: "Retrieved job information successfully" }
1164
+ rescue => e
1165
+ puts "✗ Jobs test failed: #{e.message}".red
1166
+ test_results["jobs"] = { status: "FAIL", message: e.message }
1167
+ end
1168
+
1169
+ rescue => e
1170
+ puts "\n✗ Unexpected error during testing: #{e.message}".red.bold
1171
+ puts e.backtrace.join("\n").red if client.verbosity >= 2
1172
+ ensure
1173
+ # Clean up - make sure we delete the session to avoid leaving orphaned sessions
1174
+ begin
1175
+ if client.session.respond_to?(:delete) && client.session.x_auth_token
1176
+ client.session.delete
1177
+ end
1178
+ rescue
1179
+ # Ignore errors during cleanup
1180
+ end
1181
+
1182
+ # Restore original verbosity
1183
+ client.verbosity = original_verbosity
1184
+ end
1185
+
1186
+ # Print summary
1187
+ puts "\n" + "=" * 80
1188
+ puts "TEST SUMMARY:".green.bold
1189
+ puts "=" * 80
1190
+
1191
+ pass_count = test_results.count { |_, v| v[:status] == "PASS" }
1192
+ fail_count = test_results.count { |_, v| v[:status] == "FAIL" }
1193
+
1194
+ test_results.each do |test_name, result|
1195
+ status_color = result[:status] == "PASS" ? :green : :red
1196
+ puts "#{test_name.ljust(20)}: #{result[:status].send(status_color)} - #{result[:message]}"
1197
+ end
1198
+
1199
+ puts "=" * 80
1200
+ puts "OVERALL: #{pass_count} passed, #{fail_count} failed".send(fail_count == 0 ? :green : :yellow).bold
1201
+ puts "=" * 80
1202
+ end
1203
+ end
1204
+
457
1205
  private
458
1206
 
459
1207
  def with_idrac_client
@@ -509,7 +1257,9 @@ module IDRAC
509
1257
  port: options[:port],
510
1258
  use_ssl: !options[:no_ssl],
511
1259
  verify_ssl: options[:verify_ssl],
512
- auto_delete_sessions: options[:auto_delete_sessions]
1260
+ auto_delete_sessions: options[:auto_delete_sessions],
1261
+ retry_count: options[:retries],
1262
+ retry_delay: options[:retry_delay]
513
1263
  )
514
1264
  end
515
1265
  end