Add test for different amount of pinned CPU
This testgroup should be run with this parameters: export KVM_USE=True export SLAVE_NODE_CPU=6 export DRIVER_ENABLE_ACPI=true export NUMA_NODES=2 Change-Id: Ida99b43992c854db33eab8c60ca52b0b73297f08 Implements: blueprint test-numa-cpu-pinning
This commit is contained in:
parent
7113129b1a
commit
338c465370
@ -202,14 +202,26 @@ class Common(object):
|
|||||||
self.nova.servers.delete(server)
|
self.nova.servers.delete(server)
|
||||||
|
|
||||||
def create_flavor(self, name, ram, vcpus, disk, flavorid="auto",
|
def create_flavor(self, name, ram, vcpus, disk, flavorid="auto",
|
||||||
ephemeral=0):
|
ephemeral=0, extra_specs=None):
|
||||||
flavor = self.nova.flavors.create(name, ram, vcpus, disk, flavorid,
|
flavor = self.nova.flavors.create(name, ram, vcpus, disk, flavorid,
|
||||||
ephemeral=ephemeral)
|
ephemeral=ephemeral)
|
||||||
|
if extra_specs:
|
||||||
|
flavor.set_keys(extra_specs)
|
||||||
return flavor
|
return flavor
|
||||||
|
|
||||||
def delete_flavor(self, flavor):
|
def delete_flavor(self, flavor):
|
||||||
return self.nova.flavors.delete(flavor)
|
return self.nova.flavors.delete(flavor)
|
||||||
|
|
||||||
|
def create_aggregate(self, name, availability_zone=None,
|
||||||
|
metadata=None, hosts=None):
|
||||||
|
aggregate = self.nova.aggregates.create(
|
||||||
|
name=name, availability_zone=availability_zone)
|
||||||
|
for host in hosts or []:
|
||||||
|
aggregate.add_host(host)
|
||||||
|
if metadata:
|
||||||
|
aggregate.set_metadata(metadata)
|
||||||
|
return aggregate
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_keystoneclient(username, password, tenant_name, auth_url,
|
def _get_keystoneclient(username, password, tenant_name, auth_url,
|
||||||
retries=3, ca_cert=None, insecure=False):
|
retries=3, ca_cert=None, insecure=False):
|
||||||
|
@ -30,13 +30,17 @@ TIME_ZONE = 'UTC'
|
|||||||
ENV_NAME = os.environ.get("ENV_NAME", "fuel_system_test")
|
ENV_NAME = os.environ.get("ENV_NAME", "fuel_system_test")
|
||||||
VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", "")
|
VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", "")
|
||||||
|
|
||||||
|
ACPI_ENABLE = get_var_as_bool('DRIVER_ENABLE_ACPI', False)
|
||||||
|
|
||||||
|
nic_name_mask = 'enp0s{}' if not ACPI_ENABLE else 'ens{}'
|
||||||
|
|
||||||
INTERFACES_DICT = {
|
INTERFACES_DICT = {
|
||||||
'eth0': os.environ.get('IFACE_0', 'enp0s3'),
|
'eth0': os.environ.get('IFACE_0', nic_name_mask.format(3)),
|
||||||
'eth1': os.environ.get('IFACE_1', 'enp0s4'),
|
'eth1': os.environ.get('IFACE_1', nic_name_mask.format(4)),
|
||||||
'eth2': os.environ.get('IFACE_2', 'enp0s5'),
|
'eth2': os.environ.get('IFACE_2', nic_name_mask.format(5)),
|
||||||
'eth3': os.environ.get('IFACE_3', 'enp0s6'),
|
'eth3': os.environ.get('IFACE_3', nic_name_mask.format(6)),
|
||||||
'eth4': os.environ.get('IFACE_4', 'enp0s7'),
|
'eth4': os.environ.get('IFACE_4', nic_name_mask.format(7)),
|
||||||
'eth5': os.environ.get('IFACE_5', 'enp0s8'),
|
'eth5': os.environ.get('IFACE_5', nic_name_mask.format(8)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -98,6 +102,7 @@ HARDWARE = {
|
|||||||
"admin_node_memory": os.environ.get("ADMIN_NODE_MEMORY", 3072),
|
"admin_node_memory": os.environ.get("ADMIN_NODE_MEMORY", 3072),
|
||||||
"admin_node_cpu": os.environ.get("ADMIN_NODE_CPU", 2),
|
"admin_node_cpu": os.environ.get("ADMIN_NODE_CPU", 2),
|
||||||
"slave_node_cpu": os.environ.get("SLAVE_NODE_CPU", 1),
|
"slave_node_cpu": os.environ.get("SLAVE_NODE_CPU", 1),
|
||||||
|
"numa_nodes": os.environ.get("NUMA_NODES", 0),
|
||||||
}
|
}
|
||||||
if OPENSTACK_RELEASE_UBUNTU in OPENSTACK_RELEASE:
|
if OPENSTACK_RELEASE_UBUNTU in OPENSTACK_RELEASE:
|
||||||
slave_mem_default = 2560
|
slave_mem_default = 2560
|
||||||
|
@ -12,21 +12,101 @@
|
|||||||
# 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 random
|
||||||
|
|
||||||
from proboscis import asserts
|
from proboscis import asserts
|
||||||
from proboscis import test
|
from proboscis import test
|
||||||
|
|
||||||
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
||||||
|
from fuelweb_test.helpers import os_actions
|
||||||
from fuelweb_test.helpers import utils
|
from fuelweb_test.helpers import utils
|
||||||
from fuelweb_test import logger
|
from fuelweb_test import logger
|
||||||
|
from fuelweb_test import logwrap
|
||||||
from fuelweb_test import settings
|
from fuelweb_test import settings
|
||||||
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
from fuelweb_test.tests.base_test_case import SetupEnvironment
|
||||||
from fuelweb_test.tests.base_test_case import TestBasic
|
from fuelweb_test.tests.base_test_case import TestBasic
|
||||||
|
from gates_tests.helpers import exceptions
|
||||||
|
|
||||||
|
|
||||||
@test(groups=["numa_cpu_pinning"])
|
@test(groups=["numa_cpu_pinning"])
|
||||||
class NumaCpuPinning(TestBasic):
|
class NumaCpuPinning(TestBasic):
|
||||||
"""NumaCpuPinning."""
|
"""NumaCpuPinning."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@logwrap
|
||||||
|
def assert_entry_in_config(conf, conf_name, section, option, value):
|
||||||
|
"""Check entry of parameter with a proper value.
|
||||||
|
|
||||||
|
:param conf: a ConfigParser object
|
||||||
|
:param conf_name: a string of full file path
|
||||||
|
:param section: a string of section name in configuration file
|
||||||
|
:param option: a string of option name in configuration file
|
||||||
|
:param value: a string of value that has entry in configuration file
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
current_value = conf.get(section, option)
|
||||||
|
asserts.assert_true(value in current_value,
|
||||||
|
'Expected that the option "{0}" contains value '
|
||||||
|
'"{1}" in config file "{2}", but actually has '
|
||||||
|
'value "{3}": FAIL'.format(option,
|
||||||
|
value,
|
||||||
|
conf_name,
|
||||||
|
current_value))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@logwrap
|
||||||
|
def assert_quantity_in_config(conf, conf_name, section, option,
|
||||||
|
value):
|
||||||
|
"""Check number of parameters in option section.
|
||||||
|
|
||||||
|
:param conf: a ConfigParser object
|
||||||
|
:param conf_name: a string of full file path
|
||||||
|
:param section: a string of section name in configuration file
|
||||||
|
:param option: a string of option name in configuration file
|
||||||
|
:param value: an int number of values in specific option
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
current_value = conf.get(section, option)
|
||||||
|
asserts.assert_equal(len(current_value.split(',')), value,
|
||||||
|
'Expected that the option "{0}" has "{1}"'
|
||||||
|
'values in config file {2} but actually has '
|
||||||
|
'value "{3}": FAIL'.format(option,
|
||||||
|
value,
|
||||||
|
conf_name,
|
||||||
|
current_value))
|
||||||
|
|
||||||
|
@logwrap
|
||||||
|
def create_pinned_instance(self, os_conn, cluster_id,
|
||||||
|
name, vcpus, hostname, meta):
|
||||||
|
"""Boot VM on specific compute with CPU pinning
|
||||||
|
|
||||||
|
:param os_conn: an object of connection to openstack services
|
||||||
|
:param cluster_id: an integer number of cluster id
|
||||||
|
:param name: a string name of flavor and aggregate
|
||||||
|
:param vcpus: an integer number of vcpus for flavor
|
||||||
|
:param hostname: a string fqdn name of compute
|
||||||
|
:param meta: a dict with metadata for aggregate
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
os_conn.create_aggregate(name, metadata=meta, hosts=[hostname])
|
||||||
|
|
||||||
|
extra_specs = {'aggregate_instance_extra_specs:pinned': 'true',
|
||||||
|
'hw:cpu_policy': 'dedicated'}
|
||||||
|
|
||||||
|
net_name = self.fuel_web.get_cluster_predefined_networks_name(
|
||||||
|
cluster_id)['private_net']
|
||||||
|
flavor_id = random.randint(10, 10000)
|
||||||
|
flavor = os_conn.create_flavor(name=name, ram=64, vcpus=vcpus, disk=1,
|
||||||
|
flavorid=flavor_id,
|
||||||
|
extra_specs=extra_specs)
|
||||||
|
|
||||||
|
server = os_conn.create_server_for_migration(neutron=True,
|
||||||
|
label=net_name,
|
||||||
|
flavor=flavor_id)
|
||||||
|
os_conn.verify_instance_status(server, 'ACTIVE')
|
||||||
|
os_conn.delete_instance(server)
|
||||||
|
os_conn.delete_flavor(flavor)
|
||||||
|
|
||||||
@test(depends_on=[SetupEnvironment.prepare_slaves_5],
|
@test(depends_on=[SetupEnvironment.prepare_slaves_5],
|
||||||
groups=["numa_cpu_pinning",
|
groups=["numa_cpu_pinning",
|
||||||
"basic_env_for_numa_cpu_pinning"])
|
"basic_env_for_numa_cpu_pinning"])
|
||||||
@ -46,14 +126,54 @@ class NumaCpuPinning(TestBasic):
|
|||||||
self.check_run(snapshot_name)
|
self.check_run(snapshot_name)
|
||||||
self.env.revert_snapshot("ready_with_5_slaves")
|
self.env.revert_snapshot("ready_with_5_slaves")
|
||||||
|
|
||||||
self.show_step(1, initialize=True)
|
# TODO(kdemina) Use commomn function for variables asserts
|
||||||
|
if not settings.KVM_USE:
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'KVM_USE', 'true')
|
||||||
|
|
||||||
|
if int(settings.HARDWARE['slave_node_cpu']) < 6:
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'SLAVE_NODE_CPU', 6)
|
||||||
|
|
||||||
|
if int(settings.HARDWARE['numa_nodes']) < 2:
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'NUMA_NODES', 2)
|
||||||
|
|
||||||
|
if not settings.INTERFACES_DICT['eth0'] == 'ens3':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_0', 'ens3')
|
||||||
|
|
||||||
|
if not settings.INTERFACES_DICT['eth1'] == 'ens4':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_1', 'ens4')
|
||||||
|
|
||||||
|
if not settings.INTERFACES_DICT['eth2'] == 'ens5':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_2', 'ens5')
|
||||||
|
|
||||||
|
elif not settings.INTERFACES_DICT['eth3'] == 'ens6':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_3', 'ens6')
|
||||||
|
|
||||||
|
elif not settings.INTERFACES_DICT['eth4'] == 'ens7':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_4', 'ens7')
|
||||||
|
|
||||||
|
elif not settings.INTERFACES_DICT['eth5'] == 'ens8':
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'IFACE_5', 'ens8')
|
||||||
|
|
||||||
|
elif not settings.ACPI_ENABLE:
|
||||||
|
raise exceptions.FuelQAVariableNotSet(
|
||||||
|
'DRIVER_ENABLE_ACPI', 'true')
|
||||||
|
|
||||||
|
self.show_step(1)
|
||||||
cluster_id = self.fuel_web.create_cluster(
|
cluster_id = self.fuel_web.create_cluster(
|
||||||
name=self.__class__.__name__,
|
name=self.__class__.__name__,
|
||||||
mode=settings.DEPLOYMENT_MODE,
|
mode=settings.DEPLOYMENT_MODE,
|
||||||
settings={
|
settings={
|
||||||
"net_provider": 'neutron',
|
"net_provider": 'neutron',
|
||||||
"net_segment_type": settings.NEUTRON_SEGMENT_TYPE,
|
"net_segment_type": settings.NEUTRON_SEGMENT_TYPE
|
||||||
"KVM_USE": True
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.show_step(2)
|
self.show_step(2)
|
||||||
@ -95,3 +215,132 @@ class NumaCpuPinning(TestBasic):
|
|||||||
logger.info("There is {0} NUMA nodes on node {1}".format(
|
logger.info("There is {0} NUMA nodes on node {1}".format(
|
||||||
numas_on_remote, target_node['ip']))
|
numas_on_remote, target_node['ip']))
|
||||||
self.env.make_snapshot(snapshot_name, is_make=True)
|
self.env.make_snapshot(snapshot_name, is_make=True)
|
||||||
|
|
||||||
|
@test(depends_on_groups=['basic_env_for_numa_cpu_pinning'],
|
||||||
|
groups=["cpu_pinning_on_two_compute"])
|
||||||
|
@log_snapshot_after_test
|
||||||
|
def cpu_pinning_on_two_compute(self):
|
||||||
|
"""Check different amount of pinned CPU
|
||||||
|
|
||||||
|
Scenario:
|
||||||
|
1. Revert snapshot "basic_env_for_numa_cpu_pinning"
|
||||||
|
2. Pin maximum CPU for the nova on the first compute
|
||||||
|
3. Pin minimun CPU for the nova on the second compute
|
||||||
|
4. Verify setting was successfully applied
|
||||||
|
5. Deploy cluster
|
||||||
|
6. Check new filters are enabled in nova.conf at controller
|
||||||
|
7. Check nova.conf contains pinned CPU at compute
|
||||||
|
8. Run OSTF
|
||||||
|
9. Boot VM with pinned CPU on the first compute
|
||||||
|
10. Boot VM with pinned CPU on the second compute
|
||||||
|
|
||||||
|
Snapshot: cpu_pinning_on_two_compute
|
||||||
|
"""
|
||||||
|
self.show_step(1)
|
||||||
|
self.env.revert_snapshot("basic_env_for_numa_cpu_pinning")
|
||||||
|
|
||||||
|
cluster_id = self.fuel_web.get_last_created_cluster()
|
||||||
|
|
||||||
|
self.show_step(2)
|
||||||
|
first_compute = self.fuel_web.get_nailgun_node_by_name('slave-01')
|
||||||
|
first_compute_cpu = first_compute['meta']['cpu']['total']
|
||||||
|
first_config = self.fuel_web.client.get_node_attributes(
|
||||||
|
first_compute['id'])
|
||||||
|
first_config['cpu_pinning']['nova']['value'] = first_compute_cpu - 1
|
||||||
|
self.fuel_web.client.upload_node_attributes(
|
||||||
|
first_config, first_compute['id'])
|
||||||
|
|
||||||
|
self.show_step(3)
|
||||||
|
second_compute = self.fuel_web.get_nailgun_node_by_name('slave-02')
|
||||||
|
second_config = self.fuel_web.client.get_node_attributes(
|
||||||
|
second_compute['id'])
|
||||||
|
second_config['cpu_pinning']['nova']['value'] = 1
|
||||||
|
self.fuel_web.client.upload_node_attributes(
|
||||||
|
second_config, second_compute['id'])
|
||||||
|
|
||||||
|
self.show_step(4)
|
||||||
|
first_config = self.fuel_web.client.get_node_attributes(
|
||||||
|
first_compute['id'])
|
||||||
|
asserts.assert_equal(
|
||||||
|
first_config['cpu_pinning']['nova']['value'],
|
||||||
|
first_compute_cpu - 1,
|
||||||
|
"CPU pinning wasn't applied on '{0}': "
|
||||||
|
"Expected value '{1}', actual '{2}'"
|
||||||
|
.format(first_compute['ip'], first_compute_cpu - 1,
|
||||||
|
first_config['cpu_pinning']['nova']['value']))
|
||||||
|
|
||||||
|
second_config = self.fuel_web.client.get_node_attributes(
|
||||||
|
second_compute['id'])
|
||||||
|
asserts.assert_equal(
|
||||||
|
second_config['cpu_pinning']['nova']['value'],
|
||||||
|
1,
|
||||||
|
"CPU pinning wasn't applied on '{0}': "
|
||||||
|
"Expected value '{1}', actual '{2}'"
|
||||||
|
.format(second_compute['ip'], 1,
|
||||||
|
second_config['cpu_pinning']['nova']['value']))
|
||||||
|
|
||||||
|
self.show_step(5)
|
||||||
|
self.fuel_web.deploy_cluster_wait(cluster_id)
|
||||||
|
|
||||||
|
self.show_step(6)
|
||||||
|
controllers = self.fuel_web.get_nailgun_cluster_nodes_by_roles(
|
||||||
|
cluster_id,
|
||||||
|
roles=['controller'])
|
||||||
|
|
||||||
|
nova_conf_path = "/etc/nova/nova.conf"
|
||||||
|
|
||||||
|
for controller in controllers:
|
||||||
|
nova_conf = utils.get_ini_config(self.ssh_manager.open_on_remote(
|
||||||
|
ip=controller['ip'],
|
||||||
|
path=nova_conf_path))
|
||||||
|
|
||||||
|
self.assert_entry_in_config(nova_conf,
|
||||||
|
nova_conf_path,
|
||||||
|
"DEFAULT",
|
||||||
|
"scheduler_default_filters",
|
||||||
|
"NUMATopologyFilter")
|
||||||
|
|
||||||
|
self.show_step(7)
|
||||||
|
|
||||||
|
nova_conf = utils.get_ini_config(self.ssh_manager.open_on_remote(
|
||||||
|
ip=first_compute['ip'],
|
||||||
|
path=nova_conf_path))
|
||||||
|
self.assert_quantity_in_config(nova_conf,
|
||||||
|
nova_conf_path,
|
||||||
|
"DEFAULT",
|
||||||
|
"vcpu_pin_set",
|
||||||
|
first_compute_cpu - 1)
|
||||||
|
|
||||||
|
nova_conf = utils.get_ini_config(self.ssh_manager.open_on_remote(
|
||||||
|
ip=second_compute['ip'],
|
||||||
|
path=nova_conf_path))
|
||||||
|
self.assert_quantity_in_config(nova_conf,
|
||||||
|
nova_conf_path,
|
||||||
|
"DEFAULT",
|
||||||
|
"vcpu_pin_set",
|
||||||
|
1)
|
||||||
|
|
||||||
|
self.show_step(8)
|
||||||
|
self.fuel_web.run_ostf(cluster_id=cluster_id)
|
||||||
|
|
||||||
|
self.show_step(9)
|
||||||
|
os_conn = os_actions.OpenStackActions(
|
||||||
|
self.fuel_web.get_public_vip(cluster_id))
|
||||||
|
|
||||||
|
meta = {'pinned': 'true'}
|
||||||
|
|
||||||
|
self.create_pinned_instance(os_conn=os_conn,
|
||||||
|
cluster_id=cluster_id,
|
||||||
|
name='cpu_3',
|
||||||
|
vcpus=3,
|
||||||
|
hostname=first_compute['fqdn'],
|
||||||
|
meta=meta)
|
||||||
|
self.show_step(10)
|
||||||
|
self.create_pinned_instance(os_conn=os_conn,
|
||||||
|
cluster_id=cluster_id,
|
||||||
|
name='cpu_1',
|
||||||
|
vcpus=1,
|
||||||
|
hostname=second_compute['fqdn'],
|
||||||
|
meta=meta)
|
||||||
|
|
||||||
|
self.env.make_snapshot("cpu_pinning_on_two_compute")
|
||||||
|
Loading…
Reference in New Issue
Block a user