Merge "Add compute_node ratio online data migration script"

This commit is contained in:
Zuul 2018-12-10 10:11:32 +00:00 committed by Gerrit Code Review
commit f21a428a69
4 changed files with 115 additions and 0 deletions

View File

@ -59,6 +59,7 @@ from nova.i18n import _
from nova import objects from nova import objects
from nova.objects import block_device as block_device_obj from nova.objects import block_device as block_device_obj
from nova.objects import build_request as build_request_obj from nova.objects import build_request as build_request_obj
from nova.objects import compute_node as compute_node_obj
from nova.objects import host_mapping as host_mapping_obj from nova.objects import host_mapping as host_mapping_obj
from nova.objects import instance as instance_obj from nova.objects import instance as instance_obj
from nova.objects import instance_mapping as instance_mapping_obj from nova.objects import instance_mapping as instance_mapping_obj
@ -418,6 +419,8 @@ class DbCommands(object):
consumer_obj.create_incomplete_consumers, consumer_obj.create_incomplete_consumers,
# Added in Rocky # Added in Rocky
instance_mapping_obj.populate_queued_for_delete, instance_mapping_obj.populate_queued_for_delete,
# Added in Stein
compute_node_obj.migrate_empty_ratio,
) )
def __init__(self): def __init__(self):

View File

@ -16,6 +16,8 @@
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
from oslo_utils import versionutils from oslo_utils import versionutils
from sqlalchemy import or_
from sqlalchemy.sql import null
import nova.conf import nova.conf
from nova.db import api as db from nova.db import api as db
@ -469,3 +471,39 @@ class ComputeNodeList(base.ObjectListBase, base.NovaObject):
db_computes = cls._db_compute_node_get_by_hv_type(context, hv_type) db_computes = cls._db_compute_node_get_by_hv_type(context, hv_type)
return base.obj_make_list(context, cls(context), objects.ComputeNode, return base.obj_make_list(context, cls(context), objects.ComputeNode,
db_computes) db_computes)
def _get_node_empty_ratio(context, max_count):
"""Query the DB for non-deleted compute_nodes with 0.0/None alloc ratios
Results are limited by ``max_count``.
"""
return context.session.query(models.ComputeNode).filter(or_(
models.ComputeNode.ram_allocation_ratio == '0.0',
models.ComputeNode.cpu_allocation_ratio == '0.0',
models.ComputeNode.disk_allocation_ratio == '0.0',
models.ComputeNode.ram_allocation_ratio == null(),
models.ComputeNode.cpu_allocation_ratio == null(),
models.ComputeNode.disk_allocation_ratio == null()
)).filter(models.ComputeNode.deleted == 0).limit(max_count).all()
@sa_api.pick_context_manager_writer
def migrate_empty_ratio(context, max_count):
cns = _get_node_empty_ratio(context, max_count)
# NOTE(yikun): If it's an existing record with 0.0 or None values,
# we need to migrate this record using 'xxx_allocation_ratio' config
# if it's set, and fallback to use the 'initial_xxx_allocation_ratio'
# otherwise.
for cn in cns:
for t in ['cpu', 'disk', 'ram']:
current_ratio = getattr(cn, '%s_allocation_ratio' % t)
if current_ratio in (0.0, None):
r = getattr(CONF, "%s_allocation_ratio" % t)
init_x_ratio = getattr(CONF, "initial_%s_allocation_ratio" % t)
conf_alloc_ratio = r if r else init_x_ratio
setattr(cn, '%s_allocation_ratio' % t, conf_alloc_ratio)
context.session.add(cn)
found = done = len(cns)
return found, done

View File

@ -15,6 +15,7 @@ import nova.conf
from nova import context from nova import context
from nova.db import api as db from nova.db import api as db
from nova import objects from nova import objects
from nova.objects import compute_node
from nova.objects import fields as obj_fields from nova.objects import fields as obj_fields
from nova import test from nova import test
@ -188,3 +189,71 @@ class ComputeNodeTestCase(test.TestCase):
# the ram ratio is refreshed to CONF.initial_xxx_allocation_ratio # the ram ratio is refreshed to CONF.initial_xxx_allocation_ratio
self.assertEqual(CONF.initial_ram_allocation_ratio, self.assertEqual(CONF.initial_ram_allocation_ratio,
cn['ram_allocation_ratio']) cn['ram_allocation_ratio'])
def test_migrate_empty_ratio(self):
# we have 5 records to process, the last of which is deleted
for i in range(5):
cn = fake_compute_obj.obj_clone()
cn._context = self.context
cn.host += '-alt-%s' % i
cn.create()
db.compute_node_update(self.context, cn.id,
{'cpu_allocation_ratio': 0.0})
if i == 4:
cn.destroy()
# first only process 2
res = compute_node.migrate_empty_ratio(self.context, 2)
self.assertEqual(res, (2, 2))
# then process others - there should only be 2 found since one
# of the remaining compute nodes is deleted and gets filtered out
res = compute_node.migrate_empty_ratio(self.context, 999)
self.assertEqual(res, (2, 2))
def test_migrate_none_or_zero_ratio_with_none_ratio_conf(self):
cn1 = fake_compute_obj.obj_clone()
cn1._context = self.context
cn1.create()
db.compute_node_update(self.context, cn1.id,
{'cpu_allocation_ratio': 0.0,
'disk_allocation_ratio': 0.0,
'ram_allocation_ratio': 0.0})
self.flags(initial_cpu_allocation_ratio=32.0)
self.flags(initial_ram_allocation_ratio=8.0)
self.flags(initial_disk_allocation_ratio=2.0)
res = compute_node.migrate_empty_ratio(self.context, 1)
self.assertEqual(res, (1, 1))
# the ratio is refreshed to CONF.initial_xxx_allocation_ratio
# beacause CONF.xxx_allocation_ratio is None
cns = db.compute_node_get_all(self.context)
# the ratio is refreshed to CONF.xxx_allocation_ratio
for cn in cns:
for x in ['cpu', 'disk', 'ram']:
conf_key = 'initial_%s_allocation_ratio' % x
key = '%s_allocation_ratio' % x
self.assertEqual(getattr(CONF, conf_key), cn[key])
def test_migrate_none_or_zero_ratio_with_not_empty_ratio(self):
cn1 = fake_compute_obj.obj_clone()
cn1._context = self.context
cn1.create()
db.compute_node_update(self.context, cn1.id,
{'cpu_allocation_ratio': 32.0,
'ram_allocation_ratio': 4.0,
'disk_allocation_ratio': 3.0})
res = compute_node.migrate_empty_ratio(self.context, 1)
# the non-empty ratio will not be refreshed
self.assertEqual(res, (0, 0))
cns = db.compute_node_get_all(self.context)
for cn in cns:
self.assertEqual(32.0, cn['cpu_allocation_ratio'])
self.assertEqual(4.0, cn['ram_allocation_ratio'])
self.assertEqual(3.0, cn['disk_allocation_ratio'])

View File

@ -17,6 +17,11 @@ upgrade:
initially creating the ``computes_nodes`` table record for a given initially creating the ``computes_nodes`` table record for a given
nova-compute service. nova-compute service.
Existing ``compute_nodes`` table records with ``0.0`` or ``None`` values
for ``cpu_allocation_ratio``, ``ram_allocation_ratio`` or
``disk_allocation_ratio`` will be migrated online when accessed or when
the ``nova-manage db online_data_migrations`` command is run.
For more details, refer to the `spec`__. For more details, refer to the `spec`__.
.. __: https://specs.openstack.org/openstack/nova-specs/specs/stein/approved/initial-allocation-ratios.html .. __: https://specs.openstack.org/openstack/nova-specs/specs/stein/approved/initial-allocation-ratios.html