idrac 0.1.29 → 0.1.30
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 +24 -1
- data/bin/idrac +38 -36
- data/dell_firmware_downloads/Catalog.etag +1 -0
- data/dell_firmware_downloads/Catalog.xml +0 -0
- data/idrac-0.1.6/.rspec +3 -0
- data/idrac-0.1.6/README.md +103 -0
- data/idrac-0.1.6/Rakefile +17 -0
- data/idrac-0.1.6/bin/console +11 -0
- data/idrac-0.1.6/bin/idrac +179 -0
- data/idrac-0.1.6/bin/setup +8 -0
- data/idrac-0.1.6/idrac.gemspec +51 -0
- data/idrac-0.1.6/lib/idrac/client.rb +109 -0
- data/idrac-0.1.6/lib/idrac/firmware.rb +366 -0
- data/idrac-0.1.6/lib/idrac/version.rb +5 -0
- data/idrac-0.1.6/lib/idrac.rb +30 -0
- data/idrac-0.1.6/sig/idrac.rbs +4 -0
- data/idrac-0.1.7/.rspec +3 -0
- data/idrac-0.1.7/README.md +103 -0
- data/idrac-0.1.7/Rakefile +17 -0
- data/idrac-0.1.7/bin/console +11 -0
- data/idrac-0.1.7/bin/idrac +179 -0
- data/idrac-0.1.7/bin/setup +8 -0
- data/idrac-0.1.7/idrac.gemspec +51 -0
- data/idrac-0.1.7/lib/idrac/client.rb +109 -0
- data/idrac-0.1.7/lib/idrac/firmware.rb +366 -0
- data/idrac-0.1.7/lib/idrac/screenshot.rb +49 -0
- data/idrac-0.1.7/lib/idrac/version.rb +5 -0
- data/idrac-0.1.7/lib/idrac.rb +30 -0
- data/idrac-0.1.7/sig/idrac.rbs +4 -0
- data/idrac.gemspec +1 -0
- data/idrac.py +500 -0
- data/lib/idrac/client.rb +206 -144
- data/lib/idrac/firmware.rb +38 -37
- data/lib/idrac/firmware_catalog.rb +32 -31
- data/lib/idrac/version.rb +1 -1
- data/test_firmware_update.rb +27 -29
- data/updater.rb +729 -0
- metadata +44 -1
data/lib/idrac/firmware.rb
CHANGED
@@ -6,6 +6,7 @@ require 'nokogiri'
|
|
6
6
|
require 'fileutils'
|
7
7
|
require 'securerandom'
|
8
8
|
require 'set'
|
9
|
+
require 'colorize'
|
9
10
|
require_relative 'firmware_catalog'
|
10
11
|
|
11
12
|
module IDRAC
|
@@ -126,30 +127,30 @@ module IDRAC
|
|
126
127
|
system_model = inventory[:system][:model]
|
127
128
|
service_tag = inventory[:system][:service_tag]
|
128
129
|
|
129
|
-
puts "Checking updates for system with service tag: #{service_tag}"
|
130
|
-
puts "Searching for updates for model: #{system_model}"
|
130
|
+
puts "Checking updates for system with service tag: #{service_tag}".light_cyan
|
131
|
+
puts "Searching for updates for model: #{system_model}".light_cyan
|
131
132
|
|
132
133
|
# Find system models in the catalog
|
133
134
|
models = catalog.find_system_models(system_model)
|
134
135
|
|
135
136
|
if models.empty?
|
136
|
-
puts "No matching system model found in catalog"
|
137
|
+
puts "No matching system model found in catalog".yellow
|
137
138
|
return []
|
138
139
|
end
|
139
140
|
|
140
141
|
# Use the first matching model
|
141
142
|
model = models.first
|
142
|
-
puts "Found system IDs for #{model[:name]}: #{model[:id]}"
|
143
|
+
puts "Found system IDs for #{model[:name]}: #{model[:id]}".green
|
143
144
|
|
144
145
|
# Find updates for this system
|
145
146
|
catalog_updates = catalog.find_updates_for_system(model[:id])
|
146
|
-
puts "Found #{catalog_updates.size} firmware updates for #{model[:name]}"
|
147
|
+
puts "Found #{catalog_updates.size} firmware updates for #{model[:name]}".green
|
147
148
|
|
148
149
|
# Compare current firmware with available updates
|
149
150
|
updates = []
|
150
151
|
|
151
152
|
# Print header for firmware comparison table
|
152
|
-
puts "\nFirmware Version Comparison:"
|
153
|
+
puts "\nFirmware Version Comparison:".green.bold
|
153
154
|
puts "=" * 100
|
154
155
|
puts "%-30s %-20s %-20s %-10s %-15s %s" % ["Component", "Current Version", "Available Version", "Updateable", "Category", "Status"]
|
155
156
|
puts "-" * 100
|
@@ -205,25 +206,25 @@ module IDRAC
|
|
205
206
|
fw[:name].to_s[0..29],
|
206
207
|
fw[:version],
|
207
208
|
update[:version],
|
208
|
-
fw[:updateable] ? "Yes" : "No",
|
209
|
+
fw[:updateable] ? "Yes".light_green : "No".light_red,
|
209
210
|
update[:category] || "N/A",
|
210
|
-
"UPDATE AVAILABLE"
|
211
|
+
"UPDATE AVAILABLE".light_green.bold
|
211
212
|
]
|
212
213
|
else
|
213
214
|
# Print row with no update needed
|
214
215
|
status = if !needs_update
|
215
|
-
"Current"
|
216
|
+
"Current".light_blue
|
216
217
|
elsif !fw[:updateable]
|
217
|
-
"Not updateable"
|
218
|
+
"Not updateable".light_red
|
218
219
|
else
|
219
|
-
"No update needed"
|
220
|
+
"No update needed".light_yellow
|
220
221
|
end
|
221
222
|
|
222
223
|
puts "%-30s %-20s %-20s %-10s %-15s %s" % [
|
223
224
|
fw[:name].to_s[0..29],
|
224
225
|
fw[:version],
|
225
226
|
update[:version] || "N/A",
|
226
|
-
fw[:updateable] ? "Yes" : "No",
|
227
|
+
fw[:updateable] ? "Yes".light_green : "No".light_red,
|
227
228
|
update[:category] || "N/A",
|
228
229
|
status
|
229
230
|
]
|
@@ -234,9 +235,9 @@ module IDRAC
|
|
234
235
|
fw[:name].to_s[0..29],
|
235
236
|
fw[:version],
|
236
237
|
"N/A",
|
237
|
-
fw[:updateable] ? "Yes" : "No",
|
238
|
+
fw[:updateable] ? "Yes".light_green : "No".light_red,
|
238
239
|
"N/A",
|
239
|
-
"No update available"
|
240
|
+
"No update available".light_yellow
|
240
241
|
]
|
241
242
|
end
|
242
243
|
end
|
@@ -261,11 +262,11 @@ module IDRAC
|
|
261
262
|
|
262
263
|
puts "%-30s %-20s %-20s %-10s %-15s %s" % [
|
263
264
|
update_name.to_s[0..29],
|
264
|
-
"Not Installed",
|
265
|
+
"Not Installed".light_red,
|
265
266
|
update[:version] || "Unknown",
|
266
267
|
"N/A",
|
267
268
|
update[:category] || "N/A",
|
268
|
-
"NEW COMPONENT"
|
269
|
+
"NEW COMPONENT".light_blue
|
269
270
|
]
|
270
271
|
end
|
271
272
|
|
@@ -278,13 +279,13 @@ module IDRAC
|
|
278
279
|
updates = selected_updates || check_updates(catalog_path)
|
279
280
|
|
280
281
|
if updates.empty?
|
281
|
-
puts "No updates available for your system."
|
282
|
+
puts "No updates available for your system.".yellow
|
282
283
|
return
|
283
284
|
end
|
284
285
|
|
285
|
-
puts "\nAvailable
|
286
|
+
puts "\nAvailable Updates:".green.bold
|
286
287
|
updates.each_with_index do |update, index|
|
287
|
-
puts "#{index + 1}. #{update[:name]}: #{update[:current_version]} -> #{update[:available_version]}"
|
288
|
+
puts "#{index + 1}. #{update[:name]}: #{update[:current_version]} -> #{update[:available_version]}".light_cyan
|
288
289
|
end
|
289
290
|
|
290
291
|
# If selected_updates is provided, use those directly
|
@@ -292,7 +293,7 @@ module IDRAC
|
|
292
293
|
selected = selected_updates
|
293
294
|
else
|
294
295
|
# Otherwise prompt the user for selection
|
295
|
-
puts "\nEnter the number of the update to install (or 'all' for all updates, 'q' to quit):"
|
296
|
+
puts "\nEnter the number of the update to install (or 'all' for all updates, 'q' to quit):".light_yellow
|
296
297
|
choice = STDIN.gets.chomp
|
297
298
|
|
298
299
|
return if choice.downcase == 'q'
|
@@ -304,14 +305,14 @@ module IDRAC
|
|
304
305
|
if index >= 0 && index < updates.size
|
305
306
|
[updates[index]]
|
306
307
|
else
|
307
|
-
puts "Invalid selection."
|
308
|
+
puts "Invalid selection.".red
|
308
309
|
return
|
309
310
|
end
|
310
311
|
end
|
311
312
|
end
|
312
313
|
|
313
314
|
selected.each do |update|
|
314
|
-
puts "Downloading #{update[:name]} version #{update[:available_version]}..."
|
315
|
+
puts "Downloading #{update[:name]} version #{update[:available_version]}...".light_cyan.bold
|
315
316
|
|
316
317
|
# Create temp directory
|
317
318
|
temp_dir = Dir.mktmpdir
|
@@ -332,33 +333,33 @@ module IDRAC
|
|
332
333
|
end
|
333
334
|
end
|
334
335
|
else
|
335
|
-
puts "Failed to download update: #{response.code} #{response.message}"
|
336
|
+
puts "Failed to download update: #{response.code} #{response.message}".red
|
336
337
|
next
|
337
338
|
end
|
338
339
|
end
|
339
340
|
end
|
340
341
|
|
341
|
-
puts "Installing #{update[:name]} version #{update[:available_version]}..."
|
342
|
+
puts "Installing #{update[:name]} version #{update[:available_version]}...".light_cyan.bold
|
342
343
|
|
343
344
|
begin
|
344
345
|
job_id = update(update_path, wait: true)
|
345
|
-
puts "Update completed with job ID: #{job_id}"
|
346
|
+
puts "Update completed with job ID: #{job_id}".green.bold
|
346
347
|
rescue IDRAC::Error => e
|
347
348
|
if e.message.include?("already in progress")
|
348
|
-
puts "Error: #{e.message}"
|
349
|
-
puts "\nTips for resolving this issue:"
|
350
|
-
puts "1. Wait for any existing firmware updates to complete (check iDRAC web interface)"
|
351
|
-
puts "2. Restart the iDRAC if no updates appear to be in progress (Settings > iDRAC Settings > Reset iDRAC)"
|
352
|
-
puts "3. Try again after a few minutes"
|
349
|
+
puts "Error: #{e.message}".red.bold
|
350
|
+
puts "\nTips for resolving this issue:".yellow.bold
|
351
|
+
puts "1. Wait for any existing firmware updates to complete (check iDRAC web interface)".light_yellow
|
352
|
+
puts "2. Restart the iDRAC if no updates appear to be in progress (Settings > iDRAC Settings > Reset iDRAC)".light_yellow
|
353
|
+
puts "3. Try again after a few minutes".light_yellow
|
353
354
|
elsif e.message.include?("job ID") || e.message.include?("job not found")
|
354
|
-
puts "Error: #{e.message}"
|
355
|
-
puts "\nThe job ID could not be found or monitored. This could be because:"
|
356
|
-
puts "1. The iDRAC is busy processing other requests"
|
357
|
-
puts "2. The job was created but not properly tracked"
|
358
|
-
puts "3. The iDRAC firmware may need to be updated first"
|
359
|
-
puts "\nCheck the iDRAC web interface to see if the update was actually initiated."
|
355
|
+
puts "Error: #{e.message}".red.bold
|
356
|
+
puts "\nThe job ID could not be found or monitored. This could be because:".yellow
|
357
|
+
puts "1. The iDRAC is busy processing other requests".light_yellow
|
358
|
+
puts "2. The job was created but not properly tracked".light_yellow
|
359
|
+
puts "3. The iDRAC firmware may need to be updated first".light_yellow
|
360
|
+
puts "\nCheck the iDRAC web interface to see if the update was actually initiated.".light_cyan
|
360
361
|
else
|
361
|
-
puts "Error during firmware update: #{e.message}"
|
362
|
+
puts "Error during firmware update: #{e.message}".red.bold
|
362
363
|
end
|
363
364
|
end
|
364
365
|
|
@@ -2,10 +2,13 @@ require 'net/http'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'fileutils'
|
4
4
|
require 'nokogiri'
|
5
|
+
require 'open-uri'
|
6
|
+
require 'colorize'
|
5
7
|
|
6
8
|
module IDRAC
|
7
9
|
class FirmwareCatalog
|
8
|
-
|
10
|
+
DELL_CATALOG_BASE = 'https://downloads.dell.com'
|
11
|
+
DELL_CATALOG_URL = "#{DELL_CATALOG_BASE}/catalog/Catalog.xml.gz"
|
9
12
|
|
10
13
|
attr_reader :catalog_path
|
11
14
|
|
@@ -14,40 +17,38 @@ module IDRAC
|
|
14
17
|
end
|
15
18
|
|
16
19
|
def download(output_dir = nil)
|
17
|
-
#
|
18
|
-
output_dir ||= File.expand_path(
|
20
|
+
# Default to ~/.idrac directory
|
21
|
+
output_dir ||= File.expand_path('~/.idrac')
|
19
22
|
FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir)
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
puts "Downloading Dell catalog from #{CATALOG_URL}..."
|
25
|
-
|
26
|
-
uri = URI.parse(CATALOG_URL)
|
27
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
28
|
-
request = Net::HTTP::Get.new(uri)
|
29
|
-
http.request(request) do |response|
|
30
|
-
if response.code == "200"
|
31
|
-
File.open(catalog_gz_path, 'wb') do |file|
|
32
|
-
response.read_body do |chunk|
|
33
|
-
file.write(chunk)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
else
|
37
|
-
raise Error, "Failed to download catalog: #{response.code} #{response.message}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
24
|
+
catalog_gz = File.join(output_dir, 'Catalog.xml.gz')
|
25
|
+
catalog_xml = File.join(output_dir, 'Catalog.xml')
|
41
26
|
|
42
|
-
puts "
|
43
|
-
system("gunzip -f #{catalog_gz_path}")
|
27
|
+
puts "Downloading Dell catalog from #{DELL_CATALOG_URL}...".light_cyan
|
44
28
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
29
|
+
begin
|
30
|
+
# Download the catalog
|
31
|
+
URI.open(DELL_CATALOG_URL) do |remote_file|
|
32
|
+
File.open(catalog_gz, 'wb') do |local_file|
|
33
|
+
local_file.write(remote_file.read)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "Extracting catalog...".light_cyan
|
38
|
+
|
39
|
+
# Extract the catalog
|
40
|
+
system("gunzip -f #{catalog_gz}")
|
41
|
+
|
42
|
+
if File.exist?(catalog_xml)
|
43
|
+
puts "Catalog downloaded and extracted to #{catalog_xml}".green
|
44
|
+
@catalog_path = catalog_xml
|
45
|
+
return catalog_xml
|
46
|
+
else
|
47
|
+
raise Error, "Failed to extract catalog"
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
puts "Error downloading catalog: #{e.message}".red.bold
|
51
|
+
raise Error, "Failed to download Dell catalog: #{e.message}"
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
data/lib/idrac/version.rb
CHANGED
data/test_firmware_update.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
require 'lib/idrac'
|
4
|
+
require 'colorize'
|
4
5
|
|
5
6
|
# Create a client
|
6
7
|
client = IDRAC::Client.new(
|
@@ -12,59 +13,56 @@ client = IDRAC::Client.new(
|
|
12
13
|
|
13
14
|
begin
|
14
15
|
# Login to iDRAC
|
16
|
+
puts "Logging in to iDRAC...".light_cyan
|
15
17
|
client.login
|
16
|
-
puts "Logged in successfully"
|
18
|
+
puts "Logged in successfully".green
|
17
19
|
|
18
20
|
# Create a firmware instance
|
19
21
|
firmware = IDRAC::Firmware.new(client)
|
20
22
|
|
21
23
|
# Get system inventory
|
22
|
-
puts "Getting system inventory..."
|
24
|
+
puts "Getting system inventory...".light_cyan
|
23
25
|
inventory = firmware.get_system_inventory
|
24
26
|
|
25
|
-
puts "System Information:"
|
26
|
-
puts " Model: #{inventory[:system][:model]}"
|
27
|
-
puts " Manufacturer: #{inventory[:system][:manufacturer]}"
|
28
|
-
puts " Service Tag: #{inventory[:system][:service_tag]}"
|
29
|
-
puts " BIOS Version: #{inventory[:system][:bios_version]}"
|
27
|
+
puts "System Information:".green.bold
|
28
|
+
puts " Model: #{inventory[:system][:model]}".light_cyan
|
29
|
+
puts " Manufacturer: #{inventory[:system][:manufacturer]}".light_cyan
|
30
|
+
puts " Service Tag: #{inventory[:system][:service_tag]}".light_cyan
|
31
|
+
puts " BIOS Version: #{inventory[:system][:bios_version]}".light_cyan
|
30
32
|
|
31
|
-
puts "\nInstalled Firmware:"
|
33
|
+
puts "\nInstalled Firmware:".green.bold
|
32
34
|
inventory[:firmware].each do |fw|
|
33
|
-
puts " #{fw[:name]}: #{fw[:version]} (#{fw[:updateable] ? 'Updateable' : 'Not Updateable'})"
|
35
|
+
puts " #{fw[:name]}: #{fw[:version]} (#{fw[:updateable] ? 'Updateable'.light_green : 'Not Updateable'.light_red})".light_cyan
|
34
36
|
end
|
35
37
|
|
36
38
|
# Check for updates
|
37
39
|
catalog_path = File.expand_path("~/.idrac/Catalog.xml")
|
38
40
|
if File.exist?(catalog_path)
|
39
|
-
puts "\nChecking for updates using catalog: #{catalog_path}"
|
41
|
+
puts "\nChecking for updates using catalog: #{catalog_path}".light_cyan
|
40
42
|
updates = firmware.check_updates(catalog_path)
|
41
43
|
|
42
|
-
if updates.
|
43
|
-
puts "
|
44
|
-
else
|
45
|
-
puts "\nAvailable Updates:"
|
44
|
+
if updates.any?
|
45
|
+
puts "\nAvailable Updates:".green.bold
|
46
46
|
updates.each_with_index do |update, index|
|
47
|
-
puts "#{index + 1}. #{update[:name]}: #{update[:current_version]} -> #{update[:available_version]}"
|
47
|
+
puts "#{index + 1}. #{update[:name]}: #{update[:current_version]} -> #{update[:available_version]}".light_cyan
|
48
48
|
end
|
49
49
|
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
firmware.interactive_update(catalog_path, [selected_update])
|
58
|
-
end
|
50
|
+
# Interactive update for the first update
|
51
|
+
puts "\nSelected update: #{updates.first[:name]}".light_yellow
|
52
|
+
puts "Starting interactive update for selected component...".light_cyan.bold
|
53
|
+
|
54
|
+
firmware.interactive_update(catalog_path, [updates.first])
|
55
|
+
else
|
56
|
+
puts "No updates available for your system.".yellow
|
59
57
|
end
|
60
58
|
else
|
61
|
-
puts "\nCatalog
|
59
|
+
puts "\nCatalog not found at #{catalog_path}. Run 'idrac firmware:catalog' to download it.".yellow
|
62
60
|
end
|
63
61
|
|
64
62
|
rescue IDRAC::Error => e
|
65
|
-
puts "Error: #{e.message}"
|
63
|
+
puts "Error: #{e.message}".red.bold
|
66
64
|
ensure
|
67
65
|
# Logout
|
68
|
-
client.logout if client
|
69
|
-
puts "Logged out"
|
66
|
+
client.logout if client
|
67
|
+
puts "Logged out".light_cyan
|
70
68
|
end
|