1
"""Handling of the credentials needed to authenticate with the OpenStack api
3
Supports several different sets of credentials different auth modes need:
4
* 'legacy' is built into nova and deprecated in favour of using keystone
5
* 'keypair' works with the HP public cloud implemention of keystone
6
* 'userpass' is the way keystone seems to want to do authentication generally
12
class OpenStackCredentials(object):
13
"""Encapsulation of credentials used to authenticate with OpenStack"""
16
'auth-url': ("OS_AUTH_URL", "NOVA_URL"),
17
'username': ("OS_USERNAME", "NOVA_USERNAME"),
18
'password': ("OS_PASSWORD", "NOVA_PASSWORD"),
19
# HP exposes both a numeric id and a name for tenants, passed back
20
# as tenantId and tenantName. Use the name only for simplicity.
21
'project-name': ("OS_TENANT_NAME", "NOVA_PROJECT_NAME",
23
'region': ("OS_REGION_NAME", "NOVA_REGION_NAME", "NOVA_REGION"),
24
# The key variables don't seem to have modern OS_ prefixed aliases
25
'access-key': ("NOVA_API_KEY",),
26
'secret-key': ("EC2_SECRET_KEY", "AWS_SECRET_ACCESS_KEY"),
27
# A usable mode can normally be guessed, but may be configured
31
# Really, legacy auth could pass in the project id and keystone doesn't
32
# require it, but this is what the client expects for now.
34
'userpass': ('username', 'password', 'project-name'),
35
'rax': ('username', 'password', 'project-name'),
36
'keypair': ('access-key', 'secret-key', 'project-name'),
37
'legacy': ('username', 'access-key'),
46
def __init__(self, creds_dict):
47
url = creds_dict.get("auth-url")
49
raise ValueError("Missing config 'auth-url' for OpenStack api")
50
mode = creds_dict.get("auth-mode")
52
mode = self._guess_auth_mode(url)
53
elif mode not in self._modes:
54
# The juju.environment.config layer should raise a pretty error
55
raise ValueError("Unknown 'auth-mode' value %r" % (self.mode,))
56
missing_keys = [key for key in self._modes[mode]
57
if not creds_dict.get(key)]
59
raise ValueError("Missing config %s required for %s auth" % (
60
", ".join(map(repr, missing_keys)), mode))
63
for key in self._config_vars:
64
if key not in ("auth-url", "auth-mode"):
65
setattr(self, key.replace("-", "_"), creds_dict.get(key))
68
def _guess_auth_mode(cls, url):
69
"""Pick a mode based on the version at the end of `url` given"""
70
final_part = url.rstrip("/").rsplit("/", 1)[-1]
72
return cls._version_to_mode[final_part]
75
"Missing config 'auth-mode' as unknown version"
76
" in 'auth-url' given: " + url)
79
def _get(cls, config, key):
80
"""Retrieve `key` from `config` if present or in matching envvars"""
83
for env_key in cls._config_vars[key]:
85
val = os.environ.get(env_key)
91
def from_environment(cls, config):
92
"""Create credentials from `config` falling back to environment"""
93
return cls(dict((k, cls._get(config, k)) for k in cls._config_vars))
95
def set_config_defaults(self, data):
96
"""Populate `data` with these credentials where not already set"""
97
for key in self._config_vars:
99
val = getattr(self, key.replace("auth-", "").replace("-", "_"))