Revision 144b3551
b/kamaki/cli/__init__.py | ||
---|---|---|
223 | 223 |
|
224 | 224 |
def _init_session(arguments, is_non_API=False): |
225 | 225 |
""" |
226 |
:returns: (AuthCachedClient, str) authenticator and cloud remote name
|
|
226 |
:returns: (AuthCachedClient, str) authenticator and cloud name |
|
227 | 227 |
""" |
228 | 228 |
global _help |
229 | 229 |
_help = arguments['help'].value |
... | ... | |
248 | 248 |
return None, None |
249 | 249 |
|
250 | 250 |
cloud = arguments['cloud'].value or 'default' |
251 |
if not cloud in _cnf.value.keys('remote'):
|
|
251 |
if not cloud in _cnf.value.keys('cloud'):
|
|
252 | 252 |
raise CLIError( |
253 |
'No cloud remote "%s" is configured' % cloud,
|
|
253 |
'No cloud "%s" is configured' % cloud, |
|
254 | 254 |
importance=3, details=[ |
255 |
'To configure a new cloud remote, find and set the',
|
|
255 |
'To configure a new cloud, find and set the', |
|
256 | 256 |
'single authentication URL and token:', |
257 |
' kamaki config set remote.%s.url <URL>' % cloud,
|
|
258 |
' kamaki config set remote.%s.token <t0k3n>' % cloud])
|
|
257 |
' kamaki config set cloud.%s.url <URL>' % cloud,
|
|
258 |
' kamaki config set cloud.%s.token <t0k3n>' % cloud])
|
|
259 | 259 |
auth_args = dict() |
260 | 260 |
for term in ('url', 'token'): |
261 |
auth_args[term] = _cnf.get_remote(cloud, term)
|
|
261 |
auth_args[term] = _cnf.get_cloud(cloud, term)
|
|
262 | 262 |
if not auth_args[term]: |
263 | 263 |
raise CLIError( |
264 | 264 |
'No authentication %s provided for %s cloud' % (term, cloud), |
265 | 265 |
importance=3, details=[ |
266 | 266 |
'Get and set a %s for %s cloud:' % (term, cloud), |
267 |
' kamaki config set remote.%s.%s <t0k3n>' % (term, cloud)
|
|
267 |
' kamaki config set cloud.%s.%s <t0k3n>' % (term, cloud)
|
|
268 | 268 |
]) |
269 | 269 |
|
270 | 270 |
from kamaki.clients.astakos import AstakosClient as AuthCachedClient |
b/kamaki/cli/argument.py | ||
---|---|---|
181 | 181 |
def get_global(self, option): |
182 | 182 |
return self.value.get_global(option) |
183 | 183 |
|
184 |
def get_remote(self, remote, option):
|
|
185 |
return self.value.get_remote(remote, option)
|
|
184 |
def get_cloud(self, cloud, option):
|
|
185 |
return self.value.get_cloud(cloud, option)
|
|
186 | 186 |
|
187 | 187 |
_config_arg = ConfigArgument( |
188 | 188 |
1, 'Path to configuration file', ('-c', '--config')) |
... | ... | |
409 | 409 |
|
410 | 410 |
_arguments = dict( |
411 | 411 |
config=_config_arg, |
412 |
cloud=ValueArgument('Chose a remote cloud to connect to', ('--cloud')),
|
|
412 |
cloud=ValueArgument('Chose a cloud to connect to', ('--cloud')), |
|
413 | 413 |
help=Argument(0, 'Show help message', ('-h', '--help')), |
414 | 414 |
debug=FlagArgument('Include debug output', ('-d', '--debug')), |
415 | 415 |
include=FlagArgument( |
b/kamaki/cli/commands/__init__.py | ||
---|---|---|
76 | 76 |
|
77 | 77 |
@DontRaiseKeyError |
78 | 78 |
def _custom_url(self, service): |
79 |
return self.config.get_remote(self.cloud, '%s_url' % service)
|
|
79 |
return self.config.get_cloud(self.cloud, '%s_url' % service)
|
|
80 | 80 |
|
81 | 81 |
@DontRaiseKeyError |
82 | 82 |
def _custom_token(self, service): |
83 |
return self.config.get_remote(self.cloud, '%s_token' % service)
|
|
83 |
return self.config.get_cloud(self.cloud, '%s_token' % service)
|
|
84 | 84 |
|
85 | 85 |
@DontRaiseKeyError |
86 | 86 |
def _custom_type(self, service): |
87 |
return self.config.get_remote(self.cloud, '%s_type' % service)
|
|
87 |
return self.config.get_cloud(self.cloud, '%s_type' % service)
|
|
88 | 88 |
|
89 | 89 |
@DontRaiseKeyError |
90 | 90 |
def _custom_version(self, service): |
91 |
return self.config.get_remote(self.cloud, '%s_version' % service)
|
|
91 |
return self.config.get_cloud(self.cloud, '%s_version' % service)
|
|
92 | 92 |
|
93 | 93 |
def _set_log_params(self): |
94 | 94 |
try: |
b/kamaki/cli/commands/astakos.py | ||
---|---|---|
53 | 53 |
base_url = self._custom_url('astakos') |
54 | 54 |
if base_url: |
55 | 55 |
token = self._custom_token('astakos')\ |
56 |
or self.config.get_remote(self.cloud, 'token')
|
|
56 |
or self.config.get_cloud(self.cloud, 'token')
|
|
57 | 57 |
self.client = AstakosClient(base_url=base_url, token=token) |
58 | 58 |
return |
59 | 59 |
else: |
... | ... | |
72 | 72 |
"""Authenticate a user |
73 | 73 |
Get user information (e.g. unique account name) from token |
74 | 74 |
Token should be set in settings: |
75 |
* check if a token is set /config get remote.default.token
|
|
76 |
* permanently set a token /config set remote.default.token <token>
|
|
75 |
* check if a token is set /config get cloud.default.token
|
|
76 |
* permanently set a token /config set cloud.default.token <token>
|
|
77 | 77 |
Token can also be provided as a parameter |
78 |
(In case of another named cloud remote, use its name instead of default)
|
|
78 |
(In case of another named cloud, use its name instead of default) |
|
79 | 79 |
""" |
80 | 80 |
|
81 | 81 |
@staticmethod |
b/kamaki/cli/commands/config.py | ||
---|---|---|
50 | 50 |
\n. [group]\ |
51 | 51 |
\n. option=value\ |
52 | 52 |
\n. (more options can be set per group)\ |
53 |
\n. special case: named cloud remotes.\
|
|
53 |
\n. special case: named clouds.\ |
|
54 | 54 |
\n. E.g. for a cloud "demo":\ |
55 |
\n. [remote "demo"]\
|
|
55 |
\n. [cloud "demo"]\
|
|
56 | 56 |
\n. url = <http://single/authentication/url/for/demo/site>\ |
57 | 57 |
\n. token = <auth_token_from_demo_site>\ |
58 |
\n. which are referenced as remote.demo.url , remote.demo.token'
|
|
58 |
\n. which are referenced as cloud.demo.url , cloud.demo.token'
|
|
59 | 59 |
|
60 | 60 |
|
61 | 61 |
@command(config_cmds) |
... | ... | |
73 | 73 |
for section in sorted(self.config.sections()): |
74 | 74 |
items = self.config.items(section) |
75 | 75 |
for key, val in sorted(items): |
76 |
if section in ('remote',):
|
|
76 |
if section in ('cloud',):
|
|
77 | 77 |
prefix = '%s.%s' % (section, key) |
78 | 78 |
for k, v in val.items(): |
79 | 79 |
print('%s..%s = %s' % (prefix, k, v)) |
... | ... | |
97 | 97 |
match = False |
98 | 98 |
for k in self.config.keys(key): |
99 | 99 |
match = True |
100 |
if option != 'remote':
|
|
100 |
if option != 'cloud':
|
|
101 | 101 |
stdout.write('%s.%s =' % (option, k)) |
102 | 102 |
self._run('%s.%s' % (option, k)) |
103 | 103 |
if match: |
104 | 104 |
return |
105 | 105 |
section = 'global' |
106 |
prefix = 'remote.'
|
|
106 |
prefix = 'cloud.'
|
|
107 | 107 |
get, section = ( |
108 |
self.config.get_remote, section[len(prefix):]) if (
|
|
108 |
self.config.get_cloud, section[len(prefix):]) if (
|
|
109 | 109 |
section.startswith(prefix)) else (self.config.get, section) |
110 | 110 |
value = get(section, key) |
111 | 111 |
if isinstance(value, dict): |
... | ... | |
127 | 127 |
@errors.generic.all |
128 | 128 |
def _run(self, option, value): |
129 | 129 |
section, sep, key = option.rpartition('.') |
130 |
prefix = 'remote.'
|
|
130 |
prefix = 'cloud.'
|
|
131 | 131 |
if section.startswith(prefix): |
132 |
self.config.set_remote(section[len(prefix):], key, value)
|
|
133 |
elif section in ('remote',):
|
|
132 |
self.config.set_cloud(section[len(prefix):], key, value)
|
|
133 |
elif section in ('cloud',):
|
|
134 | 134 |
raise CLISyntaxError( |
135 | 135 |
'Invalid syntax for cloud definition', importance=2, details=[ |
136 |
'To define a cloud remote "%s"' % key,
|
|
136 |
'To define a cloud "%s"' % key, |
|
137 | 137 |
'set the cloud\'s authentication url and token:', |
138 |
' /config set remote.%s.url <URL>' % key,
|
|
139 |
' /config set remote.%s.token <t0k3n>' % key])
|
|
138 |
' /config set cloud.%s.url <URL>' % key,
|
|
139 |
' /config set cloud.%s.token <t0k3n>' % key])
|
|
140 | 140 |
else: |
141 | 141 |
section = section or 'global' |
142 | 142 |
self.config.set(section, key, value) |
... | ... | |
164 | 164 |
def _run(self, option): |
165 | 165 |
section, sep, key = option.rpartition('.') |
166 | 166 |
section = section or 'global' |
167 |
prefix = 'remote.'
|
|
167 |
prefix = 'cloud.'
|
|
168 | 168 |
if section.startswith(prefix): |
169 |
remote = section[len(prefix):]
|
|
169 |
cloud = section[len(prefix):]
|
|
170 | 170 |
try: |
171 |
self.config.remove_from_remote(remote, key)
|
|
171 |
self.config.remove_from_cloud(cloud, key)
|
|
172 | 172 |
except KeyError: |
173 | 173 |
raise CLIError('Field %s does not exist' % option) |
174 | 174 |
else: |
b/kamaki/cli/commands/cyclades.py | ||
---|---|---|
53 | 53 |
|
54 | 54 |
about_authentication = '\nUser Authentication:\ |
55 | 55 |
\n* to check authentication: /user authenticate\ |
56 |
\n* to set authentication token: /config set remote.default.token <token>'
|
|
56 |
\n* to set authentication token: /config set cloud.default.token <token>'
|
|
57 | 57 |
|
58 | 58 |
howto_personality = [ |
59 | 59 |
'Defines a file to be injected to VMs personality.', |
... | ... | |
75 | 75 |
if base_url: |
76 | 76 |
token = self._custom_token(service)\ |
77 | 77 |
or self._custom_token('cyclades')\ |
78 |
or self.config.get_remote('token')
|
|
78 |
or self.config.get_cloud('token')
|
|
79 | 79 |
self.client = CycladesClient( |
80 | 80 |
base_url=base_url, token=token) |
81 | 81 |
return |
b/kamaki/cli/commands/errors.py | ||
---|---|---|
39 | 39 |
from kamaki.cli.utils import format_size |
40 | 40 |
|
41 | 41 |
CLOUDNAME = [ |
42 |
'Note: If you use a named cloud remote, use its name', |
|
43 |
'instead of "default"'] |
|
42 |
'Note: If you use a named cloud, use its name instead of "default"'] |
|
44 | 43 |
|
45 | 44 |
|
46 | 45 |
class generic(object): |
... | ... | |
71 | 70 |
'Make sure a valid token is provided:', |
72 | 71 |
' to check if token is valid: /user authenticate', |
73 | 72 |
' to set token:', |
74 |
' /config set remote.default.token <token>',
|
|
73 |
' /config set cloud.default.token <token>',
|
|
75 | 74 |
' to get current token:', |
76 |
' /config get remote.default.token'] + CLOUDNAME)
|
|
75 |
' /config get cloud.default.token'] + CLOUDNAME)
|
|
77 | 76 |
elif ce.status in range(-12, 200) + [302, 401, 403, 500]: |
78 | 77 |
raiseCLIError(ce, importance=3, details=[ |
79 | 78 |
'Check if service is up']) |
... | ... | |
86 | 85 |
raiseCLIError(ce, msg, details=[ |
87 | 86 |
'Check if authentication url is correct', |
88 | 87 |
' check current url:', |
89 |
' /config get remote.default.url',
|
|
88 |
' /config get cloud.default.url',
|
|
90 | 89 |
' set new auth. url:', |
91 |
' /config set remote.default.url'] + CLOUDNAME)
|
|
90 |
' /config set cloud.default.url'] + CLOUDNAME)
|
|
92 | 91 |
raise |
93 | 92 |
return _raise |
94 | 93 |
|
... | ... | |
96 | 95 |
class user(object): |
97 | 96 |
|
98 | 97 |
_token_details = [ |
99 |
'To check default token: /config get remote.default.token',
|
|
98 |
'To check default token: /config get cloud.default.token',
|
|
100 | 99 |
'If set/update a token:', |
101 |
'* (permanent): /config set remote.default.token <token>',
|
|
100 |
'* (permanent): /config set cloud.default.token <token>',
|
|
102 | 101 |
'* (temporary): re-run with <token> parameter'] + CLOUDNAME |
103 | 102 |
|
104 | 103 |
@classmethod |
... | ... | |
112 | 111 |
if not getattr(client, 'token', False): |
113 | 112 |
kloger.warning( |
114 | 113 |
'No permanent token (try:' |
115 |
' kamaki config set remote.default.token <tkn>)')
|
|
114 |
' kamaki config set cloud.default.token <tkn>)')
|
|
116 | 115 |
if not getattr(client, 'base_url', False): |
117 | 116 |
msg = 'Missing synnefo authentication URL' |
118 | 117 |
raise CLIError(msg, importance=3, details=[ |
119 | 118 |
'Check if authentication url is correct', |
120 | 119 |
' check current url:', |
121 |
' /config get remote.default.url',
|
|
120 |
' /config get cloud.default.url',
|
|
122 | 121 |
' set new auth. url:', |
123 |
' /config set remote.default.url'] + CLOUDNAME)
|
|
122 |
' /config set cloud.default.url'] + CLOUDNAME)
|
|
124 | 123 |
return r |
125 | 124 |
return _raise |
126 | 125 |
|
b/kamaki/cli/commands/image.py | ||
---|---|---|
80 | 80 |
if img_url: |
81 | 81 |
token = self._custom_token('image')\ |
82 | 82 |
or self._custom_token('plankton')\ |
83 |
or self.config.get_remote(self.cloud, 'token')
|
|
83 |
or self.config.get_cloud(self.cloud, 'token')
|
|
84 | 84 |
self.client = ImageClient(base_url=img_url, token=token) |
85 | 85 |
return |
86 | 86 |
if getattr(self, 'auth_base', False): |
b/kamaki/cli/commands/pithos.py | ||
---|---|---|
153 | 153 |
|
154 | 154 |
@DontRaiseKeyError |
155 | 155 |
def _custom_container(self): |
156 |
return self.config.get_remote(self.cloud, 'pithos_container')
|
|
156 |
return self.config.get_cloud(self.cloud, 'pithos_container')
|
|
157 | 157 |
|
158 | 158 |
@DontRaiseKeyError |
159 | 159 |
def _custom_uuid(self): |
160 |
return self.config.get_remote(self.cloud, 'pithos_uuid')
|
|
160 |
return self.config.get_cloud(self.cloud, 'pithos_uuid')
|
|
161 | 161 |
|
162 | 162 |
def _set_account(self): |
163 | 163 |
self.account = self._custom_uuid() |
b/kamaki/cli/commands/snf-astakos.py | ||
---|---|---|
61 | 61 |
def _run(self): |
62 | 62 |
self.cloud = self.cloud if self.cloud else 'default' |
63 | 63 |
self.token = self['token'] or self._custom_token('astakos')\ |
64 |
or self.config.get_remote(self.cloud, 'token')
|
|
64 |
or self.config.get_cloud(self.cloud, 'token')
|
|
65 | 65 |
if getattr(self, 'auth_base', False): |
66 | 66 |
astakos_endpoints = self.auth_base.get_service_endpoints( |
67 | 67 |
self._custom_type('astakos') or 'identity', |
... | ... | |
82 | 82 |
"""Authenticate a user |
83 | 83 |
Get user information (e.g. unique account name) from token |
84 | 84 |
Token should be set in settings: |
85 |
* check if a token is set /config get remote.default.token
|
|
86 |
* permanently set a token /config set remote.default.token <token>
|
|
85 |
* check if a token is set /config get cloud.default.token
|
|
86 |
* permanently set a token /config set cloud.default.token <token>
|
|
87 | 87 |
Token can also be provided as a parameter |
88 |
(To use a named cloud remote, use its name instead of "default")
|
|
88 |
(To use a named cloud, use its name instead of "default") |
|
89 | 89 |
""" |
90 | 90 |
|
91 | 91 |
arguments = dict( |
b/kamaki/cli/config.py | ||
---|---|---|
39 | 39 |
from re import match |
40 | 40 |
|
41 | 41 |
from kamaki.cli.errors import CLISyntaxError |
42 |
from kamaki import __version__ |
|
42 | 43 |
|
43 | 44 |
try: |
44 | 45 |
from collections import OrderedDict |
... | ... | |
55 | 56 |
# Name of a shell variable to bypass the CONFIG_PATH value |
56 | 57 |
CONFIG_ENV = 'KAMAKI_CONFIG' |
57 | 58 |
|
58 |
HEADER = """ |
|
59 |
# Kamaki configuration file v3 (kamaki >= v0.9) |
|
60 |
""" |
|
59 |
version = '' |
|
60 |
for c in '%s' % __version__: |
|
61 |
if c not in '0.123456789': |
|
62 |
break |
|
63 |
version += c |
|
64 |
HEADER = '# Kamaki configuration file v%s' % version |
|
61 | 65 |
|
62 | 66 |
DEFAULTS = { |
63 | 67 |
'global': { |
68 |
'default_cloud': '', |
|
64 | 69 |
'colors': 'off', |
65 | 70 |
'log_file': os.path.expanduser('~/.kamaki.log'), |
66 | 71 |
'log_token': 'off', |
... | ... | |
79 | 84 |
# 'livetest_cli': 'livetest', |
80 | 85 |
# 'astakos_cli': 'snf-astakos' |
81 | 86 |
}, |
82 |
'remote':
|
|
87 |
'cloud':
|
|
83 | 88 |
{ |
84 |
'default': { |
|
85 |
'url': '', |
|
86 |
'token': '' |
|
87 |
#'pithos_type': 'object-store',
|
|
88 |
#'pithos_version': 'v1',
|
|
89 |
#'cyclades_type': 'compute',
|
|
90 |
#'cyclades_version': 'v2.0',
|
|
91 |
#'plankton_type': 'image',
|
|
92 |
#'plankton_version': '',
|
|
93 |
#'astakos_type': 'identity',
|
|
94 |
#'astakos_version': 'v2.0'
|
|
95 |
} |
|
89 |
#'default': {
|
|
90 |
# 'url': '',
|
|
91 |
# 'token': ''
|
|
92 |
# 'pithos_type': 'object-store',
|
|
93 |
# 'pithos_version': 'v1',
|
|
94 |
# 'cyclades_type': 'compute',
|
|
95 |
# 'cyclades_version': 'v2.0',
|
|
96 |
# 'plankton_type': 'image',
|
|
97 |
# 'plankton_version': '',
|
|
98 |
# 'astakos_type': 'identity',
|
|
99 |
# 'astakos_version': 'v2.0'
|
|
100 |
#}
|
|
96 | 101 |
} |
97 | 102 |
} |
98 | 103 |
|
... | ... | |
107 | 112 |
self.read(self.path) |
108 | 113 |
|
109 | 114 |
for section in self.sections(): |
110 |
r = self._remote_name(section)
|
|
115 |
r = self._cloud_name(section)
|
|
111 | 116 |
if r: |
112 | 117 |
for k, v in self.items(section): |
113 |
self.set_remote(r, k, v)
|
|
118 |
self.set_cloud(r, k, v)
|
|
114 | 119 |
self.remove_section(section) |
115 | 120 |
|
116 | 121 |
@staticmethod |
117 |
def _remote_name(full_section_name):
|
|
118 |
matcher = match('remote "(\w+)"', full_section_name)
|
|
122 |
def _cloud_name(full_section_name):
|
|
123 |
matcher = match('cloud "(\w+)"', full_section_name)
|
|
119 | 124 |
return matcher.groups()[0] if matcher else None |
120 | 125 |
|
121 | 126 |
def rescue_old_file(self): |
... | ... | |
139 | 144 |
user=dict(serv='astakos', cmd='user'), |
140 | 145 |
) |
141 | 146 |
|
147 |
self.set('global', 'default_cloud', 'default') |
|
142 | 148 |
for s in self.sections(): |
143 | 149 |
if s in ('global'): |
144 | 150 |
# global.url, global.token --> |
145 |
# remote.default.url, remote.default.token
|
|
151 |
# cloud.default.url, cloud.default.token
|
|
146 | 152 |
for term in set(self.keys(s)).difference(global_terms): |
147 | 153 |
if term not in ('url', 'token'): |
148 | 154 |
lost_terms.append('%s.%s = %s' % ( |
... | ... | |
150 | 156 |
self.remove_option(s, term) |
151 | 157 |
continue |
152 | 158 |
gval = self.get(s, term) |
153 |
cval = self.get_remote('default', term)
|
|
159 |
cval = self.get_cloud('default', term)
|
|
154 | 160 |
if gval and cval and ( |
155 | 161 |
gval.lower().strip('/') != cval.lower().strip('/')): |
156 | 162 |
raise CLISyntaxError( |
157 | 163 |
'Conflicting values for default %s' % term, |
158 | 164 |
importance=2, details=[ |
159 | 165 |
' global.%s: %s' % (term, gval), |
160 |
' remote.default.%s: %s' % (term, cval),
|
|
166 |
' cloud.default.%s: %s' % (term, cval),
|
|
161 | 167 |
'Please remove one of them manually:', |
162 | 168 |
' /config delete global.%s' % term, |
163 | 169 |
' or' |
164 |
' /config delete remote.default.%s' % term,
|
|
170 |
' /config delete cloud.default.%s' % term,
|
|
165 | 171 |
'and try again']) |
166 | 172 |
elif gval: |
167 |
print('... rescue %s.%s => remote.default.%s' % (
|
|
173 |
print('... rescue %s.%s => cloud.default.%s' % (
|
|
168 | 174 |
s, term, term)) |
169 |
self.set_remote('default', term, gval)
|
|
175 |
self.set_cloud('default', term, gval)
|
|
170 | 176 |
self.remove_option(s, term) |
171 | 177 |
# translation for <service> or <command> settings |
172 | 178 |
# <service> or <command group> settings --> translation --> global |
... | ... | |
186 | 192 |
if v and k in ('cli',): |
187 | 193 |
print('... rescue %s.%s => global.%s_cli' % ( |
188 | 194 |
s, k, trn['cmd'])) |
189 |
self.set('global', 'file_cli', v) |
|
190 |
elif (k in ('container', 'uuid')) and ( |
|
191 |
trn['serv'] in ('pithos',)): |
|
192 |
print( |
|
193 |
'... rescue %s.%s => remote.default.pithos_%s' % ( |
|
195 |
self.set('global', '%s_cli' % trn['cmd'], v) |
|
196 |
elif k in ('container',) and trn['serv'] in ('pithos',): |
|
197 |
print('... rescue %s.%s => cloud.default.pithos_%s' % ( |
|
194 | 198 |
s, k, k)) |
195 |
self.set_remote('default', 'pithos_%s' % k, v)
|
|
196 |
elif v:
|
|
199 |
self.set_cloud('default', 'pithos_%s' % k, v)
|
|
200 |
else:
|
|
197 | 201 |
lost_terms.append('%s.%s = %s' % (s, k, v)) |
198 | 202 |
self.remove_section(s) |
199 | 203 |
# self.pretty_print() |
... | ... | |
212 | 216 |
print '\t', k, '=>', v |
213 | 217 |
|
214 | 218 |
def guess_version(self): |
219 |
""" |
|
220 |
:returns: (float) version of the config file or 0.0 if unrecognized |
|
221 |
""" |
|
215 | 222 |
checker = Config(self.path, with_defaults=False) |
216 | 223 |
sections = checker.sections() |
217 |
log.warning('Config file heuristic 1: global section ?') |
|
224 |
log.warning('Config file heuristic 1: old global section ?')
|
|
218 | 225 |
if 'global' in sections: |
219 | 226 |
if checker.get('global', 'url') or checker.get('global', 'token'): |
220 | 227 |
log.warning('..... config file has an old global section') |
221 |
return 2.0 |
|
222 |
log.warning('........ nope') |
|
223 |
log.warning('Config file heuristic 2: at least 1 remote section ?') |
|
224 |
if 'remote' in sections: |
|
225 |
for r in self.keys('remote'): |
|
226 |
log.warning('... found remote "%s"' % r) |
|
227 |
return 3.0 |
|
228 |
return 8.0 |
|
228 | 229 |
log.warning('........ nope') |
230 |
log.warning('Config file heuristic 2: missing all cloud sections ?') |
|
231 |
if 'cloud' in sections: |
|
232 |
for r in self.keys('cloud'): |
|
233 |
log.warning('... found cloud "%s"' % r) |
|
234 |
return 9.0 |
|
235 |
log.warning('........ yep') |
|
229 | 236 |
log.warning('All heuristics failed, cannot decide') |
230 | 237 |
return 0.0 |
231 | 238 |
|
232 |
def get_remote(self, remote, option):
|
|
239 |
def get_cloud(self, cloud, option):
|
|
233 | 240 |
""" |
234 |
:param remote: (str) remote cloud alias
|
|
241 |
:param cloud: (str) cloud alias
|
|
235 | 242 |
|
236 |
:param option: (str) option in remote cloud section
|
|
243 |
:param option: (str) option in cloud section |
|
237 | 244 |
|
238 | 245 |
:returns: (str) the value assigned on this option |
239 | 246 |
|
240 |
:raises KeyError: if remote or remote's option does not exist
|
|
247 |
:raises KeyError: if cloud or cloud's option does not exist
|
|
241 | 248 |
""" |
242 |
r = self.get('remote', remote)
|
|
249 |
r = self.get('cloud', cloud)
|
|
243 | 250 |
if not r: |
244 |
raise KeyError('Remote "%s" does not exist' % remote)
|
|
251 |
raise KeyError('Cloud "%s" does not exist' % cloud)
|
|
245 | 252 |
return r[option] |
246 | 253 |
|
247 | 254 |
def get_global(self, option): |
248 | 255 |
return self.get('global', option) |
249 | 256 |
|
250 |
def set_remote(self, remote, option, value):
|
|
257 |
def set_cloud(self, cloud, option, value):
|
|
251 | 258 |
try: |
252 |
d = self.get('remote', remote) or dict()
|
|
259 |
d = self.get('cloud', cloud) or dict()
|
|
253 | 260 |
except KeyError: |
254 | 261 |
d = dict() |
255 | 262 |
d[option] = value |
256 |
self.set('remote', remote, d)
|
|
263 |
self.set('cloud', cloud, d)
|
|
257 | 264 |
|
258 | 265 |
def set_global(self, option, value): |
259 | 266 |
self.set('global', option, value) |
... | ... | |
279 | 286 |
|
280 | 287 |
def get(self, section, option): |
281 | 288 |
""" |
282 |
:param section: (str) HINT: for remotes, use remote.<section>
|
|
289 |
:param section: (str) HINT: for clouds, use cloud.<section>
|
|
283 | 290 |
|
284 | 291 |
:param option: (str) |
285 | 292 |
|
... | ... | |
288 | 295 |
value = self._overrides.get(section, {}).get(option) |
289 | 296 |
if value is not None: |
290 | 297 |
return value |
291 |
if section.startswith('remote.'): |
|
292 |
return self.get_remote(section[len('remote.'):], option) |
|
298 |
prefix = 'cloud.' |
|
299 |
if section.startswith(prefix): |
|
300 |
return self.get_cloud(section[len(prefix):], option) |
|
293 | 301 |
try: |
294 | 302 |
return RawConfigParser.get(self, section, option) |
295 | 303 |
except (NoSectionError, NoOptionError): |
... | ... | |
297 | 305 |
|
298 | 306 |
def set(self, section, option, value): |
299 | 307 |
""" |
300 |
:param section: (str) HINT: for remotes use remote.<section>
|
|
308 |
:param section: (str) HINT: for remotes use cloud.<section>
|
|
301 | 309 |
|
302 | 310 |
:param option: (str) |
303 | 311 |
|
304 | 312 |
:param value: str |
305 | 313 |
""" |
306 |
if section.startswith('remote.'): |
|
307 |
return self.set_remote(section[len('remote.')], option, value) |
|
314 |
prefix = 'cloud.' |
|
315 |
if section.startswith(prefix): |
|
316 |
return self.set_cloud(section[len(prefix)], option, value) |
|
308 | 317 |
if section not in RawConfigParser.sections(self): |
309 | 318 |
self.add_section(section) |
310 | 319 |
RawConfigParser.set(self, section, option, value) |
... | ... | |
317 | 326 |
except NoSectionError: |
318 | 327 |
pass |
319 | 328 |
|
320 |
def remove_from_remote(self, remote, option):
|
|
321 |
d = self.get('remote', remote)
|
|
329 |
def remote_from_cloud(self, cloud, option):
|
|
330 |
d = self.get('cloud', cloud)
|
|
322 | 331 |
if isinstance(d, dict): |
323 | 332 |
d.pop(option) |
324 | 333 |
|
... | ... | |
334 | 343 |
self._overrides[section][option] = value |
335 | 344 |
|
336 | 345 |
def write(self): |
337 |
for r, d in self.items('remote'):
|
|
346 |
for r, d in self.items('cloud'):
|
|
338 | 347 |
for k, v in d.items(): |
339 |
self.set('remote "%s"' % r, k, v)
|
|
340 |
self.remove_section('remote')
|
|
348 |
self.set('cloud "%s"' % r, k, v)
|
|
349 |
self.remove_section('cloud')
|
|
341 | 350 |
|
342 | 351 |
with open(self.path, 'w') as f: |
343 | 352 |
os.chmod(self.path, 0600) |
b/kamaki/cli/errors.py | ||
---|---|---|
78 | 78 |
'Two options to resolve this:', |
79 | 79 |
'A. (recommended) Let kamaki discover the endpoint URLs for all', |
80 | 80 |
'services by setting a single Authentication URL and token:', |
81 |
' /config set remote.default.url <AUTH_URL>',
|
|
82 |
' /config set remote.default.token <t0k3n>',
|
|
81 |
' /config set cloud.default.url <AUTH_URL>',
|
|
82 |
' /config set cloud.default.token <t0k3n>',
|
|
83 | 83 |
'B. (advanced users) Explicitly set a valid %s endpoint URL' % ( |
84 | 84 |
service.upper()), |
85 | 85 |
'Note: url option has a higher priority, so delete it to', |
86 | 86 |
'make that work', |
87 |
' /config delete remote.default.url',
|
|
88 |
' /config set remote.%s.url <%s_URL>' % (
|
|
87 |
' /config delete cloud.default.url',
|
|
88 |
' /config set cloud.%s.url <%s_URL>' % (
|
|
89 | 89 |
service, service.upper())] |
90 | 90 |
super(CLIBaseUrlError, self).__init__(message, details, importance) |
91 | 91 |
|
b/kamaki/cli/one_command.py | ||
---|---|---|
55 | 55 |
return None |
56 | 56 |
|
57 | 57 |
|
58 |
def run(remote_base, cloud, parser, _help):
|
|
58 |
def run(auth_base, cloud, parser, _help):
|
|
59 | 59 |
group = get_command_group(list(parser.unparsed), parser.arguments) |
60 | 60 |
if not group: |
61 | 61 |
parser.parser.print_help() |
... | ... | |
96 | 96 |
exit(0) |
97 | 97 |
|
98 | 98 |
cls = cmd.get_class() |
99 |
executable = cls(parser.arguments, remote_base, cloud)
|
|
99 |
executable = cls(parser.arguments, auth_base, cloud)
|
|
100 | 100 |
parser.update_arguments(executable.arguments) |
101 | 101 |
#parsed, unparsed = parse_known_args(parser, executable.arguments) |
102 | 102 |
for term in _best_match: |
Also available in: Unified diff