diff options
-rw-r--r-- | nova/objects/__init__.py | 1 | ||||
-rw-r--r-- | nova/objects/instance.py | 33 | ||||
-rw-r--r-- | nova/objects/trusted_certs.py | 36 | ||||
-rw-r--r-- | nova/tests/unit/fake_instance.py | 1 | ||||
-rw-r--r-- | nova/tests/unit/objects/test_instance.py | 17 | ||||
-rw-r--r-- | nova/tests/unit/objects/test_objects.py | 3 | ||||
-rw-r--r-- | nova/tests/unit/objects/test_trusted_certs.py | 43 |
7 files changed, 129 insertions, 5 deletions
diff --git a/nova/objects/__init__.py b/nova/objects/__init__.py index 380b102561..08c8cd03dc 100644 --- a/nova/objects/__init__.py +++ b/nova/objects/__init__.py @@ -69,6 +69,7 @@ def register_all(): __import__('nova.objects.selection') __import__('nova.objects.service') __import__('nova.objects.task_log') + __import__('nova.objects.trusted_certs') __import__('nova.objects.vcpu_model') __import__('nova.objects.virt_cpu_topology') __import__('nova.objects.virtual_interface') diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 90dd3f7612..b9094c2342 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -57,7 +57,7 @@ _INSTANCE_OPTIONAL_NON_COLUMN_FIELDS = ['flavor', 'old_flavor', # These are fields that are optional and in instance_extra _INSTANCE_EXTRA_FIELDS = ['numa_topology', 'pci_requests', 'flavor', 'vcpu_model', 'migration_context', - 'keypairs', 'device_metadata'] + 'keypairs', 'device_metadata', 'trusted_certs'] # These are fields that applied/drooped by migration_context _MIGRATION_CONTEXT_ATTRS = ['numa_topology', 'pci_requests', 'pci_devices'] @@ -112,7 +112,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject, # Version 2.1: Added services # Version 2.2: Added keypairs # Version 2.3: Added device_metadata - VERSION = '2.3' + # Version 2.4: Added trusted_certs + VERSION = '2.4' fields = { 'id': fields.IntegerField(), @@ -212,6 +213,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject, 'migration_context': fields.ObjectField('MigrationContext', nullable=True), 'keypairs': fields.ObjectField('KeyPairList'), + 'trusted_certs': fields.ObjectField('TrustedCerts', nullable=True), } obj_extra_fields = ['name'] @@ -219,6 +221,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject, def obj_make_compatible(self, primitive, target_version): super(Instance, self).obj_make_compatible(primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (2, 4) and 'trusted_certs' in primitive: + del primitive['trusted_certs'] if target_version < (2, 3) and 'device_metadata' in primitive: del primitive['device_metadata'] if target_version < (2, 2) and 'keypairs' in primitive: @@ -453,6 +457,12 @@ class Instance(base.NovaPersistentObject, base.NovaObject, if 'keypairs' in expected_attrs: if have_extra: instance._load_keypairs(db_inst['extra'].get('keypairs')) + if 'trusted_certs' in expected_attrs: + if have_extra: + instance._load_trusted_certs( + db_inst['extra'].get('trusted_certs')) + else: + instance.trusted_certs = None if any([x in expected_attrs for x in ('flavor', 'old_flavor', 'new_flavor')]): @@ -560,6 +570,13 @@ class Instance(base.NovaPersistentObject, base.NovaObject, jsonutils.dumps(vcpu_model.obj_to_primitive())) else: updates['extra']['vcpu_model'] = None + trusted_certs = updates.pop('trusted_certs', None) + expected_attrs.append('trusted_certs') + if trusted_certs: + updates['extra']['trusted_certs'] = jsonutils.dumps( + trusted_certs.obj_to_primitive()) + else: + updates['extra']['trusted_certs'] = None db_inst = db.instance_create(self._context, updates) self._from_db_object(self._context, self, db_inst, expected_attrs) @@ -977,6 +994,16 @@ class Instance(base.NovaPersistentObject, base.NovaObject, self.tags = objects.TagList.get_by_resource_id( self._context, self.uuid) + def _load_trusted_certs(self, db_trusted_certs=_NO_DATA_SENTINEL): + if db_trusted_certs is None: + self.trusted_certs = None + elif db_trusted_certs is _NO_DATA_SENTINEL: + self.trusted_certs = objects.TrustedCerts.get_by_instance_uuid( + self._context, self.uuid) + else: + self.trusted_certs = objects.TrustedCerts.obj_from_primitive( + jsonutils.loads(db_trusted_certs)) + def apply_migration_context(self): if self.migration_context: self._set_migration_context_to_instance(prefix='new_') @@ -1072,6 +1099,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject, # NOTE(danms): Let keypairs control its own destiny for # resetting changes. return self._load_keypairs() + elif attrname == 'trusted_certs': + return self._load_trusted_certs() elif attrname == 'security_groups': self._load_security_groups() elif attrname == 'pci_devices': diff --git a/nova/objects/trusted_certs.py b/nova/objects/trusted_certs.py new file mode 100644 index 0000000000..e4dd7e46c2 --- /dev/null +++ b/nova/objects/trusted_certs.py @@ -0,0 +1,36 @@ +# 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_serialization import jsonutils + +from nova import db +from nova.objects import base +from nova.objects import fields + + +@base.NovaObjectRegistry.register +class TrustedCerts(base.NovaObject): + # Version 1.0: Initial version + VERSION = '1.0' + + fields = { + 'ids': fields.ListOfStringsField(nullable=False), + } + + @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=['trusted_certs']) + if not db_extra or not db_extra['trusted_certs']: + return None + return cls.obj_from_primitive( + jsonutils.loads(db_extra['trusted_certs'])) diff --git a/nova/tests/unit/fake_instance.py b/nova/tests/unit/fake_instance.py index 934fdd2441..39d94a029b 100644 --- a/nova/tests/unit/fake_instance.py +++ b/nova/tests/unit/fake_instance.py @@ -74,6 +74,7 @@ def fake_db_instance(**updates): 'numa_topology': None, 'vcpu_model': None, 'device_metadata': None, + 'trusted_certs': None, }, 'tags': [], 'services': [] diff --git a/nova/tests/unit/objects/test_instance.py b/nova/tests/unit/objects/test_instance.py index 488fdf3a96..97edcf4fbe 100644 --- a/nova/tests/unit/objects/test_instance.py +++ b/nova/tests/unit/objects/test_instance.py @@ -70,6 +70,7 @@ class _TestInstanceObject(object): db_inst['user_id'] = self.context.user_id db_inst['project_id'] = self.context.project_id db_inst['tags'] = [] + db_inst['trusted_certs'] = [] db_inst['info_cache'] = dict(test_instance_info_cache.fake_info_cache, instance_uuid=db_inst['uuid']) @@ -144,11 +145,12 @@ class _TestInstanceObject(object): exp_cols.remove('migration_context') exp_cols.remove('keypairs') exp_cols.remove('device_metadata') + exp_cols.remove('trusted_certs') exp_cols = [exp_col for exp_col in exp_cols if 'flavor' not in exp_col] exp_cols.extend(['extra', 'extra.numa_topology', 'extra.pci_requests', 'extra.flavor', 'extra.vcpu_model', 'extra.migration_context', 'extra.keypairs', - 'extra.device_metadata']) + 'extra.device_metadata', 'extra.trusted_certs']) fake_topology = (test_instance_numa_topology. fake_db_topology['numa_topology']) @@ -167,6 +169,8 @@ class _TestInstanceObject(object): objects.KeyPair(name='foo')]) fake_keypairs = jsonutils.dumps( fake_keypairlist.obj_to_primitive()) + fake_trusted_certs = jsonutils.dumps( + objects.TrustedCerts(ids=['123foo']).obj_to_primitive()) fake_service = {'created_at': None, 'updated_at': None, 'deleted_at': None, 'deleted': False, 'id': 123, 'host': 'fake-host', 'binary': 'nova-compute', @@ -185,6 +189,7 @@ class _TestInstanceObject(object): 'vcpu_model': fake_vcpu_model, 'migration_context': fake_mig_context, 'keypairs': fake_keypairs, + 'trusted_certs': fake_trusted_certs, }) mock_get.return_value = fake_instance @@ -199,6 +204,7 @@ class _TestInstanceObject(object): self.assertTrue(inst.obj_attr_is_set(attr)) self.assertEqual(123, inst.services[0].id) self.assertEqual('foo', inst.keypairs[0].name) + self.assertEqual(['123foo'], inst.trusted_certs.ids) mock_get.assert_called_once_with(self.context, 'uuid', columns_to_join=exp_cols) @@ -1028,6 +1034,7 @@ class _TestInstanceObject(object): 'numa_topology': None, 'pci_requests': None, 'device_metadata': None, + 'trusted_certs': None, }} fake_inst = fake_instance.fake_db_instance(**vals) mock_create.return_value = fake_inst @@ -1057,6 +1064,7 @@ class _TestInstanceObject(object): 'numa_topology': None, 'pci_requests': None, 'device_metadata': None, + 'trusted_certs': None, }} fake_inst = fake_instance.fake_db_instance(**vals) mock_create.return_value = fake_inst @@ -1072,7 +1080,9 @@ class _TestInstanceObject(object): extras = {'vcpu_model': None, 'numa_topology': None, 'pci_requests': None, - 'device_metadata': None} + 'device_metadata': None, + 'trusted_certs': None, + } mock_create.return_value = self.fake_instance inst = objects.Instance(context=self.context) inst.create() @@ -1108,6 +1118,7 @@ class _TestInstanceObject(object): objects.InstancePCIRequest(count=123, spec=[])]), vcpu_model=test_vcpu_model.fake_vcpumodel, + trusted_certs=objects.TrustedCerts(ids=['123foo']), ) inst.create() self.assertIsNotNone(inst.numa_topology) @@ -1124,6 +1135,7 @@ class _TestInstanceObject(object): vcpu_model = objects.VirtCPUModel.get_by_instance_uuid( self.context, inst.uuid) self.assertEqual('fake-model', vcpu_model.model) + self.assertEqual(['123foo'], inst.trusted_certs.ids) def test_recreate_fails(self): inst = objects.Instance(context=self.context, @@ -1161,6 +1173,7 @@ class _TestInstanceObject(object): 'numa_topology': None, 'pci_requests': None, 'device_metadata': None, + 'trusted_certs': None, }, }) diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 60bcc0e032..4ad627dd72 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1095,7 +1095,7 @@ object_data = { 'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502', 'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d', 'ImageMetaProps': '1.19-dc9581ff2b80d8c33462889916b82df0', - 'Instance': '2.3-4f98ab23f4b0a25fabb1040c8f5edecc', + 'Instance': '2.4-4437eb8b2737c3054ea579b8efe31dc5', 'InstanceAction': '1.1-f9f293e526b66fca0d05c3b3a2d13914', 'InstanceActionEvent': '1.1-e56a64fa4710e43ef7af2ad9d6028b33', 'InstanceActionEventList': '1.1-13d92fb953030cdbfee56481756e02be', @@ -1158,6 +1158,7 @@ object_data = { 'TaskLogList': '1.0-cc8cce1af8a283b9d28b55fcd682e777', 'Tag': '1.1-8b8d7d5b48887651a0e01241672e2963', 'TagList': '1.1-55231bdb671ecf7641d6a2e9109b5d8e', + 'TrustedCerts': '1.0-dcf528851e0f868c77ee47e90563cda7', 'USBDeviceBus': '1.0-e4c7dd6032e46cd74b027df5eb2d4750', 'VirtCPUFeature': '1.0-ea2464bdd09084bd388e5f61d5d4fc86', 'VirtCPUModel': '1.0-5e1864af9227f698326203d7249796b5', diff --git a/nova/tests/unit/objects/test_trusted_certs.py b/nova/tests/unit/objects/test_trusted_certs.py new file mode 100644 index 0000000000..d056244a78 --- /dev/null +++ b/nova/tests/unit/objects/test_trusted_certs.py @@ -0,0 +1,43 @@ +# 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 nova.objects import trusted_certs +from nova.tests.unit.objects import test_objects +from oslo_serialization import jsonutils + +fake_trusted_certs = trusted_certs.TrustedCerts(ids=['fake-trusted-cert-1', + 'fake-trusted-cert-2']) +fake_instance_extras = { + 'trusted_certs': jsonutils.dumps(fake_trusted_certs.obj_to_primitive()) +} + + +class _TestTrustedCertsObject(object): + + @mock.patch('nova.db.instance_extra_get_by_instance_uuid') + def test_get_by_instance_uuid(self, mock_get): + mock_get.return_value = fake_instance_extras + certs = trusted_certs.TrustedCerts.get_by_instance_uuid( + self.context, 'fake_uuid') + self.assertEqual(certs.ids, fake_trusted_certs.ids) + + +class TestTrustedCertsObject(test_objects._LocalTest, + _TestTrustedCertsObject): + pass + + +class TestRemoteTrustedCertsObject(test_objects._RemoteTest, + _TestTrustedCertsObject): + pass |