virt: move get_cpuset_ids into nova.virt.hardware

The nova.virt.cpu module has a single helper method for
getting the instance vCPU pin list. The new module
nova.virt.hardware is intended to be a single place for
all helpers related to guest hardware configuration, so
it is a natural place for the get_cpuset_ids method.
Rename it to 'get_vcpu_pin_set' to slightly clarify its
purpose too.

Blueprint: virt-driver-numa-placement
Blueprint: virt-driver-cpu-pinning
Change-Id: Id106737dc40471e8d31fbc002256b70e0b6ad5f6
This commit is contained in:
Daniel P. Berrange
2014-07-07 12:40:07 +01:00
parent 850c408ad1
commit 8577b0fa31
6 changed files with 159 additions and 197 deletions

View File

@@ -1,108 +0,0 @@
# Copyright 2013 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova import exception
from nova import test
from nova.virt import cpu
class CpuSetTestCase(test.NoDBTestCase):
def test_get_cpuset_ids_none_returns_none(self):
self.flags(vcpu_pin_set=None)
cpuset_ids = cpu.get_cpuset_ids()
self.assertIsNone(cpuset_ids)
def test_get_cpuset_ids_valid_syntax_works(self):
self.flags(vcpu_pin_set="1")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set="1,2")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1, 2], cpuset_ids)
self.flags(vcpu_pin_set=", , 1 , ,, 2, ,")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1, 2], cpuset_ids)
self.flags(vcpu_pin_set="1-1")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set=" 1 - 1, 1 - 2 , 1 -3")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1, 2, 3], cpuset_ids)
self.flags(vcpu_pin_set="1,^2")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set="1-2, ^1")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([2], cpuset_ids)
self.flags(vcpu_pin_set="1-3,5,^2")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1, 3, 5], cpuset_ids)
self.flags(vcpu_pin_set=" 1 - 3 , ^2, 5")
cpuset_ids = cpu.get_cpuset_ids()
self.assertEqual([1, 3, 5], cpuset_ids)
def test_get_cpuset_ids_invalid_syntax_raises(self):
self.flags(vcpu_pin_set=" -1-3,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-3-,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="-3,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-3,5,^2^")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-3,5,^2-")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="--13,^^5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="a-3,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-a,5,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-3,b,^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="1-3,5,^c")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="3 - 1, 5 , ^ 2 ")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set=" 1,1, ^1")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set=" 1,^1,^1,2, ^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)
self.flags(vcpu_pin_set="^2")
self.assertRaises(exception.Invalid, cpu.get_cpuset_ids)

View File

@@ -23,6 +23,96 @@ class FakeFlavor():
self.extra_specs = extra_specs
class CpuSetTestCase(test.NoDBTestCase):
def test_get_vcpu_pin_set_none_returns_none(self):
self.flags(vcpu_pin_set=None)
cpuset_ids = hw.get_vcpu_pin_set()
self.assertIsNone(cpuset_ids)
def test_get_vcpu_pin_set_valid_syntax_works(self):
self.flags(vcpu_pin_set="1")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set="1,2")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1, 2], cpuset_ids)
self.flags(vcpu_pin_set=", , 1 , ,, 2, ,")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1, 2], cpuset_ids)
self.flags(vcpu_pin_set="1-1")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set=" 1 - 1, 1 - 2 , 1 -3")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1, 2, 3], cpuset_ids)
self.flags(vcpu_pin_set="1,^2")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1], cpuset_ids)
self.flags(vcpu_pin_set="1-2, ^1")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([2], cpuset_ids)
self.flags(vcpu_pin_set="1-3,5,^2")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1, 3, 5], cpuset_ids)
self.flags(vcpu_pin_set=" 1 - 3 , ^2, 5")
cpuset_ids = hw.get_vcpu_pin_set()
self.assertEqual([1, 3, 5], cpuset_ids)
def test_get_vcpu_pin_set_invalid_syntax_raises(self):
self.flags(vcpu_pin_set=" -1-3,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-3-,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="-3,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-3,5,^2^")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-3,5,^2-")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="--13,^^5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="a-3,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-a,5,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-3,b,^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="1-3,5,^c")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="3 - 1, 5 , ^ 2 ")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set=" 1,1, ^1")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set=" 1,^1,^1,2, ^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
self.flags(vcpu_pin_set="^2")
self.assertRaises(exception.Invalid, hw.get_vcpu_pin_set)
class VCPUTopologyTest(test.NoDBTestCase):
def test_validate_config(self):

View File

@@ -1,84 +0,0 @@
# Copyright 2013 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.config import cfg
from nova import exception
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
virt_cpu_opts = [
cfg.StrOpt('vcpu_pin_set',
help='Defines which pcpus that instance vcpus can use. '
'For example, "4-12,^8,15"'),
]
CONF = cfg.CONF
CONF.register_opts(virt_cpu_opts)
def get_cpuset_ids():
"""Parsing vcpu_pin_set config.
Returns a list of pcpu ids can be used by instances.
"""
if not CONF.vcpu_pin_set:
return None
cpuset_ids = set()
cpuset_reject_ids = set()
for rule in CONF.vcpu_pin_set.split(','):
rule = rule.strip()
# Handle multi ','
if len(rule) < 1:
continue
# Note the count limit in the .split() call
range_parts = rule.split('-', 1)
if len(range_parts) > 1:
# So, this was a range; start by converting the parts to ints
try:
start, end = [int(p.strip()) for p in range_parts]
except ValueError:
raise exception.Invalid(_("Invalid range expression %r")
% rule)
# Make sure it's a valid range
if start > end:
raise exception.Invalid(_("Invalid range expression %r")
% rule)
# Add available pcpu ids to set
cpuset_ids |= set(range(start, end + 1))
elif rule[0] == '^':
# Not a range, the rule is an exclusion rule; convert to int
try:
cpuset_reject_ids.add(int(rule[1:].strip()))
except ValueError:
raise exception.Invalid(_("Invalid exclusion "
"expression %r") % rule)
else:
# OK, a single PCPU to include; convert to int
try:
cpuset_ids.add(int(rule))
except ValueError:
raise exception.Invalid(_("Invalid inclusion "
"expression %r") % rule)
# Use sets to handle the exclusion rules for us
cpuset_ids -= cpuset_reject_ids
if not cpuset_ids:
raise exception.Invalid(_("No CPUs available after parsing %r") %
CONF.vcpu_pin_set)
# This will convert the set to a sorted list for us
return sorted(cpuset_ids)

View File

@@ -14,12 +14,77 @@
import collections
from oslo.config import cfg
from nova import exception
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
virt_cpu_opts = [
cfg.StrOpt('vcpu_pin_set',
help='Defines which pcpus that instance vcpus can use. '
'For example, "4-12,^8,15"'),
]
CONF = cfg.CONF
CONF.register_opts(virt_cpu_opts)
LOG = logging.getLogger(__name__)
def get_vcpu_pin_set():
"""Parsing vcpu_pin_set config.
Returns a list of pcpu ids can be used by instances.
"""
if not CONF.vcpu_pin_set:
return None
cpuset_ids = set()
cpuset_reject_ids = set()
for rule in CONF.vcpu_pin_set.split(','):
rule = rule.strip()
# Handle multi ','
if len(rule) < 1:
continue
# Note the count limit in the .split() call
range_parts = rule.split('-', 1)
if len(range_parts) > 1:
# So, this was a range; start by converting the parts to ints
try:
start, end = [int(p.strip()) for p in range_parts]
except ValueError:
raise exception.Invalid(_("Invalid range expression %r")
% rule)
# Make sure it's a valid range
if start > end:
raise exception.Invalid(_("Invalid range expression %r")
% rule)
# Add available pcpu ids to set
cpuset_ids |= set(range(start, end + 1))
elif rule[0] == '^':
# Not a range, the rule is an exclusion rule; convert to int
try:
cpuset_reject_ids.add(int(rule[1:].strip()))
except ValueError:
raise exception.Invalid(_("Invalid exclusion "
"expression %r") % rule)
else:
# OK, a single PCPU to include; convert to int
try:
cpuset_ids.add(int(rule))
except ValueError:
raise exception.Invalid(_("Invalid inclusion "
"expression %r") % rule)
# Use sets to handle the exclusion rules for us
cpuset_ids -= cpuset_reject_ids
if not cpuset_ids:
raise exception.Invalid(_("No CPUs available after parsing %r") %
CONF.vcpu_pin_set)
# This will convert the set to a sorted list for us
return sorted(cpuset_ids)
class VirtCPUTopology(object):
def __init__(self, sockets, cores, threads):

View File

@@ -81,7 +81,6 @@ from nova import utils
from nova import version
from nova.virt import block_device as driver_block_device
from nova.virt import configdrive
from nova.virt import cpu
from nova.virt.disk import api as disk
from nova.virt import driver
from nova.virt import event as virtevent
@@ -225,7 +224,7 @@ CONF.import_opt('use_cow_images', 'nova.virt.driver')
CONF.import_opt('live_migration_retry_count', 'nova.compute.manager')
CONF.import_opt('vncserver_proxyclient_address', 'nova.vnc')
CONF.import_opt('server_proxyclient_address', 'nova.spice', group='spice')
CONF.import_opt('vcpu_pin_set', 'nova.virt.cpu')
CONF.import_opt('vcpu_pin_set', 'nova.virt.hardware')
CONF.import_opt('vif_plugging_is_fatal', 'nova.virt.driver')
CONF.import_opt('vif_plugging_timeout', 'nova.virt.driver')
@@ -3762,7 +3761,7 @@ class LibvirtDriver(driver.ComputeDriver):
self._vcpu_total = total_pcpus
return self._vcpu_total
available_ids = cpu.get_cpuset_ids()
available_ids = hardware.get_vcpu_pin_set()
if available_ids[-1] >= total_pcpus:
raise exception.Invalid(_("Invalid vcpu_pin_set config, "
"out of hypervisor cpu range."))

View File

@@ -50,9 +50,9 @@ from nova.openstack.common import versionutils
from nova.openstack.common import xmlutils
from nova import utils
from nova.virt import configdrive
from nova.virt import cpu
from nova.virt.disk import api as disk
from nova.virt.disk.vfs import localfs as vfsimpl
from nova.virt import hardware
from nova.virt.xenapi import agent
from nova.virt.xenapi.image import utils as image_utils
from nova.virt.xenapi import volume_utils
@@ -240,7 +240,7 @@ def create_vm(session, instance, name_label, kernel, ramdisk,
# we need to specify both weight and cap for either to apply
vcpu_params = {"weight": str(vcpu_weight), "cap": "0"}
cpu_mask_list = cpu.get_cpuset_ids()
cpu_mask_list = hardware.get_vcpu_pin_set()
if cpu_mask_list:
cpu_mask = ",".join(str(cpu_id) for cpu_id in cpu_mask_list)
vcpu_params["mask"] = cpu_mask