Browse Source

Merge "Support getting backups of a specific project"

tags/14.0.0.0rc1
Zuul 2 weeks ago
committed by Gerrit Code Review
parent
commit
2cd5bb6f83
5 changed files with 78 additions and 4 deletions
  1. +2
    -0
      api-ref/source/backups.inc
  2. +3
    -0
      releasenotes/notes/victoria-list-project-backups.yaml
  3. +5
    -2
      trove/backup/models.py
  4. +3
    -1
      trove/backup/service.py
  5. +65
    -1
      trove/tests/unittests/backup/test_backup_controller.py

+ 2
- 0
api-ref/source/backups.inc View File

@@ -20,6 +20,8 @@ using query string parameters. The following filters are supported:
- ``all_projects=True/False`` - Return the list of backups for all the
projects, this is an admin only param by default.
- ``datastore={datastore}`` - Return a list of backups of the same datastore.
- ``project_id={project_id}`` - Get backups of a specific project. Admin
required.

Normal response codes: 200



+ 3
- 0
releasenotes/notes/victoria-list-project-backups.yaml View File

@@ -0,0 +1,3 @@
---
features:
- The admin user is able to get backups of a specific project.

+ 5
- 2
trove/backup/models.py View File

@@ -186,13 +186,16 @@ class Backup(object):
return query.all(), marker

@classmethod
def list(cls, context, datastore=None, instance_id=None,
def list(cls, context, datastore=None, instance_id=None, project_id=None,
all_projects=False):
query = DBBackup.query()
filters = [DBBackup.deleted == 0]

if not all_projects:
if project_id:
filters.append(DBBackup.tenant_id == project_id)
elif not all_projects:
filters.append(DBBackup.tenant_id == context.project_id)

if instance_id:
filters.append(DBBackup.instance_id == instance_id)



+ 3
- 1
trove/backup/service.py View File

@@ -44,10 +44,11 @@ class BackupController(wsgi.Controller):
LOG.debug("Listing backups for tenant %s", tenant_id)
datastore = req.GET.get('datastore')
instance_id = req.GET.get('instance_id')
project_id = req.GET.get('project_id')
all_projects = strutils.bool_from_string(req.GET.get('all_projects'))
context = req.environ[wsgi.CONTEXT_KEY]

if all_projects:
if project_id or all_projects:
policy.authorize_on_tenant(context, 'backup:index:all_projects')
else:
policy.authorize_on_tenant(context, 'backup:index')
@@ -56,6 +57,7 @@ class BackupController(wsgi.Controller):
context,
datastore=datastore,
instance_id=instance_id,
project_id=project_id,
all_projects=all_projects
)
view = views.BackupViews(backups)


+ 65
- 1
trove/tests/unittests/backup/test_backup_controller.py View File

@@ -13,20 +13,36 @@
# License for the specific language governing permissions and limitations
# under the License.
#
from unittest import mock
import uuid

import jsonschema
from testtools.matchers import Equals

from trove.backup import models
from trove.backup import state
from trove.backup.service import BackupController
from trove.common import apischema
from trove.common import context
from trove.common import wsgi
from trove.tests.unittests import trove_testtools
from trove.tests.unittests.util import util


class TestBackupController(trove_testtools.TestCase):

def setUp(self):
super(TestBackupController, self).setUp()
self.uuid = "d6338c9c-3cc8-4313-b98f-13cc0684cf15"
self.invalid_uuid = "ead-edsa-e23-sdf-23"
self.controller = BackupController()
self.context = context.TroveContext(project_id=str(uuid.uuid4()))
util.init_db()

def tearDown(self):
super(TestBackupController, self).tearDown()
backups = models.DBBackup.find_all(tenant_id=self.context.project_id)
for backup in backups:
backup.delete()

def test_validate_create_complete(self):
body = {"backup": {"instance": self.uuid,
@@ -87,3 +103,51 @@ class TestBackupController(trove_testtools.TestCase):
self.assertThat(errors[0].message,
Equals("'%s' does not match '%s'" %
(self.invalid_uuid, apischema.uuid['pattern'])))

def test_list_by_project(self):
req = mock.MagicMock(GET={'project_id': self.context.project_id},
environ={wsgi.CONTEXT_KEY: self.context},
url='http://localhost')
instance_id = str(uuid.uuid4())
backup_name = str(uuid.uuid4())
location = 'https://object-storage.com/tenant/database_backups/backup'
models.DBBackup.create(tenant_id=self.context.project_id,
name=backup_name,
state=state.BackupState.NEW,
instance_id=instance_id,
deleted=False,
size=2.0,
location=location)

res = self.controller.index(req, 'fake_tenant_id')

self.assertEqual(200, res.status)
backups = res.data(None)['backups']
self.assertGreaterEqual(len(backups), 1)
our_backup = None
for backup in backups:
if backup['name'] == backup_name:
our_backup = backup
break
self.assertIsNotNone(our_backup)
expected = {
'name': backup_name,
'locationRef': location,
'instance_id': instance_id,
'size': 2.0,
'status': 'NEW',
}
self.assertTrue(
set(expected.items()).issubset(set(our_backup.items()))
)

# Get backups of unknown project
req = mock.MagicMock(GET={'project_id': str(uuid.uuid4())},
environ={wsgi.CONTEXT_KEY: self.context},
url='http://localhost')

res = self.controller.index(req, 'fake_tenant_id')

self.assertEqual(200, res.status)
backups = res.data(None)['backups']
self.assertEqual(0, len(backups))

Loading…
Cancel
Save