Merge "Actively check type instead of WB_CONF.openstack_type"

This commit is contained in:
Zuul 2025-05-08 11:30:08 +00:00 committed by Gerrit Code Review
commit f72e0a2c76
14 changed files with 95 additions and 108 deletions

View File

@ -293,24 +293,10 @@ def wait_for_neutron_api(neutron_client, timeout=100):
common_utils.wait_until_true(_list_agents, timeout=timeout, sleep=1)
def get_neutron_api_service_name():
"""Return the Neutron API service name based on the test configuration"""
if WB_CONF.openstack_type == 'devstack':
# NOTE: in OSP18+, the Neutron API will use WSGI by default (not the
# eventlet server) and the name will be "neutron api"
return 'q svc'
else:
return 'neutron api'
def get_ml2_conf_file():
"""Neutron ML2 config file name depending on the installation type
The default value of WB_CONF.ml2_plugin_config is
'/etc/neutron/plugins/ml2/ml2_conf.ini'.
"""
if WB_CONF.openstack_type in ('podified', 'devstack'):
return WB_CONF.ml2_plugin_config
else:
return ('/var/lib/config-data/puppet-generated/neutron' +
WB_CONF.ml2_plugin_config)
return WB_CONF.ml2_plugin_config

View File

@ -38,10 +38,6 @@ WhiteboxNeutronPluginOptions = [
cfg.StrOpt('tester_key_file',
default='',
help='Key file to access host to execute validated commands.'),
cfg.StrOpt('openstack_type',
default='podified',
help='Type of openstack deployment, '
'e.g. devstack, podified'),
cfg.StrOpt('pki_private_key',
default='/etc/pki/tls/private/ovn_controller.key',
help='File with private key. Need for TLS-everywhere '

View File

@ -56,6 +56,12 @@ ConfigOption = collections.namedtuple(
class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
credentials = ['primary', 'admin']
# NOTE(mblue): change devstack check if CI must not use /opt/stack,
# currently used commonly for devstack jobs needed by plugin.
if 'is_devstack' not in locals():
is_devstack = bool(shell.execute(
'test -d /opt/stack && echo stack',
check=False).stdout.strip())
@classmethod
def resource_setup(cls):
@ -74,25 +80,36 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
sriov_agents = [
agent for agent in agents if 'sriov' in agent['binary']]
cls.has_sriov_support = True if sriov_agents else False
cls.neutron_conf = local_constants.NEUTRON_CONF[WB_CONF.openstack_type]
cls.neutron_conf = local_constants.NEUTRON_CONF[
'devstack' if cls.is_devstack else 'podified']
# deployer tool dependent variables
cls.setup_proxy_host()
if WB_CONF.openstack_type == 'podified':
if not cls.is_devstack:
cls.neutron_api_prefix = '{} rsh {} '.format(
cls.OC, cls.get_pods_of_service()[0])
cls.external_network = cls.os_admin.network_client.show_network(
CONF.network.public_network_id)['network']
@classmethod
def get_neutron_api_service_name(cls):
"""Return the Neutron API service name based on test configuration"""
if cls.is_devstack:
# NOTE: in OSP18+, the Neutron API will use WSGI by default (not
# the eventlet server) and the name will be "neutron api"
return 'q svc'
else:
return 'neutron api'
@classmethod
def setup_proxy_host(cls):
# proxy host commonly used for commands such as oc or openstack
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
cls.master_node_client = cls.get_node_client(
'localhost')
cls.master_cont_cmd_executor = \
cls.run_on_master_controller
cls.neutron_api_prefix = ''
elif WB_CONF.openstack_type == 'podified':
else:
cls.OC = "oc -n openstack "
cls.proxy_host_client = cls.get_node_client(
host=WB_CONF.proxy_host_address,
@ -105,20 +122,16 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
cls.master_node_client = cls.proxy_host_client
cls.master_cont_cmd_executor = \
cls.proxy_host_client.exec_command
else:
LOG.warning(("Unrecognized deployer tool '%s', plugin supports "
"openstack_type as devstack/podified.",
WB_CONF.openstack_type))
@classmethod
def run_on_master_controller(cls, cmd):
LOG.debug("Command: %s", cmd)
if WB_CONF.openstack_type == 'podified':
output = cls.proxy_host_client.exec_command(cmd)
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
output, errors = local_utils.run_local_cmd(cmd)
LOG.debug("Stderr: %s", errors.decode())
output = output.decode()
else:
output = cls.proxy_host_client.exec_command(cmd)
LOG.debug("Output: %s", output)
return output.strip()
@ -318,7 +331,7 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
compute_hosts = [
host['hypervisor_hostname'] for host
in cls.os_admin.hv_client.list_hypervisors()['hypervisors']]
if WB_CONF.openstack_type == 'podified':
if not cls.is_devstack:
cls.nodes_data = cls.get_podified_nodes_data()
with open(WB_CONF.proxy_host_key_file, 'r') as file:
id_cifw_key = file.read()
@ -346,7 +359,7 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
host['short_name'] = host['name'].split('.')[0]
host['is_compute'] = (host['name'] in compute_hosts)
host['is_networker'] = (host['name'] in l3_agent_hosts)
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
# Here we are checking if there are controller-specific
# processes running on the node
output = host['client'].exec_command(
@ -432,7 +445,7 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
"""
assert config_list, ("At least one configuration parameter must be "
"supplied")
if WB_CONF.openstack_type == 'podified' and node_type != 'compute':
if not cls.is_devstack and node_type != 'compute':
service_pod = cls.get_pods_of_service(service)[0]
# TODO(mblue): process ini in python instead of crudini command,
# without depending on hardcoded conf filenames, crudini bin in pod
@ -537,11 +550,11 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
"""
if WB_CONF.openstack_type == 'podified':
if cls.is_devstack:
service_prefix = ""
else:
service_prefix = "{} rsh {}".format(
cls.OC, cls.get_pods_of_service(service)[0])
else:
service_prefix = ""
cmd_prefix = "crudini --get"
# If we have config file with defaults and second one with overrides,
# the latter has the config that wins
@ -592,7 +605,7 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
def reset_node_service(cls, service_alias, ssh_client,
wait_until_active=True, timeout=30):
host_ip = ssh_client.host
service_name = (None if WB_CONF.openstack_type != 'podified'
service_name = (None if cls.is_devstack
else WB_CONF.dataplane_podified_services.get(
service_alias))
service_name = service_name or ssh_client.exec_command(
@ -814,13 +827,11 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
@classmethod
def get_osp_cmd_prefix(cls, admin=True):
# TODO(mblue): figure how admin used in podified setup when needed
if WB_CONF.openstack_type == 'podified':
prefix = '{} rsh openstackclient '.format(cls.OC)
elif WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
prefix = '. /opt/stack/devstack/openrc{} && '.format(
' admin' if admin else '')
else:
prefix = '. ~/overcloudrc && '
prefix = '{} rsh openstackclient '.format(cls.OC)
return prefix
@staticmethod
@ -1094,7 +1105,7 @@ class TrafficFlowTest(BaseTempestWhiteboxTestCase):
"for public network or public_network_id "
"is not configured.")
cls.discover_nodes()
if WB_CONF.openstack_type == 'podified':
if not cls.is_devstack:
cls.set_ovs_pods_for_nodes()
@classmethod
@ -1122,7 +1133,7 @@ class TrafficFlowTest(BaseTempestWhiteboxTestCase):
'- a compute\n'
'- a networker', node['name'])
continue
elif (WB_CONF.openstack_type == 'podified' and
elif (not self.is_devstack and
node.get('ovs_pod')):
capture_client = self.proxy_host_client
command_prefix = "{} rsh {} ".format(self.OC, node['ovs_pod'])
@ -1280,19 +1291,7 @@ class BaseTempestTestCaseOvn(BaseTempestWhiteboxTestCase):
@classmethod
def _get_ovn_db_monitor_cmds(cls):
monitorcmdprefix = 'timeout 300 ovsdb-client monitor -f json '
if WB_CONF.openstack_type == 'podified':
nb_monitor_connection_opts = cls.nbctl.replace(
'ovn-nbctl', '{} unix:/tmp/ovnnb_db.sock'.format(
monitorcmdprefix))
sb_monitor_connection_opts = cls.sbctl.replace(
'ovn-sbctl', '{} unix:/tmp/ovnsb_db.sock'.format(
monitorcmdprefix))
# strip --db parameter from connection opts since we're
# going to run monitoring via a local socket
return tuple(map(
lambda cmd: re.sub(r'--db=[^\s]+', '', cmd),
[nb_monitor_connection_opts, sb_monitor_connection_opts]))
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
regex = r'--db=(.*)$'
monitorcmdprefix = 'sudo ' + monitorcmdprefix
# this regex search will return the connection string
@ -1302,6 +1301,18 @@ class BaseTempestTestCaseOvn(BaseTempestWhiteboxTestCase):
sb_monitor_connection_opts = re.search(regex, cls.sbctl).group(1)
return (monitorcmdprefix + nb_monitor_connection_opts,
monitorcmdprefix + sb_monitor_connection_opts)
# if podified
nb_monitor_connection_opts = cls.nbctl.replace(
'ovn-nbctl', '{} unix:/tmp/ovnnb_db.sock'.format(
monitorcmdprefix))
sb_monitor_connection_opts = cls.sbctl.replace(
'ovn-sbctl', '{} unix:/tmp/ovnsb_db.sock'.format(
monitorcmdprefix))
# strip --db parameter from connection opts since we're
# going to run monitoring via a local socket
return tuple(map(
lambda cmd: re.sub(r'--db=[^\s]+', '', cmd),
[nb_monitor_connection_opts, sb_monitor_connection_opts]))
@classmethod
def get_podified_ovn_db_cmd(cls, db):
@ -1341,14 +1352,13 @@ class BaseTempestTestCaseOvn(BaseTempestWhiteboxTestCase):
@classmethod
def _get_ovn_dbs(cls):
if WB_CONF.openstack_type == 'podified':
return [cls.get_podified_ovn_db_cmd('nb'),
cls.get_podified_ovn_db_cmd('sb')]
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
sbdb = "unix:/var/run/ovn/ovnsb_db.sock"
nbdb = sbdb.replace('sb', 'nb')
cmd = "sudo ovn-{}ctl --db={}"
return [cmd.format('nb', nbdb), cmd.format('sb', sbdb)]
return [cls.get_podified_ovn_db_cmd('nb'),
cls.get_podified_ovn_db_cmd('sb')]
def get_router_gateway_chassis(self, router_port_id):
cmd = "{} get port_binding cr-lrp-{} chassis".format(

View File

@ -51,8 +51,8 @@ class NeutronAPIServerTest(wb_base.BaseTempestTestCaseOvn):
wait_res='deploy/neutron')
# 3) Restart Neutron API on all controllers simultaneously.
if not WB_CONF.openstack_type == 'podified':
service_ptn = wb_utils.get_neutron_api_service_name()
if self.is_devstack:
service_ptn = self.get_neutron_api_service_name()
for node in self.nodes:
if node['is_controller']:
# NOTE(mblue): if reset fails on multinode, consider

View File

@ -53,7 +53,7 @@ class OvnDvrBase(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
"The tests require environment with at least 2 nodes")
cls.bgp_expose_tenant_networks = False
for node in cls.nodes:
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
if not node['is_controller']:
continue
cls.check_service_setting(
@ -71,7 +71,7 @@ class OvnDvrBase(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
# TODO(rsafrono) add code that defines
# cls.bgp_expose_tenant_networks on devstack
# in case such bgp environment will be ever created
if WB_CONF.openstack_type == 'podified':
if not cls.is_devstack:
config_files = cls.get_configs_of_service()
cls.check_service_setting(
{'client': cls.proxy_host_client},

View File

@ -300,7 +300,7 @@ class InternalDNSInterruptionsAdvancedTestOvn(
@classmethod
def skip_checks(cls):
super(InternalDNSInterruptionsAdvancedTestOvn, cls).skip_checks()
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
raise cls.skipException(
"Devstack doesn't support powering nodes on/off, "
"skipping tests")

View File

@ -178,7 +178,7 @@ class L3haOvnCommon(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
def refresh_nodes_data(self):
self.discover_nodes()
if WB_CONF.openstack_type == 'podified':
if not self.is_devstack:
self.set_ovs_pods_for_nodes()

View File

@ -46,7 +46,7 @@ class TestMetadataRateLimiting(wb_base.BaseTempestWhiteboxTestCase):
cls.service_name = 'neutron l3 agent'
cls.metadata_nodes = [n for n in cls.nodes if cls.is_service_on_node(
cls.service_name, n['client'])]
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
cls.metadata_conf_file = (
'/etc/neutron/neutron_ovn_metadata_agent.ini')
else:

View File

@ -119,7 +119,7 @@ class GatewayMtuTest(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
def _validate_environment_config(self):
msg = "ovn_emit_need_to_frag is not set to 'true' in config file"
for node in self.nodes:
if WB_CONF.openstack_type == 'devstack':
if self.is_devstack:
if node['is_controller'] is False:
continue
else:
@ -128,7 +128,7 @@ class GatewayMtuTest(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
config_files=[WB_CONF.ml2_plugin_config],
section='ovn', param='ovn_emit_need_to_frag',
msg=msg)
if WB_CONF.openstack_type == 'podified':
if not self.is_devstack:
config_files = self.get_configs_of_service()
self.check_service_setting(
{'client': self.proxy_host_client},

View File

@ -61,8 +61,8 @@ class OvnFdbAgingTest(wb_base.BaseTempestTestCaseOvn):
wait_res='deploy/neutron')
# 2) restart neutron api on all controllers simultaneously
if not WB_CONF.openstack_type == 'podified':
service_ptn = wb_utils.get_neutron_api_service_name()
if self.is_devstack:
service_ptn = self.get_neutron_api_service_name()
for node in self.nodes:
if node['is_controller']:
# NOTE(mblue): if reset fails on multinode, consider

View File

@ -95,7 +95,7 @@ class QosBaseTest(test_qos.QoSTestMixin, base.TrafficFlowTest):
"nodes.")
msg = "Required QoS config is not set"
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
for node in cls.nodes:
if node['is_controller'] is False:
continue
@ -107,8 +107,7 @@ class QosBaseTest(test_qos.QoSTestMixin, base.TrafficFlowTest):
host=node, service='',
config_files=[WB_CONF.ml2_plugin_config], section='ml2',
param='extension_drivers', value='qos')
if WB_CONF.openstack_type == 'podified':
else:
config_files = cls.get_configs_of_service('neutron')
cls.check_service_setting(
{'client': cls.proxy_host_client}, service='neutron',
@ -1002,15 +1001,15 @@ class QosTestDscpInheritanceOvn(QosBaseTest, base.BaseTempestTestCaseOvn):
def test_dscp_inheritance_geneve(self):
cmd = "sudo ovs-vsctl get open . external_ids:ovn-encap-tos || true"
msg = "external_ids:ovn-encap-tos is not set to 'inherit'"
if WB_CONF.openstack_type == 'podified':
if self.is_devstack:
result = self.run_on_master_controller(cmd)
if 'inherit' not in result:
raise self.skipException(msg)
else:
for node in self.nodes:
result = node['client'].exec_command(cmd)
if 'inherit' not in result:
raise self.skipException(msg)
if WB_CONF.openstack_type == 'devstack':
result = self.run_on_master_controller(cmd)
if 'inherit' not in result:
raise self.skipException(msg)
self._check_dscp_inheritance()

View File

@ -49,19 +49,6 @@ class BaseSecGroupLoggingTest(
required_extensions = ['router', 'security-group', 'logging']
ML2_CONF_FILE = utils.get_ml2_conf_file()
if WB_CONF.openstack_type == 'podified':
SG_LOG_FILE = '/var/log/messages'
rotate_service_fix = '-crond'
elif WB_CONF.openstack_type == 'devstack':
SG_LOG_FILE = '/var/log/ovn/ovn-controller.log'
rotate_service_fix = ''
else:
SG_LOG_FILE = '/var/log/containers/stdouts/ovn_controller.log'
rotate_service_fix = '-crond'
ROTATION_CHECK_CMD = (
'/usr/sbin/logrotate -s /var/lib/logrotate/'
'logrotate{0}.status /etc/logrotate{0}.conf').format(
rotate_service_fix)
SSH_DROP_EXCEPTIONS = (lib_exc.SSHTimeout,
ssh_exc.NoValidConnectionsError,
ssh_exc.SSHException,
@ -113,6 +100,16 @@ class BaseSecGroupLoggingTest(
"""Setup resources for both classes of security group logging tests:
with either stateless/stateful security groups.
"""
if cls.is_devstack:
cls.sg_log_file = '/var/log/ovn/ovn-controller.log'
cls.rotate_service_fix = ''
else:
cls.sg_log_file = '/var/log/messages'
cls.rotate_service_fix = '-crond'
cls.rotation_check_cmd = (
'/usr/sbin/logrotate -s /var/lib/logrotate/'
'logrotate{0}.status /etc/logrotate{0}.conf').format(
cls.rotate_service_fix)
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
router = cls.create_router_by_client()
@ -223,14 +220,14 @@ class BaseSecGroupLoggingTest(
# tracks A value, before test traffic sent to be logged
_track_value = int(hypervisor_ssh.exec_command(
"sudo grep {} {} | tail -n1 | cut -d '|' -f 2"
.format(self.ENTRY_PTN, self.SG_LOG_FILE), timeout=120))
.format(self.ENTRY_PTN, self.sg_log_file), timeout=120))
self._hypervisors_counts[hypervisor_ssh.host]['A'] = _track_value
LOG.debug("Start log count value A on '%s' is %d",
hypervisor_ssh.host, _track_value)
else:
# tracks B value, after test traffic sent to be logged
cmd_outputs = hypervisor_ssh.exec_command(
"sudo grep {} {}".format(self.ENTRY_PTN, self.SG_LOG_FILE),
"sudo grep {} {}".format(self.ENTRY_PTN, self.sg_log_file),
timeout=120).splitlines()
b = self._hypervisors_counts[hypervisor_ssh.host]['B'] = int(
cmd_outputs[-1].split("|")[1])
@ -447,7 +444,7 @@ class BaseSecGroupLoggingTest(
# 7) output not expected
'']
# NOTE(mblue): devstack: Extensions list not supported by Identity API
if WB_CONF.openstack_type == 'devstack':
if self.is_devstack:
cmds.pop(0)
stdout_patterns.pop(0)
for cmd, ptn in zip(cmds, stdout_patterns):
@ -486,8 +483,8 @@ class BaseSecGroupLoggingTest(
config_list=config_list,
wait_res='deploy/neutron')
# 5) restart neutron api on all controllers simultaneously
if not WB_CONF.openstack_type == 'podified':
service_ptn = utils.get_neutron_api_service_name()
if self.is_devstack:
service_ptn = self.get_neutron_api_service_name()
for node in self.nodes:
if node['is_controller']:
# NOTE(mblue): if reset fails on multinode, consider
@ -619,7 +616,7 @@ class BaseSecGroupLoggingTest(
self.verify_meter_and_band_amounts((1, 2), (1, 2))
# 12) verify same logging SGRs/ACLs amount linked to relevant meter
# NOTE(mblue): devstack ACLs for stateless SG with another meter name
if WB_CONF.openstack_type == 'devstack' and \
if self.is_devstack and \
not self.is_secgrp_stateful:
meter_postfix = '.log_stateless"'
else:
@ -765,7 +762,7 @@ class BaseSecGroupLoggingTest(
(17, 19, 24).
"""
vm_a = self._create_server()
if WB_CONF.openstack_type == 'devstack':
if self.is_devstack:
rotate_prefix = 'sudo '
else:
rotate_prefix = 'sudo podman exec logrotate_crond '
@ -806,7 +803,7 @@ class BaseSecGroupLoggingTest(
ssh_client=vm_a['hv_ssh_client']).rstrip().split(' ')[-1]
# if setup type supports log rotation due to size, then test.
# also skips rotation test on podified since logging to journal
if maxsize_si and WB_CONF.openstack_type != 'podified':
if maxsize_si and self.is_devstack:
# convert to bytes without SI prefixes k/M/G (logrotate SI options)
try:
power = 10 * ('kMG'.index(maxsize_si[-1]) + 1)
@ -818,28 +815,28 @@ class BaseSecGroupLoggingTest(
overflow_size = maxsize + 1
# 13) force check if log rotation needed (before test start)
self.validate_command(
rotate_prefix + self.ROTATION_CHECK_CMD,
rotate_prefix + self.rotation_check_cmd,
ssh_client=vm_a['hv_ssh_client'])
# current active log file size in bytes (before size overflow)
active_log_pre_overflow = int(self.validate_command(
'sudo wc -c {}'.format(self.SG_LOG_FILE),
'sudo wc -c {}'.format(self.sg_log_file),
ssh_client=vm_a['hv_ssh_client']).split()[0])
# 14) adding bytes into active log file to pass 'maxsize' value
self.validate_command(('''python3 -c "print('A'*{})" | '''
'sudo tee -a {} 1> /dev/null').format(
overflow_size, self.SG_LOG_FILE),
overflow_size, self.sg_log_file),
ssh_client=vm_a['hv_ssh_client'])
# 15) force check if log rotation is needed
self.validate_command(
rotate_prefix + self.ROTATION_CHECK_CMD,
rotate_prefix + self.rotation_check_cmd,
ssh_client=vm_a['hv_ssh_client'])
# current active log file size in bytes (after size overflow)
active_log_post_overflow = int(self.validate_command(
'sudo wc -c {}'.format(self.SG_LOG_FILE),
'sudo wc -c {}'.format(self.sg_log_file),
ssh_client=vm_a['hv_ssh_client']).split()[0])
# new rotated log file size in bytes (after size overflow)
rotated_log_post_overflow = int(self.validate_command(
'sudo wc -c {}'.format(self.SG_LOG_FILE + '.1'),
'sudo wc -c {}'.format(self.sg_log_file + '.1'),
ssh_client=vm_a['hv_ssh_client']).split()[0])
# 16) verify log rotation succesful:
# - current new active log has a small size (below 'offset').

View File

@ -68,7 +68,7 @@ class ProviderNetworkSriovBaseTest(base.ProviderBaseTest):
CONF.neutron_plugin_options.default_image_is_advanced):
raise cls.skipException(
'Advanced image is required to run these tests.')
if WB_CONF.openstack_type == 'devstack':
if cls.is_devstack:
raise cls.skipException("The tests are currently not supported "
"on devstack environment")

View File

@ -214,7 +214,6 @@
available_type_drivers: flat,geneve,vlan,gre,local,vxlan
provider_net_base_segm_id: 1
whitebox_neutron_plugin_options:
openstack_type: devstack
broadcast_receivers_count: 1
compute-feature-enabled:
console_output: false