idrac 0.10.4 → 0.10.5

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: 17491587256894c2ff168665dca777903a2d6b7d7582f745c4c3e81f697889cd
4
- data.tar.gz: 432ecbfd6df649a69644254dc942e253a8d917f6ce2cd07c30f7f328c3ffee75
3
+ metadata.gz: 9c4504dd010f1458b9705e73489d4d68ec18214ef13a5a5187dde3ed52812d1a
4
+ data.tar.gz: eb9ab621e77b1ad17ade9579b4286a7696f7f0bb9dc0761e8862446ee8f39963
5
5
  SHA512:
6
- metadata.gz: 28cc04b7ec2f246ed29d95ba50481f52dff7893e69fd94dc6f82db81e0d7b988e6d0e21589ae09a75e99c51621f2a6650a1aa0ada2c74c8aa4ff6f2726cadf98
7
- data.tar.gz: 6981e38fe25c803372a0c09aa3616db6ce7d0670415fbec9f73e143c25e44fff25e24ea650dfe5ebfcc821b14c6d17dd778664e43d11b5fbfd8c6458cacae374
6
+ metadata.gz: af0824a2ceb96d5c89a2552277d24bdf754eb748a7644d756deb3864620130b005d3f5cefa1f0921d6617fd03aab79c31fd8d9de8b0716a2e3124a8916f1bde4
7
+ data.tar.gz: 3c85876b2e93b31bed8f8dd4a8ea2ab4ae851048a2767c18e319151b74748c797502971c0932b9e534150c95ce66c3bb9ff93e5194a0d6e37108714724363396
@@ -90,12 +90,29 @@ module IDRAC
90
90
  # Id ("Installed-<componentID>-<version>"). Used to match DUPs by
91
91
  # componentID rather than by ambiguous display name.
92
92
  fw_id = component_data['Id'].to_s
93
- component_id = component_data.dig('Oem', 'Dell', 'DellSoftwareInventory', 'ComponentID')
93
+ oem = component_data.dig('Oem', 'Dell', 'DellSoftwareInventory') || {}
94
+ component_id = oem['ComponentID']
94
95
  component_id ||= fw_id[/\A(?:Installed|Current|Previous|Available)-(\d+)-/, 1]
96
+ # The same Oem block carries the device's PCI IDs, and it carries
97
+ # them exactly where the componentID is missing. The iDRAC reports
98
+ # componentID "0" for firmware it did not install itself, so
99
+ # factory-flashed hardware is unmatchable by componentID: on an
100
+ # R6525, 13 of 23 entries report "0" (both LOMs, both ConnectX-6,
101
+ # the PERC, all 8 NVMe drives) and each publishes all four PCI
102
+ # IDs, while the 10 with a real componentID publish none. An
103
+ # entry gains its componentID once a DUP is applied — a LOM went
104
+ # from "Installed-0-22.91.5" to "Installed-108255-23.61.3" — so
105
+ # the unmatchable set is first-touch hardware, not an edge case.
106
+ # No PCIeDevices/PCIeFunctions lookup is needed to identify what
107
+ # the componentID cannot; see #updates_for_component.
95
108
  firmware_inventory << {
96
109
  name: component_data['Name'],
97
110
  id: component_data['Id'],
98
111
  component_id: component_id,
112
+ vendor_id: oem['VendorID'],
113
+ device_id: oem['DeviceID'],
114
+ sub_vendor_id: oem['SubVendorID'],
115
+ sub_device_id: oem['SubDeviceID'],
99
116
  version: component_data['Version'],
100
117
  updateable: component_data['Updateable'] || false,
101
118
  status: component_data['Status'] ? component_data['Status']['State'] : 'Unknown'
@@ -172,6 +172,16 @@ module IDRAC
172
172
  # picks wrong DUPs and iDRAC rejects them (RED097 / "not compatible").
173
173
  component_ids = component.xpath(".//SupportedDevices/Device/@componentID").map(&:value).uniq
174
174
 
175
+ # The PCI IDs this DUP declares it can flash. The PCIe/storage half of
176
+ # the iDRAC inventory reports componentID "0" (measured on an R6525:
177
+ # every NIC, the PERC and all 8 NVMe drives), so componentID alone
178
+ # cannot match them and the old name heuristic guessed — it offered a
179
+ # Broadcom LOM an Intel package. PCI IDs are the identity both sides
180
+ # publish, so a cross-vendor match becomes impossible.
181
+ pci_ids = component.xpath(".//SupportedDevices/Device/PCIInfo").map { |p|
182
+ pci_key(p["vendorID"], p["deviceID"], p["subVendorID"], p["subDeviceID"])
183
+ }.compact.uniq
184
+
175
185
  # Skip if missing essential information
176
186
  next if name.empty? || path.empty? || version.empty?
177
187
 
@@ -191,6 +201,7 @@ module IDRAC
191
201
  component_type: component_type,
192
202
  category: category,
193
203
  component_ids: component_ids,
204
+ pci_ids: pci_ids,
194
205
  download_url: "https://downloads.dell.com/#{path}"
195
206
  }
196
207
  end
@@ -200,24 +211,66 @@ module IDRAC
200
211
  updates
201
212
  end
202
213
 
214
+ # Normalize one PCI ID quad to a comparable key. Dell publishes the same
215
+ # four IDs on both sides but spells them differently: the catalog writes
216
+ # bare uppercase hex (<PCIInfo vendorID="14E4" deviceID="165F"/>) while
217
+ # Redfish writes "0x790e". Returns nil unless all four are present, so a
218
+ # caller can tell "no PCI identity" from "PCI identity that matched
219
+ # nothing".
220
+ def pci_key(vendor_id, device_id, sub_vendor_id, sub_device_id)
221
+ parts = [vendor_id, device_id, sub_vendor_id, sub_device_id].map do |id|
222
+ id.to_s.strip.sub(/\A0x/i, "").upcase
223
+ end
224
+ return nil if parts.any?(&:empty?)
225
+
226
+ parts.map { |p| p.rjust(4, "0") }.join("/")
227
+ end
228
+
203
229
  # 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").
230
+ # the iDRAC inventory), most specific key first.
231
+ #
232
+ # 1. Dell componentID, when the inventory gives a real one. Exact and
233
+ # unambiguous; unchanged.
234
+ # 2. PCI IDs, for the entries that report componentID "0" — on an R6525
235
+ # that is every NIC, the PERC and every drive. The full quad first, then
236
+ # vendor+device if the catalog lists no package for that exact subsystem
237
+ # ID. Both tiers pin the vendor, which is the whole point: name matching
238
+ # reduced any NIC to the token "NIC" and any RAID device to "PERC", then
239
+ # substring-matched the DUP's package name, so a "Broadcom NetXtreme
240
+ # Gigabit Ethernet" LOM was offered "Intel NIC Family Version 25.0.0
241
+ # Firmware for Intel I350 and X550 Adapters" — wrong vendor — and a
242
+ # "PERC H755N Front" was offered the H355 package. It was also unstable:
243
+ # the same tool offered two identical PERCs different packages, because
244
+ # the winner depended on catalog order.
245
+ # 3. The name heuristic, only when the inventory gave neither key. When PCI
246
+ # IDs are present they are the answer: if nothing matches them, the
247
+ # catalog has no package for this device, and guessing by name is how
248
+ # the wrong-vendor DUPs got offered in the first place.
207
249
  def updates_for_component(catalog_updates, fw)
208
250
  component_id = fw[:component_id]
209
251
  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)
252
+ return catalog_updates.select { |u| Array(u[:component_ids]).include?(component_id) }
253
+ end
254
+
255
+ key = pci_key(fw[:vendor_id], fw[:device_id], fw[:sub_vendor_id], fw[:sub_device_id])
256
+ if key
257
+ exact = catalog_updates.select { |u| Array(u[:pci_ids]).include?(key) }
258
+ return exact if exact.any?
259
+
260
+ chip = key.split("/").first(2).join("/")
261
+ return catalog_updates.select do |u|
262
+ Array(u[:pci_ids]).any? { |k| k.start_with?("#{chip}/") }
219
263
  end
220
264
  end
265
+
266
+ name = fw[:name] || ""
267
+ ids = extract_identifiers(name)
268
+ catalog_updates.select do |u|
269
+ un = u[:name] || ""
270
+ ids.any? { |id| un.downcase.include?(id.downcase) } ||
271
+ un.downcase.include?(name.downcase) ||
272
+ name.downcase.include?(un.downcase)
273
+ end
221
274
  end
222
275
 
223
276
  # Sortable key for a Dell version string (e.g. "25.5.9.0001", "22.00.6").
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.4"
4
+ VERSION = "0.10.5"
5
5
  end
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.10.4
4
+ version: 0.10.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Siegel
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-08-29 00:00:00.000000000 Z
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.5.16
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: []