diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:35 +0000 |
commit | 7fec0b69a082aaeec72fee0612766aa42f6b1b4d (patch) | |
tree | efb569b86ca4da888717f5433e757145fa322e08 /ansible_collections/dellemc/unity/plugins/modules | |
parent | Releasing progress-linux version 7.7.0+dfsg-3~progress7.99u1. (diff) | |
download | ansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.tar.xz ansible-7fec0b69a082aaeec72fee0612766aa42f6b1b4d.zip |
Merging upstream version 9.4.0+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/dellemc/unity/plugins/modules')
18 files changed, 737 insertions, 91 deletions
diff --git a/ansible_collections/dellemc/unity/plugins/modules/cifsserver.py b/ansible_collections/dellemc/unity/plugins/modules/cifsserver.py index d40c4f11d..0225eb381 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/cifsserver.py +++ b/ansible_collections/dellemc/unity/plugins/modules/cifsserver.py @@ -124,7 +124,7 @@ EXAMPLES = r''' password: "{{password}}" validate_certs: "{{validate_certs}}" cifs_server_id: "cifs_37" - unjoin_cifs_server_account: True + unjoin_cifs_server_account: true domain_username: "domain_username" domain_password: "domain_password" state: "absent" @@ -277,7 +277,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell import LOG = utils.get_logger('cifsserver') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class CIFSServer(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/consistencygroup.py b/ansible_collections/dellemc/unity/plugins/modules/consistencygroup.py index 14e4de506..e0d6a6c06 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/consistencygroup.py +++ b/ansible_collections/dellemc/unity/plugins/modules/consistencygroup.py @@ -321,7 +321,7 @@ EXAMPLES = r""" replication_type: "remote" remote_system: remote_system_host: '10.1.2.3' - remote_system_verifycert: False + remote_system_verifycert: false remote_system_username: 'username' remote_system_password: 'password' destination_pool_name: "pool_test_1" @@ -494,7 +494,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('consistencygroup', log_devel=logging.INFO) -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class ConsistencyGroup(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/filesystem.py b/ansible_collections/dellemc/unity/plugins/modules/filesystem.py index b10f85386..95cffeec6 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/filesystem.py +++ b/ansible_collections/dellemc/unity/plugins/modules/filesystem.py @@ -330,7 +330,7 @@ EXAMPLES = r""" grace_period: 8 grace_period_unit: "days" default_soft_limit: 10 - is_user_quota_enabled: False + is_user_quota_enabled: false state: "present" - name: Expand FileSystem size @@ -364,9 +364,9 @@ EXAMPLES = r""" filesystem_name: "ansible_test_fs" nas_server_name: "lglap761" smb_properties: - is_smb_op_locks_enabled: True + is_smb_op_locks_enabled: true smb_notify_on_change_dir_depth: 5 - is_smb_notify_on_access_enabled: True + is_smb_notify_on_access_enabled: true state: "present" - name: Modify FileSystem Snap Schedule @@ -411,7 +411,7 @@ EXAMPLES = r""" rpo: 60 remote_system: remote_system_host: '0.1.2.3' - remote_system_verifycert: False + remote_system_verifycert: false remote_system_username: 'username' remote_system_password: 'password' destination_pool_name: "pool_test_1" @@ -689,7 +689,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('filesystem') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class Filesystem(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/filesystem_snapshot.py b/ansible_collections/dellemc/unity/plugins/modules/filesystem_snapshot.py index 35e536a47..a82fbe89b 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/filesystem_snapshot.py +++ b/ansible_collections/dellemc/unity/plugins/modules/filesystem_snapshot.py @@ -122,7 +122,7 @@ EXAMPLES = r''' filesystem_name: "ansible_test_FS" nas_server_name: "lglad069" description: "Created using playbook" - auto_delete: True + auto_delete: true fs_access_type: "Protocol" state: "present" @@ -166,7 +166,7 @@ EXAMPLES = r''' validate_certs: "{{validate_certs}}" snapshot_name: "ansible_test_FS_snap" description: "Description updated" - auto_delete: False + auto_delete: false expiry_time: "04/15/2021 5:30" state: "present" @@ -304,7 +304,7 @@ from datetime import datetime LOG = utils.get_logger('filesystem_snapshot') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class FilesystemSnapshot(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/host.py b/ansible_collections/dellemc/unity/plugins/modules/host.py index 21a5fbae1..fcc13dd9a 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/host.py +++ b/ansible_collections/dellemc/unity/plugins/modules/host.py @@ -347,7 +347,7 @@ import ipaddress LOG = utils.get_logger('host') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class Host(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/info.py b/ansible_collections/dellemc/unity/plugins/modules/info.py index e89d86335..641074286 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/info.py +++ b/ansible_collections/dellemc/unity/plugins/modules/info.py @@ -38,6 +38,7 @@ description: Get list of CIFS Servers in Unity array. Get list of Ethernet ports in Unity array. Get list of File interfaces used in Unity array. + Get list of Replication sessions in Unity array. extends_documentation_fragment: - dellemc.unity.unity @@ -54,7 +55,7 @@ options: for which information is required. choices: [host, fc_initiator, iscsi_initiator, cg, storage_pool, vol, snapshot_schedule, nas_server, file_system, snapshot, nfs_export, - smb_share, user_quota, tree_quota, disk_group, nfs_server, cifs_server, ethernet_port, file_interface] + smb_share, user_quota, tree_quota, disk_group, nfs_server, cifs_server, ethernet_port, file_interface, replication_session] type: list elements: str @@ -89,6 +90,7 @@ EXAMPLES = r''' - cifs_server - ethernet_port - file_interface + - replication_session - name: Get information of Unity array dellemc.unity.info: @@ -267,6 +269,15 @@ EXAMPLES = r''' validate_certs: "{{validate_certs}}" gather_subset: - file_interface + + - name: Get list of replication sessions on Unity array + dellemc.unity.info: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + gather_subset: + - replication_session ''' RETURN = r''' @@ -1213,9 +1224,77 @@ File_interfaces: "name": "3_APMXXXXXXXXXX" } ] +Replication_sessions: + description: Details of the Replication sessions. + returned: When Replication sessions exist. + type: list + contains: + id: + description: The ID of the Replication session. + type: str + name: + description: The name of the Replication session. + type: str + sample: [ + { + "current_transfer_est_remain_time": 0, + "daily_snap_replication_policy": null, + "dst_resource_id": "nas_8", + "dst_spa_interface": { + "UnityRemoteInterface": { + "hash": 8771253398547, + "id": "APM00213404195:if_181" + } + }, + "dst_spb_interface": { + "UnityRemoteInterface": { + "hash": 8771253424144, + "id": "APM00213404195:if_180" + } + }, + "dst_status": "ReplicationSessionStatusEnum.OK", + "existed": true, + "hash": 8771259012271, + "health": { + "UnityHealth": { + "hash": 8771253424168 + } + }, + "hourly_snap_replication_policy": null, + "id": "103079215114_APM00213404195_0000_103079215274_APM00213404194_0000", + "last_sync_time": "2023-04-18 10:35:25+00:00", + "local_role": "ReplicationSessionReplicationRoleEnum.DESTINATION", + "max_time_out_of_sync": 0, + "members": null, + "name": "rep_sess_nas", + "network_status": "ReplicationSessionNetworkStatusEnum.OK", + "remote_system": { + "UnityRemoteSystem": { + "hash": 8771253380142 + } + }, + "replication_resource_type": "ReplicationEndpointResourceTypeEnum.NASSERVER", + "src_resource_id": "nas_213", + "src_spa_interface": { + "UnityRemoteInterface": { + "hash": 8771253475010, + "id": "APM00213404194:if_195" + } + }, + "src_spb_interface": { + "UnityRemoteInterface": { + "hash": 8771253374169, + "id": "APM00213404194:if_194" + } + }, + "src_status": "ReplicationSessionStatusEnum.OK", + "status": "ReplicationOpStatusEnum.ACTIVE", + "sync_progress": 0, + "sync_state": "ReplicationSessionSyncStateEnum.IN_SYNC" + }, + ] ''' -from re import sub from ansible.module_utils.basic import AnsibleModule from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils @@ -1223,7 +1302,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('info') SUCCESSFULL_LISTED_MSG = 'Successfully listed.' -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class Info(object): @@ -1549,6 +1628,20 @@ class Info(object): LOG.error(msg) self.module.fail_json(msg=msg) + def get_replication_session_list(self): + """Get the list of replication sessions on a given Unity storage system""" + + try: + LOG.info("Getting replication sessions list") + replication_sessions = self.unity.get_replication_session() + return result_list(replication_sessions) + + except Exception as e: + msg = 'Get replication session list from unity array failed with' \ + ' error %s' % (str(e)) + LOG.error(msg) + self.module.fail_json(msg=msg) + def perform_module_operation(self): """ Perform different actions on Info based on user parameter chosen in playbook """ @@ -1575,6 +1668,7 @@ class Info(object): cifs_server = [] ethernet_port = [] file_interface = [] + replication_session = [] subset = self.module.params['gather_subset'] if subset is not None: @@ -1616,6 +1710,8 @@ class Info(object): ethernet_port = self.get_ethernet_port_list() if 'file_interface' in subset: file_interface = self.get_file_interface_list() + if 'replication_session' in subset: + replication_session = self.get_replication_session_list() self.module.exit_json( Array_Details=array_details, @@ -1637,7 +1733,8 @@ class Info(object): NFS_Servers=nfs_server, CIFS_Servers=cifs_server, Ethernet_ports=ethernet_port, - File_interfaces=file_interface + File_interfaces=file_interface, + Replication_sessions=replication_session ) @@ -1770,7 +1867,7 @@ def get_info_parameters(): 'file_system', 'snapshot', 'nfs_export', 'smb_share', 'user_quota', 'tree_quota', 'disk_group', 'nfs_server', 'cifs_server', - 'ethernet_port', 'file_interface'])) + 'ethernet_port', 'file_interface', 'replication_session'])) def main(): diff --git a/ansible_collections/dellemc/unity/plugins/modules/interface.py b/ansible_collections/dellemc/unity/plugins/modules/interface.py index 95ddfd26a..2523f940e 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/interface.py +++ b/ansible_collections/dellemc/unity/plugins/modules/interface.py @@ -227,7 +227,7 @@ from ipaddress import ip_network LOG = utils.get_logger('interface') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class Interface(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/nasserver.py b/ansible_collections/dellemc/unity/plugins/modules/nasserver.py index 713125cc2..925cc932e 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/nasserver.py +++ b/ansible_collections/dellemc/unity/plugins/modules/nasserver.py @@ -225,15 +225,15 @@ EXAMPLES = r''' validate_certs: "{{validate_certs}}" nas_server_name: "{{nas_server_name}}" nas_server_new_name: "updated_sample_nas_server" - is_replication_destination: False - is_backup_only: False - is_multiprotocol_enabled: True - allow_unmapped_user: True + is_replication_destination: false + is_backup_only: false + is_multiprotocol_enabled: true + allow_unmapped_user: true default_unix_user: "default_unix_sample_user" default_windows_user: "default_windows_sample_user" - enable_windows_to_unix_username_mapping: True + enable_windows_to_unix_username_mapping: true current_unix_directory_service: "LDAP" - is_packet_reflect_enabled: True + is_packet_reflect_enabled: true state: "present" - name: Enable replication for NAS Server on Local System @@ -243,7 +243,7 @@ EXAMPLES = r''' password: "{{password}}" validate_certs: "{{validate_certs}}" nas_server_id: "nas_10" - replication_reuse_resource: False + replication_reuse_resource: false replication_params: replication_name: "test_replication" destination_nas_server_name: "destination_nas" @@ -252,7 +252,7 @@ EXAMPLES = r''' replication_type: "local" destination_pool_name: "Pool_Ansible_Neo_DND" destination_sp: "SPA" - is_backup: True + is_backup: true replication_state: "enable" state: "present" @@ -263,7 +263,7 @@ EXAMPLES = r''' password: "{{password}}" validate_certs: "{{validate_certs}}" nas_server_name: "dummy_nas" - replication_reuse_resource: False + replication_reuse_resource: false replication_params: replication_name: "test_replication" destination_nas_server_name: "destination_nas" @@ -272,12 +272,12 @@ EXAMPLES = r''' replication_type: "remote" remote_system: remote_system_host: '10.10.10.10' - remote_system_verifycert: False + remote_system_verifycert: false remote_system_username: 'test1' remote_system_password: 'test1!' destination_pool_name: "fastVP_pool" destination_sp: "SPA" - is_backup: True + is_backup: true replication_state: "enable" state: "present" @@ -288,7 +288,7 @@ EXAMPLES = r''' password: "{{password}}" validate_certs: "{{validate_certs}}" nas_server_name: "dummy_nas" - replication_reuse_resource: True + replication_reuse_resource: true replication_params: destination_nas_server_name: "destination_nas" replication_mode: "asynchronous" @@ -297,7 +297,7 @@ EXAMPLES = r''' replication_name: "test_replication" remote_system: remote_system_host: '10.10.10.10' - remote_system_verifycert: False + remote_system_verifycert: false remote_system_username: 'test1' remote_system_password: 'test1!' destination_pool_name: "fastVP_pool" @@ -347,7 +347,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true nas_server_details: description: The NAS server details. type: dict @@ -388,7 +388,7 @@ nas_server_details: type: bool is_replication_destination: description: If the NAS server is a replication destination - then True. + then true. type: bool is_windows_to_unix_username_mapping_enabled: description: Indicates whether a Unix to/from Windows user name @@ -482,7 +482,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils LOG = utils.get_logger('nasserver') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class NASServer(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/nfs.py b/ansible_collections/dellemc/unity/plugins/modules/nfs.py index e6223066b..473e40b2a 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/nfs.py +++ b/ansible_collections/dellemc/unity/plugins/modules/nfs.py @@ -568,7 +568,7 @@ nfs_share_details: 'root_access_hosts': None, 'snap': None, 'type': 'NFSTypeEnum.NFS_SHARE', - 'existed': True, + 'existed': true, 'nas_server': { 'UnityNasServer': { 'id': 'nas_id_1', @@ -607,7 +607,7 @@ HOST_DICT = dict(type='list', required=False, elements='dict', HOST_STATE_LIST = ['present-in-export', 'absent-in-export'] STATE_LIST = ['present', 'absent'] -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class NFS(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/nfsserver.py b/ansible_collections/dellemc/unity/plugins/modules/nfsserver.py index e492e3af0..30d2c787f 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/nfsserver.py +++ b/ansible_collections/dellemc/unity/plugins/modules/nfsserver.py @@ -92,12 +92,12 @@ EXAMPLES = r''' validate_certs: "{{validate_certs}}" nas_server_name: "dummy_nas" host_name: "dummy_nas23" - is_secure_enabled: True + is_secure_enabled: true kerberos_domain_controller_type: "WINDOWS" kerberos_domain_controller_username: "administrator" kerberos_domain_controller_password: "Password123!" - is_extended_credentials_enabled: True - nfs_v4_enabled: True + is_extended_credentials_enabled: true + nfs_v4_enabled: true state: "present" - name: Create NFS server with kdctype as Unix @@ -108,10 +108,10 @@ EXAMPLES = r''' validate_certs: "{{validate_certs}}" nas_server_name: "dummy_nas" host_name: "dummy_nas23" - is_secure_enabled: True + is_secure_enabled: true kerberos_domain_controller_type: "UNIX" - is_extended_credentials_enabled: True - nfs_v4_enabled: True + is_extended_credentials_enabled: true + nfs_v4_enabled: true state: "present" - name: Get NFS server details @@ -132,7 +132,7 @@ EXAMPLES = r''' nas_server_name: "dummy_nas" kerberos_domain_controller_username: "administrator" kerberos_domain_controller_password: "Password123!" - unjoin_server_account: False + unjoin_server_account: false state: "absent" ''' @@ -209,7 +209,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('nfsserver') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class NFSServer(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/replication_session.py b/ansible_collections/dellemc/unity/plugins/modules/replication_session.py new file mode 100644 index 000000000..20907d50d --- /dev/null +++ b/ansible_collections/dellemc/unity/plugins/modules/replication_session.py @@ -0,0 +1,551 @@ +#!/usr/bin/python +# Copyright: (c) 2023, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Ansible module for managing replication session on Unity""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" + +module: replication_session +version_added: '1.7.0' +short_description: Manage replication session on Unity storage system +description: +- Managing replication session on Unity storage system includes getting details, pause, + resume, sync, failover, failback and deleting the replication session. + +extends_documentation_fragment: + - dellemc.unity.unity + +author: +- Jennifer John (@Jennifer-John) <ansible.team@dell.com> + +options: + session_id: + description: + - ID of replication session. + type: str + session_name: + description: + - Name of replication session. + type: str + pause: + description: + - Pause or resume replication session. + type: bool + sync: + description: + - Sync a replication session. + type: bool + failover_with_sync: + description: + - If C(true), Sync the source and destination resources before failing over the asynchronous + replication session or keep them in sync after failing over the synchronous + replication session. + - If C(false), Failover a replication session. + type: bool + failback: + description: + - Failback a replication session. + type: bool + force_full_copy: + description: + - Indicates whether to sync back all data from the destination SP to the source + SP during the failback session. Needed during resume operation when replication + session goes out of sync due to a fault. + type: bool + force: + description: + - Skip pre-checks on file system(s) replication sessions of a NAS server when a + replication failover is issued from the source NAS server. + type: bool + state: + description: + - State variable to determine whether replication session will exist or not. + choices: ['absent', 'present'] + default: present + type: str + +notes: + - The I(check_mode) is supported. +""" + +EXAMPLES = r""" +- name: Get replication session details + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + +- name: Get replication session details based on session_id + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_id: "103079215114_APM00213404195_0000_103079215274_APM00213404194_0000" + +- name: Pause a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + pause: true + +- name: Resume a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + pause: false + force_full_copy: true + +- name: Sync a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + sync: true + +- name: Failover with sync a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + failover_with_sync: true + force: true + +- name: Failover a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + failover_with_sync: false + +- name: Failback a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + failback: true + force_full_copy: true + +- name: Delete a replication session + dellemc.unity.replication_session: + unispherehost: "{{unispherehost}}" + username: "{{username}}" + password: "{{password}}" + validate_certs: "{{validate_certs}}" + session_name: "fs_replication" + state: "absent" +""" + +RETURN = r''' + +changed: + description: Whether or not the resource has changed. + returned: always + type: bool + sample: true + +replication_session_details: + description: Details of the replication session. + returned: When replication session exists. + type: dict + contains: + id: + description: Unique identifier of the replicationSession instance. + type: str + name: + description: User-specified replication session name. + type: str + replicationResourceType: + description: Replication resource type of replication session endpoints. + type: str + status: + description: Replication status of the replication session. + type: str + remoteSystem: + description: Specifies the remote system to use as the destination for the replication session. + type: dict + contains: + UnityRemoteSystem: + description: Information about remote storage system. + type: dict + contains: + id: + description: Unique identifier of the remote system instance. + type: str + serialNumber: + description: Serial number of the remote system. + type: str + maxTimeOutOfSync: + description: Maximum time to wait before the system syncs the source and destination resources. + type: int + srcStatus: + description: Status of the source end of the session. + type: str + networkStatus: + description: Status of the network connection used by the replication session. + type: str + dstStatus: + description: Status of the destination end of the replication session. + type: str + lastSyncTime: + description: Date and time of the last replication synchronization. + type: str + syncState: + description: Synchronization state between source and destination resource of the replication session. + type: str + syncProgress: + description: Synchronization completion percentage between source and destination resources of the replication session. + type: int + dstResourceId: + description: Identifier of the destination resource. + type: str + currentTransferEstRemainTime: + description: Estimated time left for the replication synchronization to complete. + type: int + sample: { + "current_transfer_est_remain_time": 0, + "daily_snap_replication_policy": null, + "dst_resource_id": "nas_8", + "dst_spa_interface": { + "UnityRemoteInterface": { + "hash": 8771253398547, + "id": "APM00213404195:if_181" + } + }, + "dst_spb_interface": { + "UnityRemoteInterface": { + "hash": 8771253424144, + "id": "APM00213404195:if_180" + } + }, + "dst_status": "ReplicationSessionStatusEnum.OK", + "existed": true, + "hash": 8771259012271, + "health": { + "UnityHealth": { + "hash": 8771253424168 + } + }, + "hourly_snap_replication_policy": null, + "id": "103079215114_APM00213404195_0000_103079215274_APM00213404194_0000", + "last_sync_time": "2023-04-18 10:35:25+00:00", + "local_role": "ReplicationSessionReplicationRoleEnum.DESTINATION", + "max_time_out_of_sync": 0, + "members": null, + "name": "rep_sess_nas", + "network_status": "ReplicationSessionNetworkStatusEnum.OK", + "remote_system": { + "UnityRemoteSystem": { + "hash": 8771253380142 + } + }, + "replication_resource_type": "ReplicationEndpointResourceTypeEnum.NASSERVER", + "src_resource_id": "nas_213", + "src_spa_interface": { + "UnityRemoteInterface": { + "hash": 8771253475010, + "id": "APM00213404194:if_195" + } + }, + "src_spb_interface": { + "UnityRemoteInterface": { + "hash": 8771253374169, + "id": "APM00213404194:if_194" + } + }, + "src_status": "ReplicationSessionStatusEnum.OK", + "status": "ReplicationOpStatusEnum.ACTIVE", + "sync_progress": 0, + "sync_state": "ReplicationSessionSyncStateEnum.IN_SYNC" + } +''' + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +LOG = utils.get_logger('replication_session') + +application_type = "Ansible/1.7.0" + + +class ReplicationSession(object): + + """Class with replication session operations""" + + def __init__(self): + """Define all parameters required by this module""" + self.module_params = utils.get_unity_management_host_parameters() + self.module_params.update(get_replication_session_parameters()) + + mutually_exclusive = [['session_id', 'session_name']] + + required_one_of = [['session_id', 'session_name']] + + # initialize the Ansible module + self.module = AnsibleModule( + argument_spec=self.module_params, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + required_one_of=required_one_of) + utils.ensure_required_libs(self.module) + self.result = dict( + changed=False, + replication_session_details={} + ) + + self.unity_conn = utils.get_unity_unisphere_connection( + self.module.params, application_type) + LOG.info('Check Mode Flag %s', self.module.check_mode) + + def get_replication_session(self, id=None, name=None): + """Get the details of a replication session. + :param id: The id of the replication session + :param name: The name of the replication session + :return: instance of the replication session if exist. + """ + + id_or_name = id if id else name + errormsg = f"Retrieving details of replication session {id_or_name} failed with error" + + try: + obj_replication_session = self.unity_conn.get_replication_session(name=name, _id=id) + + LOG.info("Successfully retrieved the replication session object %s ", obj_replication_session) + if obj_replication_session.existed: + return obj_replication_session + except utils.HttpError as e: + if e.http_status == 401: + self.module.fail_json(msg=f"Incorrect username or password {str(e)}") + else: + msg = f"{errormsg} {str(e)}" + self.module.fail_json(msg=msg) + except utils.UnityResourceNotFoundError as e: + msg = f"{errormsg} {str(e)}" + LOG.error(msg) + return None + except Exception as e: + msg = f"{errormsg} {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def pause(self, session_obj): + """Pause the replication session. + :param session_obj: Replication session object + :return: True if pause is successful. + """ + try: + LOG.info("Pause replication session %s", session_obj.name) + if session_obj.status.name != utils.ReplicationOpStatusEnum.PAUSED.name: + if not self.module.check_mode: + session_obj.pause() + return True + except Exception as e: + msg = f"Pause replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def resume(self, session_obj, force_full_copy): + """Resume the replication session. + :param session_obj: Replication session object + :param force_full_copy: needed when replication session goes out of sync due to a fault. + :return: True if resume is successful. + """ + try: + LOG.info("Resume replication session %s", session_obj.name) + if session_obj.status.name in (utils.ReplicationOpStatusEnum.PAUSED.name, + utils.ReplicationOpStatusEnum.FAILED_OVER.name, + utils.ReplicationOpStatusEnum.FAILED_OVER_WITH_SYNC.name): + if not self.module.check_mode: + session_obj.resume(force_full_copy=force_full_copy) + return True + except Exception as e: + msg = f"Resume replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def sync(self, session_obj): + """Sync the replication session. + :param session_obj: Replication session object + :return: True if sync is successful. + """ + try: + LOG.info("Sync replication session %s", session_obj.name) + if not self.module.check_mode: + session_obj.sync() + return True + except Exception as e: + msg = f"Sync replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def failover(self, session_obj, sync_failover, force): + """Failover the replication session. + :param session_obj: Replication session object + :param sync_failover: To sync the source and destination resources + :param force: Skip pre-checks on file system(s) replication sessions of a NAS server + :return: True if failover is successful. + """ + try: + LOG.info("Failover replication session %s", session_obj.name) + if (sync_failover and session_obj.status.name != utils.ReplicationOpStatusEnum.FAILED_OVER_WITH_SYNC.name) or \ + (not sync_failover and session_obj.status.name != utils.ReplicationOpStatusEnum.FAILED_OVER.name): + if not self.module.check_mode: + session_obj.failover(sync=sync_failover, force=force) + return True + except Exception as e: + msg = f"Failover replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def failback(self, session_obj, force_full_copy): + """Failback the replication session. + :param session_obj: Replication session object + :param force_full_copy: needed when replication session goes out of sync due to a fault. + :return: True if failback is successful. + """ + try: + LOG.info("Failback replication session %s", session_obj.name) + if session_obj.status.name in (utils.ReplicationOpStatusEnum.FAILED_OVER.name, + utils.ReplicationOpStatusEnum.FAILED_OVER_WITH_SYNC.name, + utils.ReplicationOpStatusEnum.PAUSED.name): + if not self.module.check_mode: + session_obj.failback(force_full_copy=force_full_copy) + return True + except Exception as e: + msg = f"Failback replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + def delete(self, session_obj): + """Delete the replication session. + :param session_obj: Replication session object + :return: True if delete is successful. + """ + try: + LOG.info("Delete replication session %s", session_obj.name) + if not self.module.check_mode: + session_obj.delete() + return True + except Exception as e: + msg = f"Deleting replication session {session_obj.name} failed with error {str(e)}" + LOG.error(msg) + self.module.fail_json(msg=msg) + + +def get_replication_session_parameters(): + """This method provide parameters required for the ansible replication session + module on Unity""" + return dict( + session_id=dict(type='str'), session_name=dict(type='str'), + pause=dict(type='bool'), sync=dict(type='bool'), + force=dict(type='bool'), failover_with_sync=dict(type='bool'), + failback=dict(type='bool'), force_full_copy=dict(type='bool'), + state=dict(type='str', choices=['present', 'absent'], default='present') + ) + + +class ReplicationSessionFailoverHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'present' and session_params['failover_with_sync'] is not None: + session_object.result['changed'] = \ + session_object.failover(replication_session_obj, session_params['failover_with_sync'], session_params['force']) or False + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionFailbackHandler().handle(session_object, session_params, replication_session_obj) + + +class ReplicationSessionFailbackHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'present' and session_params['failback']: + session_object.result['changed'] = \ + session_object.failback(replication_session_obj, session_params['force_full_copy']) or False + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionDeleteHandler().handle(session_object, session_params, replication_session_obj) + + +class ReplicationSessionSyncHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'present' and session_params['sync']: + session_object.result['changed'] = session_object.sync(replication_session_obj) + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionFailoverHandler().handle(session_object, session_params, replication_session_obj) + + +class ReplicationSessionDeleteHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'absent': + session_object.result['changed'] = session_object.delete(replication_session_obj) + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionExitHandler().handle(session_object, replication_session_obj) + + +class ReplicationSessionExitHandler(): + def handle(self, session_object, replication_session_obj): + if replication_session_obj: + session_object.result['replication_session_details'] = replication_session_obj._get_properties() + session_object.module.exit_json(**session_object.result) + + +class ReplicationSessionResumeHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'present' and session_params['pause'] is False: + session_object.result['changed'] = \ + session_object.resume(replication_session_obj, session_params['force_full_copy']) or False + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionSyncHandler().handle(session_object, session_params, replication_session_obj) + + +class ReplicationSessionPauseHandler(): + def handle(self, session_object, session_params, replication_session_obj): + if replication_session_obj and session_params['state'] == 'present' and session_params['pause']: + session_object.result['changed'] = \ + session_object.pause(replication_session_obj) or False + if session_object.result['changed']: + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + ReplicationSessionResumeHandler().handle(session_object, session_params, replication_session_obj) + + +class ReplicationSessionHandler(): + def handle(self, session_object, session_params): + replication_session_obj = session_object.get_replication_session(session_params['session_id'], session_params['session_name']) + if session_params['state'] == 'present' and not replication_session_obj: + session_object.module.fail_json(msg=f"Replication session {session_params['session_id'] or session_params['session_name']} is invalid.") + ReplicationSessionPauseHandler().handle(session_object, session_params, replication_session_obj) + + +def main(): + """ Create Unity replication session object and perform action on it + based on user input from playbook""" + obj = ReplicationSession() + ReplicationSessionHandler().handle(obj, obj.module.params) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/dellemc/unity/plugins/modules/smbshare.py b/ansible_collections/dellemc/unity/plugins/modules/smbshare.py index 58bc8c709..d8b78a7d9 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/smbshare.py +++ b/ansible_collections/dellemc/unity/plugins/modules/smbshare.py @@ -150,11 +150,11 @@ EXAMPLES = r''' nas_server_id: "NAS_11" path: "/sample_fs" description: "Sample SMB share created" - is_abe_enabled: True - is_branch_cache_enabled: True + is_abe_enabled: true + is_branch_cache_enabled: true offline_availability: "DOCUMENTS" - is_continuous_availability_enabled: True - is_encryption_enabled: True + is_continuous_availability_enabled: true + is_encryption_enabled: true umask: "777" state: "present" - name: Modify Attributes of SMB share for a filesystem @@ -166,11 +166,11 @@ EXAMPLES = r''' share_name: "sample_smb_share" nas_server_name: "sample_nas_server" description: "Sample SMB share attributes updated" - is_abe_enabled: False - is_branch_cache_enabled: False + is_abe_enabled: false + is_branch_cache_enabled: false offline_availability: "MANUAL" - is_continuous_availability_enabled: "False" - is_encryption_enabled: "False" + is_continuous_availability_enabled: "false" + is_encryption_enabled: "false" umask: "022" state: "present" - name: Create SMB share for a snapshot @@ -184,10 +184,10 @@ EXAMPLES = r''' nas_server_id: "NAS_11" path: "/sample_snapshot" description: "Sample SMB share created for snapshot" - is_abe_enabled: True - is_branch_cache_enabled: True - is_continuous_availability_enabled: True - is_encryption_enabled: True + is_abe_enabled: true + is_branch_cache_enabled: true + is_continuous_availability_enabled: true + is_encryption_enabled: true umask: "777" state: "present" - name: Modify Attributes of SMB share for a snapshot @@ -199,11 +199,11 @@ EXAMPLES = r''' share_name: "sample_snap_smb_share" snapshot_name: "sample_snapshot" description: "Sample SMB share attributes updated for snapshot" - is_abe_enabled: False - is_branch_cache_enabled: False + is_abe_enabled: false + is_branch_cache_enabled: false offline_availability: "MANUAL" - is_continuous_availability_enabled: "False" - is_encryption_enabled: "False" + is_continuous_availability_enabled: "false" + is_encryption_enabled: "false" umask: "022" state: "present" - name: Get details of SMB share @@ -229,7 +229,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true smb_share_details: description: The SMB share details. type: dict @@ -325,7 +325,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('smbshare') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class SMBShare(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/snapshot.py b/ansible_collections/dellemc/unity/plugins/modules/snapshot.py index c8aba1846..5660e3c5c 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/snapshot.py +++ b/ansible_collections/dellemc/unity/plugins/modules/snapshot.py @@ -122,7 +122,7 @@ EXAMPLES = r''' cg_name: "{{cg_name}}" snapshot_name: "{{cg_snapshot_name}}" description: "{{description}}" - auto_delete: False + auto_delete: false state: "present" - name: Create a Snapshot for a volume with Host attached @@ -257,7 +257,6 @@ snapshot_details: } ''' -import logging from ansible.module_utils.basic import AnsibleModule from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils @@ -265,7 +264,7 @@ from datetime import datetime LOG = utils.get_logger('snapshot') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class Snapshot(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/snapshotschedule.py b/ansible_collections/dellemc/unity/plugins/modules/snapshotschedule.py index aba5524cd..1d6e6ec6c 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/snapshotschedule.py +++ b/ansible_collections/dellemc/unity/plugins/modules/snapshotschedule.py @@ -144,7 +144,7 @@ EXAMPLES = r""" hours_of_day: - 8 - 14 - auto_delete: True + auto_delete: true state: "{{state_present}}" - name: Create snapshot schedule (Rule Type - every_n_days) @@ -185,7 +185,7 @@ EXAMPLES = r""" name: "Ansible_Every_Month_Testing" type: "every_month" day_of_month: 17 - auto_delete: True + auto_delete: true state: "{{state_present}}" - name: Get snapshot schedule details using name @@ -226,7 +226,7 @@ EXAMPLES = r""" name: "Ansible_Every_Day_Testing" type: "every_day" desired_retention: 200 - auto_delete: False + auto_delete: false state: "{{state_present}}" - name: Delete snapshot schedule using id @@ -253,7 +253,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true snapshot_schedule_details: description: Details of the snapshot schedule. @@ -385,14 +385,13 @@ snapshot_schedule_details: } """ -import logging from ansible.module_utils.basic import AnsibleModule from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils LOG = utils.get_logger('snapshotschedule') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class SnapshotSchedule(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/storagepool.py b/ansible_collections/dellemc/unity/plugins/modules/storagepool.py index ddb7eef65..6438e9c6a 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/storagepool.py +++ b/ansible_collections/dellemc/unity/plugins/modules/storagepool.py @@ -217,10 +217,10 @@ EXAMPLES = r''' raid_type : "RAID10" stripe_width : "BEST_FIT" alert_threshold : 50 - is_harvest_enabled : True + is_harvest_enabled : true pool_harvest_high_threshold : 60 pool_harvest_low_threshold : 40 - is_snap_harvest_enabled : True + is_snap_harvest_enabled : true snap_harvest_high_threshold : 70 snap_harvest_low_threshold : 50 fast_vp: "enabled" @@ -235,7 +235,7 @@ RETURN = r''' description: Whether or not the storage pool has changed. returned: always type: bool - sample: True + sample: true storage_pool_details: description: The storage pool details. @@ -464,11 +464,10 @@ RETURN = r''' from ansible.module_utils.basic import AnsibleModule from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils -import logging LOG = utils.get_logger('storagepool') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class StoragePool(object): @@ -499,7 +498,9 @@ class StoragePool(object): details = api_response._get_properties() is_fast_vp_enabled = api_response._get_property_from_raw( - 'pool_fast_vp').is_schedule_enabled + 'pool_fast_vp') + if is_fast_vp_enabled: + is_fast_vp_enabled = is_fast_vp_enabled.is_schedule_enabled details['is_fast_vp_enabled'] = is_fast_vp_enabled details['size_free_with_unit'] = utils.\ diff --git a/ansible_collections/dellemc/unity/plugins/modules/tree_quota.py b/ansible_collections/dellemc/unity/plugins/modules/tree_quota.py index 063834b45..b066a01fa 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/tree_quota.py +++ b/ansible_collections/dellemc/unity/plugins/modules/tree_quota.py @@ -199,7 +199,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true get_tree_quota_details: description: Details of the quota tree. @@ -283,7 +283,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('tree_quota') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class QuotaTree(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/user_quota.py b/ansible_collections/dellemc/unity/plugins/modules/user_quota.py index d9116c3a5..06413aa53 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/user_quota.py +++ b/ansible_collections/dellemc/unity/plugins/modules/user_quota.py @@ -294,7 +294,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true get_user_quota_details: description: Details of the user quota. @@ -427,7 +427,7 @@ from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ LOG = utils.get_logger('user_quota') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" class UserQuota(object): diff --git a/ansible_collections/dellemc/unity/plugins/modules/volume.py b/ansible_collections/dellemc/unity/plugins/modules/volume.py index 82bcb0174..81790ea24 100644 --- a/ansible_collections/dellemc/unity/plugins/modules/volume.py +++ b/ansible_collections/dellemc/unity/plugins/modules/volume.py @@ -177,9 +177,9 @@ EXAMPLES = r""" pool_name: "{{pool}}" size: 2 cap_unit: "{{cap_GB}}" - is_thin: True - compression: True - advanced_dedup: True + is_thin: true + compression: true + advanced_dedup: true state: "{{state_present}}" - name: Expand Volume by volume id @@ -240,9 +240,9 @@ EXAMPLES = r""" vol_name: "{{vol_name}}" new_vol_name: "{{new_vol_name}}" tiering_policy: "AUTOTIER" - compression: True - is_thin: True - advanced_dedup: True + compression: true + is_thin: true + advanced_dedup: true state: "{{state_present}}" - name: Delete Volume by vol name @@ -270,7 +270,7 @@ changed: description: Whether or not the resource has changed. returned: always type: bool - sample: True + sample: true volume_details: description: Details of the volume. @@ -392,11 +392,10 @@ volume_details: from ansible.module_utils.basic import AnsibleModule from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ import utils -import logging LOG = utils.get_logger('volume') -application_type = "Ansible/1.6.0" +application_type = "Ansible/1.7.1" def is_none_or_empty_string(param): |