Add DellEMC iDRAC Firmware module (#46675)

Co-Authored-By: rajeevarakkal <36444805+rajeevarakkal@users.noreply.github.com>
Co-Authored-By: Sviatoslav Sydorenko <578543+webknjaz@users.noreply.github.com>
This commit is contained in:
rajeevarakkal 2018-12-11 21:08:01 +05:30 committed by Sviatoslav Sydorenko
parent c9040d7579
commit 62b2a08cfb
6 changed files with 269 additions and 0 deletions

3
.github/BOTMETA.yml vendored
View file

@ -310,6 +310,7 @@ files:
$modules/remote_management/redfish/: $team_redfish
$modules/remote_management/stacki/stacki_host.py: bbyhuy bsanders
$modules/remote_management/ucs/: $team_ucs
$modules/remote_management/dellemc/: rajeevarakkal
$modules/source_control/git.py: $team_ansible
$modules/source_control/github_key.py:
ignored: erydo
@ -623,6 +624,8 @@ files:
$module_utils/remote_management/ucs:
maintainers: $team_ucs
labels: ucs
$module_utils/remote_management/dellemc:
maintainers: rajeevarakkal
$module_utils/pure.py:
maintainers: $team_purestorage
labels: pure_storage

View file

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
#
# Dell EMC OpenManage Ansible Modules
# Version 1.0
# Copyright (C) 2018 Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# All rights reserved. Dell, EMC, and other trademarks are trademarks of Dell Inc. or its subsidiaries.
# Other trademarks may be trademarks of their respective owners.
#
from __future__ import (absolute_import, division,
print_function)
__metaclass__ = type
try:
from omsdk.sdkinfra import sdkinfra
from omsdk.sdkcreds import UserCredentials
from omsdk.sdkfile import FileOnShare, file_share_manager
from omsdk.sdkprotopref import ProtoPreference, ProtocolEnum
from omsdk.http.sdkwsmanbase import WsManOptions
HAS_OMSDK = True
except ImportError:
HAS_OMSDK = False
class iDRACConnection:
def __init__(self, module_params):
if not HAS_OMSDK:
raise ImportError("Dell EMC OMSDK library is required for this module")
self.idrac_ip = module_params['idrac_ip']
self.idrac_user = module_params['idrac_user']
self.idrac_pwd = module_params['idrac_pwd']
self.idrac_port = module_params['idrac_port']
if not all((self.idrac_ip, self.idrac_user, self.idrac_pwd)):
raise ValueError("hostname, username and password required")
self.handle = None
self.creds = UserCredentials(self.idrac_user, self.idrac_pwd)
self.pOp = WsManOptions(port=self.idrac_port)
self.sdk = sdkinfra()
if self.sdk is None:
msg = "Could not initialize iDRAC drivers."
raise RuntimeError(msg)
def __enter__(self):
self.sdk.importPath()
self.handle = self.sdk.get_driver(self.sdk.driver_enum.iDRAC, self.idrac_ip, self.creds, pOptions=self.pOp)
if self.handle is None:
msg = "Could not find device driver for iDRAC with IP Address: {0}".format(self.idrac_ip)
raise RuntimeError(msg)
return self.handle
def __exit__(self, exc_type, exc_val, exc_tb):
self.handle.disconnect()
return False

View file

@ -0,0 +1,209 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Dell EMC OpenManage Ansible Modules
# Version 1.0
# Copyright (C) 2018 Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# All rights reserved. Dell, EMC, and other trademarks are trademarks of Dell Inc. or its subsidiaries.
# Other trademarks may be trademarks of their respective owners.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = """
---
module: dellemc_idrac_firmware
short_description: Firmware update from a repository on a network share (CIFS, NFS).
version_added: "2.8"
description:
- Update the Firmware by connecting to a network share (either CIFS or NFS) that contains a catalog of
available updates.
- Network share should contain a valid repository of Update Packages (DUPs) and a catalog file describing the DUPs.
- All applicable updates contained in the repository are applied to the system.
- This feature is available only with iDRAC Enterprise License.
options:
idrac_ip:
required: True
description: iDRAC IP Address.
idrac_user:
required: True
description: iDRAC username.
idrac_pwd:
required: True
description: iDRAC user password.
idrac_port:
required: False
description: iDRAC port.
default: 443
share_name:
required: True
description: CIFS or NFS Network share.
share_user:
required: False
description: Network share user in the format 'user@domain' or 'domain\\user' if user is
part of a domain else 'user'. This option is mandatory for CIFS Network Share.
share_pwd:
required: False
description: Network share user password. This option is mandatory for CIFS Network Share.
share_mnt:
required: True
description: Local mount path of the network share with read-write permission for ansible user.
This option is mandatory for Network Share.
reboot:
required: False
description: Whether to reboots after applying the updates or not.
default: False
type: bool
job_wait:
required: False
description: Whether to wait for job completion or not.
type: bool
default: True
catalog_file_name:
required: False
description: Catalog file name relative to the I(share_name).
type: str
default: 'Catalog.xml'
requirements:
- "omsdk"
- "python >= 2.7.5"
author: "Rajeev Arakkal (@rajeevarakkal)"
"""
EXAMPLES = """
---
- name: Update firmware from repository on a Network Share
dellemc_idrac_firmware:
idrac_ip: "192.168.0.1"
idrac_user: "user_name"
idrac_pwd: "user_pwd"
share_name: "192.168.0.0:/share"
share_user: "share_user_name"
share_pwd: "share_user_pwd"
share_mnt: "/mnt/share"
reboot: True
job_wait: True
catalog_file_name: "Catalog.xml"
"""
RETURN = """
---
msg:
type: string
description: Over all firmware update status.
returned: always
sample: "Successfully updated the firmware."
update_status:
type: dict
description: Firmware Update job and progress details from the iDRAC.
returned: success
sample: {
'InstanceID': 'JID_XXXXXXXXXXXX',
'JobState': 'Completed',
'Message': 'Job completed successfully.',
'MessageId': 'REDXXX',
'Name': 'Repository Update',
'JobStartTime': 'NA',
'Status': 'Success',
}
"""
from ansible.module_utils.remote_management.dellemc.dellemc_idrac import iDRACConnection
from ansible.module_utils.basic import AnsibleModule
try:
from omsdk.sdkcreds import UserCredentials
from omsdk.sdkfile import FileOnShare
HAS_OMSDK = True
except ImportError:
HAS_OMSDK = False
def _validate_catalog_file(catalog_file_name):
normilized_file_name = catalog_file_name.lower()
if not normilized_file_name:
raise ValueError('catalog_file_name should be a non-empty string.')
elif not normilized_file_name.endswith("xml"):
raise ValueError('catalog_file_name should be an XML file.')
def update_firmware(idrac, module):
"""Update firmware from a network share and return the job details."""
msg = {}
msg['changed'] = False
msg['update_status'] = {}
try:
upd_share = FileOnShare(remote=module.params['share_name'] + "/" + module.params['catalog_file_name'],
mount_point=module.params['share_mnt'],
isFolder=False,
creds=UserCredentials(
module.params['share_user'],
module.params['share_pwd'])
)
idrac.use_redfish = True
if '12' in idrac.ServerGeneration or '13' in idrac.ServerGeneration:
idrac.use_redfish = False
apply_update = True
msg['update_status'] = idrac.update_mgr.update_from_repo(upd_share,
apply_update,
module.params['reboot'],
module.params['job_wait'])
except RuntimeError as e:
module.fail_json(msg=str(e))
if "Status" in msg['update_status']:
if msg['update_status']['Status'] == "Success":
if module.params['job_wait']:
msg['changed'] = True
else:
module.fail_json(msg='Failed to update firmware.', update_status=msg['update_status'])
return msg
def main():
module = AnsibleModule(
argument_spec={
"idrac_ip": {"required": True, "type": str},
"idrac_user": {"required": True, "type": str},
"idrac_pwd": {"required": True, "type": str, "no_log": True},
"idrac_port": {"required": False, "default": 443, "type": int},
"share_name": {"required": True, "type": str},
"share_user": {"required": False, "type": str},
"share_pwd": {"required": False, "type": str, "no_log": True},
"share_mnt": {"required": True, "type": str},
"catalog_file_name": {"required": False, "type": str, "default": "Catalog.xml"},
"reboot": {"required": False, "type": bool, "default": False},
"job_wait": {"required": False, "type": bool, "default": True},
},
supports_check_mode=False)
try:
# Validate the catalog file
_validate_catalog_file(module.params['catalog_file_name'])
# Connect to iDRAC and update firmware
with iDRACConnection(module.params) as idrac:
update_status = update_firmware(idrac, module)
except (ImportError, ValueError, RuntimeError) as e:
module.fail_json(msg=str(e))
module.exit_json(msg='Successfully updated the firmware.', update_status=update_status)
if __name__ == '__main__':
main()