objects: new InstanceDeviceMetadata object

The InstanceDeviceMetadata will keep a list
of all the devices metadata, such as NICs and disks
associated to an instance. Eventually, it will be
stored in the instance_extra table.
InstanceDeviceMetadata object is new in this series
and has never been sent over RPC nor used.

Partially implements blueprint virt-device-role-tagging
Co-authored-by: Artom Lifshitz <alifshit@redhat.com>

Change-Id: I914e2c9a465864e5d320f8eb8d2fd509e64a7a75
This commit is contained in:
Vladik Romanovsky 2016-05-19 14:19:44 -04:00
parent cf6cde95a1
commit 885cf20daf
3 changed files with 119 additions and 5 deletions

View File

@ -12,12 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils
from nova import db
from nova.objects import base
from nova.objects import fields
@base.NovaObjectRegistry.register_if(False)
@base.NovaObjectRegistry.register
class DeviceBus(base.NovaObject):
VERSION = '1.0'
@ -88,9 +90,29 @@ class DiskMetadata(DeviceMetadata):
@base.NovaObjectRegistry.register
class DeviceMetadataList(base.ObjectListBase, base.NovaObject):
class InstanceDeviceMetadata(base.NovaObject):
VERSION = '1.0'
fields = {
'objects': fields.ListOfObjectsField('DeviceMetadata',
subclasses=True),
'devices': fields.ListOfObjectsField('DeviceMetadata',
subclasses=True),
}
@classmethod
def obj_from_db(cls, context, db_requests):
primitive = jsonutils.loads(db_requests)
device_metadata = cls.obj_from_primitive(primitive)
return device_metadata
@base.remotable_classmethod
def get_by_instance_uuid(cls, context, instance_uuid):
db_extra = db.instance_extra_get_by_instance_uuid(
context, instance_uuid, columns=['device_metadata'])
if not db_extra or db_extra['device_metadata'] is None:
return None
primitive = jsonutils.loads(db_extra['device_metadata'])
device_metadata = cls.obj_from_primitive(primitive)
return device_metadata
def _to_json(self):
return jsonutils.dumps(self.obj_to_primitive())

View File

@ -0,0 +1,91 @@
# 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_serialization import jsonutils
from nova import objects
from nova.tests.unit.objects import test_objects
fake_net_interface_meta = objects.NetworkInterfaceMetadata(
mac='52:54:00:f6:35:8f',
tags=['mytag1'],
bus=objects.PCIDeviceBus(address='0000:00:03.0'))
fake_pci_disk_meta = objects.DiskMetadata(
bus=objects.PCIDeviceBus(address='0000:00:09.0'),
tags=['nfvfunc3'])
fake_obj_devices_metadata = objects.InstanceDeviceMetadata(
devices=[fake_net_interface_meta, fake_pci_disk_meta])
fake_devices_metadata = fake_obj_devices_metadata._to_json()
fake_db_metadata = {
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'id': 1,
'device_metadata': fake_obj_devices_metadata._to_json()
}
fake_old_db_metadata = dict(fake_db_metadata) # copy
fake_old_db_metadata['device_metadata'] = jsonutils.dumps(
fake_devices_metadata)
def get_fake_obj_device_metadata(context):
fake_obj_devices_metadata_cpy = fake_obj_devices_metadata.obj_clone()
fake_obj_devices_metadata_cpy._context = context
return fake_obj_devices_metadata_cpy
class _TestInstanceDeviceMetadata(object):
def _check_object(self, obj_meta):
self.assertTrue(isinstance(obj_meta,
objects.NetworkInterfaceMetadata) or
isinstance(obj_meta, objects.DiskMetadata))
if isinstance(obj_meta, objects.NetworkInterfaceMetadata):
self.assertEqual(obj_meta.mac, '52:54:00:f6:35:8f')
self.assertEqual(obj_meta.tags, ['mytag1'])
self.assertTrue(obj_meta.bus, objects.PCIDeviceBus)
self.assertEqual(obj_meta.bus.address, '0000:00:03.0')
elif isinstance(obj_meta, objects.DiskMetadata):
self.assertTrue(obj_meta.bus, objects.PCIDeviceBus)
self.assertEqual(obj_meta.bus.address, '0000:00:09.0')
self.assertEqual(obj_meta.tags, ['nfvfunc3'])
@mock.patch('nova.db.instance_extra_get_by_instance_uuid')
def test_get_by_instance_uuid(self, mock_get):
mock_get.return_value = fake_db_metadata
inst_meta = objects.InstanceDeviceMetadata
dev_meta = inst_meta.get_by_instance_uuid(
self.context, 'fake_uuid')
for obj_meta, fake_meta in zip(
dev_meta.devices,
fake_obj_devices_metadata.devices):
self._check_object(obj_meta)
def test_obj_from_db(self):
db_meta = fake_db_metadata['device_metadata']
metadata = objects.InstanceDeviceMetadata.obj_from_db(None, db_meta)
for obj_meta in metadata.devices:
self._check_object(obj_meta)
class TestInstanceDeviceMetadata(test_objects._LocalTest,
_TestInstanceDeviceMetadata):
pass
class TestInstanceDeviceMetadataRemote(test_objects._RemoteTest,
_TestInstanceDeviceMetadata):
pass

View File

@ -1111,8 +1111,8 @@ object_data = {
'DNSDomain': '1.0-7b0b2dab778454b6a7b6c66afe163a1a',
'DNSDomainList': '1.0-4ee0d9efdfd681fed822da88376e04d2',
'Destination': '1.0-4c59dd1288b2e7adbda6051a2de59183',
'DeviceBus': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d',
'DeviceMetadata': '1.0-04eb8fd218a49cbc3b1e54b774d179f7',
'DeviceMetadataList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e',
'DiskMetadata': '1.0-e7a0f1ccccf10d26a76b28e7492f3788',
'EC2Ids': '1.0-474ee1094c7ec16f8ce657595d8c49d9',
'EC2InstanceMapping': '1.0-a4556eb5c5e94c045fe84f49cf71644f',
@ -1135,6 +1135,7 @@ object_data = {
'InstanceActionEvent': '1.1-e56a64fa4710e43ef7af2ad9d6028b33',
'InstanceActionEventList': '1.1-13d92fb953030cdbfee56481756e02be',
'InstanceActionList': '1.0-4a53826625cc280e15fae64a575e0879',
'InstanceDeviceMetadata': '1.0-74d78dd36aa32d26d2769a1b57caf186',
'InstanceExternalEvent': '1.1-6e446ceaae5f475ead255946dd443417',
'InstanceFault': '1.2-7ef01f16f1084ad1304a513d6d410a38',
'InstanceFaultList': '1.1-f8ec07cbe3b60f5f07a8b7a06311ac0d',