
    Vh                     2   d dl mZmZmZ eZdZdZdZd dl	Z	d dl
Z
d dlmZmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZmZ d dlmZ d dlmZ dZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-d Z. G d! d"      Z/ G d# d$e/      Z0d% Z1e2d&k(  r e1        yy)'    )absolute_importdivisionprint_functiona  
---
module: omevv_firmware
short_description: Update the firmware of a specific host in the cluster
version_added: "9.10.0"
description: This module allows you to update the firmware of a specific host in the cluster.
extends_documentation_fragment:
  - dellemc.openmanage.omevv_auth_options
options:
  check_vSAN_health:
    description:
      - Check vSAN health while updating the firmware.
      - C(true) checks the vSAN health while updating the firmware.
      - C(false) does not check the vSAN health while updating the firmware.
    type: bool
  date_time:
    description:
      - Date and time when the job must run. This is applicable when I(run_now) is C(false).
      - The supported format is YYYY-MM-DDThh:mm:ss<offset>.
    type: str
  delete_job_queue:
    description:
      - Whether to delete the job queue in iDRAC while updating firmware.
      - C(true) deletes the job queue in iDRAC while updating firmware.
      - C(false) does not delete the job queue in iDRAC while updating firmware.
    type: bool
  drs_check:
    description:
      - Allows you to check if DRS of the cluster is enabled or not.
      - C(true) checks if Distributed Resource Scheduler (DRS) of the cluster is enabled.
      - C(false) does not check if DRS of the cluster is enabled.
    type: bool
    default: false
  enter_maintenance_mode_options:
    description:
      - VM migration policy during management mode.
      - C(FULL_DATA_MIGRATION) for full data migration.
      - C(ENSURE_ACCESSIBILITY) for ensuring accessibility.
      - C(NO_DATA_MIGRATION) does not migrate any data.
    type: str
    choices: [FULL_DATA_MIGRATION, ENSURE_ACCESSIBILITY, NO_DATA_MIGRATION]
  enter_maintenance_mode_timeout:
    description:
      - Time out value during maintenance mode in minutes.
    type: int
    default: 60
  evacuate_VMs:
    description:
      - Allows to move the virtual machine (VM) to other host when current host is powered off.
      - C(true) moves the VM to another host when the current host is powered off.
      - C(false) does not move the VM to another host when the current host is powered off.
    type: bool
    default: false
  exit_maintenance_mode:
    description:
      - Whether to exit management mode after Update.
      - C(true) exits the management mode after Update.
      - C(false) does not exit the management mode after Update.
    type: bool
    default: false
  job_description:
    description:
      - Update job description.
    type: str
  job_name:
    description:
      - Update job name.
    type: str
  job_wait:
    description:
      - Whether to wait till completion of the job. This is applicable when I(power_on) is C(true).
      - C(true) waits for job completion.
      - C(false) does not wait for job completion.
    type: bool
    default: true
  job_wait_timeout:
    description:
      - The maximum wait time of I(job_wait) in seconds. The job is tracked only for this duration.
      - This option is applicable when I(job_wait) is C(true).
    type: int
    default: 1200
  maintenance_mode_count_check:
    description:
      - Allows to check if any host in cluster is in management mode.
      - C(true) checks if any host in cluster is in management mode.
      - C(false) does not check if any host in cluster is in management mode.
    type: bool
  reboot_options:
    description:
      - Host reboot option for firmware update.
      - C(FORCEREBOOT) will force reboot the server.
      - C(SAFEREBOOT) reboots the server in safe mode.
      - C(NEXTREBOOT) does not reboot the server.
    type: str
    choices: [FORCEREBOOT, SAFEREBOOT, NEXTREBOOT]
    default: SAFEREBOOT
  reset_idrac:
    description:
      - Whether to reset the iDRAC while performing firmware update.
      - C(true) resets the iDRAC while performing firmware update.
      - C(false) does not reset the iDRAC while performing firmware update.
    type: bool
  run_now:
    description:
      - Whether to run the update job now or later.
      - C(true) runs the update job instantly.
      - C(false) runs the update at the specified I(date_time).
    type: bool
    required: true
  targets:
    description:
      - The target details for the firmware update operation.
      - Either I(cluster), I(servicetag) or I(host) is required for the firmware update operation.
    type: list
    elements: dict
    required: true
    suboptions:
      cluster:
        description:
          - Name of the cluster to which firmware needs to updated.
          - I(cluster) is mutually exclusive with I(servicetag) and I(host).
          - This module supports only single cluster update.
        type: str
        required: false
      firmware_components:
        description:
          - List of host firmware components to update.
          - M(dellemc.openmanage.omevv_firmware_compliance_info) module can
            be used to fetch the supported firmware components.
        type: list
        elements: str
        required: true
      host:
        description:
          - The IP address or hostname of the host.
          - I(host) is mutually exclusive with I(servicetag) and I(cluster).
          - M(dellemc.openmanage.omevv_device_info) module can be used to fetch the device
            information.
        type: str
      servicetag:
        description:
          - The service tag of the host.
          - I(servicetag) is mutually exclusive with I(host) and I(cluster).
          - M(dellemc.openmanage.omevv_device_info) module can be used to fetch the
            device information.
        type: str
requirements:
  - "python >= 3.9.6"
author:
  - "Rajshekar P(@rajshekarp87)"
attributes:
    check_mode:
        description: Can run in check_mode and return changed status prediction without modifying target, if not supported the action will be skipped.
        support: full
    diff_mode:
        description: Will return details on what has changed (or possibly needs changing in check_mode), when in diff mode.
        support: full
notes:
    - Run this module from a system that has direct access to Dell OpenManage Enterprise.
    - This module supports IPv4 and IPv6 addresses.
a\  
---
- name: Immediately update the firmware of a single component for a specific host
  dellemc.openmanage.omevv.omevv_firmware:
    hostname: "XXX.XXX.XXX.XX"
    vcenter_uuid: "xxxxx"
    vcenter_username: "username"
    vcenter_password: "password"
    ca_path: "path/to/ca_file"
    run_now: false
    date_time: "2024-09-10T20:50:00Z"
    enter_maintenance_mode_timeout: 60
    enter_maintenance_mode_options: FULL_DATA_MIGRATION
    drs_check: true
    evacuate_VMs: true
    exit_maintenance_mode: true
    reboot_options: NEXTREBOOT
    maintenance_mode_count_check: true
    check_vSAN_health: true
    reset_idrac: true
    delete_job_queue: true
    targets:
      - servicetag: SVCTAG1
        firmware_components:
          - "DCIM:INSTALLED#802__Diagnostics.Embedded.1:LC.Embedded.1"

- name: Update the firmware of multiple components at scheduled time for a specific host
  dellemc.openmanage.omevv.omevv_firmware:
    hostname: "XXX.XXX.XXX.XY"
    vcenter_uuid: "xxxxx"
    vcenter_username: "username"
    vcenter_password: "password"
    ca_path: "path/to/ca_file"
    run_now: false
    date_time: "2024-09-10T20:50:00+05:30"
    enter_maintenance_mode_timeout: 60
    enter_maintenance_mode_options: ENSURE_ACCESSIBILITY
    drs_check: true
    evacuate_VMs: true
    exit_maintenance_mode: true
    reboot_options: FORCEREBOOT
    maintenance_mode_count_check: true
    check_vSAN_health: true
    reset_idrac: false
    delete_job_queue: false
    targets:
      - host: "XXX.XXX.XXX.XZ"
        firmware_components:
          - "DCIM:INSTALLED#iDRAC.Embedded.1-1#IDRACinfo"
          - "DCIM:INSTALLED#301_C_BOSS.SL.14-1"
          - "DCIM:INSTALLED#807__TPM.Integrated.1-1"

- name: Update the firmware of multiple components at scheduled time for a cluster
  dellemc.openmanage.omevv.omevv_firmware:
    hostname: "XXX.XXX.XXX.XX"
    vcenter_uuid: "xxxxx"
    vcenter_username: "username"
    vcenter_password: "password"
    ca_path: "path/to/ca_file"
    run_now: false
    date_time: "2024-09-10T20:50:00+05:30"
    enter_maintenance_mode_timeout: 60
    enter_maintenance_mode_options: ENSURE_ACCESSIBILITY
    drs_check: true
    evacuate_VMs: true
    exit_maintenance_mode: true
    reboot_options: SAFEREBOOT
    maintenance_mode_count_check: true
    check_vSAN_health: true
    reset_idrac: false
    delete_job_queue: false
    targets:
      - cluster: cluster_a
        firmware_components:
          - "DCIM:INSTALLED#iDRAC.Embedded.1-1#IDRACinfo"
          - "DCIM:INSTALLED#301_C_BOSS.SL.14-1"
          - "DCIM:INSTALLED#807__TPM.Integrated.1-1"

- name: Retrieve firmware compliance report of all hosts in the specific cluster
  dellemc.openmanage.omevv_firmware_compliance_info:
    hostname: "XXX.XXX.XXX.XX"
    vcenter_uuid: "xxxxx"
    vcenter_username: "username"
    vcenter_password: "password"
    ca_path: "path/to/ca_file"
    clusters:
      - cluster_name: cluster_a
  register: compliance_data

- name: Initialize compliance status results
  ansible.builtin.set_fact:
    source_names: []
    service_tag: ""

- name: Flatten host compliance reports
  ansible.builtin.set_fact:
    host_reports: "{{
        compliance_data.firmware_compliance_info |
        map(attribute='hostComplianceReports') |
        flatten(levels=1) }}"

- name: Flatten and filter concompliant components
  ansible.builtin.set_fact:
    non_compliant_components: >-
        {{
          host_reports
          | map(attribute='componentCompliances')
          | flatten(levels=1)
          | selectattr('driftStatus', 'equalto', 'NonCompliant')
        }}

- name: Gather components source name and set service tag
  ansible.builtin.set_fact:
    source_names: "{{ source_names + [item.sourceName] }}"
    service_tag: "{{ host_report.serviceTag }}"
  loop: "{{ non_compliant_components }}"
  vars:
    host_report: >-
        {{
          host_reports
          | selectattr('componentCompliances', 'contains', item)
          | first
        }}

- name: Combine the final non compliance report
  ansible.builtin.set_fact:
    noncompliance_report:
      sourceNames: "{{ source_names }}"
      serviceTag: "{{ service_tag }}"

- name: Update firmware at the scheduled time for a specific host
  dellemc.openmanage.omevv.omevv_firmware:
    hostname: "192.168.0.1"
    vcenter_uuid: "{{ vcenter_uuid }}"
    vcenter_username: "username"
    vcenter_password: "password"
    ca_path: "path/to/ca_file"
    run_now: false
    date_time: "2024-09-10T20:50:00Z"
    enter_maintenance_mode_timeout: 60
    enter_maintenance_mode_options: NO_DATA_MIGRATION
    drs_check: true
    evacuate_VMs: false
    exit_maintenance_mode: true
    reboot_options: SAFEREBOOT
    maintenance_mode_count_check: true
    check_vSAN_health: true
    reset_idrac: true
    delete_job_queue: true
    targets:
      - servicetag: "{{ noncompliance_report.serviceTag }}"
        firmware_components: "{{ noncompliance_report.sourceNames }}"
a  
---
msg:
  type: str
  description: Status of the firmware update operation.
  returned: always
  sample: "Successfully created the OMEVV baseline profile."
error_info:
  description: Details of the module HTTP Error.
  returned: on HTTP error
  type: dict
  sample:
    {
        "errorCode": "20058",
        "message": "Update Job already running for group id 1004 corresponding to cluster OMAM-Cluster-1. Wait for its completion and trigger."
    }
N)URLError	HTTPError)ConnectionError)	RestOMEVVOMEVVAnsibleModule)validate_job_wait)OMEVVFirmwareUpdateOMEVVBaselineProfile)	OMEVVInfo)datetimez0Successfully submitted the firmware updated job.z+Successfully completed the firmware update.z/Successfully scheduled the firmware update job.z'Failed to complete the firmware update.z0Firmware update job timed out after {0} seconds.zQInvalid date time. Enter a valid date time in the format of YYYY-MM-DDTHH:MM:SSZ.zYThe value for the 'enter_maintenance_mode_timeout' parameter must be between 60 and 1440.z;parameters are mutually exclusive: cluster|host|servicetag.z=Either 'cluster' or 'host' or 'servicetag' must be specified.zwUpdate job is either running or in a scheduled state for cluster '{cluster_name}'. Wait for its completion and trigger.zBJob with name '{job_name}' already exists. Provide different name.z&No managed hosts found in the cluster.z4Host '{managed_host}' not found under managed hosts.z4Provided cluster name '{cluster_name}' is not valid.zChanges found to be applied.zNo changes found to be applied.zJThe value for the 'job_wait_timeout' parameter cannot be negative or zero.z/The URL with the {ip}:{port} cannot be reached.z'The Requested resource cannot be found.z)/Consoles/{vcenter_uuid}/CanTriggerUpdatec                   H    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zy)FirmwareUpdatec                     || _         || _        t        | j                        | _        t	        | j                        | _        t        | j                        | _        y)z
        Initializes the FirmwareUpdate object.

        Args:
            module (Any): The module to execute.
            rest_obj (Any): The rest object.

        Returns:
            None
        N)moduleobjr   omevv_info_objr   omevv_update_objr   omevv_baseline_obj)selfr   rest_objs      u/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/dellemc/openmanage/plugins/modules/omevv_firmware.py__init__zFirmwareUpdate.__init__  sE     '1 3DHH ="6txx"@    c                 0   |}| j                   j                  }|d   }ddg ii}|d   }|d   j                  | j                  ||             | j	                  ||      }| j                  ||      }|d   j                  | j                  |||             |S )z
        Retrieves the payload details for the firmware update.

        Args:
            host_id (str): The ID of the host.

        Returns:
            dict: The payload details for the firmware update.
        targetsfirmware)r   paramsupdateset_firmwareset_scheduleset_job_detailsadd_targets)r   host_id	device_id
parameterstarget_listpayloadr   s          r   get_payload_detailsz"FirmwareUpdate.get_payload_details  s     	[[''
 +	2/:&
""4#4#4Xz#JK##GZ8&&w
;
""4#3#3Hk9#UVr   c                 J    g d}|D ]  \  }}|j                  |      ||<    |S )a  
        Adds optional fields to the firmware dictionary based on the
        parameters.

        Args:
            firmware (dict): The firmware dictionary.
            parameters (dict): The parameters dictionary.

        Returns:
            None
        )
)check_vSAN_healthcheckvSANHealth)delete_job_queuedeleteJobsQueue)	drs_checkdrsCheck)enter_maintenance_mode_optionsenterMaintenanceModeOption)enter_maintenance_mode_timeoutenterMaintenanceModetimeout)evacuate_VMsevacuateVMs)exit_maintenance_modeexitMaintenanceMode)maintenance_mode_count_checkmaintenanceModeCountCheck)reboot_optionsrebootOptions)reset_idrac
resetIDracget)r   r   r(   optional_fields	param_keyfirmware_keys         r   r"   zFirmwareUpdate.set_firmware  s9    
 (7 	?#I|%/^^I%>H\"	? r   c                 p    d|j                  d      i|d<   |d   d   s|j                  d      |d   d<   |S )z
        Sets the schedule for the payload.

        Args:
            payload (dict): The payload dictionary.
            parameters (dict): The parameters dictionary.

        Returns:
            None
        runNowrun_nowschedule	date_timedateTimerA   )r   r*   r(   s      r   r#   zFirmwareUpdate.set_schedule  sF      (	)BC
z"8,.8nn[.IGJ
+r   c           	      ~   |j                  d      r|j                  d      |d<   nd|d<   |j                  d      r|j                  d      |d<   |S t        j                         }d|j                   |j                  d|j
                  dd|j                  d|j                  d|j                  d}||d<   |S )	z
        Sets the job details in the payload dictionary.

        Args:
            payload (dict): The payload dictionary.
            parameters (dict): The parameters dictionary.

        Returns:
            None
        job_descriptionjobDescriptionNjob_namejobNameomam_firmware_update_job_02_)	rB   r   nowyearmonthdayhourminutesecond)r   r*   r(   rJ   rO   s        r   r$   zFirmwareUpdate.set_job_details  s     >>+,(27H(IG$%(,G$%>>*%!+
!;GI  !I+INN+;IOOB;OPYP]P]^`Oaab>>"%i&6&6r%:9;K;KB:OQ  "*GIr   c                     |D ]R  }t        |t              r$|D ]  }|d   |d}|d   j                  |         7|d   |d}|d   j                  |       T |S )a&  
        Adds targets to the firmware dictionary.

        Args:
            firmware (dict): The firmware dictionary.
            target_list (list): The list of targets.
            device_id (Union[str, list]): The device ID or list of device IDs.

        Returns:
            None
        firmware_components)firmwarecomponentsidr   )
isinstancelistappend)r   r   r)   r'   targetsingle_device_idactual_targets          r   r%   zFirmwareUpdate.add_targets  s     " 	:F)T*(1 >$.45J.K.%M Y'..}=> +11F*G#! #**=9	:  r   c                 n   | j                   j                  j                  dg       D ]  }|j                  d      }|j                  d      }|j                  d      }|r|s|r|s|r#|r!| j                   j                  t        d       |rf|ri|rl| j                   j                  t
        d        y)z
        Check the existence of host and servicetag in the targets.

        Args:
            self (object): The instance of the class.

        Returns:
            None
        r   clusterhost
servicetagTmsgfailedN)r   r    rB   	exit_json,CLUSTER_HOST_SERVICETAG_MUTUAL_EXCLUSIVE_MSG%CLUSTER_HOST_SERVICETSAG_REQUIRED_MSG)r   rb   rf   rg   rh   s        r   host_servicetag_existencez(FirmwareUpdate.host_servicetag_existence  s     kk((,,Y; 		^Fjj+G::f%DL1J'zg%%*V-1 & 3
7%%*OX\%]		^r   c                     	 t        j                  | j                  j                  j	                  d      d      }|S # t
        $ r% | j                  j                  t        d       Y S w xY w)a  
        Validates the date and time format.

        This function takes the date and time string from the 'date_time' parameter
        and attempts to parse it using the specified format. If the parsing is
        successful, the parsed datetime object is returned. If the parsing fails,
        the function exits with a failure message.

        Returns:
            datetime: The parsed datetime object.
        rJ   z%Y-%m-%dT%H:%M:%S%zTri   )r   strptimer   r    rB   
ValueErrorrl   INVALID_DATE_TIME_MSG)r   ftimes     r   validate_date_timez!FirmwareUpdate.validate_date_time+  sg    	J%%dkk&8&8&<&<[&IK`aE   	JKK!!&;D!I	Js   9= *A+*A+c                     | j                   j                  j                  d      }|dk  s|dkD  r"| j                   j                  t        d       yy)a  
        Validates the timeout value for entering maintenance mode.

        This function checks if the value of the 'enter_maintenance_mode_timeout' parameter is
        within the valid range (60 to 1440). If the value is outside the valid range, the function
        exits with a failure message.

        Parameters:
            self (object): The instance of the class.

        Returns:
            None

        Raises:
            SystemExit: If the value of 'enter_maintenance_mode_timeout' is outside the valid range.
        r5   <   i  Tri   N)r   r    rB   rl   $MAINTENANCE_MODE_TIMEOUT_INVALID_MSG)r   r5   s     r   r5   z-FirmwareUpdate.enter_maintenance_mode_timeout=  sP    " *.););)?)?@`)a&)B.2PSW2WKK!!&JSW!X 3Xr   c                 f   | j                          t        | j                        r!| j                  j                  t        d       | j                  j
                  j                  d      r| j                          | j                  j
                  j                  d      r| j                          yy)a  
        Validates the parameters of the class.

        This function checks the existence of the 'host' and 'servicetag' parameters.
        It also validates the 'job_wait' parameter and the 'date_time' parameter.
        Additionally, it validates the 'enter_maintenance_mode_timeout' parameter.

        Parameters:
            self (object): The instance of the class.

        Returns:
            None
        Tri   rJ   r5   N)	ro   r   r   rl   TIMEOUT_NEGATIVE_OR_ZERO_MSGr    rB   ru   r5   )r   s    r   validate_paramszFirmwareUpdate.validate_paramsR  s      	&&( T[[)KK!!&B4!P ;;!!+.##% ;;!!"BC//1 Dr   N)__name__
__module____qualname__r   r+   r"   r#   r$   r%   ro   ru   r5   r{    r   r   r   r     s7    A".<"4<^*$Y*2r   r   c                   l    e Zd Zd Zd Zd Z	 	 ddZd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd Zy)UpdateClusterc                    d}d}d}d}d}| j                          | j                  j                  j                  d      }| j                  j                  }| j	                  |d         }|d   }|d   r| j                  |      \  }}}n| j                  |      \  }}}}t        |t              s|g}|g}| j                  |||       | j                  || j                  j                  j                  d             | j                  ||||d   |      \  }	}
}| j                  j                  r| j                  |	|
|       |	r| j                  |||||
|       y| j                  j                  t         |
|dd       y)	a  
        Executes the firmware update process.

        This function validates the parameters, retrieves the target cluster and payload,
        checks if the update job is allowed, and handles the firmware update process.

        Returns:
            None
        Nvcenter_uuidr   rf   rO   beforeafterF)rj   diffchanged)r{   r   r    rB   
get_targetprocess_cluster_targetprocess_non_cluster_targetr_   r`   is_update_job_allowedis_job_name_existingis_firmware_update_needed
check_modehandle_check_modehandle_firmware_updaterl   CHANGES_NOT_FOUND_MSG)r   cluster_namecluster_group_idhost_service_tagsnew_host_idr*   r   r(   rb   firmware_update_neededbefore_dict
after_dicts               r   executezUpdateCluster.executes  s     {{))--n=[[''
I!67i()595P5PQW5X2g{CGCbCbcmCn@L*G[+t,&-K!2 3""<1A<P!!,0B0B0F0Fz0RS:>:X:X*KI9NPa;c7Z ;;!!""#9;
S!''6FQ[(3ZA KK!!&;2=1;(=FK " Mr   c                 0   | j                   j                  j                  d      }| j                  ||      \  }}||s!| j                   j	                  t
        d       |d   }| j                  j                  ||      }| j                  |      }|||fS )z
        Process the cluster target.

        Args:
            target (dict): The target cluster.

        Returns:
            tuple: A tuple containing the cluster group ID, payload, and new host ID.
        r   Trj   skippedrf   r&   )	r   r    rB   &get_host_id_either_host_or_service_tagrl   CLUSTER_HOST_NOT_FOUND_MSGr   get_group_id_of_clusterr+   )r   rb   r   host_idsr   r   r   r*   s           r   r   z$UpdateCluster.process_cluster_target  s     {{))--n=&*&Q&QR^`f&g##8KK!!&@$!Oi(..FF|GSU**8*<(22r   c                    | j                   j                  j                  d      }| j                  |d         }| j	                  ||      \  }}|n|d   r5| j                   j                  t        j                  |d         d       n4| j                   j                  t        j                  |d         d       | j                  j                  ||      }| j                  j                  ||      }| j                  |      }||||fS )	z
        Process the non-cluster target.

        Args:
            parameters (dict): The parameters dictionary.

        Returns:
            tuple: A tuple containing the cluster group ID, payload, and new host ID.
        r   r   rg   )managed_hostTr   rh   r   )r   r    rB   r   get_host_from_parametersrl   HOST_NOT_FOUND_MSGformatr   get_cluster_namer   r+   )	r   r(   r   rb   r&   r   r   r   r*   s	            r   r   z(UpdateCluster.process_non_cluster_target  s    {{))--n=I!67%)%B%B<Q[%\""?f~%%*<*C*C!' +D +1:> & @ %%*<*C*C!'!5 +D +7@D & F**;;L'R..FF|GSU**7*;-w??r   Nc                 n    | j                  |d         }|d   r||fS | j                  ||      \  }}||fS )a  
        Retrieves the host and service tags from the given parameters.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            parameters (dict): The parameters dictionary.
            host_ids (list, optional): The list of host IDs. Defaults to None.
            host_service_tags (list, optional): The list of host service tags. Defaults to None.

        Returns:
            tuple: A tuple containing the host IDs and host service tags.
        r   rf   )r   r   )r   r   r(   r   r   rb   s         r   r   z&UpdateCluster.get_host_from_parameters  sQ     I!67)...*.*U*UVbdj*k'H'...r   c                 ~   |r^| j                   j                  r&| j                   j                  t        d||d       y| j                   j                  t        d       y| j                   j                  r&| j                   j                  t        d||d       y| j                   j                  t        d       y)ar  
        Handles the check mode for firmware update.

        Args:
            firmware_update_needed (bool): Indicates if firmware update is needed.
            before_dict (dict): The dictionary representing the state before the update.
            after_dict (dict): The dictionary representing the state after the update.

        Returns:
            None
        Tr   )rj   r   r   )rj   r   FN)r   _diffrl   CHANGES_FOUND_MSGr   )r   r   r   r   s       r   r   zUpdateCluster.handle_check_mode  s     "{{  %%*;T6AJ+W & Y %%*;T%J{{  %%*?6A5?,A & B %%*?%Or   c                    | j                  ||||||      }| j                  j                  j                  d      r'| j                  j	                  t
        d|||d       y| j                  j	                  t        d|||d       y)a  
        Executes the firmware update job and handles the response.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            cluster_group_id (str): The ID of the cluster group.
            payload (dict): The payload for the firmware update.
            parameters (dict): The parameters for the firmware update.
            before_dict (dict): The state of the system before the update.
            after_dict (dict): The state of the system after the update.

        Returns:
            None
        rH   Tr   rj   r   job_detailsr   N)execute_update_jobr   r    rB   rl   SUCCESS_UPDATE_MSGSUCCESS_UPDATE_SCHEDULED_MSG)r   r   r   r*   r(   r   r   job_resps           r   r   z$UpdateCluster.handle_firmware_update  s      **<9I7T^+6
D;;!!),KK!!&8$T\2=
'S " U KK!!&BD.62=
'S " Ur   c                     |D ]  }|c S  y)z
        Returns the first item in the target_list.

        Args:
            target_list (list): The list of targets.

        Returns:
            Any: The first item in the target_list.
        Nr   )r   r)   rb   s      r   r   zUpdateCluster.get_target  s     " 	FM	r   c                    |d   }|d   }|d   }|r%| j                   j                  |d|      \  }}||fS |r%| j                   j                  ||d      \  }}||fS | j                   j                  ||      }|dk(  r2| j                  j	                  t
        j                  |      d	       y| j                   j                  ||      \  }	}
|	|
fS )
a=  
        Retrieves the host ID and service tag for a given target.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            target (dict): The target containing the cluster, service tag, and host.

        Returns:
            tuple: A tuple containing the host ID and service tag.
        rf   rh   rg   N)hostnamerh   r   Tr   )r   r   r   r   rl   CLUSTER_NOT_FOUND_MSGr    get_cluster_managed_host_details)r   r   rb   r   service_tagrg   r&   host_service_tagr   r   r   s              r   r   z4UpdateCluster.get_host_id_either_host_or_service_tag(  s    i(\*f~(,(;(;(b(bt )c )E%G%,,,(,(;(;(b(bt )c )>%G%,,,#22JJ<KW Y2%%%*?*F*FT`*F*a.2 & 4 /3.A.A.b.b "2/4++!222r   c                     d}t        |t              r|g}t        |t              r|g}i }i }t        |      D ].  \  }	}
| j	                  |||
|      \  }}}}|||<   |||<   |xs |}0 |||fS )a  
        Determines if a firmware update is needed.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            cluster_group_id (int): The ID of the cluster group.
            host_ids (List[int]): The list of host IDs.
            target (List[Dict[str, str]]): The list of targets.
            host_service_tags (List[str]): The list of host service tags.

        Returns:
            Tuple[bool, Dict[str, Dict[str, str]], Dict[str, Dict[str, str]], Dict[str, Dict[str, str]], Dict[str, Dict[str, str]]]:
                A tuple containing the following:
                - firmware_update_needed (bool): True if a firmware update is needed, False otherwise.
                - main_before_no_change_dict (Dict[str, Dict[str, str]]): The dictionary of before no change firmware versions.
                - main_after_no_change_dict (Dict[str, Dict[str, str]]): The dictionary of after no change firmware versions.
                - main_before_dict (Dict[str, Dict[str, str]]): The dictionary of before firmware versions.
                - main_after_dict (Dict[str, Dict[str, str]]): The dictionary of after firmware versions.
        F)r_   intstr	enumeratecheck_firmware_update)r   r   r   r   rb   r   r   main_before_dictmain_after_dictidxone_host_idupdate_neededr   r   current_host_sts                  r   r   z'UpdateCluster.is_firmware_update_neededJ  s    * "'h$ zH'-!2 3 )( 3 	MCFJF`F`.VGECM;
O0;_-/9OO,%;%L}"	M &'7HHr   c                 2   d}i i }}d|d   v r`|d   d   rX| j                   j                  |||      }|j                  d      }	|	d   j                  d      }|	d   j                  dg       }
ng| j                   j                  |||      }|j                  d      }	|	d   j                  d      }|j                  dg       d   j                  dg       }
|d   d   }|D ],  }|
D ]%  }|d   |k(  sd	|d
   i||d   <   d	|d   i||d   <   ' . ||k7  }||||fS )a  
        Check if firmware update is needed for a host.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            cluster_group_id (str): The ID of the cluster group.
            host_id (str): The ID of the host.
            target (list): The list of targets.

        Returns:
            tuple: A tuple containing the following:
                - firmware_update_needed (bool): A boolean indicating if firmware update is needed.
                - before_dict (dict): A dictionary containing the firmware version before the update.
                - after_dict (dict): A dictionary containing the firmware version after the update.
                - current_host_st (str): The service tag of the current host.
        Nrf   r   hostComplianceReports
serviceTagcomponentCompliancesr\   
sourceNamefirmwareversioncurrentValuebaselineValue)r   'get_firmware_drift_info_for_single_hostrB   )r   r   r   r&   rb   r   r   r   cluster_firmware_drift_infocurrent_firmware_comp_reportscurrent_firmware_componentsfirmware_drift_inforequired_firmware_components	componentcurrent_componentr   s                   r   r   z#UpdateCluster.check_firmware_updater  s   " "$bZq	!fQi	&:*.*=*=*e*e.+9',G,K,KLc,d);A>BB<PO*G*J*N*NOegi*j'"&"5"5"]"].#9,?,C,CD[,\);A>BB<PO*=*A*A'+--.+0034JB0O ( (.ay1F'G$5 	OI%@ O!$\2i?)+<^+LDNK 1, ?@ *+<_+MCOJ0>?	O	O #.";%{JOOr   c                     	 | j                   j                  ||       y# t        $ r4 | j                  j	                  t
        j                  |      d       Y yw xY w)aN  
        Check if an update job is allowed.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            cluster_group_id (str): The ID of the cluster group.
            cluster_name (str): The name of the cluster.

        Returns:
            bool: True if the update job is allowed, False otherwise.
        r   Tr   N)r   check_existing_update_job	Exceptionr   rl   UPDATE_JOB_PRESENT_MSGr   )r   r   r   r   s       r   r   z#UpdateCluster.is_update_job_allowed  sY    	0!!;;LJZ[ 	0KK!!&<&C&CQ]&C&^*. " 0	0s    :AAc                     | j                   j                  ||      }|du r2| j                  j                  t        j                  |      d       yy)a   
        Check if a job name already exists.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            job_name (str): The name of the job.

        Returns:
            bool: True if the job name exists, False otherwise.
        T)rO   r   N)r   check_existing_job_namer   rl   JOB_NAME_ALREADY_EXISTS_MSGr   )r   r   rO   job_exist_statuss       r   r   z"UpdateCluster.is_job_name_existing  sW      00HHW_`t#KK!!&A&H&HRZ&H&[*. " 0 $r   c                    d|d   d   i|d   d   |d   d   |d   d   |d   d   |d   d   |d   d	   |d   d
   |d   d   |d   d   |d   d   |d   d   dd}|d   d   du r|d   d   |d   d<   i }|j                  di i       |d   j                         D ]  \  }	}
|
	|d   j                  |	|
i         |d   |d<   |d   d|d<   n|d   |d<   |d   |d<    | j                  j                  ||fi |\  }}|j                  rB| j                  j                  ||j                        \  }}| j                  |||||||       |S | j                  j                  t        d|       S )a5  
        Executes the firmware update job for a cluster.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            cluster_group_id (str): The ID of the cluster group.
            payload (dict): The payload for the firmware update.
            parameters (dict): The parameters for the firmware update.
            before_dict (dict): The state of the system before the update.
            after_dict (dict): The state of the system after the update.

        Returns:
            dict: The response from the firmware update job.
        rG   rI   r   r6   r2   r8   r:   r>   r4   r<   r.   r@   r0   r   )r6   r2   r8   r:   r>   r4   r<   r.   r@   r0   r   )rI   r   FrK   rP   rN    Trj   rk   
error_info)r!   itemsr   update_clustersuccessfirmware_update_job_track	json_datahandle_job_responser   rl   FAILED_UPDATE_MSG)r   r   r   r*   r(   r   r   tmp_payloadfinal_payloadkeyvalueresp	error_msgr   err_msgs                  r   r   z UpdateCluster.execute_update_job  s&   $ '*-h7 07z/BC`/a#J/
;&z2=A'.z':;P'Q!(!4_!E.5j.AB^._-4Z-@A\-]#*:#67H#I%j1,?#*:#67H#I":.y9	
$ :x(E129*2Ej2QK
#J/j"-.%j1779 	?JC j)00#u>	? $+9#5i #$,.0M*+.56F.GM*+$+J$7j!>$//>>|?ObS`bi<< $ 5 5 O OP\PTP^P^!`Hg$$ZtXw%0*>  KK!!&7QZ![r   c                 @   |j                  d      }|s'| j                  j                  t        d|||d       y| j                  j                  j                  d      }	|	r| j                  ||||||       y| j                  j                  t        d|||d       y)a\  
        Handle the response from the firmware update job.

        Args:
            parameters (dict): The parameters for the firmware update.
            vcenter_uuid (str): The UUID of the vCenter.
            resp (Response): The response from the firmware update.
            job_resp (dict): The response from the firmware update job.
            err_msg (str): The error message from the firmware update.
            before_dict (dict): The state of the system before the update.
            after_dict (dict): The state of the system after the update.

        Returns:
            None
        rH   Tr   r   job_waitN)rB   r   rl   r   r    wait_for_job_completionSUCCESS_UPDATE_SUBMIT_MSG)
r   r(   r   r   r   r   r   r   rH   r   s
             r   r   z!UpdateCluster.handle_job_response  s    " ..+KK!!&BD.62=
'S " U {{))--j9H,,\47-8*F %%*CT2:6AJ+W & Yr   c                 4   | j                   j                  j                  d      }|dz  }|d   dvrU|dkD  rPt        j                  d       | j
                  j                  ||j                        \  }}|dz  }|d   dvr|dkD  rP|dk  r1| j                   j                  t        j                  |      d|       |d   d	k(  r2|d
   d   dk(  r'| j                   j                  t        d|||d       y| j                   j                  t        d|       y)a4  
        Waits for the firmware update job to complete.

        Args:
            vcenter_uuid (str): The UUID of the vCenter.
            resp (Response): The response from the firmware update.
            job_resp (dict): The response from the firmware update job.
            err_msg (str): The error message from the firmware update.
            before_dict (dict): The state of the system before the update.
            after_dict (dict): The state of the system after the update.

        Returns:
            None

        Raises:
            None
        job_wait_timeout   state)	COMPLETEDFAILEDr      T)rj   rk   r   r   lastExecutionHistorystatusSummary
SUCCESSFULr   r   r   N)r   r    rB   timesleepr   r   r   rl   FAILED_UPDATE_TIMEOUT_MSGr   r   r   )	r   r   r   r   r   r   r   r   counts	            r   r   z%UpdateCluster.wait_for_job_completion  s-   &  ;;--112DE A%w'>>519JJqM $ 5 5 O OP\PTP^P^!`HgQJE	 w'>>519 A:KK!!&?&F&FGW&X)-8 " E G+9O0PQ`0aeq0qKK!!&8$T\2=
'S " U KK!!&7QX!Yr   )NN)r|   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   q  se    /Mb3(@4 KO37/*P4U4 3D&IP,P\0$0 8tY@#Zr   r   c            
         i dddidddidddidddd	d
dg dddddd	dddd	dddd	dddidddidddd	dddd	dddiddg ddddddiddddd d!d"dd!ddd#ddiddiddid$d%} t        | g d&gd'      }	 t        |j                        5 }t        ||      }|j	                          d(d(d(       y(# 1 sw Y   y(xY w# t
        $ r}t        |      dd)}i }	 t        j                  |      }n"# t        $ r t        |      |d*<   d+|d<   Y nw xY w|j                  d,k(  r|j                  d*t        |            |d-<   nF|j                  d.k(  r
t        |d-<   n-|j                  |j                  d*t        |            |d/        |j                  d8i | Y d(}~y(d(}~wt        $ rg}d0|j                  j                  d1       d2|j                  j                  d3       d4dt        |      d5d6d7} |j                  d8i | Y d(}~y(d(}~wt         t        t"        t$        t&        t(        t*        t,        f$ r&}|j                  t        |      d)       Y d(}~y(d(}~ww xY w)9a\  
    The main function of the module. It sets up the argument spec and initializes the OMEVVAnsibleModule.
    It then creates an instance of the UpdateCluster class and calls its execute method.
    If any exceptions occur, it handles them and exits the module with the appropriate response.

    Args:
        None

    Returns:
        None
    r-   typeboolrJ   r   r/   r1   F)r  defaultr3   )FULL_DATA_MIGRATIONENSURE_ACCESSIBILITYNO_DATA_MIGRATION)r  choicesr5   r   rw   r7   r9   rM   rO   r   Tr   i  r;   r=   )FORCEREBOOT
SAFEREBOOT
NEXTREBOOTr  )r  r  r  r?   rH   )r  requiredr   r`   dict)r  elementsr  )r\   rf   rg   rh   )r  r  r  options)rH   F)rJ   )argument_specrequired_ifsupports_check_modeNri   messager   i  rj   i  )rj   r   zThe URL with IP r   z
 and port portz cannot be reached.r   )r  r  )rj   unreachabler   r   )r
   r	   r    r   r   r   r   jsonloadrr   coderB   SOURCE_NOT_FOUND_MSGr!   rl   r   IOError	TypeErrorr   AttributeError
IndexErrorKeyErrorOSError)	r  r   r   	omevv_objhttperrresponse_datar   urlerrgenerrs	            r   mainr(  B  s=   /ff-/fe_/ 	VV,/ 	f7	/
 	)+
/ 	)5R*H/ 	E:/ 	 &U!C/  	FE?!/" 	VUO#/$ 	V5%/& 	Ut<'/( 	'(8)/* 	
 $
+/< 	'=/> 	F5?/@ 	 # % $(
 #E?%uo		
A/Mb  #.
 !F"7v}}% 	 %fh7I	  	  	   * #G=
	-7+J 	-$'LJy!!,Jv	- <<3#->>)S_#MM% \\S #7M%   !~~iZA("  	)=) *%fmm&7&7
&C%DJv}}O`O`agOhNii|}&)&k:F

 	)=)ZOJ'; 7S[667st   
C C<C C
C C 	I2F.+D F.D F.D  B	F..I2:AH0I2I--I2__main__)3
__future__r   r   r   r  __metaclass__DOCUMENTATIONEXAMPLESRETURNr  r   +ansible.module_utils.six.moves.urllib.errorr   r   ansible.module_utils.urlsr   Aansible_collections.dellemc.openmanage.plugins.module_utils.omevvr	   r
   Aansible_collections.dellemc.openmanage.plugins.module_utils.utilsr   \ansible_collections.dellemc.openmanage.plugins.module_utils.omevv_utils.omevv_firmware_utilsr   r   Xansible_collections.dellemc.openmanage.plugins.module_utils.omevv_utils.omevv_info_utilsr   r   r   r   r   r   r  rs   rx   rm   rn   r   r   r   r   r   r   r   rz   UNREACHABLE_MSGr  TRIGGER_UPDATE_CHECK_URIr   r   r(  r|   r   r   r   <module>r7     s   C B`DXt
$   K 5 k _ S n N B P = N 0 (P $0U ,)8 %R b E K N 2 9  3 C@ F i2 i2XNZN NZbg7T zF r   