Merge "Fix backup creation errors with NetApp driver"

This commit is contained in:
Zuul 2024-06-05 15:14:17 +00:00 committed by Gerrit Code Review
commit d773353502
9 changed files with 225 additions and 48 deletions

View File

@ -2315,7 +2315,9 @@ class NetAppRestClient(object):
fields = ['state', 'source.svm.name', 'source.path', fields = ['state', 'source.svm.name', 'source.path',
'destination.svm.name', 'destination.path', 'destination.svm.name', 'destination.path',
'transfer.end_time', 'uuid', 'policy.type', 'transfer.end_time', 'uuid', 'policy.type',
'transfer_schedule.name', 'transfer.state'] 'transfer_schedule.name', 'transfer.state',
'last_transfer_type', 'transfer.bytes_transferred',
'healthy']
query = {} query = {}
query['fields'] = ','.join(fields) query['fields'] = ','.join(fields)
@ -2365,7 +2367,14 @@ class NetAppRestClient(object):
(self._parse_timestamp(record['transfer']['end_time']) if (self._parse_timestamp(record['transfer']['end_time']) if
record.get('transfer', {}).get('end_time') else 0), record.get('transfer', {}).get('end_time') else 0),
'uuid': record['uuid'], 'uuid': record['uuid'],
'policy-type': record.get('policy', {}).get('type') 'policy-type': record.get('policy', {}).get('type'),
'is-healthy': (
'true'
if record.get('healthy', {}) is True else 'false'),
'last-transfer-type': record.get('last_transfer_type', None),
'last-transfer-size': record.get('transfer',
{}).get('bytes_transferred'),
}) })
return snapmirrors return snapmirrors

View File

@ -73,20 +73,20 @@ def get_backend_configuration(backend_name):
return config return config
def get_backup_configuration(backup_name): def get_backup_configuration(backup_type):
config_stanzas = CONF.list_all_sections() config_stanzas = CONF.list_all_sections()
if backup_name not in config_stanzas: if backup_type not in config_stanzas:
msg = _("Could not find backend stanza %(backup_name)s in " msg = _("Could not find backup_type stanza %(backup_type)s in "
"configuration which is required for backup workflows " "configuration which is required for backup workflows "
"with the source share. Available stanzas are " "with the source share. Available stanzas are "
"%(stanzas)s") "%(stanzas)s")
params = { params = {
"stanzas": config_stanzas, "stanzas": config_stanzas,
"backend_name": backup_name, "backup_type": backup_type,
} }
raise exception.BadConfigurationException(reason=msg % params) raise exception.BadConfigurationException(reason=msg % params)
config = configuration.Configuration(driver.share_opts, config = configuration.Configuration(driver.share_opts,
config_group=backup_name) config_group=backup_type)
config.append_config_values(na_opts.netapp_backup_opts) config.append_config_values(na_opts.netapp_backup_opts)
return config return config

View File

@ -64,9 +64,9 @@ class Backup(Enum):
BACKUP_TYPE = "backup_type" BACKUP_TYPE = "backup_type"
BACKEND_NAME = "netapp_backup_backend_section_name" BACKEND_NAME = "netapp_backup_backend_section_name"
DES_VSERVER = "netapp_backup_vserver" DES_VSERVER = "netapp_backup_vserver"
DES_VOLUME = "netapp_backup_share" DES_VOLUME = "netapp_backup_volume"
SM_LABEL = "backup" SM_LABEL = "backup"
DES_VSERVER_PREFIX = "backup_vserver" DES_VSERVER_PREFIX = "backup"
DES_VOLUME_PREFIX = "backup_volume" DES_VOLUME_PREFIX = "backup_volume"
VOLUME_TYPE = "dp" VOLUME_TYPE = "dp"
SM_POLICY = "os_backup_policy" SM_POLICY = "os_backup_policy"
@ -4350,13 +4350,24 @@ class NetAppCmodeFileStorageLibrary(object):
" from command line or API.") " from command line or API.")
# check the backend is related to NetApp # check the backend is related to NetApp
try:
backup_config = data_motion.get_backup_configuration(backup_type) backup_config = data_motion.get_backup_configuration(backup_type)
except exception.BadConfigurationException:
msg = _("Could not find backup_type '%(backup_type)s' stanza"
" in config file") % {'backup_type': backup_type}
raise exception.BadConfigurationException(reason=msg)
backend_name = backup_config.safe_get(Backup.BACKEND_NAME.value) backend_name = backup_config.safe_get(Backup.BACKEND_NAME.value)
try:
backend_config = data_motion.get_backend_configuration( backend_config = data_motion.get_backend_configuration(
backend_name) backend_name
)
except exception.BadConfigurationException:
msg = _("Could not find backend '%(backend_name)s' stanza"
" in config file") % {'backend_name': backend_name}
raise exception.BadConfigurationException(reason=msg)
if (backend_config.safe_get("netapp_storage_family") if (backend_config.safe_get("netapp_storage_family")
!= 'ontap_cluster'): != 'ontap_cluster'):
err_msg = _("Wrong vendor backend %s is provided, provide" err_msg = _("Wrong vendor backend '%s' is provided, provide"
" only NetApp backend.") % backend_name " only NetApp backend.") % backend_name
raise exception.BackupException(err_msg) raise exception.BackupException(err_msg)
@ -4393,16 +4404,17 @@ class NetAppCmodeFileStorageLibrary(object):
# Get the destination vserver and volume for relationship # Get the destination vserver and volume for relationship
source_path = f"{src_vserver}:{src_vol}" source_path = f"{src_vserver}:{src_vol}"
snapmirror_info = src_vserver_client.get_snapmirror_destinations( snapmirror_info = src_vserver_client.get_snapmirror_destinations(
source_path=source_path) source_path=source_path
)
if len(snapmirror_info) > 1: if len(snapmirror_info) > 1:
err_msg = _("Source path %(path)s has more than one relationships." msg = _("Source path '%(path)s' has more than one relationships."
" To create the share backup, delete the all source" " To create the share backup, delete the all source"
" volume's SnapMirror relationships using 'snapmirror'" " volume's SnapMirror relationships using 'snapmirror'"
" ONTAP CLI or System Manger.") " ONTAP CLI or System Manager.")
msg_args = { msg_args = {
'path': source_path 'path': source_path
} }
raise exception.NetAppException(err_msg % msg_args) raise exception.NetAppException(msg % msg_args)
elif len(snapmirror_info) == 1: elif len(snapmirror_info) == 1:
des_vserver, des_volume = self._get_destination_vserver_and_vol( des_vserver, des_volume = self._get_destination_vserver_and_vol(
src_vserver_client, source_path, False) src_vserver_client, source_path, False)
@ -4431,7 +4443,8 @@ class NetAppCmodeFileStorageLibrary(object):
if share_server: if share_server:
self._delete_backup_vserver(backup, des_vserver) self._delete_backup_vserver(backup, des_vserver)
msg = _("Failed to create a volume in vserver %(des_vserver)s") msg = _("Failed to create a volume in vserver '%(des_vserver)s"
"'")
msg_args = {'des_vserver': des_vserver} msg_args = {'des_vserver': des_vserver}
raise exception.NetAppException(msg % msg_args) raise exception.NetAppException(msg % msg_args)
@ -4451,8 +4464,7 @@ class NetAppCmodeFileStorageLibrary(object):
Backup.SM_LABEL.value) Backup.SM_LABEL.value)
] ]
if len(snap_list_with_backup) == 1: if len(snap_list_with_backup) == 1:
self.is_volume_backup_before = True self._set_volume_has_backup_before(True)
policy_name = f"{Backup.SM_POLICY.value}_{share_instance['id']}" policy_name = f"{Backup.SM_POLICY.value}_{share_instance['id']}"
try: try:
des_vserver_client.create_snapmirror_policy( des_vserver_client.create_snapmirror_policy(
@ -4490,9 +4502,9 @@ class NetAppCmodeFileStorageLibrary(object):
des_volume, des_volume,
share_server=share_server) share_server=share_server)
msg = _("SnapVault relationship creation or initialization" msg = _("SnapVault relationship creation or initialization"
" failed between source %(source_vserver)s:" " failed between source '%(source_vserver)s:"
"%(source_volume)s and destination %(des_vserver)s:" "%(source_volume)s' and destination '%(des_vserver)s:"
"%(des_volume)s for share id %(share_id)s.") "%(des_volume)s' for share id %(share_id)s.")
msg_args = { msg_args = {
'source_vserver': src_vserver, 'source_vserver': src_vserver,
@ -4564,7 +4576,7 @@ class NetAppCmodeFileStorageLibrary(object):
} }
msg = _("There is no SnapMirror relationship available for" msg = _("There is no SnapMirror relationship available for"
" source path '%(source_path)s' and destination path" " source path '%(source_path)s' and destination path"
" '%(des_path)s' yet.") % msg_args " '%(des_path)s' yet.")
LOG.warning(msg, msg_args) LOG.warning(msg, msg_args)
return progress_status return progress_status
LOG.debug("SnapMirror details %s:", snapmirror_info) LOG.debug("SnapMirror details %s:", snapmirror_info)
@ -4582,6 +4594,22 @@ class NetAppCmodeFileStorageLibrary(object):
{'progress_status': progress_status}) {'progress_status': progress_status})
return progress_status return progress_status
if snapmirror_info[0].get("is-healthy") == 'false':
self._resource_cleanup_for_backup(backup,
share_instance,
des_vserver,
des_vol,
share_server=share_server)
msg_args = {
'source_path': source_path,
'des_path': des_path,
}
msg = _("There is an issue with SnapMirror relationship with"
" source path '%(source_path)s' and destination path"
" '%(des_path)s'. Make sure destination volume is or was "
"not part of any other SnapMirror relationship.")
raise exception.NetAppException(message=msg % msg_args)
# Verify that snapshot is transferred to destination volume # Verify that snapshot is transferred to destination volume
snap_name = self._get_backup_snapshot_name(backup, snap_name = self._get_backup_snapshot_name(backup,
share_instance['id']) share_instance['id'])
@ -4589,7 +4617,7 @@ class NetAppCmodeFileStorageLibrary(object):
des_vol, des_vol,
snap_name) snap_name)
LOG.debug("Snapshot '%(snap_name)s' transferred successfully to" LOG.debug("Snapshot '%(snap_name)s' transferred successfully to"
" destination", {'snap_name': snap_name}) " destination.", {'snap_name': snap_name})
# previously if volume was part of some relationship and if we delete # previously if volume was part of some relationship and if we delete
# all the backup of share then last snapshot will be left on # all the backup of share then last snapshot will be left on
# destination volume, and we can't delete that snapshot due to ONTAP # destination volume, and we can't delete that snapshot due to ONTAP
@ -4611,7 +4639,7 @@ class NetAppCmodeFileStorageLibrary(object):
snap_to_delete = snap_list_with_backup[1] snap_to_delete = snap_list_with_backup[1]
else: else:
snap_to_delete = snap_list_with_backup[0] snap_to_delete = snap_list_with_backup[0]
self.is_volume_backup_before = False self._set_volume_has_backup_before(False)
des_vserver_client.delete_snapshot(des_vol, snap_to_delete, des_vserver_client.delete_snapshot(des_vol, snap_to_delete,
True) True)
LOG.debug("Previous snapshot %{snap_name}s deleted" LOG.debug("Previous snapshot %{snap_name}s deleted"
@ -4676,7 +4704,7 @@ class NetAppCmodeFileStorageLibrary(object):
"total_progress": Backup.TOTAL_PROGRESS_ZERO.value "total_progress": Backup.TOTAL_PROGRESS_ZERO.value
} }
return progress_status return progress_status
LOG.debug("SnapMirror relationship of type RST is deleted") LOG.debug("SnapMirror relationship of type RST is deleted.")
snap_name = self._get_backup_snapshot_name(backup, snap_name = self._get_backup_snapshot_name(backup,
share_instance['id']) share_instance['id'])
snapshot_list = src_vserver_client.list_volume_snapshots(src_vol_name) snapshot_list = src_vserver_client.list_volume_snapshots(src_vol_name)
@ -4699,7 +4727,7 @@ class NetAppCmodeFileStorageLibrary(object):
share_server=share_server, share_server=share_server,
) )
except exception.VserverNotFound: except exception.VserverNotFound:
LOG.warning("Vserver associated with share %s was not found.", LOG.warning("Vserver associated with share '%s' was not found.",
share_instance['id']) share_instance['id'])
return return
src_vol_name = self._get_backend_share_name(share_instance['id']) src_vol_name = self._get_backend_share_name(share_instance['id'])
@ -4762,7 +4790,7 @@ class NetAppCmodeFileStorageLibrary(object):
des_vserver_client.get_snapshot(des_vol, snap_name) des_vserver_client.get_snapshot(des_vol, snap_name)
is_snapshot_deleted = self._is_snapshot_deleted(False) is_snapshot_deleted = self._is_snapshot_deleted(False)
except (SnapshotResourceNotFound, netapp_api.NaApiError): except (SnapshotResourceNotFound, netapp_api.NaApiError):
LOG.debug("Snapshot %s deleted successfully.", snap_name) LOG.debug("Snapshot '%s' deleted successfully.", snap_name)
if not is_snapshot_deleted: if not is_snapshot_deleted:
err_msg = _("Snapshot '%(snapshot_name)s' is not deleted" err_msg = _("Snapshot '%(snapshot_name)s' is not deleted"
" successfully on ONTAP." " successfully on ONTAP."
@ -4770,6 +4798,10 @@ class NetAppCmodeFileStorageLibrary(object):
LOG.exception(err_msg) LOG.exception(err_msg)
raise exception.NetAppException(err_msg) raise exception.NetAppException(err_msg)
@na_utils.trace
def _set_volume_has_backup_before(self, value):
self.is_volume_backup_before = value
@na_utils.trace @na_utils.trace
def _is_snapshot_deleted(self, is_deleted): def _is_snapshot_deleted(self, is_deleted):
return is_deleted return is_deleted
@ -4839,14 +4871,15 @@ class NetAppCmodeFileStorageLibrary(object):
des_vserver_client) des_vserver_client)
if not des_aggr: if not des_aggr:
msg = _("Not able to find any aggregate from ONTAP" msg = _("Not able to find any aggregate from ONTAP"
" to create the volume") " to create the volume. Make sure aggregates are"
" added to destination vserver")
raise exception.NetAppException(msg) raise exception.NetAppException(msg)
src_vol = self._get_backend_share_name(share_instance['id']) src_vol = self._get_backend_share_name(share_instance['id'])
vol_attr = src_vserver_client.get_volume(src_vol) vol_attr = src_vserver_client.get_volume(src_vol)
source_vol_size = vol_attr.get('size') source_vol_size = vol_attr.get('size')
vol_size_in_gb = int(source_vol_size) / units.Gi vol_size_in_gb = int(source_vol_size) / units.Gi
share_id = share_instance['id'].replace('-', '_') share_id = share_instance['id'].replace('-', '_')
des_volume = f"backup_volume_{share_id}" des_volume = f"{Backup.DES_VOLUME_PREFIX.value}_{share_id}"
des_vserver_client.create_volume(des_aggr, des_volume, des_vserver_client.create_volume(des_aggr, des_volume,
vol_size_in_gb, volume_type='dp') vol_size_in_gb, volume_type='dp')
return des_volume return des_volume
@ -4860,7 +4893,7 @@ class NetAppCmodeFileStorageLibrary(object):
snapmirror_info = src_vserver_client.get_snapmirror_destinations( snapmirror_info = src_vserver_client.get_snapmirror_destinations(
source_path=source_path) source_path=source_path)
if validate_relation and len(snapmirror_info) != 1: if validate_relation and len(snapmirror_info) != 1:
msg = _("There are more then one relationship with the source." msg = _("There are more then one relationship with the source"
" '%(source_path)s'." % {'source_path': source_path}) " '%(source_path)s'." % {'source_path': source_path})
raise exception.NetAppException(msg) raise exception.NetAppException(msg)
if len(snapmirror_info) == 1: if len(snapmirror_info) == 1:

View File

@ -21,6 +21,7 @@ as needed to provision shares.
""" """
import re import re
from manila.share.drivers.netapp.dataontap.cluster_mode.lib_base import Backup
from oslo_log import log from oslo_log import log
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import excutils from oslo_utils import excutils
@ -2393,7 +2394,7 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
] ]
aggr_list = aggr_matching_list aggr_list = aggr_matching_list
share_server_id = share_server['id'] share_server_id = share_server['id']
des_vserver = f"backup_{share_server_id}" des_vserver = f"{Backup.DES_VSERVER_PREFIX.value}_{share_server_id}"
LOG.debug("Creating vserver %s:", des_vserver) LOG.debug("Creating vserver %s:", des_vserver)
try: try:
des_cluster_api_client.create_vserver( des_cluster_api_client.create_vserver(

View File

@ -309,7 +309,7 @@ netapp_backup_opts = [
'are enabled, create separate config sections for each ' 'are enabled, create separate config sections for each '
'backup type specifying the "netapp_backup_vserver", ' 'backup type specifying the "netapp_backup_vserver", '
'"netapp_backup_backend_section_name", ' '"netapp_backup_backend_section_name", '
'"netapp_backup_share", and ' '"netapp_backup_volume", and '
'"netapp_snapmirror_job_timeout" as appropriate.' '"netapp_snapmirror_job_timeout" as appropriate.'
' Example- netapp_enabled_backup_types = eng_backup,' ' Example- netapp_enabled_backup_types = eng_backup,'
' finance_backup'), ' finance_backup'),
@ -322,7 +322,7 @@ netapp_backup_opts = [
help='vserver name of backend that is use for backup the share.' help='vserver name of backend that is use for backup the share.'
' When user provide vserver value then backup volume will ' ' When user provide vserver value then backup volume will '
' be created under this vserver '), ' be created under this vserver '),
cfg.StrOpt('netapp_backup_share', cfg.StrOpt('netapp_backup_volume',
default='', default='',
help='Specify backup share name in case user wanted to backup ' help='Specify backup share name in case user wanted to backup '
'the share. Some case user has dedicated volume for backup' 'the share. Some case user has dedicated volume for backup'

View File

@ -3994,8 +3994,10 @@ SNAPMIRROR_GET_ITER_RESPONSE_REST = {
"name": "hourly", "name": "hourly",
}, },
"transfer": { "transfer": {
"state": "success" "state": "success",
} "bytes_transferred": "3352",
},
"last_transfer_type": "update",
} }
], ],
"num_records": 1, "num_records": 1,
@ -4012,7 +4014,10 @@ REST_GET_SNAPMIRRORS_RESPONSE = [{
'uuid': FAKE_UUID, 'uuid': FAKE_UUID,
'policy-type': 'async', 'policy-type': 'async',
'schedule': 'hourly', 'schedule': 'hourly',
'transferring-state': 'success' 'transferring-state': 'success',
'is-healthy': 'true',
'last-transfer-size': '3352',
'last-transfer-type': 'update',
}] }]
FAKE_CIFS_RECORDS = { FAKE_CIFS_RECORDS = {

View File

@ -2220,7 +2220,8 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
':' + fake.SM_DEST_VOLUME), ':' + fake.SM_DEST_VOLUME),
'fields': 'state,source.svm.name,source.path,destination.svm.name,' 'fields': 'state,source.svm.name,source.path,destination.svm.name,'
'destination.path,transfer.end_time,uuid,policy.type,' 'destination.path,transfer.end_time,uuid,policy.type,'
'transfer_schedule.name,transfer.state' 'transfer_schedule.name,transfer.state,'
'last_transfer_type,transfer.bytes_transferred,healthy'
} }
mock_send_request.assert_called_once_with('/snapmirror/relationships', mock_send_request.assert_called_once_with('/snapmirror/relationships',
@ -2252,7 +2253,8 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
':' + fake.SM_DEST_VOLUME), ':' + fake.SM_DEST_VOLUME),
'fields': 'state,source.svm.name,source.path,destination.svm.name,' 'fields': 'state,source.svm.name,source.path,destination.svm.name,'
'destination.path,transfer.end_time,uuid,policy.type,' 'destination.path,transfer.end_time,uuid,policy.type,'
'transfer_schedule.name,transfer.state' 'transfer_schedule.name,transfer.state,'
'last_transfer_type,transfer.bytes_transferred,healthy'
} }
mock_send_request.assert_called_once_with('/snapmirror/relationships', mock_send_request.assert_called_once_with('/snapmirror/relationships',
@ -2280,7 +2282,8 @@ class NetAppRestCmodeClientTestCase(test.TestCase):
':' + fake.SM_DEST_VOLUME), ':' + fake.SM_DEST_VOLUME),
'fields': 'state,source.svm.name,source.path,destination.svm.name,' 'fields': 'state,source.svm.name,source.path,destination.svm.name,'
'destination.path,transfer.end_time,uuid,policy.type,' 'destination.path,transfer.end_time,uuid,policy.type,'
'transfer_schedule.name,transfer.state' 'transfer_schedule.name,transfer.state,'
'last_transfer_type,transfer.bytes_transferred,healthy'
} }
mock_send_request.assert_called_once_with('/snapmirror/relationships', mock_send_request.assert_called_once_with('/snapmirror/relationships',

View File

@ -81,7 +81,7 @@ def _get_config():
CONF.set_override("netapp_backup_vserver", CONF.set_override("netapp_backup_vserver",
"fake_backup_share", "fake_backup_share",
group=backup_config) group=backup_config)
CONF.set_override("netapp_backup_share", CONF.set_override("netapp_backup_volume",
"fake_share_server", "fake_share_server",
group=backup_config) group=backup_config)
return config return config
@ -8023,7 +8023,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
backup_config = 'backup_config' backup_config = 'backup_config'
fake_config = configuration.Configuration(driver.share_opts, fake_config = configuration.Configuration(driver.share_opts,
config_group=backup_config) config_group=backup_config)
CONF.set_override("netapp_backup_share", "", CONF.set_override("netapp_backup_volume", "",
group=backup_config) group=backup_config)
CONF.set_override("netapp_backup_vserver", "", CONF.set_override("netapp_backup_vserver", "",
group=backup_config) group=backup_config)
@ -8045,7 +8045,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
backup_config = 'backup_config' backup_config = 'backup_config'
fake_config = configuration.Configuration(driver.share_opts, fake_config = configuration.Configuration(driver.share_opts,
config_group=backup_config) config_group=backup_config)
CONF.set_override("netapp_backup_share", "", CONF.set_override("netapp_backup_volume", "",
group=backup_config) group=backup_config)
CONF.set_override("netapp_backup_vserver", "", CONF.set_override("netapp_backup_vserver", "",
group=backup_config) group=backup_config)
@ -8240,7 +8240,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self._backup_mock_common_method(mock_des_vserver_client) self._backup_mock_common_method(mock_des_vserver_client)
backup_config = 'backup_config' backup_config = 'backup_config'
CONF.set_override("netapp_backup_share", "", CONF.set_override("netapp_backup_volume", "",
group=backup_config) group=backup_config)
CONF.set_override("netapp_backup_vserver", "", CONF.set_override("netapp_backup_vserver", "",
group=backup_config) group=backup_config)
@ -8469,6 +8469,48 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.SHARE_BACKUP, fake.SHARE_BACKUP,
) )
def test_create_backup_when_invalid_backup_type_negative(self):
mock_src_client = mock.Mock()
self.mock_object(self.library,
'_get_vserver',
mock.Mock(return_value=(fake.VSERVER1,
mock_src_client)))
self.mock_object(self.mock_dm_session,
'get_backup_configuration',
mock.Mock(
side_effect=exception.BadConfigurationException,
))
self.assertRaises(
exception.BadConfigurationException,
self.library.create_backup,
self.context,
fake.SHARE_INSTANCE,
fake.SHARE_BACKUP,
)
def test_create_backup_when_invalid_backend_negative(self):
mock_src_client = mock.Mock()
self.mock_object(self.library,
'_get_vserver',
mock.Mock(return_value=(fake.VSERVER1,
mock_src_client)))
self.mock_object(data_motion,
'get_backup_configuration',
mock.Mock(return_value=_get_config()))
self.mock_object(self.mock_dm_session,
'get_backend_configuration',
mock.Mock(
side_effect=exception.BadConfigurationException,
))
self.assertRaises(
exception.BadConfigurationException,
self.library.create_backup,
self.context,
fake.SHARE_INSTANCE,
fake.SHARE_BACKUP,
)
def test_create_backup_continue_with_status_inprogress(self): def test_create_backup_continue_with_status_inprogress(self):
vserver_client = mock.Mock() vserver_client = mock.Mock()
mock_dest_client = mock.Mock() mock_dest_client = mock.Mock()
@ -8578,6 +8620,60 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.SHARE_BACKUP, fake.SHARE_BACKUP,
) )
def test_create_backup_continue_snapshot_left_from_old_relationship(self):
vserver_client = mock.Mock()
mock_dest_client = mock.Mock()
self._backup_mock_common_method(mock_dest_client)
self.mock_object(self.library,
'_get_vserver',
mock.Mock(return_value=(fake.VSERVER1,
vserver_client)))
snapmirror_info = [fake.SNAP_MIRROR_INFO]
self.mock_object(mock_dest_client,
'get_snapmirrors',
mock.Mock(return_value=snapmirror_info))
snap_list = ["snap1", "snap2"]
self.mock_object(self.library,
'_get_des_volume_backup_snapshots',
mock.Mock(return_value=snap_list))
self.library._set_volume_has_backup_before(True)
share_instance = fake.SHARE_INSTANCE
backup = fake.SHARE_BACKUP
self.library.create_backup_continue(self.context, share_instance,
backup)
self.library._set_volume_has_backup_before(False)
def test_create_backup_continue_relationship_not_healthy_negative(self):
vserver_client = mock.Mock()
mock_dest_client = mock.Mock()
self._backup_mock_common_method(mock_dest_client)
self.mock_object(self.library,
'_get_vserver',
mock.Mock(return_value=(fake.VSERVER1,
vserver_client)))
snapmirror_info = [
{
'source-vserver': fake.VSERVER1,
'source-volume': fake.FLEXVOL_NAME,
'destination-vserver': fake.VSERVER2,
'destination-volume': fake.FLEXVOL_NAME_1,
'relationship-status': "idle",
'last-transfer-type': "update",
'is-healthy': "false",
}
]
self.mock_object(mock_dest_client,
'get_snapmirrors',
mock.Mock(return_value=snapmirror_info))
self.assertRaises(
exception.NetAppException,
self.library.create_backup_continue,
self.context,
fake.SHARE_INSTANCE,
fake.SHARE_BACKUP,
)
def test_restore_backup_with_vserver_volume_none(self): def test_restore_backup_with_vserver_volume_none(self):
vserver_client = mock.Mock() vserver_client = mock.Mock()
self.mock_object(self.library, self.mock_object(self.library,
@ -8727,6 +8823,27 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
fake.SHARE_BACKUP, fake.SHARE_BACKUP,
) )
def test_delete_backup_snapshot_not_exist(self):
vserver_client = mock.Mock()
mock_des_client = mock.Mock()
self._backup_mock_common_method(mock_des_client)
self._backup_mock_common_method_for_negative(vserver_client,
mock_des_client)
self.mock_object(self.library,
'_get_des_volume_backup_snapshots',
mock.Mock(return_value=['fake_snapshot1',
'fake_snapshot2']))
self.mock_object(self.library,
'_is_snapshot_deleted',
mock.Mock(return_value=True))
msg = "entry doesn't exist"
self.mock_object(mock_des_client,
'delete_snapshot',
mock.Mock(side_effect=netapp_api.NaApiError(
message=msg)))
self.library.delete_backup(self.context, fake.SHARE_BACKUP,
fake.SHARE_INSTANCE)
def test__get_backup_progress_status(self): def test__get_backup_progress_status(self):
mock_dest_client = mock.Mock() mock_dest_client = mock.Mock()
vol_attr = {'name': 'fake_vol', 'size-used': '123454'} vol_attr = {'name': 'fake_vol', 'size-used': '123454'}

View File

@ -0,0 +1,9 @@
---
fixes:
- |
NetApp driver `bug #2058027
<https://bugs.launchpad.net/manila/+bug/2058027>`_:
Fix the issue for NetApp driver for backup feature. Backup status
update used to fail when administrator misconfigured backup settings
configuration or SnapMirror relationship created during backup
creation was not in healthy state.