idrac 0.10.0 → 0.10.2

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: ed5ada7ae018807e7dfc073f096fca65c1721b02698a27ae8253c4fe0ea7a999
4
- data.tar.gz: 9463bffbbc3915cad87522b36ff9e29ef795e8e90ed0cffaed1912f0a7bb67ac
3
+ metadata.gz: 5e3c0e2f73e3449a852e4e46ca5838705d9ac5eeb780c7fa2023329747406a94
4
+ data.tar.gz: 7430d5ee6cf11aee77dd5f01990a7a1fca680cbfeb40fbad9e65a7a933ed7619
5
5
  SHA512:
6
- metadata.gz: 7072b7e0ac5d30a9bdef4bf88b4b9f09054343196eb4021b5318ee26baa7abb026e72662b3740cdd68ac5cb110911715fde1bbe02b430e0f07eab50a0a303cb4
7
- data.tar.gz: 56ed519ae70e0786d6d1c26a2596cea0a8d8cec9c8b1aafbf4686d75c5c8cde39da0add93dabd518ddffe4e0ac6b3a736b0fcd35669f3d2296a5a79024520d3e
6
+ metadata.gz: 0cbb04e015b2cb0d4c5181355e34c5768250929e99b101b2a23d946b61b6b24f9b4ca8b6e803a7660ffe5f0d388d0f89c8a8b5ef9dda0cb262fcbd580260cfcc
7
+ data.tar.gz: e5284b739c221f9b96697dfdccb14d148e9a07ff1cc86131fc4975f608526583a13f540ba243b9167455de6325f1ced21bb6416230512f2d71a52f2765d6888b
@@ -86,9 +86,16 @@ module IDRAC
86
86
 
87
87
  if component_response.status == 200
88
88
  component_data = JSON.parse(component_response.body)
89
+ # Dell componentID — prefer the Oem field, else parse the inventory
90
+ # Id ("Installed-<componentID>-<version>"). Used to match DUPs by
91
+ # componentID rather than by ambiguous display name.
92
+ fw_id = component_data['Id'].to_s
93
+ component_id = component_data.dig('Oem', 'Dell', 'DellSoftwareInventory', 'ComponentID')
94
+ component_id ||= fw_id[/\A(?:Installed|Current|Previous|Available)-(\d+)-/, 1]
89
95
  firmware_inventory << {
90
96
  name: component_data['Name'],
91
97
  id: component_data['Id'],
98
+ component_id: component_id,
92
99
  version: component_data['Version'],
93
100
  updateable: component_data['Updateable'] || false,
94
101
  status: component_data['Status'] ? component_data['Status']['State'] : 'Unknown'
@@ -168,25 +175,16 @@ module IDRAC
168
175
  next if displayed_components.include?(firmware_name.downcase)
169
176
  displayed_components.add(firmware_name.downcase)
170
177
 
171
- # Extract key identifiers from the firmware name
172
- identifiers = catalog.extract_identifiers(firmware_name)
173
-
174
- # Try to find a matching update
175
- matching_updates = catalog_updates.select do |update|
176
- update_name = update[:name] || ""
177
-
178
- # Check if any of our identifiers match the update name
179
- identifiers.any? { |id| update_name.downcase.include?(id.downcase) } ||
180
- # Or if the update name contains the firmware name
181
- update_name.downcase.include?(firmware_name.downcase) ||
182
- # Or if the firmware name contains the update name
183
- firmware_name.downcase.include?(update_name.downcase)
184
- end
185
-
178
+ # Match the installed component to catalog DUPs. Prefer the Dell
179
+ # componentID (reliable) — only fall back to the legacy name heuristic
180
+ # when the inventory doesn't expose one.
181
+ matching_updates = catalog.updates_for_component(catalog_updates, fw)
182
+
186
183
  if matching_updates.any?
187
- # Use the first matching update
188
- update = matching_updates.first
189
-
184
+ # Among matches, take the newest available version (the catalog can
185
+ # list several revisions for one component).
186
+ update = matching_updates.max_by { |u| catalog.version_key(u[:version]) }
187
+
190
188
  # Check if version is newer
191
189
  needs_update = catalog.compare_versions(fw[:version], update[:version])
192
190
 
@@ -253,12 +251,7 @@ module IDRAC
253
251
 
254
252
  # Skip if this update was already matched to a current firmware
255
253
  next if inventory[:firmware].any? do |fw|
256
- firmware_name = fw[:name] || ""
257
- identifiers = catalog.extract_identifiers(firmware_name)
258
-
259
- identifiers.any? { |id| update_name.downcase.include?(id.downcase) } ||
260
- update_name.downcase.include?(firmware_name.downcase) ||
261
- firmware_name.downcase.include?(update_name.downcase)
254
+ catalog.updates_for_component([update], fw).any?
262
255
  end
263
256
 
264
257
  puts "%-30s %-20s %-20s %-10s %-15s %s" % [
@@ -161,11 +161,20 @@ module IDRAC
161
161
  category_node = component.xpath("./Category/Display[@lang='en']").first
162
162
  category = category_node ? category_node.text.strip : ""
163
163
 
164
- version = component['dellVersion'] || component['vendorVersion'] || ""
165
-
164
+ # Prefer the numeric vendorVersion (e.g. "25.5.9.0001") over dellVersion,
165
+ # which is just the package revision label ("A17"). Comparing that label
166
+ # against an installed numeric version falsely flags every component.
167
+ version = component['vendorVersion'] || component['dellVersion'] || ""
168
+
169
+ # Dell componentIDs this DUP actually flashes. This is the reliable key
170
+ # for matching a DUP to an installed component (see #check_updates) —
171
+ # names are ambiguous (every NIC DUP says "Ethernet"), so name-matching
172
+ # picks wrong DUPs and iDRAC rejects them (RED097 / "not compatible").
173
+ component_ids = component.xpath(".//SupportedDevices/Device/@componentID").map(&:value).uniq
174
+
166
175
  # Skip if missing essential information
167
176
  next if name.empty? || path.empty? || version.empty?
168
-
177
+
169
178
  # Only include firmware updates
170
179
  if component_type.include?("Firmware") ||
171
180
  category.include?("BIOS") ||
@@ -174,13 +183,14 @@ module IDRAC
174
183
  name.include?("BIOS") ||
175
184
  name.include?("Firmware") ||
176
185
  name.include?("iDRAC")
177
-
186
+
178
187
  updates << {
179
188
  name: name,
180
189
  version: version,
181
190
  path: path,
182
191
  component_type: component_type,
183
192
  category: category,
193
+ component_ids: component_ids,
184
194
  download_url: "https://downloads.dell.com/#{path}"
185
195
  }
186
196
  end
@@ -189,7 +199,35 @@ module IDRAC
189
199
  puts "Found #{updates.size} firmware updates for system ID #{system_id}"
190
200
  updates
191
201
  end
192
-
202
+
203
+ # Select the catalog DUPs that apply to one installed component (`fw` from
204
+ # the iDRAC inventory). Matches on Dell componentID — the reliable key —
205
+ # and only falls back to the legacy name heuristic when the inventory
206
+ # didn't expose a componentID (e.g. it reports "0").
207
+ def updates_for_component(catalog_updates, fw)
208
+ component_id = fw[:component_id]
209
+ if component_id && component_id != "0"
210
+ catalog_updates.select { |u| Array(u[:component_ids]).include?(component_id) }
211
+ else
212
+ name = fw[:name] || ""
213
+ ids = extract_identifiers(name)
214
+ catalog_updates.select do |u|
215
+ un = u[:name] || ""
216
+ ids.any? { |id| un.downcase.include?(id.downcase) } ||
217
+ un.downcase.include?(name.downcase) ||
218
+ name.downcase.include?(un.downcase)
219
+ end
220
+ end
221
+ end
222
+
223
+ # Sortable key for a Dell version string (e.g. "25.5.9.0001", "22.00.6").
224
+ # Non-numeric/odd versions sort lowest rather than raising.
225
+ def version_key(version)
226
+ Gem::Version.new(version.to_s[/\d[\d.]*/] || "0")
227
+ rescue ArgumentError
228
+ Gem::Version.new("0")
229
+ end
230
+
193
231
  def extract_identifiers(name)
194
232
  return [] unless name
195
233
 
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.10.0"
4
+ VERSION = "0.10.2"
5
5
  end
@@ -12,11 +12,18 @@ module IDRAC
12
12
  data = JSON.parse(response.body)
13
13
 
14
14
  media = data["Members"].map do |m|
15
- # Check if media is inserted based on multiple indicators
16
- is_inserted = m["Inserted"] ||
17
- (!m["Image"].nil? && !m["Image"].empty?) ||
18
- (m["ConnectedVia"] && m["ConnectedVia"] != "NotConnected") ||
19
- (m["ImageName"] && !m["ImageName"].empty?)
15
+ # Trust the BMC's structured connection state when present; fall back to the
16
+ # Image/ImageName string only when it isn't. On iDRAC8 a slot can keep a stale
17
+ # Image string with nothing actually mounted (ConnectedVia == "NotConnected" /
18
+ # Inserted == false); treating that as "inserted" makes eject POST an EjectMedia
19
+ # the BMC rejects with HTTP 500 (VRM0009).
20
+ is_inserted = if !m["Inserted"].nil?
21
+ m["Inserted"]
22
+ elsif m["ConnectedVia"]
23
+ m["ConnectedVia"] != "NotConnected"
24
+ else
25
+ (m["Image"] && !m["Image"].empty?) || (m["ImageName"] && !m["ImageName"].empty?)
26
+ end
20
27
 
21
28
  # Indicate which field is used for this iDRAC version and print it
22
29
  puts "ImageName is used for this iDRAC version".yellow if m["ImageName"]
@@ -70,13 +77,21 @@ module IDRAC
70
77
  "Managers/iDRAC.Embedded.1/VirtualMedia/#{device}/Actions/VirtualMedia.EjectMedia"
71
78
  end
72
79
 
73
- response = authenticated_request(
74
- :post,
75
- "/redfish/v1/#{path}",
76
- body: {}.to_json
77
- )
78
-
79
- response.status.between?(200, 299)
80
+ begin
81
+ response = authenticated_request(
82
+ :post,
83
+ "/redfish/v1/#{path}",
84
+ body: {}.to_json
85
+ )
86
+ response.status.between?(200, 299)
87
+ rescue IDRAC::Error => e
88
+ # iDRAC8 can still 500 with VRM0009 ("No Virtual Media devices are currently connected")
89
+ # when the slot reported a stale image but nothing was actually mounted. Ejecting nothing
90
+ # is a no-op success for callers, so swallow exactly that rejection.
91
+ raise unless e.message =~ /VRM0009|No Virtual Media devices are currently connected/i
92
+ puts "Nothing actually mounted on #{device}; treating eject as no-op".yellow
93
+ false
94
+ end
80
95
  end
81
96
 
82
97
  # Insert virtual media (ISO)
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idrac
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-06-03 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: httparty
@@ -281,6 +282,7 @@ licenses:
281
282
  metadata:
282
283
  homepage_uri: https://github.com/buildio/idrac
283
284
  source_code_uri: https://github.com/buildio/idrac
285
+ post_install_message:
284
286
  rdoc_options: []
285
287
  require_paths:
286
288
  - lib
@@ -295,7 +297,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
295
297
  - !ruby/object:Gem::Version
296
298
  version: '0'
297
299
  requirements: []
298
- rubygems_version: 3.6.9
300
+ rubygems_version: 3.5.16
301
+ signing_key:
299
302
  specification_version: 4
300
303
  summary: API Client for Dell iDRAC
301
304
  test_files: []