38 |
38 |
from ConfigParser import RawConfigParser, NoOptionError, NoSectionError
|
39 |
39 |
from re import match
|
40 |
40 |
|
|
41 |
from kamaki.cli.errors import CLISyntaxError
|
|
42 |
|
41 |
43 |
try:
|
42 |
44 |
from collections import OrderedDict
|
43 |
45 |
except ImportError:
|
... | ... | |
74 |
76 |
'config_cli': 'config',
|
75 |
77 |
'history_cli': 'history'
|
76 |
78 |
# Optional command specs:
|
77 |
|
# 'livetest': 'livetest',
|
78 |
|
# 'astakos': 'snf-astakos'
|
|
79 |
# 'livetest_cli': 'livetest',
|
|
80 |
# 'astakos_cli': 'snf-astakos'
|
79 |
81 |
},
|
80 |
82 |
'remotes':
|
81 |
83 |
{
|
... | ... | |
104 |
106 |
self._load_defaults()
|
105 |
107 |
self.read(self.path)
|
106 |
108 |
|
107 |
|
assert False, 'Config.__init__: translate remotes to dict first'
|
|
109 |
for section in self.sections():
|
|
110 |
r = self._remote_name(section)
|
|
111 |
if r:
|
|
112 |
for k, v in self.items(section):
|
|
113 |
self.set_remote(r, k, v)
|
|
114 |
self.remove_section(section)
|
108 |
115 |
|
109 |
116 |
@staticmethod
|
110 |
117 |
def _remote_name(full_section_name):
|
... | ... | |
112 |
119 |
return matcher.groups()[0] if matcher else None
|
113 |
120 |
|
114 |
121 |
def rescue_old_file(self):
|
115 |
|
pass
|
116 |
|
# global.url, global.token --> remote.default.url, remote.default.token
|
117 |
|
# remove global.url, global.token
|
118 |
|
# translation for <service> or <command> settings
|
119 |
|
# <service> or <command group> settings --> translation --> global
|
|
122 |
lost_terms = []
|
|
123 |
global_terms = DEFAULTS['global'].keys()
|
|
124 |
translations = dict(
|
|
125 |
config=dict(serv='', cmd='config'),
|
|
126 |
history=dict(serv='', cmd='history'),
|
|
127 |
pithos=dict(serv='pithos', cmd='file'),
|
|
128 |
file=dict(serv='pithos', cmd='file'),
|
|
129 |
store=dict(serv='pithos', cmd='file'),
|
|
130 |
storage=dict(serv='pithos', cmd='file'),
|
|
131 |
image=dict(serv='plankton', cmd='image'),
|
|
132 |
plankton=dict(serv='plankton', cmd='image'),
|
|
133 |
compute=dict(serv='compute', cmd=''),
|
|
134 |
cyclades=dict(serv='compute', cmd='server'),
|
|
135 |
server=dict(serv='compute', cmd='server'),
|
|
136 |
flavor=dict(serv='compute', cmd='flavor'),
|
|
137 |
network=dict(serv='compute', cmd='network'),
|
|
138 |
astakos=dict(serv='astakos', cmd='user'),
|
|
139 |
user=dict(serv='astakos', cmd='user'),
|
|
140 |
)
|
|
141 |
|
|
142 |
for s in self.sections():
|
|
143 |
if s in ('global'):
|
|
144 |
# global.url, global.token -->
|
|
145 |
# remote.default.url, remote.default.token
|
|
146 |
for term in set(self.keys(s)).difference(global_terms):
|
|
147 |
if term not in ('url', 'token'):
|
|
148 |
lost_terms.append('%s.%s = %s' % (
|
|
149 |
s, term, self.get(s, term)))
|
|
150 |
self.remove_option(s, term)
|
|
151 |
continue
|
|
152 |
gval = self.get(s, term)
|
|
153 |
cval = self.get_remote('default', term)
|
|
154 |
if gval and cval and (
|
|
155 |
gval.lower().strip('/') != cval.lower().strip('/')):
|
|
156 |
raise CLISyntaxError(
|
|
157 |
'Conflicting values for default %s' % term,
|
|
158 |
importance=2, details=[
|
|
159 |
' global.%s: %s' % (term, gval),
|
|
160 |
' remote.default.%s: %s' % (term, cval),
|
|
161 |
'Please remove one of them manually:',
|
|
162 |
' /config delete global.%s' % term,
|
|
163 |
' or'
|
|
164 |
' /config delete remote.default.%s' % term,
|
|
165 |
'and try again'])
|
|
166 |
elif gval:
|
|
167 |
print('... rescue %s.%s => remote.default.%s' % (
|
|
168 |
s, term, term))
|
|
169 |
self.set_remote('default', term, gval)
|
|
170 |
self.remove_option(s, term)
|
|
171 |
# translation for <service> or <command> settings
|
|
172 |
# <service> or <command group> settings --> translation --> global
|
|
173 |
elif s in translations:
|
|
174 |
|
|
175 |
if s in ('history',):
|
|
176 |
k = 'file'
|
|
177 |
v = self.get(s, k)
|
|
178 |
if v:
|
|
179 |
print('... rescue %s.%s => global.%s_%s' % (
|
|
180 |
s, k, s, k))
|
|
181 |
self.set('global', '%s_%s' % (s, k), v)
|
|
182 |
self.remove_option(s, k)
|
|
183 |
|
|
184 |
trn = translations[s]
|
|
185 |
for k, v in self.items(s, False):
|
|
186 |
if v and k in ('cli',):
|
|
187 |
print('... rescue %s.%s => global.%s_cli' % (
|
|
188 |
s, k, trn['cmd']))
|
|
189 |
self.set('global', 'file_cli', v)
|
|
190 |
elif v and k in ('url', 'token'):
|
|
191 |
print(
|
|
192 |
'... rescue %s.%s => remote.default.%s_%s' % (
|
|
193 |
s, k, trn['serv'], k))
|
|
194 |
self.set_remote('default', 'pithos_%s' % k, v)
|
|
195 |
elif v:
|
|
196 |
lost_terms.append('%s.%s = %s' % (s, k, v))
|
|
197 |
self.remove_section(s)
|
|
198 |
# self.pretty_print()
|
|
199 |
return lost_terms
|
|
200 |
|
|
201 |
def pretty_print(self):
|
|
202 |
for s in self.sections():
|
|
203 |
print s
|
|
204 |
for k, v in self.items(s):
|
|
205 |
if isinstance(v, dict):
|
|
206 |
print '\t', k, '=> {'
|
|
207 |
for ki, vi in v.items():
|
|
208 |
print '\t\t', ki, '=>', vi
|
|
209 |
print('\t}')
|
|
210 |
else:
|
|
211 |
print '\t', k, '=>', v
|
120 |
212 |
|
121 |
213 |
def guess_version(self):
|
122 |
214 |
checker = Config(self.path, with_defaults=False)
|
... | ... | |
128 |
220 |
return 2.0
|
129 |
221 |
log.warning('........ nope')
|
130 |
222 |
log.warning('Config file heuristic 2: at least 1 remote section ?')
|
131 |
|
for section in sections:
|
132 |
|
if self._remote_name(section):
|
133 |
|
log.warning('... found %s section' % section)
|
|
223 |
if 'remotes' in sections:
|
|
224 |
for r in self.keys('remotes'):
|
|
225 |
log.warning('... found remote "%s"' % r)
|
134 |
226 |
return 3.0
|
135 |
227 |
log.warning('........ nope')
|
136 |
228 |
log.warning('All heuristics failed, cannot decide')
|
137 |
229 |
return 0.0
|
138 |
230 |
|
|
231 |
def get_remote(self, remote, option):
|
|
232 |
"""
|
|
233 |
:param remote: (str) remote cloud alias
|
|
234 |
|
|
235 |
:param option: (str) option in remote cloud section
|
|
236 |
|
|
237 |
:returns: (str) the value assigned on this option
|
|
238 |
|
|
239 |
:raises KeyError: if remote or remote's option does not exist
|
|
240 |
"""
|
|
241 |
r = self.get('remotes', remote)
|
|
242 |
if not r:
|
|
243 |
raise KeyError('Remote "%s" does not exist' % remote)
|
|
244 |
return r[option]
|
|
245 |
|
|
246 |
def set_remote(self, remote, option, value):
|
|
247 |
try:
|
|
248 |
d = self.get('remotes', remote)
|
|
249 |
except KeyError:
|
|
250 |
pass
|
|
251 |
d[option] = value
|
|
252 |
self.set('remotes', remote, d)
|
|
253 |
|
139 |
254 |
def _load_defaults(self):
|
140 |
255 |
for section, options in DEFAULTS.items():
|
141 |
256 |
for option, val in options.items():
|
... | ... | |
190 |
305 |
self._overrides[section][option] = value
|
191 |
306 |
|
192 |
307 |
def write(self):
|
|
308 |
for r, d in self.items('remotes'):
|
|
309 |
for k, v in d.items():
|
|
310 |
self.set('remote "%s"' % r, k, v)
|
|
311 |
self.remove_section('remotes')
|
|
312 |
|
193 |
313 |
with open(self.path, 'w') as f:
|
194 |
314 |
os.chmod(self.path, 0600)
|
195 |
315 |
f.write(HEADER.lstrip())
|
196 |
316 |
f.flush()
|
197 |
|
assert False, 'Config.write: Trasnlate remotes to file first'
|
198 |
317 |
RawConfigParser.write(self, f)
|