diff --git a/osc_lib/cli/client_config.py b/osc_lib/cli/client_config.py index 9aca067..43d59f0 100644 --- a/osc_lib/cli/client_config.py +++ b/osc_lib/cli/client_config.py @@ -16,6 +16,7 @@ import logging from os_client_config import config +from os_client_config import exceptions as occ_exceptions from oslo_utils import strutils import six @@ -116,6 +117,7 @@ class OSC_Config(config.OpenStackConfig): # present, then do not change the behaviour. Otherwise, set the # PROJECT_DOMAIN_ID to 'OS_DEFAULT_DOMAIN' for better usability. if ( + auth_type in ("password", "v3password", "v3totp") and not config['auth'].get('project_domain_id') and not config['auth'].get('project_domain_name') ): @@ -151,3 +153,68 @@ class OSC_Config(config.OpenStackConfig): LOG.debug("auth_config_hook(): %s", strutils.mask_password(six.text_type(config))) return config + + def _validate_auth_ksc(self, config, cloud, fixed_argparse=None): + """Old compatibility hack for OSC, no longer needed/wanted""" + return config + + def _validate_auth(self, config, loader, fixed_argparse=None): + """Validate auth plugin arguments""" + # May throw a keystoneauth1.exceptions.NoMatchingPlugin + + plugin_options = loader.get_options() + + msgs = [] + prompt_options = [] + for p_opt in plugin_options: + # if it's in config, win, move it and kill it from config dict + # if it's in config.auth but not in config we're good + # deprecated loses to current + # provided beats default, deprecated or not + winning_value = self._find_winning_auth_value(p_opt, config) + if not winning_value: + winning_value = self._find_winning_auth_value( + p_opt, config['auth']) + + # if the plugin tells us that this value is required + # then error if it's doesn't exist now + if not winning_value and p_opt.required: + msgs.append( + 'Missing value {auth_key}' + ' required for auth plugin {plugin}'.format( + auth_key=p_opt.name, plugin=config.get('auth_type'), + ) + ) + + # Clean up after ourselves + for opt in [p_opt.name] + [o.name for o in p_opt.deprecated]: + opt = opt.replace('-', '_') + config.pop(opt, None) + config['auth'].pop(opt, None) + + if winning_value: + # Prefer the plugin configuration dest value if the value's key + # is marked as depreciated. + if p_opt.dest is None: + config['auth'][p_opt.name.replace('-', '_')] = ( + winning_value) + else: + config['auth'][p_opt.dest] = winning_value + + # See if this needs a prompting + if ( + 'prompt' in vars(p_opt) and + p_opt.prompt is not None and + p_opt.dest not in config['auth'] and + self._pw_callback is not None + ): + # Defer these until we know all required opts are present + prompt_options.append(p_opt) + + if msgs: + raise occ_exceptions.OpenStackConfigException('\n'.join(msgs)) + else: + for p_opt in prompt_options: + config['auth'][p_opt.dest] = self._pw_callback(p_opt.prompt) + + return config diff --git a/osc_lib/tests/cli/test_client_config.py b/osc_lib/tests/cli/test_client_config.py index cb538cc..3450f1c 100644 --- a/osc_lib/tests/cli/test_client_config.py +++ b/osc_lib/tests/cli/test_client_config.py @@ -177,7 +177,7 @@ class TestOSCConfig(utils.TestCase): self.assertEqual('v3oidcpassword', ret_config['auth_type']) self.assertEqual('default', ret_config['default_domain']) self.assertEqual('fred', ret_config['auth']['username']) - self.assertEqual('default', ret_config['auth']['project_domain_id']) + self.assertNotIn('project_domain_id', ret_config['auth']) self.assertNotIn('user_domain_id', ret_config['auth']) def test_auth_default_domain_use_default(self):