Revision f724cd35

b/kamaki/cli/__init__.py
208 208
        remove_colors()
209 209
    _silent = arguments['silent'].value
210 210
    _setup_logging(_silent, _debug, _verbose, _include)
211
    global_url = arguments['config'].get('global', 'url')
212
    global_token = arguments['config'].get('global', 'token')
213
    from kamaki.clients.astakos import AstakosClient as AuthCachedClient
214
    return AuthCachedClient(global_url, global_token)
211 215

  
212 216

  
213 217
def _load_spec_module(spec, arguments, module):
214
    spec_name = arguments['config'].get(spec, 'cli')
215
    if spec_name is None:
218
    #spec_name = arguments['config'].get('cli', spec)
219
    if not spec:
216 220
        return None
217 221
    pkg = None
218 222
    for location in cmd_spec_locations:
219
        location += spec_name if location == '' else '.%s' % spec_name
223
        location += spec if location == '' else '.%s' % spec
220 224
        try:
221 225
            pkg = __import__(location, fromlist=[module])
222 226
            return pkg
223
        except ImportError:
227
        except ImportError as ie:
224 228
            continue
229
    if not pkg:
230
        kloger.debug('Loading cmd grp %s failed: %s' % (spec, ie))
225 231
    return pkg
226 232

  
227 233

  
......
229 235
    global _debug
230 236
    global kloger
231 237
    descriptions = {}
232
    for spec in arguments['config'].get_groups():
238
    for cmd_group, spec in arguments['config'].get_cli_specs():
233 239
        pkg = _load_spec_module(spec, arguments, '_commands')
234 240
        if pkg:
235
            cmds = None
236
            try:
237
                _cnf = arguments['config']
238
                cmds = [cmd for cmd in getattr(pkg, '_commands') if _cnf.get(
239
                    cmd.name, 'cli')]
240
            except AttributeError:
241
                if _debug:
242
                    kloger.warning('No description for %s' % spec)
241
            cmds = getattr(pkg, '_commands')
242
            #try:
243
            #   #_cnf = arguments['config']
244
            #   #cmds = [cmd for cmd in getattr(pkg, '_commands') if _cnf.get(
245
            #   #    'cli', cmd.name)]
246
            #except AttributeError:
247
            #   if _debug:
248
            #       kloger.warning('No description for %s' % cmd_group)
243 249
            try:
244 250
                for cmd in cmds:
245 251
                    descriptions[cmd.name] = cmd.description
246 252
            except TypeError:
247 253
                if _debug:
248
                    kloger.warning('no cmd specs in module %s' % spec)
254
                    kloger.warning(
255
                        'No cmd description for module %s' % cmd_group)
249 256
        elif _debug:
250
            kloger.warning('Loading of %s cmd spec failed' % spec)
257
            kloger.warning('Loading of %s cmd spec failed' % cmd_group)
251 258
    print('\nOptions:\n - - - -')
252 259
    print_dict(descriptions)
253 260

  
254 261

  
255 262
def _load_all_commands(cmd_tree, arguments):
256 263
    _cnf = arguments['config']
257
    specs = [spec for spec in _cnf.get_groups() if _cnf.get(spec, 'cli')]
258
    for spec in specs:
264
    #specs = [spec for spec in _cnf.get_groups() if _cnf.get(spec, 'cli')]
265
    for cmd_group, spec in _cnf.get_cli_specs():
259 266
        try:
260 267
            spec_module = _load_spec_module(spec, arguments, '_commands')
261 268
            spec_commands = getattr(spec_module, '_commands')
262 269
        except AttributeError:
263 270
            if _debug:
264 271
                global kloger
265
                kloger.warning('No valid description for %s' % spec)
272
                kloger.warning('No valid description for %s' % cmd_group)
266 273
            continue
267 274
        for spec_tree in spec_commands:
268
            if spec_tree.name == spec:
275
            if spec_tree.name == cmd_group:
269 276
                cmd_tree.add_tree(spec_tree)
270 277
                break
271 278

  
......
314 321
        errmsg = red(errmsg)
315 322
    stdout.write(errmsg)
316 323
    for errmsg in cli_err.details:
317
        print('| %s' % errmsg)
324
        print('|  %s' % errmsg)
318 325

  
319 326

  
320 327
def exec_cmd(instance, cmd_args, help_method):
......
358 365

  
359 366
#  CLI Choice:
360 367

  
361
def run_one_cmd(exe_string, parser):
368
def run_one_cmd(exe_string, parser, auth_base):
362 369
    global _history
363 370
    _history = History(
364 371
        parser.arguments['config'].get('history', 'file'))
365 372
    _history.add(' '.join([exe_string] + argv[1:]))
366 373
    from kamaki.cli import one_command
367
    one_command.run(parser, _help)
374
    one_command.run(auth_base, parser, _help)
368 375

  
369 376

  
370
def run_shell(exe_string, parser):
377
def run_shell(exe_string, parser, auth_base):
371 378
    from command_shell import _init_shell
372 379
    shell = _init_shell(exe_string, parser)
373 380
    _load_all_commands(shell.cmd_tree, parser.arguments)
374
    shell.run(parser)
381
    shell.run(auth_base, parser)
375 382

  
376 383

  
377 384
def main():
......
389 396
        filelog = logger.add_file_logger(__name__.split('.')[0])
390 397
        filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
391 398

  
392
        _init_session(parser.arguments)
399
        auth_base = _init_session(parser.arguments)
393 400

  
394 401
        from kamaki.cli.utils import suggest_missing
395 402
        suggest_missing()
396 403

  
397 404
        if parser.unparsed:
398
            run_one_cmd(exe, parser)
405
            run_one_cmd(exe, parser, auth_base)
399 406
        elif _help:
400 407
            parser.parser.print_help()
401 408
            _groups_help(parser.arguments)
402 409
        else:
403
            run_shell(exe, parser)
410
            run_shell(exe, parser, auth_base)
404 411
    except CLIError as err:
405 412
        print_error_message(err)
406 413
        if _debug:
b/kamaki/cli/argument.py
167 167
        return self.value.get(group, term)
168 168

  
169 169
    def get_groups(self):
170
        return self.value.apis()
170
        return self.value.keys('cli')
171

  
172
    def get_cli_specs(self):
173
        return self.value.items('cli')
171 174

  
172 175
_config_arg = ConfigArgument(
173 176
    1, 'Path to configuration file',
b/kamaki/cli/command_shell.py
68 68
    _context_stack = []
69 69
    _prompt_stack = []
70 70
    _parser = None
71
    auth_base = None
71 72

  
72 73
    undoc_header = 'interactive shell commands:'
73 74

  
......
197 198
                    if subcmd.path == 'history_run':
198 199
                        instance = cls(
199 200
                            dict(cmd_parser.arguments),
200
                            self.cmd_tree)
201
                            cmd_tree=self.cmd_tree)
201 202
                    else:
202
                        instance = cls(dict(cmd_parser.arguments))
203
                        instance = cls(
204
                            dict(cmd_parser.arguments), self.auth_base)
203 205
                    cmd_parser.update_arguments(instance.arguments)
204
                    #instance.arguments.pop('config')
205 206
                    cmd_parser.arguments = instance.arguments
206 207
                    cmd_parser.syntax = '%s %s' % (
207 208
                        subcmd.path.replace('_', ' '), cls.syntax)
......
296 297
        hdr = tmp_partition[0].strip()
297 298
        return '%s commands:' % hdr
298 299

  
299
    def run(self, parser, path=''):
300
    def run(self, auth_base, parser, path=''):
301
        self.auth_base = auth_base
300 302
        self._parser = parser
301 303
        self._history = History(
302 304
            parser.arguments['config'].get('history', 'file'))
b/kamaki/cli/commands/__init__.py
40 40

  
41 41
class _command_init(object):
42 42

  
43
    def __init__(self, arguments={}):
43
    def __init__(self, arguments={}, auth_base=None):
44 44
        if hasattr(self, 'arguments'):
45 45
            arguments.update(self.arguments)
46 46
        if isinstance(self, _optional_output_cmd):
......
52 52
            self.config = self['config']
53 53
        except KeyError:
54 54
            pass
55
        self.auth_base = auth_base or getattr(self, 'auth_base', None)
55 56

  
56 57
    def _set_log_params(self):
57 58
        try:
b/kamaki/cli/commands/astakos.py
32 32
# or implied, of GRNET S.A.command
33 33

  
34 34
from kamaki.cli import command
35
from kamaki.clients.astakos import AstakosClient
35
#from kamaki.clients.astakos import AstakosClient
36 36
from kamaki.cli.commands import _command_init, errors, _optional_json
37 37
from kamaki.cli.command_tree import CommandTree
38 38

  
......
45 45
    @errors.generic.all
46 46
    @errors.user.load
47 47
    def _run(self):
48
        token = self.config.get('user', 'token')\
49
            or self.config.get('global', 'token')
50
        base_url = self.config.get('user', 'url')\
51
            or self.config.get('global', 'url')
52
        self.client = AstakosClient(base_url=base_url, token=token)
48
        #token = self.config.get('user', 'token')\
49
        #    or self.config.get('global', 'token')
50
        #base_url = self.config.get('global', 'url')
51
        #self.client = AstakosClient(base_url=base_url, token=token)
52
        self.client = self.auth_base
53 53
        self._set_log_params()
54 54
        self._update_max_threads()
55 55

  
......
71 71
    @errors.user.authenticate
72 72
    def _run(self, custom_token=None):
73 73
        super(self.__class__, self)._run()
74
        self._print(
75
            [self.client.authenticate(custom_token)],
76
            title=('uuid', 'name',), with_redundancy=True)
74
        r = self.auth_base.authenticate(custom_token)
75
        self._print([r], title=('uuid', 'name',), with_redundancy=True)
77 76

  
78 77
    def main(self, custom_token=None):
79 78
        self._run(custom_token)
b/kamaki/cli/commands/config.py
41 41

  
42 42
about_options = '\nAbout options:\
43 43
    \n. syntax: [group.]option\
44
    \n. example: file.account\
44
    \n. example: file.uuid\
45 45
    \n. special case: <option> is equivalent to global.<option>\
46 46
    \n. configuration file syntax:\
47 47
    \n.   [group]\
b/kamaki/cli/commands/cyclades.py
70 70
    def _run(self, service='compute'):
71 71
        token = self.config.get(service, 'token')\
72 72
            or self.config.get('global', 'token')
73
        base_url = self.config.get(service, 'url')\
74
            or self.config.get('global', 'url')
73
        cyclades_endpoints = self.auth_base.get_service_endpoints(
74
            self.config.get('cyclades', 'type'),
75
            self.config.get('cyclades', 'version'))
76
        base_url = cyclades_endpoints['publicURL']
75 77
        self.client = CycladesClient(base_url=base_url, token=token)
76 78
        self._set_log_params()
77 79
        self._update_max_threads()
b/kamaki/cli/commands/errors.py
54 54
        return _raise
55 55

  
56 56
    @classmethod
57
    def _connection(this, foo, base_url):
57
    def _connection(this, foo):
58 58
        def _raise(self, *args, **kwargs):
59 59
            try:
60 60
                foo(self, *args, **kwargs)
......
68 68
                        '  to get current token: /config get [server.]token'])
69 69
                elif ce.status in range(-12, 200) + [302, 401, 403, 500]:
70 70
                    raiseCLIError(ce, importance=3, details=[
71
                        'Check if service is up or set to url %s' % base_url,
72
                        '  to get url: /config get %s' % base_url,
73
                        '  to set url: /config set %s <URL>' % base_url])
71
                        'Check if serviceis up'])
74 72
                elif ce.status == 404 and 'kamakihttpresponse' in ce_msg:
75 73
                    client = getattr(self, 'client', None)
76 74
                    if not client:
......
78 76
                    url = getattr(client, 'base_url', '<empty>')
79 77
                    msg = 'Invalid service url %s' % url
80 78
                    raiseCLIError(ce, msg, details=[
81
                        'Please, check if service url is correctly set',
82
                        '* to get current url: /config get compute.url',
83
                        '* to set url: /config set compute.url <URL>'])
79
                        'Check if authentication url is correct',
80
                        '  check current url:   /config get url',
81
                        '  set new auth. url:   /config set url'])
84 82
                raise
85 83
        return _raise
86 84

  
......
90 88
    _token_details = [
91 89
        'To check default token: /config get token',
92 90
        'If set/update a token:',
93
        '*  (permanent):    /config set token <token>',
94
        '*  (temporary):    re-run with <token> parameter']
91
        '*  (permanent):  /config set token <token>',
92
        '*  (temporary):  re-run with <token> parameter']
95 93

  
96 94
    @classmethod
97 95
    def load(this, foo):
......
105 103
                kloger.warning(
106 104
                    'No permanent token (try: kamaki config set token <tkn>)')
107 105
            if not getattr(client, 'base_url', False):
108
                msg = 'Missing astakos server URL'
106
                msg = 'Missing synnefo URL'
109 107
                raise CLIError(msg, importance=3, details=[
110
                    'Check if user.url is set correctly',
111
                    'To get astakos url:   /config get user.url',
112
                    'To set astakos url:   /config set user.url <URL>'])
108
                    'Check if authentication url is correct',
109
                        '  check current url:  /config get url',
110
                        '  set new auth. url:  /config set url'])
113 111
            return r
114 112
        return _raise
115 113

  
......
164 162

  
165 163
    @classmethod
166 164
    def connection(this, foo):
167
        return generic._connection(foo, 'compute.url')
165
        return generic._connection(foo)
168 166

  
169 167
    @classmethod
170 168
    def date(this, foo):
......
360 358

  
361 359
    @classmethod
362 360
    def connection(this, foo):
363
        return generic._connection(foo, 'image.url')
361
        return generic._connection(foo)
364 362

  
365 363
    @classmethod
366 364
    def id(this, foo):
......
408 406

  
409 407
    @classmethod
410 408
    def connection(this, foo):
411
        return generic._connection(foo, 'file.url')
409
        return generic._connection(foo)
412 410

  
413 411
    @classmethod
414 412
    def account(this, foo):
b/kamaki/cli/commands/history.py
160 160

  
161 161
    _cmd_tree = None
162 162

  
163
    def __init__(self, arguments={}, cmd_tree=None):
163
    def __init__(self, arguments={}, auth_base=None, cmd_tree=None):
164 164
        super(self.__class__, self).__init__(arguments)
165 165
        self._cmd_tree = cmd_tree
166 166

  
b/kamaki/cli/commands/image.py
77 77
        token = self.config.get('image', 'token')\
78 78
            or self.config.get('compute', 'token')\
79 79
            or self.config.get('global', 'token')
80
        plankton_endpoints = self.auth_base.get_service_endpoints(
81
            self.config.get('plankton', 'type'),
82
            self.config.get('plankton', 'version'))
83
        base_url = plankton_endpoints['publicURL']
80 84
        base_url = self.config.get('image', 'url')\
81 85
            or self.config.get('compute', 'url')\
82 86
            or self.config.get('global', 'url')
......
305 309
    def _get_pithos_client(self, container):
306 310
        if self['no_metafile_upload']:
307 311
            return None
308
        purl = self.config.get('file', 'url')
312
        pithos_endpoints = self.auth_base.get_service_endpoints(
313
            self.config.get('pithos', 'type'),
314
            self.config.get('pithos', 'version'))
315
        purl = pithos_endpoints['publicURL']
309 316
        ptoken = self.client.token
310 317
        return PithosClient(purl, ptoken, self._get_uuid(), container)
311 318

  
b/kamaki/cli/commands/pithos.py
154 154
    def _run(self):
155 155
        self.token = self.config.get('file', 'token')\
156 156
            or self.config.get('global', 'token')
157
        self.base_url = self.config.get('file', 'url')\
158
            or self.config.get('global', 'url')
157
        pithos_endpoints = self.auth_base.get_service_endpoints(
158
            self.config.get('pithos', 'type'),
159
            self.config.get('pithos', 'version'))
160
        self.base_url = pithos_endpoints['publicURL']
159 161
        self._set_account()
160 162
        self.container = self.config.get('file', 'container')\
161 163
            or self.config.get('global', 'container')
......
171 173
        self._run()
172 174

  
173 175
    def _set_account(self):
174
        user = AstakosClient(self.config.get('user', 'url'), self.token)
175
        self.account = self['account'] or user.term('uuid')
176

  
177
        """Backwards compatibility"""
178
        self.account = self.account\
179
            or self.config.get('file', 'account')\
180
            or self.config.get('global', 'account')
176
        self.account = self.auth_base.user_term('uuid', self.token)
181 177

  
182 178

  
183 179
class _file_account_command(_pithos_init):
184 180
    """Base class for account level storage commands"""
185 181

  
186
    def __init__(self, arguments={}):
187
        super(_file_account_command, self).__init__(arguments)
182
    def __init__(self, arguments={}, auth_base=None):
183
        super(_file_account_command, self).__init__(arguments, auth_base)
188 184
        self['account'] = ValueArgument(
189 185
            'Set user account (not permanent)',
190 186
            ('-A', '--account'))
......
207 203
    container = None
208 204
    path = None
209 205

  
210
    def __init__(self, arguments={}):
211
        super(_file_container_command, self).__init__(arguments)
206
    def __init__(self, arguments={}, auth_base=None):
207
        super(_file_container_command, self).__init__(arguments, auth_base)
212 208
        self['container'] = ValueArgument(
213 209
            'Set container to work with (temporary)',
214 210
            ('-C', '--container'))
......
525 521
        suffix_replace=ValueArgument('', '--suffix-to-replace', default=''),
526 522
    )
527 523

  
528
    def __init__(self, arguments={}):
524
    def __init__(self, arguments={}, auth_base=None):
529 525
        self.arguments.update(arguments)
530
        super(_source_destination_command, self).__init__(self.arguments)
526
        super(_source_destination_command, self).__init__(
527
            self.arguments, auth_base)
531 528

  
532 529
    def _run(self, source_container___path, path_is_optional=False):
533 530
        super(_source_destination_command, self)._run(
......
1480 1477
            ('-R', '--recursive'))
1481 1478
    )
1482 1479

  
1483
    def __init__(self, arguments={}):
1484
        super(self.__class__, self).__init__(arguments)
1480
    def __init__(self, arguments={}, auth_base=None):
1481
        super(self.__class__, self).__init__(arguments, auth_base)
1485 1482
        self['delimiter'] = DelimiterArgument(
1486 1483
            self,
1487 1484
            parsed_name='--delimiter',
b/kamaki/cli/commands/snf-astakos.py
50 50

  
51 51
class _astakos_init(_command_init):
52 52

  
53
    def __init__(self, arguments=dict()):
54
        super(_astakos_init, self).__init__(arguments)
53
    def __init__(self, arguments=dict(), auth_base=None):
54
        super(_astakos_init, self).__init__(arguments, auth_base)
55 55
        self['token'] = ValueArgument('Custom token', '--token')
56 56

  
57 57
    @errors.generic.all
......
61 61
            or self.config.get('astakos', 'token')\
62 62
            or self.config.get('user', 'token')\
63 63
            or self.config.get('global', 'token')
64
        base_url = self.config.get('astakos', 'url')\
65
            or self.config.get('user', 'url')\
66
            or self.config.get('global', 'url')
64
        astakos_endpoints = self.auth_base.get_service_endpoints(
65
            self.config.get('astakos', 'type'),
66
            self.config.get('astakos', 'version'))
67
        base_url = astakos_endpoints['publicURL']
67 68
        self.client = AstakosClient(base_url, logger=log)
68 69
        self._set_log_params()
69 70
        self._update_max_threads()
b/kamaki/cli/config.py
108 108
            for option, val in options.items():
109 109
                self.set(section, option, val)
110 110

  
111
    def _get_dict(self, section, include_defaults=True):
112
        try:
113
            d = dict(DEFAULTS[section]) if include_defaults else {}
114
        except KeyError:
115
            d = {}
116
        try:
117
            d.update(RawConfigParser.items(self, section))
118
        except NoSectionError:
119
            pass
120
        return d
121

  
111 122
    def reload(self):
112 123
        self = self.__init__(self.path)
113 124

  
114
    def apis(self):
115
        return [api for api in self.sections() if api != 'global']
116

  
117 125
    def get(self, section, option):
118 126
        value = self._overrides.get(section, {}).get(option)
119 127
        if value is not None:
......
137 145
        except NoSectionError:
138 146
            pass
139 147

  
148
    def keys(self, section, include_defaults=True):
149
        d = self._get_dict(section, include_defaults)
150
        return d.keys()
151

  
140 152
    def items(self, section, include_defaults=True):
141
        try:
142
            d = dict(DEFAULTS[section]) if include_defaults else {}
143
        except KeyError:
144
            d = {}
145
        try:
146
            d.update(RawConfigParser.items(self, section))
147
        except NoSectionError:
148
            pass
153
        d = self._get_dict(section, include_defaults)
149 154
        return d.items()
150 155

  
151 156
    def override(self, section, option, value):
b/kamaki/cli/one_command.py
55 55
    return None
56 56

  
57 57

  
58
def run(parser, _help):
58
def run(auth_base, parser, _help):
59 59
    group = get_command_group(list(parser.unparsed), parser.arguments)
60 60
    if not group:
61 61
        parser.parser.print_help()
......
68 68
    global _best_match
69 69
    _best_match = []
70 70

  
71
    spec_module = _load_spec_module(group, parser.arguments, '_commands')
71
    group_spec = parser.arguments['config'].get('cli', group)
72
    spec_module = _load_spec_module(group_spec, parser.arguments, '_commands')
72 73
    if spec_module is None:
73 74
        raise CLIUnknownCommand(
74 75
            'Could not find specs for %s commands' % group,
......
95 96
        exit(0)
96 97

  
97 98
    cls = cmd.get_class()
98
    executable = cls(parser.arguments)
99
    executable = cls(parser.arguments, auth_base)
99 100
    parser.update_arguments(executable.arguments)
100 101
    #parsed, unparsed = parse_known_args(parser, executable.arguments)
101 102
    for term in _best_match:
b/kamaki/clients/astakos/__init__.py
35 35
from logging import getLogger
36 36

  
37 37

  
38

  
39

  
40 38
class AstakosClient(Client):
41 39
    """Synnefo Astakos API client"""
42 40

  
......
139 137

  
140 138
    def term(self, key, token=None):
141 139
        """Get (cached) term, from user credentials"""
140
        return self.user_term(key, token)
141

  
142
    def user_term(self, key, token=None):
143
        """Get (cached) term, from user credentials"""
142 144
        return self.user_info(token).get(key, None)

Also available in: Unified diff