module IDRAC::SystemConfig
def get_system_configuration_profile(target: "RAID")
Get the system configuration profile for a given target (e.g. "RAID")
def get_system_configuration_profile(target: "RAID")
tries = 0
location = nil
started_at = Time.now
while location.nil?
debug "Exporting System Configuration try #{tries+=1}..."
response = authenticated_request(:post,
"/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager.ExportSystemConfiguration",
body: {"ExportFormat": "JSON", "ShareParameters":{"Target": target}}.to_json,
headers: {"Content-Type" => "application/json"}
)
if response.status == 400
debug "Failed exporting system configuration: #{response.body}", 1, :red
raise Error, "Failed exporting system configuration profile"
elsif response.status.between?(401, 599)
debug "Failed exporting system configuration: #{response.body}", 1, :red
# Parse error response
error_data = JSON.parse(response.body) rescue nil
if error_data && error_data["error"] && error_data["error"]["@Message.ExtendedInfo"]
message_info = error_data["error"]["@Message.ExtendedInfo"]
# Check for specific error conditions
if message_info.any? { |m| m["Message"] =~ /existing configuration job is already in progress/ }
debug "Existing configuration job is already in progress, retrying...", 1, :yellow
sleep 30
elsif message_info.any? { |m| m["Message"] =~ /job operation is already running/ }
debug "Existing job operation is already in progress, retrying...", 1, :yellow
sleep 60
else
# Detailed error info for debugging
debug "*" * 80, 1, :red
debug "Headers: #{response.headers.inspect}", 1, :red
debug "Body: #{response.body}", 1, :yellow
# Extract the first error message if available
error_message = message_info.first["Message"] rescue "Unknown error"
debug "Error: #{error_message}", 1, :red
raise Error, "Failed to export SCP: #{error_message}"
end
else
raise Error, "Failed to export SCP with status #{response.status}"
end
else
# Success path - extract location header
location = response.headers["location"]
if location.nil? || location.empty?
raise Error, "Empty location header in response: #{response.headers.inspect}"
end
end
# Progress reporting
minutes_elapsed = ((Time.now - started_at).to_f / 60).to_i
debug "Waiting for export to complete... #{minutes_elapsed} minutes", 1, :yellow
# Exponential backoff
sleep 2**[tries, 6].min # Cap at 64 seconds
if tries > 10
raise Error, "Failed exporting SCP after #{tries} tries, location: #{location}"
end
end
# Extract job ID from location
job_id = location.split("/").last
# Poll for job completion
job_complete = false
scp = nil
while !job_complete
job_response = authenticated_request(:get, "/redfish/v1/TaskService/Tasks/#{job_id}")
if job_response.status == 200
job_data = JSON.parse(job_response.body)
if ["Running", "Pending", "New"].include?(job_data["TaskState"])
debug "Job status: #{job_data["TaskState"]}, waiting...", 2
sleep 3
else
job_complete = true
scp = job_data
# Verify we have the system configuration data
unless scp["SystemConfiguration"]
raise Error, "Failed exporting SCP, taskstate: #{scp["TaskState"]}, taskstatus: #{scp["TaskStatus"]}"
end
end
else
raise Error, "Failed to check job status: #{job_response.status} - #{job_response.body}"
end
end
return scp
end
def set_scp_attribute(scp, name, value)
Set an attribute in a system configuration profile
def set_scp_attribute(scp, name, value)
# Make a deep copy to avoid modifying the original
scp_copy = JSON.parse(scp.to_json)
# Clear unrelated attributes for quicker transfer
scp_copy["SystemConfiguration"].delete("Comments")
scp_copy["SystemConfiguration"].delete("TimeStamp")
scp_copy["SystemConfiguration"].delete("ServiceTag")
scp_copy["SystemConfiguration"].delete("Model")
# Skip these attribute groups to make the transfer faster
excluded_prefixes = [
"User", "Telemetry", "SecurityCertificate", "AutoUpdate", "PCIe", "LDAP", "ADGroup", "ActiveDirectory",
"IPMILan", "EmailAlert", "SNMP", "IPBlocking", "IPMI", "Security", "RFS", "OS-BMC", "SupportAssist",
"Redfish", "RedfishEventing", "Autodiscovery", "SEKM-LKC", "Telco-EdgeServer", "8021XSecurity", "SPDM",
"InventoryHash", "RSASecurID2FA", "USB", "NIC", "IPv6", "NTP", "Logging", "IOIDOpt", "SSHCrypto",
"RemoteHosts", "SysLog", "Time", "SmartCard", "ACME", "ServiceModule", "Lockdown",
"DefaultCredentialMitigation", "AutoOSLockGroup", "LocalSecurity", "IntegratedDatacenter",
"SecureDefaultPassword.1#ForceChangePassword", "SwitchConnectionView.1#Enable", "GroupManager.1",
"ASRConfig.1#Enable", "SerialCapture.1#Enable", "CertificateManagement.1",
"Update", "SSH", "SysInfo", "GUI"
]
# Remove excluded attribute groups
if scp_copy["SystemConfiguration"]["Components"] &&
scp_copy["SystemConfiguration"]["Components"][0] &&
scp_copy["SystemConfiguration"]["Components"][0]["Attributes"]
attrs = scp_copy["SystemConfiguration"]["Components"][0]["Attributes"]
attrs.reject! do |attr|
excluded_prefixes.any? { |prefix| attr["Name"] =~ /\A#{prefix}/ }
end
# Update or add the specified attribute
if attrs.find { |a| a["Name"] == name }.nil?
# Attribute doesn't exist, create it
attrs << { "Name" => name, "Value" => value, "Set On Import" => "True" }
else
# Update existing attribute
attrs.find { |a| a["Name"] == name }["Value"] = value
attrs.find { |a| a["Name"] == name }["Set On Import"] = "True"
end
scp_copy["SystemConfiguration"]["Components"][0]["Attributes"] = attrs
end
return scp_copy
end