idrac 0.1.91 → 0.3.1

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.
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add ActiveSupport-like blank? method to core Ruby classes
4
+ # This allows us to use blank? without requiring Rails' ActiveSupport
5
+
6
+ class NilClass
7
+ # nil is always blank
8
+ def blank?
9
+ true
10
+ end
11
+ end
12
+
13
+ class String
14
+ # A string is blank if it's empty or contains whitespace only
15
+ def blank?
16
+ strip.empty?
17
+ end
18
+ end
19
+
20
+ class Array
21
+ # An array is blank if it's empty
22
+ def blank?
23
+ empty?
24
+ end
25
+ end
26
+
27
+ class Hash
28
+ # A hash is blank if it's empty
29
+ def blank?
30
+ empty?
31
+ end
32
+ end
33
+
34
+ class Object
35
+ # An object is blank if it responds to empty? and is empty
36
+ # Otherwise return false
37
+ def blank?
38
+ respond_to?(:empty?) ? empty? : false
39
+ end
40
+ end
41
+
42
+ # Add ActiveSupport-like numeric extensions
43
+ class Integer
44
+ # Byte size helpers
45
+ def byte
46
+ self
47
+ end
48
+ alias_method :bytes, :byte
49
+
50
+ def kilobyte
51
+ self * 1024
52
+ end
53
+ alias_method :kilobytes, :kilobyte
54
+
55
+ def megabyte
56
+ self * 1024 * 1024
57
+ end
58
+ alias_method :megabytes, :megabyte
59
+
60
+ def gigabyte
61
+ self * 1024 * 1024 * 1024
62
+ end
63
+ alias_method :gigabytes, :gigabyte
64
+
65
+ def terabyte
66
+ self * 1024 * 1024 * 1024 * 1024
67
+ end
68
+ alias_method :terabytes, :terabyte
69
+
70
+ def petabyte
71
+ self * 1024 * 1024 * 1024 * 1024 * 1024
72
+ end
73
+ alias_method :petabytes, :petabyte
74
+
75
+ # Time duration helpers (for potential future use)
76
+ def second
77
+ self
78
+ end
79
+ alias_method :seconds, :second
80
+
81
+ def minute
82
+ self * 60
83
+ end
84
+ alias_method :minutes, :minute
85
+
86
+ def hour
87
+ self * 60 * 60
88
+ end
89
+ alias_method :hours, :hour
90
+
91
+ def day
92
+ self * 24 * 60 * 60
93
+ end
94
+ alias_method :days, :day
95
+
96
+ def week
97
+ self * 7 * 24 * 60 * 60
98
+ end
99
+ alias_method :weeks, :week
100
+ end
@@ -3,221 +3,113 @@ require 'colorize'
3
3
 
4
4
  module IDRAC
5
5
  module LifecycleMethods
6
- # Get the Lifecycle Controller status
6
+ # Check if the Lifecycle Controller is enabled
7
7
  def get_lifecycle_status
8
- # Try first method (older iDRACs)
9
- path1 = '/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.GetRemoteServicesAPIStatus'
8
+ # Try the standard Attributes endpoint first
9
+ path = "/redfish/v1/Managers/iDRAC.Embedded.1/Attributes"
10
+ response = authenticated_request(:get, path)
10
11
 
11
- begin
12
- response = authenticated_request(
13
- :post,
14
- path1,
15
- body: {}.to_json,
16
- headers: { 'Content-Type' => 'application/json' }
17
- )
18
-
19
- if response.status.between?(200, 299)
20
- begin
21
- lc_data = JSON.parse(response.body)
22
- puts "LC Status: #{lc_data['LCStatus']}".light_cyan
23
- return lc_data
24
- rescue JSON::ParserError
25
- # Fall through to alternative method
12
+ if response.status == 200
13
+ begin
14
+ attributes_data = JSON.parse(response.body)
15
+ if attributes_data["Attributes"] && attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
16
+ lifecycle_state = attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
17
+ debug "Lifecycle Controller state (from Attributes): #{lifecycle_state}".light_cyan, 1
18
+ return lifecycle_state == "Enabled"
26
19
  end
20
+ rescue JSON::ParserError
21
+ debug "Failed to parse Attributes response".yellow, 1
22
+ # Fall through to registry method if parsing fails or attribute not found
27
23
  end
28
- rescue => e
29
- # Fall through to alternative method
24
+ else
25
+ debug "Failed to get Attributes endpoint (Status: #{response.status}), trying registry method...".yellow, 1
30
26
  end
31
27
 
32
- # Try alternative method (newer iDRACs)
33
- path2 = '/redfish/v1/Managers/iDRAC.Embedded.1/Attributes'
28
+ # Try getting the DellAttributes for LifecycleController directly
29
+ # The key insight is that we need to use just the base path without the fragment
30
+ attributes_path = "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/LifecycleController.Embedded.1"
31
+ attributes_response = authenticated_request(:get, attributes_path)
34
32
 
35
- begin
36
- response = authenticated_request(:get, path2)
37
-
38
- if response.status.between?(200, 299)
39
- begin
40
- attributes_data = JSON.parse(response.body)
41
-
42
- if attributes_data["Attributes"] && attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
43
- lifecycle_state = attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
44
- puts "Lifecycle Controller state: #{lifecycle_state}".light_cyan
45
- return { "LCStatus" => lifecycle_state }
46
- end
47
- rescue JSON::ParserError
48
- # Fall through to final error
49
- end
50
- end
51
- rescue => e
52
- # Fall through to final error
53
- end
54
-
55
- # If we get here, try one last approach - try to get iDRAC status
56
- begin
57
- response = authenticated_request(:get, '/redfish/v1/Managers/iDRAC.Embedded.1')
58
-
59
- if response.status.between?(200, 299)
60
- begin
61
- data = JSON.parse(response.body)
62
- status = data["Status"] && data["Status"]["State"]
63
- if status
64
- puts "iDRAC State: #{status}".light_cyan
65
- puts "Note: Could not retrieve direct LC status, showing iDRAC status instead".yellow
66
- return { "iDRACStatus" => status }
67
- end
68
- rescue JSON::ParserError
69
- # Fall through to final error
33
+ if attributes_response.status == 200
34
+ begin
35
+ dell_attr_data = JSON.parse(attributes_response.body)
36
+ if dell_attr_data["Attributes"] && dell_attr_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
37
+ lifecycle_state = dell_attr_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
38
+ debug "Lifecycle Controller state (from Dell Attributes): #{lifecycle_state}".light_cyan, 1
39
+ return lifecycle_state == "Enabled"
70
40
  end
41
+ rescue JSON::ParserError
42
+ debug "Failed to parse Dell Attributes response".yellow, 1
43
+ # Fall through to registry method if parsing fails or attribute not found
71
44
  end
72
- rescue => e
73
- # Fall through to final error
45
+ else
46
+ debug "Failed to get Dell Attributes (Status: #{attributes_response.status}), trying registry method...".yellow, 1
74
47
  end
75
-
76
- # If we reached here, all methods failed
77
- puts "Unable to retrieve Lifecycle Controller status through any available method".red
78
- raise Error, "Failed to get Lifecycle Controller status through any available method"
79
- end
80
-
81
- # Check if the Lifecycle Controller is enabled
82
- def get_idrac_lifecycle_status
83
- # Use the DellLCService GetRemoteServicesAPIStatus
84
- path = '/redfish/v1/Dell/Managers/iDRAC.Embedded.1/DellLCService/Actions/DellLCService.GetRemoteServicesAPIStatus'
85
48
 
86
- response = authenticated_request(
87
- :post,
88
- path,
89
- body: {}.to_json,
90
- headers: { 'Content-Type' => 'application/json' }
49
+ # Fallback to the registry method if both Attributes endpoints fail
50
+ registry_response = authenticated_request(
51
+ :get,
52
+ "/redfish/v1/Registries/ManagerAttributeRegistry/ManagerAttributeRegistry.v1_0_0.json"
91
53
  )
92
54
 
93
- if response.status.between?(200, 299)
94
- begin
95
- lc_data = JSON.parse(response.body)
96
- status = lc_data["LCStatus"]
97
-
98
- debug "LC Status: #{status}", 1
99
-
100
- # Get the LCReplication status
101
- attributes_path = "/redfish/v1/Managers/iDRAC.Embedded.1/Attributes"
102
- attributes_response = authenticated_request(:get, attributes_path)
103
-
104
- if attributes_response.status == 200
105
- begin
106
- attributes_data = JSON.parse(attributes_response.body)
107
- lc_replication = attributes_data["Attributes"]["ServiceModule.1.LCLReplication"]
108
-
109
- debug "ServiceModule.1.LCLReplication: #{lc_replication}", 1
110
-
111
- is_enabled = lc_replication == "Enabled"
112
-
113
- puts "Lifecycle Controller replication is #{is_enabled ? 'enabled' : 'disabled'}".light_cyan
114
- puts "Lifecycle Controller status: #{status}".light_cyan
115
- return is_enabled
116
- rescue => e
117
- debug "Error parsing attributes: #{e.message}", 1
118
- end
119
- end
120
-
121
- # If we can't determine from attributes, just return if LC is Ready
122
- is_ready = status == "Ready"
123
- puts "Lifecycle Controller is #{is_ready ? 'Ready' : status}".light_cyan
124
- return is_ready
125
- rescue JSON::ParserError
126
- raise Error, "Failed to parse Lifecycle Controller status response: #{response.body}"
55
+ if registry_response.status != 200
56
+ debug "Failed to get Lifecycle Controller Attributes Registry", 0, :red
57
+ return false
58
+ end
59
+
60
+ begin
61
+ registry_data = JSON.parse(registry_response.body)
62
+ # This is the attribute we want:
63
+ target = registry_data['RegistryEntries']['Attributes'].find {|q| q['AttributeName'] =~ /LCAttributes.1.LifecycleControllerState/ }
64
+ if !target
65
+ debug "Could not find LCAttributes.1.LifecycleControllerState in registry", 0, :red
66
+ return false
127
67
  end
128
- else
129
- raise Error, "Failed to get Lifecycle Controller status. Status code: #{response.status}"
68
+
69
+ debug "Found attribute in registry but couldn't access it via other endpoints".yellow, 1
70
+ return false
71
+ rescue JSON::ParserError, NoMethodError, StandardError => e
72
+ debug "Error during registry access: #{e.message}", 0, :red
73
+ return false
130
74
  end
131
75
  end
132
76
 
133
77
  # Set the Lifecycle Controller status (enable/disable)
134
- def set_idrac_lifecycle_status(status)
135
- enabled = !!status # Convert to boolean
136
-
137
- debug "Setting Lifecycle Controller status to #{enabled ? 'enabled' : 'disabled'}", 1
138
-
139
- # Use the attributes method to set the ServiceModule.1.LCLReplication
140
- path = "/redfish/v1/Managers/iDRAC.Embedded.1/Attributes"
141
-
142
- # Create the payload with the attribute we want to modify
143
- payload = {
144
- "Attributes": {
145
- "ServiceModule.1.LCLReplication": enabled ? "Enabled" : "Disabled"
146
- }
147
- }
148
-
149
- debug "Using attributes endpoint: #{path}", 1
150
- debug "Payload: #{payload.inspect}", 1
78
+ def set_lifecycle_status(status)
79
+ payload = { "Attributes": { "LCAttributes.1.LifecycleControllerState": status ? 'Enabled' : 'Disabled' } }
80
+ response = authenticated_request(
81
+ :patch,
82
+ "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/LifecycleController.Embedded.1",
83
+ body: payload.to_json,
84
+ headers: { 'Content-Type': 'application/json' }
85
+ )
151
86
 
152
- begin
153
- response = authenticated_request(
154
- :patch,
155
- path,
156
- body: payload.to_json,
157
- headers: { 'Content-Type' => 'application/json' }
158
- )
159
-
160
- debug "Response status: #{response.status}", 1
161
- debug "Response body: #{response.body}", 2 if response.body
162
-
163
- if response.status.between?(200, 299)
164
- puts "Successfully #{enabled ? 'enabled' : 'disabled'} Lifecycle Controller".green
165
- return true
166
- else
167
- error_message = "Failed to set Lifecycle Controller status. Status code: #{response.status}"
168
-
169
- # Print the full response body for debugging
170
- puts "Full error response body:".red
171
- puts response.body.inspect.red
172
-
173
- begin
174
- error_data = JSON.parse(response.body)
175
- puts "Extended error information:".red if error_data['@Message.ExtendedInfo']
176
-
177
- if error_data['error'] && error_data['error']['message']
178
- error_message += ", Message: #{error_data['error']['message']}"
179
- end
180
-
181
- if error_data['@Message.ExtendedInfo']
182
- error_data['@Message.ExtendedInfo'].each do |info|
183
- puts " Message: #{info['Message']}".red
184
- puts " Resolution: #{info['Resolution']}".yellow if info['Resolution']
185
- puts " Severity: #{info['Severity']}".yellow if info['Severity']
186
- puts " MessageId: #{info['MessageId']}".yellow if info['MessageId']
187
- end
188
-
189
- if error_data['@Message.ExtendedInfo'].first
190
- error_message += ", Message: #{error_data['@Message.ExtendedInfo'].first['Message']}"
191
- error_message += ", Resolution: #{error_data['@Message.ExtendedInfo'].first['Resolution']}" if error_data['@Message.ExtendedInfo'].first['Resolution']
192
- end
193
- end
194
- rescue => e
195
- debug "Error parsing response: #{e.message}", 1
196
- # Ignore JSON parsing errors
197
- end
198
-
199
- raise Error, error_message
200
- end
201
- rescue => e
202
- debug "Error in request: #{e.message}", 1
203
- raise Error, "Failed to set Lifecycle Controller status: #{e.message}"
87
+ code = response.status
88
+ case code
89
+ when 200..299
90
+ debug "Lifecycle Controller is now #{status ? 'Enabled' : 'Disabled'}".green, 1
91
+ when 400..499
92
+ debug "[#{code}] This iDRAC does not support Lifecycle Controller", 0, :red
93
+ when 500..599
94
+ debug "[#{code}] iDRAC does not support Lifecycle Controller", 0, :red
95
+ else
204
96
  end
205
97
  end
206
98
 
207
99
  # Ensure the Lifecycle Controller is enabled
208
100
  def ensure_lifecycle_controller!
209
- if !get_idrac_lifecycle_status
210
- puts "Lifecycle Controller is disabled, enabling...".yellow
211
- set_idrac_lifecycle_status(true)
101
+ if !get_lifecycle_status
102
+ debug "Lifecycle Controller is disabled, enabling...".yellow, 1
103
+ set_lifecycle_status(true)
212
104
 
213
105
  # Verify it was enabled
214
- if !get_idrac_lifecycle_status
106
+ if !get_lifecycle_status
215
107
  raise Error, "Failed to enable Lifecycle Controller"
216
108
  end
217
109
 
218
- puts "Lifecycle Controller successfully enabled".green
110
+ debug "Lifecycle Controller successfully enabled".green, 1
219
111
  else
220
- puts "Lifecycle Controller is already enabled".green
112
+ debug "Lifecycle Controller is already enabled".green, 1
221
113
  end
222
114
 
223
115
  return true
@@ -236,10 +128,10 @@ module IDRAC
236
128
  )
237
129
 
238
130
  if response.status.between?(200, 299)
239
- puts "Lifecycle log cleared".green
131
+ debug "Lifecycle log cleared", 0, :green
240
132
  return true
241
133
  else
242
- puts "Failed to clear Lifecycle log".red
134
+ debug "Failed to clear Lifecycle log", 0, :red
243
135
 
244
136
  error_message = "Failed to clear Lifecycle log. Status code: #{response.status}"
245
137
 
@@ -279,10 +171,10 @@ module IDRAC
279
171
  response = authenticated_request(:post, path, body: {}.to_json, headers: { 'Content-Type' => 'application/json' })
280
172
 
281
173
  if response.status.between?(200, 299)
282
- puts "System Event Logs cleared".green
174
+ debug "System Event Logs cleared", 0, :green
283
175
  return true
284
176
  else
285
- puts "Failed to clear System Event Logs".red
177
+ debug "Failed to clear System Event Logs", 0, :red
286
178
 
287
179
  error_message = "Failed to clear System Event Logs. Status code: #{response.status}"
288
180
 
@@ -296,5 +188,10 @@ module IDRAC
296
188
  raise Error, error_message
297
189
  end
298
190
  end
191
+
192
+ # Updates the status message for the lifecycle controller
193
+ def update_status_message(status)
194
+ debug "Lifecycle Controller is now #{status ? 'Enabled' : 'Disabled'}".green, 1
195
+ end
299
196
  end
300
197
  end