idrac 0.9.3 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8f284844e8559e5cb1873cc31e8f08bdff27f358f6b9c74e3cef2d41913ba96
4
- data.tar.gz: 02db8a1bdc940f6a345db7543dd8b3d3cb5e1b3ac16efaa63bf0e35a369f4271
3
+ metadata.gz: 54237d0e5e104838b8770088791b1896b11928d0092572035ee05117de1d6733
4
+ data.tar.gz: 802a048dcf46d8d9a1eab4626be4425269ee58d0012b61f1ac167b44a8b1def9
5
5
  SHA512:
6
- metadata.gz: 9151c3a3dbbf5be669d9482f5d24af9f0313f97b8fac83262c32b780bc641aeb93d1c3fbee2eeefbff8ea60006ce766b6fa0921e52a01bfcebf40142889f5a1a
7
- data.tar.gz: 79d18056308f3e4255bd19f5003d38aec5ed05c8a20222d6ce07e0bb230eeaf139cd4d94d6f428a35e24c413785a045a2b6a4121660e11ada3213d5f565dad0d
6
+ metadata.gz: 95ff7c2f6e83194632b4ceb9febd251f01332f39271c02bfc2e0f35e677159b873b7ff74a8906f5b293af855aa2fb3f69ed4e73242be8ca704f6346da507c9a8
7
+ data.tar.gz: 94f8e2b5ab66ff0cf428bdb1903d3ba3d38d9b3e2002323e36a866ffb4461ae22a2766861550d4daf0fe74b274e2991ef9280fd9732581af9d0b86d3209b7047
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 the standard license endpoint first (works in iDRAC 9+)
7
- response = authenticated_request(:get, "/redfish/v1/LicenseService/Licenses")
8
-
9
- if response.status == 200
10
- license_data = JSON.parse(response.body)
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 version from the license description or server header
42
- # @return [Integer, nil] The license version (e.g. 9) or nil if not found
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
- # Check the Description field, which often contains the version
60
- # Example: "iDRAC9 Enterprise License"
61
- if license["Description"]&.match(/iDRAC(\d+)/i)
62
- version = license["Description"].match(/iDRAC(\d+)/i)[1].to_i
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
- # If license info failed or didn't have version info, try to get from server header
83
- # Make a simple request to check the server header (often contains iDRAC version)
84
- response = authenticated_request(:get, "/redfish/v1")
85
- if response.headers["server"] && response.headers["server"].match(/iDRAC\/(\d+)/i)
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 several potential Dell license paths (order matters - most likely first)
99
- dell_license_paths = [
100
- "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLicenseManagementService/Licenses",
101
- "/redfish/v1/Managers/iDRAC.Embedded.1/Attributes", # iDRAC attributes might contain license info
102
- "/redfish/v1/Managers/iDRAC.Embedded.1" # Manager entity might have license info embedded
103
- ]
104
-
105
- dell_license_paths.each do |path|
106
- response = authenticated_request(:get, path)
107
-
108
- if response.status == 200
109
- debug "Found valid Dell license path: #{path}", 2
110
- data = JSON.parse(response.body)
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
- # If we couldn't find any API path that works, try the service tag detection method
126
- service_tag = get_service_tag
127
- if service_tag
128
- # Service tag is often used to indicate Enterprise licenses on Dell systems
129
- license_type = determine_license_type()
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
- # If no license attributes found, fall back to feature detection
209
- license_type = determine_license_type()
210
- return {
211
- "Id" => "iDRAC-License",
212
- "Description" => "iDRAC8 #{license_type} License",
213
- "Name" => "iDRAC License",
214
- "LicenseType" => license_type,
215
- "Status" => { "Health" => "OK" },
216
- "Removable" => false
217
- }
218
- end
219
-
220
- # Handle response from Dell Manager entity
221
- def handle_dell_manager_response(data)
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
- # Check if license info is embedded directly
98
+
99
+ dell_data = data.dig("Oem", "Dell") || {}
238
100
  if dell_data["LicenseType"] || dell_data["License"]
239
- license_type = dell_data["LicenseType"] ||
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
- nil
104
+
105
+ # Last resort: detect from features
106
+ build_license_hash(detect_license_type)
296
107
  end
297
-
298
- # Helper method to extract license type from description
299
- def get_license_type_from_description(description)
300
- return "Unknown" unless description
301
-
302
- if description.include?("Enterprise")
303
- return "Enterprise"
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
- # Creates a basic license info object based on system information
314
- # Used as a fallback when neither the standard nor Dell OEM endpoints work
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" => version ? "iDRAC#{version} #{license_type} License" : "iDRAC License",
120
+ "Description" => "iDRAC #{type} License",
330
121
  "Name" => "iDRAC License",
331
- "LicenseType" => license_type,
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
- # Attempt to determine the license type (Enterprise/Express) based on available features
341
- # @return [String] The license type (Enterprise, Express, or Basic)
342
- def determine_license_type
343
- # We can try to check for features only available in Enterprise
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/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IDRAC
4
- VERSION = "0.9.3"
4
+ VERSION = "0.9.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idrac
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel