diff --git a/config_tempest/constants.py b/config_tempest/constants.py index b2e63c76..9efa7e8c 100644 --- a/config_tempest/constants.py +++ b/config_tempest/constants.py @@ -27,6 +27,25 @@ DEFAULT_IMAGE = ("http://download.cirros-cloud.net/0.3.5/" "cirros-0.3.5-x86_64-disk.img") DEFAULT_IMAGE_FORMAT = 'qcow2' +# The dict holds the credentials, which are not supposed to be printed +# to a tempest.conf when --test-accounts CLI parameter is used. +ALL_CREDENTIALS_KEYS = { + "auth.admin_username": [], + "auth.admin_password": [], + "auth.admin_project_name": [], + "auth.admin_domain_name": [], + "identity.username": [], + "identity.password": [], + "identity.tenant_name": [], + "identity.alt_username": [], + "identity.alt_password": [], + "identity.alt_tenant_name": [], + "identity.admin_username": [], + "identity.admin_password": [], + "identity.admin_tenant_name": [], + "identity.admin_domain_name": [], +} + # services and their codenames SERVICE_NAMES = { 'baremetal': 'ironic', diff --git a/config_tempest/main.py b/config_tempest/main.py index 577513b5..b7500d52 100755 --- a/config_tempest/main.py +++ b/config_tempest/main.py @@ -359,7 +359,8 @@ def config_tempest(**kwargs): remove = parse_values_to_remove(kwargs.get('remove', [])) set_logging(kwargs.get('debug', False), kwargs.get('verbose', False)) - conf = tempest_conf.TempestConf() + write_credentials = kwargs.get('test_accounts') is None + conf = tempest_conf.TempestConf(write_credentials=write_credentials) set_options(conf, kwargs.get('deployer_input'), kwargs.get('non_admin', False), kwargs.get('overrides', []), kwargs.get('test_accounts'), @@ -403,9 +404,7 @@ def config_tempest(**kwargs): LOG.info("Removing configuration: %s", str(remove)) conf.remove_values(remove) out_path = kwargs.get('out', 'etc/tempest.conf') - LOG.info("Creating configuration file %s", os.path.abspath(out_path)) - with open(out_path, 'w') as f: - conf.write(f) + conf.write(out_path) def main(): diff --git a/config_tempest/tempest_conf.py b/config_tempest/tempest_conf.py index a80c9100..d62b3408 100644 --- a/config_tempest/tempest_conf.py +++ b/config_tempest/tempest_conf.py @@ -14,9 +14,10 @@ # under the License. import ConfigParser +import os import sys -from constants import LOG +import constants as C from oslo_config import cfg import tempest.config @@ -31,6 +32,10 @@ class TempestConf(ConfigParser.SafeConfigParser): CONF = tempest.config.TempestConfigPrivate(parse_conf=False) + def __init__(self, write_credentials=True, **kwargs): + self.write_credentials = write_credentials + ConfigParser.SafeConfigParser.__init__(self, **kwargs) + def get_bool_value(self, value): """Returns boolean value of the string value given. @@ -63,7 +68,8 @@ class TempestConf(ConfigParser.SafeConfigParser): else: return self.CONF.get(section).get(key) except cfg.NoSuchOptError: - LOG.warning("Option %s is not defined in %s section", key, section) + 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 `SafeConfigParser.set` @@ -88,16 +94,25 @@ class TempestConf(ConfigParser.SafeConfigParser): if not self.has_section(section) and section.lower() != "default": self.add_section(section) if not priority and (section, key) in self.priority_sectionkeys: - LOG.debug("Option '[%s] %s = %s' was defined by user, NOT" - " overwriting into value '%s'", section, key, - self.get(section, key), value) + 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)) - LOG.debug("Setting [%s] %s = %s", section, key, value) + C.LOG.debug("Setting [%s] %s = %s", section, key, value) ConfigParser.SafeConfigParser.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.SafeConfigParser.write(self, f) + def remove_values(self, to_remove): """Remove values from configuration file specified in arguments. @@ -125,7 +140,7 @@ class TempestConf(ConfigParser.SafeConfigParser): self.set(section, key, ",".join(conf_values)) except ConfigParser.NoOptionError: # only inform a user, option specified by him doesn't exist - LOG.error(sys.exc_info()[1]) + C.LOG.error(sys.exc_info()[1]) except ConfigParser.NoSectionError: # only inform a user, section specified by him doesn't exist - LOG.error(sys.exc_info()[1]) + C.LOG.error(sys.exc_info()[1]) diff --git a/config_tempest/tests/test_tempest_conf.py b/config_tempest/tests/test_tempest_conf.py index 978e7171..3f7b97dc 100644 --- a/config_tempest/tests/test_tempest_conf.py +++ b/config_tempest/tests/test_tempest_conf.py @@ -102,7 +102,7 @@ class TestTempestConf(BaseConfigTempestTest): else: self.assertTrue(ext in conf_exts) - @mock.patch('config_tempest.tempest_conf.LOG') + @mock.patch('config_tempest.tempest_conf.C.LOG') def test_remove_not_defined_values(self, mock_logging): self.conf.remove_values({"notExistSection.key": []}) # check if LOG.error was called diff --git a/releasenotes/notes/Do-not-expose-user-credentials-1ffba4d72798b5c9.yaml b/releasenotes/notes/Do-not-expose-user-credentials-1ffba4d72798b5c9.yaml new file mode 100644 index 00000000..20196377 --- /dev/null +++ b/releasenotes/notes/Do-not-expose-user-credentials-1ffba4d72798b5c9.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + When --test-accounts parameter (specifying a path to a accounts.yaml file) + is used, don't write any user credentials to tempest.conf. + This will make it easier for users who run tempest tests with accounts.yaml + file and want to share their tempest.conf without exposing their credentials.