Skip to content

Instantly share code, notes, and snippets.

@perzizzle
Created March 29, 2019 16:33
Show Gist options
  • Select an option

  • Save perzizzle/893a53bf6b5d0babed2da3e6f7dda157 to your computer and use it in GitHub Desktop.

Select an option

Save perzizzle/893a53bf6b5d0babed2da3e6f7dda157 to your computer and use it in GitHub Desktop.
Some python for using the redfish api to apply firmware
# Inspired by https://github.com/dell/iDRAC-Redfish-Scripting/blob/master/Redfish%20Python/DeviceFirmwareDellUpdateServiceREDFISH.py
import requests
import json
import time
def main():
module = AnsibleModule(
argument_spec = dict(
idrac_hostname = dict(type='str', required=True),
idrac_username = dict(type='str', required=True),
idrac_password = dict(type='str', required=True, no_log=True),
firmware_file_path = dict(type='str', required=True),
firmware_image = dict(type='str', required=True),
install_option = dict(type='str', default="NowAndReboot", required=False),
),
supports_check_mode=False
)
idrac_hostname = module.params['idrac_hostname']
idrac_username = module.params['idrac_username']
idrac_password = module.params['idrac_password']
firmware_file_path = module.params['firmware_file_path']
firmware_image = module.params['firmware_image']
install_option = module.params['install_option']
changed = False
job_id = None
state = None
status = None
job_state = "unknown"
result = {'changed': changed, 'job_id': job_id}
def check_idrac_api_support(idrac_hostname, idrac_username, idrac_password):
url = 'https://{0}/redfish/v1/UpdateService/FirmwareInventory/'.format(idrac_hostname)
try:
response = requests.get(url, auth=(idrac_username, idrac_password), verify=False)
response.raise_for_status()
except Exception as e:
module.fail_json(msg=str(e))
#module.fail_json(msg="Current server {0} iDRAC version does not support Redfish firmware features".format(idrac_hostname))
def check_job_status(idrac_hostname, idrac_username, idrac_password, job_id):
state = None
status = None
job_state = None
url = 'https://{0}/redfish/v1/TaskService/Tasks/{1}'.format(idrac_hostname, job_id)
try:
response = requests.get(url, auth=(idrac_username, idrac_password), verify=False)
response.raise_for_status()
data = response.json()
state = data["TaskState"]
status = data["TaskStatus"]
job_state = data["Oem"]["Dell"]["JobState"]
# TaskState = [Pending, Completed, Completed with Errors, ... ]
# TaskStatus = [OK, Critical ...]
# JobState = [New, Scheduled]
if "failed" in data["Messages"] or "completed with errors" in data["Messages"]:
module.fail_json(msg="Job failed, current message is: {0}".format(data[u"Messages"]))
elif data["TaskState"] == "Completed":
done = True
elif data["TaskState"] == "Completed with Errors" or data["TaskState"] == "Failed":
module.fail_json(msg="Job failed, current message is: {0}".format(data["Messages"]))
except Exception as e:
module.fail_json(msg=str(e))
return state, status, job_state
def download_image_payload(idrac_hostname, idrac_username, idrac_password, firmware_file_path, firmware_filename):
url = 'https://{0}/redfish/v1/UpdateService/FirmwareInventory/'.format(idrac_hostname)
req = requests.get(url, auth=(idrac_username, idrac_password), verify=False)
etag = req.headers['ETag'] # TODO: what is etag?
image_path = "{0}/{1}".format(firmware_file_path, firmware_filename)
url = 'https://{0}/redfish/v1/UpdateService/FirmwareInventory'.format(idrac_hostname)
files = {'file': (firmware_filename, open(image_path, 'rb'), 'multipart/form-data')}
headers = {"if-match": etag}
try:
response = requests.post(url, files=files, auth=(idrac_username, idrac_password), verify=False, headers=headers)
response.raise_for_status()
firmware_version = response.json()['Id']
except Exception as e:
error = json.loads(response.text)
if error['error']['@Message.ExtendedInfo'][0]['Severity'] == 'Critical':
module.fail_json(msg="Failed to download image payload", error=response.text, exception = str(e.__class__.__name__))
location = response.headers['Location'] # TODO: why?
return location, firmware_version
def install_image_payload(idrac_hostname, idrac_username, idrac_password, install_option, location):
url = 'https://{0}/redfish/v1/UpdateService/Actions/Oem/DellUpdateService.Install'.format(idrac_hostname)
payload = {'SoftwareIdentityURIs': [location], 'InstallUpon': install_option}
headers = {'content-type': 'application/json'}
try:
response = requests.post(url, json=payload, auth = (idrac_username, idrac_password), verify=False, headers=headers)
response.raise_for_status()
job_id_location = response.headers['Location']
job_id = re.search("JID_.+",job_id_location).group()
except Exception as e:
module.fail_json(msg=str(e))
return job_id
check_idrac_api_support(idrac_hostname, idrac_username, idrac_password)
location, firmware_version = download_image_payload(idrac_hostname, idrac_username, idrac_password, firmware_file_path, firmware_image)
job_id = install_image_payload(idrac_hostname, idrac_username, idrac_password, install_option, location)
counter = 0
while job_state.lower() not in [ "scheduled", "completed"]:
state, status, job_state = check_job_status(idrac_hostname, idrac_username, idrac_password, job_id)
counter = counter + 1
time.sleep(10)
if counter > 30: # 5 minutes
module.fail_json(msg="Job state: {0} Job id: {1} has not been scheduled within 5 minutes ".format(job_state, job_id))
result['changed'] = True
result['job_id'] = str(job_id)
result['job_state'] = str(job_state)
module.exit_json(**result)
# import module snippets
from ansible.module_utils.basic import *
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment