mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-07 13:52:54 +00:00
Initial commit
This commit is contained in:
215
plugins/modules/storage/netapp/netapp_e_drive_firmware.py
Normal file
215
plugins/modules/storage/netapp/netapp_e_drive_firmware.py
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# (c) 2016, NetApp, Inc
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: netapp_e_drive_firmware
|
||||
short_description: NetApp E-Series manage drive firmware
|
||||
description:
|
||||
- Ensure drive firmware version is activated on specified drive model.
|
||||
author:
|
||||
- Nathan Swartz (@ndswartz)
|
||||
extends_documentation_fragment:
|
||||
- netapp.ontap.netapp.eseries
|
||||
|
||||
options:
|
||||
firmware:
|
||||
description:
|
||||
- list of drive firmware file paths.
|
||||
- NetApp E-Series drives require special firmware which can be downloaded from https://mysupport.netapp.com/NOW/download/tools/diskfw_eseries/
|
||||
type: list
|
||||
required: True
|
||||
wait_for_completion:
|
||||
description:
|
||||
- This flag will cause module to wait for any upgrade actions to complete.
|
||||
type: bool
|
||||
default: false
|
||||
ignore_inaccessible_drives:
|
||||
description:
|
||||
- This flag will determine whether drive firmware upgrade should fail if any affected drives are inaccessible.
|
||||
type: bool
|
||||
default: false
|
||||
upgrade_drives_online:
|
||||
description:
|
||||
- This flag will determine whether drive firmware can be upgrade while drives are accepting I/O.
|
||||
- When I(upgrade_drives_online==False) stop all I/O before running task.
|
||||
type: bool
|
||||
default: true
|
||||
'''
|
||||
EXAMPLES = """
|
||||
- name: Ensure correct firmware versions
|
||||
nac_santricity_drive_firmware:
|
||||
ssid: "1"
|
||||
api_url: "https://192.168.1.100:8443/devmgr/v2"
|
||||
api_username: "admin"
|
||||
api_password: "adminpass"
|
||||
validate_certs: true
|
||||
firmware: "path/to/drive_firmware"
|
||||
wait_for_completion: true
|
||||
ignore_inaccessible_drives: false
|
||||
"""
|
||||
RETURN = """
|
||||
msg:
|
||||
description: Whether any drive firmware was upgraded and whether it is in progress.
|
||||
type: str
|
||||
returned: always
|
||||
sample:
|
||||
{ changed: True, upgrade_in_process: True }
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
from time import sleep
|
||||
from ansible_collections.netapp.ontap.plugins.module_utils.netapp import NetAppESeriesModule, create_multipart_formdata
|
||||
from ansible.module_utils._text import to_native, to_text, to_bytes
|
||||
|
||||
|
||||
class NetAppESeriesDriveFirmware(NetAppESeriesModule):
|
||||
WAIT_TIMEOUT_SEC = 60 * 15
|
||||
|
||||
def __init__(self):
|
||||
ansible_options = dict(
|
||||
firmware=dict(type="list", required=True),
|
||||
wait_for_completion=dict(type="bool", default=False),
|
||||
ignore_inaccessible_drives=dict(type="bool", default=False),
|
||||
upgrade_drives_online=dict(type="bool", default=True))
|
||||
|
||||
super(NetAppESeriesDriveFirmware, self).__init__(ansible_options=ansible_options,
|
||||
web_services_version="02.00.0000.0000",
|
||||
supports_check_mode=True)
|
||||
|
||||
args = self.module.params
|
||||
self.firmware_list = args["firmware"]
|
||||
self.wait_for_completion = args["wait_for_completion"]
|
||||
self.ignore_inaccessible_drives = args["ignore_inaccessible_drives"]
|
||||
self.upgrade_drives_online = args["upgrade_drives_online"]
|
||||
|
||||
self.upgrade_list_cache = None
|
||||
|
||||
self.upgrade_required_cache = None
|
||||
self.upgrade_in_progress = False
|
||||
self.drive_info_cache = None
|
||||
|
||||
def upload_firmware(self):
|
||||
"""Ensure firmware has been upload prior to uploaded."""
|
||||
for firmware in self.firmware_list:
|
||||
firmware_name = os.path.basename(firmware)
|
||||
files = [("file", firmware_name, firmware)]
|
||||
headers, data = create_multipart_formdata(files)
|
||||
try:
|
||||
rc, response = self.request("/files/drive", method="POST", headers=headers, data=data)
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to upload drive firmware [%s]. Array [%s]. Error [%s]." % (firmware_name, self.ssid, to_native(error)))
|
||||
|
||||
def upgrade_list(self):
|
||||
"""Determine whether firmware is compatible with the specified drives."""
|
||||
if self.upgrade_list_cache is None:
|
||||
self.upgrade_list_cache = list()
|
||||
try:
|
||||
rc, response = self.request("storage-systems/%s/firmware/drives" % self.ssid)
|
||||
|
||||
# Create upgrade list, this ensures only the firmware uploaded is applied
|
||||
for firmware in self.firmware_list:
|
||||
filename = os.path.basename(firmware)
|
||||
|
||||
for uploaded_firmware in response["compatibilities"]:
|
||||
if uploaded_firmware["filename"] == filename:
|
||||
|
||||
# Determine whether upgrade is required
|
||||
drive_reference_list = []
|
||||
for drive in uploaded_firmware["compatibleDrives"]:
|
||||
try:
|
||||
rc, drive_info = self.request("storage-systems/%s/drives/%s" % (self.ssid, drive["driveRef"]))
|
||||
|
||||
# Add drive references that are supported and differ from current firmware
|
||||
if (drive_info["firmwareVersion"] != uploaded_firmware["firmwareVersion"] and
|
||||
uploaded_firmware["firmwareVersion"] in uploaded_firmware["supportedFirmwareVersions"]):
|
||||
|
||||
if self.ignore_inaccessible_drives or (not drive_info["offline"] and drive_info["available"]):
|
||||
drive_reference_list.append(drive["driveRef"])
|
||||
|
||||
if not drive["onlineUpgradeCapable"] and self.upgrade_drives_online:
|
||||
self.module.fail_json(msg="Drive is not capable of online upgrade. Array [%s]. Drive [%s]."
|
||||
% (self.ssid, drive["driveRef"]))
|
||||
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to retrieve drive information. Array [%s]. Drive [%s]. Error [%s]."
|
||||
% (self.ssid, drive["driveRef"], to_native(error)))
|
||||
|
||||
if drive_reference_list:
|
||||
self.upgrade_list_cache.extend([{"filename": filename, "driveRefList": drive_reference_list}])
|
||||
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to complete compatibility and health check. Array [%s]. Error [%s]." % (self.ssid, to_native(error)))
|
||||
|
||||
return self.upgrade_list_cache
|
||||
|
||||
def wait_for_upgrade_completion(self):
|
||||
"""Wait for drive firmware upgrade to complete."""
|
||||
drive_references = [reference for drive in self.upgrade_list() for reference in drive["driveRefList"]]
|
||||
last_status = None
|
||||
for attempt in range(int(self.WAIT_TIMEOUT_SEC / 5)):
|
||||
try:
|
||||
rc, response = self.request("storage-systems/%s/firmware/drives/state" % self.ssid)
|
||||
|
||||
# Check drive status
|
||||
for status in response["driveStatus"]:
|
||||
last_status = status
|
||||
if status["driveRef"] in drive_references:
|
||||
if status["status"] == "okay":
|
||||
continue
|
||||
elif status["status"] in ["inProgress", "inProgressRecon", "pending", "notAttempted"]:
|
||||
break
|
||||
else:
|
||||
self.module.fail_json(msg="Drive firmware upgrade failed. Array [%s]. Drive [%s]. Status [%s]."
|
||||
% (self.ssid, status["driveRef"], status["status"]))
|
||||
else:
|
||||
self.upgrade_in_progress = False
|
||||
break
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to retrieve drive status. Array [%s]. Error [%s]." % (self.ssid, to_native(error)))
|
||||
|
||||
sleep(5)
|
||||
else:
|
||||
self.module.fail_json(msg="Timed out waiting for drive firmware upgrade. Array [%s]. Status [%s]." % (self.ssid, last_status))
|
||||
|
||||
def upgrade(self):
|
||||
"""Apply firmware to applicable drives."""
|
||||
try:
|
||||
rc, response = self.request("storage-systems/%s/firmware/drives/initiate-upgrade?onlineUpdate=%s"
|
||||
% (self.ssid, "true" if self.upgrade_drives_online else "false"), method="POST", data=self.upgrade_list())
|
||||
self.upgrade_in_progress = True
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to upgrade drive firmware. Array [%s]. Error [%s]." % (self.ssid, to_native(error)))
|
||||
|
||||
if self.wait_for_completion:
|
||||
self.wait_for_upgrade_completion()
|
||||
|
||||
def apply(self):
|
||||
"""Apply firmware policy has been enforced on E-Series storage system."""
|
||||
self.upload_firmware()
|
||||
|
||||
if self.upgrade_list() and not self.module.check_mode:
|
||||
self.upgrade()
|
||||
|
||||
self.module.exit_json(changed=True if self.upgrade_list() else False,
|
||||
upgrade_in_process=self.upgrade_in_progress)
|
||||
|
||||
|
||||
def main():
|
||||
drive_firmware = NetAppESeriesDriveFirmware()
|
||||
drive_firmware.apply()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user