idrac 0.9.0 → 0.9.4
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 +7 -0
- data/lib/idrac/boot.rb +11 -18
- data/lib/idrac/client.rb +12 -7
- data/lib/idrac/firmware.rb +2 -6
- data/lib/idrac/jobs.rb +5 -7
- data/lib/idrac/license.rb +91 -316
- data/lib/idrac/lifecycle.rb +5 -7
- data/lib/idrac/network.rb +2 -4
- data/lib/idrac/power.rb +14 -23
- data/lib/idrac/session.rb +28 -31
- data/lib/idrac/storage.rb +10 -23
- data/lib/idrac/system.rb +2 -3
- data/lib/idrac/system_config.rb +7 -10
- data/lib/idrac/utility.rb +4 -8
- data/lib/idrac/version.rb +1 -1
- data/lib/idrac/virtual_media.rb +8 -13
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54237d0e5e104838b8770088791b1896b11928d0092572035ee05117de1d6733
|
|
4
|
+
data.tar.gz: 802a048dcf46d8d9a1eab4626be4425269ee58d0012b61f1ac167b44a8b1def9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95ff7c2f6e83194632b4ceb9febd251f01332f39271c02bfc2e0f35e677159b873b7ff74a8906f5b293af855aa2fb3f69ed4e73242be8ca704f6346da507c9a8
|
|
7
|
+
data.tar.gz: 94f8e2b5ab66ff0cf428bdb1903d3ba3d38d9b3e2002323e36a866ffb4461ae22a2766861550d4daf0fe74b274e2991ef9280fd9732581af9d0b86d3209b7047
|
data/README.md
CHANGED
|
@@ -291,6 +291,13 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
291
291
|
|
|
292
292
|
## Changelog
|
|
293
293
|
|
|
294
|
+
### Version 0.9.1
|
|
295
|
+
- **Code Simplification**: Removed redundant `handle_response` calls throughout the codebase
|
|
296
|
+
- `authenticated_request` now automatically handles error responses (status >= 400)
|
|
297
|
+
- Removed 15 lines of redundant error handling code across storage.rb, power.rb, and virtual_media.rb
|
|
298
|
+
- Simplified response parsing in `get_power_state` and `get_power_usage_watts` methods
|
|
299
|
+
- Improved code maintainability by relying on centralized error handling
|
|
300
|
+
|
|
294
301
|
### Version 0.9.0
|
|
295
302
|
- **Automatic Retry Handling**: ServiceTemporarilyUnavailable (503) errors now automatically retry with iDRAC-specified delay
|
|
296
303
|
- **Simplified API**: `authenticated_request` now returns response body string by default instead of response object
|
data/lib/idrac/boot.rb
CHANGED
|
@@ -165,8 +165,7 @@ module IDRAC
|
|
|
165
165
|
response = authenticated_request(
|
|
166
166
|
:patch,
|
|
167
167
|
"/redfish/v1/Systems/System.Embedded.1",
|
|
168
|
-
body: body.to_json
|
|
169
|
-
headers: { 'Content-Type': 'application/json' }
|
|
168
|
+
body: body.to_json
|
|
170
169
|
)
|
|
171
170
|
|
|
172
171
|
if response.status.between?(200, 299)
|
|
@@ -190,8 +189,7 @@ module IDRAC
|
|
|
190
189
|
response = authenticated_request(
|
|
191
190
|
:patch,
|
|
192
191
|
"/redfish/v1/Systems/System.Embedded.1",
|
|
193
|
-
body: body.to_json
|
|
194
|
-
headers: { 'Content-Type': 'application/json' }
|
|
192
|
+
body: body.to_json
|
|
195
193
|
)
|
|
196
194
|
|
|
197
195
|
if response.status.between?(200, 299)
|
|
@@ -215,8 +213,7 @@ module IDRAC
|
|
|
215
213
|
response = authenticated_request(
|
|
216
214
|
:patch,
|
|
217
215
|
"/redfish/v1/Systems/System.Embedded.1",
|
|
218
|
-
body: body.to_json
|
|
219
|
-
headers: { 'Content-Type': 'application/json' }
|
|
216
|
+
body: body.to_json
|
|
220
217
|
)
|
|
221
218
|
|
|
222
219
|
if response.status.between?(200, 299)
|
|
@@ -312,10 +309,9 @@ module IDRAC
|
|
|
312
309
|
end
|
|
313
310
|
|
|
314
311
|
response = authenticated_request(
|
|
315
|
-
:patch,
|
|
312
|
+
:patch,
|
|
316
313
|
"/redfish/v1/Systems/System.Embedded.1/Bios/Settings",
|
|
317
|
-
body: payload.to_json
|
|
318
|
-
headers: { 'Content-Type': 'application/json' }
|
|
314
|
+
body: payload.to_json
|
|
319
315
|
)
|
|
320
316
|
|
|
321
317
|
wait_for_job(response.headers["location"])
|
|
@@ -396,10 +392,9 @@ module IDRAC
|
|
|
396
392
|
|
|
397
393
|
# Set boot order
|
|
398
394
|
response = authenticated_request(
|
|
399
|
-
:patch,
|
|
395
|
+
:patch,
|
|
400
396
|
"/redfish/v1/Systems/System.Embedded.1",
|
|
401
|
-
body: { "Boot": { "BootOrder": [boot_id] } }.to_json
|
|
402
|
-
headers: { 'Content-Type': 'application/json' }
|
|
397
|
+
body: { "Boot": { "BootOrder": [boot_id] } }.to_json
|
|
403
398
|
)
|
|
404
399
|
|
|
405
400
|
if response.status.between?(200, 299)
|
|
@@ -495,10 +490,9 @@ module IDRAC
|
|
|
495
490
|
# Configure BIOS settings
|
|
496
491
|
def configure_bios_settings(settings)
|
|
497
492
|
response = authenticated_request(
|
|
498
|
-
:patch,
|
|
493
|
+
:patch,
|
|
499
494
|
"/redfish/v1/Systems/System.Embedded.1/Bios/Settings",
|
|
500
|
-
body: { "Attributes": settings }.to_json
|
|
501
|
-
headers: { 'Content-Type': 'application/json' }
|
|
495
|
+
body: { "Attributes": settings }.to_json
|
|
502
496
|
)
|
|
503
497
|
|
|
504
498
|
if response.status.between?(200, 299)
|
|
@@ -676,10 +670,9 @@ module IDRAC
|
|
|
676
670
|
params["HostPowerState"] = reboot ? "On" : "Off"
|
|
677
671
|
|
|
678
672
|
response = authenticated_request(
|
|
679
|
-
:post,
|
|
673
|
+
:post,
|
|
680
674
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ImportSystemConfiguration",
|
|
681
|
-
body: params.to_json
|
|
682
|
-
headers: { 'Content-Type': 'application/json' }
|
|
675
|
+
body: params.to_json
|
|
683
676
|
)
|
|
684
677
|
|
|
685
678
|
task = wait_for_task(response.headers["location"])
|
data/lib/idrac/client.rb
CHANGED
|
@@ -86,14 +86,14 @@ module IDRAC
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
def authenticated?
|
|
90
|
+
@direct_mode || session.x_auth_token
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Login to iDRAC (no-op if already authenticated)
|
|
90
94
|
def login
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
debug "Using direct mode (Basic Auth) for all requests", 1, :light_yellow
|
|
94
|
-
return true
|
|
95
|
-
end
|
|
96
|
-
|
|
95
|
+
return true if authenticated?
|
|
96
|
+
|
|
97
97
|
# Try to create a Redfish session
|
|
98
98
|
if session.create
|
|
99
99
|
debug "Successfully logged in to iDRAC using Redfish session", 1, :green
|
|
@@ -105,6 +105,11 @@ module IDRAC
|
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
+
# Ensure we're authenticated before making requests (idempotent)
|
|
109
|
+
def ensure_authenticated!
|
|
110
|
+
login unless authenticated?
|
|
111
|
+
end
|
|
112
|
+
|
|
108
113
|
# Logout from iDRAC
|
|
109
114
|
def logout
|
|
110
115
|
session.delete if session.x_auth_token
|
data/lib/idrac/firmware.rb
CHANGED
|
@@ -30,8 +30,7 @@ module IDRAC
|
|
|
30
30
|
# Ensure we have a client
|
|
31
31
|
raise Error, "Client is required for firmware update" unless client
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
client.login unless client.instance_variable_get(:@session_id)
|
|
33
|
+
client.ensure_authenticated!
|
|
35
34
|
|
|
36
35
|
# Upload firmware file
|
|
37
36
|
job_id = upload_firmware(firmware_path)
|
|
@@ -563,10 +562,7 @@ module IDRAC
|
|
|
563
562
|
update_response = client.authenticated_request(
|
|
564
563
|
:post,
|
|
565
564
|
"/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
|
|
566
|
-
|
|
567
|
-
headers: { 'Content-Type' => 'application/json' },
|
|
568
|
-
body: simple_update_payload.to_json
|
|
569
|
-
}
|
|
565
|
+
body: simple_update_payload.to_json
|
|
570
566
|
)
|
|
571
567
|
|
|
572
568
|
if update_response.status != 202 && update_response.status != 200
|
data/lib/idrac/jobs.rb
CHANGED
|
@@ -75,10 +75,9 @@ module IDRAC
|
|
|
75
75
|
payload = { "JobID" => "JID_CLEARALL_FORCE" }
|
|
76
76
|
|
|
77
77
|
response = authenticated_request(
|
|
78
|
-
:post,
|
|
79
|
-
path,
|
|
80
|
-
body: payload.to_json
|
|
81
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
78
|
+
:post,
|
|
79
|
+
path,
|
|
80
|
+
body: payload.to_json
|
|
82
81
|
)
|
|
83
82
|
|
|
84
83
|
if response.status.between?(200, 299)
|
|
@@ -90,10 +89,9 @@ module IDRAC
|
|
|
90
89
|
retries = 60 # ~10 minutes with 10s sleep
|
|
91
90
|
while retries > 0
|
|
92
91
|
lc_response = authenticated_request(
|
|
93
|
-
:post,
|
|
92
|
+
:post,
|
|
94
93
|
'/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.GetRemoteServicesAPIStatus',
|
|
95
|
-
body: {}.to_json
|
|
96
|
-
headers: { 'Content-Type': 'application/json' }
|
|
94
|
+
body: {}.to_json
|
|
97
95
|
)
|
|
98
96
|
|
|
99
97
|
if lc_response.status.between?(200, 299)
|
data/lib/idrac/license.rb
CHANGED
|
@@ -1,359 +1,134 @@
|
|
|
1
1
|
module IDRAC
|
|
2
2
|
module License
|
|
3
3
|
# Gets the license information from the iDRAC
|
|
4
|
-
# @return [Hash] License details
|
|
4
|
+
# @return [Hash, nil] License details
|
|
5
5
|
def license_info
|
|
6
|
-
# Try
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
debug "License collection: #{license_data}", 2
|
|
12
|
-
|
|
13
|
-
# Check if there are any license entries
|
|
14
|
-
if !license_data["Members"] || license_data["Members"].empty?
|
|
15
|
-
debug "No licenses found", 1, :yellow
|
|
16
|
-
return try_dell_oem_license_path()
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Get the first license in the list
|
|
20
|
-
license_uri = license_data["Members"][0]["@odata.id"]
|
|
21
|
-
debug "Using license URI: #{license_uri}", 2
|
|
22
|
-
|
|
23
|
-
# Get detailed license information
|
|
24
|
-
license_response = authenticated_request(:get, license_uri)
|
|
25
|
-
if license_response.status != 200
|
|
26
|
-
debug "Failed to retrieve license details: #{license_response.status}", 1, :red
|
|
27
|
-
return try_dell_oem_license_path()
|
|
6
|
+
# Try standard endpoint first (iDRAC 9+)
|
|
7
|
+
if (data = safe_get("/redfish/v1/LicenseService/Licenses"))
|
|
8
|
+
if data["Members"]&.any?
|
|
9
|
+
license_uri = data["Members"][0]["@odata.id"]
|
|
10
|
+
return safe_get(license_uri) || try_dell_oem_license_path
|
|
28
11
|
end
|
|
29
|
-
|
|
30
|
-
license_details = JSON.parse(license_response.body)
|
|
31
|
-
debug "License details: #{license_details}", 2
|
|
32
|
-
|
|
33
|
-
return license_details
|
|
34
|
-
else
|
|
35
|
-
# The endpoint is not available (probably iDRAC 8)
|
|
36
|
-
debug "Standard license endpoint failed: #{response.status}, trying Dell OEM path", 1, :yellow
|
|
37
|
-
return try_dell_oem_license_path()
|
|
38
12
|
end
|
|
13
|
+
|
|
14
|
+
try_dell_oem_license_path
|
|
39
15
|
end
|
|
40
16
|
|
|
41
|
-
# Extracts the iDRAC
|
|
42
|
-
# @return [Integer, nil]
|
|
17
|
+
# Extracts the iDRAC generation (e.g. 8, 9) from license or server header
|
|
18
|
+
# @return [Integer, nil]
|
|
43
19
|
def license_version
|
|
44
|
-
# Use memoization to cache the result and avoid multiple API calls
|
|
45
20
|
@license_version ||= compute_license_version
|
|
46
21
|
end
|
|
47
|
-
|
|
48
|
-
# Clear the cached license version (useful if iDRAC state changes)
|
|
22
|
+
|
|
49
23
|
def clear_license_version_cache
|
|
50
24
|
@license_version = nil
|
|
51
25
|
end
|
|
52
|
-
|
|
26
|
+
|
|
53
27
|
private
|
|
54
|
-
|
|
28
|
+
|
|
29
|
+
# GET that returns parsed JSON on 200, nil otherwise. Never raises on 4xx.
|
|
30
|
+
def safe_get(path)
|
|
31
|
+
response = authenticated_request(:get, path) { |r| r }
|
|
32
|
+
return nil unless response.status == 200
|
|
33
|
+
JSON.parse(response.body)
|
|
34
|
+
rescue JSON::ParserError
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
55
38
|
def compute_license_version
|
|
56
|
-
# First try to get from license info
|
|
57
39
|
license = license_info
|
|
58
40
|
if license
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
debug "Found license version from Description: #{version}", 1
|
|
64
|
-
return version
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Try alternative fields if Description didn't work
|
|
68
|
-
if license["Name"]&.match(/iDRAC(\d+)/i)
|
|
69
|
-
version = license["Name"].match(/iDRAC(\d+)/i)[1].to_i
|
|
70
|
-
debug "Found license version from Name: #{version}", 1
|
|
71
|
-
return version
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# For Dell OEM license response format
|
|
75
|
-
if license["LicenseDescription"]&.match(/iDRAC(\d+)/i)
|
|
76
|
-
version = license["LicenseDescription"].match(/iDRAC(\d+)/i)[1].to_i
|
|
77
|
-
debug "Found license version from LicenseDescription: #{version}", 1
|
|
78
|
-
return version
|
|
41
|
+
%w[Description Name LicenseDescription].each do |field|
|
|
42
|
+
if license[field]&.match(/iDRAC(\d+)/i)
|
|
43
|
+
return $1.to_i
|
|
44
|
+
end
|
|
79
45
|
end
|
|
80
46
|
end
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
response
|
|
85
|
-
|
|
86
|
-
version = response.headers["server"].match(/iDRAC\/(\d+)/i)[1].to_i
|
|
87
|
-
debug "Found license version from server header: #{version}", 1
|
|
88
|
-
return version
|
|
47
|
+
|
|
48
|
+
# Fall back to server header
|
|
49
|
+
response = authenticated_request(:get, "/redfish/v1") { |r| r }
|
|
50
|
+
if response.headers["server"]&.match(/iDRAC\/(\d+)/i)
|
|
51
|
+
return $1.to_i
|
|
89
52
|
end
|
|
90
|
-
|
|
91
|
-
debug "Could not determine license version from license info or server header", 1, :yellow
|
|
53
|
+
|
|
92
54
|
nil
|
|
93
55
|
end
|
|
94
|
-
|
|
95
|
-
# Attempt to get license information using Dell OEM extension path (for iDRAC 8)
|
|
96
|
-
# @return [Hash, nil] License info or nil if not found
|
|
56
|
+
|
|
97
57
|
def try_dell_oem_license_path
|
|
98
|
-
# Try
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# Check for license info in this response based on the path
|
|
113
|
-
if path.include?("DellLicenseManagementService")
|
|
114
|
-
return handle_dell_license_service_response(data)
|
|
115
|
-
elsif path.include?("Attributes")
|
|
116
|
-
return handle_dell_attributes_response(data)
|
|
117
|
-
elsif path.include?("iDRAC.Embedded.1") && !path.include?("Attributes")
|
|
118
|
-
return handle_dell_manager_response(data)
|
|
58
|
+
# Try Dell OEM license service (iDRAC 8)
|
|
59
|
+
if (data = safe_get("/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLicenseManagementService/Licenses"))
|
|
60
|
+
if data["Members"]&.any?
|
|
61
|
+
license_uri = data["Members"][0]["@odata.id"]
|
|
62
|
+
if (details = safe_get(license_uri))
|
|
63
|
+
return {
|
|
64
|
+
"Id" => details["EntitlementID"] || "iDRAC-License",
|
|
65
|
+
"Description" => details["LicenseDescription"] || "iDRAC License",
|
|
66
|
+
"Name" => details["LicenseDescription"] || "iDRAC License",
|
|
67
|
+
"LicenseType" => details["LicenseType"] || license_type_from(details["LicenseDescription"]),
|
|
68
|
+
"Status" => { "Health" => "OK" },
|
|
69
|
+
"Removable" => true
|
|
70
|
+
}
|
|
119
71
|
end
|
|
120
|
-
else
|
|
121
|
-
debug "Dell path #{path} response status: #{response.status}", 3
|
|
122
72
|
end
|
|
123
73
|
end
|
|
124
|
-
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
"Id" => "iDRAC-License",
|
|
132
|
-
"Description" => "iDRAC8 #{license_type} License",
|
|
133
|
-
"Name" => "iDRAC License",
|
|
134
|
-
"LicenseType" => license_type,
|
|
135
|
-
"Status" => { "Health" => "OK" },
|
|
136
|
-
"Removable" => false,
|
|
137
|
-
"EntitlementID" => service_tag # Dell often uses service tag as entitlement ID
|
|
138
|
-
}
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Fall back to feature detection if all else fails
|
|
142
|
-
debug "All Dell OEM license paths failed, using fallback detection", 1, :yellow
|
|
143
|
-
return create_fallback_license_info()
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# Handle response from Dell License Management Service
|
|
147
|
-
def handle_dell_license_service_response(data)
|
|
148
|
-
# Check if there are any license entries
|
|
149
|
-
if !data["Members"] || data["Members"].empty?
|
|
150
|
-
debug "No licenses found in Dell OEM path", 1, :yellow
|
|
151
|
-
return create_fallback_license_info(use_basic: true)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# Get the first license in the list
|
|
155
|
-
license_uri = data["Members"][0]["@odata.id"]
|
|
156
|
-
debug "Using Dell OEM license URI: #{license_uri}", 2
|
|
157
|
-
|
|
158
|
-
# Get detailed license information
|
|
159
|
-
license_response = authenticated_request(:get, license_uri)
|
|
160
|
-
if license_response.status != 200
|
|
161
|
-
debug "Failed to retrieve Dell OEM license details: #{license_response.status}", 1, :red
|
|
162
|
-
return create_fallback_license_info(use_basic: true)
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
dell_license = JSON.parse(license_response.body)
|
|
166
|
-
debug "Dell OEM license details: #{dell_license}", 2
|
|
167
|
-
|
|
168
|
-
# Convert Dell OEM license format to standard format
|
|
169
|
-
license_info = {
|
|
170
|
-
"Id" => dell_license["EntitlementID"] || "iDRAC-License",
|
|
171
|
-
"Description" => dell_license["LicenseDescription"] || "iDRAC License",
|
|
172
|
-
"Name" => dell_license["LicenseDescription"] || "iDRAC License",
|
|
173
|
-
"LicenseType" => dell_license["LicenseType"] || get_license_type_from_description(dell_license["LicenseDescription"]),
|
|
174
|
-
"Status" => { "Health" => "OK" },
|
|
175
|
-
"Removable" => true
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return license_info
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# Handle response from Dell Manager attributes
|
|
182
|
-
def handle_dell_attributes_response(data)
|
|
183
|
-
# Look for license information in attributes
|
|
184
|
-
if data["Attributes"] && (
|
|
185
|
-
data["Attributes"]["LicensableDevice.1.LicenseInfo.1"] ||
|
|
186
|
-
data["Attributes"]["System.ServerOS.1.OSName"] ||
|
|
187
|
-
data["Attributes"]["iDRAC.Info.1.LicensingInfo"]
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
license_info = data["Attributes"]["LicensableDevice.1.LicenseInfo.1"] ||
|
|
191
|
-
data["Attributes"]["iDRAC.Info.1.LicensingInfo"]
|
|
192
|
-
|
|
193
|
-
if license_info
|
|
194
|
-
license_type = license_info.include?("Enterprise") ? "Enterprise" :
|
|
195
|
-
license_info.include?("Express") ? "Express" : "Basic"
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
"Id" => "iDRAC-License",
|
|
199
|
-
"Description" => "iDRAC8 #{license_type} License",
|
|
200
|
-
"Name" => "iDRAC License",
|
|
201
|
-
"LicenseType" => license_type,
|
|
202
|
-
"Status" => { "Health" => "OK" },
|
|
203
|
-
"Removable" => false
|
|
204
|
-
}
|
|
205
|
-
end
|
|
74
|
+
|
|
75
|
+
# Try manager attributes
|
|
76
|
+
if (data = safe_get("/redfish/v1/Managers/iDRAC.Embedded.1/Attributes"))
|
|
77
|
+
attr = data.dig("Attributes", "LicensableDevice.1.LicenseInfo.1") ||
|
|
78
|
+
data.dig("Attributes", "iDRAC.Info.1.LicensingInfo")
|
|
79
|
+
return build_license_hash(license_type_from(attr)) if attr
|
|
206
80
|
end
|
|
207
|
-
|
|
208
|
-
#
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
# Look for license information in Oem data
|
|
223
|
-
if data["Oem"] && data["Oem"]["Dell"]
|
|
224
|
-
dell_data = data["Oem"]["Dell"]
|
|
225
|
-
|
|
226
|
-
if dell_data["DellLicenseManagementService"]
|
|
227
|
-
# Found license service reference, but need to query it directly
|
|
228
|
-
service_uri = dell_data["DellLicenseManagementService"]["@odata.id"]
|
|
229
|
-
debug "Found license service URI: #{service_uri}", 2
|
|
230
|
-
|
|
231
|
-
service_response = authenticated_request(:get, service_uri)
|
|
232
|
-
if service_response.status == 200
|
|
233
|
-
return handle_dell_license_service_response(JSON.parse(service_response.body))
|
|
81
|
+
|
|
82
|
+
# Try manager entity OEM data
|
|
83
|
+
if (data = safe_get("/redfish/v1/Managers/iDRAC.Embedded.1"))
|
|
84
|
+
if (service_uri = data.dig("Oem", "Dell", "DellLicenseManagementService", "@odata.id"))
|
|
85
|
+
if (svc_data = safe_get(service_uri)) && svc_data["Members"]&.any?
|
|
86
|
+
if (details = safe_get(svc_data["Members"][0]["@odata.id"]))
|
|
87
|
+
return {
|
|
88
|
+
"Id" => details["EntitlementID"] || "iDRAC-License",
|
|
89
|
+
"Description" => details["LicenseDescription"] || "iDRAC License",
|
|
90
|
+
"Name" => details["LicenseDescription"] || "iDRAC License",
|
|
91
|
+
"LicenseType" => details["LicenseType"] || license_type_from(details["LicenseDescription"]),
|
|
92
|
+
"Status" => { "Health" => "OK" },
|
|
93
|
+
"Removable" => true
|
|
94
|
+
}
|
|
95
|
+
end
|
|
234
96
|
end
|
|
235
97
|
end
|
|
236
|
-
|
|
237
|
-
|
|
98
|
+
|
|
99
|
+
dell_data = data.dig("Oem", "Dell") || {}
|
|
238
100
|
if dell_data["LicenseType"] || dell_data["License"]
|
|
239
|
-
|
|
240
|
-
(dell_data["License"] && dell_data["License"].include?("Enterprise") ? "Enterprise" :
|
|
241
|
-
dell_data["License"].include?("Express") ? "Express" : "Basic")
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
"Id" => "iDRAC-License",
|
|
245
|
-
"Description" => "iDRAC8 #{license_type} License",
|
|
246
|
-
"Name" => "iDRAC License",
|
|
247
|
-
"LicenseType" => license_type,
|
|
248
|
-
"Status" => { "Health" => "OK" },
|
|
249
|
-
"Removable" => false
|
|
250
|
-
}
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
# Check for license type in model name or description
|
|
255
|
-
if data["Model"] && data["Model"].include?("Enterprise")
|
|
256
|
-
return {
|
|
257
|
-
"Id" => "iDRAC-License",
|
|
258
|
-
"Description" => "iDRAC8 Enterprise License",
|
|
259
|
-
"Name" => "iDRAC License",
|
|
260
|
-
"LicenseType" => "Enterprise",
|
|
261
|
-
"Status" => { "Health" => "OK" },
|
|
262
|
-
"Removable" => false
|
|
263
|
-
}
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
# If no license info found in manager data, fall back to feature detection
|
|
267
|
-
license_type = determine_license_type()
|
|
268
|
-
return {
|
|
269
|
-
"Id" => "iDRAC-License",
|
|
270
|
-
"Description" => "iDRAC8 #{license_type} License",
|
|
271
|
-
"Name" => "iDRAC License",
|
|
272
|
-
"LicenseType" => license_type,
|
|
273
|
-
"Status" => { "Health" => "OK" },
|
|
274
|
-
"Removable" => false
|
|
275
|
-
}
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
# Get service tag from system info
|
|
279
|
-
def get_service_tag
|
|
280
|
-
response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1")
|
|
281
|
-
if response.status == 200
|
|
282
|
-
data = JSON.parse(response.body)
|
|
283
|
-
return data["SKU"] if data["SKU"] # Service tag is usually in SKU field
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
# Try alternate location
|
|
287
|
-
response = authenticated_request(:get, "/redfish/v1")
|
|
288
|
-
if response.status == 200
|
|
289
|
-
data = JSON.parse(response.body)
|
|
290
|
-
if data["Oem"] && data["Oem"]["Dell"] && data["Oem"]["Dell"]["ServiceTag"]
|
|
291
|
-
return data["Oem"]["Dell"]["ServiceTag"]
|
|
101
|
+
return build_license_hash(license_type_from(dell_data["LicenseType"] || dell_data["License"]))
|
|
292
102
|
end
|
|
293
103
|
end
|
|
294
|
-
|
|
295
|
-
|
|
104
|
+
|
|
105
|
+
# Last resort: detect from features
|
|
106
|
+
build_license_hash(detect_license_type)
|
|
296
107
|
end
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
return "
|
|
301
|
-
|
|
302
|
-
if
|
|
303
|
-
|
|
304
|
-
elsif description.include?("Express")
|
|
305
|
-
return "Express"
|
|
306
|
-
elsif description.include?("Datacenter")
|
|
307
|
-
return "Datacenter"
|
|
308
|
-
else
|
|
309
|
-
return "Basic"
|
|
310
|
-
end
|
|
108
|
+
|
|
109
|
+
def license_type_from(str)
|
|
110
|
+
return "Unknown" unless str
|
|
111
|
+
return "Enterprise" if str.include?("Enterprise")
|
|
112
|
+
return "Datacenter" if str.include?("Datacenter")
|
|
113
|
+
return "Express" if str.include?("Express")
|
|
114
|
+
"Basic"
|
|
311
115
|
end
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
# @return [Hash] A basic license info object
|
|
316
|
-
def create_fallback_license_info(use_basic: false)
|
|
317
|
-
# Get the iDRAC version number from server headers
|
|
318
|
-
version = nil
|
|
319
|
-
response = authenticated_request(:get, "/redfish/v1")
|
|
320
|
-
if response.headers["server"] && response.headers["server"].match(/iDRAC\/(\d+)/i)
|
|
321
|
-
version = response.headers["server"].match(/iDRAC\/(\d+)/i)[1].to_i
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
# Try to determine if it's Enterprise or Express based on available features
|
|
325
|
-
license_type = use_basic ? "Basic" : determine_license_type
|
|
326
|
-
|
|
327
|
-
license_info = {
|
|
116
|
+
|
|
117
|
+
def build_license_hash(type)
|
|
118
|
+
{
|
|
328
119
|
"Id" => "iDRAC-License",
|
|
329
|
-
"Description" =>
|
|
120
|
+
"Description" => "iDRAC #{type} License",
|
|
330
121
|
"Name" => "iDRAC License",
|
|
331
|
-
"LicenseType" =>
|
|
122
|
+
"LicenseType" => type,
|
|
332
123
|
"Status" => { "Health" => "OK" },
|
|
333
124
|
"Removable" => false
|
|
334
125
|
}
|
|
335
|
-
|
|
336
|
-
debug "Created fallback license info: #{license_info}", 2
|
|
337
|
-
license_info
|
|
338
126
|
end
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
begin
|
|
345
|
-
# For example, virtual media is typically an Enterprise feature
|
|
346
|
-
virtual_media_response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1/VirtualMedia")
|
|
347
|
-
# If we successfully get virtual media, it's likely Enterprise
|
|
348
|
-
if virtual_media_response.status == 200
|
|
349
|
-
return "Enterprise"
|
|
350
|
-
end
|
|
351
|
-
rescue
|
|
352
|
-
# If the request fails, don't fail the whole method
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
# Default to basic license if we can't determine
|
|
356
|
-
return "Express"
|
|
127
|
+
|
|
128
|
+
def detect_license_type
|
|
129
|
+
# Virtual media is typically Enterprise-only
|
|
130
|
+
data = safe_get("/redfish/v1/Managers/iDRAC.Embedded.1/VirtualMedia")
|
|
131
|
+
data ? "Enterprise" : "Express"
|
|
357
132
|
end
|
|
358
133
|
end
|
|
359
|
-
end
|
|
134
|
+
end
|
data/lib/idrac/lifecycle.rb
CHANGED
|
@@ -169,8 +169,7 @@ module IDRAC
|
|
|
169
169
|
response = authenticated_request(
|
|
170
170
|
:patch,
|
|
171
171
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/LifecycleController.Embedded.1",
|
|
172
|
-
body: payload.to_json
|
|
173
|
-
headers: { 'Content-Type': 'application/json' }
|
|
172
|
+
body: payload.to_json
|
|
174
173
|
)
|
|
175
174
|
|
|
176
175
|
code = response.status
|
|
@@ -210,10 +209,9 @@ module IDRAC
|
|
|
210
209
|
payload = { "Component": ["LCData"] }
|
|
211
210
|
|
|
212
211
|
response = authenticated_request(
|
|
213
|
-
:post,
|
|
214
|
-
path,
|
|
215
|
-
body: payload.to_json
|
|
216
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
212
|
+
:post,
|
|
213
|
+
path,
|
|
214
|
+
body: payload.to_json
|
|
217
215
|
)
|
|
218
216
|
|
|
219
217
|
if response.status.between?(200, 299)
|
|
@@ -264,7 +262,7 @@ module IDRAC
|
|
|
264
262
|
def clear_system_event_logs!
|
|
265
263
|
path = '/redfish/v1/Managers/iDRAC.Embedded.1/LogServices/Sel/Actions/LogService.ClearLog'
|
|
266
264
|
|
|
267
|
-
response = authenticated_request(:post, path, body: {}.to_json
|
|
265
|
+
response = authenticated_request(:post, path, body: {}.to_json)
|
|
268
266
|
|
|
269
267
|
if response.status.between?(200, 299)
|
|
270
268
|
debug "System Event Logs cleared", 0, :green
|
data/lib/idrac/network.rb
CHANGED
|
@@ -171,8 +171,7 @@ module IDRAC
|
|
|
171
171
|
response = authenticated_request(
|
|
172
172
|
:patch,
|
|
173
173
|
interface_path,
|
|
174
|
-
body: body.to_json
|
|
175
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
174
|
+
body: body.to_json
|
|
176
175
|
)
|
|
177
176
|
puts "✅ Got response with status: #{response.status}".green
|
|
178
177
|
rescue => e
|
|
@@ -189,8 +188,7 @@ module IDRAC
|
|
|
189
188
|
restart_response = authenticated_request(
|
|
190
189
|
:post,
|
|
191
190
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.Reset",
|
|
192
|
-
body: { "ResetType" => "GracefulRestart" }.to_json
|
|
193
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
191
|
+
body: { "ResetType" => "GracefulRestart" }.to_json
|
|
194
192
|
)
|
|
195
193
|
|
|
196
194
|
if restart_response.status == 204
|
data/lib/idrac/power.rb
CHANGED
|
@@ -4,8 +4,7 @@ require 'colorize'
|
|
|
4
4
|
module IDRAC
|
|
5
5
|
module Power
|
|
6
6
|
def power_on(wait: true)
|
|
7
|
-
|
|
8
|
-
login unless @session_id
|
|
7
|
+
ensure_authenticated!
|
|
9
8
|
|
|
10
9
|
puts "Powering on server...".light_cyan
|
|
11
10
|
|
|
@@ -22,7 +21,7 @@ module IDRAC
|
|
|
22
21
|
|
|
23
22
|
tries = 10
|
|
24
23
|
while tries > 0
|
|
25
|
-
response = authenticated_request(:post, path, body: payload.to_json
|
|
24
|
+
response = authenticated_request(:post, path, body: payload.to_json)
|
|
26
25
|
|
|
27
26
|
case response.status
|
|
28
27
|
when 200, 204
|
|
@@ -60,8 +59,7 @@ module IDRAC
|
|
|
60
59
|
end
|
|
61
60
|
|
|
62
61
|
def power_off(wait: true, kind: "ForceOff")
|
|
63
|
-
|
|
64
|
-
login unless @session_id
|
|
62
|
+
ensure_authenticated!
|
|
65
63
|
|
|
66
64
|
puts "Powering off server...".light_cyan
|
|
67
65
|
|
|
@@ -76,12 +74,10 @@ module IDRAC
|
|
|
76
74
|
path = "/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
|
|
77
75
|
payload = { "ResetType" => kind }
|
|
78
76
|
|
|
79
|
-
response = authenticated_request(:post, path, body: payload.to_json
|
|
80
|
-
|
|
77
|
+
response = authenticated_request(:post, path, body: payload.to_json)
|
|
78
|
+
|
|
81
79
|
if response.status == 409
|
|
82
80
|
puts "Server is already powered OFF.".yellow
|
|
83
|
-
else
|
|
84
|
-
handle_response(response)
|
|
85
81
|
end
|
|
86
82
|
|
|
87
83
|
# Wait for power state change if requested
|
|
@@ -98,8 +94,7 @@ module IDRAC
|
|
|
98
94
|
end
|
|
99
95
|
|
|
100
96
|
def reboot
|
|
101
|
-
|
|
102
|
-
login unless @session_id
|
|
97
|
+
ensure_authenticated!
|
|
103
98
|
|
|
104
99
|
puts "Rebooting server...".light_cyan
|
|
105
100
|
|
|
@@ -114,7 +109,7 @@ module IDRAC
|
|
|
114
109
|
path = "/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset"
|
|
115
110
|
payload = { "ResetType" => "ForceRestart" }
|
|
116
111
|
|
|
117
|
-
response = authenticated_request(:post, path, body: payload.to_json
|
|
112
|
+
response = authenticated_request(:post, path, body: payload.to_json)
|
|
118
113
|
|
|
119
114
|
if response.status >= 200 && response.status < 300
|
|
120
115
|
puts "Server reboot command sent successfully".green
|
|
@@ -125,31 +120,27 @@ module IDRAC
|
|
|
125
120
|
# Try gracefulRestart as an alternative
|
|
126
121
|
puts "Trying GracefulRestart instead...".yellow
|
|
127
122
|
payload = { "ResetType" => "GracefulRestart" }
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
handle_response(response)
|
|
123
|
+
authenticated_request(:post, path, body: payload.to_json)
|
|
131
124
|
else
|
|
132
125
|
raise Error, "Failed to reboot server. Status code: #{response.status}"
|
|
133
126
|
end
|
|
134
127
|
end
|
|
135
128
|
|
|
136
129
|
def get_power_state
|
|
137
|
-
|
|
138
|
-
login unless @session_id
|
|
130
|
+
ensure_authenticated!
|
|
139
131
|
|
|
140
132
|
# Get system information
|
|
141
133
|
response = authenticated_request(:get, "/redfish/v1/Systems/System.Embedded.1?$select=PowerState")
|
|
142
|
-
|
|
143
|
-
JSON.parse(
|
|
134
|
+
|
|
135
|
+
JSON.parse(response.body)&.dig("PowerState")
|
|
144
136
|
end
|
|
145
137
|
|
|
146
138
|
def get_power_usage_watts
|
|
147
|
-
|
|
148
|
-
login unless @session_id
|
|
139
|
+
ensure_authenticated!
|
|
149
140
|
|
|
150
141
|
response = authenticated_request(:get, "/redfish/v1/Chassis/System.Embedded.1/Power")
|
|
151
|
-
|
|
152
|
-
JSON.parse(
|
|
142
|
+
|
|
143
|
+
JSON.parse(response.body)&.dig("PowerControl", 0, "PowerConsumedWatts")&.to_f
|
|
153
144
|
end
|
|
154
145
|
|
|
155
146
|
# TODO: Migrate method names to match radfish interface for uniformity:
|
data/lib/idrac/session.rb
CHANGED
|
@@ -180,38 +180,36 @@ module IDRAC
|
|
|
180
180
|
debug "Skipping Redfish session creation (direct mode)", 1, :light_yellow
|
|
181
181
|
return false
|
|
182
182
|
end
|
|
183
|
-
|
|
184
|
-
#
|
|
183
|
+
|
|
184
|
+
# Skip if already have a valid token
|
|
185
|
+
if @x_auth_token
|
|
186
|
+
debug "Session already active", 1, :green
|
|
187
|
+
return true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Determine the correct session endpoint (cached after first call)
|
|
185
191
|
session_endpoint = determine_session_endpoint
|
|
186
|
-
|
|
187
|
-
# Check current session count before creating new session
|
|
188
|
-
current_sessions = get_session_count
|
|
189
|
-
debug "Current active sessions: #{current_sessions}", 1, :cyan
|
|
190
|
-
|
|
192
|
+
|
|
191
193
|
payload = { "UserName" => username, "Password" => password }
|
|
192
|
-
|
|
194
|
+
|
|
193
195
|
debug "Attempting to create Redfish session at #{base_url}#{session_endpoint}", 1
|
|
194
196
|
debug "SSL verification: #{verify_ssl ? 'Enabled' : 'Disabled'}", 1
|
|
195
197
|
print_connection_debug_info if @verbosity >= 2
|
|
196
|
-
|
|
198
|
+
|
|
197
199
|
# Try creation methods in sequence
|
|
198
200
|
if create_session_with_content_type(session_endpoint, payload)
|
|
199
|
-
log_session_creation_success(current_sessions)
|
|
200
201
|
return true
|
|
201
202
|
end
|
|
202
203
|
if create_session_with_basic_auth(session_endpoint, payload)
|
|
203
|
-
log_session_creation_success(current_sessions)
|
|
204
204
|
return true
|
|
205
205
|
end
|
|
206
206
|
if handle_max_sessions_and_retry(session_endpoint, payload)
|
|
207
|
-
log_session_creation_success(current_sessions)
|
|
208
207
|
return true
|
|
209
208
|
end
|
|
210
209
|
if create_session_with_form_urlencoded(session_endpoint, payload)
|
|
211
|
-
log_session_creation_success(current_sessions)
|
|
212
210
|
return true
|
|
213
211
|
end
|
|
214
|
-
|
|
212
|
+
|
|
215
213
|
# If all attempts fail, switch to direct mode
|
|
216
214
|
@direct_mode = true
|
|
217
215
|
false
|
|
@@ -652,32 +650,32 @@ module IDRAC
|
|
|
652
650
|
end
|
|
653
651
|
end
|
|
654
652
|
|
|
655
|
-
# Determine the correct session endpoint based on Redfish version
|
|
653
|
+
# Determine the correct session endpoint based on Redfish version (cached)
|
|
656
654
|
def determine_session_endpoint
|
|
655
|
+
return @session_endpoint if @session_endpoint
|
|
656
|
+
|
|
657
657
|
begin
|
|
658
658
|
debug "Checking Redfish version to determine session endpoint...", 1
|
|
659
|
-
|
|
659
|
+
|
|
660
660
|
response = connection.get('/redfish/v1') do |req|
|
|
661
661
|
req.headers['Accept'] = 'application/json'
|
|
662
662
|
req.headers['Host'] = host_header if host_header
|
|
663
663
|
end
|
|
664
|
-
|
|
664
|
+
|
|
665
665
|
if response.status == 200
|
|
666
666
|
begin
|
|
667
667
|
data = JSON.parse(response.body)
|
|
668
668
|
redfish_version = data['RedfishVersion']
|
|
669
|
-
|
|
669
|
+
|
|
670
670
|
if redfish_version
|
|
671
671
|
debug "Detected Redfish version: #{redfish_version}", 1
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
endpoint = Gem::Version.new(redfish_version) <= Gem::Version.new('1.17.0') ?
|
|
676
|
-
'/redfish/v1/Sessions' :
|
|
672
|
+
|
|
673
|
+
@session_endpoint = Gem::Version.new(redfish_version) <= Gem::Version.new('1.17.0') ?
|
|
674
|
+
'/redfish/v1/Sessions' :
|
|
677
675
|
'/redfish/v1/SessionService/Sessions'
|
|
678
|
-
|
|
679
|
-
debug "Using endpoint #{
|
|
680
|
-
return
|
|
676
|
+
|
|
677
|
+
debug "Using endpoint #{@session_endpoint} for Redfish version #{redfish_version}", 1
|
|
678
|
+
return @session_endpoint
|
|
681
679
|
end
|
|
682
680
|
rescue JSON::ParserError => e
|
|
683
681
|
debug "Error parsing Redfish version: #{e.message}", 1, :red
|
|
@@ -688,11 +686,10 @@ module IDRAC
|
|
|
688
686
|
rescue => e
|
|
689
687
|
debug "Error checking Redfish version: #{e.message}", 1, :red
|
|
690
688
|
end
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
default_endpoint
|
|
689
|
+
|
|
690
|
+
@session_endpoint = '/redfish/v1/Sessions'
|
|
691
|
+
debug "Defaulting to endpoint #{@session_endpoint}", 1, :light_yellow
|
|
692
|
+
@session_endpoint
|
|
696
693
|
end
|
|
697
694
|
|
|
698
695
|
# Get current session count
|
data/lib/idrac/storage.rb
CHANGED
|
@@ -361,8 +361,6 @@ module IDRAC
|
|
|
361
361
|
puts "Deleting volume: #{path}"
|
|
362
362
|
|
|
363
363
|
response = authenticated_request(:delete, "/redfish/v1/#{path}")
|
|
364
|
-
|
|
365
|
-
handle_response(response)
|
|
366
364
|
end
|
|
367
365
|
|
|
368
366
|
# Create a new virtual disk with RAID5 and FastPath optimizations
|
|
@@ -430,13 +428,10 @@ module IDRAC
|
|
|
430
428
|
end
|
|
431
429
|
|
|
432
430
|
response = authenticated_request(
|
|
433
|
-
:post,
|
|
431
|
+
:post,
|
|
434
432
|
"#{controller_path}/Volumes",
|
|
435
|
-
body: payload.to_json
|
|
436
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
433
|
+
body: payload.to_json
|
|
437
434
|
)
|
|
438
|
-
|
|
439
|
-
handle_response(response)
|
|
440
435
|
end
|
|
441
436
|
|
|
442
437
|
|
|
@@ -541,24 +536,20 @@ module IDRAC
|
|
|
541
536
|
response = authenticated_request(
|
|
542
537
|
:post,
|
|
543
538
|
"/redfish/v1/Dell/Systems/System.Embedded.1/DellRaidService/Actions/DellRaidService.SetControllerKey",
|
|
544
|
-
body: payload.to_json
|
|
545
|
-
headers: { 'Content-Type': 'application/json' }
|
|
539
|
+
body: payload.to_json
|
|
546
540
|
)
|
|
547
541
|
|
|
548
542
|
if response.status == 202
|
|
549
543
|
puts "Controller encryption enabled".green
|
|
550
|
-
|
|
544
|
+
|
|
551
545
|
# Check if we need to wait for a job
|
|
552
546
|
if response.headers["location"]
|
|
553
547
|
job_id = response.headers["location"].split("/").last
|
|
554
548
|
wait_for_job(job_id)
|
|
555
549
|
end
|
|
556
|
-
|
|
557
|
-
return true
|
|
558
|
-
else
|
|
559
|
-
# Use generic error handler which includes ExtendedInfo parsing
|
|
560
|
-
handle_response(response)
|
|
561
550
|
end
|
|
551
|
+
|
|
552
|
+
true
|
|
562
553
|
end
|
|
563
554
|
|
|
564
555
|
# Disable Self-Encrypting Drive support on controller
|
|
@@ -568,24 +559,20 @@ module IDRAC
|
|
|
568
559
|
response = authenticated_request(
|
|
569
560
|
:post,
|
|
570
561
|
"/redfish/v1/Dell/Systems/System.Embedded.1/DellRaidService/Actions/DellRaidService.RemoveControllerKey",
|
|
571
|
-
body: payload.to_json
|
|
572
|
-
headers: { 'Content-Type': 'application/json' }
|
|
562
|
+
body: payload.to_json
|
|
573
563
|
)
|
|
574
564
|
|
|
575
565
|
if response.status == 202
|
|
576
566
|
puts "Controller encryption disabled".green
|
|
577
|
-
|
|
567
|
+
|
|
578
568
|
# Check if we need to wait for a job
|
|
579
569
|
if response.headers["location"]
|
|
580
570
|
job_id = response.headers["location"].split("/").last
|
|
581
571
|
wait_for_job(job_id)
|
|
582
572
|
end
|
|
583
|
-
|
|
584
|
-
return true
|
|
585
|
-
else
|
|
586
|
-
# Use generic error handler which includes ExtendedInfo parsing
|
|
587
|
-
handle_response(response)
|
|
588
573
|
end
|
|
574
|
+
|
|
575
|
+
true
|
|
589
576
|
end
|
|
590
577
|
|
|
591
578
|
# Check if all physical disks are Self-Encrypting Drives
|
data/lib/idrac/system.rb
CHANGED
|
@@ -708,10 +708,9 @@ module IDRAC
|
|
|
708
708
|
# Clear system event logs
|
|
709
709
|
def clear_system_event_logs
|
|
710
710
|
response = authenticated_request(
|
|
711
|
-
:post,
|
|
711
|
+
:post,
|
|
712
712
|
"/redfish/v1/Managers/iDRAC.Embedded.1/LogServices/Sel/Actions/LogService.ClearLog",
|
|
713
|
-
body: {}.to_json
|
|
714
|
-
headers: { 'Content-Type': 'application/json' }
|
|
713
|
+
body: {}.to_json
|
|
715
714
|
)
|
|
716
715
|
|
|
717
716
|
if response.status.between?(200, 299)
|
data/lib/idrac/system_config.rb
CHANGED
|
@@ -39,10 +39,9 @@ module IDRAC
|
|
|
39
39
|
|
|
40
40
|
# Submit configuration with job availability handling
|
|
41
41
|
res = wait_for_job_availability do
|
|
42
|
-
authenticated_request(:post,
|
|
42
|
+
authenticated_request(:post,
|
|
43
43
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ImportSystemConfiguration",
|
|
44
|
-
body: {"ImportBuffer": scp.to_json, "ShareParameters": {"Target": "iDRAC"}}.to_json
|
|
45
|
-
headers: {"Content-Type" => "application/json"}
|
|
44
|
+
body: {"ImportBuffer": scp.to_json, "ShareParameters": {"Target": "iDRAC"}}.to_json
|
|
46
45
|
)
|
|
47
46
|
end
|
|
48
47
|
|
|
@@ -58,10 +57,9 @@ module IDRAC
|
|
|
58
57
|
# Get the system configuration profile for a given target (e.g. "RAID")
|
|
59
58
|
def get_system_configuration_profile(target: "RAID")
|
|
60
59
|
debug "Exporting System Configuration..."
|
|
61
|
-
response = authenticated_request(:post,
|
|
62
|
-
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ExportSystemConfiguration",
|
|
63
|
-
body: {"ExportFormat": "JSON", "ShareParameters":{"Target": target}}.to_json
|
|
64
|
-
headers: {"Content-Type" => "application/json"}
|
|
60
|
+
response = authenticated_request(:post,
|
|
61
|
+
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ExportSystemConfiguration",
|
|
62
|
+
body: {"ExportFormat": "JSON", "ShareParameters":{"Target": target}}.to_json
|
|
65
63
|
)
|
|
66
64
|
scp = handle_location(response.headers["location"])
|
|
67
65
|
# We experienced this with older iDRACs, so let's give a enriched error to help debug.
|
|
@@ -117,10 +115,9 @@ module IDRAC
|
|
|
117
115
|
|
|
118
116
|
# Make the API request
|
|
119
117
|
response = authenticated_request(
|
|
120
|
-
:post,
|
|
118
|
+
:post,
|
|
121
119
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ImportSystemConfiguration",
|
|
122
|
-
body: params.to_json
|
|
123
|
-
headers: {"Content-Type" => "application/json"}
|
|
120
|
+
body: params.to_json
|
|
124
121
|
)
|
|
125
122
|
|
|
126
123
|
# Check for immediate errors
|
data/lib/idrac/utility.rb
CHANGED
|
@@ -61,8 +61,7 @@ module IDRAC
|
|
|
61
61
|
response = authenticated_request(
|
|
62
62
|
:post,
|
|
63
63
|
"/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.SupportAssistCollection",
|
|
64
|
-
body: payload.to_json
|
|
65
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
64
|
+
body: payload.to_json
|
|
66
65
|
)
|
|
67
66
|
|
|
68
67
|
case response.status
|
|
@@ -303,8 +302,7 @@ module IDRAC
|
|
|
303
302
|
response = authenticated_request(
|
|
304
303
|
:post,
|
|
305
304
|
"/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.SupportAssistGetEULAStatus",
|
|
306
|
-
body: {}.to_json
|
|
307
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
305
|
+
body: {}.to_json
|
|
308
306
|
)
|
|
309
307
|
|
|
310
308
|
if response.status.between?(200, 299)
|
|
@@ -333,8 +331,7 @@ module IDRAC
|
|
|
333
331
|
response = authenticated_request(
|
|
334
332
|
:post,
|
|
335
333
|
"/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.SupportAssistAcceptEULA",
|
|
336
|
-
body: {}.to_json
|
|
337
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
334
|
+
body: {}.to_json
|
|
338
335
|
)
|
|
339
336
|
|
|
340
337
|
if response.status.between?(200, 299)
|
|
@@ -357,8 +354,7 @@ module IDRAC
|
|
|
357
354
|
response = authenticated_request(
|
|
358
355
|
:post,
|
|
359
356
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Manager.Reset",
|
|
360
|
-
body: { "ResetType" => "GracefulRestart" }.to_json
|
|
361
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
357
|
+
body: { "ResetType" => "GracefulRestart" }.to_json
|
|
362
358
|
)
|
|
363
359
|
|
|
364
360
|
if response.status.between?(200, 299)
|
data/lib/idrac/version.rb
CHANGED
data/lib/idrac/virtual_media.rb
CHANGED
|
@@ -71,13 +71,11 @@ module IDRAC
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
response = authenticated_request(
|
|
74
|
-
:post,
|
|
74
|
+
:post,
|
|
75
75
|
"/redfish/v1/#{path}",
|
|
76
|
-
body: {}.to_json
|
|
77
|
-
headers: { 'Content-Type': 'application/json' }
|
|
76
|
+
body: {}.to_json
|
|
78
77
|
)
|
|
79
78
|
|
|
80
|
-
handle_response(response)
|
|
81
79
|
response.status.between?(200, 299)
|
|
82
80
|
end
|
|
83
81
|
|
|
@@ -106,10 +104,9 @@ module IDRAC
|
|
|
106
104
|
end
|
|
107
105
|
|
|
108
106
|
response = authenticated_request(
|
|
109
|
-
:post,
|
|
107
|
+
:post,
|
|
110
108
|
"/redfish/v1/#{path}",
|
|
111
|
-
body: { "Image": iso_url, "Inserted": true, "WriteProtected": true }.to_json
|
|
112
|
-
headers: { 'Content-Type': 'application/json' }
|
|
109
|
+
body: { "Image": iso_url, "Inserted": true, "WriteProtected": true }.to_json
|
|
113
110
|
)
|
|
114
111
|
|
|
115
112
|
if response.status == 204 || response.status == 200
|
|
@@ -158,10 +155,9 @@ module IDRAC
|
|
|
158
155
|
|
|
159
156
|
# Set one-time boot to CD
|
|
160
157
|
response = authenticated_request(
|
|
161
|
-
:patch,
|
|
158
|
+
:patch,
|
|
162
159
|
"/redfish/v1/Systems/System.Embedded.1",
|
|
163
|
-
body: { "Boot": { "BootSourceOverrideTarget": "Cd", "BootSourceOverrideEnabled": "Once" } }.to_json
|
|
164
|
-
headers: { 'Content-Type': 'application/json' }
|
|
160
|
+
body: { "Boot": { "BootSourceOverrideTarget": "Cd", "BootSourceOverrideEnabled": "Once" } }.to_json
|
|
165
161
|
)
|
|
166
162
|
|
|
167
163
|
if response.status.between?(200, 299)
|
|
@@ -189,10 +185,9 @@ module IDRAC
|
|
|
189
185
|
}
|
|
190
186
|
|
|
191
187
|
response = authenticated_request(
|
|
192
|
-
:patch,
|
|
188
|
+
:patch,
|
|
193
189
|
"/redfish/v1/Managers/iDRAC.Embedded.1/Attributes",
|
|
194
|
-
body: payload.to_json
|
|
195
|
-
headers: { 'Content-Type': 'application/json' }
|
|
190
|
+
body: payload.to_json
|
|
196
191
|
)
|
|
197
192
|
|
|
198
193
|
if response.status.between?(200, 299)
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: idrac
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Siegel
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: httparty
|
|
@@ -282,7 +281,6 @@ licenses:
|
|
|
282
281
|
metadata:
|
|
283
282
|
homepage_uri: https://github.com/buildio/idrac
|
|
284
283
|
source_code_uri: https://github.com/buildio/idrac
|
|
285
|
-
post_install_message:
|
|
286
284
|
rdoc_options: []
|
|
287
285
|
require_paths:
|
|
288
286
|
- lib
|
|
@@ -297,8 +295,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
297
295
|
- !ruby/object:Gem::Version
|
|
298
296
|
version: '0'
|
|
299
297
|
requirements: []
|
|
300
|
-
rubygems_version: 3.
|
|
301
|
-
signing_key:
|
|
298
|
+
rubygems_version: 3.6.9
|
|
302
299
|
specification_version: 4
|
|
303
300
|
summary: API Client for Dell iDRAC
|
|
304
301
|
test_files: []
|