`set_service_setting` accept multiple config changes

The method ``BaseTempestWhiteboxTestCase.set_service_setting`` accepts
multiple configuration parameters in one call. If the service
configuration changes, it will be needed to restart it only once.

Closes-Bug: #OSPRH-10514
Change-Id: I206f3ce73e9ab36d4fe1ba072735a0bd382c5621
This commit is contained in:
Rodolfo Alonso Hernandez 2024-10-04 08:45:40 +00:00
parent 6c381d8e20
commit 8b160a4c6e
5 changed files with 55 additions and 48 deletions

View File

@ -13,13 +13,13 @@
# 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 base64 import base64
import collections
from functools import partial from functools import partial
from multiprocessing import Process from multiprocessing import Process
import os import os
import random import random
import re import re
import time import time
import typing
import yaml import yaml
import netaddr import netaddr
@ -48,6 +48,8 @@ from whitebox_neutron_tempest_plugin.common import utils as local_utils
CONF = config.CONF CONF = config.CONF
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
WB_CONF = CONF.whitebox_neutron_plugin_options WB_CONF = CONF.whitebox_neutron_plugin_options
ConfigOption = collections.namedtuple(
'ConfigOption', ('section', 'parameter', 'value'))
class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase): class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
@ -398,25 +400,29 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
# TODO(mblue): next gen computes configuration set should be done too, # TODO(mblue): next gen computes configuration set should be done too,
# 'oc patch' for data plane would need more steps and triggers deployment # 'oc patch' for data plane would need more steps and triggers deployment
@classmethod @classmethod
def set_service_setting(cls, node_type: str = 'controller', def set_service_setting(
file: str = '', service: str = 'neutron', cls,
section: str = 'DEFAULT', param: str = '', node_type: str = 'controller',
value: typing.Union[str, int] = '', file: str = '',
cfg_change: bool = True) -> None: service: str = 'neutron',
config_list: list[ConfigOption] = None,
cfg_change: bool = True
) -> None:
"""Set configuration for service """Set configuration for service
:param node_type: Node type for change, ex: controller/compute :param node_type: Node type for change, ex: controller/compute
(currently only controllers). (currently only controllers).
:param file: File for configuration change (except in podified). :param file: File for configuration change (except in podified).
All configuration parameters must be defined in the same file.
:param service: Podified service name (only podified). :param service: Podified service name (only podified).
:param section: Section in the config file. :param config_list: List with the multiple configuration parameters,
:param param: Parameter in section to change. defined in a namedtuple ConfigOption(section, parameter, value).
:param value: Value to set.
:param cfg_change: by default, it is always expected that the :param cfg_change: by default, it is always expected that the
configuration will change; in a podified environment, that implies a configuration will change; in a podified environment, that implies a
pod replacement. pod replacement.
""" """
assert param, "'param' must be supplied" assert config_list, ("At least one configuration parameter must be "
"supplied")
if WB_CONF.openstack_type == 'podified' and node_type != 'compute': if WB_CONF.openstack_type == 'podified' 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,
@ -425,16 +431,22 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
# combine configuration to stdout using mutable copy in service pod # combine configuration to stdout using mutable copy in service pod
# NOTE(mblue): 'bash -c' needed for 'oc rsh' to execute a few # NOTE(mblue): 'bash -c' needed for 'oc rsh' to execute a few
# commands in pod shell session (instead of outside session). # commands in pod shell session (instead of outside session).
combine_conf_cmd = ( copy_config = (
"{0} rsh {1} bash -c '" "{0} rsh {1} bash -c "
"cp /etc/neutron/neutron.conf.d/{2} /tmp/ && " "'cp /etc/neutron/neutron.conf.d/{2} /tmp/ && "
"chmod g+w /tmp/{2} && " "chmod g+w /tmp/{2}'").format(
"crudini --set --output=- /tmp/{2} {3} {4} {5}'").format( cls.OC, service_pod, custom_file)
cls.OC, service_pod, cls.proxy_host_client.exec_command(copy_config)
custom_file, section, param, value) for config_option in config_list:
combined_conf = cls.proxy_host_client.exec_command( combine_conf_cmd = (
combine_conf_cmd) "{0} rsh {1} bash -c '"
# correct indentation required for configuration to be accepted "crudini --set /tmp/{2} {3} {4} {5}'").format(
cls.OC, service_pod, custom_file, config_option.section,
config_option.parameter, config_option.value)
cls.proxy_host_client.exec_command(combine_conf_cmd)
read_conf_cmd = "{0} rsh {1} bash -c 'cat /tmp/{2}'".format(
cls.OC, service_pod, custom_file)
combined_conf = cls.proxy_host_client.exec_command(read_conf_cmd)
combined_conf_ind = combined_conf.replace('\n', '\n' + 8 * ' ') combined_conf_ind = combined_conf.replace('\n', '\n' + 8 * ' ')
patch_buffer = ( patch_buffer = (
'spec:\n' 'spec:\n'
@ -485,10 +497,12 @@ class BaseTempestWhiteboxTestCase(base.BaseTempestTestCase):
service=service, service=service,
pod_state='')))) pod_state=''))))
else: else:
cls.run_group_cmd( for config_option in config_list:
'sudo crudini --set {} {} {} {} && sudo sync'.format( cls.run_group_cmd(
file, section, param, value), 'sudo crudini --set {} {} {} {} && sudo sync'.format(
node_type) file, config_option.section, config_option.parameter,
config_option.value),
node_type)
@classmethod @classmethod
def check_service_setting( def check_service_setting(

View File

@ -44,10 +44,10 @@ class NeutronAPIServerTest(wb_base.BaseTempestTestCaseOvn):
# that will trigger the Neutron API restart. In a "devstack" # that will trigger the Neutron API restart. In a "devstack"
# environment, it will be needed to manually restart the Neutron API # environment, it will be needed to manually restart the Neutron API
# server. # server.
_config = wb_base.ConfigOption('ovn', 'fdb_age_threshold',
random.randint(10000, 90000))
self.set_service_setting(file=wb_utils.get_ml2_conf_file(), self.set_service_setting(file=wb_utils.get_ml2_conf_file(),
section='ovn', config_list=[_config])
param='fdb_age_threshold',
value=random.randint(10000, 90000))
# 3) Restart Neutron API on all controllers simultaneously. # 3) Restart Neutron API on all controllers simultaneously.
if not WB_CONF.openstack_type == 'podified': if not WB_CONF.openstack_type == 'podified':

View File

@ -97,12 +97,11 @@ class TestMetadataRateLimiting(wb_base.BaseTempestWhiteboxTestCase):
f'Section - {METADATA_RATE_LIMITING_SECTION}\n' f'Section - {METADATA_RATE_LIMITING_SECTION}\n'
f'Parameter - {key}\n' f'Parameter - {key}\n'
f'Value - {value}\n') f'Value - {value}\n')
cls.set_service_setting( _config = wb_base.ConfigOption(METADATA_RATE_LIMITING_SECTION,
node_type='compute', key, value)
file=cls.metadata_conf_file, cls.set_service_setting(node_type='compute',
section=METADATA_RATE_LIMITING_SECTION, file=cls.metadata_conf_file,
param=key, config_list=[_config])
value=value)
cls._restart_metadata_agent() cls._restart_metadata_agent()
def tearDown(self): def tearDown(self):

View File

@ -51,15 +51,12 @@ class OvnFdbAgingTest(wb_base.BaseTempestTestCaseOvn):
def test_fdb_aging(self): def test_fdb_aging(self):
# 1) Configure the FDB learn flag and set the aging threshold to 5 # 1) Configure the FDB learn flag and set the aging threshold to 5
# seconds. # seconds.
config_list = [
wb_base.ConfigOption('ovn', 'localnet_learn_fdb', 'true'),
wb_base.ConfigOption('ovn', 'fdb_age_threshold',
FDB_AGE_THRESHOLD)]
self.set_service_setting(file=wb_utils.get_ml2_conf_file(), self.set_service_setting(file=wb_utils.get_ml2_conf_file(),
section='ovn', config_list=config_list,
param='localnet_learn_fdb',
value='true',
cfg_change=False)
self.set_service_setting(file=wb_utils.get_ml2_conf_file(),
section='ovn',
param='fdb_age_threshold',
value=FDB_AGE_THRESHOLD,
cfg_change=False) cfg_change=False)
# 2) restart neutron api on all controllers simultaneously # 2) restart neutron api on all controllers simultaneously

View File

@ -452,14 +452,11 @@ class BaseSecGroupLoggingTest(
# default preset (min possible): rate limit 100, burst limit 25 # default preset (min possible): rate limit 100, burst limit 25
burst_val = random.randint(30, 150) burst_val = random.randint(30, 150)
rate_val = random.randint(120, 300) rate_val = random.randint(120, 300)
config_list = [
wb_base.ConfigOption('network_log', 'burst_limit', burst_val),
wb_base.ConfigOption('network_log', 'rate_limit', rate_val)]
self.set_service_setting(file=self.ML2_CONF_FILE, self.set_service_setting(file=self.ML2_CONF_FILE,
section='network_log', config_list=config_list)
param='burst_limit',
value=burst_val)
self.set_service_setting(file=self.ML2_CONF_FILE,
section='network_log',
param='rate_limit',
value=rate_val)
# 5) restart neutron api on all controllers simultaneously # 5) restart neutron api on all controllers simultaneously
if not WB_CONF.openstack_type == 'podified': if not WB_CONF.openstack_type == 'podified':
service_ptn = utils.get_neutron_api_service_name() service_ptn = utils.get_neutron_api_service_name()