Merge "Make Inventory and ResourceProvider objects use the API DB instead"
This commit is contained in:
commit
f280d26216
@ -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
|
||||
|
@ -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')).\
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user