diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 96dbee86..90990c97 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -18,15 +18,7 @@ function configure { iniset $TEMPEST_CONFIG whitebox rx_queue_size $WHITEBOX_RX_QUEUE_SIZE iniset $TEMPEST_CONFIG whitebox default_video_model $WHITEBOX_DEFAULT_VIDEO_MODEL iniset $TEMPEST_CONFIG whitebox max_disk_devices_to_attach $WHITEBOX_MAX_DISK_DEVICES_TO_ATTACH - - iniset $TEMPEST_CONFIG whitebox-nova-compute config_path "$WHITEBOX_NOVA_COMPUTE_CONFIG_PATH" - iniset $TEMPEST_CONFIG whitebox-nova-compute stop_command "$WHITEBOX_NOVA_COMPUTE_STOP_COMMAND" - iniset $TEMPEST_CONFIG whitebox-nova-compute start_command "$WHITEBOX_NOVA_COMPUTE_START_COMMAND" - - iniset $TEMPEST_CONFIG whitebox-libvirt start_command "$WHITEBOX_LIBVIRT_START_COMMAND" - iniset $TEMPEST_CONFIG whitebox-libvirt stop_command "$WHITEBOX_LIBVIRT_STOP_COMMAND" - iniset $TEMPEST_CONFIG whitebox-libvirt mask_command "$WHITEBOX_LIBVIRT_MASK_COMMAND" - iniset $TEMPEST_CONFIG whitebox-libvirt unmask_command "$WHITEBOX_LIBVIRT_UNMASK_COMMAND" + iniset $TEMPEST_CONFIG whitebox nodes_yaml $WHITEBOX_NODES_YAML iniset $TEMPEST_CONFIG whitebox-database user $DATABASE_USER iniset $TEMPEST_CONFIG whitebox-database password $DATABASE_PASSWORD diff --git a/devstack/settings b/devstack/settings index e5a13ca1..44881a7d 100644 --- a/devstack/settings +++ b/devstack/settings @@ -6,15 +6,7 @@ WHITEBOX_FILE_BACKED_MEMORY_SIZE=${WHITEBOX_FILE_BACKED_MEMORY_SIZE:-8192} WHITEBOX_RX_QUEUE_SIZE=${WHITEBOX_RX_QUEUE_SIZE:-1024} WHITEBOX_DEFAULT_VIDEO_MODEL=${WHITEBOX_DEFAULT_VIDEO_MODEL:-'virtio'} WHITEBOX_MAX_DISK_DEVICES_TO_ATTACH=${WHITEBOX_MAX_DISK_DEVICES_TO_ATTACH:-7} - -WHITEBOX_NOVA_COMPUTE_CONFIG_PATH=${WHITEBOX_NOVA_COMPUTE_CONFIG_PATH:-/etc/nova/nova-cpu.conf} -WHITEBOX_NOVA_COMPUTE_STOP_COMMAND=${WHITEBOX_NOVA_COMPUTE_STOP_COMMAND:-'systemctl stop devstack@n-cpu'} -WHITEBOX_NOVA_COMPUTE_START_COMMAND=${WHITEBOX_NOVA_COMPUTE_START_COMMAND:-'systemctl start devstack@n-cpu'} - -WHITEBOX_LIBVIRT_START_COMMAND=${WHITEBOX_LIBVIRT_START_COMMAND:-'systemctl start libvirtd'} -WHITEBOX_LIBVIRT_STOP_COMMAND=${WHITEBOX_LIBVIRT_STOP_COMMAND:-'systemctl stop libvirtd'} -WHITEBOX_LIBVIRT_MASK_COMMAND=${WHITEBOX_LIBVIRT_MASK_COMMAND:-'systemctl mask libvirtd'} -WHITEBOX_LIBVIRT_UNMASK_COMMAND=${WHITEBOX_LIBVIRT_UNMASK_COMMAND:-'systemctl unmask libvirtd'} +WHITEBOX_NODES_YAML=${WHITEBOX_NODES_YAML:-'/home/zuul/compute_nodes.yaml'} WHITEBOX_CPU_TOPOLOGY=${WHITEBOX_CPU_TOPOLOGY:-''} WHITEBOX_DEDICATED_CPUS_PER_NUMA=${WHITEBOX_DEDICATED_CPUS_PER_NUMA:-4} diff --git a/playbooks/templates/compute_nodes.yaml.j2 b/playbooks/templates/compute_nodes.yaml.j2 new file mode 100644 index 00000000..addc33f7 --- /dev/null +++ b/playbooks/templates/compute_nodes.yaml.j2 @@ -0,0 +1,13 @@ +{% for compute in computes -%} +{{ compute }}: + services: + libvirt: + start_command: 'systemctl start libvirtd' + stop_command: 'systemctl stop libvirtd' + mask_command: 'systemctl mask libvirtd' + unmask_command: 'systemctl unmask libvirtd' + nova-compute: + config_path: '/etc/nova/nova-cpu.conf' + start_command: 'systemctl start devstack@n-cpu' + stop_command: 'systemctl stop devstack@n-cpu' +{% endfor %} \ No newline at end of file diff --git a/playbooks/whitebox/pre.yaml b/playbooks/whitebox/pre.yaml index 55921a40..ba4dbe4b 100644 --- a/playbooks/whitebox/pre.yaml +++ b/playbooks/whitebox/pre.yaml @@ -26,4 +26,22 @@ name: copy-build-sshkey vars: ansible_become: yes - copy_sshkey_target_user: 'tempest' \ No newline at end of file + copy_sshkey_target_user: 'tempest' + + - name: Collect compute hostnames + set_fact: + computes: "{{ ansible_play_hosts_all|map('extract', hostvars, 'ansible_fqdn')|list }}" + run_once: true + + - name: Render compute_nodes.yaml template + template: + src: ../templates/compute_nodes.yaml.j2 + dest: /home/zuul/compute_nodes.yaml + run_once: true + delegate_to: controller + + - name: Output the rendered file at /home/zuul/compute_nodes.yaml + shell: | + cat /home/zuul/compute_nodes.yaml + run_once: true + delegate_to: controller \ No newline at end of file diff --git a/tox.ini b/tox.ini index 449bf47e..3e2552a9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.18.0 -envlist = pep8,py{36,38,39,310} +envlist = pep8 skip_missing_interpreters = True # Automatic envs (pyXX) will only use the python version appropriate to that # env and ignore basepython inherited from [testenv] if we set @@ -16,9 +16,6 @@ allowlist_externals = * deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt -commands = - find . -type f -name "*.pyc" -delete - stestr run {posargs} [testenv:pep8] commands = diff --git a/whitebox_tempest_plugin/api/compute/base.py b/whitebox_tempest_plugin/api/compute/base.py index cfe6b324..84a0f4ff 100644 --- a/whitebox_tempest_plugin/api/compute/base.py +++ b/whitebox_tempest_plugin/api/compute/base.py @@ -24,7 +24,6 @@ from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import test_utils from whitebox_tempest_plugin.services import clients -from whitebox_tempest_plugin import utils as whitebox_utils if six.PY2: import contextlib2 as contextlib @@ -125,17 +124,15 @@ class BaseWhiteboxComputeTest(base.BaseV2ComputeAdminTest): def get_server_xml(self, server_id): server = self.os_admin.servers_client.show_server(server_id)['server'] host = server['OS-EXT-SRV-ATTR:host'] - cntrlplane_addr = whitebox_utils.get_ctlplane_address(host) server_instance_name = server['OS-EXT-SRV-ATTR:instance_name'] - virshxml = clients.VirshXMLClient(cntrlplane_addr) + virshxml = clients.VirshXMLClient(host) xml = virshxml.dumpxml(server_instance_name) return ET.fromstring(xml) def get_server_blockdevice_path(self, server_id, device_name): host = self.get_host_for_server(server_id) - cntrlplane_addr = whitebox_utils.get_ctlplane_address(host) - virshxml = clients.VirshXMLClient(cntrlplane_addr) + virshxml = clients.VirshXMLClient(host) blklist = virshxml.domblklist(server_id).splitlines() source = None for line in blklist: diff --git a/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py b/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py index 9c002e4e..fd898966 100644 --- a/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py +++ b/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py @@ -277,7 +277,6 @@ class CPUThreadPolicyTest(BasePinningTest): """ siblings = {} - host = whitebox_utils.get_ctlplane_address(host) virshxml = clients.VirshXMLClient(host) capxml = virshxml.capabilities() root = ET.fromstring(capxml) diff --git a/whitebox_tempest_plugin/api/compute/test_rbd_direct_download.py b/whitebox_tempest_plugin/api/compute/test_rbd_direct_download.py index 3f8dc8f1..722f688a 100644 --- a/whitebox_tempest_plugin/api/compute/test_rbd_direct_download.py +++ b/whitebox_tempest_plugin/api/compute/test_rbd_direct_download.py @@ -19,7 +19,6 @@ from tempest import config from whitebox_tempest_plugin.api.compute import base from whitebox_tempest_plugin.services import clients -from whitebox_tempest_plugin.utils import get_ctlplane_address CONF = config.CONF LOG = logging.getLogger(__name__) @@ -66,8 +65,7 @@ class TestRBDDirectDownload(base.BaseWhiteboxComputeTest): log_query_string = f"Attempting to export RBD image: " \ f"[[]pool_name: {rbd_pool}[]] [[]image_uuid: " \ f"{image_id}[]]" - host_ip = get_ctlplane_address(host) - logs_client = clients.LogParserClient(host_ip) + logs_client = clients.LogParserClient(host) # Assert if log with specified image is found self.assertTrue(len(logs_client.parse(log_query_string))) path = self.get_server_blockdevice_path(server['id'], 'vda') diff --git a/whitebox_tempest_plugin/api/compute/test_volume_encryption.py b/whitebox_tempest_plugin/api/compute/test_volume_encryption.py index b73201e5..f6aad8c6 100644 --- a/whitebox_tempest_plugin/api/compute/test_volume_encryption.py +++ b/whitebox_tempest_plugin/api/compute/test_volume_encryption.py @@ -18,7 +18,6 @@ from tempest import config from whitebox_tempest_plugin.api.compute import base from whitebox_tempest_plugin.services.clients import QEMUImgClient -from whitebox_tempest_plugin.utils import get_ctlplane_address CONF = config.CONF LOG = logging.getLogger(__name__) @@ -107,7 +106,7 @@ class TestQEMUVolumeEncryption(base.BaseWhiteboxComputeTest): # Get volume details from qemu-img info with the previously generated # volume path - host = get_ctlplane_address(self.get_host_for_server(server['id'])) + host = self.get_host_for_server(server['id']) qemu_img_client = QEMUImgClient(host) qemu_info = qemu_img_client.info(path) diff --git a/whitebox_tempest_plugin/api/compute/test_volume_negative.py b/whitebox_tempest_plugin/api/compute/test_volume_negative.py index 0b5143ec..043fc584 100644 --- a/whitebox_tempest_plugin/api/compute/test_volume_negative.py +++ b/whitebox_tempest_plugin/api/compute/test_volume_negative.py @@ -22,7 +22,6 @@ from tempest import config from whitebox_tempest_plugin.api.compute import base from whitebox_tempest_plugin.services import clients -from whitebox_tempest_plugin import utils as whitebox_utils CONF = config.CONF @@ -71,8 +70,7 @@ class VolumesAdminNegativeTest(base.BaseWhiteboxComputeTest, self.assertGreater( len(disks_after_attach), len(disks_before_attach)) - host = whitebox_utils.get_ctlplane_address( - self.get_host_for_server(server['id'])) + host = self.get_host_for_server(server['id']) with clients.ServiceManager(host, 'libvirt').stopped(): # While this call to n-api will return successfully the underlying diff --git a/whitebox_tempest_plugin/config.py b/whitebox_tempest_plugin/config.py index 657de166..7a02cf11 100644 --- a/whitebox_tempest_plugin/config.py +++ b/whitebox_tempest_plugin/config.py @@ -22,6 +22,9 @@ general_group = cfg.OptGroup( title='General Whitebox Tempest plugin config options') general_opts = [ + cfg.StrOpt( + 'nodes_yaml', + help='File path to the yaml description file of the compute hosts '), cfg.StrOpt( 'ctlplane_ssh_username', help='Username to use when accessing controllers and/or compute hosts ' @@ -133,59 +136,13 @@ nova_compute_group = cfg.OptGroup( title='Config options to manage the nova-compute service') nova_compute_opts = [ - cfg.StrOpt( - 'config_path', - help='Path to the configuration file for the nova-compute service.'), - cfg.StrOpt( - 'start_command', - help='Command to start the nova-compute service, without any ' - 'privilege management (ie, no sudo).'), - cfg.StrOpt( - 'stop_command', - help='Command to stop the nova-compute service, without any ' - 'privilege management (ie, no sudo).'), cfg.StrOpt( 'log_query_command', default="journalctl", choices=["journalctl", "zgrep"], help="Name of the utility to run LogParserClient commands. " "Currently, supported values are 'journalctl' (default) " - "for devstack and 'zgrep' for TripleO"), -] - -libvirt_group = cfg.OptGroup( - name='whitebox-libvirt', - title='Config options to manage the libvirt service') - -libvirt_opts = [ - cfg.StrOpt( - 'start_command', - help='Command to start the libvirt service, without any ' - 'privilege management (ie, no sudo).'), - cfg.StrOpt( - 'stop_command', - help='Command to stop the libvirt service, without any ' - 'privilege management (ie, no sudo).', - deprecated_opts=[cfg.DeprecatedOpt('stop_command', - group='whitebox-nova-libvirt')]), - cfg.StrOpt( - 'mask_command', - help='In some situations (Ubuntu Focal, for example), libvirtd can ' - 'be activated by other systemd units even if it is stopped. ' - 'In such cases, it can be useful to mask a service (ie, disable ' - 'it completely) to prevent it from being started outside of our ' - 'control. This config options sets the command to mask libvirt. ' - 'If set, it will be executed after every stop command.'), - cfg.StrOpt( - 'unmask_command', - help='Similar to the mask_command option, this config options sets ' - 'the command to unmask libvirt. If set, it will be run before ' - 'every start command.'), - cfg.StrOpt( - 'libvirt_container_name', - default="nova_libvirt", - help='The container name to use when needing to interact with the ' - 'respective virsh command of the compute host'), + "for devstack and 'zgrep' for TripleO") ] database_group = cfg.OptGroup( diff --git a/whitebox_tempest_plugin/plugin.py b/whitebox_tempest_plugin/plugin.py index f93644fb..e36f6a7d 100644 --- a/whitebox_tempest_plugin/plugin.py +++ b/whitebox_tempest_plugin/plugin.py @@ -38,8 +38,6 @@ class WhiteboxTempestPlugin(plugins.TempestPlugin): whitebox_config.nova_compute_opts) config.register_opt_group(conf, whitebox_config.database_group, whitebox_config.database_opts) - config.register_opt_group(conf, whitebox_config.libvirt_group, - whitebox_config.libvirt_opts) config.register_opt_group(conf, whitebox_config.hardware_group, whitebox_config.hardware_opts) config.register_opt_group(conf, config.compute_features_group, @@ -50,8 +48,6 @@ class WhiteboxTempestPlugin(plugins.TempestPlugin): whitebox_config.general_opts), (whitebox_config.nova_compute_group.name, whitebox_config.nova_compute_opts), - (whitebox_config.libvirt_group.name, - whitebox_config.libvirt_opts), (whitebox_config.database_group.name, whitebox_config.database_opts), (whitebox_config.hardware_group.name, diff --git a/whitebox_tempest_plugin/services/clients.py b/whitebox_tempest_plugin/services/clients.py index 0c01ab66..9d29d975 100644 --- a/whitebox_tempest_plugin/services/clients.py +++ b/whitebox_tempest_plugin/services/clients.py @@ -36,10 +36,11 @@ LOG = logging.getLogger(__name__) class SSHClient(object): """A client to execute remote commands, based on tempest.lib.common.ssh.""" - def __init__(self, ctlplane_address): + def __init__(self, host): self.ssh_key = CONF.whitebox.ctlplane_ssh_private_key_path self.ssh_user = CONF.whitebox.ctlplane_ssh_username - self.ctlplane_address = ctlplane_address + self.host_parameters = whitebox_utils.get_host_details(host) + self.ctlplane_address = whitebox_utils.get_ctlplane_address(host) def execute(self, command, container_name=None, sudo=False): ssh_client = ssh.Client(self.ctlplane_address, self.ssh_user, @@ -59,9 +60,12 @@ class SSHClient(object): class VirshXMLClient(SSHClient): """A client to obtain libvirt XML from a remote host.""" - def __init__(self, ctlplane_address): - super(VirshXMLClient, self).__init__(ctlplane_address) - self.container_name = CONF.whitebox_libvirt.libvirt_container_name + def __init__(self, host): + super(VirshXMLClient, self).__init__(host) + service_dict = self.host_parameters.get('services', {}).get('libvirt') + if service_dict is None: + raise exceptions.MissingServiceSectionException(service='libvirt') + self.container_name = service_dict.get('container_name') def dumpxml(self, domain): command = 'virsh dumpxml %s' % domain @@ -96,7 +100,10 @@ class QEMUImgClient(SSHClient): def __init__(self, ctlplane_address): super(QEMUImgClient, self).__init__(ctlplane_address) - self.container_name = CONF.whitebox_libvirt.libvirt_container_name + service_dict = self.host_parameters.get('services', {}).get('libvirt') + if service_dict is None: + raise exceptions.MissingServiceSectionException(service='libvirt') + self.container_name = service_dict.get('container_name') def info(self, path): command = 'qemu-img info --output=json --force-share %s' % path @@ -120,15 +127,15 @@ class ServiceManager(SSHClient): this must match the binary in the Nova os-services API. """ super(ServiceManager, self).__init__(hostname) - conf = getattr(CONF, 'whitebox-%s' % service, None) - if conf is None: + service_dict = self.host_parameters.get('services', {}).get(service) + if service_dict is None: raise exceptions.MissingServiceSectionException(service=service) self.service = service - self.config_path = getattr(conf, 'config_path', None) - self.start_command = getattr(conf, 'start_command', None) - self.stop_command = getattr(conf, 'stop_command', None) - self.mask_command = getattr(conf, 'mask_command', None) - self.unmask_command = getattr(conf, 'unmask_command', None) + self.config_path = service_dict.get('config_path') + self.start_command = service_dict.get('start_command') + self.stop_command = service_dict.get('stop_command') + self.mask_command = service_dict.get('mask_command') + self.unmask_command = service_dict.get('unmask_command') @contextlib.contextmanager def config_options(self, *opts): @@ -222,10 +229,7 @@ class NovaServiceManager(ServiceManager): """ def __init__(self, host, service, services_client): - super(NovaServiceManager, self).__init__( - whitebox_utils.get_ctlplane_address(host), - service - ) + super(NovaServiceManager, self).__init__(host, service) self.services_client = services_client self.host = host diff --git a/whitebox_tempest_plugin/utils.py b/whitebox_tempest_plugin/utils.py index d90d8f4a..1e94afe4 100644 --- a/whitebox_tempest_plugin/utils.py +++ b/whitebox_tempest_plugin/utils.py @@ -17,6 +17,7 @@ import six from oslo_serialization import jsonutils from tempest import config from whitebox_tempest_plugin import exceptions +import yaml if six.PY2: import contextlib2 as contextlib @@ -24,6 +25,7 @@ else: import contextlib CONF = config.CONF +_nodes = None def normalize_json(json): @@ -70,3 +72,12 @@ def get_ctlplane_address(compute_hostname): return CONF.whitebox.ctlplane_addresses[compute_hostname] raise exceptions.CtrlplaneAddressResolutionError(host=compute_hostname) + + +def get_host_details(host): + global _nodes + if _nodes is None: + nodes_location = CONF.whitebox.nodes_yaml + with open(nodes_location, "r") as f: + _nodes = yaml.safe_load(f) + return _nodes.get(host)