diff --git a/nova/objects/compute_node.py b/nova/objects/compute_node.py index d3dee9d3e8d8..ee28d004636e 100644 --- a/nova/objects/compute_node.py +++ b/nova/objects/compute_node.py @@ -297,28 +297,8 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): pools = jsonutils.dumps(pools.obj_to_primitive()) updates['pci_stats'] = pools - def _should_manage_inventory(self): - related_binaries = ['nova-api', 'nova-conductor', 'nova-scheduler'] - required_version = 10 - min_ver = objects.Service.get_minimum_version_multi(self._context, - related_binaries) - return min_ver >= required_version - - def _update_inventory(self, updates): - """Update inventory records from legacy model values - - :param updates: Legacy model update dict which will be modified when - we return - """ - # NOTE(danms): Here we update our inventory records with our - # resource information. Since this information is prepared in - # updates against our older compute_node columns, we need to - # zero those values after we have updated the inventory - # records so that it is clear that they have been migrated. - # We return True or False here based on whether we found - # inventory records to update. If not, then we need to signal - # to our caller that _create_inventory() needs to be called - # instead + def update_inventory(self): + """Update inventory records from legacy model values.""" inventory_list = \ objects.InventoryList.get_all_by_resource_provider_uuid( @@ -338,30 +318,22 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): inventory.resource_class) continue - if key in updates: + if key in self.obj_what_changed(): inventory.total = getattr(self, key) - updates[key] = 0 - inventory.save() + return True - def _create_inventory(self, updates): + def create_inventory(self): """Create the initial inventory objects for this compute node. This is only ever called once, either for the first time when a compute is created, or after an upgrade where the required services have reached the required version. - - :param updates: Legacy model update dict which will be modified when - we return """ rp = objects.ResourceProvider(context=self._context, uuid=self.uuid) rp.create() - # NOTE(danms): Until we remove the columns from compute_nodes, - # we need to constantly zero out each value in our updates to - # signal that we wrote the value into inventory instead. - cpu = objects.Inventory(context=self._context, resource_provider=rp, resource_class=fields.ResourceClass.VCPU, @@ -372,7 +344,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): step_size=1, allocation_ratio=self.cpu_allocation_ratio) cpu.create() - updates['vcpus'] = 0 mem = objects.Inventory(context=self._context, resource_provider=rp, @@ -384,7 +355,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): step_size=1, allocation_ratio=self.ram_allocation_ratio) mem.create() - updates['memory_mb'] = 0 # FIXME(danms): Eventually we want to not write this record # if the compute host is on shared storage. We'll need some @@ -401,7 +371,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): step_size=1, allocation_ratio=self.disk_allocation_ratio) disk.create() - updates['local_gb'] = 0 @base.remotable def create(self): @@ -418,9 +387,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): self._convert_supported_instances_to_db_format(updates) self._convert_pci_stats_to_db_format(updates) - if self._should_manage_inventory(): - self._create_inventory(updates) - db_compute = db.compute_node_create(self._context, updates) # NOTE(danms): compute_node_create() operates on (and returns) the # compute node model only. We need to get the full inventory-based @@ -441,10 +407,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject): self._convert_supported_instances_to_db_format(updates) self._convert_pci_stats_to_db_format(updates) - if self._should_manage_inventory(): - if not self._update_inventory(updates): - # NOTE(danms): This only happens once - self._create_inventory(updates) db_compute = db.compute_node_update(self._context, self.id, updates) # NOTE(danms): compute_node_update() operates on (and returns) the # compute node model only. We need to get the full inventory-based diff --git a/nova/objects/resource_provider.py b/nova/objects/resource_provider.py index 166d45ec0af1..3932b6f72ed7 100644 --- a/nova/objects/resource_provider.py +++ b/nova/objects/resource_provider.py @@ -13,14 +13,14 @@ from sqlalchemy.orm import joinedload from nova.db.sqlalchemy import api as db_api -from nova.db.sqlalchemy import models +from nova.db.sqlalchemy import api_models as models from nova import exception from nova import objects from nova.objects import base from nova.objects import fields -@db_api.main_context_manager.writer +@db_api.api_context_manager.writer def _create_rp_in_db(context, updates): db_rp = models.ResourceProvider() db_rp.update(updates) @@ -28,7 +28,7 @@ def _create_rp_in_db(context, updates): return db_rp -@db_api.main_context_manager.reader +@db_api.api_context_manager.reader def _get_rp_by_uuid_from_db(context, uuid): result = context.session.query(models.ResourceProvider).filter_by( uuid=uuid).first() @@ -129,7 +129,7 @@ class _HasAResourceProvider(base.NovaObject): return target -@db_api.main_context_manager.writer +@db_api.api_context_manager.writer def _create_inventory_in_db(context, updates): db_inventory = models.Inventory() db_inventory.update(updates) @@ -137,7 +137,7 @@ def _create_inventory_in_db(context, updates): return db_inventory -@db_api.main_context_manager.writer +@db_api.api_context_manager.writer def _update_inventory_in_db(context, id_, updates): result = context.session.query( models.Inventory).filter_by(id=id_).update(updates) @@ -199,7 +199,7 @@ class InventoryList(base.ObjectListBase, base.NovaObject): } @staticmethod - @db_api.main_context_manager.reader + @db_api.api_context_manager.reader def _get_all_by_resource_provider(context, rp_uuid): return context.session.query(models.Inventory).\ options(joinedload('resource_provider')).\ diff --git a/nova/tests/functional/db/test_compute_node.py b/nova/tests/functional/db/test_compute_node.py index 6f845b6fff3c..2eb37656c79a 100644 --- a/nova/tests/functional/db/test_compute_node.py +++ b/nova/tests/functional/db/test_compute_node.py @@ -10,13 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. -import mock - from nova import context -from nova import db from nova import objects from nova.objects import fields from nova import test +from nova.tests import uuidsentinel class ComputeNodeTestCase(test.TestCase): @@ -24,6 +22,7 @@ class ComputeNodeTestCase(test.TestCase): super(ComputeNodeTestCase, self).setUp() self.context = context.RequestContext('fake-user', 'fake-project') self.cn = objects.ComputeNode(context=self.context, + uuid=uuidsentinel.compute_node, memory_mb=512, local_gb=1000, vcpus=8, vcpus_used=0, local_gb_used=0, memory_mb_used=0, free_ram_mb=0, @@ -33,111 +32,30 @@ class ComputeNodeTestCase(test.TestCase): ram_allocation_ratio=1.0, disk_allocation_ratio=1.0) - @mock.patch('nova.objects.Service.get_minimum_version_multi') - def test_create_creates_inventories(self, mock_minver): - mock_minver.return_value = 10 - self.cn.create() - self.assertEqual(512, self.cn.memory_mb) - self.assertEqual(1000, self.cn.local_gb) - self.assertEqual(8, self.cn.vcpus) - db_cn = db.compute_node_get(self.context, self.cn.id) - self.assertEqual(0, db_cn['memory_mb']) - self.assertEqual(0, db_cn['local_gb']) - self.assertEqual(0, db_cn['vcpus']) - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( + def test_create_inventory(self): + self.cn.create_inventory() + objs = objects.InventoryList.get_all_by_resource_provider_uuid( self.context, self.cn.uuid) - self.assertEqual(3, len(inventories)) - inv = {i.resource_class: i.total for i in inventories} - expected = { - fields.ResourceClass.DISK_GB: 1000, - fields.ResourceClass.MEMORY_MB: 512, - fields.ResourceClass.VCPU: 8, - } - self.assertEqual(expected, inv) + for obj in objs: + if obj.resource_class == fields.ResourceClass.VCPU: + self.assertEqual(8, obj.total) + elif obj.resource_class == fields.ResourceClass.MEMORY_MB: + self.assertEqual(512, obj.total) + elif obj.resource_class == fields.ResourceClass.DISK_GB: + self.assertEqual(1000, obj.total) - @mock.patch('nova.objects.Service.get_minimum_version_multi') - def test_save_updates_inventories(self, mock_minver): - mock_minver.return_value = 10 - self.cn.create() - self.cn.memory_mb = 2048 + def test_update_inventory(self): + self.cn.create_inventory() + self.cn.memory_mb = 1024 self.cn.local_gb = 2000 - self.cn.save() - self.assertEqual(2048, self.cn.memory_mb) - self.assertEqual(2000, self.cn.local_gb) - self.assertEqual(8, self.cn.vcpus) - db_cn = db.compute_node_get(self.context, self.cn.id) - self.assertEqual(0, db_cn['memory_mb']) - self.assertEqual(0, db_cn['local_gb']) - self.assertEqual(0, db_cn['vcpus']) - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( + self.cn.vcpus = 16 + self.cn.update_inventory() + objs = objects.InventoryList.get_all_by_resource_provider_uuid( self.context, self.cn.uuid) - self.assertEqual(3, len(inventories)) - inv = {i.resource_class: i.total for i in inventories} - expected = { - fields.ResourceClass.DISK_GB: 2000, - fields.ResourceClass.MEMORY_MB: 2048, - fields.ResourceClass.VCPU: 8, - } - self.assertEqual(expected, inv) - - @mock.patch('nova.objects.Service.get_minimum_version_multi') - def test_save_creates_inventories(self, mock_minver): - mock_minver.return_value = 7 - self.cn.create() - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( - self.context, self.cn.uuid) - self.assertEqual(0, len(inventories)) - mock_minver.return_value = 10 - self.cn.memory_mb = 2048 - self.cn.local_gb = 2000 - self.cn.save() - self.assertEqual(2048, self.cn.memory_mb) - self.assertEqual(2000, self.cn.local_gb) - self.assertEqual(8, self.cn.vcpus) - db_cn = db.compute_node_get(self.context, self.cn.id) - self.assertEqual(0, db_cn['memory_mb']) - self.assertEqual(0, db_cn['local_gb']) - self.assertEqual(0, db_cn['vcpus']) - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( - self.context, self.cn.uuid) - self.assertEqual(3, len(inventories)) - inv = {i.resource_class: i.total for i in inventories} - expected = { - fields.ResourceClass.DISK_GB: 2000, - fields.ResourceClass.MEMORY_MB: 2048, - fields.ResourceClass.VCPU: 8, - } - self.assertEqual(expected, inv) - - @mock.patch('nova.objects.Service.get_minimum_version_multi') - def test_create_honors_version(self, mock_minver): - mock_minver.return_value = 7 - self.cn.create() - self.assertEqual(512, self.cn.memory_mb) - self.assertEqual(1000, self.cn.local_gb) - self.assertEqual(8, self.cn.vcpus) - db_cn = db.compute_node_get(self.context, self.cn.id) - self.assertEqual(512, db_cn['memory_mb']) - self.assertEqual(1000, db_cn['local_gb']) - self.assertEqual(8, db_cn['vcpus']) - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( - self.context, self.cn.uuid) - self.assertEqual(0, len(inventories)) - - @mock.patch('nova.objects.Service.get_minimum_version_multi') - def test_save_honors_version(self, mock_minver): - mock_minver.return_value = 7 - self.cn.create() - self.cn.memory_mb = 2048 - self.cn.local_gb = 2000 - self.cn.save() - self.assertEqual(2048, self.cn.memory_mb) - self.assertEqual(2000, self.cn.local_gb) - self.assertEqual(8, self.cn.vcpus) - db_cn = db.compute_node_get(self.context, self.cn.id) - self.assertEqual(2048, db_cn['memory_mb']) - self.assertEqual(2000, db_cn['local_gb']) - self.assertEqual(8, db_cn['vcpus']) - inventories = objects.InventoryList.get_all_by_resource_provider_uuid( - self.context, self.cn.uuid) - self.assertEqual(0, len(inventories)) + for obj in objs: + if obj.resource_class == fields.ResourceClass.VCPU: + self.assertEqual(16, obj.total) + elif obj.resource_class == fields.ResourceClass.MEMORY_MB: + self.assertEqual(1024, obj.total) + elif obj.resource_class == fields.ResourceClass.DISK_GB: + self.assertEqual(2000, obj.total) diff --git a/nova/tests/functional/db/test_resource_provider.py b/nova/tests/functional/db/test_resource_provider.py index ad655f2b6db6..89ec789d52e3 100644 --- a/nova/tests/functional/db/test_resource_provider.py +++ b/nova/tests/functional/db/test_resource_provider.py @@ -36,6 +36,7 @@ class ResourceProviderTestCase(test.NoDBTestCase): def setUp(self): super(ResourceProviderTestCase, self).setUp() self.useFixture(fixtures.Database()) + self.useFixture(fixtures.Database(database='api')) self.context = context.RequestContext('fake-user', 'fake-project') def test_create_resource_provider_requires_uuid(self): diff --git a/nova/tests/unit/compute/test_resource_tracker.py b/nova/tests/unit/compute/test_resource_tracker.py index 23140dc25a75..59470ab8dd83 100644 --- a/nova/tests/unit/compute/test_resource_tracker.py +++ b/nova/tests/unit/compute/test_resource_tracker.py @@ -774,8 +774,7 @@ class _MoveClaimTestCase(BaseTrackerTestCase): @mock.patch('nova.objects.Instance.save') @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid', return_value=objects.InstancePCIRequests(requests=[])) - @mock.patch('nova.objects.ComputeNode._create_inventory') - def test_additive_claims(self, mock_ci, mock_get, mock_save): + def test_additive_claims(self, mock_get, mock_save): limits = self._limits( 2 * FAKE_VIRT_MEMORY_WITH_OVERHEAD, @@ -797,8 +796,7 @@ class _MoveClaimTestCase(BaseTrackerTestCase): @mock.patch('nova.objects.Instance.save') @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid', return_value=objects.InstancePCIRequests(requests=[])) - @mock.patch('nova.objects.ComputeNode._create_inventory') - def test_move_type_not_tracked(self, mock_ci, mock_get, mock_save): + def test_move_type_not_tracked(self, mock_get, mock_save): self.claim_method(self.context, self.instance, self.instance_type, limits=self.limits, move_type="live-migration") mock_save.assert_called_once_with()