NetApp: Implement share metadata update method
Consider two metadata keys i.e. snapshot_policy and showmount. Partially-implements: blueprint pass-resource-metadata-updates-to-backend-drivers Depends-on: If4297cca3249359f72976800db2112ea9c61c06f Change-Id: I042a2caa5884ddea09ecfa0028d01758c18af5a3
This commit is contained in:
parent
4bf505404a
commit
52d423f606
@ -3733,7 +3733,8 @@ class ShareDriver(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def update_share_from_metadata(self, context, share, metadata):
|
def update_share_from_metadata(self, context, share, metadata,
|
||||||
|
share_server=None):
|
||||||
"""Update the share from metadata.
|
"""Update the share from metadata.
|
||||||
|
|
||||||
Driver must implement this method if needs to perform some action
|
Driver must implement this method if needs to perform some action
|
||||||
@ -3743,5 +3744,6 @@ class ShareDriver(object):
|
|||||||
:param share: Share instance model with share data.
|
:param share: Share instance model with share data.
|
||||||
:param metadata: Dict contains key-value pair where driver will
|
:param metadata: Dict contains key-value pair where driver will
|
||||||
perform necessary action based on key.
|
perform necessary action based on key.
|
||||||
|
:param share_server: Reference to the share server.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -1600,6 +1600,14 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
'Data ONTAP driver')
|
'Data ONTAP driver')
|
||||||
raise exception.NetAppException(msg % security_service['type'])
|
raise exception.NetAppException(msg % security_service['type'])
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_showmount(self, showmount):
|
||||||
|
"""Update show mount for vserver. """
|
||||||
|
nfs_service_modify_arg = {
|
||||||
|
'showmount': showmount
|
||||||
|
}
|
||||||
|
self.send_request('nfs-service-modify', nfs_service_modify_arg)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def enable_nfs(self, versions, nfs_config=None):
|
def enable_nfs(self, versions, nfs_config=None):
|
||||||
"""Enables NFS on Vserver."""
|
"""Enables NFS on Vserver."""
|
||||||
@ -2326,6 +2334,27 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
|||||||
|
|
||||||
return api_args
|
return api_args
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_volume_snapshot_policy(self, volume_name, snapshot_policy):
|
||||||
|
"""Set snapshot policy for the specified volume."""
|
||||||
|
api_args = {
|
||||||
|
'query': {
|
||||||
|
'volume-attributes': {
|
||||||
|
'volume-id-attributes': {
|
||||||
|
'name': volume_name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'attributes': {
|
||||||
|
'volume-attributes': {
|
||||||
|
'volume-snapshot-attributes': {
|
||||||
|
'snapshot-policy': snapshot_policy,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.send_request('volume-modify-iter', api_args)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
@manila_utils.retry(retry_param=exception.NetAppException,
|
@manila_utils.retry(retry_param=exception.NetAppException,
|
||||||
interval=3,
|
interval=3,
|
||||||
|
@ -1110,6 +1110,18 @@ class NetAppRestClient(object):
|
|||||||
'compression': compression,
|
'compression': compression,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_volume_snapshot_policy(self, volume_name, snapshot_policy):
|
||||||
|
"""Set snapshot policy for the specified volume."""
|
||||||
|
volume = self._get_volume_by_args(vol_name=volume_name)
|
||||||
|
uuid = volume['uuid']
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'snapshot_policy.name': snapshot_policy
|
||||||
|
}
|
||||||
|
# update snapshot policy
|
||||||
|
self.send_request(f'/storage/volumes/{uuid}', 'patch', body=body)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def update_volume_efficiency_attributes(self, volume_name, dedup_enabled,
|
def update_volume_efficiency_attributes(self, volume_name, dedup_enabled,
|
||||||
compression_enabled,
|
compression_enabled,
|
||||||
@ -4686,6 +4698,26 @@ class NetAppRestClient(object):
|
|||||||
}
|
}
|
||||||
raise exception.NetAppException(msg % msg_args)
|
raise exception.NetAppException(msg % msg_args)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_showmount(self, showmount):
|
||||||
|
"""Update show mount for vserver. """
|
||||||
|
# Get SVM UUID.
|
||||||
|
query = {
|
||||||
|
'name': self.vserver,
|
||||||
|
'fields': 'uuid'
|
||||||
|
}
|
||||||
|
res = self.send_request('/svm/svms', 'get', query=query)
|
||||||
|
if not res.get('records'):
|
||||||
|
msg = _('Vserver %s not found.') % self.vserver
|
||||||
|
raise exception.NetAppException(msg)
|
||||||
|
svm_id = res.get('records')[0]['uuid']
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'showmount_enabled': showmount,
|
||||||
|
}
|
||||||
|
self.send_request(f'/protocols/nfs/services/{svm_id}', 'patch',
|
||||||
|
body=body)
|
||||||
|
|
||||||
@na_utils.trace
|
@na_utils.trace
|
||||||
def enable_nfs(self, versions, nfs_config=None):
|
def enable_nfs(self, versions, nfs_config=None):
|
||||||
"""Enables NFS on Vserver."""
|
"""Enables NFS on Vserver."""
|
||||||
|
@ -398,3 +398,8 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
|||||||
|
|
||||||
def delete_backup(self, context, backup, share, **kwargs):
|
def delete_backup(self, context, backup, share, **kwargs):
|
||||||
return self.library.delete_backup(context, backup, share, **kwargs)
|
return self.library.delete_backup(context, backup, share, **kwargs)
|
||||||
|
|
||||||
|
def update_share_from_metadata(self, context, share, metadata,
|
||||||
|
share_server=None):
|
||||||
|
self.library.update_share_from_metadata(
|
||||||
|
context, share, metadata, share_server=share_server)
|
||||||
|
@ -362,3 +362,8 @@ class NetAppCmodeSingleSvmShareDriver(driver.ShareDriver):
|
|||||||
|
|
||||||
def delete_backup(self, context, backup, share, **kwargs):
|
def delete_backup(self, context, backup, share, **kwargs):
|
||||||
return self.library.delete_backup(context, backup, share, **kwargs)
|
return self.library.delete_backup(context, backup, share, **kwargs)
|
||||||
|
|
||||||
|
def update_share_from_metadata(self, context, share, metadata,
|
||||||
|
share_server=None):
|
||||||
|
self.library.update_share_from_metadata(
|
||||||
|
context, share, metadata, share_server=share_server)
|
||||||
|
@ -5014,3 +5014,29 @@ class NetAppCmodeFileStorageLibrary(object):
|
|||||||
# Delete Vserver
|
# Delete Vserver
|
||||||
if share_server is not None:
|
if share_server is not None:
|
||||||
self._delete_backup_vserver(backup, des_vserver)
|
self._delete_backup_vserver(backup, des_vserver)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_volume_snapshot_policy(self, share, snapshot_policy,
|
||||||
|
share_server=None):
|
||||||
|
share_name = self._get_backend_share_name(share['id'])
|
||||||
|
_, vserver_client = self._get_vserver(share_server=share_server)
|
||||||
|
vserver_client.update_volume_snapshot_policy(share_name,
|
||||||
|
snapshot_policy)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_showmount(self, share, showmount, share_server=None):
|
||||||
|
_, vserver_client = self._get_vserver(share_server=share_server)
|
||||||
|
vserver_client.update_showmount(showmount)
|
||||||
|
|
||||||
|
@na_utils.trace
|
||||||
|
def update_share_from_metadata(self, context, share, metadata,
|
||||||
|
share_server=None):
|
||||||
|
metadata_update_func_map = {
|
||||||
|
"snapshot_policy": "update_volume_snapshot_policy",
|
||||||
|
"showmount": "update_showmount",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in metadata.items():
|
||||||
|
update_func = getattr(self, metadata_update_func_map.get(k))
|
||||||
|
if update_func:
|
||||||
|
update_func(share, v, share_server=share_server)
|
||||||
|
@ -6759,9 +6759,10 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
def update_share_from_metadata(self, context, share_id, metadata):
|
def update_share_from_metadata(self, context, share_id, metadata):
|
||||||
share = self.db.share_get(context, share_id)
|
share = self.db.share_get(context, share_id)
|
||||||
share_instance = self._get_share_instance(context, share)
|
share_instance = self._get_share_instance(context, share)
|
||||||
|
share_server = self._get_share_server(context, share_instance)
|
||||||
try:
|
try:
|
||||||
self.driver.update_share_from_metadata(context, share_instance,
|
self.driver.update_share_from_metadata(context, share_instance,
|
||||||
metadata)
|
metadata, share_server)
|
||||||
self.message_api.create(
|
self.message_api.create(
|
||||||
context,
|
context,
|
||||||
message_field.Action.UPDATE_METADATA,
|
message_field.Action.UPDATE_METADATA,
|
||||||
|
@ -1054,3 +1054,10 @@ class DummyDriver(driver.ShareDriver):
|
|||||||
{'backup': backup['id'],
|
{'backup': backup['id'],
|
||||||
'share': share_instance['share_id']})
|
'share': share_instance['share_id']})
|
||||||
return {'total_progress': '100'}
|
return {'total_progress': '100'}
|
||||||
|
|
||||||
|
def update_share_from_metadata(self, context, share_instance, metadata,
|
||||||
|
share_server=None):
|
||||||
|
LOG.debug("Updated share %(share)s. Metadata %(metadata)s "
|
||||||
|
"applied successfully.",
|
||||||
|
{'share': share_instance['share_id'],
|
||||||
|
'metadata': metadata})
|
||||||
|
@ -2534,6 +2534,19 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
self.client.send_request.assert_has_calls([
|
self.client.send_request.assert_has_calls([
|
||||||
mock.call('vserver-modify', vserver_modify_args)])
|
mock.call('vserver-modify', vserver_modify_args)])
|
||||||
|
|
||||||
|
def test_update_showmount(self):
|
||||||
|
|
||||||
|
self.mock_object(self.client, 'send_request')
|
||||||
|
|
||||||
|
fake_showmount = 'true'
|
||||||
|
self.client.update_showmount(fake_showmount)
|
||||||
|
|
||||||
|
nfs_service_modify_args = {
|
||||||
|
'showmount': fake_showmount,
|
||||||
|
}
|
||||||
|
self.client.send_request.assert_called_once_with(
|
||||||
|
'nfs-service-modify', nfs_service_modify_args)
|
||||||
|
|
||||||
@ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
|
@ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
|
||||||
def test_enable_nfs(self, nfs_config):
|
def test_enable_nfs(self, nfs_config):
|
||||||
|
|
||||||
@ -3490,6 +3503,32 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.assertFalse(result)
|
self.assertFalse(result)
|
||||||
|
|
||||||
|
def test_update_volume_snapshot_policy(self):
|
||||||
|
self.mock_object(self.client, 'send_request')
|
||||||
|
|
||||||
|
self.client.update_volume_snapshot_policy(fake.SHARE_NAME,
|
||||||
|
fake.SNAPSHOT_POLICY_NAME)
|
||||||
|
|
||||||
|
volume_modify_iter_api_args = {
|
||||||
|
'query': {
|
||||||
|
'volume-attributes': {
|
||||||
|
'volume-id-attributes': {
|
||||||
|
'name': fake.SHARE_NAME,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'attributes': {
|
||||||
|
'volume-attributes': {
|
||||||
|
'volume-snapshot-attributes': {
|
||||||
|
'snapshot-policy': fake.SNAPSHOT_POLICY_NAME,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.client.send_request.assert_called_once_with(
|
||||||
|
'volume-modify-iter', volume_modify_iter_api_args)
|
||||||
|
|
||||||
def test_enable_dedup(self):
|
def test_enable_dedup(self):
|
||||||
|
|
||||||
self.mock_object(self.client, 'send_request')
|
self.mock_object(self.client, 'send_request')
|
||||||
|
@ -2766,6 +2766,23 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
|
|||||||
self.client.get_job_state,
|
self.client.get_job_state,
|
||||||
'fake_uuid')
|
'fake_uuid')
|
||||||
|
|
||||||
|
def test_update_volume_snapshot_policy(self):
|
||||||
|
return_uuid = {
|
||||||
|
'uuid': 'fake_uuid'
|
||||||
|
}
|
||||||
|
mock_get_vol = self.mock_object(self.client, '_get_volume_by_args',
|
||||||
|
mock.Mock(return_value=return_uuid))
|
||||||
|
mock_sr = self.mock_object(self.client, 'send_request')
|
||||||
|
|
||||||
|
self.client.update_volume_snapshot_policy('fake_volume_name',
|
||||||
|
fake.SNAPSHOT_POLICY_NAME)
|
||||||
|
body = {
|
||||||
|
'snapshot_policy.name': fake.SNAPSHOT_POLICY_NAME
|
||||||
|
}
|
||||||
|
mock_sr.assert_called_once_with('/storage/volumes/fake_uuid',
|
||||||
|
'patch', body=body)
|
||||||
|
mock_get_vol.assert_called_once_with(vol_name='fake_volume_name')
|
||||||
|
|
||||||
@ddt.data(True, False)
|
@ddt.data(True, False)
|
||||||
def test_update_volume_efficiency_attributes(self, status):
|
def test_update_volume_efficiency_attributes(self, status):
|
||||||
response = {
|
response = {
|
||||||
@ -4499,6 +4516,31 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
|
|||||||
self.client.send_request.assert_called_once_with(
|
self.client.send_request.assert_called_once_with(
|
||||||
'/svm/peers/fake_uuid', 'delete', enable_tunneling=False)
|
'/svm/peers/fake_uuid', 'delete', enable_tunneling=False)
|
||||||
|
|
||||||
|
def test_update_showmount(self):
|
||||||
|
query = {
|
||||||
|
'name': fake.VSERVER_NAME,
|
||||||
|
'fields': 'uuid'
|
||||||
|
}
|
||||||
|
response_svm = fake.SVMS_LIST_SIMPLE_RESPONSE_REST
|
||||||
|
self.client.vserver = fake.VSERVER_NAME
|
||||||
|
self.mock_object(self.client,
|
||||||
|
'send_request',
|
||||||
|
mock.Mock(side_effect=[response_svm, None]))
|
||||||
|
|
||||||
|
fake_showmount = 'true'
|
||||||
|
self.client.update_showmount(fake_showmount)
|
||||||
|
|
||||||
|
svm_id = response_svm.get('records')[0]['uuid']
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'showmount_enabled': fake_showmount,
|
||||||
|
}
|
||||||
|
self.client.send_request.assert_has_calls([
|
||||||
|
mock.call('/svm/svms', 'get', query=query),
|
||||||
|
mock.call(f'/protocols/nfs/services/{svm_id}',
|
||||||
|
'patch', body=body)
|
||||||
|
])
|
||||||
|
|
||||||
@ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
|
@ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
|
||||||
def test_enable_nfs(self, nfs_config):
|
def test_enable_nfs(self, nfs_config):
|
||||||
self.mock_object(self.client, '_get_unique_svm_by_name',
|
self.mock_object(self.client, '_get_unique_svm_by_name',
|
||||||
|
@ -8905,3 +8905,23 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
|||||||
self.mock_object(mock_des_client,
|
self.mock_object(mock_des_client,
|
||||||
'list_volume_snapshots',
|
'list_volume_snapshots',
|
||||||
mock.Mock(return_value=snap_list))
|
mock.Mock(return_value=snap_list))
|
||||||
|
|
||||||
|
def test_update_share_from_metadata(self):
|
||||||
|
metadata = {
|
||||||
|
"snapshot_policy": "daily",
|
||||||
|
"showmount": "True",
|
||||||
|
}
|
||||||
|
|
||||||
|
share_instance = fake.SHARE_INSTANCE
|
||||||
|
mock_update_volume_snapshot_policy = self.mock_object(
|
||||||
|
self.library, 'update_volume_snapshot_policy')
|
||||||
|
mock_update_showmount = self.mock_object(
|
||||||
|
self.library, 'update_showmount')
|
||||||
|
|
||||||
|
self.library.update_share_from_metadata(self.context, share_instance,
|
||||||
|
metadata)
|
||||||
|
|
||||||
|
mock_update_volume_snapshot_policy.assert_called_once_with(
|
||||||
|
share_instance, "daily", share_server=None)
|
||||||
|
mock_update_showmount.assert_called_once_with(
|
||||||
|
share_instance, "True", share_server=None)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
The NetApp ONTAP driver is now able to update the current `snapshot_policy`
|
||||||
|
and/or both `showmount` configurations in a pre-created share. Please use
|
||||||
|
the share metadata set feature to update these values.
|
Loading…
Reference in New Issue
Block a user