supermicro 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 669c0c630a85f14dd798b0ae247f337e0f87ded512ffeb3900cb26a1b90d3fbb
4
+ data.tar.gz: 308a2fb1e423da978a72ac6e5ef47107faf92dd896deb90a5cf787aad6529eb0
5
+ SHA512:
6
+ metadata.gz: d0d5e2e6813f3e7a6723b02ccae82ee1a385b523567bade9646129e89a1d7a620f96753b8daf5c4d837c56dd52499132fe69ad6cba54293520fa4bd55262d86b
7
+ data.tar.gz: c4746751cc618049f748c28020890fe8dee881c643b031e77d354081074b337f6f2fc8f0c53d05067fb60c92580e8e6b389beb861151c724e5ae130ef68d3e19
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jonathan Siegel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # Supermicro Redfish Ruby Client
2
+
3
+ A Ruby client library for interacting with Supermicro BMC (Baseboard Management Controller) via the Redfish API.
4
+
5
+ ## Features
6
+
7
+ This gem provides a Ruby interface to manage Supermicro servers through their BMC, offering the same functionality as the iDRAC gem but for Supermicro hardware:
8
+
9
+ ### Inventory Management
10
+ - **System Information**: Model, serial number, BIOS version, UUID
11
+ - **CPU**: Socket information, cores, threads, speed
12
+ - **Memory**: DIMMs capacity, speed, health status
13
+ - **Storage**: Controllers, physical drives, volumes/RAID configuration
14
+ - **Network**: NICs with MAC addresses, link status, IP configuration
15
+ - **Power Supplies**: Status, wattage, health monitoring
16
+ - **Thermal**: Fan speeds, temperature sensors
17
+ - **Power Consumption**: Current usage, capacity
18
+
19
+ ### Configuration
20
+ - **Boot Order**: Set boot device priority
21
+ - **Boot Override**: One-time or persistent boot device selection
22
+ - **BIOS Settings**: Read and modify BIOS attributes
23
+ - **Network Protocols**: Configure BMC network services
24
+ - **User Management**: Create, modify, delete BMC users
25
+
26
+ ### Virtual Media
27
+ - **Mount/Unmount ISO**: Attach HTTP-served ISO images
28
+ - **Virtual Media Status**: Check mounted media
29
+ - **Boot from Virtual Media**: Combined mount and boot configuration
30
+
31
+ ### Power Management
32
+ - **Power Status**: Check current power state
33
+ - **Power Control**: On, Off, Restart, Power Cycle
34
+ - **Graceful Shutdown**: Attempt graceful OS shutdown
35
+
36
+ ### Monitoring & Logging
37
+ - **System Event Log**: View and clear SEL entries
38
+ - **Jobs/Tasks**: Monitor long-running operations
39
+ - **Active Sessions**: View current BMC sessions
40
+
41
+ ## Installation
42
+
43
+ Add to your Gemfile:
44
+
45
+ ```ruby
46
+ gem 'supermicro'
47
+ ```
48
+
49
+ Or install directly:
50
+
51
+ ```bash
52
+ gem install supermicro
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ ### Basic Connection
58
+
59
+ ```ruby
60
+ require 'supermicro'
61
+
62
+ # Create a client
63
+ client = Supermicro.new(
64
+ host: '192.168.1.100',
65
+ username: 'admin',
66
+ password: 'password',
67
+ verify_ssl: false
68
+ )
69
+
70
+ # Or use block form with automatic session cleanup
71
+ Supermicro.connect(
72
+ host: '192.168.1.100',
73
+ username: 'admin',
74
+ password: 'password'
75
+ ) do |client|
76
+ # Your code here
77
+ puts client.power_status
78
+ end
79
+ ```
80
+
81
+ ### Power Management
82
+
83
+ ```ruby
84
+ # Check power status
85
+ status = client.power_status # => "On" or "Off"
86
+
87
+ # Power operations
88
+ client.power_on
89
+ client.power_off
90
+ client.power_restart
91
+ client.power_cycle
92
+ ```
93
+
94
+ ### System Inventory
95
+
96
+ ```ruby
97
+ # Get system information
98
+ info = client.system_info
99
+
100
+ # Get CPU information
101
+ cpus = client.cpus
102
+
103
+ # Get memory information
104
+ memory = client.memory
105
+
106
+ # Get storage summary
107
+ storage = client.storage_summary
108
+
109
+ # Get thermal information
110
+ fans = client.fans
111
+ temps = client.temperatures
112
+ ```
113
+
114
+ ### Virtual Media
115
+
116
+ ```ruby
117
+ # Check virtual media status
118
+ media = client.virtual_media_status
119
+
120
+ # Mount an ISO
121
+ client.insert_virtual_media("http://example.com/os.iso")
122
+
123
+ # Unmount all media
124
+ client.unmount_all_media
125
+
126
+ # Mount ISO and set boot override
127
+ client.mount_iso_and_boot("http://example.com/os.iso")
128
+ ```
129
+
130
+ ### Boot Configuration
131
+
132
+ ```ruby
133
+ # Get boot options
134
+ options = client.boot_options
135
+
136
+ # Set one-time boot override
137
+ client.set_boot_override("Pxe", persistent: false)
138
+
139
+ # Quick boot methods
140
+ client.boot_to_pxe
141
+ client.boot_to_disk
142
+ client.boot_to_cd
143
+ client.boot_to_bios_setup
144
+ ```
145
+
146
+ ### BIOS Configuration
147
+
148
+ ```ruby
149
+ # Get BIOS attributes
150
+ attrs = client.bios_attributes
151
+
152
+ # Set BIOS attribute
153
+ client.set_bios_attribute("QuietBoot", "Enabled")
154
+
155
+ # Reset BIOS to defaults
156
+ client.reset_bios_defaults
157
+ ```
158
+
159
+ ## Configuration Options
160
+
161
+ - `host`: BMC IP address or hostname
162
+ - `username`: BMC username
163
+ - `password`: BMC password
164
+ - `port`: BMC port (default: 443)
165
+ - `use_ssl`: Use HTTPS (default: true)
166
+ - `verify_ssl`: Verify SSL certificates (default: false)
167
+ - `direct_mode`: Use Basic Auth instead of sessions (default: false)
168
+ - `retry_count`: Number of retries for failed requests (default: 3)
169
+ - `retry_delay`: Initial delay between retries in seconds (default: 1)
170
+
171
+ ## Debugging
172
+
173
+ Enable verbose output:
174
+
175
+ ```ruby
176
+ client.verbosity = 1 # Basic debug output
177
+ client.verbosity = 2 # Include request/response details
178
+ client.verbosity = 3 # Include full stack traces
179
+ ```
180
+
181
+ ## Compatibility
182
+
183
+ Tested with:
184
+ - Supermicro BMC firmware version 01.04.08
185
+ - Redfish API version 1.11.0
186
+ - Ruby 3.0+
187
+
188
+ ## Differences from iDRAC
189
+
190
+ While the API is similar to the iDRAC gem, there are some Supermicro-specific differences:
191
+
192
+ 1. **URL Paths**: Supermicro uses numeric IDs (e.g., `/Systems/1`) instead of Dell's embedded names
193
+ 2. **Redirects**: Supermicro BMC redirects some paths to include trailing slashes
194
+ 3. **SEL Path**: System Event Log may be at different locations depending on firmware
195
+ 4. **Task Management**: Task/Job structure differs from Dell's implementation
196
+ 5. **Virtual Media**: Different action paths and supported media types
197
+
198
+ ## Testing
199
+
200
+ Run the test suite:
201
+
202
+ ```bash
203
+ bundle exec rspec
204
+ ```
205
+
206
+ Or with specific tests:
207
+
208
+ ```bash
209
+ bundle exec rspec spec/supermicro_spec.rb
210
+ ```
211
+
212
+ ## Development
213
+
214
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rspec` to run the tests.
215
+
216
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
217
+
218
+ ## Contributing
219
+
220
+ Bug reports and pull requests are welcome on GitHub at https://github.com/buildio/supermicro.
221
+
222
+ ## License
223
+
224
+ MIT
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'colorize'
5
+
6
+ module Supermicro
7
+ module Boot
8
+ def boot_options
9
+ response = authenticated_request(:get, "/redfish/v1/Systems/1")
10
+
11
+ if response.status == 200
12
+ begin
13
+ data = JSON.parse(response.body)
14
+
15
+ boot_info = data["Boot"] || {}
16
+
17
+ {
18
+ "boot_source_override_enabled" => boot_info["BootSourceOverrideEnabled"],
19
+ "boot_source_override_target" => boot_info["BootSourceOverrideTarget"],
20
+ "boot_source_override_mode" => boot_info["BootSourceOverrideMode"],
21
+ "allowed_targets" => boot_info["BootSourceOverrideTarget@Redfish.AllowableValues"],
22
+ "boot_options" => boot_info["BootOptions"],
23
+ "boot_order" => boot_info["BootOrder"],
24
+ "uefi_target" => boot_info["UefiTargetBootSourceOverride"]
25
+ }
26
+ rescue JSON::ParserError
27
+ raise Error, "Failed to parse boot options response: #{response.body}"
28
+ end
29
+ else
30
+ raise Error, "Failed to get boot options. Status code: #{response.status}"
31
+ end
32
+ end
33
+
34
+ def set_boot_override(target, persistence: nil, mode: nil, persistent: false)
35
+ valid_targets = boot_options["allowed_targets"]
36
+
37
+ unless valid_targets&.include?(target)
38
+ debug "Invalid boot target. Allowed values:"
39
+ valid_targets&.each { |t| debug " - #{t}" }
40
+ raise Error, "Invalid boot target: #{target}"
41
+ end
42
+
43
+ # Handle both old persistent parameter and new persistence parameter
44
+ enabled = if persistence
45
+ persistence # Use new parameter if provided
46
+ elsif persistent
47
+ "Continuous" # Legacy support
48
+ else
49
+ "Once" # Default
50
+ end
51
+
52
+ debug "Setting boot override to #{target} (#{enabled})..."
53
+
54
+ body = {
55
+ "Boot" => {
56
+ "BootSourceOverrideEnabled" => enabled,
57
+ "BootSourceOverrideTarget" => target
58
+ }
59
+ }
60
+
61
+ # Add boot mode if specified
62
+ if mode
63
+ body["Boot"]["BootSourceOverrideMode"] = mode
64
+ end
65
+
66
+ response = authenticated_request(
67
+ :patch,
68
+ "/redfish/v1/Systems/1",
69
+ body: body.to_json,
70
+ headers: { 'Content-Type': 'application/json' }
71
+ )
72
+
73
+ if response.status.between?(200, 299)
74
+ debug "Boot override set successfully."
75
+ return true
76
+ else
77
+ raise Error, "Failed to set boot override: #{response.status} - #{response.body}"
78
+ end
79
+ end
80
+
81
+ def configure_boot_settings(persistence: nil, mode: nil)
82
+ debug "Configuring boot settings..."
83
+
84
+ body = { "Boot" => {} }
85
+
86
+ if persistence
87
+ body["Boot"]["BootSourceOverrideEnabled"] = persistence
88
+ end
89
+
90
+ if mode
91
+ body["Boot"]["BootSourceOverrideMode"] = mode
92
+ end
93
+
94
+ return false if body["Boot"].empty?
95
+
96
+ response = authenticated_request(
97
+ :patch,
98
+ "/redfish/v1/Systems/1",
99
+ body: body.to_json,
100
+ headers: { 'Content-Type': 'application/json' }
101
+ )
102
+
103
+ if response.status.between?(200, 299)
104
+ debug "Boot settings configured successfully."
105
+ return true
106
+ else
107
+ raise Error, "Failed to configure boot settings: #{response.status} - #{response.body}"
108
+ end
109
+ end
110
+
111
+ def clear_boot_override
112
+ puts "Clearing boot override...".yellow
113
+
114
+ body = {
115
+ "Boot" => {
116
+ "BootSourceOverrideEnabled" => "Disabled"
117
+ }
118
+ }
119
+
120
+ response = authenticated_request(
121
+ :patch,
122
+ "/redfish/v1/Systems/1",
123
+ body: body.to_json,
124
+ headers: { 'Content-Type': 'application/json' }
125
+ )
126
+
127
+ if response.status.between?(200, 299)
128
+ puts "Boot override cleared successfully.".green
129
+ return true
130
+ else
131
+ raise Error, "Failed to clear boot override: #{response.status} - #{response.body}"
132
+ end
133
+ end
134
+
135
+ def set_boot_order(devices)
136
+ puts "Setting boot order...".yellow
137
+
138
+ body = {
139
+ "Boot" => {
140
+ "BootOrder" => devices
141
+ }
142
+ }
143
+
144
+ response = authenticated_request(
145
+ :patch,
146
+ "/redfish/v1/Systems/1",
147
+ body: body.to_json,
148
+ headers: { 'Content-Type': 'application/json' }
149
+ )
150
+
151
+ if response.status.between?(200, 299)
152
+ puts "Boot order set successfully.".green
153
+ return true
154
+ else
155
+ raise Error, "Failed to set boot order: #{response.status} - #{response.body}"
156
+ end
157
+ end
158
+
159
+ def get_boot_devices
160
+ response = authenticated_request(:get, "/redfish/v1/Systems/1/BootOptions?$expand=*($levels=1)")
161
+
162
+ if response.status == 200
163
+ begin
164
+ data = JSON.parse(response.body)
165
+
166
+ devices = data["Members"]&.map do |device|
167
+ {
168
+ "id" => device["Id"],
169
+ "name" => device["DisplayName"] || device["Name"],
170
+ "description" => device["Description"],
171
+ "boot_option_reference" => device["BootOptionReference"],
172
+ "enabled" => device["BootOptionEnabled"],
173
+ "uefi_device_path" => device["UefiDevicePath"]
174
+ }
175
+ end || []
176
+
177
+ return devices
178
+ rescue JSON::ParserError
179
+ raise Error, "Failed to parse boot devices response: #{response.body}"
180
+ end
181
+ else
182
+ []
183
+ end
184
+ end
185
+
186
+ def boot_to_pxe(persistence: nil, mode: nil)
187
+ set_boot_override("Pxe", persistence: persistence, mode: mode)
188
+ end
189
+
190
+ def boot_to_disk(persistence: nil, mode: nil)
191
+ set_boot_override("Hdd", persistence: persistence, mode: mode)
192
+ end
193
+
194
+ def boot_to_cd(persistence: nil, mode: nil)
195
+ set_boot_override("Cd", persistence: persistence, mode: mode)
196
+ end
197
+
198
+ def boot_to_usb(persistence: nil, mode: nil)
199
+ set_boot_override("Usb", persistence: persistence, mode: mode)
200
+ end
201
+
202
+ def boot_to_bios_setup(persistence: nil, mode: nil)
203
+ set_boot_override("BiosSetup", persistence: persistence, mode: mode)
204
+ end
205
+ end
206
+ end