Merge "volume-backup add incremental flag"

This commit is contained in:
Zuul 2022-09-20 06:43:09 +00:00 committed by Gerrit Code Review
commit 34b2e82343
3 changed files with 170 additions and 9 deletions

View File

@ -585,8 +585,9 @@ def volume_backup_get(request, backup_id):
return VolumeBackup(backup)
def volume_backup_list(request):
backups, _, __ = volume_backup_list_paged(request, paginate=False)
def volume_backup_list(request, search_opts=None):
backups, _, __ = volume_backup_list_paged(request, paginate=False,
search_opts=search_opts)
return backups
@ -625,7 +626,7 @@ def volume_backup_list_paged_with_page_menu(request, page_number=1,
@profiler.trace
def volume_backup_list_paged(request, marker=None, paginate=False,
sort_dir="desc"):
sort_dir="desc", search_opts=None):
has_more_data = False
has_prev_data = False
backups = []
@ -642,13 +643,13 @@ def volume_backup_list_paged(request, marker=None, paginate=False,
sort = 'created_at:' + sort_dir
for b in c_client.backups.list(limit=page_size + 1,
marker=marker,
sort=sort):
sort=sort, search_opts=search_opts):
backups.append(VolumeBackup(b))
backups, has_more_data, has_prev_data = update_pagination(
backups, page_size, marker, sort_dir)
else:
for b in c_client.backups.list():
for b in c_client.backups.list(search_opts=search_opts):
backups.append(VolumeBackup(b))
return backups, has_more_data, has_prev_data
@ -661,6 +662,7 @@ def volume_backup_create(request,
name,
description,
force=False,
incremental=False,
snapshot_id=None):
# need to ensure the container name is not an empty
# string, but pass None to get the container name
@ -671,6 +673,7 @@ def volume_backup_create(request,
name=name,
description=description,
snapshot_id=snapshot_id,
incremental=incremental,
force=force)
return VolumeBackup(backup)

View File

@ -42,9 +42,30 @@ class CreateBackupForm(forms.SelfHandlingForm):
volume_id = forms.CharField(widget=forms.HiddenInput())
snapshot_id = forms.ThemableChoiceField(label=_("Backup Snapshot"),
required=False)
incremental = forms.BooleanField(
label=_("Incremental"),
required=False,
help_text=_("By default, a backup is created as a full backup. "
"Check this to do an incremental backup from latest "
"backup. Only available if a prior backup exists."))
def __init__(self, request, *args, **kwargs):
super().__init__(request, *args, **kwargs)
search_opts = {"volume_id": kwargs['initial']['volume_id'],
"status": "available"}
try:
if not api.cinder.volume_backup_list(request,
search_opts=search_opts):
self.fields.pop('incremental')
except Exception:
# Do not include incremental if list of prior backups fails
self.fields.pop('incremental')
msg = _('Unable to retrieve volume backup list '
'for volume "%s", so incremental '
'backup is disabled.') % search_opts['volume_id']
exceptions.handle(self.request, msg)
if kwargs['initial'].get('snapshot_id'):
snap_id = kwargs['initial']['snapshot_id']
try:
@ -84,12 +105,14 @@ class CreateBackupForm(forms.SelfHandlingForm):
volume = api.cinder.volume_get(request, data['volume_id'])
snapshot_id = data['snapshot_id'] or None
force = False
incremental = data.get('incremental', False)
if volume.status == 'in-use':
force = True
backup = api.cinder.volume_backup_create(
request, data['volume_id'],
data['container_name'], data['name'],
data['description'], force=force,
incremental=incremental,
snapshot_id=snapshot_id
)

View File

@ -134,11 +134,13 @@ class VolumeBackupsViewTests(test.TestCase):
self.assertCountEqual(result, expected_backups)
@test.create_mocks({api.cinder: ('volume_backup_create',
'volume_backup_list',
'volume_snapshot_list',
'volume_get')})
def test_create_backup_available(self):
volume = self.cinder_volumes.first()
backup = self.cinder_volume_backups.first()
self.mock_volume_backup_list.return_value = []
self.mock_volume_get.return_value = volume
self.mock_volume_backup_create.return_value = backup
@ -168,17 +170,61 @@ class VolumeBackupsViewTests(test.TestCase):
backup.name,
backup.description,
force=False,
incremental=False,
snapshot_id=None)
@test.create_mocks({api.cinder: ('volume_backup_create',
'volume_backup_list',
'volume_snapshot_list',
'volume_get')})
def test_create_backup_available_incremental(self):
volume = self.cinder_volumes.first()
backup = self.cinder_volume_backups.list()[1]
prior_backups = [self.cinder_volume_backups.list()[0]]
self.mock_volume_backup_list.return_value = prior_backups
self.mock_volume_get.return_value = volume
self.mock_volume_backup_create.return_value = backup
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
'container_name': backup.container_name,
'name': backup.name,
'incremental': True,
'description': backup.description}
url = reverse('horizon:project:volumes:create_backup',
args=[volume.id])
res = self.client.post(url, formData)
self.assertNoFormErrors(res)
self.assertMessageCount(error=0, warning=0)
self.assertRedirectsNoFollow(res, INDEX_URL)
self.mock_volume_snapshot_list.assert_called_once_with(
test.IsHttpRequest(),
search_opts={'volume_id': volume.id})
self.mock_volume_get.assert_called_once_with(test.IsHttpRequest(),
volume.id)
self.mock_volume_backup_create.assert_called_once_with(
test.IsHttpRequest(),
volume.id,
backup.container_name,
backup.name,
backup.description,
force=False,
incremental=True,
snapshot_id=None)
@test.create_mocks(
{api.cinder: ('volume_backup_create', 'volume_snapshot_get',
'volume_get')})
'volume_get', 'volume_backup_list')})
def test_create_backup_from_snapshot_table(self):
backup = self.cinder_volume_backups.list()[1]
volume = self.cinder_volumes.list()[4]
snapshot = self.cinder_volume_snapshots.list()[1]
self.mock_volume_backup_create.return_value = backup
self.mock_volume_get.return_value = volume
self.mock_volume_backup_list.return_value = []
self.mock_volume_snapshot_get.return_value = snapshot
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
@ -204,18 +250,20 @@ class VolumeBackupsViewTests(test.TestCase):
backup.name,
backup.description,
force=False,
incremental=False,
snapshot_id=backup.snapshot_id)
@test.create_mocks(
{api.cinder: ('volume_backup_create',
'volume_snapshot_list',
'volume_get')})
'volume_get', 'volume_backup_list')})
def test_create_backup_from_snapshot_volume_table(self):
volume = self.cinder_volumes.list()[4]
backup = self.cinder_volume_backups.list()[1]
snapshots = self.cinder_volume_snapshots.list()[1:3]
self.mock_volume_backup_create.return_value = backup
self.mock_volume_get.return_value = volume
self.mock_volume_backup_list.return_value = []
self.mock_volume_snapshot_list.return_value = snapshots
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
@ -244,11 +292,12 @@ class VolumeBackupsViewTests(test.TestCase):
backup.name,
backup.description,
force=False,
incremental=False,
snapshot_id=backup.snapshot_id)
@test.create_mocks(
{api.cinder: ('volume_backup_create', 'volume_snapshot_list',
'volume_get')})
'volume_get', 'volume_backup_list')})
def test_create_backup_in_use(self):
# The third volume in the cinder test volume data is in-use
volume = self.cinder_volumes.list()[2]
@ -258,6 +307,7 @@ class VolumeBackupsViewTests(test.TestCase):
self.mock_volume_get.return_value = volume
self.mock_volume_backup_create.return_value = backup
self.mock_volume_snapshot_list.return_value = snapshots
self.mock_volume_backup_list.return_value = []
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
@ -283,7 +333,92 @@ class VolumeBackupsViewTests(test.TestCase):
backup.name,
backup.description,
force=True,
snapshot_id=None)
snapshot_id=None,
incremental=False)
@test.create_mocks(
{api.cinder: ('volume_backup_create', 'volume_snapshot_list',
'volume_get', 'volume_backup_list')})
def test_create_backup_in_use_incremental(self):
volume = self.cinder_volumes.list()[2]
backup = self.cinder_volume_backups.list()[1]
snapshots = []
self.mock_volume_get.return_value = volume
self.mock_volume_backup_create.return_value = backup
self.mock_volume_snapshot_list.return_value = snapshots
prior_backups = [self.cinder_volume_backups.list()[0]]
self.mock_volume_backup_list.return_value = prior_backups
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
'container_name': backup.container_name,
'name': backup.name,
'incremental': True,
'description': backup.description}
url = reverse('horizon:project:volumes:create_backup',
args=[volume.id])
res = self.client.post(url, formData)
self.mock_volume_snapshot_list.assert_called_once_with(
test.IsHttpRequest(),
search_opts={'volume_id': volume.id})
self.assertNoFormErrors(res)
self.assertMessageCount(error=0, warning=0)
self.assertRedirectsNoFollow(res, INDEX_URL)
self.mock_volume_get.assert_called_once_with(test.IsHttpRequest(),
volume.id)
self.mock_volume_backup_create.assert_called_once_with(
test.IsHttpRequest(),
volume.id,
backup.container_name,
backup.name,
backup.description,
force=True,
snapshot_id=None,
incremental=True)
@test.create_mocks(
{api.cinder: ('volume_backup_create', 'volume_snapshot_list',
'volume_get', 'volume_backup_list')})
def test_create_backup_in_use_incremental_set_false(self):
volume = self.cinder_volumes.list()[2]
backup = self.cinder_volume_backups.list()[1]
snapshots = []
self.mock_volume_get.return_value = volume
self.mock_volume_backup_create.return_value = backup
self.mock_volume_snapshot_list.return_value = snapshots
prior_backups = [self.cinder_volume_backups.list()[0]]
self.mock_volume_backup_list.return_value = prior_backups
formData = {'method': 'CreateBackupForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
'container_name': backup.container_name,
'name': backup.name,
'incremental': False,
'description': backup.description}
url = reverse('horizon:project:volumes:create_backup',
args=[volume.id])
res = self.client.post(url, formData)
self.mock_volume_snapshot_list.assert_called_once_with(
test.IsHttpRequest(),
search_opts={'volume_id': volume.id})
self.assertNoFormErrors(res)
self.assertMessageCount(error=0, warning=0)
self.assertRedirectsNoFollow(res, INDEX_URL)
self.mock_volume_get.assert_called_once_with(test.IsHttpRequest(),
volume.id)
self.mock_volume_backup_create.assert_called_once_with(
test.IsHttpRequest(),
volume.id,
backup.container_name,
backup.name,
backup.description,
force=True,
snapshot_id=None,
incremental=False)
@test.create_mocks({api.cinder: ('volume_list',
'volume_snapshot_list',