Lukáš Piwowarski 6488be3e82 Change class variables to instance variables
TempestConf has a set of class variables that do not need to be
class variables because there are no multiple instances of
TempestConf class that could share the value.

The reason why we need to move the class variables to instance
variables is that some unit tests under certain conditions were
failing because multiple unit tests were changing the
TempestConf.priority_sectionkeys value.

Change-Id: Ic6f51be112aa9f93904fcab289d78a7e06f20f62
2022-11-24 08:56:45 +00:00

169 lines
6.8 KiB
Python

# Copyright 2016, 2017, 2018 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import sys
from config_tempest import constants as C
from oslo_config import cfg
from six.moves import configparser
import tempest.config
class TempestConf(configparser.ConfigParser):
CONF = tempest.config.TempestConfigPrivate(parse_conf=False)
def __init__(self, write_credentials=True, **kwargs):
# causes the config parser to preserve case of the options
self.optionxform = str
# set of pairs `(section, key)` which have a higher priority (are
# user-defined) and will usually not be overwritten by
# `TempestConf.set()`
self.priority_sectionkeys = set()
self.write_credentials = write_credentials
super().__init__(self, **kwargs)
def get_bool_value(self, value):
"""Returns boolean value of the string value given.
:param value: True/False
:type value: String
:returns: Boolean value of the string value given
:rtype: Boolean
"""
strval = str(value).lower()
if strval == 'true':
return True
elif strval == 'false':
return False
else:
raise ValueError("'%s' is not a boolean" % value)
def get_defaulted(self, section, key):
"""Returns default value for the section.key pair.
:param section: a section in a tempest.conf file
:type section: String
:param key: a key in a section in a tempest.conf file
:type key: String
:returns: default value for the section.key pair
:rtype: String
"""
try:
if self.has_option(section, key):
return self.get(section, key)
else:
return self.CONF.get(section).get(key)
except cfg.NoSuchOptError:
C.LOG.warning("Option %s is not defined in %s section",
key, section)
def set(self, section, key, value, priority=False):
"""Set value in configuration, similar to `ConfigParser.set`
Creates non-existent sections. Keeps track of options which were
specified by the user and should not be normally overwritten.
:param section: a section in a tempest.conf file
:type section: String
:param key: a key in a section in a tempest.conf file
:type key: String
:param value: a value to be set to the section.key
:type value: String
:param priority: if True, always over-write the value. If False, don't
over-write an existing value if it was written before with a
priority (i.e. if it was specified by the user)
:type priority: Boolean
:returns: True if the value was written, False if not (because of
priority)
:rtype: Boolean
"""
if not self.has_section(section) and section.lower() != "default":
self.add_section(section)
if not priority and (section, key) in self.priority_sectionkeys:
C.LOG.debug("Option '[%s] %s = %s' was defined by user, NOT"
" overwriting into value '%s'", section, key,
self.get(section, key), value)
return False
if priority:
self.priority_sectionkeys.add((section, key))
C.LOG.debug("Setting [%s] %s = %s", section, key, value)
configparser.ConfigParser.set(self, section, key, value)
return True
def write(self, out_path):
C.LOG.info("Creating configuration file %s", os.path.abspath(out_path))
if not self.write_credentials:
C.LOG.info("Credentials will not be printed to a tempest.conf, "
"writing credentials is disabled.")
self.remove_values(C.ALL_CREDENTIALS_KEYS)
with open(out_path, 'w') as f:
configparser.ConfigParser.write(self, f)
def remove_values(self, to_remove):
"""Remove values from configuration file specified in arguments.
:param to_remove: {'section.key': [values_to_be_removed], ...}
:type to_remove: dict
"""
for key_path in to_remove:
section, key = key_path.split('.')
try:
conf_values = self.get(section, key).split(',')
remove = to_remove[key_path]
if len(remove) == 0:
# delete all values in section.key
self.remove_option(section, key)
elif len(conf_values) == 1:
# make sure only the value specified by user
# will be deleted if in the key is other value
# than expected, ignore it
if conf_values[0] in to_remove[key_path]:
self.remove_option(section, key)
else:
# exclude all unwanted values from the list
# and preserve the original order of items
conf_values = [v for v in conf_values if v not in remove]
self.set(section, key, ",".join(conf_values))
except configparser.NoOptionError:
# only inform a user, option specified by him doesn't exist
C.LOG.error(sys.exc_info()[1])
except configparser.NoSectionError:
# only inform a user, section specified by him doesn't exist
C.LOG.error(sys.exc_info()[1])
def append_values(self, to_append):
"""Appends values to configuration file specified in arguments.
:param to_append: {'section.key': [values_to_be_added], ...}
:type to_append: dict
"""
for key_path in to_append:
section, key = key_path.split('.')
try:
conf_val = self.get(section, key).split(',')
# omit duplicates if found any
conf_val += list(set(to_append[key_path]) - set(conf_val))
self.set(section, key, ",".join(conf_val))
except configparser.NoOptionError:
# only inform a user, option specified by him doesn't exist
C.LOG.error(sys.exc_info()[1])
except configparser.NoSectionError:
# only inform a user, section specified by him doesn't exist
C.LOG.error(sys.exc_info()[1])