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())
|
pools = jsonutils.dumps(pools.obj_to_primitive())
|
||||||
updates['pci_stats'] = pools
|
updates['pci_stats'] = pools
|
||||||
|
|
||||||
def _should_manage_inventory(self):
|
def update_inventory(self):
|
||||||
related_binaries = ['nova-api', 'nova-conductor', 'nova-scheduler']
|
"""Update inventory records from legacy model values."""
|
||||||
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
|
|
||||||
|
|
||||||
inventory_list = \
|
inventory_list = \
|
||||||
objects.InventoryList.get_all_by_resource_provider_uuid(
|
objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||||
@ -338,30 +318,22 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject):
|
|||||||
inventory.resource_class)
|
inventory.resource_class)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if key in updates:
|
if key in self.obj_what_changed():
|
||||||
inventory.total = getattr(self, key)
|
inventory.total = getattr(self, key)
|
||||||
updates[key] = 0
|
|
||||||
|
|
||||||
inventory.save()
|
inventory.save()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _create_inventory(self, updates):
|
def create_inventory(self):
|
||||||
"""Create the initial inventory objects for this compute node.
|
"""Create the initial inventory objects for this compute node.
|
||||||
|
|
||||||
This is only ever called once, either for the first time when a compute
|
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
|
is created, or after an upgrade where the required services have
|
||||||
reached the required version.
|
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 = objects.ResourceProvider(context=self._context, uuid=self.uuid)
|
||||||
rp.create()
|
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,
|
cpu = objects.Inventory(context=self._context,
|
||||||
resource_provider=rp,
|
resource_provider=rp,
|
||||||
resource_class=fields.ResourceClass.VCPU,
|
resource_class=fields.ResourceClass.VCPU,
|
||||||
@ -372,7 +344,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject):
|
|||||||
step_size=1,
|
step_size=1,
|
||||||
allocation_ratio=self.cpu_allocation_ratio)
|
allocation_ratio=self.cpu_allocation_ratio)
|
||||||
cpu.create()
|
cpu.create()
|
||||||
updates['vcpus'] = 0
|
|
||||||
|
|
||||||
mem = objects.Inventory(context=self._context,
|
mem = objects.Inventory(context=self._context,
|
||||||
resource_provider=rp,
|
resource_provider=rp,
|
||||||
@ -384,7 +355,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject):
|
|||||||
step_size=1,
|
step_size=1,
|
||||||
allocation_ratio=self.ram_allocation_ratio)
|
allocation_ratio=self.ram_allocation_ratio)
|
||||||
mem.create()
|
mem.create()
|
||||||
updates['memory_mb'] = 0
|
|
||||||
|
|
||||||
# FIXME(danms): Eventually we want to not write this record
|
# FIXME(danms): Eventually we want to not write this record
|
||||||
# if the compute host is on shared storage. We'll need some
|
# 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,
|
step_size=1,
|
||||||
allocation_ratio=self.disk_allocation_ratio)
|
allocation_ratio=self.disk_allocation_ratio)
|
||||||
disk.create()
|
disk.create()
|
||||||
updates['local_gb'] = 0
|
|
||||||
|
|
||||||
@base.remotable
|
@base.remotable
|
||||||
def create(self):
|
def create(self):
|
||||||
@ -418,9 +387,6 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject):
|
|||||||
self._convert_supported_instances_to_db_format(updates)
|
self._convert_supported_instances_to_db_format(updates)
|
||||||
self._convert_pci_stats_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)
|
db_compute = db.compute_node_create(self._context, updates)
|
||||||
# NOTE(danms): compute_node_create() operates on (and returns) the
|
# NOTE(danms): compute_node_create() operates on (and returns) the
|
||||||
# compute node model only. We need to get the full inventory-based
|
# 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_supported_instances_to_db_format(updates)
|
||||||
self._convert_pci_stats_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)
|
db_compute = db.compute_node_update(self._context, self.id, updates)
|
||||||
# NOTE(danms): compute_node_update() operates on (and returns) the
|
# NOTE(danms): compute_node_update() operates on (and returns) the
|
||||||
# compute node model only. We need to get the full inventory-based
|
# compute node model only. We need to get the full inventory-based
|
||||||
|
@ -13,14 +13,14 @@
|
|||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
from nova.db.sqlalchemy import api as db_api
|
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 exception
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import base
|
from nova.objects import base
|
||||||
from nova.objects import fields
|
from nova.objects import fields
|
||||||
|
|
||||||
|
|
||||||
@db_api.main_context_manager.writer
|
@db_api.api_context_manager.writer
|
||||||
def _create_rp_in_db(context, updates):
|
def _create_rp_in_db(context, updates):
|
||||||
db_rp = models.ResourceProvider()
|
db_rp = models.ResourceProvider()
|
||||||
db_rp.update(updates)
|
db_rp.update(updates)
|
||||||
@ -28,7 +28,7 @@ def _create_rp_in_db(context, updates):
|
|||||||
return db_rp
|
return db_rp
|
||||||
|
|
||||||
|
|
||||||
@db_api.main_context_manager.reader
|
@db_api.api_context_manager.reader
|
||||||
def _get_rp_by_uuid_from_db(context, uuid):
|
def _get_rp_by_uuid_from_db(context, uuid):
|
||||||
result = context.session.query(models.ResourceProvider).filter_by(
|
result = context.session.query(models.ResourceProvider).filter_by(
|
||||||
uuid=uuid).first()
|
uuid=uuid).first()
|
||||||
@ -129,7 +129,7 @@ class _HasAResourceProvider(base.NovaObject):
|
|||||||
return target
|
return target
|
||||||
|
|
||||||
|
|
||||||
@db_api.main_context_manager.writer
|
@db_api.api_context_manager.writer
|
||||||
def _create_inventory_in_db(context, updates):
|
def _create_inventory_in_db(context, updates):
|
||||||
db_inventory = models.Inventory()
|
db_inventory = models.Inventory()
|
||||||
db_inventory.update(updates)
|
db_inventory.update(updates)
|
||||||
@ -137,7 +137,7 @@ def _create_inventory_in_db(context, updates):
|
|||||||
return db_inventory
|
return db_inventory
|
||||||
|
|
||||||
|
|
||||||
@db_api.main_context_manager.writer
|
@db_api.api_context_manager.writer
|
||||||
def _update_inventory_in_db(context, id_, updates):
|
def _update_inventory_in_db(context, id_, updates):
|
||||||
result = context.session.query(
|
result = context.session.query(
|
||||||
models.Inventory).filter_by(id=id_).update(updates)
|
models.Inventory).filter_by(id=id_).update(updates)
|
||||||
@ -199,7 +199,7 @@ class InventoryList(base.ObjectListBase, base.NovaObject):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@db_api.main_context_manager.reader
|
@db_api.api_context_manager.reader
|
||||||
def _get_all_by_resource_provider(context, rp_uuid):
|
def _get_all_by_resource_provider(context, rp_uuid):
|
||||||
return context.session.query(models.Inventory).\
|
return context.session.query(models.Inventory).\
|
||||||
options(joinedload('resource_provider')).\
|
options(joinedload('resource_provider')).\
|
||||||
|
@ -10,13 +10,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import db
|
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import fields
|
from nova.objects import fields
|
||||||
from nova import test
|
from nova import test
|
||||||
|
from nova.tests import uuidsentinel
|
||||||
|
|
||||||
|
|
||||||
class ComputeNodeTestCase(test.TestCase):
|
class ComputeNodeTestCase(test.TestCase):
|
||||||
@ -24,6 +22,7 @@ class ComputeNodeTestCase(test.TestCase):
|
|||||||
super(ComputeNodeTestCase, self).setUp()
|
super(ComputeNodeTestCase, self).setUp()
|
||||||
self.context = context.RequestContext('fake-user', 'fake-project')
|
self.context = context.RequestContext('fake-user', 'fake-project')
|
||||||
self.cn = objects.ComputeNode(context=self.context,
|
self.cn = objects.ComputeNode(context=self.context,
|
||||||
|
uuid=uuidsentinel.compute_node,
|
||||||
memory_mb=512, local_gb=1000, vcpus=8,
|
memory_mb=512, local_gb=1000, vcpus=8,
|
||||||
vcpus_used=0, local_gb_used=0,
|
vcpus_used=0, local_gb_used=0,
|
||||||
memory_mb_used=0, free_ram_mb=0,
|
memory_mb_used=0, free_ram_mb=0,
|
||||||
@ -33,111 +32,30 @@ class ComputeNodeTestCase(test.TestCase):
|
|||||||
ram_allocation_ratio=1.0,
|
ram_allocation_ratio=1.0,
|
||||||
disk_allocation_ratio=1.0)
|
disk_allocation_ratio=1.0)
|
||||||
|
|
||||||
@mock.patch('nova.objects.Service.get_minimum_version_multi')
|
def test_create_inventory(self):
|
||||||
def test_create_creates_inventories(self, mock_minver):
|
self.cn.create_inventory()
|
||||||
mock_minver.return_value = 10
|
objs = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||||
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(
|
|
||||||
self.context, self.cn.uuid)
|
self.context, self.cn.uuid)
|
||||||
self.assertEqual(3, len(inventories))
|
for obj in objs:
|
||||||
inv = {i.resource_class: i.total for i in inventories}
|
if obj.resource_class == fields.ResourceClass.VCPU:
|
||||||
expected = {
|
self.assertEqual(8, obj.total)
|
||||||
fields.ResourceClass.DISK_GB: 1000,
|
elif obj.resource_class == fields.ResourceClass.MEMORY_MB:
|
||||||
fields.ResourceClass.MEMORY_MB: 512,
|
self.assertEqual(512, obj.total)
|
||||||
fields.ResourceClass.VCPU: 8,
|
elif obj.resource_class == fields.ResourceClass.DISK_GB:
|
||||||
}
|
self.assertEqual(1000, obj.total)
|
||||||
self.assertEqual(expected, inv)
|
|
||||||
|
|
||||||
@mock.patch('nova.objects.Service.get_minimum_version_multi')
|
def test_update_inventory(self):
|
||||||
def test_save_updates_inventories(self, mock_minver):
|
self.cn.create_inventory()
|
||||||
mock_minver.return_value = 10
|
self.cn.memory_mb = 1024
|
||||||
self.cn.create()
|
|
||||||
self.cn.memory_mb = 2048
|
|
||||||
self.cn.local_gb = 2000
|
self.cn.local_gb = 2000
|
||||||
self.cn.save()
|
self.cn.vcpus = 16
|
||||||
self.assertEqual(2048, self.cn.memory_mb)
|
self.cn.update_inventory()
|
||||||
self.assertEqual(2000, self.cn.local_gb)
|
objs = objects.InventoryList.get_all_by_resource_provider_uuid(
|
||||||
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.context, self.cn.uuid)
|
||||||
self.assertEqual(3, len(inventories))
|
for obj in objs:
|
||||||
inv = {i.resource_class: i.total for i in inventories}
|
if obj.resource_class == fields.ResourceClass.VCPU:
|
||||||
expected = {
|
self.assertEqual(16, obj.total)
|
||||||
fields.ResourceClass.DISK_GB: 2000,
|
elif obj.resource_class == fields.ResourceClass.MEMORY_MB:
|
||||||
fields.ResourceClass.MEMORY_MB: 2048,
|
self.assertEqual(1024, obj.total)
|
||||||
fields.ResourceClass.VCPU: 8,
|
elif obj.resource_class == fields.ResourceClass.DISK_GB:
|
||||||
}
|
self.assertEqual(2000, obj.total)
|
||||||
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))
|
|
||||||
|
@ -36,6 +36,7 @@ class ResourceProviderTestCase(test.NoDBTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ResourceProviderTestCase, self).setUp()
|
super(ResourceProviderTestCase, self).setUp()
|
||||||
self.useFixture(fixtures.Database())
|
self.useFixture(fixtures.Database())
|
||||||
|
self.useFixture(fixtures.Database(database='api'))
|
||||||
self.context = context.RequestContext('fake-user', 'fake-project')
|
self.context = context.RequestContext('fake-user', 'fake-project')
|
||||||
|
|
||||||
def test_create_resource_provider_requires_uuid(self):
|
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.Instance.save')
|
||||||
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
|
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
|
||||||
return_value=objects.InstancePCIRequests(requests=[]))
|
return_value=objects.InstancePCIRequests(requests=[]))
|
||||||
@mock.patch('nova.objects.ComputeNode._create_inventory')
|
def test_additive_claims(self, mock_get, mock_save):
|
||||||
def test_additive_claims(self, mock_ci, mock_get, mock_save):
|
|
||||||
|
|
||||||
limits = self._limits(
|
limits = self._limits(
|
||||||
2 * FAKE_VIRT_MEMORY_WITH_OVERHEAD,
|
2 * FAKE_VIRT_MEMORY_WITH_OVERHEAD,
|
||||||
@ -797,8 +796,7 @@ class _MoveClaimTestCase(BaseTrackerTestCase):
|
|||||||
@mock.patch('nova.objects.Instance.save')
|
@mock.patch('nova.objects.Instance.save')
|
||||||
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
|
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
|
||||||
return_value=objects.InstancePCIRequests(requests=[]))
|
return_value=objects.InstancePCIRequests(requests=[]))
|
||||||
@mock.patch('nova.objects.ComputeNode._create_inventory')
|
def test_move_type_not_tracked(self, mock_get, mock_save):
|
||||||
def test_move_type_not_tracked(self, mock_ci, mock_get, mock_save):
|
|
||||||
self.claim_method(self.context, self.instance, self.instance_type,
|
self.claim_method(self.context, self.instance, self.instance_type,
|
||||||
limits=self.limits, move_type="live-migration")
|
limits=self.limits, move_type="live-migration")
|
||||||
mock_save.assert_called_once_with()
|
mock_save.assert_called_once_with()
|
||||||
|
Loading…
Reference in New Issue
Block a user