Actively check type instead of WB_CONF.openstack_type

Plugin was built extensively around podified/devstack setups, maybe more
types in the future.
It isn't likely to be changed any time soon, such change will require
adding code into plenty of conditions spread around plugin.

We can replace manually maintained configuration with automated check
to reduce CI maintenance upstream/downstream.

As documented for devstack [1] home directory can optionally be
`/opt/stack`, for this plugin's devstack jobs it is commonly used,
check should work to tell the difference.

[1] https://docs.openstack.org/devstack/latest/

Related-Bug: #OSPRH-16056
Related-Bug: #OSPRH-15819
Change-Id: I2d3f807b07e5eb810b87320e31cf64ad72f2f2a9
This commit is contained in:
Maor Blaustein
2025-04-23 17:30:48 +03:00
parent 4d12e79276
commit ea0e811aa9
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) 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(): def get_ml2_conf_file():
"""Neutron ML2 config file name depending on the installation type """Neutron ML2 config file name depending on the installation type
The default value of WB_CONF.ml2_plugin_config is The default value of WB_CONF.ml2_plugin_config is
'/etc/neutron/plugins/ml2/ml2_conf.ini'. '/etc/neutron/plugins/ml2/ml2_conf.ini'.
""" """
if WB_CONF.openstack_type in ('podified', 'devstack'):
return WB_CONF.ml2_plugin_config return WB_CONF.ml2_plugin_config
else:
return ('/var/lib/config-data/puppet-generated/neutron' +
WB_CONF.ml2_plugin_config)

View File

@@ -38,10 +38,6 @@ WhiteboxNeutronPluginOptions = [
cfg.StrOpt('tester_key_file', cfg.StrOpt('tester_key_file',
default='', default='',
help='Key file to access host to execute validated commands.'), 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', cfg.StrOpt('pki_private_key',
default='/etc/pki/tls/private/ovn_controller.key', default='/etc/pki/tls/private/ovn_controller.key',
help='File with private key. Need for TLS-everywhere ' help='File with private key. Need for TLS-everywhere '

View File

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

View File

@@ -51,8 +51,8 @@ class NeutronAPIServerTest(wb_base.BaseTempestTestCaseOvn):
wait_res='deploy/neutron') wait_res='deploy/neutron')
# 3) Restart Neutron API on all controllers simultaneously. # 3) Restart Neutron API on all controllers simultaneously.
if not WB_CONF.openstack_type == 'podified': if self.is_devstack:
service_ptn = wb_utils.get_neutron_api_service_name() service_ptn = self.get_neutron_api_service_name()
for node in self.nodes: for node in self.nodes:
if node['is_controller']: if node['is_controller']:
# NOTE(mblue): if reset fails on multinode, consider # 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") "The tests require environment with at least 2 nodes")
cls.bgp_expose_tenant_networks = False cls.bgp_expose_tenant_networks = False
for node in cls.nodes: for node in cls.nodes:
if WB_CONF.openstack_type == 'devstack': if cls.is_devstack:
if not node['is_controller']: if not node['is_controller']:
continue continue
cls.check_service_setting( cls.check_service_setting(
@@ -71,7 +71,7 @@ class OvnDvrBase(base.TrafficFlowTest, base.BaseTempestTestCaseOvn):
# TODO(rsafrono) add code that defines # TODO(rsafrono) add code that defines
# cls.bgp_expose_tenant_networks on devstack # cls.bgp_expose_tenant_networks on devstack
# in case such bgp environment will be ever created # 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() config_files = cls.get_configs_of_service()
cls.check_service_setting( cls.check_service_setting(
{'client': cls.proxy_host_client}, {'client': cls.proxy_host_client},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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