Merge "volume-backup add incremental flag"
This commit is contained in:
commit
34b2e82343
@ -585,8 +585,9 @@ def volume_backup_get(request, backup_id):
|
|||||||
return VolumeBackup(backup)
|
return VolumeBackup(backup)
|
||||||
|
|
||||||
|
|
||||||
def volume_backup_list(request):
|
def volume_backup_list(request, search_opts=None):
|
||||||
backups, _, __ = volume_backup_list_paged(request, paginate=False)
|
backups, _, __ = volume_backup_list_paged(request, paginate=False,
|
||||||
|
search_opts=search_opts)
|
||||||
return backups
|
return backups
|
||||||
|
|
||||||
|
|
||||||
@ -625,7 +626,7 @@ def volume_backup_list_paged_with_page_menu(request, page_number=1,
|
|||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def volume_backup_list_paged(request, marker=None, paginate=False,
|
def volume_backup_list_paged(request, marker=None, paginate=False,
|
||||||
sort_dir="desc"):
|
sort_dir="desc", search_opts=None):
|
||||||
has_more_data = False
|
has_more_data = False
|
||||||
has_prev_data = False
|
has_prev_data = False
|
||||||
backups = []
|
backups = []
|
||||||
@ -642,13 +643,13 @@ def volume_backup_list_paged(request, marker=None, paginate=False,
|
|||||||
sort = 'created_at:' + sort_dir
|
sort = 'created_at:' + sort_dir
|
||||||
for b in c_client.backups.list(limit=page_size + 1,
|
for b in c_client.backups.list(limit=page_size + 1,
|
||||||
marker=marker,
|
marker=marker,
|
||||||
sort=sort):
|
sort=sort, search_opts=search_opts):
|
||||||
backups.append(VolumeBackup(b))
|
backups.append(VolumeBackup(b))
|
||||||
|
|
||||||
backups, has_more_data, has_prev_data = update_pagination(
|
backups, has_more_data, has_prev_data = update_pagination(
|
||||||
backups, page_size, marker, sort_dir)
|
backups, page_size, marker, sort_dir)
|
||||||
else:
|
else:
|
||||||
for b in c_client.backups.list():
|
for b in c_client.backups.list(search_opts=search_opts):
|
||||||
backups.append(VolumeBackup(b))
|
backups.append(VolumeBackup(b))
|
||||||
|
|
||||||
return backups, has_more_data, has_prev_data
|
return backups, has_more_data, has_prev_data
|
||||||
@ -661,6 +662,7 @@ def volume_backup_create(request,
|
|||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
force=False,
|
force=False,
|
||||||
|
incremental=False,
|
||||||
snapshot_id=None):
|
snapshot_id=None):
|
||||||
# need to ensure the container name is not an empty
|
# need to ensure the container name is not an empty
|
||||||
# string, but pass None to get the container name
|
# string, but pass None to get the container name
|
||||||
@ -671,6 +673,7 @@ def volume_backup_create(request,
|
|||||||
name=name,
|
name=name,
|
||||||
description=description,
|
description=description,
|
||||||
snapshot_id=snapshot_id,
|
snapshot_id=snapshot_id,
|
||||||
|
incremental=incremental,
|
||||||
force=force)
|
force=force)
|
||||||
return VolumeBackup(backup)
|
return VolumeBackup(backup)
|
||||||
|
|
||||||
|
@ -42,9 +42,30 @@ class CreateBackupForm(forms.SelfHandlingForm):
|
|||||||
volume_id = forms.CharField(widget=forms.HiddenInput())
|
volume_id = forms.CharField(widget=forms.HiddenInput())
|
||||||
snapshot_id = forms.ThemableChoiceField(label=_("Backup Snapshot"),
|
snapshot_id = forms.ThemableChoiceField(label=_("Backup Snapshot"),
|
||||||
required=False)
|
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):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super().__init__(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'):
|
if kwargs['initial'].get('snapshot_id'):
|
||||||
snap_id = kwargs['initial']['snapshot_id']
|
snap_id = kwargs['initial']['snapshot_id']
|
||||||
try:
|
try:
|
||||||
@ -84,12 +105,14 @@ class CreateBackupForm(forms.SelfHandlingForm):
|
|||||||
volume = api.cinder.volume_get(request, data['volume_id'])
|
volume = api.cinder.volume_get(request, data['volume_id'])
|
||||||
snapshot_id = data['snapshot_id'] or None
|
snapshot_id = data['snapshot_id'] or None
|
||||||
force = False
|
force = False
|
||||||
|
incremental = data.get('incremental', False)
|
||||||
if volume.status == 'in-use':
|
if volume.status == 'in-use':
|
||||||
force = True
|
force = True
|
||||||
backup = api.cinder.volume_backup_create(
|
backup = api.cinder.volume_backup_create(
|
||||||
request, data['volume_id'],
|
request, data['volume_id'],
|
||||||
data['container_name'], data['name'],
|
data['container_name'], data['name'],
|
||||||
data['description'], force=force,
|
data['description'], force=force,
|
||||||
|
incremental=incremental,
|
||||||
snapshot_id=snapshot_id
|
snapshot_id=snapshot_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -134,11 +134,13 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
self.assertCountEqual(result, expected_backups)
|
self.assertCountEqual(result, expected_backups)
|
||||||
|
|
||||||
@test.create_mocks({api.cinder: ('volume_backup_create',
|
@test.create_mocks({api.cinder: ('volume_backup_create',
|
||||||
|
'volume_backup_list',
|
||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
'volume_get')})
|
'volume_get')})
|
||||||
def test_create_backup_available(self):
|
def test_create_backup_available(self):
|
||||||
volume = self.cinder_volumes.first()
|
volume = self.cinder_volumes.first()
|
||||||
backup = self.cinder_volume_backups.first()
|
backup = self.cinder_volume_backups.first()
|
||||||
|
self.mock_volume_backup_list.return_value = []
|
||||||
|
|
||||||
self.mock_volume_get.return_value = volume
|
self.mock_volume_get.return_value = volume
|
||||||
self.mock_volume_backup_create.return_value = backup
|
self.mock_volume_backup_create.return_value = backup
|
||||||
@ -168,17 +170,61 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
backup.name,
|
backup.name,
|
||||||
backup.description,
|
backup.description,
|
||||||
force=False,
|
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)
|
snapshot_id=None)
|
||||||
|
|
||||||
@test.create_mocks(
|
@test.create_mocks(
|
||||||
{api.cinder: ('volume_backup_create', 'volume_snapshot_get',
|
{api.cinder: ('volume_backup_create', 'volume_snapshot_get',
|
||||||
'volume_get')})
|
'volume_get', 'volume_backup_list')})
|
||||||
def test_create_backup_from_snapshot_table(self):
|
def test_create_backup_from_snapshot_table(self):
|
||||||
backup = self.cinder_volume_backups.list()[1]
|
backup = self.cinder_volume_backups.list()[1]
|
||||||
volume = self.cinder_volumes.list()[4]
|
volume = self.cinder_volumes.list()[4]
|
||||||
snapshot = self.cinder_volume_snapshots.list()[1]
|
snapshot = self.cinder_volume_snapshots.list()[1]
|
||||||
self.mock_volume_backup_create.return_value = backup
|
self.mock_volume_backup_create.return_value = backup
|
||||||
self.mock_volume_get.return_value = volume
|
self.mock_volume_get.return_value = volume
|
||||||
|
self.mock_volume_backup_list.return_value = []
|
||||||
self.mock_volume_snapshot_get.return_value = snapshot
|
self.mock_volume_snapshot_get.return_value = snapshot
|
||||||
formData = {'method': 'CreateBackupForm',
|
formData = {'method': 'CreateBackupForm',
|
||||||
'tenant_id': self.tenant.id,
|
'tenant_id': self.tenant.id,
|
||||||
@ -204,18 +250,20 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
backup.name,
|
backup.name,
|
||||||
backup.description,
|
backup.description,
|
||||||
force=False,
|
force=False,
|
||||||
|
incremental=False,
|
||||||
snapshot_id=backup.snapshot_id)
|
snapshot_id=backup.snapshot_id)
|
||||||
|
|
||||||
@test.create_mocks(
|
@test.create_mocks(
|
||||||
{api.cinder: ('volume_backup_create',
|
{api.cinder: ('volume_backup_create',
|
||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
'volume_get')})
|
'volume_get', 'volume_backup_list')})
|
||||||
def test_create_backup_from_snapshot_volume_table(self):
|
def test_create_backup_from_snapshot_volume_table(self):
|
||||||
volume = self.cinder_volumes.list()[4]
|
volume = self.cinder_volumes.list()[4]
|
||||||
backup = self.cinder_volume_backups.list()[1]
|
backup = self.cinder_volume_backups.list()[1]
|
||||||
snapshots = self.cinder_volume_snapshots.list()[1:3]
|
snapshots = self.cinder_volume_snapshots.list()[1:3]
|
||||||
self.mock_volume_backup_create.return_value = backup
|
self.mock_volume_backup_create.return_value = backup
|
||||||
self.mock_volume_get.return_value = volume
|
self.mock_volume_get.return_value = volume
|
||||||
|
self.mock_volume_backup_list.return_value = []
|
||||||
self.mock_volume_snapshot_list.return_value = snapshots
|
self.mock_volume_snapshot_list.return_value = snapshots
|
||||||
formData = {'method': 'CreateBackupForm',
|
formData = {'method': 'CreateBackupForm',
|
||||||
'tenant_id': self.tenant.id,
|
'tenant_id': self.tenant.id,
|
||||||
@ -244,11 +292,12 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
backup.name,
|
backup.name,
|
||||||
backup.description,
|
backup.description,
|
||||||
force=False,
|
force=False,
|
||||||
|
incremental=False,
|
||||||
snapshot_id=backup.snapshot_id)
|
snapshot_id=backup.snapshot_id)
|
||||||
|
|
||||||
@test.create_mocks(
|
@test.create_mocks(
|
||||||
{api.cinder: ('volume_backup_create', 'volume_snapshot_list',
|
{api.cinder: ('volume_backup_create', 'volume_snapshot_list',
|
||||||
'volume_get')})
|
'volume_get', 'volume_backup_list')})
|
||||||
def test_create_backup_in_use(self):
|
def test_create_backup_in_use(self):
|
||||||
# The third volume in the cinder test volume data is in-use
|
# The third volume in the cinder test volume data is in-use
|
||||||
volume = self.cinder_volumes.list()[2]
|
volume = self.cinder_volumes.list()[2]
|
||||||
@ -258,6 +307,7 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
self.mock_volume_get.return_value = volume
|
self.mock_volume_get.return_value = volume
|
||||||
self.mock_volume_backup_create.return_value = backup
|
self.mock_volume_backup_create.return_value = backup
|
||||||
self.mock_volume_snapshot_list.return_value = snapshots
|
self.mock_volume_snapshot_list.return_value = snapshots
|
||||||
|
self.mock_volume_backup_list.return_value = []
|
||||||
formData = {'method': 'CreateBackupForm',
|
formData = {'method': 'CreateBackupForm',
|
||||||
'tenant_id': self.tenant.id,
|
'tenant_id': self.tenant.id,
|
||||||
'volume_id': volume.id,
|
'volume_id': volume.id,
|
||||||
@ -283,7 +333,92 @@ class VolumeBackupsViewTests(test.TestCase):
|
|||||||
backup.name,
|
backup.name,
|
||||||
backup.description,
|
backup.description,
|
||||||
force=True,
|
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',
|
@test.create_mocks({api.cinder: ('volume_list',
|
||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user