Object: Add BayModel as an ObjectField to Bay object

It is inconvenient to get baymodel from a bay, such as:
        bay = objects.Bay.get_by_uuid(pecan.request.context, obj.bay_uuid)
        baymodel = objects.BayModel.get_by_uuid(pecan.request.context,
                                                bay.baymodel_id)

We can load baymodel as an ObjectField of bay, then we can refer bay.baymodel
to get that bay's baymodel.

This patch requires version bump of Bay object.
Implemented: blueprint add-baymodel-object-to-bay
Change-Id: I04e52a16225416cd8da9342ce9cce2959373c887
This commit is contained in:
Eli Qiao 2015-12-14 17:06:28 +08:00
parent 2862a60203
commit 3e1bedd580
8 changed files with 101 additions and 57 deletions

View File

@ -19,6 +19,7 @@ from magnum.common import exception
from magnum.common import utils
from magnum.db import api as dbapi
from magnum.objects import base
from magnum.objects import baymodel
from magnum.objects import fields as m_fields
@ -28,7 +29,8 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
# Version 1.0: Initial version
# Version 1.1: Added 'bay_create_timeout' field
# Version 1.2: Add 'registry_trust_id' field
VERSION = '1.2'
# Version 1.3: Added 'baymodel' field
VERSION = '1.3'
dbapi = dbapi.get_instance()
@ -51,14 +53,23 @@ class Bay(base.MagnumPersistentObject, base.MagnumObject,
'master_addresses': fields.ListOfStringsField(nullable=True),
'ca_cert_ref': fields.StringField(nullable=True),
'magnum_cert_ref': fields.StringField(nullable=True),
'registry_trust_id': fields.StringField(nullable=True)
'registry_trust_id': fields.StringField(nullable=True),
'baymodel': fields.ObjectField('BayModel'),
}
@staticmethod
def _from_db_object(bay, db_bay):
"""Converts a database entity to a formal object."""
for field in bay.fields:
bay[field] = db_bay[field]
if field != 'baymodel':
bay[field] = db_bay[field]
# Note(eliqiao): The following line needs to be placed outside the
# loop because there is a dependency from baymodel to baymodel_id.
# The baymodel_id must be populated first in the loop before it can be
# used to find the baymodel.
bay['baymodel'] = baymodel.BayModel.get_by_uuid(bay._context,
bay.baymodel_id)
bay.obj_reset_changes()
return bay

View File

@ -41,9 +41,7 @@ class TestListPod(api_base.FunctionalTest):
def setUp(self):
super(TestListPod, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.pod = obj_utils.create_test_pod(self.context)
@mock.patch.object(rpcapi.API, 'pod_list')
@ -210,9 +208,7 @@ class TestPatch(api_base.FunctionalTest):
def setUp(self):
super(TestPatch, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.pod = obj_utils.create_test_pod(self.context,
desc='pod_example_A_desc',
status='Running')
@ -404,16 +400,18 @@ class TestPost(api_base.FunctionalTest):
def setUp(self):
super(TestPost, self).setUp()
obj_utils.create_test_bay(self.context)
self.test_bay = obj_utils.create_test_bay(self.context,
coe='kubernetes')
self.pod_obj = obj_utils.create_test_pod(self.context)
p = mock.patch.object(rpcapi.API, 'pod_create')
self.mock_pod_create = p.start()
self.mock_pod_create.return_value = self.pod_obj
self.addCleanup(p.stop)
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
self.mock_baymodel_get_by_uuid = p.start()
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
self.addCleanup(p.stop)
self.mock_baymodel_get_by_uuid = obj_utils.get_test_baymodel(
self.context,
uuid=self.test_bay.baymodel_id,
coe='kubernetes')
@mock.patch('oslo_utils.timeutils.utcnow')
@mock.patch.object(rpcapi.API, 'rc_create')
@ -508,9 +506,7 @@ class TestDelete(api_base.FunctionalTest):
def setUp(self):
super(TestDelete, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.pod = obj_utils.create_test_pod(self.context)
@mock.patch.object(rpcapi.API, 'pod_delete')

View File

@ -41,9 +41,7 @@ class TestListRC(api_base.FunctionalTest):
def setUp(self):
super(TestListRC, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.rc = obj_utils.create_test_rc(self.context)
@mock.patch.object(rpcapi.API, 'rc_list')
@ -199,9 +197,7 @@ class TestPatch(api_base.FunctionalTest):
def setUp(self):
super(TestPatch, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.rc = obj_utils.create_test_rc(self.context,
images=['rc_example_A_image'])
self.another_bay = obj_utils.create_test_bay(
@ -430,16 +426,18 @@ class TestPost(api_base.FunctionalTest):
def setUp(self):
super(TestPost, self).setUp()
obj_utils.create_test_bay(self.context)
self.test_bay = obj_utils.create_test_bay(self.context,
coe='kubernetes')
self.rc_obj = obj_utils.create_test_rc(self.context)
p = mock.patch.object(rpcapi.API, 'rc_create')
self.mock_rc_create = p.start()
self.mock_rc_create.return_value = self.rc_obj
self.addCleanup(p.stop)
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
self.mock_baymodel_get_by_uuid = p.start()
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
self.addCleanup(p.stop)
self.mock_baymodel_get_by_uuid = obj_utils.get_test_baymodel(
self.context,
uuid=self.test_bay.baymodel_id,
coe='kubernetes')
@mock.patch('oslo_utils.timeutils.utcnow')
@mock.patch.object(rpcapi.API, 'rc_create')
@ -524,9 +522,7 @@ class TestDelete(api_base.FunctionalTest):
def setUp(self):
super(TestDelete, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.rc = obj_utils.create_test_rc(self.context)
@mock.patch.object(rpcapi.API, 'rc_delete')

View File

@ -41,9 +41,7 @@ class TestListService(api_base.FunctionalTest):
def setUp(self):
super(TestListService, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.service = obj_utils.create_test_service(self.context)
@mock.patch.object(rpcapi.API, 'service_list')
@ -219,11 +217,11 @@ class TestPatch(api_base.FunctionalTest):
def setUp(self):
super(TestPatch, self).setUp()
self.bay = obj_utils.create_test_bay(self.context,
uuid=utils.generate_uuid())
obj_utils.create_test_baymodel(self.context, uuid=self.bay.baymodel_id,
coe='kubernetes')
uuid=utils.generate_uuid(),
coe='kubernetes')
self.bay2 = obj_utils.create_test_bay(self.context,
uuid=utils.generate_uuid())
uuid=utils.generate_uuid(),
coe='kubernetes')
self.service = obj_utils.create_test_service(self.context,
bay_uuid=self.bay.uuid)
@ -408,7 +406,8 @@ class TestPost(api_base.FunctionalTest):
def setUp(self):
super(TestPost, self).setUp()
obj_utils.create_test_bay(self.context)
self.test_bay = obj_utils.create_test_bay(self.context,
coe='kubernetes')
self.service_obj = obj_utils.create_test_service(self.context)
p = mock.patch.object(rpcapi.API, 'service_create')
self.mock_service_create = p.start()
@ -416,10 +415,10 @@ class TestPost(api_base.FunctionalTest):
self.mock_service_create.side_effect = (
self._simulate_rpc_service_create)
self.addCleanup(p.stop)
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
self.mock_baymodel_get_by_uuid = p.start()
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
self.addCleanup(p.stop)
self.mock_baymodel_get_by_uuid = obj_utils.get_test_baymodel(
self.context,
uuid=self.test_bay.baymodel_id,
coe='kubernetes')
def _simulate_rpc_service_create(self, service):
service.create()
@ -519,9 +518,7 @@ class TestDelete(api_base.FunctionalTest):
def setUp(self):
super(TestDelete, self).setUp()
bay = obj_utils.create_test_bay(self.context)
obj_utils.create_test_baymodel(self.context, uuid=bay.baymodel_id,
coe='kubernetes')
obj_utils.create_test_bay(self.context, coe='kubernetes')
self.service = obj_utils.create_test_service(self.context)
@mock.patch.object(rpcapi.API, 'service_delete')

View File

@ -134,6 +134,16 @@ class TestHandler(db_base.DbTestCase):
mock_create_stack.side_effect = create_stack_side_effect
# FixMe(eliqiao): bay_create will call bay.create() again, this so bad
# because we have already called it in setUp since other test case will
# share the codes in setUp()
# But in self.handler.bay_create, we update bay.uuid and bay.stack_id
# so bay.create will create a new recored with baymodel_id None,
# this is bad because we load BayModel object in Bay object by
# baymodel_id. Here update self.bay.baymodel_id so bay.obj_get_changes
# will get notice that baymodel_id is updated and will update it
# in db.
self.bay.baymodel_id = self.baymodel.uuid
self.handler.bay_create(self.context,
self.bay, timeout)

View File

@ -28,52 +28,68 @@ class TestBayObject(base.DbTestCase):
def setUp(self):
super(TestBayObject, self).setUp()
self.fake_bay = utils.get_test_bay()
baymodel_id = self.fake_bay['baymodel_id']
self.fake_baymodel = objects.BayModel(uuid=baymodel_id)
def test_get_by_id(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_get_by_id(self, mock_baymodel_get):
bay_id = self.fake_bay['id']
with mock.patch.object(self.dbapi, 'get_bay_by_id',
autospec=True) as mock_get_bay:
mock_baymodel_get.return_value = self.fake_baymodel
mock_get_bay.return_value = self.fake_bay
bay = objects.Bay.get(self.context, bay_id)
mock_get_bay.assert_called_once_with(self.context, bay_id)
self.assertEqual(self.context, bay._context)
self.assertEqual(bay.baymodel_id, bay.baymodel.uuid)
def test_get_by_uuid(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_get_by_uuid(self, mock_baymodel_get):
uuid = self.fake_bay['uuid']
with mock.patch.object(self.dbapi, 'get_bay_by_uuid',
autospec=True) as mock_get_bay:
mock_baymodel_get.return_value = self.fake_baymodel
mock_get_bay.return_value = self.fake_bay
bay = objects.Bay.get(self.context, uuid)
mock_get_bay.assert_called_once_with(self.context, uuid)
self.assertEqual(self.context, bay._context)
self.assertEqual(bay.baymodel_id, bay.baymodel.uuid)
def test_get_by_name(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_get_by_name(self, mock_baymodel_get):
name = self.fake_bay['name']
with mock.patch.object(self.dbapi, 'get_bay_by_name',
autospec=True) as mock_get_bay:
mock_baymodel_get.return_value = self.fake_baymodel
mock_get_bay.return_value = self.fake_bay
bay = objects.Bay.get_by_name(self.context, name)
mock_get_bay.assert_called_once_with(self.context, name)
self.assertEqual(self.context, bay._context)
self.assertEqual(bay.baymodel_id, bay.baymodel.uuid)
def test_get_bad_id_and_uuid(self):
self.assertRaises(exception.InvalidIdentity,
objects.Bay.get, self.context, 'not-a-uuid')
def test_list(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_list(self, mock_baymodel_get):
with mock.patch.object(self.dbapi, 'get_bay_list',
autospec=True) as mock_get_list:
mock_get_list.return_value = [self.fake_bay]
mock_baymodel_get.return_value = self.fake_baymodel
bays = objects.Bay.list(self.context)
self.assertEqual(1, mock_get_list.call_count)
self.assertThat(bays, HasLength(1))
self.assertIsInstance(bays[0], objects.Bay)
self.assertEqual(self.context, bays[0]._context)
self.assertEqual(bays[0].baymodel_id, bays[0].baymodel.uuid)
def test_list_all(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_list_all(self, mock_baymodel_get):
with mock.patch.object(self.dbapi, 'get_bay_list',
autospec=True) as mock_get_list:
mock_get_list.return_value = [self.fake_bay]
mock_baymodel_get.return_value = self.fake_baymodel
self.context.all_tenants = True
bays = objects.Bay.list(self.context)
mock_get_list.assert_called_once_with(
@ -84,10 +100,12 @@ class TestBayObject(base.DbTestCase):
self.assertIsInstance(bays[0], objects.Bay)
self.assertEqual(self.context, bays[0]._context)
def test_list_with_filters(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_list_with_filters(self, mock_baymodel_get):
with mock.patch.object(self.dbapi, 'get_bay_list',
autospec=True) as mock_get_list:
mock_get_list.return_value = [self.fake_bay]
mock_baymodel_get.return_value = self.fake_baymodel
filters = {'name': 'bay1'}
bays = objects.Bay.list(self.context, filters=filters)
@ -100,20 +118,24 @@ class TestBayObject(base.DbTestCase):
self.assertIsInstance(bays[0], objects.Bay)
self.assertEqual(self.context, bays[0]._context)
def test_create(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_create(self, mock_baymodel_get):
with mock.patch.object(self.dbapi, 'create_bay',
autospec=True) as mock_create_bay:
mock_baymodel_get.return_value = self.fake_baymodel
mock_create_bay.return_value = self.fake_bay
bay = objects.Bay(self.context, **self.fake_bay)
bay.create()
mock_create_bay.assert_called_once_with(self.fake_bay)
self.assertEqual(self.context, bay._context)
def test_destroy(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_destroy(self, mock_baymodel_get):
uuid = self.fake_bay['uuid']
with mock.patch.object(self.dbapi, 'get_bay_by_uuid',
autospec=True) as mock_get_bay:
mock_get_bay.return_value = self.fake_bay
mock_baymodel_get.return_value = self.fake_baymodel
with mock.patch.object(self.dbapi, 'destroy_bay',
autospec=True) as mock_destroy_bay:
bay = objects.Bay.get_by_uuid(self.context, uuid)
@ -122,10 +144,12 @@ class TestBayObject(base.DbTestCase):
mock_destroy_bay.assert_called_once_with(uuid)
self.assertEqual(self.context, bay._context)
def test_save(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_save(self, mock_baymodel_get):
uuid = self.fake_bay['uuid']
with mock.patch.object(self.dbapi, 'get_bay_by_uuid',
autospec=True) as mock_get_bay:
mock_baymodel_get.return_value = self.fake_baymodel
mock_get_bay.return_value = self.fake_bay
with mock.patch.object(self.dbapi, 'update_bay',
autospec=True) as mock_update_bay:
@ -136,10 +160,12 @@ class TestBayObject(base.DbTestCase):
mock_get_bay.assert_called_once_with(self.context, uuid)
mock_update_bay.assert_called_once_with(
uuid, {'node_count': 10, 'master_count': 5})
uuid, {'node_count': 10, 'master_count': 5,
'baymodel': self.fake_baymodel})
self.assertEqual(self.context, bay._context)
def test_refresh(self):
@mock.patch('magnum.objects.BayModel.get_by_uuid')
def test_refresh(self, mock_baymodel_get):
uuid = self.fake_bay['uuid']
new_uuid = magnum_utils.generate_uuid()
returns = [dict(self.fake_bay, uuid=uuid),
@ -149,6 +175,7 @@ class TestBayObject(base.DbTestCase):
with mock.patch.object(self.dbapi, 'get_bay_by_uuid',
side_effect=returns,
autospec=True) as mock_get_bay:
mock_baymodel_get.return_value = self.fake_baymodel
bay = objects.Bay.get_by_uuid(self.context, uuid)
self.assertEqual(uuid, bay.uuid)
bay.refresh()

View File

@ -423,7 +423,7 @@ class _TestObject(object):
# For more information on object version testing, read
# http://docs.openstack.org/developer/magnum/objects.html
object_data = {
'Bay': '1.2-0749bac339a2cc24dc03f45a4359013d',
'Bay': '1.3-5c09d266a4f21301b3243848d4c09a90',
'BayModel': '1.8-a4bb0976be245f06edbd1db087a18071',
'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',
'Container': '1.3-e2d9d2e8a8844d421148cd9fde6c6bd6',

View File

@ -14,6 +14,8 @@
# under the License.
"""Magnum object test utilities."""
from magnum.common import exception
from magnum import objects
from magnum.tests.unit.db import utils as db_utils
@ -41,7 +43,10 @@ def create_test_baymodel(context, **kw):
attributes.
"""
baymodel = get_test_baymodel(context, **kw)
baymodel.create()
try:
baymodel.create()
except exception.BayModelAlreadyExists:
baymodel = objects.BayModel.get(context, baymodel.uuid)
return baymodel
@ -68,6 +73,8 @@ def create_test_bay(context, **kw):
attributes.
"""
bay = get_test_bay(context, **kw)
create_test_baymodel(context, uuid=bay['baymodel_id'],
coe=kw.get('coe', 'swarm'))
bay.create()
return bay