Fix KeyError in modify_volume when autosize attributes missing

The test 'test_snapshot_before_share_replica' failed due to a KeyError
for 'mode' during replica promotion. The modify_volume() method in
client_cmode_rest.py accessed keys like 'mode' and 'grow-threshold-percent'
from the autosize_attributes dictionary without checking if they exist.

During replica promotion, _update_autosize_attributes_after_promote_replica()
called modify_volume() with a dictionary missing the 'mode' key, resulting
in a KeyError.

This change updates modify_volume() to check for the existence of each
autosize attribute before accessing it. The function now gracefully handles
partial autosize attribute dictionaries, including only present attributes
in the request body.
Closes-bug: #2130717

Change-Id: I8ee3f84abc295c40d35c201c0360578e56239ddf
Signed-off-by: medhac1403 <medhaj06@gmail.com>
This commit is contained in:
medhac1403
2025-10-29 05:42:35 -04:00
committed by Medha Choudhary
parent 58e8f893e3
commit 4dc5390ed0
3 changed files with 124 additions and 8 deletions

View File

@@ -2589,14 +2589,9 @@ class NetAppRestClient(object):
}
if autosize_attributes:
attributes = autosize_attributes
body['autosize'] = {
'mode': attributes['mode'],
'grow_threshold': attributes['grow-threshold-percent'],
'shrink_threshold': attributes['shrink-threshold-percent'],
'maximum': attributes['maximum-size'],
'minimum': attributes['minimum-size'],
}
autosize = self._build_autosize_attributes(autosize_attributes)
if autosize:
body['autosize'] = autosize
if language:
body['language'] = language
@@ -2639,6 +2634,35 @@ class NetAppRestClient(object):
if self._is_snaplock_enabled_volume(volume_name):
self.set_snaplock_attributes(volume_name, **options)
@na_utils.trace
def _build_autosize_attributes(self, autosize_attributes):
"""Build autosize attributes dict from autosize_attributes."""
reset_val = autosize_attributes.get('reset', '')
if str(reset_val).lower() == 'true':
return None
src = autosize_attributes
# Build autosize dict directly
autosize_key_map = {
'grow-threshold-percent': 'grow_threshold',
'shrink-threshold-percent': 'shrink_threshold',
'maximum-size': 'maximum',
'minimum-size': 'minimum',
}
autosize = {
dest_key: src[src_key]
for src_key, dest_key in autosize_key_map.items()
if src_key in src
}
# Add mode if present
if 'mode' in src:
autosize['mode'] = src['mode']
return autosize if autosize else None
@na_utils.trace
def start_volume_move(self, volume_name, vserver, destination_aggregate,
cutover_action='wait', encrypt_destination=None):

View File

@@ -2488,6 +2488,89 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
self.client._parse_timestamp,
test_time_str)
def test__build_autosize_attributes(self):
"""Test _build_autosize_attributes with various input scenarios."""
# Test case 1: Basic functionality with all supported attributes
autosize_attrs = {
'grow-threshold-percent': 90,
'shrink-threshold-percent': 50,
'maximum-size': '10GB',
'minimum-size': '1GB',
'mode': 'grow'
}
result = self.client._build_autosize_attributes(autosize_attrs)
expected = {
'grow_threshold': 90,
'shrink_threshold': 50,
'maximum': '10GB',
'minimum': '1GB',
'mode': 'grow'
}
self.assertEqual(expected, result)
def test__build_autosize_attributes_reset_true(self):
"""Test _build_autosize_attributes returns None when reset is true."""
autosize_attrs = {
'reset': 'true',
'grow-threshold-percent': 90,
'maximum-size': '10GB'
}
result = self.client._build_autosize_attributes(autosize_attrs)
self.assertIsNone(result)
def test__build_autosize_attributes_partial_attrs(self):
"""Test _build_autosize_attributes with only some attributes."""
autosize_attrs = {
'grow-threshold-percent': 85,
'maximum-size': '5GB'
}
result = self.client._build_autosize_attributes(autosize_attrs)
expected = {
'grow_threshold': 85,
'maximum': '5GB'
}
self.assertEqual(expected, result)
def test__build_autosize_attributes_empty_dict(self):
"""Test _build_autosize_attributes returns None for empty dict."""
autosize_attrs = {}
result = self.client._build_autosize_attributes(autosize_attrs)
self.assertIsNone(result)
def test__build_autosize_attributes_with_mode_only(self):
"""Test _build_autosize_attributes with only mode attribute."""
autosize_attrs = {
'mode': 'grow_shrink'
}
result = self.client._build_autosize_attributes(autosize_attrs)
expected = {
'mode': 'grow_shrink'
}
self.assertEqual(expected, result)
autosize_attrs = {
'grow-threshold-percent': 90,
'maximum-size': '10GB'
}
result = self.client._build_autosize_attributes(autosize_attrs)
expected = {
'grow_threshold': 90,
'maximum': '10GB'
}
self.assertEqual(expected, result)
def test_start_volume_move(self):
mock__send_volume_move_request = self.mock_object(

View File

@@ -0,0 +1,9 @@
---
fixes:
- |
Fixed an issue that caused the share replica promotion to fail due to
missing replica attributes in the NetApp driver while using the REST API.
For more details, please refer to
`launchpad bug #2130717 <https://bugs.launchpad.net/manila/+bug/2130717>`_.