Merge "Add metadata objects for device tagging"

This commit is contained in:
Jenkins
2016-04-08 09:50:39 +00:00
committed by Gerrit Code Review
5 changed files with 239 additions and 0 deletions

View File

@@ -50,6 +50,7 @@ def register_all():
__import__('nova.objects.instance_pci_requests')
__import__('nova.objects.keypair')
__import__('nova.objects.migrate_data')
__import__('nova.objects.virt_device_metadata')
__import__('nova.objects.migration')
__import__('nova.objects.migration_context')
__import__('nova.objects.monitor_metric')

View File

@@ -13,6 +13,7 @@
# under the License.
from oslo_versionedobjects import fields
import re
import six
# TODO(berrange) Temporary import for Arch class
@@ -64,6 +65,7 @@ IPV4NetworkField = fields.IPV4NetworkField
IPV6NetworkField = fields.IPV6NetworkField
AutoTypedField = fields.AutoTypedField
BaseEnumField = fields.BaseEnumField
MACAddressField = fields.MACAddressField
# NOTE(danms): These are things we need to import for some of our
@@ -645,6 +647,63 @@ class NonNegativeInteger(FieldType):
return v
class AddressBase(FieldType):
@staticmethod
def coerce(obj, attr, value):
if re.match(obj.PATTERN, str(value)):
return str(value)
else:
raise ValueError(_('Value must match %s') % obj.PATTERN)
class PCIAddress(AddressBase):
PATTERN = '[a-f0-9]{4}:[a-f0-9]{2}:[a-f0-9]{2}.[a-f0-9]'
@staticmethod
def coerce(obj, attr, value):
return AddressBase.coerce(PCIAddress, attr, value)
class USBAddress(AddressBase):
PATTERN = '[a-f0-9]+:[a-f0-9]+'
@staticmethod
def coerce(obj, attr, value):
return AddressBase.coerce(USBAddress, attr, value)
class SCSIAddress(AddressBase):
PATTERN = '[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+'
@staticmethod
def coerce(obj, attr, value):
return AddressBase.coerce(SCSIAddress, attr, value)
class IDEAddress(AddressBase):
PATTERN = '[0-1]:[0-1]'
@staticmethod
def coerce(obj, attr, value):
return AddressBase.coerce(IDEAddress, attr, value)
class PCIAddressField(AutoTypedField):
AUTO_TYPE = PCIAddress()
class USBAddressField(AutoTypedField):
AUTO_TYPE = USBAddress()
class SCSIAddressField(AutoTypedField):
AUTO_TYPE = SCSIAddress()
class IDEAddressField(AutoTypedField):
AUTO_TYPE = IDEAddress()
class ArchitectureField(BaseEnumField):
AUTO_TYPE = Architecture()

View File

@@ -0,0 +1,96 @@
# Copyright (C) 2016, Red Hat, Inc.
#
# 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 nova.objects import base
from nova.objects import fields
@base.NovaObjectRegistry.register_if(False)
class DeviceBus(base.NovaObject):
VERSION = '1.0'
@base.NovaObjectRegistry.register
class PCIDeviceBus(DeviceBus):
VERSION = '1.0'
fields = {
'address': fields.PCIAddressField(),
}
@base.NovaObjectRegistry.register
class USBDeviceBus(DeviceBus):
VERSION = '1.0'
fields = {
'address': fields.USBAddressField(),
}
@base.NovaObjectRegistry.register
class SCSIDeviceBus(DeviceBus):
VERSION = '1.0'
fields = {
'address': fields.SCSIAddressField(),
}
@base.NovaObjectRegistry.register
class IDEDeviceBus(DeviceBus):
VERSION = '1.0'
fields = {
'address': fields.IDEAddressField(),
}
@base.NovaObjectRegistry.register
class DeviceMetadata(base.NovaObject):
VERSION = '1.0'
fields = {
'bus': fields.ObjectField("DeviceBus", subclasses=True),
'tags': fields.ListOfStringsField(),
}
@base.NovaObjectRegistry.register
class NetworkInterfaceMetadata(DeviceMetadata):
VERSION = '1.0'
fields = {
'mac': fields.MACAddressField(),
}
@base.NovaObjectRegistry.register
class DiskMetadata(DeviceMetadata):
VERSION = '1.0'
fields = {
'serial': fields.StringField(nullable=True),
'path': fields.StringField(nullable=True),
}
@base.NovaObjectRegistry.register
class DeviceMetadataList(base.ObjectListBase, base.NovaObject):
VERSION = '1.0'
fields = {
'objects': fields.ListOfObjectsField('DeviceMetadata',
subclasses=True),
}

View File

@@ -536,3 +536,70 @@ class TestNotificationAction(TestField):
def test_stringify_invalid(self):
self.assertRaises(ValueError, self.field.stringify, 'magic')
class TestPCIAddress(TestField):
def setUp(self):
super(TestPCIAddress, self).setUp()
self.field = fields.Field(fields.PCIAddressField())
self.coerce_good_values = [('0000:00:02.0', '0000:00:02.0')]
self.coerce_bad_values = [
'000:00:02.0',
'0000:0:02.0',
'0000:00:2.0',
'0000:00:02.',
'-000:00:02.0',
'0000:0-:02.0',
'0000:00:-2.0',
'0000:00:02.-',
'000000:02.0',
'0000:0:02.0',
'0000:00:020',
]
self.to_primitive_values = self.coerce_good_values
self.from_primitive_values = self.coerce_good_values
class TestUSBAddress(TestField):
def setUp(self):
super(TestUSBAddress, self).setUp()
self.field = fields.Field(fields.USBAddressField())
self.coerce_good_values = [('0:0', '0:0')]
self.coerce_bad_values = [
'00',
'0:',
'0.0',
'-.0',
]
self.to_primitive_values = self.coerce_good_values
self.from_primitive_values = self.coerce_good_values
class TestSCSIAddress(TestField):
def setUp(self):
super(TestSCSIAddress, self).setUp()
self.field = fields.Field(fields.SCSIAddressField())
self.coerce_good_values = [('1:0:2:0', '1:0:2:0')]
self.coerce_bad_values = [
'1:0:2',
'-:0:2:0',
'1:-:2:0',
'1:0:-:0',
'1:0:2:-',
]
self.to_primitive_values = self.coerce_good_values
self.from_primitive_values = self.coerce_good_values
class TestIDEAddress(TestField):
def setUp(self):
super(TestIDEAddress, self).setUp()
self.field = fields.Field(fields.IDEAddressField())
self.coerce_good_values = [('0:0', '0:0')]
self.coerce_bad_values = [
'0:2',
'00',
'0',
]
self.to_primitive_values = self.coerce_good_values
self.from_primitive_values = self.coerce_good_values

View File

@@ -36,6 +36,7 @@ from nova import objects
from nova.objects import base
from nova.objects import fields
from nova.objects import notification
from nova.objects import virt_device_metadata
from nova import test
from nova.tests import fixtures as nova_fixtures
from nova.tests.unit import fake_notifier
@@ -1111,6 +1112,9 @@ object_data = {
'ComputeNodeList': '1.14-3b6f4f5ade621c40e70cb116db237844',
'DNSDomain': '1.0-7b0b2dab778454b6a7b6c66afe163a1a',
'DNSDomainList': '1.0-4ee0d9efdfd681fed822da88376e04d2',
'DeviceMetadata': '1.0-04eb8fd218a49cbc3b1e54b774d179f7',
'DeviceMetadataList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e',
'DiskMetadata': '1.0-e7a0f1ccccf10d26a76b28e7492f3788',
'EC2Ids': '1.0-474ee1094c7ec16f8ce657595d8c49d9',
'EC2InstanceMapping': '1.0-a4556eb5c5e94c045fe84f49cf71644f',
'EC2SnapshotMapping': '1.0-47e7ddabe1af966dce0cfd0ed6cd7cd1',
@@ -1125,6 +1129,7 @@ object_data = {
'HostMapping': '1.0-1a3390a696792a552ab7bd31a77ba9ac',
'HyperVLiveMigrateData': '1.0-0b868dd6228a09c3f3e47016dddf6a1c',
'HVSpec': '1.2-db672e73304da86139086d003f3977e7',
'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502',
'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d',
'ImageMetaProps': '1.12-6a132dee47931447bf86c03c7006d96c',
'Instance': '2.1-416fdd0dfc33dfa12ff2cfdd8cc32e17',
@@ -1162,10 +1167,12 @@ object_data = {
'NUMATopology': '1.2-c63fad38be73b6afd04715c9c1b29220',
'NUMATopologyLimits': '1.0-9463e0edd40f64765ae518a539b9dfd2',
'Network': '1.2-a977ab383aa462a479b2fae8211a5dde',
'NetworkInterfaceMetadata': '1.0-99a9574d086feb5ad45cd04a34855647',
'NetworkList': '1.2-69eca910d8fa035dfecd8ba10877ee59',
'NetworkRequest': '1.1-7a3e4ca2ce1e7b62d8400488f2f2b756',
'NetworkRequestList': '1.1-15ecf022a68ddbb8c2a6739cfc9f8f5e',
'PciDevice': '1.5-0d5abe5c91645b8469eb2a93fc53f932',
'PCIDeviceBus': '1.0-2b891cb77e42961044689f3dc2718995',
'PciDeviceList': '1.3-52ff14355491c8c580bdc0ba34c26210',
'PciDevicePool': '1.1-3f5ddc3ff7bfa14da7f6c7e9904cc000',
'PciDevicePoolList': '1.1-15ecf022a68ddbb8c2a6739cfc9f8f5e',
@@ -1176,6 +1183,7 @@ object_data = {
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
'SchedulerRetries': '1.1-3c9c8b16143ebbb6ad7030e999d14cc0',
'SCSIDeviceBus': '1.0-61c1e89a00901069ab1cf2991681533b',
'SecurityGroup': '1.1-0e1b9ba42fe85c13c1437f8b74bdb976',
'SecurityGroupList': '1.0-dc8bbea01ba09a2edb6e5233eae85cbc',
'SecurityGroupRule': '1.1-ae1da17b79970012e8536f88cb3c6b29',
@@ -1188,6 +1196,7 @@ object_data = {
'TaskLogList': '1.0-cc8cce1af8a283b9d28b55fcd682e777',
'Tag': '1.1-8b8d7d5b48887651a0e01241672e2963',
'TagList': '1.1-55231bdb671ecf7641d6a2e9109b5d8e',
'USBDeviceBus': '1.0-e4c7dd6032e46cd74b027df5eb2d4750',
'VirtCPUFeature': '1.0-3310718d8c72309259a6e39bdefe83ee',
'VirtCPUModel': '1.0-6a5cc9f322729fc70ddc6733bacd57d3',
'VirtCPUTopology': '1.0-fc694de72e20298f7c6bab1083fd4563',
@@ -1243,6 +1252,13 @@ class TestObjectVersions(test.NoDBTestCase):
self.assertNotEqual(old_hash, new_hash)
def test_obj_make_compatible(self):
# NOTE(danms): This is normally not registered because it is just a
# base class. However, the test fixture below requires it to be
# in the registry so that it can verify backports based on its
# children. So, register it here, which will be reverted after the
# cleanUp for this (and all) tests is run.
base.NovaObjectRegistry.register(virt_device_metadata.DeviceBus)
# Iterate all object classes and verify that we can run
# obj_make_compatible with every older version than current.
# This doesn't actually test the data conversions, but it at least