python-tempestconf/config_tempest/tempest_conf.py

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])