diff options
Diffstat (limited to 'ansible_collections/dellemc/unity/tests')
26 files changed, 3392 insertions, 0 deletions
diff --git a/ansible_collections/dellemc/unity/tests/requirements.txt b/ansible_collections/dellemc/unity/tests/requirements.txt new file mode 100644 index 000000000..3541acd15 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/requirements.txt @@ -0,0 +1,7 @@ +pytest +pytest-xdist +pytest-mock +pytest-cov +pytest-forked +coverage==4.5.4 +mock diff --git a/ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt new file mode 100644 index 000000000..f78c82922 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.12.txt @@ -0,0 +1,33 @@ +plugins/modules/nfs.py compile-2.6 +plugins/modules/nfs.py import-2.6 +plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license +plugins/modules/filesystem.py validate-modules:missing-gplv3-license +plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license +plugins/modules/info.py validate-modules:missing-gplv3-license +plugins/modules/host.py validate-modules:missing-gplv3-license +plugins/modules/nasserver.py validate-modules:missing-gplv3-license +plugins/modules/nfs.py validate-modules:missing-gplv3-license +plugins/modules/smbshare.py validate-modules:missing-gplv3-license +plugins/modules/snapshot.py validate-modules:missing-gplv3-license +plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license +plugins/modules/storagepool.py validate-modules:missing-gplv3-license +plugins/modules/tree_quota.py validate-modules:missing-gplv3-license +plugins/modules/user_quota.py validate-modules:missing-gplv3-license +plugins/modules/volume.py validate-modules:missing-gplv3-license +plugins/modules/cifsserver.py validate-modules:missing-gplv3-license +plugins/modules/nfsserver.py validate-modules:missing-gplv3-license +plugins/modules/host.py import-2.6 +plugins/modules/host.py import-2.7 +plugins/modules/interface.py import-2.6 +plugins/modules/interface.py import-2.7 +plugins/modules/nfs.py import-2.7 +plugins/modules/nfs.py import-3.5 +plugins/modules/nfs.py compile-2.7 +plugins/modules/nfs.py compile-3.5 +plugins/modules/filesystem.py import-2.6 +plugins/modules/filesystem.py compile-2.6 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 +plugins/modules/interface.py validate-modules:missing-gplv3-license
\ No newline at end of file diff --git a/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt new file mode 100644 index 000000000..a175e9976 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.13.txt @@ -0,0 +1,27 @@ +plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license +plugins/modules/filesystem.py validate-modules:missing-gplv3-license +plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license +plugins/modules/info.py validate-modules:missing-gplv3-license +plugins/modules/host.py validate-modules:missing-gplv3-license +plugins/modules/nasserver.py validate-modules:missing-gplv3-license +plugins/modules/nfs.py validate-modules:missing-gplv3-license +plugins/modules/smbshare.py validate-modules:missing-gplv3-license +plugins/modules/snapshot.py validate-modules:missing-gplv3-license +plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license +plugins/modules/storagepool.py validate-modules:missing-gplv3-license +plugins/modules/tree_quota.py validate-modules:missing-gplv3-license +plugins/modules/user_quota.py validate-modules:missing-gplv3-license +plugins/modules/volume.py validate-modules:missing-gplv3-license +plugins/modules/cifsserver.py validate-modules:missing-gplv3-license +plugins/modules/nfsserver.py validate-modules:missing-gplv3-license +plugins/modules/host.py import-2.7 +plugins/modules/interface.py import-2.7 +plugins/modules/nfs.py import-2.7 +plugins/modules/nfs.py import-3.5 +plugins/modules/nfs.py compile-2.7 +plugins/modules/nfs.py compile-3.5 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 +plugins/modules/interface.py validate-modules:missing-gplv3-license diff --git a/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt new file mode 100644 index 000000000..a175e9976 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/sanity/ignore-2.14.txt @@ -0,0 +1,27 @@ +plugins/modules/consistencygroup.py validate-modules:missing-gplv3-license +plugins/modules/filesystem.py validate-modules:missing-gplv3-license +plugins/modules/filesystem_snapshot.py validate-modules:missing-gplv3-license +plugins/modules/info.py validate-modules:missing-gplv3-license +plugins/modules/host.py validate-modules:missing-gplv3-license +plugins/modules/nasserver.py validate-modules:missing-gplv3-license +plugins/modules/nfs.py validate-modules:missing-gplv3-license +plugins/modules/smbshare.py validate-modules:missing-gplv3-license +plugins/modules/snapshot.py validate-modules:missing-gplv3-license +plugins/modules/snapshotschedule.py validate-modules:missing-gplv3-license +plugins/modules/storagepool.py validate-modules:missing-gplv3-license +plugins/modules/tree_quota.py validate-modules:missing-gplv3-license +plugins/modules/user_quota.py validate-modules:missing-gplv3-license +plugins/modules/volume.py validate-modules:missing-gplv3-license +plugins/modules/cifsserver.py validate-modules:missing-gplv3-license +plugins/modules/nfsserver.py validate-modules:missing-gplv3-license +plugins/modules/host.py import-2.7 +plugins/modules/interface.py import-2.7 +plugins/modules/nfs.py import-2.7 +plugins/modules/nfs.py import-3.5 +plugins/modules/nfs.py compile-2.7 +plugins/modules/nfs.py compile-3.5 +plugins/modules/filesystem.py compile-2.7 +plugins/modules/filesystem.py compile-3.5 +plugins/modules/filesystem.py import-2.7 +plugins/modules/filesystem.py import-3.5 +plugins/modules/interface.py validate-modules:missing-gplv3-license diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py new file mode 100644 index 000000000..4ddee9661 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_api_exception.py @@ -0,0 +1,19 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock ApiException for Unity Test modules""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + + +class MockApiException(Exception): + body = "SDK Error message" + status = "500" + + +class HttpError(Exception): + body = "Http Error message" + http_status = 401 diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py new file mode 100644 index 000000000..427d530fa --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_cifsserver_api.py @@ -0,0 +1,200 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of CIFS server module on Unity""" + +from __future__ import (absolute_import, division, print_function) +from unittest.mock import MagicMock + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockCIFSServerApi: + CIFS_SERVER_MODULE_ARGS = { + 'nas_server_id': None, + 'nas_server_name': None, + 'netbios_name': None, + 'workgroup': None, + 'local_password': None, + 'domain': None, + 'domain_username': None, + 'domain_password': None, + 'cifs_server_id': None, + 'cifs_server_name': None, + 'interfaces': None, + 'unjoin_cifs_server_account': None, + 'state': None + } + + @staticmethod + def get_cifs_server_details_method_response(): + return { + "description": None, + "domain": "xxx.xxx.xxx.xxx", + "existed": True, + "file_interfaces": { + "UnityFileInterfaceList": [ + { + "UnityFileInterface": { + "hash": 8791477905949, + "id": "if_43" + } + } + ] + }, + "hash": 8791478461637, + "health": { + "UnityHealth": { + "hash": 8791478461623 + } + }, + "id": "cifs_59", + "is_standalone": False, + "last_used_organizational_unit": "ou=Computers,ou=EMC NAS servers", + "name": "test_cifs_server", + "nas_server": { + "UnityNasServer": { + "hash": 8791478461595, + "id": "nas_18" + } + }, + "netbios_name": "TEST_CIFS_SERVER", + "smb_multi_channel_supported": True, + "smb_protocol_versions": [ + "1.0", + "2.0", + "2.1", + "3.0" + ], + "smbca_supported": True, + "workgroup": None + } + + @staticmethod + def get_cifs_server_details_method_netbios_response(): + return { + "UnityCifsServerList": [{ + "UnityCifsServer": { + "existed": True, + "file_interfaces": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": -9223363293222387298, + "id": "if_43" + } + }] + }, + "hash": 8743632213638, + "health": { + "UnityHealth": { + "hash": -9223363293222562209 + } + }, + "id": "cifs_60", + "is_standalone": True, + "nas_server": { + "UnityNasServer": { + "hash": -9223363293221242245, + "id": "nas_18" + } + }, + "netbios_name": "ANSIBLE_CIFS", + "smb_multi_channel_supported": True, + "smb_protocol_versions": ["1.0", "2.0", "2.1", "3.0"], + "smbca_supported": True, + "workgroup": "ANSIBLE" + } + }] + } + + @staticmethod + def create_cifs_server_without_nas(): + return "Please provide nas server id/name to create CIFS server." + + @staticmethod + def invalid_credentials(): + return "Incorrect username or password provided." + + @staticmethod + def modify_error_msg(): + return "Modification is not supported through Ansible module" + + @staticmethod + def get_nas_server_details(): + return { + "UnityNasServer": { + "cifs_server": { + "UnityCifsServerList": [{ + "UnityCifsServer": { + "hash": 8734183189936, + "id": "cifs_60" + } + }] + }, + "current_sp": { + "UnityStorageProcessor": { + "hash": 8734188780762, + "id": "spa" + } + }, + "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NONE", + "existed": True, + "file_dns_server": { + "UnityFileDnsServer": { + "hash": 8734183189782, + "id": "dns_11" + } + }, + "file_interface": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": -9223363302671584431, + "id": "if_43" + } + }] + }, + "hash": -9223363302671053452, + "health": { + "UnityHealth": { + "hash": 8734182402245 + } + }, + "home_sp": { + "UnityStorageProcessor": { + "hash": -9223363302671594510, + "id": "spa" + } + }, + "id": "nas_18", + "is_backup_only": False, + "is_multi_protocol_enabled": False, + "is_packet_reflect_enabled": False, + "is_replication_destination": False, + "is_replication_enabled": False, + "name": "test_nas1", + "pool": { + "UnityPool": { + "hash": -9223363302672128291, + "id": "pool_7" + } + }, + "preferred_interface_settings": { + "UnityPreferredInterfaceSettings": { + "hash": -9223363302671585904, + "id": "preferred_if_16" + } + }, + "replication_type": "ReplicationTypeEnum.NONE", + "size_allocated": 2952790016, + "virus_checker": { + "UnityVirusChecker": { + "hash": 8734183191465, + "id": "cava_18" + } + } + } + } diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py new file mode 100644 index 000000000..07fe6b5d7 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_consistencygroup_api.py @@ -0,0 +1,122 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of consistency group module on Unity""" + +from __future__ import (absolute_import, division, print_function) +from unittest.mock import MagicMock + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockConsistenyGroupApi: + CONSISTENCY_GROUP_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'cg_id': None, + 'cg_name': None, + 'new_cg_name': None, + 'pool_id': None, + 'description': None, + 'snap_schedule': None, + 'tiering_policy': None, + 'volumes': [], + 'vol_state': None, + 'hosts': [], + 'mapping_state': None, + 'replication_params': {}, + 'replication_state': None, + 'state': None + } + IP_ADDRESS_MOCK_VALUE = '***.***.***.**' + + @staticmethod + def cg_get_details_method_response(): + return {'advanced_dedup_status': 'DedupStatusEnum.DISABLED', 'block_host_access': None, 'data_reduction_percent': 0, + 'data_reduction_ratio': 1.0, 'data_reduction_size_saved': 0, 'data_reduction_status': 'DataReductionStatusEnum.DISABLED', + 'datastores': None, 'dedup_status': None, 'description': '', 'esx_filesystem_block_size': None, + 'esx_filesystem_major_version': None, 'filesystem': None, 'health': {}, 'host_v_vol_datastore': None, + 'id': 'cg_id_1', 'is_replication_destination': False, 'is_snap_schedule_paused': None, + 'luns': [{'id': 'lun_id_1', 'name': 'test_lun_cg_issue', 'is_thin_enabled': False, + 'size_total': 1, 'is_data_reduction_enabled': False}], + 'name': 'lun_test_cg_source_12', 'per_tier_size_used': [1, 0, 0], + 'pools': [{'id': 'pool_id_1'}], + 'relocation_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', 'replication_type': 'ReplicationTypeEnum.NONE', + 'size_allocated': 0, 'size_total': 1, 'size_used': None, 'snap_count': 0, 'snap_schedule': None, + 'snaps_size_allocated': 0, 'snaps_size_total': 0, 'thin_status': 'ThinStatusEnum.TRUE', + 'type': 'StorageResourceTypeEnum.CONSISTENCY_GROUP', 'virtual_volumes': None, 'vmware_uuid': None, + 'existed': True, 'snapshots': [], 'cg_replication_enabled': False} + + @staticmethod + def get_cg_object(): + return MockSDKObject({'advanced_dedup_status': 'DedupStatusEnum.DISABLED', 'block_host_access': None, + 'data_reduction_percent': 0, 'data_reduction_ratio': 1.0, 'data_reduction_size_saved': 0, + 'data_reduction_status': 'DataReductionStatusEnum.DISABLED', + 'datastores': None, 'dedup_status': None, 'description': '', 'esx_filesystem_block_size': None, + 'esx_filesystem_major_version': None, 'filesystem': None, 'health': {}, 'host_v_vol_datastore': None, + 'id': 'cg_id_1', 'is_replication_destination': False, 'is_snap_schedule_paused': None, + 'luns': [MockSDKObject({'id': 'lun_id_1', 'name': 'test_lun_cg_issue', + 'is_thin_enabled': False, 'size_total': 1, 'is_data_reduction_enabled': False})], + 'name': 'lun_test_cg_source_12', 'per_tier_size_used': [1, 0, 0], + 'pools': [MockSDKObject({'id': 'pool_id_1'})], + 'relocation_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', 'replication_type': 'ReplicationTypeEnum.NONE', + 'size_allocated': 0, 'size_total': 1, 'size_used': None, 'snap_count': 0, 'snap_schedule': None, + 'snaps_size_allocated': 0, 'snaps_size_total': 0, 'thin_status': 'ThinStatusEnum.TRUE', + 'type': 'StorageResourceTypeEnum.CONSISTENCY_GROUP', 'virtual_volumes': None, 'vmware_uuid': None, + 'existed': True, 'snapshots': [], 'cg_replication_enabled': False}) + + @staticmethod + def get_cg_replication_dependent_response(response_type): + if response_type == 'cg_replication_enabled_details': + cg_replication_enabled_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_replication_enabled_details['cg_replication_enabled'] = True + return cg_replication_enabled_details + elif response_type == 'remote_system': + return [MockSDKObject({"connection_type": "ReplicationCapabilityEnum.ASYNC", "existed": True, + "health": {"UnityHealth": {}}, "id": "system_id_1", "local_spa_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE], + "local_spb_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE], + "management_address": "**.***.**.**", "model": "U XXX", + "name": "ABXXXXXX", "remote_spa_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE], + "remote_spb_interfaces": [MockConsistenyGroupApi.IP_ADDRESS_MOCK_VALUE], + "serial_number": "ABXXXXXX", "sync_fc_ports": ["abc_def", "ghi_jkl"], "username": "username"})] + elif response_type == 'remote_system_pool_object': + return MockSDKObject({"alert_threshold": 60, "creation_time": "2021-10-18 12:51:27+00:00", "description": "", + "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE", "health": {"UnityHealth": {}}, + "id": "pool_3", "is_all_flash": True, "is_empty": False, "is_fast_cache_enabled": False, + "is_harvest_enabled": True, "is_snap_harvest_enabled": True, "name": "Extreme_Perf_tier", + "object_id": 1, "pool_fast_vp": {"UnityPoolFastVp": {}}, "pool_space_harvest_high_threshold": 95.0, + "pool_space_harvest_low_threshold": 70.5, "pool_type": "StoragePoolTypeEnum.DYNAMIC", + "raid_type": "RaidTypeEnum.RAID5", "size_free": 1, "size_subscribed": 1, "size_total": 1, + "size_used": 1, "snap_size_subscribed": 1, "snap_size_used": 1, "snap_space_harvest_high_threshold": 20.5, + "snap_space_harvest_low_threshold": 1.0, + "tiers": {"UnityPoolTierList": [{"UnityPoolTier": {}}, {"UnityPoolTier": {}}, {"UnityPoolTier": {}}]}}) + elif response_type == 'replication_session': + return MockSDKObject({"current_transfer_est_remain_time": 0, "daily_snap_replication_policy": {}, + "dst_resource_id": "dest_id_1", "dst_status": "ReplicationSessionStatusEnum.OK", "existed": True, + "health": {}, "hourly_snap_replication_policy": {}, + "id": "111111_XXX1111111_0000_1111111_XXX111111111_0000", + "last_sync_time": "2022-02-17 09: 50: 54+00: 00", + "local_role": "ReplicationSessionReplicationRoleEnum.LOOPBACK", + "max_time_out_of_sync": 60, "members": {}, "name": "rep_session_1", + "network_status": "ReplicationSessionNetworkStatusEnum.OK", "remote_system": {}, + "replication_resource_type": "ReplicationEndpointResourceTypeEnum.CONSISTENCYGROUP", + "src_resource_id": "src_id_1", + "src_status": "ReplicationSessionStatusEnum.OK", + "status": "ReplicationOpStatusEnum.AUTO_SYNC_CONFIGURED", + "sync_progress": 0, "sync_state": "ReplicationSessionSyncStateEnum.IDLE"}) + elif response_type == 'destination_cg_name_validation': + return 'destination_cg_name value should be in range of 1 to 95' + elif response_type == 'enable_cg_exception': + return 'Enabling replication to the consistency group lun_test_cg_source_12 failed with error ' + elif response_type == 'disable_cg_exception': + return 'Disabling replication to the consistency group lun_test_cg_source_12 failed with error ' + + @staticmethod + def get_remote_system_conn_response(): + conn = MockConsistenyGroupApi.get_cg_replication_dependent_response("remote_system")[0] + conn.get_pool = MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system_pool_object')) + return conn diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py new file mode 100644 index 000000000..d855815a2 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_filesystem_api.py @@ -0,0 +1,68 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of FileSystem module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockFileSystemApi: + @staticmethod + def get_file_system_response(): + filesystem_response = {"UnityFileSystem": { + "access_policy": "AccessPolicyEnum.NATIVE", + "cifs_notify_on_change_dir_depth": 512, + "data_reduction_percent": 0, + "data_reduction_ratio": 1.0, + "data_reduction_size_saved": 0, + "description": "", + "existed": True, + "size_total": 5, + "folder_rename_policy": "FSRenamePolicyEnum.SMB_RENAME_FORBIDDEN", + "id": "fs_208", + "replication_type": "Remote"}} + filesystem_response['storage_resource'] = MockSDKObject({'replication_type': None}) + return filesystem_response + + @staticmethod + def get_replication_params(is_valid=True): + rpo = 60 + if not is_valid: + rpo = 2 + return {'replication_params': { + 'replication_name': None, + 'new_replication_name': None, + 'replication_mode': 'asynchronous', + 'replication_type': 'local', + 'rpo': rpo, + 'remote_system': None, + 'destination_pool_name': 'pool_test_name_1', + 'destination_pool_id': None}, + 'replication_state': 'enable', + 'state': 'present' + } + else: + return {'replication_params': { + 'replication_name': None, + 'replication_mode': 'asynchronous', + 'new_replication_name': None, + 'replication_type': 'remote', + 'rpo': rpo, + 'remote_system': { + 'remote_system_host': '1.1.1.1', + 'remote_system_verifycert': False, + 'remote_system_username': 'username', + 'remote_system_password': 'password', + 'remote_system_port': 1 + }, + 'destination_pool_name': 'pool_test_name_1', + 'destination_pool_id': None}, + 'replication_state': 'enable', + 'state': 'present' + } diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py new file mode 100644 index 000000000..4e93b6285 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_host_api.py @@ -0,0 +1,154 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of host module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockHostApi: + HOST_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'host_id': None, + 'host_name': None, + 'host_os': None, + 'description': None, + 'initiators': None, + 'initiator_state': None, + 'new_host_name': None, + 'network_address': None, + 'network_address_state': None, + 'state': None + } + + IP_ADDRESS_MOCK_VALUE = '***.***.*.*' + IQN_INITIATOR_MOCK_VALUE = 'iqn.1111-11.com.vmware: host_name_1-111111f' + + @staticmethod + def get_host_count_response(): + return [{"auto_manage_type": "HostManageEnum.OTHERS", "description": "", "existed": True, + "fc_host_initiators": {"UnityHostInitiatorList": [{"UnityHostInitiator": {}}]}, "health": + {"UnityHealth": {}}, "host_ip_ports": {"UnityHostIpPortList": [{"UnityHostIpPort": {}}, + {"UnityHostIpPort": {}}]}, "host_pushed_uuid": "1-1-1-1-1", + "id": "Host_id_1", "iscsi_host_initiators": {"UnityHostInitiatorList": [{"UnityHostInitiator": {}}]}, + "name": "host_name_1", "os_type": "XXXXXXXX", "type": "HostTypeEnum.HOST_AUTO"}] + + @staticmethod + def get_host_initiators_list(): + return ['1:1:1:1:1:1:1:1:1', MockHostApi.IQN_INITIATOR_MOCK_VALUE] + + @staticmethod + def get_host_details_response(response_type): + if response_type == 'api': + return {'auto_manage_type': 'HostManageEnum.OTHERS', 'datastores': None, 'description': '', + 'fc_host_initiators': [MockSDKObject({'chap_user_name': None, + 'health': {'UnityHealth': {}}, 'id': 'HostInitiator_fc_1', + 'initiator_id': '1:1:1:1:1:1:1:1:1', + 'initiator_source_type': 'HostInitiatorSourceTypeEnum.OPEN_NATIVE', 'is_bound': None, + 'is_chap_secret_enabled': False, + 'is_ignored': False, 'iscsi_type': None, + 'node_wwn': '11:12:13:14:**:**:**:**', + 'parent_host': {'UnityHost': {'id': 'Host_id_1'}}, + 'paths': [MockSDKObject({'id': 'HostInitiator_mock_6', 'is_logged_in': True}), + MockSDKObject({'id': 'HostInitiator_mock_5', 'is_logged_in': True}), + MockSDKObject({'id': 'HostInitiator_mock_4', 'is_logged_in': True}), + MockSDKObject({'id': 'HostInitiator_mock_3', 'is_logged_in': True})], + 'port_wwn': '10:10:10:10:10:10:10:10:10', 'source_type': None, + 'type': 'HostInitiatorTypeEnum.FC', 'existed': True})], + 'host_container': None, 'host_ip_ports': [MockSDKObject({'address': MockHostApi.IP_ADDRESS_MOCK_VALUE, + 'host': None, 'id': 'HostNetworkAddress_1', + 'is_ignored': None, 'name': None, 'netmask': None, 'type': None, + 'v6_prefix_length': None, 'existed': True}), + MockSDKObject({'address': 'host_name_1', 'host': None, 'id': 'HostNetworkAddress_2', + 'is_ignored': None, 'name': None, 'netmask': None, 'type': None, + 'v6_prefix_length': None, 'existed': True})], + 'host_luns': MockSDKObject({'lun': + [MockSDKObject({'hlu': 1, 'host': None, 'id': 'host_a', 'name': 'host_name_a', 'is_read_only': None, + 'lun': {'UnityLun': {}}, 'snap': None, 'type': None, 'existed': True}), + MockSDKObject({'hlu': 0, 'host': None, 'id': 'host_b', 'name': 'host_name_b', 'is_read_only': None, + 'lun': {'UnityLun': {}}, 'snap': None, 'type': None, 'existed': True})]}), + 'host_polled_uuid': None, 'host_pushed_uuid': '1-1-1-1-1', + 'host_uuid': None, 'host_v_vol_datastore': None, 'id': 'Host_id_1', + 'iscsi_host_initiators': [MockSDKObject({'chap_user_name': None, 'health': {'UnityHealth': {}}, 'id': 'HostInitiator_iscsi_1', + 'initiator_id': MockHostApi.IQN_INITIATOR_MOCK_VALUE, + 'initiator_source_type': 'HostInitiatorSourceTypeEnum.OPEN_NATIVE', 'is_bound': True, + 'is_chap_secret_enabled': False, 'is_ignored': False, + 'iscsi_type': 'HostInitiatorIscsiTypeEnum.SOFTWARE', 'node_wwn': None, + 'parent_host': {'UnityHost': {'id': 'Host_id_1'}}, + 'paths': [MockSDKObject({'id': 'HostInitiator_mock_1', 'is_logged_in': True}), + MockSDKObject({'id': 'HostInitiator_mock_2', 'is_logged_in': True})], + 'port_wwn': None, 'source_type': None, 'type': 'HostInitiatorTypeEnum.ISCSI', + 'existed': True})], + 'last_poll_time': None, 'name': 'host_name_1', + 'os_type': 'XXXXXXXX', 'registration_type': None, 'storage_resources': None, 'tenant': None, + 'type': 'HostTypeEnum.HOST_AUTO', + 'vms': None, 'existed': True, 'health': {'UnityHealth': {}}} + elif response_type == 'module': + return {'changed': False, + 'host_details': {'auto_manage_type': 'HostManageEnum.OTHERS', 'datastores': None, 'description': '', + 'fc_host_initiators': [{'id': 'HostInitiator_fc_1', + 'name': '1:1:1:1:1:1:1:1:1', + 'paths': [{'id': 'HostInitiator_mock_6', + 'is_logged_in': True}, + {'id': 'HostInitiator_mock_5', + 'is_logged_in': True}, + {'id': 'HostInitiator_mock_4', + 'is_logged_in': True}, + {'id': 'HostInitiator_mock_3', + 'is_logged_in': True}]}], + 'health': {'UnityHealth': {}}, + 'host_container': None, + 'host_luns': [{'id': "host_a", 'name': 'host_name_a'}, {'id': 'host_b', 'name': 'host_name_b'}], + 'host_polled_uuid': None, 'host_pushed_uuid': '1-1-1-1-1', + 'host_uuid': None, 'host_v_vol_datastore': None, 'id': 'Host_id_1', + 'iscsi_host_initiators': [{'id': 'HostInitiator_iscsi_1', + 'name': MockHostApi.IQN_INITIATOR_MOCK_VALUE, + 'paths': [{'id': 'HostInitiator_mock_1', + 'is_logged_in': True}, + {'id': 'HostInitiator_mock_2', + 'is_logged_in': True}]}], + 'last_poll_time': None, 'name': 'host_name_1', 'os_type': 'XXXXXXXX', + 'registration_type': None, 'storage_resources': None, 'tenant': None, + 'type': 'HostTypeEnum.HOST_AUTO', 'vms': None, 'existed': True, + 'network_addresses': [MockHostApi.IP_ADDRESS_MOCK_VALUE, 'host_name_1']}} + elif response_type == 'error': + return "Incorrect username or password provided." + + @staticmethod + def get_host_details_after_network_address_addition(response_type): + if response_type == 'api': + host_object = MockHostApi.get_host_details_response('api') + host_object['host_ip_ports'].append(MockSDKObject({'address': 'net_add_1', 'host': None, 'id': 'HostNetworkAddress_3', + 'is_ignored': None, 'name': None, 'netmask': None, 'type': None, + 'v6_prefix_length': None, 'existed': True})) + return host_object + elif response_type == 'module': + host_module_response = MockHostApi.get_host_details_response('module') + host_module_response['host_details']['network_addresses'].append('net_add_1') + host_module_response['changed'] = True + return host_module_response + elif response_type == 'invalid_address': + return 'Please enter valid IPV4 address or host name for network address' + + @staticmethod + def get_host_details_after_network_address_removal(response_type): + if response_type == 'api': + host_object = MockHostApi.get_host_details_response('api') + host_object['host_ip_ports'] = [MockSDKObject({'address': MockHostApi.IP_ADDRESS_MOCK_VALUE, 'host': None, 'id': 'HostNetworkAddress_1', + 'is_ignored': None, 'name': None, 'netmask': None, 'type': None, + 'v6_prefix_length': None, 'existed': True})] + return host_object + elif response_type == 'module': + host_module_response = MockHostApi.get_host_details_response('module') + host_module_response['host_details']['network_addresses'].remove('host_name_1') + host_module_response['changed'] = True + return host_module_response + elif response_type == 'invalid_IPV4': + return 'Please enter valid IPV4 address for network address' diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py new file mode 100644 index 000000000..6bd53ea9b --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_interface_api.py @@ -0,0 +1,122 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of interface on Unity""" + +from __future__ import (absolute_import, division, print_function) +from unittest.mock import MagicMock + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from copy import deepcopy + + +class MockInterfaceApi: + INTERFACE_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'nas_server_id': None, + 'nas_server_name': None, + 'ethernet_port_name': None, + 'ethernet_port_id': None, + 'role': None, + 'interface_ip': None, + 'netmask': None, + 'prefix_length': None, + 'gateway': None, + 'vlan_id': None, + 'state': None + } + ETHERNET_PORT_NAME = "Card Ethernet Port" + NETMASK_DUMMY = "255.xx.xx.xx" + GATEWAY_DUMMY = "10.***.**.1" + INTERFACE_DUMMY = "10.***.**.**" + + NAS_SERVER_OBJECT = \ + MockSDKObject({'allow_unmapped_user': None, 'cifs_server': {'UnityCifsServerList': [{'UnityCifsServer': {'id': 'cifs_id_0'}}]}, + 'current_sp': {'UnityStorageProcessor': {'id': 'abc'}}, + 'current_unix_directory_service': 'NasServerUnixDirectoryServiceEnum.NIS', 'default_unix_user': None, + 'default_windows_user': None, 'file_dns_server': {'UnityFileDnsServer': {'id': 'dns_id_0'}}, + 'file_interface': {'UnityFileInterfaceList': [{'UnityFileInterface': {'id': 'file_interface_id_0'}}]}, + 'filesystems': {'UnityFileSystemList': [{'UnityFileSystem': {'id': 'fs_id_0'}}]}, + 'home_sp': {'UnityStorageProcessor': {'id': 'abd'}}, + 'id': 'nas_id_00', 'is_backup_only': False, 'is_multi_protocol_enabled': False, + 'is_packet_reflect_enabled': False, 'is_replication_destination': False, + 'is_replication_enabled': True, 'is_windows_to_unix_username_mapping_enabled': None, + 'name': 'dummy_nas', 'pool': {'UnityPool': {'id': 'pool_id_0'}}, + 'preferred_interface_settings': {'UnityPreferredInterfaceSettings': {'id': 'preferred_interface_0'}}, + 'replication_type': 'ReplicationTypeEnum.MIXED', + 'tenant': None, 'virus_checker': {'UnityVirusChecker': {'id': 'cava_id_0'}}, + 'existed': True}) + + INTERFACE_OBJECT = \ + MockSDKObject({"existed": True, + "gateway": GATEWAY_DUMMY, + "id": "file_interface_id_0", + "ip_address": INTERFACE_DUMMY, + "ip_port": {"UnityIpPort": {"id": "ethernet_port_id_0"}}, + "ip_protocol_version": "IpProtocolVersionEnum.IPv4", + "is_disabled": False, "is_preferred": True, + "mac_address": "AA:AA:AA:**:**:**", + "name": "dummy_if_name", + "nas_server": {"UnityNasServer": {"id": "nas_id_00"}}, + "netmask": NETMASK_DUMMY, + "role": "FileInterfaceRoleEnum.BACKUP", + "vlan_id": 324}) + + FILE_INTERFACE_ROLE_ENUM_DUMMY = { + 'PRODUCTION': (0, 'Production'), + 'BACKUP': (1, 'Backup') + } + + @staticmethod + def get_nas_without_interface(): + nas_object = deepcopy(MockInterfaceApi.NAS_SERVER_OBJECT) + nas_object.file_interface['UnityFileInterfaceList'] = [] + return nas_object + + @staticmethod + def get_nas_server_obj_existed_false(): + nas_object = deepcopy(MockInterfaceApi.NAS_SERVER_OBJECT) + nas_object.existed = False + return nas_object + + @staticmethod + def get_interface_exception_response(response_type): + if response_type == 'nas_server_id_exception': + return "Failed to get details of NAS server: dummy_nas with error: " + elif response_type == 'interface_exception': + return "Getting Interface details failed with error " + elif response_type == 'add_interface_exception': + return "Failed to add interface to NAS Server with error: " + elif response_type == 'delete_interface_exception': + return "Failed to delete interface with error: " + + @staticmethod + def get_interface_error_response(response_type): + if response_type == 'invalid_ethernet_port_name': + return "Please provide valid value for: ethernet_port_name" + elif response_type == 'invalid_vlan_id': + return "vlan_id should be in the range of 3 to 4094" + elif response_type == 'invalid_interface_ip': + return 'The value for interface ip is invalid' + elif response_type == 'invalid_gateway': + return "The value for gateway is invalid" + elif response_type == 'invalid_netmask': + return 'Invalid IPV4 address specified for netmask' + elif response_type == 'modify_failure': + return "Modification of Interfaces for NAS server is not supported through Ansible module" + elif response_type == 'no_role': + return "Role is a mandatory parameter for adding interface to NAS Server." + elif response_type == 'no_ethernet': + return "ethernet_port_name/ethernet_port_id is mandatory parameter for adding interface to NAS Server." + + @staticmethod + def get_nas_server_obj_errors(response_type): + if response_type == 'existed_false': + return "NAS server with id nas_id_00 does not exist" + elif response_type == 'exception': + return "Failed to get details of NAS server with error: " diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py new file mode 100644 index 000000000..cb11e6d8e --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nasserver_api.py @@ -0,0 +1,64 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of NASServer module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + + +class MockNASServerApi: + @staticmethod + def get_nas_server_response(): + return ({"access_policy": "AccessPolicyEnum.NATIVE", + "cifs_notify_on_change_dir_depth": 512, + "data_reduction_percent": 0, + "data_reduction_ratio": 1.0, + "data_reduction_size_saved": 0, + "description": "", + "existed": True, + "size_total": 5, + "id": "nas0", + "name": "nas0", + "replication_type": "Remote"}) + + @staticmethod + def get_replication_params(is_valid=True): + rpo = 60 + if not is_valid: + rpo = 2 + return {'replication_params': { + 'replication_name': None, + 'new_replication_name': None, + 'replication_type': 'local', + 'replication_mode': 'asynchronous', + 'rpo': rpo, + 'remote_system': None, + 'destination_nas_server_name': None, + 'destination_pool_name': 'pool_test_name_1', + 'destination_pool_id': None}, + 'replication_state': 'enable', + 'state': 'present' + } + else: + return {'replication_params': { + 'replication_name': None, + 'replication_mode': 'asynchronous', + 'new_replication_name': None, + 'replication_type': 'remote', + 'rpo': rpo, + 'remote_system': { + 'remote_system_host': '1.1.1.1', + 'remote_system_verifycert': False, + 'remote_system_username': 'username', + 'remote_system_password': 'password', + 'remote_system_port': 1 + }, + 'destination_nas_server_name': None, + 'destination_pool_name': 'pool_test_name_1', + 'destination_pool_id': None}, + 'replication_state': 'enable', + 'state': 'present' + } diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py new file mode 100644 index 000000000..bd933f7ce --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfs_api.py @@ -0,0 +1,187 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of nfs module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from mock.mock import MagicMock + + +class MockNfsApi: + NFS_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'description': None, + 'anonymous_uid': None, + 'anonymous_gid': None, + 'min_security': None, + 'default_access': None, + 'nas_server_id': None, + 'nas_server_name': None, + 'nfs_export_id': None, + 'nfs_export_name': None, + 'snapshot_name': None, + 'snapshot_id': None, + 'filesystem_name': None, + 'filesystem_id': None, + 'host_state': None, + 'adv_host_mgmt_enabled': None, + 'no_access_hosts': None, + 'read_only_hosts': None, + 'read_only_root_hosts': None, + 'read_write_hosts': None, + 'read_write_root_hosts': None, + 'path': None, + 'state': None + } + + DUMMY_DOMAIN_VALUE = "google.com" + DUMMY_SUBNET_VALUE = "**.***.2.2/10" + + FILESYSTEM_OBJECT = MockSDKObject({"access_policy": "AccessPolicyEnum.UNIX", "cifs_notify_on_change_dir_depth": 512, + "data_reduction_percent": 0, "data_reduction_ratio": 1.0, "data_reduction_size_saved": 0, + "description": "", "existed": True, + "folder_rename_policy": "FSRenamePolicyEnum.SMB_RENAME_FORBIDDEN", + "format": "FSFormatEnum.UFS64", "host_io_size": "HostIOSizeEnum.GENERAL_16K", + "id": "fs_id_1", "is_advanced_dedup_enabled": False, "is_cifs_notify_on_access_enabled": False, + "is_cifs_notify_on_write_enabled": False, "is_cifs_op_locks_enabled": True, + "is_cifs_sync_writes_enabled": False, "is_data_reduction_enabled": False, "is_read_only": False, + "is_smbca": False, "is_thin_enabled": True, "locking_policy": "FSLockingPolicyEnum.MANDATORY", + "min_size_allocated": 0, "name": "fs_dummy_name", "nas_server": {"id": "nas_id_1"}, + "nfs_share": [{"id": "NFSShare_id_1"}], "pool": {"id": "pool_id_1"}, + "pool_full_policy": "ResourcePoolFullPolicyEnum.FAIL_WRITES", "snap_count": 0, "snaps_size": 0, + "snaps_size_allocated": 0, "storage_resource": {"id": "stg_id_1"}, + "supported_protocols": "FSSupportedProtocolEnum.NFS", + "tiering_policy": "TieringPolicyEnum.AUTOTIER_HIGH", + "type": "FilesystemTypeEnum.FILESYSTEM"}) + + NFS_SHARE_OBJECT = MockSDKObject({"anonymous_gid": 4294967294, "anonymous_uid": 4294967294, + "default_access": "NFSShareDefaultAccessEnum.NO_ACCESS", "description": "", "existed": True, + "export_option": 1, "export_paths": ["**.***.**.**:/nfsshare_dummy_name"], + "filesystem": MockSDKObject({"id": "fs_id_1", "name": "fs_name1", "nas_server": "not_none"}), + "id": "NFSShare_id_1", + "min_security": "NFSShareSecurityEnum.SYS", + "modification_time": "2022-04-24 17:07:57.749000+00:00", + "name": "nfsshare_dummy_name", + "no_access_hosts": None, + "no_access_hosts_string": None, + "read_only_hosts": None, + "read_only_hosts_string": None, + "read_only_root_access_hosts": None, + "read_only_root_hosts_string": None, + "read_write_hosts": None, + "read_write_hosts_string": None, + "read_write_root_hosts_string": None, + "root_access_hosts": None, + "path": "/", + "role": "NFSShareRoleEnum.PRODUCTION", + "type": "NFSTypeEnum.NFS_SHARE"}) + + NFS_SHARE_DISPLAY_ATTR = {'anonymous_gid': 4294967294, 'anonymous_uid': 4294967294, 'creation_time': '2022-03-09 15:05:34.720000+00:00', + 'default_access': 'NFSShareDefaultAccessEnum.NO_ACCESS', 'description': '', 'export_option': 1, + 'export_paths': ['**.***.**.**:/nfsshare_dummy_name'], + 'filesystem': {'UnityFileSystem': {'id': 'fs_id_1', 'name': 'fs_name1'}}, 'host_accesses': None, + 'id': 'NFSShare_id_1', 'is_read_only': None, 'min_security': 'NFSShareSecurityEnum.SYS', + 'modification_time': '2022-04-24 17:07:57.749000+00:00', 'name': 'nfsshare_dummy_name', + 'nfs_owner_username': None, 'no_access_hosts': None, + 'no_access_hosts_string': None, + 'path': '/', 'read_only_hosts': None, 'read_only_hosts_string': '', 'read_only_root_access_hosts': None, + 'read_only_root_hosts_string': '', 'read_write_hosts': None, 'read_write_hosts_string': '', + 'read_write_root_hosts_string': '', 'role': 'NFSShareRoleEnum.PRODUCTION', 'root_access_hosts': None, + 'snap': None, 'type': 'NFSTypeEnum.NFS_SHARE', 'existed': True, + 'nas_server': {'UnityNasServer': {'id': 'nas_id_1', 'name': 'lglad068'}}} + + @staticmethod + def get_nfs_share_object_on_host_access(action, advhostmgmt): + if advhostmgmt: + if action == 'add': + nfs_share_object = MockNfsApi.NFS_SHARE_OBJECT + return nfs_share_object + elif action == 'remove': + nfs_share_object = MockNfsApi.NFS_SHARE_OBJECT + nfs_share_object.no_access_hosts = { + 'UnityHostList': [ + { + 'UnityHost': { + 'id': 'Host_1389' + } + }, + { + 'UnityHost': { + 'id': 'Host_1330' + } + } + ] + } + return nfs_share_object + else: + if action == 'add': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_OBJECT + nfs_share_display_attr.read_only_root_hosts_string = '' + return nfs_share_display_attr + elif action == 'remove': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_OBJECT + nfs_share_display_attr.read_only_root_hosts_string = '*.google.com,**.***.0.0/255.***.*.*' + return nfs_share_display_attr + + @staticmethod + def get_nfs_share_display_attr_on_host_access(action, advhostmgmt): + if advhostmgmt: + if action == 'add': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR + nfs_share_display_attr['no_access_hosts'] = { + 'UnityHostList': [ + { + 'UnityHost': { + 'id': 'Host_1389' + } + }, + { + 'UnityHost': { + 'id': 'Host_1330' + } + } + ] + } + return nfs_share_display_attr + elif action == 'remove': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR + nfs_share_display_attr['no_access_hosts'] = None + return nfs_share_display_attr + else: + if action == 'add': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR + nfs_share_display_attr['read_only_root_hosts_string'] = '*.google.com,**.***.0.0/255.***.*.*' + return nfs_share_display_attr + elif action == 'remove': + nfs_share_display_attr = MockNfsApi.NFS_SHARE_DISPLAY_ATTR + nfs_share_display_attr['read_only_root_hosts_string'] = '' + return nfs_share_display_attr + + @staticmethod + def get_host_obj(id): + if id == 1: + host_1 = MagicMock() + host_1.id = 'Host_1389' + host_1.name = 'host_1' + return host_1 + elif id == 2: + host_2 = MagicMock() + host_2.id = 'Host_1330' + host_2.name = 'host_2' + return host_2 + + @staticmethod + def host_access_negative_response(response_type): + if response_type == 'subnet_validation': + return "Subnet should be in format 'IP address/netmask' or 'IP address/prefix length'" + elif response_type == 'advhostmngmnt_field_validation': + return "'host_state' and 'adv_host_mgmt_enabled' is required along with: read_only_root_hosts" + elif response_type == 'modify_exception': + return 'Failed to modify nfs error: ' diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py new file mode 100644 index 000000000..1254f0035 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_nfsserver_api.py @@ -0,0 +1,259 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of NFS server module on Unity""" + +from __future__ import (absolute_import, division, print_function) +from unittest.mock import MagicMock + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockNFSServerApi: + NFS_SERVER_MODULE_ARGS = { + 'nas_server_id': None, + 'nas_server_name': None, + 'host_name': None, + 'is_secure_enabled': None, + 'kerberos_domain_controller_type': None, + 'kerberos_domain_controller_username': None, + 'kerberos_domain_controller_password': None, + 'is_extended_credentials_enabled': None, + 'nfs_v4_enabled': None, + 'nfs_server_id': None, + 'interfaces': None, + 'remove_spn_from_kerberos': None, + 'state': None + } + + NAS_SERVER_OBJ = MockSDKObject({"id": "nas_10"}) + + @staticmethod + def get_nfs_server_details_method_response(): + return { + "credentials_cache_ttl": "0:15:00", + "existed": True, + "file_interfaces": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": 1111111111111, + "id": "if_3" + } + }] + }, + "hash": 1111111111111, + "id": "nfs_95", + "is_extended_credentials_enabled": False, + "is_secure_enabled": False, + "nas_server": MockNFSServerApi.NAS_SERVER_OBJ, + "nfs_v4_enabled": True, + 'servicee_principal_name': None + } + + @staticmethod + def get_nfs_server_details(): + return [MockSDKObject({ + "credentials_cache_ttl": "0:15:00", + "existed": True, + "file_interfaces": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": 1111111111111, + "id": "if_3" + } + }] + }, + "hash": 1111111111111, + "id": "nfs_95", + "is_extended_credentials_enabled": False, + "is_secure_enabled": False, + "nas_server": MockNFSServerApi.NAS_SERVER_OBJ, + "nfs_v4_enabled": True, + 'servicee_principal_name': None})] + + @staticmethod + def validate_params_exception(): + return "Please provide valid value for:" + + @staticmethod + def create_nfs_server_without_nas_server_id(): + return "Please provide nas server id/name to create NFS server." + + @staticmethod + def get_nas_server_id_api_exception(): + return "Failed to get details of NAS server:" + + @staticmethod + def create_nfs_server_without_is_secure_enabled(): + return "For create NFS Server nfs_v4_enabled and is_secure_enabled should be true." + + @staticmethod + def create_nfs_server_with_api_exception(): + return "Failed to create NFS server with on NAS Server" + + @staticmethod + def get_nfs_server_api_exception(): + return "Incorrect username or password provided." + + @staticmethod + def get_nfs_server_api_exception_1(): + return "Failed to get details of NFS Server with error" + + @staticmethod + def delete_exception(): + return "Failed to delete NFS server:" + + @staticmethod + def modify_error_msg(): + return "Modification of NFS Server parameters is not supported through Ansible module" + + @staticmethod + def get_nas_server_details(): + return { + "UnityNasServer": { + "cifs_server": { + "UnityCifsServerList": [{ + "UnityCifsServer": { + "hash": 1111111111111, + "id": "cifs_60" + } + }] + }, + "current_sp": { + "UnityStorageProcessor": { + "hash": 1111111111111, + "id": "spa" + } + }, + "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NONE", + "existed": True, + "file_dns_server": { + "UnityFileDnsServer": { + "hash": 1111111111111, + "id": "dns_11" + } + }, + "file_interface": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": -1111111111111, + "id": "if_43" + } + }] + }, + "hash": -1111111111111, + "health": { + "UnityHealth": { + "hash": 1111111111111 + } + }, + "home_sp": { + "UnityStorageProcessor": { + "hash": -1111111111111, + "id": "spa" + } + }, + "id": "nas_18", + "is_backup_only": False, + "is_multi_protocol_enabled": False, + "is_packet_reflect_enabled": False, + "is_replication_destination": False, + "is_replication_enabled": False, + "name": "test_nas1", + "pool": { + "UnityPool": { + "hash": -1111111111111, + "id": "pool_7" + } + }, + "preferred_interface_settings": { + "UnityPreferredInterfaceSettings": { + "hash": -1111111111111, + "id": "preferred_if_16" + } + }, + "replication_type": "ReplicationTypeEnum.NONE", + "size_allocated": 1111111111111, + "virus_checker": { + "UnityVirusChecker": { + "hash": 1111111111111, + "id": "cava_18" + } + } + } + } + + @staticmethod + def get_nas_server_id(): + return MockSDKObject({ + "cifs_server": { + "UnityCifsServerList": [{ + "UnityCifsServer": { + "hash": 1111111111111, + "id": "cifs_34" + } + }] + }, + "current_sp": { + "UnityStorageProcessor": { + "hash": 1111111111111, + "id": "spb" + } + }, + "current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NIS", + "existed": True, + "file_dns_server": { + "UnityFileDnsServer": { + "hash": 1111111111111, + "id": "dns_12" + } + }, + "file_interface": { + "UnityFileInterfaceList": [{ + "UnityFileInterface": { + "hash": 1111111111111, + "id": "if_37" + } + }] + }, + "hash": 1111111111111, + "health": { + "UnityHealth": { + "hash": 1111111111111 + } + }, + "home_sp": { + "UnityStorageProcessor": { + "hash": 1111111111111, + "id": "spb" + } + }, + "id": "nas_10", + "is_backup_only": False, + "is_multi_protocol_enabled": False, + "is_packet_reflect_enabled": False, + "is_replication_destination": False, + "is_replication_enabled": True, + "name": "dummy_nas", + "pool": { + "UnityPool": { + "hash": 1111111111111, + "id": "pool_7" + } + }, + "preferred_interface_settings": { + "UnityPreferredInterfaceSettings": { + "hash": 1111111111111, + "id": "preferred_if_10" + } + }, + "replication_type": "ReplicationTypeEnum.REMOTE", + "size_allocated": 1111111111111, + "virus_checker": { + "UnityVirusChecker": { + "hash": 1111111111111, + "id": "cava_10"}}}) diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py new file mode 100644 index 000000000..2556870ba --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_sdk_response.py @@ -0,0 +1,32 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock SDKResponse for Unit tests for Unity modules""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + + +class MockSDKObject: + def __init__(self, data): + self.skip_list = ['skip_list'] + for key, value in data.items(): + setattr(self, key, value) + + def add_to_skip_list(self, key): + self.skip_list.append(key) + + def _get_properties(self): + data = {} + for attr, value in self.__dict__.items(): + if attr not in self.skip_list: + data[attr] = value + return data + + def get_id(self): + return "res_0" + + def name(self): + return "res_0" diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py new file mode 100644 index 000000000..1ec9fcadd --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_storagepool_api.py @@ -0,0 +1,168 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of storagepool module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject + + +class MockStoragePoolApi: + STORAGE_POOL_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'pool_name': None, + 'pool_id': None, + 'new_pool_name': None, + 'pool_description': None, + 'fast_cache': None, + 'fast_vp': None, + 'raid_groups': {}, + 'state': None + } + RAID_TYPE_5 = 'RaidTypeEnum.RAID5' + + @staticmethod + def get_pool_details_response(response_type): + if response_type == 'get_pool': + return {'alert_threshold': 84, 'creation_time': '2021-11-11 11:11:11+00:00', + 'description': '', 'harvest_state': 'UsageHarvestStateEnum.IDLE', + 'health': {'UnityHealth': {}}, 'id': 'pool_mock_1', + 'is_all_flash': True, 'is_empty': False, 'is_fast_cache_enabled': False, + 'is_harvest_enabled': True, 'is_snap_harvest_enabled': False, + 'metadata_size_subscribed': 1, 'metadata_size_used': 1, + 'name': 'Ansible_Unity_TEST_1', 'object_id': 1, 'pool_fast_vp': {'UnityPoolFastVp': {}}, + 'pool_space_harvest_high_threshold': 95.0, 'pool_space_harvest_low_threshold': 85.0, 'pool_type': + 'StoragePoolTypeEnum.DYNAMIC', 'raid_type': MockStoragePoolApi.RAID_TYPE_5, 'rebalance_progress': None, 'size_free': 1, + 'size_subscribed': 1, 'size_total': 1, 'size_used': 1, 'snap_size_subscribed': + 1, 'snap_size_used': 1, 'snap_space_harvest_high_threshold': 25.0, 'snap_space_harvest_low_threshold': + 20.0, 'tiers': {'UnityPoolTierList': [{'UnityPoolTier': {}}, {'UnityPoolTier': {}}, {'UnityPoolTier': {}}]}, 'existed': True} + elif response_type == 'pool_object': + return {'alert_threshold': 84, 'creation_time': '2021-11-11 11:11:11+00:00', + 'description': '', 'harvest_state': 'UsageHarvestStateEnum.IDLE', + 'health': {'UnityHealth': {}}, 'id': 'pool_mock_1', + 'is_all_flash': True, 'is_empty': False, 'is_fast_cache_enabled': False, + 'is_harvest_enabled': True, 'is_snap_harvest_enabled': False, + 'metadata_size_subscribed': 1, 'metadata_size_used': 1, + 'name': 'Ansible_Unity_TEST_1', 'object_id': 1, + 'pool_fast_vp': {'UnityPoolFastVp': {}}, + 'pool_space_harvest_high_threshold': 95.0, + 'pool_space_harvest_low_threshold': 85.0, 'pool_type': 'StoragePoolTypeEnum.DYNAMIC', + 'raid_type': MockStoragePoolApi.RAID_TYPE_5, 'rebalance_progress': None, 'size_free': 1, + 'size_subscribed': 1, 'size_total': 1, 'size_used': 1, + 'snap_size_subscribed': 1, 'snap_size_used': 1, + 'snap_space_harvest_high_threshold': 25.0, 'snap_space_harvest_low_threshold': 20.0, + 'tiers': MockSDKObject({'disk_count': [5, 0, 0], 'name': ['Extreme Performance', 'Performance', 'Capacity'], + 'pool_units': [{'UnityPoolUnitList': [{'UnityPoolUnit': {'id': 'pool_unit_mock_1'}}]}, None, None], + 'raid_type': [MockStoragePoolApi.RAID_TYPE_5, 'RaidTypeEnum.NONE', 'RaidTypeEnum.NONE'], + 'size_free': [1, 0, 0], + 'size_moving_down': [0, 0, 0], 'size_moving_up': [0, 0, 0], + 'size_moving_within': [0, 0, 0], 'size_total': [1, 0, 0], + 'size_used': [1, 0, 0], 'stripe_width': ['RaidStripeWidthEnum._5', None, None], + 'tier_type': ['TierTypeEnum.EXTREME_PERFORMANCE', 'TierTypeEnum.PERFORMANCE', 'TierTypeEnum.CAPACITY'], + 'existed': True}), + 'existed': True} + elif response_type == 'disk_list': + return [MockSDKObject({"bus_id": 99, "current_speed": 1, "disk_group": {"UnityDiskGroup": {"id": "disk_mock_1"}}, + "disk_technology": MockSDKObject({"name": "mock_disk_tech"}), "emc_part_number": "XXXXXXXX", + "emc_serial_number": "XXXXXXXX", "existed": True, "health": {"UnityHealth": {}}, + "id": "disk_mock_2", "is_fast_cache_in_use": False, "is_in_use": True, + "is_sed": False, "manufacturer": "mock_disk_manufacturer", + "max_speed": 1, "model": "mock_disk_model", "name": "Drive 12", + "needs_replacement": False, "pool": MockSDKObject({"id": "pool_5", "name": "Pool_Mock_TEST_2", "UnityPool": {}}), + "raw_size": 1, "rpm": 0, "size": 1, "slot_number": 12, + "tier_type": MockSDKObject({"name": "EXTREME_PERFORMANCE"}), "vendor_size": 1, + "version": "S109", "wwn": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"}), + MockSDKObject({"bus_id": 99, "current_speed": 1, + "disk_group": {"UnityDiskGroup": {"id": "disk_mock_1"}}, + "disk_technology": MockSDKObject({"name": "mock_disk_tech"}), "emc_part_number": "XXXXXXXX", + "emc_serial_number": "XXXXXXXX", "existed": True, "health": {"UnityHealth": {}}, + "id": "mock_disk_id", "is_fast_cache_in_use": False, "is_in_use": True, "is_sed": False, + "manufacturer": "mock_disk_manufacturer", "max_speed": 1, "model": "mock_disk_model", + "name": "disk_disk_name", "needs_replacement": False, + "pool": MockSDKObject({"id": "pool_mock_1", "name": "Ansible_Unity_TEST_1"}), + "raw_size": 1, "rpm": 0, "size": 1, + "slot_number": 13, "tier_type": MockSDKObject({"name": "EXTREME_PERFORMANCE"}), + "vendor_size": 1, "version": "S109", + "wwn": "01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"})] + elif response_type == 'module': + return {"storage_pool_details": + {"alert_threshold": 84, "creation_time": "2021-11-11 11:11:11+00:00", "description": "", + "drives": [{"disk_technology": "mock_disk_tech", "id": "mock_disk_id", "name": "disk_disk_name", + "size": 1, "tier_type": "EXTREME_PERFORMANCE"}], + "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE", + "health": {"UnityHealth": {}}, + "id": "pool_mock_1", "is_all_flash": True, "is_empty": False, + "is_fast_cache_enabled": False, "is_fast_vp_enabled": True, + "is_harvest_enabled": True, "is_snap_harvest_enabled": False, + "metadata_size_subscribed": 1, "metadata_size_used": + 1, "name": "Ansible_Unity_TEST_1", "object_id": 1, + "pool_fast_vp": {"UnityPoolFastVp": {}}, + "pool_space_harvest_high_threshold": 95.0, + "pool_space_harvest_low_threshold": 85.0, "pool_type": "StoragePoolTypeEnum.DYNAMIC", + "raid_type": "RaidTypeEnum.RAID5", "rebalance_progress": None, "size_free": 1, + "size_free_with_unit": "1.0 B", "size_subscribed": 1, "size_subscribed_with_unit": "1.0 B", + "size_total": 1, "size_total_with_unit": "1.0 B", "size_used": 1, "size_used_with_unit": "1.0 B", + "snap_size_subscribed": 1, "snap_size_subscribed_with_unit": "1.0 B", "snap_size_used": 1, + "snap_size_used_with_unit": "1.0 B", "snap_space_harvest_high_threshold": 25.0, "snap_space_harvest_low_threshold": 20.0, + "tiers": {"UnityPoolTierList": [{"disk_count": [5, 0, 0], "existed": True, + "name": ["Extreme Performance", "Performance", "Capacity"], + "pool_units": [{"UnityPoolUnitList": [{"UnityPoolUnit": {"id": "pool_unit_mock_1"}}]}, None, None], + "raid_type": ["RaidTypeEnum.RAID5", "RaidTypeEnum.NONE", "RaidTypeEnum.NONE"], + "size_free": [1, 0, 0], "size_moving_down": [0, 0, 0], + "size_moving_up": [0, 0, 0], + "size_moving_within": [0, 0, 0], + "size_total": [1, 0, 0], + "size_used": [1, 0, 0], + "stripe_width": ["RaidStripeWidthEnum._5", None, None], + "tier_type": ["TierTypeEnum.EXTREME_PERFORMANCE", "TierTypeEnum.PERFORMANCE", + "TierTypeEnum.CAPACITY"]}]}}} + elif response_type == 'error': + return 'Get details of storage pool failed with error: ' + + @staticmethod + def create_pool_response(response_type): + if response_type == 'api': + return {"storage_pool_details": + {"alert_threshold": 50, "creation_time": "2022-03-08 10:51:08+00:00", "description": "Unity test pool.", + "drives": [{"disk_technology": "SAS", "id": "disk_id_1", "name": "DPE Drive 1", + "size": 1, "tier_type": "PERFORMANCE"}, + {"disk_technology": "SAS", "id": "disk_id_2", "name": "DPE Drive 2", + "size": 1, "tier_type": "PERFORMANCE"}, + {"disk_technology": "SAS", "id": "disk_id_3", "name": "DPE Drive 3", + "size": 1, "tier_type": "PERFORMANCE"}], + "existed": True, "harvest_state": "UsageHarvestStateEnum.IDLE", + "health": {"UnityHealth": {}}, + "id": "pool_id_1", "is_all_flash": False, "is_empty": True, + "is_fast_cache_enabled": False, "is_fast_vp_enabled": True, + "is_harvest_enabled": True, "is_snap_harvest_enabled": True, + "metadata_size_subscribed": 0, "metadata_size_used": + 0, "name": "Mock_Test", "object_id": 123, + "pool_fast_vp": {"UnityPoolFastVp": {}}, + "pool_space_harvest_high_threshold": 59.0, + "pool_space_harvest_low_threshold": 40.0, "pool_type": "StoragePoolTypeEnum.DYNAMIC", + "raid_type": "RaidTypeEnum.RAID10", "rebalance_progress": None, "size_free": 1, + "size_free_with_unit": "1 GB", "size_subscribed": 0, "size_subscribed_with_unit": "0B", + "size_total": 1, "size_total_with_unit": "1 GB", "size_used": 0, "size_used_with_unit": "0B", + "snap_size_subscribed": 0, "snap_size_subscribed_with_unit": "0B", "snap_size_used": 0, + "snap_size_used_with_unit": "0B", "snap_space_harvest_high_threshold": 80.0, "snap_space_harvest_low_threshold": 60.0, + "tiers": {"UnityPoolTierList": [{"disk_count": [0, 3, 0], "existed": True, + "name": ["Extreme Performance", "Performance", "Capacity"], + "pool_units": [{"UnityPoolUnitList": [{"UnityPoolUnit": {"id": "rg_id_1"}}, + {"UnityPoolUnit": {"id": "rg_id_2"}}]}, None], + "raid_type": ["RaidTypeEnum.NONE", "RaidTypeEnum.RAID10", "RaidTypeEnum.NONE"], + "size_free": [0, 1, 0], "size_moving_down": [0, 0, 0], + "size_moving_up": [0, 0, 0], + "size_moving_within": [0, 0, 0], + "size_total": [0, 1, 0], + "size_used": [0, 0, 0], + "stripe_width": [None, "RaidStripeWidthEnum._2", None], + "tier_type": ["TierTypeEnum.EXTREME_PERFORMANCE", "TierTypeEnum.PERFORMANCE", + "TierTypeEnum.CAPACITY"]}]}}} + elif response_type == 'error': + return 'Failed to create storage pool with error: ' diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py new file mode 100644 index 000000000..82097a338 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/module_utils/mock_volume_api.py @@ -0,0 +1,174 @@ +# Copyright: (c) 2023, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http: //www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of volume module on Unity""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response import MockSDKObject + + +class MockVolumeApi: + + VOLUME_MODULE_ARGS = { + 'unispherehost': '**.***.**.***', + 'port': '123', + 'vol_name': None, + 'vol_id': None, + 'description': None, + 'pool_name': None, + 'pool_id': None, + 'size': None, + 'cap_unit': None, + 'is_thin': None, + 'compression': None, + 'advanced_dedup': None, + 'sp': None, + 'io_limit_policy': None, + 'snap_schedule': None, + 'host_name': None, + 'host_id': None, + 'hosts': {}, + 'hlu': None, + 'mapping_state': None, + 'new_vol_name': None, + 'tiering_policy': None, + 'state': None, + } + + pool = { + 'alert_threshold': 60, + 'creation_time': '2021-10-18 12:51:27+00:00', + 'description': 'A2Z', + 'existed': True, + 'harvest_state': 'UsageHarvestStateEnum.IDLE', + 'hash': 8778647453970, + 'health': {'UnityHealth': {'hash': 8778647453730}}, + 'id': 'pool_3', + 'is_all_flash': True, + 'is_empty': False, + 'is_fast_cache_enabled': False, + 'is_harvest_enabled': True, + 'is_snap_harvest_enabled': True, + 'metadata_size_subscribed': 646124142592, + 'metadata_size_used': 357287591936, + 'name': 'Extreme_Perf_tier', + 'object_id': 12884901892, + 'pool_fast_vp': {'UnityPoolFastVp': {'hash': 8778647539688}}, + 'pool_space_harvest_high_threshold': 95.0, + 'pool_space_harvest_low_threshold': 70.5, + 'pool_type': 'StoragePoolTypeEnum.TRADITIONAL', + 'raid_type': 'RaidTypeEnum.RAID5', + 'size_free': 1174673555456, + 'size_subscribed': 8703230820352, + 'size_total': 3141768577024, + 'size_used': 1802576257024, + 'snap_size_subscribed': 290195193856, + 'snap_size_used': 43098112, + 'snap_space_harvest_high_threshold': 20.5, + 'snap_space_harvest_low_threshold': 1.0, + 'tiers': {'UnityPoolTierList': [{'UnityPoolTier': {'hash': 8778647538737}}, + {'UnityPoolTier': {'hash': 8778647538749}}, + {'UnityPoolTier': {'hash': 8778647526797}}]}, + } + + @staticmethod + def create_volume_response(response_type): + if response_type == 'api': + return {'volume_details': { + 'current_node': 'NodeEnum.SPB', + 'data_reduction_percent': 0, + 'data_reduction_ratio': 1.0, + 'data_reduction_size_saved': 0, + 'default_node': 'NodeEnum.SPB', + 'description': None, + 'effective_io_limit_max_iops': None, + 'effective_io_limit_max_kbps': None, + 'existed': True, + 'family_base_lun': {'UnityLun': {}}, + 'family_clone_count': 0, + 'hash': 8769317548849, + 'health': {'UnityHealth': {}}, + 'host_access': [], + 'id': 'sv_214551', + 'io_limit_policy': True, + 'is_advanced_dedup_enabled': True, + 'is_compression_enabled': True, + 'is_data_reduction_enabled': True, + 'is_replication_destination': False, + 'is_snap_schedule_paused': False, + 'is_thin_clone': False, + 'is_thin_enabled': True, + 'metadata_size': 3758096384, + 'metadata_size_allocated': 3221225472, + 'name': 'Atest', + 'per_tier_size_used': [3489660928, 0, 0], + 'pool': {'id': 'pool_3', 'name': 'Extreme_Perf_tier'}, + 'size_allocated': 0, + 'size_total': 2147483648, + 'size_total_with_unit': '2.0 GB', + 'size_used': None, + 'snap_count': 0, + 'snap_schedule': None, + 'snap_wwn': '60:06:01:60:5C:F0:50:00:F6:42:70:38:7A:90:40:FF', + 'snaps_size': 0, + 'snaps_size_allocated': 0, + 'storage_resource': {'UnityStorageResource': {}}, + 'tiering_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', + 'type': 'LUNTypeEnum.STANDALONE', + 'wwn': '60:06:01:60:5C:F0:50:00:41:25:EA:63:94:92:92:AE', + }} + else: + return 'Create volume operation Atest failed with error' + + @staticmethod + def modify_volume_response(response_type): + if response_type == 'api': + return {'volume_details': { + 'current_node': 'NodeEnum.SPB', + 'data_reduction_percent': 0, + 'data_reduction_ratio': 1.0, + 'data_reduction_size_saved': 0, + 'default_node': 'NodeEnum.SPB', + 'description': None, + 'effective_io_limit_max_iops': None, + 'effective_io_limit_max_kbps': None, + 'existed': True, + 'family_base_lun': {'UnityLun': {}}, + 'family_clone_count': 0, + 'hash': 8769317548849, + 'health': {'UnityHealth': {}}, + 'host_access': [], + 'id': 'sv_214551', + 'io_limit_policy': None, + 'is_advanced_dedup_enabled': False, + 'is_compression_enabled': True, + 'is_data_reduction_enabled': True, + 'is_replication_destination': False, + 'is_snap_schedule_paused': False, + 'is_thin_clone': False, + 'is_thin_enabled': True, + 'metadata_size': 3758096384, + 'metadata_size_allocated': 3221225472, + 'name': 'Atest', + 'per_tier_size_used': [3489660928, 0, 0], + 'pool': {'id': 'pool_3', 'name': 'Extreme_Perf_tier'}, + 'size_allocated': 0, + 'size_total': 2147483648, + 'size_total_with_unit': '2.0 GB', + 'size_used': None, + 'snap_count': 0, + 'snap_schedule': None, + 'snap_wwn': '60:06:01:60:5C:F0:50:00:F6:42:70:38:7A:90:40:FF', + 'snaps_size': 0, + 'snaps_size_allocated': 0, + 'storage_resource': {'UnityStorageResource': {}}, + 'tiering_policy': 'TieringPolicyEnum.AUTOTIER_HIGH', + 'type': 'LUNTypeEnum.STANDALONE', + 'wwn': '60:06:01:60:5C:F0:50:00:41:25:EA:63:94:92:92:AE', + }} + else: + return 'Failed to modify the volume Atest with error' diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py new file mode 100644 index 000000000..e28c2e935 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_cifsserver.py @@ -0,0 +1,169 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of CIFS server module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_cifsserver_api \ + import MockCIFSServerApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import HttpError as http_error, MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +utils.UnityCifsServer = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() +from ansible_collections.dellemc.unity.plugins.modules.cifsserver import CIFSServer + + +class TestCIFSServer(): + + get_module_args = MockCIFSServerApi.CIFS_SERVER_MODULE_ARGS + + @pytest.fixture + def cifsserver_module_mock(self): + cifsserver_module_mock = CIFSServer() + cifsserver_module_mock.unity_conn = MagicMock() + utils.cifsserver = MagicMock() + return cifsserver_module_mock + + def test_get_cifs_server_details(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.unity_conn.get_cifs_server = MagicMock(return_value=MockSDKObject(cifs_server_details)) + cifsserver_module_mock.perform_module_operation() + assert MockCIFSServerApi.get_cifs_server_details_method_response() == \ + cifsserver_module_mock.module.exit_json.call_args[1]['cifs_server_details'] + + def test_get_cifs_server_details_using_id(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_id': 'cifs_59', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.unity_conn.get_cifs_server = MagicMock(return_value=MockSDKObject(cifs_server_details)) + cifsserver_module_mock.perform_module_operation() + assert MockCIFSServerApi.get_cifs_server_details_method_response() == \ + cifsserver_module_mock.module.exit_json.call_args[1]['cifs_server_details'] + + def test_get_get_nas_server_id(self, cifsserver_module_mock): + nas_server_details = MockCIFSServerApi.get_nas_server_details() + self.get_module_args.update({ + 'cifs_server_id': 'cifs_59', + 'nas_server_name': 'test_nas1', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=MockSDKObject(nas_server_details)) + cifsserver_module_mock.perform_module_operation() + cifsserver_module_mock.unity_conn.get_nas_server.assert_called() + + def test_create_cifs_server(self, cifsserver_module_mock): + self.get_module_args.update({ + 'nas_server_id': 'nas_18', + 'cifs_server_name': 'test_cifs_server', + 'domain': 'xxx.xxx.xxx.xxx', + 'domain_username': 'xxxxxxxx', + 'domain_password': 'xxxxxxxx', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=None) + cifsserver_module_mock.unity_conn.create_cifs_server = MagicMock(return_value=True) + cifsserver_module_mock.perform_module_operation() + assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_create_cifs_server_throws_exception(self, cifsserver_module_mock): + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'domain': 'xxx.xxx.xxx.xxx', + 'domain_username': 'xxxxxxxx', + 'domain_password': 'xxxxxxxx', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=None) + cifsserver_module_mock.perform_module_operation() + assert MockCIFSServerApi.create_cifs_server_without_nas() == cifsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_delete_cifs_server(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'unjoin_cifs_server_account': False, + 'domain_username': 'xxxxxxxx', + 'domain_password': 'xxxxxxxx', + 'state': 'absent' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details) + cifsserver_module_mock.get_cifs_server_instance = MagicMock(return_value=MockSDKObject(cifs_server_details)) + cifsserver_module_mock.perform_module_operation() + assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_is_modification_required(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'netbios_name': 'ansible_netbios', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details) + cifsserver_module_mock.perform_module_operation() + assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_is_domain_modification_required(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'domain': 'yyy.yyy.yyy.yyy', + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details) + cifsserver_module_mock.perform_module_operation() + print(cifsserver_module_mock.module.fail_json.call_args[1]) + assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_is_modify_interfaces(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'interfaces': ['if_39'], + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details) + cifsserver_module_mock.perform_module_operation() + print(cifsserver_module_mock.module.fail_json.call_args[1]) + assert MockCIFSServerApi.modify_error_msg() == cifsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_is_modify_interfaces_idempotency(self, cifsserver_module_mock): + cifs_server_details = MockCIFSServerApi.get_cifs_server_details_method_response() + self.get_module_args.update({ + 'cifs_server_name': 'test_cifs_server', + 'interfaces': ['if_43'], + 'state': 'present' + }) + cifsserver_module_mock.module.params = self.get_module_args + cifsserver_module_mock.get_details = MagicMock(return_value=cifs_server_details) + cifsserver_module_mock.perform_module_operation() + assert cifsserver_module_mock.module.exit_json.call_args[1]['changed'] is False diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py new file mode 100644 index 000000000..dd2cdd81a --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_consistencygroup.py @@ -0,0 +1,193 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for consistency group module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_consistencygroup_api \ + import MockConsistenyGroupApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock(side_effect=[MagicMock(), + MockConsistenyGroupApi.get_remote_system_conn_response()]) +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.consistencygroup import ConsistencyGroup + + +class TestConsistencyGroup(): + + get_module_args = MockConsistenyGroupApi.CONSISTENCY_GROUP_MODULE_ARGS + + @pytest.fixture + def consistencygroup_module_mock(self): + consistencygroup_module_mock = ConsistencyGroup() + consistencygroup_module_mock.unity_conn = MagicMock() + utils.cg = MagicMock() + return consistencygroup_module_mock + + def test_enable_cg_replication(self, consistencygroup_module_mock): + self.get_module_args.update({ + 'cg_name': 'lun_test_cg_source_12', + 'replication_params': { + 'destination_cg_name': 'destination_cg_1', + 'replication_mode': 'asynchronous', + 'rpo': 60, + 'replication_type': 'remote', + 'remote_system': { + 'remote_system_host': '11.111.11.11', + 'remote_system_verifycert': False, + 'remote_system_username': 'username', + 'remote_system_password': 'password', + 'remote_system_port': 1111 + }, + 'destination_pool_name': 'pool_test_name_1', + 'destination_pool_id': None + }, + 'replication_state': 'enable', + 'state': 'present' + }) + consistencygroup_module_mock.module.params = self.get_module_args + cg_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_object = MockConsistenyGroupApi.get_cg_object() + consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object) + consistencygroup_module_mock.get_details = MagicMock(side_effect=[ + cg_details, + MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')]) + cg_object.get_id = MagicMock(return_value=cg_details['id']) + utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object) + cg_object.check_cg_is_replicated = MagicMock(return_value=False) + consistencygroup_module_mock.unity_conn.get_remote_system = \ + MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system')) + utils.UnityStorageResource = MagicMock(return_value=MockSDKObject({})) + cg_object.replicate_cg_with_dst_resource_provisioning = MagicMock(return_value=None) + consistencygroup_module_mock.perform_module_operation() + assert consistencygroup_module_mock.module.exit_json.call_args[1]['consistency_group_details']['cg_replication_enabled'] is True + assert consistencygroup_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_enable_cg_replication_negative_1(self, consistencygroup_module_mock): + self.get_module_args.update({ + 'cg_name': 'lun_test_cg_source_12', + 'replication_params': { + 'destination_cg_name': '', + 'replication_mode': 'asynchronous', + 'rpo': 60, + 'replication_type': 'local', + 'destination_pool_name': None, + 'destination_pool_id': 'pool_test_1' + }, + 'replication_state': 'enable', + 'state': 'present' + }) + consistencygroup_module_mock.module.params = self.get_module_args + cg_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_object = MockConsistenyGroupApi.get_cg_object() + consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object) + consistencygroup_module_mock.get_details = MagicMock(side_effect=[ + cg_details, + MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')]) + cg_object.get_id = MagicMock(return_value=cg_details['id']) + utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object) + cg_object.check_cg_is_replicated = MagicMock(return_value=False) + consistencygroup_module_mock.unity_conn.get_remote_system = \ + MagicMock(return_value=MockConsistenyGroupApi.get_cg_replication_dependent_response('remote_system')) + utils.UnityStorageResource = MagicMock(return_value=MockSDKObject({})) + cg_object.replicate_cg_with_dst_resource_provisioning = MagicMock(return_value=None) + consistencygroup_module_mock.perform_module_operation() + assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockConsistenyGroupApi.get_cg_replication_dependent_response('destination_cg_name_validation') + + def test_enable_cg_replication_negative_2(self, consistencygroup_module_mock): + self.get_module_args.update({ + 'cg_name': 'lun_test_cg_source_12', + 'replication_params': { + 'destination_cg_name': 'destination_cg_1', + 'replication_mode': 'asynchronous', + 'rpo': 60, + 'replication_type': 'remote', + 'remote_system': { + 'remote_system_host': '11.111.11.11', + 'remote_system_verifycert': False, + 'remote_system_username': 'username', + 'remote_system_password': 'password', + 'remote_system_port': 1111 + }, + 'destination_pool_name': None, + 'destination_pool_id': 'pool_test_1' + }, + 'replication_state': 'enable', + 'state': 'present' + }) + consistencygroup_module_mock.module.params = self.get_module_args + cg_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_object = MockConsistenyGroupApi.get_cg_object() + consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object) + consistencygroup_module_mock.get_details = MagicMock(side_effect=[ + cg_details, + MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details')]) + cg_object.get_id = MagicMock(return_value=cg_details['id']) + utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object) + cg_object.check_cg_is_replicated = MagicMock(return_value=False) + consistencygroup_module_mock.unity_conn.get_remote_system = MagicMock(side_effect=MockApiException) + consistencygroup_module_mock.perform_module_operation() + assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockConsistenyGroupApi.get_cg_replication_dependent_response('enable_cg_exception') + + def test_disable_cg_replication(self, consistencygroup_module_mock): + self.get_module_args.update({ + 'cg_name': 'lun_test_cg_source_12', + 'replication_state': 'disable', + 'state': 'present' + }) + consistencygroup_module_mock.module.params = self.get_module_args + cg_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_object = MockConsistenyGroupApi.get_cg_object() + consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object) + consistencygroup_module_mock.get_details = MagicMock(side_effect=[ + MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details'), + cg_details]) + cg_object.get_id = MagicMock(return_value=cg_details['id']) + utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object) + cg_object.check_cg_is_replicated = MagicMock(return_value=True) + repl_session = MockConsistenyGroupApi.get_cg_replication_dependent_response('replication_session') + repl_session.delete = MagicMock(return_value=None) + consistencygroup_module_mock.unity_conn.get_replication_session = \ + MagicMock(return_value=[repl_session]) + consistencygroup_module_mock.perform_module_operation() + assert consistencygroup_module_mock.module.exit_json.call_args[1]['consistency_group_details']['cg_replication_enabled'] is False + assert consistencygroup_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_disable_cg_replication_throws_exception(self, consistencygroup_module_mock): + self.get_module_args.update({ + 'cg_name': 'lun_test_cg_source_12', + 'replication_state': 'disable', + 'state': 'present' + }) + consistencygroup_module_mock.module.params = self.get_module_args + cg_details = MockConsistenyGroupApi.cg_get_details_method_response() + cg_object = MockConsistenyGroupApi.get_cg_object() + consistencygroup_module_mock.unity_conn.get_cg = MagicMock(return_value=cg_object) + consistencygroup_module_mock.get_details = MagicMock(side_effect=[ + MockConsistenyGroupApi.get_cg_replication_dependent_response('cg_replication_enabled_details'), + cg_details]) + cg_object.get_id = MagicMock(return_value=cg_details['id']) + utils.cg.UnityConsistencyGroup.get = MagicMock(return_value=cg_object) + cg_object.check_cg_is_replicated = MagicMock(side_effect=MockApiException) + consistencygroup_module_mock.perform_module_operation() + assert consistencygroup_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockConsistenyGroupApi.get_cg_replication_dependent_response('disable_cg_exception') diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py new file mode 100644 index 000000000..c8551d08b --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_filesystem.py @@ -0,0 +1,94 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for FileSystem module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +import re +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_filesystem_api \ + import MockFileSystemApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.UnityReplicationSession = object + +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.filesystem import Filesystem + + +class TestFileSystem(): + + FILE_SYSTEM_MODULE_ARGS = {'filesystem_id': '123', 'filesystem_name': None, 'nas_server_name': None, + 'nas_server_id': None, 'pool_name': None, 'pool_id': None, 'size': None, + 'cap_unit': None, 'quota_config': None, 'snap_schedule_name': None, + 'snap_schedule_id': None, 'replication_params': {}, 'replication_state': None, 'state': None} + + @pytest.fixture + def filesystem_module_mock(self): + filesystem_module_mock = Filesystem() + filesystem_module_mock.unity_conn = MagicMock() + return filesystem_module_mock + + def test_enable_fs_replication(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params()) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_response = MockFileSystemApi.get_file_system_response() + filesystem_response['replicate_with_dst_resource_provisioning'] = MagicMock(return_value=True) + filesystem_module_mock.perform_module_operation() + assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_enable_fs_replication_invalid_params(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params(False)) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_module_mock.is_modify_required = MagicMock(return_value=False) + filesystem_module_mock.perform_module_operation() + assert "Invalid rpo value" in \ + filesystem_module_mock.module.fail_json.call_args[1]['msg'] + + def test_enable_fs_replication_throws_ex(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params()) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_module_mock.is_modify_required = MagicMock(return_value=False) + filesystem_response = MockFileSystemApi.get_file_system_response() + filesystem_response['replicate_with_dst_resource_provisioning'] = MagicMock(side_effect=Exception) + filesystem_module_mock.get_filesystem = MagicMock(side_effect=[ + MockSDKObject(filesystem_response)]) + filesystem_module_mock.get_filesystem_display_attributes = MagicMock(side_effect=[ + MockSDKObject(filesystem_response)]) + filesystem_module_mock.perform_module_operation() + assert "Enabling replication to the filesystem failed with error" in \ + re.sub(' <.*?>>', '', filesystem_module_mock.module.fail_json.call_args[1]['msg']) + + def test_modify_fs_replication(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update(MockFileSystemApi.get_replication_params()) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_module_mock.perform_module_operation() + filesystem_module_mock.get_replication_session_on_filter = MagicMock() + assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_disable_replication(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'}) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_module_mock.get_filesystem_display_attributes = MagicMock() + filesystem_module_mock.perform_module_operation() + assert filesystem_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_disable_replication_throws_ex(self, filesystem_module_mock): + self.FILE_SYSTEM_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'}) + filesystem_module_mock.module.params = self.FILE_SYSTEM_MODULE_ARGS + filesystem_module_mock.get_replication_session = MagicMock(side_effect=Exception) + filesystem_module_mock.get_filesystem_display_attributes = MagicMock() + filesystem_module_mock.perform_module_operation() + assert "Disabling replication on the filesystem failed with error" in \ + re.sub(' <.*?>', '', filesystem_module_mock.module.fail_json.call_args[1]['msg']) diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py new file mode 100644 index 000000000..de94c38d3 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_host.py @@ -0,0 +1,143 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for host module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_host_api \ + import MockHostApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import HttpError as http_error, MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.host import Host + + +class TestHost(): + + get_module_args = MockHostApi.HOST_MODULE_ARGS + + @pytest.fixture + def host_module_mock(self): + host_module_mock = Host() + host_module_mock.unity = MagicMock() + utils.host = MagicMock() + return host_module_mock + + def test_get_host_details(self, host_module_mock): + host_details = MockHostApi.get_host_details_response('api') + self.get_module_args.update({ + 'host_name': 'host_name_1', + }) + host_module_mock.module.params = self.get_module_args + host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list()) + utils.host.UnityHostList.get = MagicMock(return_value=MockHostApi.get_host_count_response()) + host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]]) + host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(host_details)) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_response('module')['host_details'] == host_module_mock.module.exit_json.call_args[1]['host_details'] + + def test_get_host_details_throws_exception(self, host_module_mock): + self.get_module_args.update({ + 'host_name': 'name1' + }) + host_module_mock.module.params = self.get_module_args + utils.HttpError = http_error + utils.host.UnityHostList.get = MagicMock(side_effect=http_error) + host_module_mock.create_host = MagicMock(return_value=(False, MagicMock())) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_response('error') == host_module_mock.module.fail_json.call_args[1]['msg'] + + def test_add_network_address_to_host(self, host_module_mock): + self.get_module_args.update({ + 'host_name': 'host_name_1', + 'network_address': 'net_add_1', + 'network_address_state': 'present-in-host', + 'state': 'present' + }) + host_module_mock.module.params = self.get_module_args + host_details = MockHostApi.get_host_details_response('api') + host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]]) + host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list()) + host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(MockHostApi.get_host_details_after_network_address_addition('api'))) + host_details = MockSDKObject(host_details) + host_details.add_ip_port = MagicMock(return_value=None) + host_details.add_to_skip_list('add_ip_port') + host_module_mock.get_host_details = MagicMock(return_value=host_details) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_after_network_address_addition('module')['host_details'] == \ + host_module_mock.module.exit_json.call_args[1]['host_details'] + assert MockHostApi.get_host_details_after_network_address_addition('module')['changed'] == host_module_mock.module.exit_json.call_args[1]['changed'] + + def test_add_network_address_to_host_negative(self, host_module_mock): + self.get_module_args.update({ + 'host_name': 'host_name_1', + 'network_address': 'net_ad$$$$$d_12', + 'network_address_state': 'present-in-host', + 'state': 'present' + }) + host_module_mock.module.params = self.get_module_args + host_details = MockHostApi.get_host_details_response('api') + host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]]) + host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list()) + host_module_mock.manage_network_address = MagicMock(return_value=(None, False)) + host_module_mock.get_host_details = MagicMock(return_value=MockSDKObject(host_details)) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_after_network_address_addition('invalid_address') == \ + host_module_mock.module.fail_json.call_args[1]['msg'] + assert host_module_mock.module.exit_json.call_args[1]['changed'] is False + + def test_remove_network_address_from_host(self, host_module_mock): + self.get_module_args.update({ + 'host_name': 'host_name_1', + 'network_address': 'host_name_1', + 'network_address_state': 'absent-in-host', + 'state': 'present' + }) + host_module_mock.module.params = self.get_module_args + host_details = MockHostApi.get_host_details_response('api') + host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]]) + host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list()) + host_module_mock.unity.get_host = MagicMock(return_value=MockSDKObject(MockHostApi.get_host_details_after_network_address_removal('api'))) + host_details = MockSDKObject(host_details) + host_details.delete_ip_port = MagicMock(return_value=None) + host_details.add_to_skip_list('delete_ip_port') + host_module_mock.get_host_details = MagicMock(return_value=host_details) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_after_network_address_removal('module')['host_details'] == \ + host_module_mock.module.exit_json.call_args[1]['host_details'] + assert MockHostApi.get_host_details_after_network_address_removal('module')['changed'] == host_module_mock.module.exit_json.call_args[1]['changed'] + + def test_remove_network_address_from_host_negative(self, host_module_mock): + self.get_module_args.update({ + 'host_name': 'host_name_1', + 'network_address': '1.1.1', + 'network_address_state': 'absent-in-host', + 'state': 'present' + }) + host_module_mock.module.params = self.get_module_args + host_details = MockHostApi.get_host_details_response('api') + host_module_mock.unity.get_initiator = MagicMock(side_effect=[host_details['fc_host_initiators'][0], host_details['iscsi_host_initiators'][0]]) + host_module_mock.get_host_initiators_list = MagicMock(return_value=MockHostApi.get_host_initiators_list()) + host_module_mock.manage_network_address = MagicMock(return_value=(None, False)) + host_module_mock.get_host_details = MagicMock(return_value=MockSDKObject(host_details)) + host_module_mock.perform_module_operation() + assert MockHostApi.get_host_details_after_network_address_removal('invalid_IPV4') == \ + host_module_mock.module.fail_json.call_args[1]['msg'] + assert host_module_mock.module.exit_json.call_args[1]['changed'] is False diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py new file mode 100644 index 000000000..88151bcba --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_interface.py @@ -0,0 +1,350 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for interface module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_interface_api \ + import MockInterfaceApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.interface import Interface + + +class TestInterface(): + + interface_module_args = MockInterfaceApi.INTERFACE_MODULE_ARGS + + @pytest.fixture + def interface_module_mock(self): + interface_module_mock = Interface() + interface_module_mock.module.check_mode = False + interface_module_mock.unity_conn = MagicMock() + return interface_module_mock + + def test_validate_param_ethernet_port_name_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'ethernet_port_name': " ", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.get_nas_server_obj = mock_none_response + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('invalid_ethernet_port_name') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_validate_param_vlan_id_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'vlan_id': 2, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.get_nas_server_obj = mock_none_response + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('invalid_vlan_id') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_validate_param_interface_ip_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': "10.2.2", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.get_nas_server_obj = mock_none_response + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('invalid_interface_ip') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_validate_param_gateway_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'gateway': "10.2.1", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.get_nas_server_obj = mock_none_response + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('invalid_gateway') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_validate_param_netmask_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'netmask': "10.2.0/2", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.get_nas_server_obj = mock_none_response + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('invalid_netmask') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_get_nas_server_obj_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_id': "nas_id_00", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=MockInterfaceApi.get_nas_server_obj_existed_false()) + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_nas_server_obj_errors('existed_false') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_get_nas_server_obj_exception(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_id': "nas_id_00", + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + mock_none_response = MagicMock(return_value=None) + interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=MockApiException) + interface_module_mock.validate_create_params = mock_none_response + interface_module_mock.add_interface = mock_none_response + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_nas_server_obj_errors('exception') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_modify_operation_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'vlan_id': 4, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object) + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT) + interface_module_mock.perform_module_operation() + assert MockInterfaceApi.get_interface_error_response('modify_failure') == \ + interface_module_mock.module.fail_json.call_args[1]['msg'] + + def test_get_interface_details(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object) + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT) + interface_module_mock.perform_module_operation() + interface_details = MockInterfaceApi.INTERFACE_OBJECT._get_properties() + assert interface_module_mock.module.exit_json.call_args[1]['interface_details'] == interface_details + + def test_get_interface_details_exception(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object) + interface_module_mock.unity_conn.get_file_interface = MagicMock(side_effect=[MockApiException, MockInterfaceApi.INTERFACE_OBJECT]) + interface_module_mock.validate_create_params = MagicMock(return_value=None) + interface_module_mock.add_interface = MagicMock(return_value=None) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockInterfaceApi.get_interface_exception_response('interface_exception') + + def test_add_interface_without_role_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME, + 'netmask': MockInterfaceApi.NETMASK_DUMMY, + 'gateway': MockInterfaceApi.GATEWAY_DUMMY, + 'vlan_id': 324, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_existing = MockInterfaceApi.get_nas_without_interface() + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_Value=nas_server_existing) + interface_module_mock.add_interface = MagicMock(return_value=None) + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockInterfaceApi.get_interface_error_response('no_role') + + def test_add_interface_without_ethernet_negative(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'role': "PRODUCTION", + 'netmask': MockInterfaceApi.NETMASK_DUMMY, + 'gateway': MockInterfaceApi.GATEWAY_DUMMY, + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'vlan_id': 324, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_existing = MockInterfaceApi.get_nas_without_interface() + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_Value=nas_server_existing) + interface_module_mock.add_interface = MagicMock(return_value=None) + interface_module_mock.get_interface_details = MagicMock(side_effect=[None, MockSDKObject({})]) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockInterfaceApi.get_interface_error_response('no_ethernet') + + def test_add_interface(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME, + 'role': "PRODUCTION", + 'netmask': MockInterfaceApi.NETMASK_DUMMY, + 'gateway': MockInterfaceApi.GATEWAY_DUMMY, + 'vlan_id': 324, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + nas_server_existing = MockInterfaceApi.get_nas_without_interface() + nas_server_existing.get_id = MagicMock(return_value='nas_id_00') + nas_server_existing.add_to_skip_list('get_id') + interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_existing, + nas_server_object]) + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT) + utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY + ethernet_port_info = MagicMock() + ethernet_port_info.id = 'ethernet_port_id_0' + interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info) + utils.UnityFileInterface = MagicMock() + utils.UnityFileInterface.create = MagicMock(return_value=None) + interface_module_mock.perform_module_operation() + interface_details = MockInterfaceApi.INTERFACE_OBJECT._get_properties() + assert interface_module_mock.module.exit_json.call_args[1]['interface_details'] == interface_details + + def test_add_interface_no_change(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME, + 'role': "PRODUCTION", + 'netmask': MockInterfaceApi.NETMASK_DUMMY, + 'gateway': MockInterfaceApi.GATEWAY_DUMMY, + 'vlan_id': 324, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_object, + nas_server_object]) + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT) + utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY + ethernet_port_info = MagicMock() + ethernet_port_info.id = 'ethernet_port_id_0' + interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info) + utils.UnityFileInterface = MagicMock() + utils.UnityFileInterface.create = MagicMock(return_value=None) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.exit_json.call_args[1]['changed'] is False + + def test_add_interface_exception(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'ethernet_port_name': MockInterfaceApi.ETHERNET_PORT_NAME, + 'role': "PRODUCTION", + 'netmask': MockInterfaceApi.NETMASK_DUMMY, + 'gateway': MockInterfaceApi.GATEWAY_DUMMY, + 'vlan_id': 324, + 'state': "present" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + nas_server_existing = MockInterfaceApi.get_nas_without_interface() + nas_server_existing.get_id = MagicMock(return_value='nas_id_00') + nas_server_existing.add_to_skip_list('get_id') + interface_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=[nas_server_existing, + nas_server_object]) + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=MockInterfaceApi.INTERFACE_OBJECT) + utils.FileInterfaceRoleEnum = MockInterfaceApi.FILE_INTERFACE_ROLE_ENUM_DUMMY + ethernet_port_info = MagicMock() + ethernet_port_info.id = 'ethernet_port_id_0' + interface_module_mock.unity_conn.get_ethernet_port = MagicMock(return_value=ethernet_port_info) + utils.UnityFileInterface = MagicMock() + utils.UnityFileInterface.create = MagicMock(side_effect=MockApiException) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockInterfaceApi.get_interface_exception_response('add_interface_exception') + + def test_delete_interface(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'state': "absent" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object) + interface_object = MockInterfaceApi.INTERFACE_OBJECT + interface_object.delete = MagicMock(return_value=None) + interface_object.add_to_skip_list('delete') + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=interface_object) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_delete_interface_exception(self, interface_module_mock): + self.interface_module_args.update({ + 'nas_server_name': "dummy_nas", + 'interface_ip': MockInterfaceApi.INTERFACE_DUMMY, + 'state': "absent" + }) + interface_module_mock.module.params = self.interface_module_args + nas_server_object = MockInterfaceApi.NAS_SERVER_OBJECT + interface_module_mock.unity_conn.get_nas_server = MagicMock(return_value=nas_server_object) + interface_object = MockInterfaceApi.INTERFACE_OBJECT + interface_object.delete = MagicMock(side_effect=MockApiException) + interface_object.add_to_skip_list('delete') + interface_module_mock.unity_conn.get_file_interface = MagicMock(return_value=interface_object) + interface_module_mock.perform_module_operation() + assert interface_module_mock.module.fail_json.call_args[1]['msg'] == \ + MockInterfaceApi.get_interface_exception_response('delete_interface_exception') diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py new file mode 100644 index 000000000..a929ba497 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nasserver.py @@ -0,0 +1,112 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for NAS Server module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nasserver_api \ + import MockNASServerApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.nas_server = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() + +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.nasserver import NASServer + + +class TestNASServer(): + + NAS_SERVER_MODULE_ARGS = {'nas_server_name': 'nas0', 'nas_server_id': None, 'nas_server_new_name': None, 'default_unix_user': None, + 'default_windows_user': None, 'is_replication_destination': None, 'is_multiprotocol_enabled': None, + 'allow_unmapped_user': None, 'enable_windows_to_unix_username_mapping': None, + 'is_backup_only': None, 'is_packet_reflect_enabled': None, 'current_unix_directory_service': None, + 'replication_reuse_resource': None, 'replication_params': {}, 'replication_state': None, 'state': None} + + @pytest.fixture + def nasserver_module_mock(self): + nasserver_module_mock = NASServer() + nasserver_module_mock.unity_conn = MagicMock() + return nasserver_module_mock + + def get_nas_response(self): + nasserver_response = MockNASServerApi.get_nas_server_response() + nasserver_response['replicate_with_dst_resource_provisioning'] = MagicMock(return_value=True) + return nasserver_response + + def test_enable_nas_replication(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params()) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.perform_module_operation() + assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_enable_nas_replication_invalid_params(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params(False)) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.perform_module_operation() + assert "rpo value should be in range of 5 to 1440" in \ + nasserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_enable_nas_replication_throws_ex(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params()) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.get_remote_system = MagicMock(side_effect=Exception) + nasserver_module_mock.perform_module_operation() + assert "Enabling replication to the nas server %s failed with error" \ + % self.NAS_SERVER_MODULE_ARGS['nas_server_name'] in \ + nasserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_modify_nas_replication(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update(MockNASServerApi.get_replication_params()) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.get_replication_session_on_filter = MagicMock() + nasserver_module_mock.perform_module_operation() + assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_disable_replication(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'}) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.update_replication_params = MagicMock() + nasserver_module_mock.perform_module_operation() + assert nasserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_disable_replication_throws_ex(self, nasserver_module_mock): + self.NAS_SERVER_MODULE_ARGS.update({'replication_state': 'disable', 'state': 'present'}) + nasserver_module_mock.module.params = self.NAS_SERVER_MODULE_ARGS + nasserver_module_mock.get_nas_server = \ + MagicMock(return_value=MockSDKObject(self.get_nas_response())) + nasserver_module_mock.to_update = MagicMock(return_value=False) + nasserver_module_mock.get_replication_session = MagicMock(side_effect=Exception) + nasserver_module_mock.perform_module_operation() + assert "Disabling replication on the nas server %s failed with error" \ + % self.NAS_SERVER_MODULE_ARGS['nas_server_name'] in \ + nasserver_module_mock.module.fail_json.call_args[1]['msg'] diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py new file mode 100644 index 000000000..ed138147c --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfs.py @@ -0,0 +1,183 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for nfs module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nfs_api \ + import MockNfsApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules import nfs + + +class TestNfs(): + + get_module_args = MockNfsApi.NFS_MODULE_ARGS + + @pytest.fixture + def nfs_module_mock(self): + nfs_module_mock = nfs.NFS() + nfs_module_mock.unity = MagicMock() + return nfs_module_mock + + def test_add_host_in_nfs_share_on_advhostmgmt_true(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': True, + 'no_access_hosts': [{'host_name': "host1"}, {'ip_address': "**.***.2.2"}], + 'host_state': 'present-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + utils.UnityNfsShareList = MagicMock + nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('add', True) + nfs_object.modify = MagicMock(return_value=None) + nfs_object.add_to_skip_list('modify') + fs_object = MockNfsApi.FILESYSTEM_OBJECT + get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('add', True) + nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object) + nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object) + nfs_module_mock.unity.get_host = MagicMock(side_effect=[MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2)]) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_remove_host_in_nfs_share_on_advhostmgmt_true(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': True, + 'no_access_hosts': [{'host_name': "host1"}, {'ip_address': "**.***.2.2"}], + 'host_state': 'absent-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + utils.UnityNfsShareList = MagicMock + nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', True) + nfs_object.modify = MagicMock(return_value=None) + nfs_object.add_to_skip_list('modify') + fs_object = MockNfsApi.FILESYSTEM_OBJECT + get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('remove', True) + nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object) + nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object) + nfs_module_mock.unity.get_host = MagicMock(side_effect=[MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2), + MockNfsApi.get_host_obj(id=1), MockNfsApi.get_host_obj(id=2)]) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_add_host_in_nfs_share_on_advhostmgmt_false(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': False, + 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}], + 'host_state': 'present-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + utils.UnityNfsShareList = MagicMock + nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('add', False) + nfs_object.modify = MagicMock(return_value=None) + nfs_object.add_to_skip_list('modify') + fs_object = MockNfsApi.FILESYSTEM_OBJECT + get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('add', False) + nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object) + nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_remove_host_in_nfs_share_on_advhostmgmt_false(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': False, + 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}], + 'host_state': 'absent-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + utils.UnityNfsShareList = MagicMock + nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', False) + nfs_object.modify = MagicMock(return_value=None) + nfs_object.add_to_skip_list('modify') + fs_object = MockNfsApi.FILESYSTEM_OBJECT + get_nfs_share_display_attrs_data = MockNfsApi.get_nfs_share_display_attr_on_host_access('remove', False) + nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object) + nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=get_nfs_share_display_attrs_data) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_host_access_nfs_share_subnet_negative(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': False, + 'read_only_root_hosts': [{'subnet': "1x.x.x.x"}], + 'host_state': 'present-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + nfs_module_mock.get_filesystem = MagicMock(return_value=None) + nfs_module_mock.get_nfs_share = MagicMock(return_value=None) + nfs_module_mock.create_nfs_share = MagicMock(return_value=None) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=None) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('subnet_validation') + + def test_host_access_nfs_share_advhostmngmt_negative(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'read_only_root_hosts': [{'subnet': "1x.x.x.x/10"}], + 'host_state': 'present-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + nfs_module_mock.get_filesystem = MagicMock(return_value=None) + nfs_module_mock.get_nfs_share = MagicMock(return_value=None) + nfs_module_mock.create_nfs_share = MagicMock(return_value=None) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=None) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('advhostmngmnt_field_validation') + + def test_host_access_nfs_share_exception_negative(self, nfs_module_mock): + self.get_module_args.update({ + 'nfs_export_name': "nfsshare_dummy_name", + 'filesystem_id': "fs_id_1", + 'adv_host_mgmt_enabled': False, + 'read_only_root_hosts': [{'domain': MockNfsApi.DUMMY_DOMAIN_VALUE}, {'subnet': MockNfsApi.DUMMY_SUBNET_VALUE}], + 'host_state': 'absent-in-export', + 'state': 'present' + }) + nfs_module_mock.module.params = self.get_module_args + utils.UnityNfsShareList = MagicMock + nfs_object = MockNfsApi.get_nfs_share_object_on_host_access('remove', False) + nfs_object.modify = MagicMock(side_effect=MockApiException) + nfs_object.add_to_skip_list('modify') + fs_object = MockNfsApi.FILESYSTEM_OBJECT + nfs_module_mock.unity.get_filesystem = MagicMock(return_value=fs_object) + nfs_module_mock.unity.get_nfs_share = MagicMock(return_value=nfs_object) + nfs.get_nfs_share_display_attrs = MagicMock(return_value=None) + nfs_module_mock.perform_module_operation() + assert nfs_module_mock.module.fail_json.call_args[1]['msg'] == MockNfsApi.host_access_negative_response('modify_exception') diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py new file mode 100644 index 000000000..c2a680487 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_nfsserver.py @@ -0,0 +1,225 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Mock Api response for Unit tests of NFS server module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_nfsserver_api \ + import MockNFSServerApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import HttpError as http_error, MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +utils.UnityNfsServer = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() +from ansible_collections.dellemc.unity.plugins.modules.nfsserver import NFSServer + + +class TestNFSServer(): + + get_module_args = MockNFSServerApi.NFS_SERVER_MODULE_ARGS + + @pytest.fixture + def nfsserver_module_mock(self): + nfsserver_module_mock = NFSServer() + nfsserver_module_mock.unity_conn = MagicMock() + utils.nfsserver = MagicMock() + nfsserver_module_mock.module.check_mode = False + return nfsserver_module_mock + + def test_get_nfs_server_details(self, nfsserver_module_mock): + self.get_module_args.update({ + 'nfs_server_id': 'nfs_95', + 'state': 'present' + }) + nfsserver_module_mock.module.params = self.get_module_args + host_details = MockNFSServerApi.get_nas_server_id() + host_details.get_id = MagicMock(return_value="nas_10") + host_details.add_to_skip_list('get_id') + nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=host_details) + nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(return_value=MockNFSServerApi.get_nfs_server_details()[0]) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.get_nfs_server_details_method_response() == \ + nfsserver_module_mock.module.exit_json.call_args[1]['nfs_server_details'] + + def test_get_nfs_server_details_with_exception(self, nfsserver_module_mock): + self.get_module_args.update({ + 'nas_server_name': 'test_nas_server', + 'state': 'present' + }) + nfsserver_module_mock.module.params = self.get_module_args + host_details = MockNFSServerApi.get_nas_server_id() + host_details.get_id = MagicMock(return_value="nas_10") + host_details.add_to_skip_list('get_id') + nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(return_value=host_details) + utils.HttpError = http_error + nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(side_effect=http_error) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.get_nfs_server_api_exception() == \ + nfsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_create_nfs_server(self, nfsserver_module_mock): + self.get_module_args.update({ + 'nas_server_name': 'dummy_name', + 'host_name': "dummy_nas23", + 'is_secure_enabled': True, + 'kerberos_domain_controller_type': "WINDOWS", + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'is_extended_credentials_enabled': False, + 'nfs_v4_enabled': True, + 'state': "present" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None) + utils.KdcTypeEnum = MagicMock(return_value={"KdcTypeEnum": {"description": "Windows", "name": "WINDOWS", "value": 2}}) + utils.UnityNfsServer = MagicMock() + utils.UnityNfsServer.create = MagicMock(return_value=True) + nfsserver_module_mock.perform_module_operation() + assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_create_nfs_server_with_unix(self, nfsserver_module_mock): + self.get_module_args.update({ + 'nas_server_name': 'dummy_name', + 'host_name': "dummy_nas23", + 'is_secure_enabled': True, + 'kerberos_domain_controller_type': "UNIX", + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'is_extended_credentials_enabled': False, + 'nfs_v4_enabled': True, + 'state': "present" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None) + utils.KdcTypeEnum = MagicMock(return_value={"KdcTypeEnum": {"description": "Windows", "name": "UNIX", "value": 1}}) + utils.UnityNfsServer = MagicMock() + utils.UnityNfsServer.create = MagicMock(return_value=True) + nfsserver_module_mock.perform_module_operation() + assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_create_nfs_server_throws_exception(self, nfsserver_module_mock): + self.get_module_args.update({ + 'nas_server_name': 'dummy_name', + 'host_name': "dummy_nas23", + 'is_secure_enabled': True, + 'kerberos_domain_controller_type': "WINDOWS", + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'is_extended_credentials_enabled': False, + 'nfs_v4_enabled': True, + 'state': "present" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None) + utils.UnityNfsServer = MagicMock() + utils.UnityNfsServer.create = MagicMock(side_effect=MockApiException) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.create_nfs_server_with_api_exception() in nfsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_delete_nfs_server(self, nfsserver_module_mock): + nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response() + self.get_module_args.update({ + 'nas_server_name': 'test_nas_server', + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'remove_spn_from_kerberos': True, + 'state': "absent" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details) + nfsserver_module_mock.perform_module_operation() + assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_delete_nfs_server_with_spn_false(self, nfsserver_module_mock): + nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response() + self.get_module_args.update({ + 'nas_server_name': 'test_nas_server', + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'remove_spn_from_kerberos': False, + 'state': "absent" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details) + nfsserver_module_mock.perform_module_operation() + assert nfsserver_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_delete_nfs_server_with_exception(self, nfsserver_module_mock): + nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response() + self.get_module_args.update({ + 'nas_server_name': 'test_nas_server', + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'remove_spn_from_kerberos': False, + 'state': "absent" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details) + nfsserver_module_mock.unity_conn.get_nfs_server = MagicMock(side_effect=MockApiException) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.delete_exception() in nfsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_is_modification_required(self, nfsserver_module_mock): + nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response() + self.get_module_args.update({ + 'nas_server_name': 'test_nas_server', + 'is_extended_credentials_enabled': True, + 'state': 'present' + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.modify_error_msg() == nfsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_get_nas_server_id_exception(self, nfsserver_module_mock): + nfs_server_details = MockNFSServerApi.get_nfs_server_details_method_response() + self.get_module_args.update({ + 'nas_server_name': 'dummy_name', + 'is_secure_enabled': True, + 'host_name': "dummy_nas23", + 'kerberos_domain_controller_type': "WINDOWS", + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'is_extended_credentials_enabled': False, + 'nfs_v4_enabled': True, + 'state': "present" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.unity_conn.get_nas_server = MagicMock(side_effect=MockApiException) + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=nfs_server_details) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.get_nas_server_id_api_exception() in \ + nfsserver_module_mock.module.fail_json.call_args[1]['msg'] + + def test_create_nas_server_without_nas_server_id(self, nfsserver_module_mock): + self.get_module_args.update({ + 'is_secure_enabled': True, + 'host_name': "dummy_nas23", + 'kerberos_domain_controller_type': "WINDOWS", + 'kerberos_domain_controller_username': "xxxxxxxx", + 'kerberos_domain_controller_password': "xxxxxxxx", + 'is_extended_credentials_enabled': False, + 'nfs_v4_enabled': True, + 'state': "present" + }) + nfsserver_module_mock.module.params = self.get_module_args + nfsserver_module_mock.get_nas_server_id = MagicMock(return_value=None) + nfsserver_module_mock.get_nfs_server_details = MagicMock(return_value=None) + nfsserver_module_mock.create_nfs_server = MagicMock(return_value=None) + nfsserver_module_mock.perform_module_operation() + assert MockNFSServerApi.create_nfs_server_without_nas_server_id() in \ + nfsserver_module_mock.module.fail_json.call_args[1]['msg'] diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py new file mode 100644 index 000000000..94bf18c35 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_storagepool.py @@ -0,0 +1,132 @@ +# Copyright: (c) 2022, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for host module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_storagepool_api \ + import MockStoragePoolApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.storagepool import StoragePool + + +class TestUnityStoragePool(): + + get_module_args = MockStoragePoolApi.STORAGE_POOL_MODULE_ARGS + + @pytest.fixture + def storagepool_module_mock(self): + storagepool_module_mock = StoragePool() + storagepool_module_mock.conn = MagicMock() + return storagepool_module_mock + + def test_get_host_details(self, storagepool_module_mock): + self.get_module_args.update({ + 'pool_name': 'Ansible_Unity_TEST_1', + }) + storagepool_module_mock.module.params = self.get_module_args + get_pool = MockSDKObject(MockStoragePoolApi.get_pool_details_response('get_pool')) + get_pool._get_property_from_raw = MagicMock(return_value=MockSDKObject({'is_schedule_enabled': True})) + get_pool.add_to_skip_list('_get_property_from_raw') + storagepool_module_mock.conn.get_pool = MagicMock(return_value=get_pool) + pool_object = MockStoragePoolApi.get_pool_details_response('pool_object') + utils.UnityPool = MagicMock() + utils.UnityPool.get = MagicMock(return_value=MockSDKObject(pool_object)) + disk_list = MockStoragePoolApi.get_pool_details_response('disk_list') + utils.UnityDiskList = MagicMock() + utils.UnityDiskList.get = MagicMock(return_value=disk_list) + storagepool_module_mock.perform_module_operation() + assert MockStoragePoolApi.get_pool_details_response('module')['storage_pool_details'] == \ + storagepool_module_mock.module.exit_json.call_args[1]['storage_pool_details'] + + def test_get_host_details_throws_exception(self, storagepool_module_mock): + self.get_module_args.update({ + 'pool_name': 'Ansible_Unity_SP_3', + }) + storagepool_module_mock.module.params = self.get_module_args + storagepool_module_mock.conn.get_pool = MagicMock(side_effect=MockApiException) + storagepool_module_mock.result = MagicMock() + storagepool_module_mock.get_pool_drives = MagicMock() + storagepool_module_mock.perform_module_operation() + storagepool_module_mock.is_pool_modification_required = MagicMock(return_value=False) + assert MockStoragePoolApi.get_pool_details_response('error') == storagepool_module_mock.module.fail_json.call_args[1]['msg'] + + def test_create_pool(self, storagepool_module_mock): + self.get_module_args.update({ + 'pool_name': 'test_pool', + 'pool_description': 'Unity test pool.', + 'raid_groups': { + 'disk_group_id': "dg_16", + 'disk_num': 3, + 'raid_type': 'RAID10', + 'stripe_width': 'BEST_FIT', + }, + 'alert_threshold': 50, + 'is_harvest_enabled': True, + 'pool_harvest_high_threshold': 59, + 'pool_harvest_low_threshold': 40, + 'is_snap_harvest_enabled': True, + 'snap_harvest_high_threshold': 80, + 'snap_harvest_low_threshold': 60, + 'fast_vp': "enabled", + 'fast_cache': "disabled", + 'pool_type': 'TRADITIONAL', + 'state': 'present' + }) + storagepool_module_mock.module.params = self.get_module_args + storagepool_module_mock.get_raid_groups_response = MagicMock(return_value=None) + storagepool_module_mock.get_details = MagicMock(return_value=None) + pool_object = MockStoragePoolApi.create_pool_response('api') + utils.UnityPool = MagicMock() + utils.UnityPool.create = MagicMock(return_value=MockSDKObject(pool_object)) + storagepool_module_mock.perform_module_operation() + assert storagepool_module_mock.module.exit_json.call_args[1]['changed'] + + def test_create_pool_throws_exception(self, storagepool_module_mock): + self.get_module_args.update({ + 'pool_name': 'test_pool', + 'pool_description': 'Unity test pool.', + 'raid_groups': { + 'disk_group_id': "dg_16", + 'disk_num': 3, + 'raid_type': 'RAID10', + 'stripe_width': 'BEST_FIT', + }, + 'alert_threshold': 50, + 'is_harvest_enabled': True, + 'pool_harvest_high_threshold': 59, + 'pool_harvest_low_threshold': 40, + 'is_snap_harvest_enabled': True, + 'snap_harvest_high_threshold': 80, + 'snap_harvest_low_threshold': 60, + 'fast_vp': "enabled", + 'fast_cache': "disabled", + 'pool_type': 'TRADITIONAL', + 'state': 'present' + }) + storagepool_module_mock.module.params = self.get_module_args + storagepool_module_mock.get_details = MagicMock(return_value=None) + utils.UnityPool = MagicMock() + storagepool_module_mock.get_raid_groups_response = MagicMock(side_effect=MockApiException) + storagepool_module_mock.perform_module_operation() + assert MockStoragePoolApi.create_pool_response('error') in \ + storagepool_module_mock.module.fail_json.call_args[1]['msg'] diff --git a/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py new file mode 100644 index 000000000..1081f8c07 --- /dev/null +++ b/ansible_collections/dellemc/unity/tests/unit/plugins/modules/test_volume.py @@ -0,0 +1,128 @@ +# Copyright: (c) 2023, Dell Technologies + +# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt) + +"""Unit Tests for volume module on Unity""" + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +import pytest +from mock.mock import MagicMock +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_volume_api \ + import MockVolumeApi +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_sdk_response \ + import MockSDKObject +from ansible_collections.dellemc.unity.tests.unit.plugins.module_utils.mock_api_exception \ + import MockApiException +from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \ + import utils + +utils.get_logger = MagicMock() +utils.get_unity_management_host_parameters = MagicMock() +utils.ensure_required_libs = MagicMock() +utils.get_unity_unisphere_connection = MagicMock() +utils.UnityPool = MagicMock() +utils.UnityPool.get_size_in_gb = MagicMock() +from ansible.module_utils import basic +basic.AnsibleModule = MagicMock() + +from ansible_collections.dellemc.unity.plugins.modules.volume import Volume + + +class TestUnityVolume(): + + get_module_args = MockVolumeApi.VOLUME_MODULE_ARGS + + @pytest.fixture + def volume_module_mock(self): + volume_module_mock = Volume() + volume_module_mock.conn = MagicMock() + return volume_module_mock + + def test_create_volume(self, volume_module_mock): + self.get_module_args.update({ + 'vol_name': "Atest", + 'pool_name': "Extreme_Perf_tier", + 'size': 2, + 'cap_unit': "GB", + 'is_thin': True, + 'compression': True, + 'advanced_dedup': True, + 'state': 'present' + }) + volume_module_mock.module.params = self.get_module_args + volume_module_mock.host_access_modify_required = MagicMock(return_value=False) + obj_pool = MockSDKObject(MockVolumeApi.pool) + volume_object = MockVolumeApi.create_volume_response('api')['volume_details'] + volume_module_mock.unity_conn.get_pool = MagicMock(return_value=obj_pool) + volume_module_mock.unity_conn.get_lun = MagicMock(return_value=None) + obj_pool.create_lun = MagicMock(return_value=MockSDKObject(volume_object)) + volume_module_mock.perform_module_operation() + assert volume_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_create_volume_exception(self, volume_module_mock): + self.get_module_args.update({ + 'vol_name': "Atest", + 'pool_name': "Extreme_Perf_tier", + 'size': 2, + 'cap_unit': "GB", + 'is_thin': True, + 'compression': True, + 'advanced_dedup': True, + 'state': 'present' + }) + volume_module_mock.module.params = self.get_module_args + volume_module_mock.host_access_modify_required = MagicMock(return_value=False) + obj_pool = MockSDKObject(MockVolumeApi.pool) + volume_module_mock.unity_conn.get_pool = MagicMock(return_value=obj_pool) + volume_module_mock.unity_conn.get_lun = MagicMock(return_value=None) + obj_pool.create_lun = MagicMock(side_effect=MockApiException) + volume_module_mock.perform_module_operation() + assert MockVolumeApi.create_volume_response('error') in \ + volume_module_mock.module.fail_json.call_args[1]['msg'] + + def test_modify_volume(self, volume_module_mock): + self.get_module_args.update({ + 'vol_name': "Atest", + 'pool_name': "Extreme_Perf_tier", + 'size': 2, + 'cap_unit': "GB", + 'is_thin': True, + 'compression': True, + 'advanced_dedup': False, + 'state': 'present' + }) + volume_module_mock.module.params = self.get_module_args + volume_module_mock.host_access_modify_required = MagicMock(return_value=False) + obj_vol = MockSDKObject(MockVolumeApi.modify_volume_response('api')['volume_details']) + volume_object = MockVolumeApi.modify_volume_response('api')['volume_details'] + volume_module_mock.unity_conn.get_lun = MagicMock(return_value=obj_vol) + obj_vol.modify = MagicMock(return_value=MockSDKObject(volume_object)) + volume_module_mock.volume_modify_required = MagicMock() + volume_module_mock.get_volume_display_attributes = MagicMock() + volume_module_mock.perform_module_operation() + assert volume_module_mock.module.exit_json.call_args[1]['changed'] is True + + def test_modify_volume_exception(self, volume_module_mock): + self.get_module_args.update({ + 'vol_name': "Atest", + 'pool_name': "Extreme_Perf_tier", + 'size': 2, + 'cap_unit': "GB", + 'is_thin': True, + 'compression': True, + 'advanced_dedup': False, + 'state': 'present' + }) + volume_module_mock.module.params = self.get_module_args + volume_module_mock.host_access_modify_required = MagicMock(return_value=False) + obj_vol = MockSDKObject(MockVolumeApi.modify_volume_response('api')['volume_details']) + volume_module_mock.unity_conn.get_lun = MagicMock(return_value=obj_vol) + obj_vol.modify = MagicMock(side_effect=MockApiException) + volume_module_mock.volume_modify_required = MagicMock() + volume_module_mock.get_volume_display_attributes = MagicMock() + volume_module_mock.perform_module_operation() + assert MockVolumeApi.modify_volume_response('error') in \ + volume_module_mock.module.fail_json.call_args[1]['msg'] |