Skip to content

Commit

Permalink
Merge "Add online migration for Instance.compute_id"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and openstack-gerrit committed Aug 1, 2023
2 parents 74a2da3 + 25be030 commit f0565e8
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 0 deletions.
2 changes: 2 additions & 0 deletions nova/cmd/manage.py
Expand Up @@ -185,6 +185,8 @@ class DbCommands(object):
instance_mapping_obj.populate_user_id,
# Added in Victoria
pci_device_obj.PciDevice.populate_dev_uuids,
# Added in 2023.2
instance_obj.populate_instance_compute_id,
)

@args('--local_cell', action='store_true',
Expand Down
25 changes: 25 additions & 0 deletions nova/objects/instance.py
Expand Up @@ -28,6 +28,7 @@
from nova import availability_zones as avail_zone
from nova.compute import task_states
from nova.compute import vm_states
from nova import context as nova_context
from nova.db.main import api as db
from nova.db.main import models
from nova import exception
Expand Down Expand Up @@ -1351,6 +1352,30 @@ def populate_missing_availability_zones(context, count):
return count_all, count_hit


@db.pick_context_manager_writer
def populate_instance_compute_id(context, count):
instances = (context.session.query(models.Instance).
filter(models.Instance.compute_id == None). # noqa E711
limit(count).all())
count_all = count_hit = 0
rd_context = nova_context.get_admin_context(read_deleted='yes')
for instance in instances:
count_all += 1
try:
node = objects.ComputeNode.get_by_host_and_nodename(rd_context,
instance.host,
instance.node)
except exception.ComputeHostNotFound:
LOG.error('Unable to migrate instance because host %s with '
'node %s not found', instance.host, instance.node,
instance=instance)
continue
instance.compute_id = node.id
instance.save(context.session)
count_hit += 1
return count_all, count_hit


@base.NovaObjectRegistry.register
class InstanceList(base.ObjectListBase, base.NovaObject):
# Version 2.0: Initial Version
Expand Down
58 changes: 58 additions & 0 deletions nova/tests/functional/db/test_instance.py
Expand Up @@ -18,6 +18,7 @@
from nova.db.main import api as db
from nova import objects
from nova import test
from nova import utils


class InstanceObjectTestCase(test.TestCase):
Expand Down Expand Up @@ -124,6 +125,63 @@ def test_populate_missing_availability_zones(self):
inst3 = objects.Instance.get_by_uuid(self.context, uuid3)
self.assertEqual('nova-test', inst3.availability_zone)

def test_populate_instance_compute_id(self):
# Create three test nodes, one deleted
node_values = dict(vcpus=10, memory_mb=1024, local_gb=10,
vcpus_used=0, memory_mb_used=0, local_gb_used=0,
hypervisor_type='libvirt', hypervisor_version='1',
cpu_info='')
node1 = objects.ComputeNode(context=self.context, host='fake_host1',
hypervisor_hostname='fake_node1',
**node_values)
node1.create()
node2 = objects.ComputeNode(context=self.context, host='fake_host2',
hypervisor_hostname='fake_node2',
**node_values)
node2.create()
node3 = objects.ComputeNode(context=self.context, host='fake_host3',
hypervisor_hostname='fake_node3',
**node_values)
node3.create()
node3.destroy()

# Create four test instances across the test nodes, including a
# deleted instance and one instance with a missing compute node.
self._create_instance(host='fake_host1', node='fake_node1',
compute_id=None)
self._create_instance(host='fake_host2', node='fake_node2',
compute_id=None)
self._create_instance(host='fake_host3', node='fake_node3',
compute_id=None)
to_delete = self._create_instance(host='fake_host1', node='fake_node1',
compute_id=None)
to_delete.destroy()
self._create_instance(host='fake_host4', node='fake_node4',
compute_id=None)

# Do the actual migration
count_all, count_hit = objects.instance.populate_instance_compute_id(
self.context, 10)

# We should have found all instances, and fixed all but one which
# has a node we cannot find
self.assertEqual(5, count_all)
self.assertEqual(4, count_hit)

with utils.temporary_mutation(self.context, read_deleted='yes'):
instances = objects.InstanceList.get_all(self.context)

# Make sure we found all the instances we expect, including the
# deleted one.
self.assertEqual(5, len(instances))

# Make sure they all have the compute_id set as we expect, including
# the one remaining None because the node is not found.
expected_nodes = {n.hypervisor_hostname: n.id
for n in [node1, node2, node3]}
for inst in instances:
self.assertEqual(inst.compute_id, expected_nodes.get(inst.node))

def test_get_count_by_hosts(self):
self._create_instance(host='fake_host1')
self._create_instance(host='fake_host1')
Expand Down

0 comments on commit f0565e8

Please sign in to comment.