Module: IDRAC::Lifecycle

Included in:
Client
Defined in:
lib/idrac/lifecycle.rb

Instance Method Summary collapse

Instance Method Details

#clear_lifecycle!Object

Clear the Lifecycle log



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/idrac/lifecycle.rb', line 205

def clear_lifecycle!
  path = '/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellLCService/Actions/DellLCService.SystemErase'
  payload = { "Component": ["LCData"] }
  
  response = authenticated_request(
    :post, 
    path, 
    body: payload.to_json, 
    headers: { 'Content-Type' => 'application/json' }
  )
  
  if response.status.between?(200, 299)
    debug "Lifecycle log cleared", 0, :green
    return true
  else
    debug "Failed to clear Lifecycle log", 0, :red
    
    error_message = "Failed to clear Lifecycle log. Status code: #{response.status}"
    
    begin
      error_data = JSON.parse(response.body)
      error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
    rescue
      # Ignore JSON parsing errors
    end
    
    raise Error, error_message
  end
end

#clear_system_event_logs!Object

Clear the system event logs



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/idrac/lifecycle.rb', line 261

def clear_system_event_logs!
  path = '/redfish/v1/Managers/iDRAC.Embedded.1/LogServices/Sel/Actions/LogService.ClearLog'
  
  response = authenticated_request(:post, path, body: {}.to_json, headers: { 'Content-Type' => 'application/json' })
  
  if response.status.between?(200, 299)
    debug "System Event Logs cleared", 0, :green
    return true
  else
    debug "Failed to clear System Event Logs", 0, :red
    
    error_message = "Failed to clear System Event Logs. Status code: #{response.status}"
    
    begin
      error_data = JSON.parse(response.body)
      error_message += ", Message: #{error_data['error']['message']}" if error_data['error'] && error_data['error']['message']
    rescue
      # Ignore JSON parsing errors
    end
    
    raise Error, error_message
  end
end

#ensure_lifecycle_controller!Object

Ensure the Lifecycle Controller is enabled



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/idrac/lifecycle.rb', line 186

def ensure_lifecycle_controller!
  if !get_lifecycle_status
    debug "Lifecycle Controller is disabled, enabling...".yellow, 1
    set_lifecycle_status(true)
    
    # Verify it was enabled
    if !get_lifecycle_status
      raise Error, "Failed to enable Lifecycle Controller"
    end
    
    debug "Lifecycle Controller successfully enabled".green, 1
  else
    debug "Lifecycle Controller is already enabled".green, 1
  end
  
  return true
end

#get_lifecycle_statusObject

This follows from these Scripts “GetIdracLcSystemAttributesREDFISH.py” and “SetIdracLcSystemAttributesREDFISH.py” They can do more than just the lifecycle, but that’s what we need right now. True or False if it’s enabled or not



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/idrac/lifecycle.rb', line 9

def get_lifecycle_status
  # Check iDRAC version first to determine the right approach
  idrac_version = get_idrac_version rescue 0
  
  debug "Detected iDRAC version: #{idrac_version}", 1
  
  # Use version-specific methods
  if idrac_version > 9
    debug "Using modern approach for iDRAC > 9", 1
    return get_lifecycle_status_modern_firmware
  elsif idrac_version == 9
    debug "Using registry approach for iDRAC 9", 1
    return get_lifecycle_status_from_registry
  else
    debug "Using SCP approach for older iDRAC (v#{idrac_version})", 1
    return get_lifecycle_status_from_scp
  end
end

#get_lifecycle_status_from_registryObject

Get lifecycle status from registry (for iDRAC 9)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/idrac/lifecycle.rb', line 66

def get_lifecycle_status_from_registry
  # This big JSON explains all the attributes:
  path = "/redfish/v1/Registries/ManagerAttributeRegistry/ManagerAttributeRegistry.v1_0_0.json"
  response = authenticated_request(:get, path)
  if response.status != 200
    debug "Failed to get any Lifecycle Controller Attributes".red, 1
    return false
  end
  attributes = JSON.parse(response.body)
  # This is the attribute we want:
  target = attributes&.dig('RegistryEntries', 'Attributes')&.find {|q| q['AttributeName'] =~ /LCAttributes.1.LifecycleControllerState/ }
  # This is the FQDN of the attribute we want to get the value of:
  fqdn = target.dig('Id')  # LifecycleController.Embedded.1#LCAttributes.1#LifecycleControllerState
  # This is the Current Value:
  response = authenticated_request(:get, "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/#{fqdn}")
  if response.status != 200
    debug "Failed to get Lifecycle Controller Attributes".red, 1
    return false
  end
  attributes = JSON.parse(response.body)
  # There is a ValueName and a Value Display Name (e.g. Enabled, Disabled, Recovery)
  display = attributes&.dig('Attributes','LCAttributes.1.LifecycleControllerState')
  value = target&.dig('Value')&.find { |v| v['ValueDisplayName'] == display }&.dig('ValueName')&.to_i
  value == 1
end

#get_lifecycle_status_from_scpObject

Get lifecycle status from SCP export (for older iDRAC firmware)



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/idrac/lifecycle.rb', line 29

def get_lifecycle_status_from_scp
  debug "Exporting System Configuration Profile to check LifecycleController state...", 1
  
  begin
    # Use the SCP export to get LifecycleController state
    scp = get_system_configuration_profile(target: "LifecycleController")
    
    # Check if we have data in the expected format
    if scp && scp["SystemConfiguration"] && scp["SystemConfiguration"]["Components"]
      # Find the LifecycleController component
      lc_component = scp["SystemConfiguration"]["Components"].find do |component|
        component["FQDD"] == "LifecycleController.Embedded.1"
      end
      
      if lc_component && lc_component["Attributes"]
        # Find the LifecycleControllerState attribute
        lc_state_attr = lc_component["Attributes"].find do |attr|
          attr["Name"] == "LCAttributes.1#LifecycleControllerState"
        end
        
        if lc_state_attr
          debug "Found LifecycleController state from SCP: #{lc_state_attr["Value"]}", 1
          return lc_state_attr["Value"] == "Enabled"
        end
      end
    end
    
    debug "Could not find LifecycleController state in SCP export", 1, :yellow
    return false
  rescue => e
    debug "Error getting Lifecycle Controller status from SCP: #{e.message}", 1, :red
    debug e.backtrace.join("\n"), 3, :red
    return false
  end
end

#get_lifecycle_status_modern_firmwareObject

Check if the Lifecycle Controller is enabled



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/idrac/lifecycle.rb', line 93

def get_lifecycle_status_modern_firmware
  # Try the standard Attributes endpoint first
  path = "/redfish/v1/Managers/iDRAC.Embedded.1/Attributes"
  response = authenticated_request(:get, path)
  
  if response.status == 200
    begin
      attributes_data = JSON.parse(response.body)
      if attributes_data["Attributes"] && attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
        lifecycle_state = attributes_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
        debug "Lifecycle Controller state (from Attributes): #{lifecycle_state}".light_cyan, 1
        return lifecycle_state == "Enabled"
      end
    rescue JSON::ParserError
      debug "Failed to parse Attributes response".yellow, 1
      # Fall through to registry method if parsing fails or attribute not found
    end
  else
    debug "Failed to get Attributes endpoint (Status: #{response.status}), trying registry method...".yellow, 1
  end
  
  # Try getting the DellAttributes for LifecycleController directly
  # The key insight is that we need to use just the base path without the fragment
  attributes_path = "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/LifecycleController.Embedded.1"
  attributes_response = authenticated_request(:get, attributes_path)
  
  if attributes_response.status == 200
    begin
      dell_attr_data = JSON.parse(attributes_response.body)
      if dell_attr_data["Attributes"] && dell_attr_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
        lifecycle_state = dell_attr_data["Attributes"]["LCAttributes.1.LifecycleControllerState"]
        debug "Lifecycle Controller state (from Dell Attributes): #{lifecycle_state}".light_cyan, 1
        return lifecycle_state == "Enabled"
      end
    rescue JSON::ParserError
      debug "Failed to parse Dell Attributes response".yellow, 1
      # Fall through to registry method if parsing fails or attribute not found
    end
  else
    debug "Failed to get Dell Attributes (Status: #{attributes_response.status}), trying registry method...".yellow, 1
  end
  
  # Fallback to the registry method if both Attributes endpoints fail
  registry_response = authenticated_request(
    :get,
    "/redfish/v1/Registries/ManagerAttributeRegistry/ManagerAttributeRegistry.v1_0_0.json"
  )
  
  if registry_response.status != 200                                                                                               
    debug "Failed to get Lifecycle Controller Attributes Registry", 0, :red                                                             
    return false                                                                                                         
  end
  
  begin
    registry_data = JSON.parse(registry_response.body)
    # This is the attribute we want:                                                                                       
    target = registry_data['RegistryEntries']['Attributes'].find {|q| q['AttributeName'] =~ /LCAttributes.1.LifecycleControllerState/ }
    if !target
      debug "Could not find LCAttributes.1.LifecycleControllerState in registry", 0, :red
      return false
    end
    
    debug "Found attribute in registry but couldn't access it via other endpoints".yellow, 1
    return false
  rescue JSON::ParserError, NoMethodError, StandardError => e
    debug "Error during registry access: #{e.message}", 0, :red
    return false
  end
end

#get_system_event_logsObject

Get the system event logs



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/idrac/lifecycle.rb', line 236

def get_system_event_logs
  path = '/redfish/v1/Managers/iDRAC.Embedded.1/Logs/Sel?$expand=*($levels=1)'
  
  response = authenticated_request(:get, path)
  
  if response.status == 200
    begin
      data = JSON.parse(response.body)['Members'].map do |entry|
          { 
            id: entry['Id'],
            created: entry['Created'],
            message: entry['Message'],
            severity: entry['Severity']
          }
        end
      return data # RecursiveOpenStruct.new(data, recurse_over_arrays: true)
    rescue JSON::ParserError
      raise Error, "Failed to parse system event logs response: #{response.body}"
    end
  else
    raise Error, "Failed to get system event logs. Status code: #{response.status}"
  end
end

#set_lifecycle_status(status) ⇒ Object

Set the Lifecycle Controller status (enable/disable)



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/idrac/lifecycle.rb', line 164

def set_lifecycle_status(status)                                                                                   
  payload = { "Attributes": { "LCAttributes.1.LifecycleControllerState": status ? 'Enabled' : 'Disabled' } }
  response = authenticated_request(
    :patch,
    "/redfish/v1/Managers/iDRAC.Embedded.1/Oem/Dell/DellAttributes/LifecycleController.Embedded.1",
    body: payload.to_json,
    headers: { 'Content-Type': 'application/json' }
  )
  
  code = response.status
  case code
  when 200..299
    debug "Lifecycle Controller is now #{status ? 'Enabled' : 'Disabled'}".green, 1                                          
  when 400..499
    debug "[#{code}] This iDRAC does not support Lifecycle Controller", 0, :red                                                
  when 500..599
    debug "[#{code}] iDRAC does not support Lifecycle Controller", 0, :red                                                     
  else
  end
end

#update_status_message(status) ⇒ Object

Updates the status message for the lifecycle controller



286
287
288
# File 'lib/idrac/lifecycle.rb', line 286

def update_status_message(status)
  debug "Lifecycle Controller is now #{status ? 'Enabled' : 'Disabled'}".green, 1
end