idrac 0.1.19 → 0.1.21
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 +14 -0
- data/bin/idrac +1 -3
- data/lib/idrac/client.rb +58 -150
- data/lib/idrac/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a32506a7e00919c067cf111bdb2cd7f2e3422302a93f2678512ffa8e17b46758
|
4
|
+
data.tar.gz: 7271bbbfcdca8616c4cb9c742c46a49213f314eaa0774e4dd2e31e189402ac49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3918c78519d1d10062a9efe2bf69988a038e6d82dc433478448901b12eeb55bdd1ba371ea1843309f6a2eba40c2eb80f8feb88dfa25f01e3e6811bca70039de8
|
7
|
+
data.tar.gz: a96828348048c1b281ed075f23d3baed1446206806085a87d4699a14879d186cc44dfc552bd1950c07517eb05fe0b6591b80f75822a4f44d778099e1cdfb8ca5
|
data/README.md
CHANGED
@@ -105,6 +105,20 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
105
105
|
|
106
106
|
## Changelog
|
107
107
|
|
108
|
+
### Version 0.1.21
|
109
|
+
- **Improved Authentication Flow**: Completely restructured the login process
|
110
|
+
- Renamed `legacy_login` to `webui_login` and limited its use to screenshot functionality only
|
111
|
+
- Implemented proper Redfish authentication flow: start with direct login to get a session
|
112
|
+
- Enhanced session management: when max sessions are encountered, delete sessions using direct login
|
113
|
+
- Simplified code by removing redundant authentication methods and focusing on Redfish standards
|
114
|
+
- Improved error handling and logging for better troubleshooting
|
115
|
+
|
116
|
+
### Version 0.1.20
|
117
|
+
- **Simplified CLI Interface**: Removed the direct-mode CLI option
|
118
|
+
- Maintained internal direct mode functionality as an automatic fallback mechanism
|
119
|
+
- The client will still automatically switch to direct mode when session management fails
|
120
|
+
- This change simplifies the user interface while preserving the robust session handling
|
121
|
+
|
108
122
|
### Version 0.1.19
|
109
123
|
- **Basic Auth Session Clearing**: Implemented direct session management using Basic Authentication
|
110
124
|
- Added ability to list and delete all active sessions without requiring a session
|
data/bin/idrac
CHANGED
@@ -19,7 +19,6 @@ module IDRAC
|
|
19
19
|
class_option :port, type: :numeric, default: 443, desc: "iDRAC port"
|
20
20
|
class_option :no_ssl, type: :boolean, default: false, desc: "Disable SSL"
|
21
21
|
class_option :verify_ssl, type: :boolean, default: false, desc: "Enable SSL verification (not recommended for iDRAC's self-signed certificates)"
|
22
|
-
class_option :direct_mode, type: :boolean, default: false, desc: "Use direct mode with Basic Auth instead of sessions (for environments with session limits)"
|
23
22
|
|
24
23
|
desc "firmware:update PATH", "Update firmware using the specified file"
|
25
24
|
method_option :wait, type: :boolean, default: true, desc: "Wait for the update to complete"
|
@@ -192,8 +191,7 @@ module IDRAC
|
|
192
191
|
password: options[:password],
|
193
192
|
port: options[:port],
|
194
193
|
use_ssl: !options[:no_ssl],
|
195
|
-
verify_ssl: options[:verify_ssl]
|
196
|
-
direct_mode: options[:direct_mode]
|
194
|
+
verify_ssl: options[:verify_ssl]
|
197
195
|
)
|
198
196
|
end
|
199
197
|
end
|
data/lib/idrac/client.rb
CHANGED
@@ -34,58 +34,18 @@ module IDRAC
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
# Force clear all sessions by
|
37
|
+
# Force clear all sessions by directly using Basic Auth
|
38
38
|
def force_clear_sessions
|
39
39
|
puts "Attempting to force clear all sessions..."
|
40
40
|
|
41
|
-
#
|
41
|
+
# Try to delete sessions directly using Basic Auth
|
42
42
|
if delete_all_sessions_with_basic_auth
|
43
43
|
puts "Successfully cleared sessions using Basic Auth"
|
44
44
|
return true
|
45
|
+
else
|
46
|
+
puts "Failed to clear sessions using Basic Auth"
|
47
|
+
return false
|
45
48
|
end
|
46
|
-
|
47
|
-
# If direct deletion fails, try the login/logout cycle approach
|
48
|
-
puts "Falling back to login/logout cycle approach for clearing sessions..."
|
49
|
-
|
50
|
-
# Try multiple login/logout cycles with both methods
|
51
|
-
3.times do |i|
|
52
|
-
begin
|
53
|
-
# Try Redfish session first
|
54
|
-
begin
|
55
|
-
if create_redfish_session
|
56
|
-
puts "Successfully created Redfish session (attempt #{i+1})"
|
57
|
-
delete_redfish_session
|
58
|
-
puts "Deleted Redfish session (attempt #{i+1})"
|
59
|
-
sleep(2)
|
60
|
-
end
|
61
|
-
rescue => e
|
62
|
-
puts "Error during Redfish session cycle: #{e.message}"
|
63
|
-
end
|
64
|
-
|
65
|
-
# Then try legacy session
|
66
|
-
begin
|
67
|
-
legacy_login(i)
|
68
|
-
puts "Successfully created legacy session (attempt #{i+1})"
|
69
|
-
legacy_logout
|
70
|
-
puts "Deleted legacy session (attempt #{i+1})"
|
71
|
-
sleep(2)
|
72
|
-
rescue => e
|
73
|
-
# If we get "maximum sessions" error, that's expected
|
74
|
-
if e.message.include?("maximum number of user sessions")
|
75
|
-
puts "Maximum sessions error during legacy login (expected during clearing)"
|
76
|
-
else
|
77
|
-
puts "Error during legacy session cycle: #{e.message}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Add a longer delay between cycles
|
82
|
-
sleep(3) if i < 2
|
83
|
-
rescue => e
|
84
|
-
puts "Error during session clearing cycle #{i+1}: #{e.message}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
puts "Completed session clearing attempts"
|
89
49
|
end
|
90
50
|
|
91
51
|
# Delete all sessions using Basic Authentication
|
@@ -158,19 +118,25 @@ module IDRAC
|
|
158
118
|
end
|
159
119
|
end
|
160
120
|
|
161
|
-
# Create a Redfish session
|
121
|
+
# Create a Redfish session
|
162
122
|
def create_redfish_session
|
163
|
-
# Skip if we're in direct mode
|
164
|
-
if @direct_mode
|
165
|
-
puts "Skipping Redfish session creation (direct mode
|
123
|
+
# Skip if we're in direct mode
|
124
|
+
if @direct_mode
|
125
|
+
puts "Skipping Redfish session creation (direct mode)"
|
166
126
|
return false
|
167
127
|
end
|
168
128
|
|
169
129
|
url = '/redfish/v1/SessionService/Sessions'
|
170
130
|
payload = { "UserName" => username, "Password" => password }
|
171
131
|
|
132
|
+
# Use Basic Auth for the initial session creation
|
133
|
+
basic_auth_headers = {
|
134
|
+
'Authorization' => "Basic #{Base64.strict_encode64("#{username}:#{password}")}",
|
135
|
+
'Content-Type' => 'application/json'
|
136
|
+
}
|
137
|
+
|
172
138
|
response = connection.post(url) do |req|
|
173
|
-
req.headers
|
139
|
+
req.headers.merge!(basic_auth_headers)
|
174
140
|
req.body = payload.to_json
|
175
141
|
end
|
176
142
|
|
@@ -188,14 +154,13 @@ module IDRAC
|
|
188
154
|
puts "Maximum sessions reached during Redfish session creation"
|
189
155
|
@sessions_maxed = true
|
190
156
|
|
191
|
-
#
|
192
|
-
if
|
193
|
-
|
194
|
-
force_clear_sessions
|
157
|
+
# Try to clear sessions
|
158
|
+
if force_clear_sessions
|
159
|
+
puts "Successfully cleared sessions, trying to create a new session"
|
195
160
|
|
196
161
|
# Try one more time after clearing
|
197
162
|
response = connection.post(url) do |req|
|
198
|
-
req.headers
|
163
|
+
req.headers.merge!(basic_auth_headers)
|
199
164
|
req.body = payload.to_json
|
200
165
|
end
|
201
166
|
|
@@ -212,7 +177,7 @@ module IDRAC
|
|
212
177
|
return false
|
213
178
|
end
|
214
179
|
else
|
215
|
-
|
180
|
+
puts "Failed to clear sessions, switching to direct mode"
|
216
181
|
@direct_mode = true
|
217
182
|
return false
|
218
183
|
end
|
@@ -244,24 +209,13 @@ module IDRAC
|
|
244
209
|
end
|
245
210
|
end
|
246
211
|
|
247
|
-
#
|
248
|
-
def
|
249
|
-
# Skip if we're in direct mode
|
250
|
-
if @direct_mode
|
251
|
-
puts "Skipping legacy login (direct mode)"
|
252
|
-
return false
|
253
|
-
end
|
254
|
-
|
212
|
+
# WebUI login method for screenshot functionality only
|
213
|
+
def webui_login(retry_count = 0)
|
255
214
|
# Limit retries to prevent infinite loops
|
256
215
|
if retry_count >= 3
|
257
|
-
|
258
|
-
@direct_mode = true
|
259
|
-
raise Error, "Failed to login after multiple attempts due to maximum sessions limit"
|
216
|
+
raise Error, "Failed to login to WebUI after multiple attempts"
|
260
217
|
end
|
261
218
|
|
262
|
-
# Always try to logout first to clear any existing sessions
|
263
|
-
legacy_logout if retry_count > 0
|
264
|
-
|
265
219
|
response = connection.post('/data/login') do |req|
|
266
220
|
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
267
221
|
req.body = "user=#{username}&password=#{password}"
|
@@ -282,13 +236,13 @@ module IDRAC
|
|
282
236
|
if error_message && !error_message.empty?
|
283
237
|
# Check for maximum sessions error
|
284
238
|
if error_message.include?("maximum number of user sessions")
|
285
|
-
puts "Maximum sessions reached, attempting to clear sessions (attempt #{retry_count + 1}/3)..."
|
286
|
-
# Try to clear any existing sessions
|
287
|
-
|
288
|
-
# Wait
|
289
|
-
sleep(
|
239
|
+
puts "Maximum sessions reached for WebUI, attempting to clear sessions (attempt #{retry_count + 1}/3)..."
|
240
|
+
# Try to clear any existing sessions
|
241
|
+
force_clear_sessions
|
242
|
+
# Wait for the server to process the session changes
|
243
|
+
sleep(3)
|
290
244
|
# Try logging in again with incremented retry counter
|
291
|
-
return
|
245
|
+
return webui_login(retry_count + 1)
|
292
246
|
end
|
293
247
|
|
294
248
|
raise Error, "Error Message: #{error_message}"
|
@@ -297,27 +251,21 @@ module IDRAC
|
|
297
251
|
forward_url = xml_doc.xpath('//forwardUrl').text
|
298
252
|
return forward_url
|
299
253
|
else
|
300
|
-
raise Error, "
|
254
|
+
raise Error, "WebUI login failed with status #{response.status}: #{response.body}"
|
301
255
|
end
|
302
256
|
end
|
303
257
|
|
304
|
-
#
|
305
|
-
def
|
258
|
+
# WebUI logout method for screenshot functionality
|
259
|
+
def webui_logout
|
306
260
|
return unless @session_id
|
307
261
|
|
308
262
|
begin
|
309
|
-
|
310
|
-
|
311
|
-
response = connection.get('/data/logout') do |req|
|
312
|
-
req.headers['Cookie'] = "sessionid=#{@session_id}"
|
313
|
-
end
|
314
|
-
|
315
|
-
break if response.status == 200
|
316
|
-
sleep(1) if i < 2 # Sleep between attempts, but not after the last one
|
263
|
+
response = connection.get('/data/logout') do |req|
|
264
|
+
req.headers['Cookie'] = "sessionid=#{@session_id}"
|
317
265
|
end
|
318
266
|
rescue => e
|
319
267
|
# Ignore errors during logout
|
320
|
-
puts "Warning: Error during logout: #{e.message}"
|
268
|
+
puts "Warning: Error during WebUI logout: #{e.message}"
|
321
269
|
ensure
|
322
270
|
@session_id = nil
|
323
271
|
@cookies = nil
|
@@ -326,7 +274,7 @@ module IDRAC
|
|
326
274
|
true
|
327
275
|
end
|
328
276
|
|
329
|
-
# Main login method
|
277
|
+
# Main login method
|
330
278
|
def login
|
331
279
|
# If we're in direct mode, skip login attempts
|
332
280
|
if @direct_mode
|
@@ -334,40 +282,29 @@ module IDRAC
|
|
334
282
|
return true
|
335
283
|
end
|
336
284
|
|
337
|
-
#
|
285
|
+
# Try to create a Redfish session
|
338
286
|
if create_redfish_session
|
339
287
|
return true
|
340
288
|
else
|
341
|
-
# If we failed to create a Redfish session
|
342
|
-
if
|
343
|
-
@tried_clearing_sessions = true
|
344
|
-
force_clear_sessions
|
345
|
-
|
346
|
-
# Try Redfish again
|
347
|
-
if create_redfish_session
|
348
|
-
return true
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
# Fall back to legacy login if Redfish session creation fails
|
353
|
-
if !@direct_mode
|
354
|
-
puts "Falling back to legacy login method"
|
355
|
-
return legacy_login
|
356
|
-
else
|
289
|
+
# If we failed to create a Redfish session and direct_mode is set, just return
|
290
|
+
if @direct_mode
|
357
291
|
puts "Operating in direct mode (no session)"
|
358
292
|
return true
|
293
|
+
else
|
294
|
+
# If we're here, something went wrong with session creation
|
295
|
+
raise Error, "Failed to create a session and direct mode is not enabled"
|
359
296
|
end
|
360
297
|
end
|
361
298
|
end
|
362
299
|
|
363
|
-
# Main logout method
|
300
|
+
# Main logout method
|
364
301
|
def logout
|
365
302
|
if @x_auth_token
|
366
303
|
delete_redfish_session
|
367
304
|
end
|
368
305
|
|
369
306
|
if @session_id
|
370
|
-
|
307
|
+
webui_logout
|
371
308
|
end
|
372
309
|
|
373
310
|
true
|
@@ -384,23 +321,15 @@ module IDRAC
|
|
384
321
|
# Ensure we have a valid session (unless in direct mode)
|
385
322
|
unless @direct_mode
|
386
323
|
begin
|
387
|
-
login unless @x_auth_token
|
324
|
+
login unless @x_auth_token
|
388
325
|
rescue Error => e
|
389
|
-
# If login fails
|
390
|
-
if
|
391
|
-
|
392
|
-
|
393
|
-
sleep(5) # Longer delay
|
394
|
-
return authenticated_request(method, path, options, retry_count + 1)
|
326
|
+
# If login fails and we've tried too many times, switch to direct mode
|
327
|
+
if retry_count >= 2
|
328
|
+
@direct_mode = true
|
329
|
+
puts "Switching to direct mode after multiple authentication failures"
|
395
330
|
else
|
396
|
-
#
|
397
|
-
|
398
|
-
@direct_mode = true
|
399
|
-
puts "Switching to direct mode after multiple authentication failures"
|
400
|
-
else
|
401
|
-
# Re-raise other errors or if we've tried too many times
|
402
|
-
raise
|
403
|
-
end
|
331
|
+
# Re-raise other errors
|
332
|
+
raise
|
404
333
|
end
|
405
334
|
end
|
406
335
|
end
|
@@ -410,9 +339,6 @@ module IDRAC
|
|
410
339
|
# Use X-Auth-Token if available (preferred Redfish method)
|
411
340
|
if @x_auth_token
|
412
341
|
options[:headers]['X-Auth-Token'] = @x_auth_token
|
413
|
-
elsif @session_id
|
414
|
-
# Fall back to session cookie if needed
|
415
|
-
options[:headers]['Cookie'] = "sessionid=#{@session_id}"
|
416
342
|
elsif @direct_mode
|
417
343
|
# In direct mode, use Basic Auth
|
418
344
|
options[:headers]['Authorization'] = "Basic #{Base64.strict_encode64("#{username}:#{password}")}"
|
@@ -427,15 +353,13 @@ module IDRAC
|
|
427
353
|
if response.status == 401 && !@direct_mode
|
428
354
|
puts "Session expired, re-authenticating..."
|
429
355
|
logout
|
430
|
-
sleep(
|
356
|
+
sleep(2)
|
431
357
|
login
|
432
358
|
|
433
359
|
# Update headers with new authentication
|
434
360
|
options[:headers] ||= {}
|
435
361
|
if @x_auth_token
|
436
362
|
options[:headers]['X-Auth-Token'] = @x_auth_token
|
437
|
-
elsif @session_id
|
438
|
-
options[:headers]['Cookie'] = "sessionid=#{@session_id}"
|
439
363
|
elsif @direct_mode
|
440
364
|
options[:headers]['Authorization'] = "Basic #{Base64.strict_encode64("#{username}:#{password}")}"
|
441
365
|
end
|
@@ -453,31 +377,13 @@ module IDRAC
|
|
453
377
|
end
|
454
378
|
end
|
455
379
|
|
456
|
-
# Check for maximum sessions error in the response
|
457
|
-
if response.status == 200
|
458
|
-
begin
|
459
|
-
xml_doc = Nokogiri::XML(response.body)
|
460
|
-
error_message = xml_doc.at_xpath('//errorMsg')&.text
|
461
|
-
|
462
|
-
if error_message && error_message.include?("maximum number of user sessions") && retry_count < 2
|
463
|
-
puts "Maximum sessions reached, clearing sessions and retrying (attempt #{retry_count + 1}/3)..."
|
464
|
-
logout
|
465
|
-
sleep(5)
|
466
|
-
login
|
467
|
-
return authenticated_request(method, path, options, retry_count + 1)
|
468
|
-
end
|
469
|
-
rescue => e
|
470
|
-
# If we can't parse the response as XML, just continue
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
380
|
response
|
475
381
|
end
|
476
382
|
|
477
383
|
def get(path:, headers: {})
|
478
|
-
# For screenshot functionality, we need to use the
|
479
|
-
if @cookies.nil? &&
|
480
|
-
|
384
|
+
# For screenshot functionality, we need to use the WebUI cookies
|
385
|
+
if @cookies.nil? && path.include?('screen/screen.jpg')
|
386
|
+
webui_login unless @session_id
|
481
387
|
end
|
482
388
|
|
483
389
|
headers_to_use = {
|
@@ -490,6 +396,8 @@ module IDRAC
|
|
490
396
|
elsif @direct_mode
|
491
397
|
# In direct mode, use Basic Auth
|
492
398
|
headers_to_use["Authorization"] = "Basic #{Base64.strict_encode64("#{username}:#{password}")}"
|
399
|
+
elsif @x_auth_token
|
400
|
+
headers_to_use["X-Auth-Token"] = @x_auth_token
|
493
401
|
end
|
494
402
|
|
495
403
|
response = HTTParty.get(
|
data/lib/idrac/version.rb
CHANGED