Add resource provider objects
Spec: https://review.openstack.org/#/c/427007/ Change-Id: Iadeb659e6f778f480a99b0bd7d418dc044d236cd Implements: blueprint expose-host-capabilities
This commit is contained in:
parent
18f9225ae8
commit
0398d43837
@ -13,12 +13,17 @@
|
||||
|
||||
from zun.objects import container
|
||||
from zun.objects import image
|
||||
from zun.objects import resource_provider
|
||||
from zun.objects import zun_service
|
||||
|
||||
Container = container.Container
|
||||
ZunService = zun_service.ZunService
|
||||
Image = image.Image
|
||||
ResourceProvider = resource_provider.ResourceProvider
|
||||
|
||||
__all__ = (Container,
|
||||
__all__ = (
|
||||
Container,
|
||||
ZunService,
|
||||
Image)
|
||||
Image,
|
||||
ResourceProvider,
|
||||
)
|
||||
|
161
zun/objects/resource_provider.py
Normal file
161
zun/objects/resource_provider.py
Normal file
@ -0,0 +1,161 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
from zun.db import api as dbapi
|
||||
from zun.objects import base
|
||||
|
||||
|
||||
@base.ZunObjectRegistry.register
|
||||
class ResourceProvider(base.ZunPersistentObject, base.ZunObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(read_only=True),
|
||||
'uuid': fields.UUIDField(nullable=False),
|
||||
'name': fields.StringField(nullable=False),
|
||||
'root_provider': fields.UUIDField(nullable=False),
|
||||
'parent_provider': fields.UUIDField(nullable=True),
|
||||
'can_host': fields.IntegerField(default=0),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(provider, db_provider):
|
||||
"""Converts a database entity to a formal object."""
|
||||
for field in provider.fields:
|
||||
setattr(provider, field, db_provider[field])
|
||||
|
||||
provider.obj_reset_changes()
|
||||
return provider
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object_list(db_objects, cls, context):
|
||||
"""Converts a list of database entities to a list of formal objects."""
|
||||
return [ResourceProvider._from_db_object(cls(context), obj)
|
||||
for obj in db_objects]
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_uuid(cls, context, uuid):
|
||||
"""Find a resource provider based on uuid.
|
||||
|
||||
:param uuid: the uuid of a resource provider.
|
||||
:param context: Security context
|
||||
:returns: a :class:`ResourceProvider` object.
|
||||
"""
|
||||
db_provider = dbapi.get_resource_provider(context, uuid)
|
||||
provider = ResourceProvider._from_db_object(cls(context), db_provider)
|
||||
return provider
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_name(cls, context, name):
|
||||
"""Find a resource provider based on name.
|
||||
|
||||
:param name: the logical name of a resource provider.
|
||||
:param context: Security context
|
||||
:returns: a :class:`ResourceProvider` object.
|
||||
"""
|
||||
db_provider = dbapi.get_resource_provider(context, name)
|
||||
provider = ResourceProvider._from_db_object(cls(context), db_provider)
|
||||
return provider
|
||||
|
||||
@base.remotable_classmethod
|
||||
def list(cls, context, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None, filters=None):
|
||||
"""Return a list of ResourceProvider objects.
|
||||
|
||||
:param context: Security context.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param sort_key: column to sort results by.
|
||||
:param sort_dir: direction to sort. "asc" or "desc".
|
||||
:param filters: filters when list resource providers.
|
||||
:returns: a list of :class:`ResourceProvider` object.
|
||||
|
||||
"""
|
||||
db_providers = dbapi.list_resource_providers(
|
||||
context, limit=limit, marker=marker, sort_key=sort_key,
|
||||
sort_dir=sort_dir, filters=filters)
|
||||
return ResourceProvider._from_db_object_list(
|
||||
db_providers, cls, context)
|
||||
|
||||
@base.remotable
|
||||
def create(self, context):
|
||||
"""Create a ResourceProvider record in the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ResourceProvider(context)
|
||||
|
||||
"""
|
||||
values = self.obj_get_changes()
|
||||
db_provider = dbapi.create_resource_provider(context, values)
|
||||
self._from_db_object(self, db_provider)
|
||||
|
||||
@base.remotable
|
||||
def destroy(self, context=None):
|
||||
"""Delete the ResourceProvider from the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ResourceProvider(context)
|
||||
"""
|
||||
dbapi.destroy_resource_provider(context, self.uuid)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def save(self, context=None):
|
||||
"""Save updates to this ResourceProvider.
|
||||
|
||||
Updates will be made column by column based on the result
|
||||
of self.what_changed().
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ResourceProvider(context)
|
||||
"""
|
||||
updates = self.obj_get_changes()
|
||||
dbapi.update_resource_provider(context, self.uuid, updates)
|
||||
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def refresh(self, context=None):
|
||||
"""Loads updates for this ResourceProvider.
|
||||
|
||||
Loads a resource provider with the same uuid from the database and
|
||||
checks for updated attributes. Updates are applied from
|
||||
the loaded resource provider column by column, if there are any
|
||||
updates.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: ResourceProvider(context)
|
||||
"""
|
||||
current = self.__class__.get_by_uuid(self._context, uuid=self.uuid)
|
||||
for field in self.fields:
|
||||
if self.obj_attr_is_set(field) and \
|
||||
getattr(self, field) != getattr(current, field):
|
||||
setattr(self, field, getattr(current, field))
|
137
zun/tests/unit/objects/test_resource_provider.py
Normal file
137
zun/tests/unit/objects/test_resource_provider.py
Normal file
@ -0,0 +1,137 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
from testtools.matchers import HasLength
|
||||
|
||||
from zun import objects
|
||||
from zun.tests.unit.db import base
|
||||
from zun.tests.unit.db import utils
|
||||
|
||||
|
||||
class TestResourceProviderObject(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestResourceProviderObject, self).setUp()
|
||||
self.fake_provider = utils.get_test_resource_provider()
|
||||
|
||||
def test_get_by_uuid(self):
|
||||
uuid = self.fake_provider['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_resource_provider',
|
||||
autospec=True) as mock_get_resource_provider:
|
||||
mock_get_resource_provider.return_value = self.fake_provider
|
||||
provider = objects.ResourceProvider.get_by_uuid(self.context, uuid)
|
||||
mock_get_resource_provider.assert_called_once_with(
|
||||
self.context, uuid)
|
||||
self.assertEqual(self.context, provider._context)
|
||||
|
||||
def test_get_by_name(self):
|
||||
name = self.fake_provider['name']
|
||||
with mock.patch.object(self.dbapi, 'get_resource_provider',
|
||||
autospec=True) as mock_get_resource_provider:
|
||||
mock_get_resource_provider.return_value = self.fake_provider
|
||||
provider = objects.ResourceProvider.get_by_name(self.context, name)
|
||||
mock_get_resource_provider.assert_called_once_with(
|
||||
self.context, name)
|
||||
self.assertEqual(self.context, provider._context)
|
||||
|
||||
def test_list(self):
|
||||
with mock.patch.object(self.dbapi, 'list_resource_providers',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_provider]
|
||||
providers = objects.ResourceProvider.list(self.context)
|
||||
self.assertEqual(1, mock_get_list.call_count)
|
||||
self.assertThat(providers, HasLength(1))
|
||||
self.assertIsInstance(providers[0], objects.ResourceProvider)
|
||||
self.assertEqual(self.context, providers[0]._context)
|
||||
|
||||
def test_list_with_filters(self):
|
||||
with mock.patch.object(self.dbapi, 'list_resource_providers',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_provider]
|
||||
filt = {'name': 'testprovider'}
|
||||
providers = objects.ResourceProvider.list(
|
||||
self.context, filters=filt)
|
||||
self.assertEqual(1, mock_get_list.call_count)
|
||||
self.assertThat(providers, HasLength(1))
|
||||
self.assertIsInstance(providers[0], objects.ResourceProvider)
|
||||
self.assertEqual(self.context, providers[0]._context)
|
||||
mock_get_list.assert_called_once_with(
|
||||
self.context, filters=filt, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None)
|
||||
|
||||
def test_create(self):
|
||||
with mock.patch.object(self.dbapi, 'create_resource_provider',
|
||||
autospec=True) as mock_create:
|
||||
mock_create.return_value = self.fake_provider
|
||||
provider = objects.ResourceProvider(
|
||||
self.context, **self.fake_provider)
|
||||
provider.create(self.context)
|
||||
mock_create.assert_called_once_with(
|
||||
self.context, self.fake_provider)
|
||||
self.assertEqual(self.context, provider._context)
|
||||
|
||||
def test_destroy(self):
|
||||
uuid = self.fake_provider['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_resource_provider',
|
||||
autospec=True) as mock_get_resource_provider:
|
||||
mock_get_resource_provider.return_value = self.fake_provider
|
||||
with mock.patch.object(self.dbapi, 'destroy_resource_provider',
|
||||
autospec=True) as mock_destroy:
|
||||
provider = objects.ResourceProvider.get_by_uuid(
|
||||
self.context, uuid)
|
||||
provider.destroy()
|
||||
mock_get_resource_provider.assert_called_once_with(
|
||||
self.context, uuid)
|
||||
mock_destroy.assert_called_once_with(None, uuid)
|
||||
self.assertEqual(self.context, provider._context)
|
||||
|
||||
def test_save(self):
|
||||
uuid = self.fake_provider['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_resource_provider',
|
||||
autospec=True) as mock_get_resource_provider:
|
||||
mock_get_resource_provider.return_value = self.fake_provider
|
||||
with mock.patch.object(self.dbapi, 'update_resource_provider',
|
||||
autospec=True) as mock_update:
|
||||
provider = objects.ResourceProvider.get_by_uuid(
|
||||
self.context, uuid)
|
||||
provider.name = 'provider2'
|
||||
provider.root_provider = '09d0fcb9-155e-434a-ad76-3620b6382a37'
|
||||
provider.save()
|
||||
|
||||
mock_get_resource_provider.assert_called_once_with(
|
||||
self.context, uuid)
|
||||
mock_update.assert_called_once_with(
|
||||
None, uuid,
|
||||
{'name': 'provider2',
|
||||
'root_provider': '09d0fcb9-155e-434a-ad76-3620b6382a37'})
|
||||
self.assertEqual(self.context, provider._context)
|
||||
|
||||
def test_refresh(self):
|
||||
uuid = self.fake_provider['uuid']
|
||||
new_uuid = uuidutils.generate_uuid()
|
||||
returns = [dict(self.fake_provider, uuid=uuid),
|
||||
dict(self.fake_provider, uuid=new_uuid)]
|
||||
expected = [mock.call(self.context, uuid),
|
||||
mock.call(self.context, uuid)]
|
||||
with mock.patch.object(self.dbapi, 'get_resource_provider',
|
||||
side_effect=returns,
|
||||
autospec=True) as mock_get_resource_provider:
|
||||
provider = objects.ResourceProvider.get_by_uuid(self.context, uuid)
|
||||
self.assertEqual(uuid, provider.uuid)
|
||||
provider.refresh()
|
||||
self.assertEqual(new_uuid, provider.uuid)
|
||||
self.assertEqual(
|
||||
expected, mock_get_resource_provider.call_args_list)
|
||||
self.assertEqual(self.context, provider._context)
|
Loading…
Reference in New Issue
Block a user