From 37dd373c6b8a21a5a99460278d70daeedf36ab6d Mon Sep 17 00:00:00 2001 From: Nathan Swartz Date: Tue, 27 Aug 2019 08:04:02 -0500 Subject: [PATCH] Volume dev upstream new options (#59660) * Add controller ownership and cache without batteries option * Add unit test for new netapp_e_volume options * Add integration tests for netapp_e_volume module. * Changed default read_ahead_enable option to true in netapp_e_volume module. * Fix off-segment aligned volume size in netapp_e_volume module. --- .../modules/storage/netapp/netapp_e_volume.py | 50 ++++++++++++++++--- .../storage/netapp/test_netapp_e_volume.py | 37 +++++++------- 2 files changed, 61 insertions(+), 26 deletions(-) diff --git a/lib/ansible/modules/storage/netapp/netapp_e_volume.py b/lib/ansible/modules/storage/netapp/netapp_e_volume.py index 1bc5cce94cb..6ee91e4d05e 100644 --- a/lib/ansible/modules/storage/netapp/netapp_e_volume.py +++ b/lib/ansible/modules/storage/netapp/netapp_e_volume.py @@ -106,6 +106,13 @@ options: - Values must be between or equal to 10 and 99. default: 95 version_added: 2.8 + owning_controller: + description: + - Specifies which controller will be the primary owner of the volume + - Not specifying will allow the controller to choose ownership. + required: false + choices: ["A", "B"] + version_added: 2.9 ssd_cache_enabled: description: - Whether an existing SSD cache should be enabled on the volume (fails if no SSD cache defined) @@ -138,6 +145,13 @@ options: type: bool default: true version_added: 2.8 + cache_without_batteries: + description: + - Indicates whether caching should be used without battery backup. + - Warning, M(cache_without_batteries==true) and the storage system looses power and there is no battery backup, data will be lost! + type: bool + default: false + version_added: 2.9 workload_name: description: - Label for the workload defined by the metadata. @@ -268,6 +282,7 @@ class NetAppESeriesVolume(NetAppESeriesModule): type="str"), size=dict(type="float"), segment_size_kb=dict(type="int", default=128), + owning_controller=dict(required=False, choices=['A', 'B']), ssd_cache_enabled=dict(type="bool", default=False), data_assurance_enabled=dict(type="bool", default=False), thin_provision=dict(type="bool", default=False), @@ -278,6 +293,7 @@ class NetAppESeriesVolume(NetAppESeriesModule): read_cache_enable=dict(type="bool", default=True), read_ahead_enable=dict(type="bool", default=True), write_cache_enable=dict(type="bool", default=True), + cache_without_batteries=dict(type="bool", default=False), workload_name=dict(type="str", required=False), metadata=dict(type="dict", require=False), wait_for_initialization=dict(type="bool", default=False), @@ -300,12 +316,17 @@ class NetAppESeriesVolume(NetAppESeriesModule): self.size_unit = args["size_unit"] self.segment_size_kb = args["segment_size_kb"] if args["size"]: - self.size_b = int(args["size"] * self.SIZE_UNIT_MAP[self.size_unit]) + self.size_b = self.convert_to_aligned_bytes(args["size"]) + + self.owning_controller_id = None + if args["owning_controller"]: + self.owning_controller_id = "070000000000000000000001" if args["owning_controller"] == "A" else "070000000000000000000002" self.read_cache_enable = args["read_cache_enable"] self.read_ahead_enable = args["read_ahead_enable"] self.write_cache_enable = args["write_cache_enable"] self.ssd_cache_enabled = args["ssd_cache_enabled"] + self.cache_without_batteries = args["cache_without_batteries"] self.data_assurance_enabled = args["data_assurance_enabled"] self.thin_provision = args["thin_provision"] @@ -315,10 +336,9 @@ class NetAppESeriesVolume(NetAppESeriesModule): self.thin_volume_max_repo_size_b = None if args["thin_volume_repo_size"]: - self.thin_volume_repo_size_b = args["thin_volume_repo_size"] * self.SIZE_UNIT_MAP[self.size_unit] + self.thin_volume_repo_size_b = self.convert_to_aligned_bytes(args["thin_volume_repo_size"]) if args["thin_volume_max_repo_size"]: - self.thin_volume_max_repo_size_b = int(args["thin_volume_max_repo_size"] * - self.SIZE_UNIT_MAP[self.size_unit]) + self.thin_volume_max_repo_size_b = self.convert_to_aligned_bytes(args["thin_volume_max_repo_size"]) self.workload_name = args["workload_name"] self.metadata = args["metadata"] @@ -361,6 +381,13 @@ class NetAppESeriesVolume(NetAppESeriesModule): self.pool_detail = None self.workload_id = None + def convert_to_aligned_bytes(self, size): + """Convert size to the truncated byte size that aligns on the segment size.""" + size_bytes = int(size * self.SIZE_UNIT_MAP[self.size_unit]) + segment_size_bytes = int(self.segment_size_kb * self.SIZE_UNIT_MAP["kb"]) + segment_count = int(size_bytes / segment_size_bytes) + return segment_count * segment_size_bytes + def get_volume(self): """Retrieve volume details from storage array.""" volumes = list() @@ -579,6 +606,11 @@ class NetAppESeriesVolume(NetAppESeriesModule): self.ssd_cache_enabled != self.volume_detail["flashCached"]): change = True + # controller ownership + if self.owning_controller_id and self.owning_controller_id != self.volume_detail["preferredManager"]: + change = True + request_body.update(dict(owningControllerId=self.owning_controller_id)) + if self.workload_name: request_body.update(dict(metaTags=[dict(key="workloadId", value=self.workload_id), dict(key="volumeTypeId", value="volume")])) @@ -595,9 +627,13 @@ class NetAppESeriesVolume(NetAppESeriesModule): if self.thin_volume_expansion_policy != self.volume_detail["expansionPolicy"]: change = True request_body.update(dict(expansionPolicy=self.thin_volume_expansion_policy)) - elif self.read_ahead_enable != (int(self.volume_detail["cacheSettings"]["readAheadMultiplier"]) > 0): - change = True - request_body["cacheSettings"].update(dict(readAheadEnable=self.read_ahead_enable)) + else: + if self.read_ahead_enable != (int(self.volume_detail["cacheSettings"]["readAheadMultiplier"]) > 0): + change = True + request_body["cacheSettings"].update(dict(readAheadEnable=self.read_ahead_enable)) + if self.cache_without_batteries != self.volume_detail["cacheSettings"]["cwob"]: + change = True + request_body["cacheSettings"].update(dict(cacheWithoutBatteries=self.cache_without_batteries)) return request_body if change else dict() diff --git a/test/units/modules/storage/netapp/test_netapp_e_volume.py b/test/units/modules/storage/netapp/test_netapp_e_volume.py index 8d27f619a68..348d0e4b1f4 100644 --- a/test/units/modules/storage/netapp/test_netapp_e_volume.py +++ b/test/units/modules/storage/netapp/test_netapp_e_volume.py @@ -238,16 +238,14 @@ class NetAppESeriesVolumeTest(ModuleTestCase): self._set_args(arg_set) volume_object = NetAppESeriesVolume() - size_unit_multiplier = NetAppESeriesModule.SIZE_UNIT_MAP[arg_set["size_unit"]] - self.assertEqual(volume_object.size_b, arg_set["size"] * size_unit_multiplier) - self.assertEqual(volume_object.thin_volume_repo_size_b, - arg_set["thin_volume_repo_size"] * size_unit_multiplier) + self.assertEqual(volume_object.size_b, volume_object.convert_to_aligned_bytes(arg_set["size"])) + self.assertEqual(volume_object.thin_volume_repo_size_b, volume_object.convert_to_aligned_bytes(arg_set["thin_volume_repo_size"])) self.assertEqual(volume_object.thin_volume_expansion_policy, "automatic") if "thin_volume_max_repo_size" not in arg_set.keys(): - self.assertEqual(volume_object.thin_volume_max_repo_size_b, arg_set["size"] * size_unit_multiplier) + self.assertEqual(volume_object.thin_volume_max_repo_size_b, volume_object.convert_to_aligned_bytes(arg_set["size"])) else: self.assertEqual(volume_object.thin_volume_max_repo_size_b, - arg_set["thin_volume_max_repo_size"] * size_unit_multiplier) + volume_object.convert_to_aligned_bytes(arg_set["thin_volume_max_repo_size"])) # validate metadata form self._set_args( @@ -502,7 +500,7 @@ class NetAppESeriesVolumeTest(ModuleTestCase): "read_ahead_enable": True, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": True, "segmentSize": str(128 * 1024)} self.assertEqual(volume_object.get_volume_property_changes(), dict()) @@ -514,7 +512,7 @@ class NetAppESeriesVolumeTest(ModuleTestCase): "thin_volume_max_repo_size": 1000, "thin_volume_growth_alert_threshold": 90}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": True, "growthAlertThreshold": "90", "expansionPolicy": "automatic", "segmentSize": str(128 * 1024)} @@ -527,7 +525,7 @@ class NetAppESeriesVolumeTest(ModuleTestCase): "read_ahead_enable": True, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": False, "writeCacheEnable": True, + "cacheSettings": {"cwob": False, "readCacheEnable": False, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": True, "segmentSize": str(128 * 1024)} self.assertEqual(volume_object.get_volume_property_changes(), @@ -535,11 +533,11 @@ class NetAppESeriesVolumeTest(ModuleTestCase): 'flashCache': True}) self._set_args( {"state": "present", "name": "Matthew", "storage_pool_name": "pool", "size": 100, "ssd_cache_enabled": True, - "read_cache_enable": True, "write_cache_enable": True, + "read_cache_enable": True, "write_cache_enable": True, "cache_without_batteries": False, "read_ahead_enable": True, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": False, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": False, "readAheadMultiplier": 1}, "flashCached": True, "segmentSize": str(128 * 1024)} self.assertEqual(volume_object.get_volume_property_changes(), @@ -547,29 +545,30 @@ class NetAppESeriesVolumeTest(ModuleTestCase): 'flashCache': True}) self._set_args( {"state": "present", "name": "Matthew", "storage_pool_name": "pool", "size": 100, "ssd_cache_enabled": True, - "read_cache_enable": True, "write_cache_enable": True, + "read_cache_enable": True, "write_cache_enable": True, "cache_without_batteries": True, "read_ahead_enable": True, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": False, "segmentSize": str(128 * 1024)} self.assertEqual(volume_object.get_volume_property_changes(), - {"metaTags": [], 'cacheSettings': {'readCacheEnable': True, 'writeCacheEnable': True}, + {"metaTags": [], 'cacheSettings': {'readCacheEnable': True, 'writeCacheEnable': True, "cacheWithoutBatteries": True}, 'flashCache': True}) self._set_args( {"state": "present", "name": "Matthew", "storage_pool_name": "pool", "size": 100, "ssd_cache_enabled": True, - "read_cache_enable": True, "write_cache_enable": True, + "read_cache_enable": True, "write_cache_enable": True, "cache_without_batteries": True, "read_ahead_enable": False, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": False, "segmentSize": str(128 * 1024)} self.assertEqual(volume_object.get_volume_property_changes(), {"metaTags": [], 'cacheSettings': {'readCacheEnable': True, 'writeCacheEnable': True, - 'readAheadEnable': False}, + 'readAheadEnable': False, + "cacheWithoutBatteries": True}, 'flashCache': True}) self._set_args( @@ -579,7 +578,7 @@ class NetAppESeriesVolumeTest(ModuleTestCase): "thin_volume_max_repo_size": 1000, "thin_volume_growth_alert_threshold": 90}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = {"metadata": [], - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, + "cacheSettings": {"cwob": True, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": True, "growthAlertThreshold": "95", "expansionPolicy": "automatic", "segmentSize": str(128 * 1024)} @@ -594,7 +593,7 @@ class NetAppESeriesVolumeTest(ModuleTestCase): "read_cache_enable": True, "write_cache_enable": True, "read_ahead_enable": True, "thin_provision": False}) volume_object = NetAppESeriesVolume() volume_object.volume_detail = { - "cacheSettings": {"readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, + "cacheSettings": {"cwob": False, "readCacheEnable": True, "writeCacheEnable": True, "readAheadMultiplier": 1}, "flashCached": True, "segmentSize": str(512 * 1024)} with self.assertRaisesRegexp(AnsibleFailJson, "Existing volume segment size is"): volume_object.get_volume_property_changes()