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 +7 -0
- data/LICENSE +21 -0
- data/README.md +224 -0
- data/lib/supermicro/boot.rb +206 -0
- data/lib/supermicro/client.rb +420 -0
- data/lib/supermicro/error.rb +10 -0
- data/lib/supermicro/jobs.rb +179 -0
- data/lib/supermicro/license.rb +132 -0
- data/lib/supermicro/power.rb +169 -0
- data/lib/supermicro/session.rb +121 -0
- data/lib/supermicro/spinner.rb +179 -0
- data/lib/supermicro/storage.rb +180 -0
- data/lib/supermicro/system.rb +275 -0
- data/lib/supermicro/system_config.rb +201 -0
- data/lib/supermicro/tasks.rb +139 -0
- data/lib/supermicro/utility.rb +235 -0
- data/lib/supermicro/version.rb +5 -0
- data/lib/supermicro/virtual_media.rb +372 -0
- data/lib/supermicro.rb +55 -0
- data/supermicro.gemspec +41 -0
- metadata +193 -0
@@ -0,0 +1,372 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'colorize'
|
5
|
+
|
6
|
+
module Supermicro
|
7
|
+
module VirtualMedia
|
8
|
+
def virtual_media
|
9
|
+
response = authenticated_request(:get, "/redfish/v1/Managers/1/VirtualMedia")
|
10
|
+
|
11
|
+
if response.status == 200
|
12
|
+
begin
|
13
|
+
data = JSON.parse(response.body)
|
14
|
+
|
15
|
+
# Fetch each member individually since $expand doesn't work properly
|
16
|
+
media = data["Members"].map do |member|
|
17
|
+
member_path = member["@odata.id"]
|
18
|
+
member_response = authenticated_request(:get, member_path)
|
19
|
+
|
20
|
+
if member_response.status == 200
|
21
|
+
m = JSON.parse(member_response.body)
|
22
|
+
else
|
23
|
+
next nil
|
24
|
+
end
|
25
|
+
# Check if media is actually inserted (not just a dummy URL)
|
26
|
+
dummy_url = "http://0.0.0.0/dummy.iso"
|
27
|
+
has_real_image = !m["Image"].nil? && !m["Image"].empty? && m["Image"] != dummy_url
|
28
|
+
|
29
|
+
is_inserted = m["Inserted"] ||
|
30
|
+
has_real_image ||
|
31
|
+
(m["ConnectedVia"] && m["ConnectedVia"] != "NotConnected") ||
|
32
|
+
(m["ImageName"] && !m["ImageName"].empty?)
|
33
|
+
|
34
|
+
# Override: if it's the dummy URL, consider it not inserted
|
35
|
+
is_inserted = false if m["Image"] == dummy_url
|
36
|
+
|
37
|
+
# Show media status in debug mode
|
38
|
+
if is_inserted
|
39
|
+
debug "#{m["Name"] || m["Id"]} #{m["ConnectedVia"]} #{m["Image"] || m["ImageName"]}", 1, :green
|
40
|
+
else
|
41
|
+
debug "#{m["Name"] || m["Id"]} #{m["ConnectedVia"] || 'NotConnected'}", 1, :yellow
|
42
|
+
end
|
43
|
+
|
44
|
+
action_path = m.dig("Actions", "#VirtualMedia.InsertMedia", "target")
|
45
|
+
eject_path = m.dig("Actions", "#VirtualMedia.EjectMedia", "target")
|
46
|
+
|
47
|
+
# Use a more descriptive name if the API returns generic names
|
48
|
+
name = if m["Name"] == "Virtual Removable Media" && m["Id"]
|
49
|
+
"#{m["Name"]} (#{m["Id"]})"
|
50
|
+
else
|
51
|
+
m["Name"] || m["Id"]
|
52
|
+
end
|
53
|
+
|
54
|
+
{
|
55
|
+
device: m["Id"],
|
56
|
+
name: name,
|
57
|
+
inserted: is_inserted,
|
58
|
+
image: m["Image"] || m["ImageName"],
|
59
|
+
connected_via: m["ConnectedVia"],
|
60
|
+
media_types: m["MediaTypes"],
|
61
|
+
action_path: action_path,
|
62
|
+
eject_path: eject_path
|
63
|
+
}
|
64
|
+
end.compact # Remove any nil entries
|
65
|
+
|
66
|
+
return media
|
67
|
+
rescue JSON::ParserError
|
68
|
+
raise Error, "Failed to parse virtual media response: #{response.body}"
|
69
|
+
end
|
70
|
+
else
|
71
|
+
raise Error, "Failed to get virtual media. Status code: #{response.status}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def eject_virtual_media(device: nil)
|
76
|
+
media_list = virtual_media
|
77
|
+
|
78
|
+
if device
|
79
|
+
# Check for media with an image URL even if Inserted is false (Supermicro quirk)
|
80
|
+
media_to_eject = media_list.find { |m| m[:device] == device && (m[:inserted] || m[:image]) }
|
81
|
+
else
|
82
|
+
media_to_eject = media_list.find { |m| m[:inserted] || m[:image] }
|
83
|
+
end
|
84
|
+
|
85
|
+
if media_to_eject.nil?
|
86
|
+
debug "No media to eject#{device ? " for device #{device}" : ''}", 1, :yellow
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
|
90
|
+
debug "Ejecting #{media_to_eject[:name]} (#{media_to_eject[:image]})...", 1, :yellow
|
91
|
+
|
92
|
+
# Supermicro quirk: EjectMedia action may not be available when Inserted is false
|
93
|
+
# Try to use InsertMedia with Inserted:false to eject
|
94
|
+
path = if media_to_eject[:eject_path] && media_to_eject[:inserted]
|
95
|
+
media_to_eject[:eject_path]
|
96
|
+
elsif media_to_eject[:action_path]
|
97
|
+
# Use InsertMedia action to eject by setting Inserted to false
|
98
|
+
media_to_eject[:action_path]
|
99
|
+
else
|
100
|
+
"/redfish/v1/Managers/1/VirtualMedia/#{media_to_eject[:device]}/Actions/VirtualMedia.InsertMedia"
|
101
|
+
end
|
102
|
+
|
103
|
+
# For Supermicro, use InsertMedia with a dummy image and Inserted:false to eject
|
104
|
+
# Empty string doesn't work, so use a dummy URL
|
105
|
+
body = if path.include?("InsertMedia")
|
106
|
+
{
|
107
|
+
"Image" => "http://0.0.0.0/dummy.iso", # Dummy URL to clear the media
|
108
|
+
"Inserted" => false,
|
109
|
+
"TransferMethod" => "Stream"
|
110
|
+
}
|
111
|
+
else
|
112
|
+
{}
|
113
|
+
end
|
114
|
+
|
115
|
+
response = authenticated_request(
|
116
|
+
:post,
|
117
|
+
path,
|
118
|
+
body: body.to_json,
|
119
|
+
headers: { 'Content-Type': 'application/json' }
|
120
|
+
)
|
121
|
+
|
122
|
+
if response.status.between?(200, 299)
|
123
|
+
debug "Media ejected successfully.", 1, :green
|
124
|
+
return true
|
125
|
+
else
|
126
|
+
debug "Failed to eject media: #{response.status} - #{response.body}", 1, :red
|
127
|
+
return false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def insert_virtual_media(iso_url, device: nil)
|
132
|
+
# Check for license if mounting HTTP/HTTPS media
|
133
|
+
if iso_url.start_with?('http://', 'https://')
|
134
|
+
license_info = check_virtual_media_license
|
135
|
+
|
136
|
+
if license_info[:available] == false
|
137
|
+
raise Error, "Virtual media license required: #{license_info[:message]}"
|
138
|
+
elsif license_info[:available] == :unknown
|
139
|
+
debug "Warning: Unable to verify virtual media license. Mount may fail if license is missing.", 1, :yellow
|
140
|
+
debug "Supermicro requires SFT-OOB-LIC or SFT-DCMS-SINGLE for HTTP/HTTPS virtual media.", 1, :yellow
|
141
|
+
else
|
142
|
+
debug "Virtual media license verified: #{license_info[:licenses].join(', ')}", 2, :green
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
device ||= find_best_virtual_media_device
|
147
|
+
|
148
|
+
unless device
|
149
|
+
raise Error, "No suitable virtual media device found"
|
150
|
+
end
|
151
|
+
|
152
|
+
eject_virtual_media(device: device)
|
153
|
+
|
154
|
+
debug "Inserting media: #{iso_url} into #{device}...", 1, :yellow
|
155
|
+
|
156
|
+
tries = 0
|
157
|
+
max_tries = 3
|
158
|
+
|
159
|
+
while tries < max_tries
|
160
|
+
begin
|
161
|
+
media_info = virtual_media.find { |m| m[:device] == device }
|
162
|
+
|
163
|
+
unless media_info
|
164
|
+
raise Error, "Virtual media device #{device} not found"
|
165
|
+
end
|
166
|
+
|
167
|
+
path = if media_info[:action_path]
|
168
|
+
media_info[:action_path]
|
169
|
+
else
|
170
|
+
"/redfish/v1/Managers/1/VirtualMedia/#{device}/Actions/VirtualMedia.InsertMedia"
|
171
|
+
end
|
172
|
+
|
173
|
+
body = {
|
174
|
+
"Image" => iso_url,
|
175
|
+
"Inserted" => true,
|
176
|
+
"WriteProtected" => true,
|
177
|
+
"TransferMethod" => "Stream",
|
178
|
+
"TransferProtocolType" => iso_url.start_with?("https") ? "HTTPS" : "HTTP"
|
179
|
+
}
|
180
|
+
|
181
|
+
response = authenticated_request(
|
182
|
+
:post,
|
183
|
+
path,
|
184
|
+
body: body.to_json,
|
185
|
+
headers: { 'Content-Type': 'application/json' }
|
186
|
+
)
|
187
|
+
|
188
|
+
if response.status == 202
|
189
|
+
# Async operation - poll the task
|
190
|
+
debug "Virtual media insert is async, polling task...", 1, :yellow
|
191
|
+
|
192
|
+
task_result = wait_for_task_completion(response, timeout: 30)
|
193
|
+
|
194
|
+
if task_result[:success]
|
195
|
+
# Task completed, now verify the media is connected
|
196
|
+
if verbosity == 0
|
197
|
+
# Show spinner while verifying connection
|
198
|
+
spinner = Spinner.new("Verifying connection", type: :dots, color: :yellow)
|
199
|
+
spinner.start
|
200
|
+
else
|
201
|
+
debug "Task completed, verifying connection...", 1, :yellow
|
202
|
+
end
|
203
|
+
|
204
|
+
connected = false
|
205
|
+
5.times do |i|
|
206
|
+
sleep 1
|
207
|
+
current_media = virtual_media
|
208
|
+
inserted_media = current_media.find { |m| m[:device] == device }
|
209
|
+
|
210
|
+
if inserted_media
|
211
|
+
if verbosity == 0
|
212
|
+
spinner&.update("Checking connection: #{inserted_media[:connected_via]}")
|
213
|
+
else
|
214
|
+
debug " Status: ConnectedVia=#{inserted_media[:connected_via]}, Inserted=#{inserted_media[:inserted]}", 2
|
215
|
+
end
|
216
|
+
|
217
|
+
if inserted_media[:connected_via] == "URI" && inserted_media[:inserted]
|
218
|
+
spinner&.stop("Media connected via URI", success: true) if verbosity == 0
|
219
|
+
debug "✓ Media connected successfully via URI!", 1, :green
|
220
|
+
connected = true
|
221
|
+
break
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
spinner&.stop if spinner && verbosity == 0
|
227
|
+
|
228
|
+
if connected
|
229
|
+
return true
|
230
|
+
else
|
231
|
+
# Final check
|
232
|
+
current_media = virtual_media
|
233
|
+
inserted_media = current_media.find { |m| m[:device] == device }
|
234
|
+
if inserted_media && inserted_media[:image] == iso_url
|
235
|
+
if inserted_media[:connected_via] == "NotConnected"
|
236
|
+
debug "ERROR: Media mounted but NOT CONNECTED!", 1, :red
|
237
|
+
debug "The ISO will NOT boot! ConnectedVia must be 'URI', not 'NotConnected'.", 1, :red
|
238
|
+
return false
|
239
|
+
else
|
240
|
+
debug "Media mounted with status: #{inserted_media[:connected_via]}", 1, :green
|
241
|
+
return true
|
242
|
+
end
|
243
|
+
else
|
244
|
+
debug "Failed to verify media mount.", 1, :red
|
245
|
+
return false
|
246
|
+
end
|
247
|
+
end
|
248
|
+
else
|
249
|
+
debug "Task failed or timed out", 1, :red
|
250
|
+
return false
|
251
|
+
end
|
252
|
+
elsif response.status.between?(200, 299)
|
253
|
+
# Synchronous success (rare)
|
254
|
+
debug "Virtual media inserted synchronously.", 1, :green
|
255
|
+
sleep 2
|
256
|
+
current_media = virtual_media
|
257
|
+
inserted_media = current_media.find { |m| m[:device] == device }
|
258
|
+
|
259
|
+
if inserted_media && (inserted_media[:inserted] || inserted_media[:image] == iso_url)
|
260
|
+
if inserted_media[:connected_via] == "URI"
|
261
|
+
debug "✓ Media connected via URI", 1, :green
|
262
|
+
return true
|
263
|
+
elsif inserted_media[:connected_via] == "NotConnected"
|
264
|
+
debug "WARNING: Media mounted but not connected!", 1, :red
|
265
|
+
return false
|
266
|
+
else
|
267
|
+
debug "Media mounted with status: #{inserted_media[:connected_via]}", 1, :yellow
|
268
|
+
return true
|
269
|
+
end
|
270
|
+
else
|
271
|
+
debug "Could not verify media mount", 1, :yellow
|
272
|
+
return true
|
273
|
+
end
|
274
|
+
elsif response.status == 400 && response.body.include?("already")
|
275
|
+
debug "Media already inserted, ejecting and retrying...", 1, :yellow
|
276
|
+
eject_virtual_media(device: device)
|
277
|
+
sleep 2
|
278
|
+
tries += 1
|
279
|
+
else
|
280
|
+
debug "Failed to insert media: #{response.status} - #{response.body}", 1, :red
|
281
|
+
tries += 1
|
282
|
+
sleep 2
|
283
|
+
end
|
284
|
+
rescue => e
|
285
|
+
debug "Error inserting media: #{e.message}", 1, :red
|
286
|
+
tries += 1
|
287
|
+
sleep 2
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
raise Error, "Failed to insert virtual media after #{max_tries} attempts"
|
292
|
+
end
|
293
|
+
|
294
|
+
def find_best_virtual_media_device
|
295
|
+
media_list = virtual_media
|
296
|
+
|
297
|
+
cd_device = media_list.find { |m|
|
298
|
+
m[:media_types]&.include?("CD") || m[:media_types]&.include?("DVD") ||
|
299
|
+
m[:name]&.downcase&.include?("cd") || m[:device]&.downcase&.include?("cd")
|
300
|
+
}
|
301
|
+
|
302
|
+
return cd_device[:device] if cd_device
|
303
|
+
|
304
|
+
removable = media_list.find { |m|
|
305
|
+
m[:media_types]&.include?("Removable") ||
|
306
|
+
m[:name]&.downcase&.include?("removable")
|
307
|
+
}
|
308
|
+
|
309
|
+
return removable[:device] if removable
|
310
|
+
|
311
|
+
media_list.first&.dig(:device)
|
312
|
+
end
|
313
|
+
|
314
|
+
def virtual_media_status
|
315
|
+
media_list = virtual_media
|
316
|
+
|
317
|
+
debug "\n=== Virtual Media Status ===", 1, :green
|
318
|
+
|
319
|
+
media_list.each do |media|
|
320
|
+
debug "\nDevice: #{media[:name]} (#{media[:device]})", 1, :cyan
|
321
|
+
debug " Media Types: #{media[:media_types]&.join(', ')}", 1 if media[:media_types]
|
322
|
+
debug " Inserted: #{media[:inserted] ? 'Yes'.green : 'No'.yellow}", 1
|
323
|
+
debug " Image: #{media[:image]}", 1 if media[:image]
|
324
|
+
debug " Connected Via: #{media[:connected_via]}", 1 if media[:connected_via]
|
325
|
+
end
|
326
|
+
|
327
|
+
media_list
|
328
|
+
end
|
329
|
+
|
330
|
+
def mount_iso_and_boot(iso_url, device: nil)
|
331
|
+
debug "Mounting ISO and setting boot override...", 1, :yellow
|
332
|
+
|
333
|
+
insert_virtual_media(iso_url, device: device)
|
334
|
+
|
335
|
+
sleep 2
|
336
|
+
|
337
|
+
begin
|
338
|
+
require_relative 'boot'
|
339
|
+
boot_to_cd
|
340
|
+
debug "System will boot from virtual media on next restart.", 1, :green
|
341
|
+
return true
|
342
|
+
rescue => e
|
343
|
+
debug "ISO mounted but failed to set boot override: #{e.message}", 1, :yellow
|
344
|
+
return false
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def unmount_all_media
|
349
|
+
debug "Unmounting all virtual media...", 1, :yellow
|
350
|
+
|
351
|
+
media_list = virtual_media
|
352
|
+
mounted = media_list.select { |m| m[:inserted] }
|
353
|
+
|
354
|
+
if mounted.empty?
|
355
|
+
debug "No virtual media currently mounted.", 1, :yellow
|
356
|
+
return true
|
357
|
+
end
|
358
|
+
|
359
|
+
success = true
|
360
|
+
mounted.each do |media|
|
361
|
+
if eject_virtual_media(device: media[:device])
|
362
|
+
debug " Ejected: #{media[:name]}", 1, :green
|
363
|
+
else
|
364
|
+
debug " Failed to eject: #{media[:name]}", 1, :red
|
365
|
+
success = false
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
success
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
data/lib/supermicro.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'faraday'
|
6
|
+
require 'faraday/multipart'
|
7
|
+
require 'base64'
|
8
|
+
require 'uri'
|
9
|
+
require 'colorize'
|
10
|
+
require 'active_support'
|
11
|
+
require 'active_support/core_ext'
|
12
|
+
require 'debug' if ENV['RUBY_ENV'] == 'development'
|
13
|
+
|
14
|
+
module Supermicro
|
15
|
+
module Debuggable
|
16
|
+
def debug(message, level = 1, color = :light_cyan)
|
17
|
+
return unless respond_to?(:verbosity) && verbosity >= level
|
18
|
+
color_method = color.is_a?(Symbol) && String.method_defined?(color) ? color : :to_s
|
19
|
+
puts message.send(color_method)
|
20
|
+
|
21
|
+
if respond_to?(:verbosity) && verbosity >= 3 && caller.length > 1
|
22
|
+
puts " Called from:".light_yellow
|
23
|
+
caller[1..3].each do |call|
|
24
|
+
puts " #{call}".light_yellow
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Error < StandardError; end
|
31
|
+
|
32
|
+
def self.new(options = {})
|
33
|
+
Client.new(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.connect(**options, &block)
|
37
|
+
Client.connect(**options, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'supermicro/version'
|
42
|
+
require 'supermicro/error'
|
43
|
+
require 'supermicro/session'
|
44
|
+
require 'supermicro/spinner'
|
45
|
+
require 'supermicro/power'
|
46
|
+
require 'supermicro/jobs'
|
47
|
+
require 'supermicro/storage'
|
48
|
+
require 'supermicro/system'
|
49
|
+
require 'supermicro/tasks'
|
50
|
+
require 'supermicro/virtual_media'
|
51
|
+
require 'supermicro/boot'
|
52
|
+
require 'supermicro/system_config'
|
53
|
+
require 'supermicro/utility'
|
54
|
+
require 'supermicro/license'
|
55
|
+
require 'supermicro/client'
|
data/supermicro.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/supermicro/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "supermicro"
|
7
|
+
spec.version = Supermicro::VERSION
|
8
|
+
spec.authors = ["Jonathan Siegel"]
|
9
|
+
spec.email = ["248302+usiegj00@users.noreply.github.com"]
|
10
|
+
|
11
|
+
spec.summary = "API Client for Supermicro BMC"
|
12
|
+
spec.description = "A Ruby client for the Supermicro BMC Redfish API with support for power management, virtual media, and system configuration"
|
13
|
+
spec.homepage = "https://github.com/buildio/supermicro"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
16
|
+
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
|
+
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/buildio/supermicro"
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/buildio/supermicro/blob/main/CHANGELOG.md"
|
22
|
+
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
Dir["{lib}/**/*", "LICENSE", "README.md", "*.gemspec"]
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_dependency "httparty", "~> 0.21"
|
32
|
+
spec.add_dependency "faraday", "~> 2.0"
|
33
|
+
spec.add_dependency "faraday-multipart", "~> 1.0"
|
34
|
+
spec.add_dependency "nokogiri", "~> 1.14"
|
35
|
+
spec.add_dependency "colorize", "~> 0.8"
|
36
|
+
spec.add_dependency "activesupport", "~> 7.0"
|
37
|
+
|
38
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
39
|
+
spec.add_development_dependency "webmock", "~> 3.0"
|
40
|
+
spec.add_development_dependency "debug", "~> 1.0"
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: supermicro
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Siegel
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-08-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.21'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.21'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday-multipart
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: nokogiri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.14'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.14'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: colorize
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.8'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '7.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '7.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: debug
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.0'
|
139
|
+
description: A Ruby client for the Supermicro BMC Redfish API with support for power
|
140
|
+
management, virtual media, and system configuration
|
141
|
+
email:
|
142
|
+
- 248302+usiegj00@users.noreply.github.com
|
143
|
+
executables: []
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- LICENSE
|
148
|
+
- README.md
|
149
|
+
- lib/supermicro.rb
|
150
|
+
- lib/supermicro/boot.rb
|
151
|
+
- lib/supermicro/client.rb
|
152
|
+
- lib/supermicro/error.rb
|
153
|
+
- lib/supermicro/jobs.rb
|
154
|
+
- lib/supermicro/license.rb
|
155
|
+
- lib/supermicro/power.rb
|
156
|
+
- lib/supermicro/session.rb
|
157
|
+
- lib/supermicro/spinner.rb
|
158
|
+
- lib/supermicro/storage.rb
|
159
|
+
- lib/supermicro/system.rb
|
160
|
+
- lib/supermicro/system_config.rb
|
161
|
+
- lib/supermicro/tasks.rb
|
162
|
+
- lib/supermicro/utility.rb
|
163
|
+
- lib/supermicro/version.rb
|
164
|
+
- lib/supermicro/virtual_media.rb
|
165
|
+
- supermicro.gemspec
|
166
|
+
homepage: https://github.com/buildio/supermicro
|
167
|
+
licenses:
|
168
|
+
- MIT
|
169
|
+
metadata:
|
170
|
+
allowed_push_host: https://rubygems.org
|
171
|
+
homepage_uri: https://github.com/buildio/supermicro
|
172
|
+
source_code_uri: https://github.com/buildio/supermicro
|
173
|
+
changelog_uri: https://github.com/buildio/supermicro/blob/main/CHANGELOG.md
|
174
|
+
post_install_message:
|
175
|
+
rdoc_options: []
|
176
|
+
require_paths:
|
177
|
+
- lib
|
178
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 2.7.0
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
requirements: []
|
189
|
+
rubygems_version: 3.3.26
|
190
|
+
signing_key:
|
191
|
+
specification_version: 4
|
192
|
+
summary: API Client for Supermicro BMC
|
193
|
+
test_files: []
|