
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
169 lines
6.8 KiB
Python
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])
|