Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / __init__.py @ 16d7b9ff

History | View | Annotate | Download (17.9 kB)

1 d486baec Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 fd5db045 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 fd5db045 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 fd5db045 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 fd5db045 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 fd5db045 Stavros Sachtouris
#      provided with the distribution.
15 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 d486baec Stavros Sachtouris
# or implied, of GRNET S.A.command
33 7493ccb6 Stavros Sachtouris
34 7493ccb6 Stavros Sachtouris
import logging
35 3185cd6d Stavros Sachtouris
from sys import argv, exit, stdout, stderr
36 df0045d8 Stavros Sachtouris
from os.path import basename, exists
37 d486baec Stavros Sachtouris
from inspect import getargspec
38 3dabe5d2 Stavros Sachtouris
39 ee4c47d7 Stavros Sachtouris
from kamaki.cli.argument import ArgumentParseManager
40 fd5db045 Stavros Sachtouris
from kamaki.cli.history import History
41 af569ab9 Stavros Sachtouris
from kamaki.cli.utils import print_dict, red, magenta, yellow
42 7b2e4bf1 Stavros Sachtouris
from kamaki.cli.errors import CLIError, CLICmdSpecError
43 7637d600 Stavros Sachtouris
from kamaki.cli import logger
44 dc897a7e Stavros Sachtouris
from kamaki.clients.astakos import AstakosClient as AuthCachedClient
45 dc897a7e Stavros Sachtouris
from kamaki.clients import ClientError
46 7493ccb6 Stavros Sachtouris
47 d486baec Stavros Sachtouris
_help = False
48 d486baec Stavros Sachtouris
_debug = False
49 d486baec Stavros Sachtouris
_verbose = False
50 d486baec Stavros Sachtouris
_colors = False
51 aa5c0458 Stavros Sachtouris
kloger = None
52 9dc724e5 Stavros Sachtouris
filelog = None
53 fd5db045 Stavros Sachtouris
54 b6a99832 Stavros Sachtouris
#  command auxiliary methods
55 b6a99832 Stavros Sachtouris
56 b6a99832 Stavros Sachtouris
_best_match = []
57 b6a99832 Stavros Sachtouris
58 fd5db045 Stavros Sachtouris
59 24ff0a35 Stavros Sachtouris
def _arg2syntax(arg):
60 24ff0a35 Stavros Sachtouris
    return arg.replace(
61 24ff0a35 Stavros Sachtouris
        '____', '[:').replace(
62 2005b18e Stavros Sachtouris
            '___', ':').replace(
63 2005b18e Stavros Sachtouris
                '__', ']').replace(
64 2005b18e Stavros Sachtouris
                    '_', ' ')
65 24ff0a35 Stavros Sachtouris
66 24ff0a35 Stavros Sachtouris
67 d486baec Stavros Sachtouris
def _construct_command_syntax(cls):
68 fd5db045 Stavros Sachtouris
        spec = getargspec(cls.main.im_func)
69 fd5db045 Stavros Sachtouris
        args = spec.args[1:]
70 fd5db045 Stavros Sachtouris
        n = len(args) - len(spec.defaults or ())
71 24ff0a35 Stavros Sachtouris
        required = ' '.join(['<%s>' % _arg2syntax(x) for x in args[:n]])
72 24ff0a35 Stavros Sachtouris
        optional = ' '.join(['[%s]' % _arg2syntax(x) for x in args[n:]])
73 fd5db045 Stavros Sachtouris
        cls.syntax = ' '.join(x for x in [required, optional] if x)
74 fd5db045 Stavros Sachtouris
        if spec.varargs:
75 fd5db045 Stavros Sachtouris
            cls.syntax += ' <%s ...>' % spec.varargs
76 fd5db045 Stavros Sachtouris
77 fd5db045 Stavros Sachtouris
78 d486baec Stavros Sachtouris
def _num_of_matching_terms(basic_list, attack_list):
79 d486baec Stavros Sachtouris
    if not attack_list:
80 75c3fc42 Stavros Sachtouris
        return len(basic_list)
81 fd5db045 Stavros Sachtouris
82 d486baec Stavros Sachtouris
    matching_terms = 0
83 d486baec Stavros Sachtouris
    for i, term in enumerate(basic_list):
84 d486baec Stavros Sachtouris
        try:
85 d486baec Stavros Sachtouris
            if term != attack_list[i]:
86 d486baec Stavros Sachtouris
                break
87 d486baec Stavros Sachtouris
        except IndexError:
88 d486baec Stavros Sachtouris
            break
89 d486baec Stavros Sachtouris
        matching_terms += 1
90 d486baec Stavros Sachtouris
    return matching_terms
91 dfee2caf Stavros Sachtouris
92 fd5db045 Stavros Sachtouris
93 d486baec Stavros Sachtouris
def _update_best_match(name_terms, prefix=[]):
94 d486baec Stavros Sachtouris
    if prefix:
95 d486baec Stavros Sachtouris
        pref_list = prefix if isinstance(prefix, list) else prefix.split('_')
96 d486baec Stavros Sachtouris
    else:
97 d486baec Stavros Sachtouris
        pref_list = []
98 dfee2caf Stavros Sachtouris
99 d486baec Stavros Sachtouris
    num_of_matching_terms = _num_of_matching_terms(name_terms, pref_list)
100 d486baec Stavros Sachtouris
    global _best_match
101 e9533b0c Stavros Sachtouris
    if not prefix:
102 e9533b0c Stavros Sachtouris
        _best_match = []
103 fd5db045 Stavros Sachtouris
104 d486baec Stavros Sachtouris
    if num_of_matching_terms and len(_best_match) <= num_of_matching_terms:
105 d486baec Stavros Sachtouris
        if len(_best_match) < num_of_matching_terms:
106 d486baec Stavros Sachtouris
            _best_match = name_terms[:num_of_matching_terms]
107 d486baec Stavros Sachtouris
        return True
108 d486baec Stavros Sachtouris
    return False
109 d486baec Stavros Sachtouris
110 d486baec Stavros Sachtouris
111 d486baec Stavros Sachtouris
def command(cmd_tree, prefix='', descedants_depth=1):
112 d486baec Stavros Sachtouris
    """Load a class as a command
113 16d7b9ff Stavros Sachtouris
        e.g., spec_cmd0_cmd1 will be command spec cmd0
114 451a7992 Stavros Sachtouris

115 451a7992 Stavros Sachtouris
        :param cmd_tree: is initialized in cmd_spec file and is the structure
116 d486baec Stavros Sachtouris
            where commands are loaded. Var name should be _commands
117 451a7992 Stavros Sachtouris
        :param prefix: if given, load only commands prefixed with prefix,
118 451a7992 Stavros Sachtouris
        :param descedants_depth: is the depth of the tree descedants of the
119 d486baec Stavros Sachtouris
            prefix command. It is used ONLY if prefix and if prefix is not
120 d486baec Stavros Sachtouris
            a terminal command
121 451a7992 Stavros Sachtouris

122 451a7992 Stavros Sachtouris
        :returns: the specified class object
123 d486baec Stavros Sachtouris
    """
124 d486baec Stavros Sachtouris
125 d486baec Stavros Sachtouris
    def wrap(cls):
126 451a7992 Stavros Sachtouris
        global kloger
127 d486baec Stavros Sachtouris
        cls_name = cls.__name__
128 d486baec Stavros Sachtouris
129 d486baec Stavros Sachtouris
        if not cmd_tree:
130 d486baec Stavros Sachtouris
            if _debug:
131 451a7992 Stavros Sachtouris
                kloger.warning('command %s found but not loaded' % cls_name)
132 d486baec Stavros Sachtouris
            return cls
133 0b368c8c Stavros Sachtouris
134 d486baec Stavros Sachtouris
        name_terms = cls_name.split('_')
135 d486baec Stavros Sachtouris
        if not _update_best_match(name_terms, prefix):
136 e9533b0c Stavros Sachtouris
            if _debug:
137 451a7992 Stavros Sachtouris
                kloger.warning('%s failed to update_best_match' % cls_name)
138 d486baec Stavros Sachtouris
            return None
139 fd5db045 Stavros Sachtouris
140 d486baec Stavros Sachtouris
        global _best_match
141 d486baec Stavros Sachtouris
        max_len = len(_best_match) + descedants_depth
142 d486baec Stavros Sachtouris
        if len(name_terms) > max_len:
143 d486baec Stavros Sachtouris
            partial = '_'.join(name_terms[:max_len])
144 d486baec Stavros Sachtouris
            if not cmd_tree.has_command(partial):  # add partial path
145 d486baec Stavros Sachtouris
                cmd_tree.add_command(partial)
146 e9533b0c Stavros Sachtouris
            if _debug:
147 451a7992 Stavros Sachtouris
                kloger.warning('%s failed max_len test' % cls_name)
148 d486baec Stavros Sachtouris
            return None
149 fd5db045 Stavros Sachtouris
150 7b2e4bf1 Stavros Sachtouris
        try:
151 7b2e4bf1 Stavros Sachtouris
            (
152 7b2e4bf1 Stavros Sachtouris
                cls.description, sep, cls.long_description
153 7b2e4bf1 Stavros Sachtouris
            ) = cls.__doc__.partition('\n')
154 7b2e4bf1 Stavros Sachtouris
        except AttributeError:
155 7b2e4bf1 Stavros Sachtouris
            raise CLICmdSpecError(
156 7b2e4bf1 Stavros Sachtouris
                'No commend in %s (acts as cmd description)' % cls.__name__)
157 d486baec Stavros Sachtouris
        _construct_command_syntax(cls)
158 0b368c8c Stavros Sachtouris
159 38db356b Stavros Sachtouris
        cmd_tree.add_command(
160 38db356b Stavros Sachtouris
            cls_name, cls.description, cls, cls.long_description)
161 d486baec Stavros Sachtouris
        return cls
162 d486baec Stavros Sachtouris
    return wrap
163 fd5db045 Stavros Sachtouris
164 0b368c8c Stavros Sachtouris
165 d486baec Stavros Sachtouris
cmd_spec_locations = [
166 d486baec Stavros Sachtouris
    'kamaki.cli.commands',
167 d486baec Stavros Sachtouris
    'kamaki.commands',
168 d486baec Stavros Sachtouris
    'kamaki.cli',
169 d486baec Stavros Sachtouris
    'kamaki',
170 d486baec Stavros Sachtouris
    '']
171 fd5db045 Stavros Sachtouris
172 0b368c8c Stavros Sachtouris
173 b6a99832 Stavros Sachtouris
#  Generic init auxiliary functions
174 b6a99832 Stavros Sachtouris
175 b6a99832 Stavros Sachtouris
176 f6822a26 Stavros Sachtouris
def _setup_logging(silent=False, debug=False, verbose=False):
177 fd5db045 Stavros Sachtouris
    """handle logging for clients package"""
178 fd5db045 Stavros Sachtouris
179 fd5db045 Stavros Sachtouris
    if silent:
180 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.CRITICAL)
181 db8d1766 Stavros Sachtouris
        return
182 db8d1766 Stavros Sachtouris
183 6e1f863b Stavros Sachtouris
    sfmt, rfmt = '> %(message)s', '< %(message)s'
184 db8d1766 Stavros Sachtouris
    if debug:
185 9dc724e5 Stavros Sachtouris
        print('Logging location: %s' % logger.get_log_filename())
186 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.DEBUG, sfmt)
187 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.DEBUG, rfmt)
188 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.DEBUG)
189 fd5db045 Stavros Sachtouris
    elif verbose:
190 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.INFO, sfmt)
191 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.INFO, rfmt)
192 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.INFO)
193 9dc724e5 Stavros Sachtouris
    logger.add_stream_logger(__name__, logging.WARNING)
194 aa5c0458 Stavros Sachtouris
    global kloger
195 9dc724e5 Stavros Sachtouris
    kloger = logger.get_logger(__name__)
196 fd5db045 Stavros Sachtouris
197 ce48608f Stavros Sachtouris
198 ce9ccb40 Stavros Sachtouris
def _check_config_version(cnf):
199 ce9ccb40 Stavros Sachtouris
    guess = cnf.guess_version()
200 df0045d8 Stavros Sachtouris
    if exists(cnf.path) and guess < 0.9:
201 c825ddc9 Stavros Sachtouris
        print('Config file format version >= 9.0 is required')
202 df0045d8 Stavros Sachtouris
        print('Configuration file: %s' % cnf.path)
203 fa382f9e Stavros Sachtouris
        print('Attempting to fix this:')
204 362adf50 Stavros Sachtouris
        print('Calculating changes while preserving information')
205 ce9ccb40 Stavros Sachtouris
        lost_terms = cnf.rescue_old_file()
206 ce9ccb40 Stavros Sachtouris
        print('... DONE')
207 362adf50 Stavros Sachtouris
        if lost_terms:
208 362adf50 Stavros Sachtouris
            print 'The following information will NOT be preserved:'
209 362adf50 Stavros Sachtouris
            print '\t', '\n\t'.join(lost_terms)
210 fa382f9e Stavros Sachtouris
        print('Kamaki is ready to convert the config file')
211 904091dd Stavros Sachtouris
        stdout.write('Create (overwrite) file %s ? [y/N] ' % cnf.path)
212 ce9ccb40 Stavros Sachtouris
        from sys import stdin
213 ce9ccb40 Stavros Sachtouris
        reply = stdin.readline()
214 ce9ccb40 Stavros Sachtouris
        if reply in ('Y\n', 'y\n'):
215 ce9ccb40 Stavros Sachtouris
            cnf.write()
216 ce9ccb40 Stavros Sachtouris
            print('... DONE')
217 ce9ccb40 Stavros Sachtouris
        else:
218 ce9ccb40 Stavros Sachtouris
            print('... ABORTING')
219 ce9ccb40 Stavros Sachtouris
            raise CLIError(
220 ce9ccb40 Stavros Sachtouris
                'Invalid format for config file %s' % cnf.path,
221 362adf50 Stavros Sachtouris
                importance=3, details=[
222 fa382f9e Stavros Sachtouris
                    'Please, update config file',
223 362adf50 Stavros Sachtouris
                    'For automatic conversion, rerun and say Y'])
224 ce9ccb40 Stavros Sachtouris
225 ce9ccb40 Stavros Sachtouris
226 362adf50 Stavros Sachtouris
def _init_session(arguments, is_non_API=False):
227 844a6bdb Stavros Sachtouris
    """
228 db03f805 Stavros Sachtouris
    :returns: cloud name
229 844a6bdb Stavros Sachtouris
    """
230 d486baec Stavros Sachtouris
    global _help
231 d486baec Stavros Sachtouris
    _help = arguments['help'].value
232 d486baec Stavros Sachtouris
    global _debug
233 d486baec Stavros Sachtouris
    _debug = arguments['debug'].value
234 d486baec Stavros Sachtouris
    global _verbose
235 d486baec Stavros Sachtouris
    _verbose = arguments['verbose'].value
236 cb4a5d9c Stavros Sachtouris
    _cnf = arguments['config']
237 df0045d8 Stavros Sachtouris
238 f1d06d74 Stavros Sachtouris
    _silent = arguments['silent'].value
239 f6822a26 Stavros Sachtouris
    _setup_logging(_silent, _debug, _verbose)
240 f1d06d74 Stavros Sachtouris
241 df0045d8 Stavros Sachtouris
    if _help or is_non_API:
242 db03f805 Stavros Sachtouris
        return None
243 df0045d8 Stavros Sachtouris
244 ce9ccb40 Stavros Sachtouris
    _check_config_version(_cnf.value)
245 3f0eae61 Stavros Sachtouris
246 d486baec Stavros Sachtouris
    global _colors
247 362adf50 Stavros Sachtouris
    _colors = _cnf.value.get_global('colors')
248 87565d2c Stavros Sachtouris
    if not (stdout.isatty() and _colors == 'on'):
249 4f6a21f6 Stavros Sachtouris
        from kamaki.cli.utils import remove_colors
250 4f6a21f6 Stavros Sachtouris
        remove_colors()
251 362adf50 Stavros Sachtouris
252 c825ddc9 Stavros Sachtouris
    cloud = arguments['cloud'].value or _cnf.value.get(
253 c825ddc9 Stavros Sachtouris
        'global', 'default_cloud')
254 c825ddc9 Stavros Sachtouris
    if not cloud:
255 c825ddc9 Stavros Sachtouris
        num_of_clouds = len(_cnf.value.keys('cloud'))
256 c825ddc9 Stavros Sachtouris
        if num_of_clouds == 1:
257 c825ddc9 Stavros Sachtouris
            cloud = _cnf.value.keys('cloud')[0]
258 df0045d8 Stavros Sachtouris
        elif num_of_clouds > 1:
259 c825ddc9 Stavros Sachtouris
            raise CLIError(
260 44101d8a Stavros Sachtouris
                'Found %s clouds but none of them is set as default' % (
261 44101d8a Stavros Sachtouris
                    num_of_clouds),
262 c825ddc9 Stavros Sachtouris
                importance=2, details=[
263 c825ddc9 Stavros Sachtouris
                    'Please, choose one of the following cloud names:',
264 c825ddc9 Stavros Sachtouris
                    ', '.join(_cnf.value.keys('cloud')),
265 44101d8a Stavros Sachtouris
                    'To see all cloud settings:',
266 44101d8a Stavros Sachtouris
                    '  kamaki config get cloud.<cloud name>',
267 c825ddc9 Stavros Sachtouris
                    'To set a default cloud:',
268 c825ddc9 Stavros Sachtouris
                    '  kamaki config set default_cloud <cloud name>',
269 c825ddc9 Stavros Sachtouris
                    'To pick a cloud for the current session, use --cloud:',
270 c825ddc9 Stavros Sachtouris
                    '  kamaki --cloud=<cloud name> ...'])
271 144b3551 Stavros Sachtouris
    if not cloud in _cnf.value.keys('cloud'):
272 362adf50 Stavros Sachtouris
        raise CLIError(
273 df0045d8 Stavros Sachtouris
            'No cloud%s is configured' % ((' "%s"' % cloud) if cloud else ''),
274 362adf50 Stavros Sachtouris
            importance=3, details=[
275 df0045d8 Stavros Sachtouris
                'To configure a new cloud "%s", find and set the' % (
276 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>'),
277 362adf50 Stavros Sachtouris
                'single authentication URL and token:',
278 df0045d8 Stavros Sachtouris
                '  kamaki config set cloud.%s.url <URL>' % (
279 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>'),
280 df0045d8 Stavros Sachtouris
                '  kamaki config set cloud.%s.token <t0k3n>' % (
281 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>')])
282 844a6bdb Stavros Sachtouris
    auth_args = dict()
283 844a6bdb Stavros Sachtouris
    for term in ('url', 'token'):
284 c825ddc9 Stavros Sachtouris
        try:
285 c825ddc9 Stavros Sachtouris
            auth_args[term] = _cnf.get_cloud(cloud, term)
286 dc897a7e Stavros Sachtouris
        except KeyError or IndexError:
287 c825ddc9 Stavros Sachtouris
            auth_args[term] = ''
288 844a6bdb Stavros Sachtouris
        if not auth_args[term]:
289 844a6bdb Stavros Sachtouris
            raise CLIError(
290 b4ed3a7e Stavros Sachtouris
                'No authentication %s provided for cloud "%s"' % (
291 b4ed3a7e Stavros Sachtouris
                    term.upper(), cloud),
292 844a6bdb Stavros Sachtouris
                importance=3, details=[
293 b4ed3a7e Stavros Sachtouris
                    'Set a %s for cloud %s:' % (term.upper(), cloud),
294 44101d8a Stavros Sachtouris
                    '  kamaki config set cloud.%s.%s <%s>' % (
295 b4ed3a7e Stavros Sachtouris
                        cloud, term, term.upper())])
296 db03f805 Stavros Sachtouris
    return cloud
297 db03f805 Stavros Sachtouris
298 362adf50 Stavros Sachtouris
299 db03f805 Stavros Sachtouris
def init_cached_authenticator(url, tokens, config_module, logger):
300 8cec3671 Stavros Sachtouris
    try:
301 dc897a7e Stavros Sachtouris
        auth_base = None
302 db03f805 Stavros Sachtouris
        for token in reversed(tokens):
303 dc897a7e Stavros Sachtouris
            try:
304 dc897a7e Stavros Sachtouris
                if auth_base:
305 dc897a7e Stavros Sachtouris
                    auth_base.authenticate(token)
306 dc897a7e Stavros Sachtouris
                else:
307 db03f805 Stavros Sachtouris
                    auth_base = AuthCachedClient(url, tokens)
308 f5ff79d9 Stavros Sachtouris
                    from kamaki.cli.commands import _command_init
309 db03f805 Stavros Sachtouris
                    fake_cmd = _command_init(dict(config=config_module))
310 f5ff79d9 Stavros Sachtouris
                    fake_cmd.client = auth_base
311 f5ff79d9 Stavros Sachtouris
                    fake_cmd._set_log_params()
312 f5ff79d9 Stavros Sachtouris
                    fake_cmd._update_max_threads()
313 dc897a7e Stavros Sachtouris
                    auth_base.authenticate(token)
314 dc897a7e Stavros Sachtouris
            except ClientError as ce:
315 dc897a7e Stavros Sachtouris
                if ce.status in (401, ):
316 db03f805 Stavros Sachtouris
                    logger.warning(
317 db03f805 Stavros Sachtouris
                        'WARNING: Failed to authenticate token %s' % token)
318 dc897a7e Stavros Sachtouris
                else:
319 dc897a7e Stavros Sachtouris
                    raise
320 db03f805 Stavros Sachtouris
        return auth_base
321 8cec3671 Stavros Sachtouris
    except AssertionError as ae:
322 db03f805 Stavros Sachtouris
        logger.warning('WARNING: Failed to load authenticator [%s]' % ae)
323 db03f805 Stavros Sachtouris
        return None
324 d486baec Stavros Sachtouris
325 d486baec Stavros Sachtouris
326 d486baec Stavros Sachtouris
def _load_spec_module(spec, arguments, module):
327 f1d06d74 Stavros Sachtouris
    global kloger
328 f724cd35 Stavros Sachtouris
    if not spec:
329 d486baec Stavros Sachtouris
        return None
330 d486baec Stavros Sachtouris
    pkg = None
331 d486baec Stavros Sachtouris
    for location in cmd_spec_locations:
332 f724cd35 Stavros Sachtouris
        location += spec if location == '' else '.%s' % spec
333 d486baec Stavros Sachtouris
        try:
334 f1d06d74 Stavros Sachtouris
            kloger.debug('Import %s from %s' % ([module], location))
335 d486baec Stavros Sachtouris
            pkg = __import__(location, fromlist=[module])
336 f1d06d74 Stavros Sachtouris
            kloger.debug('\t...OK')
337 d486baec Stavros Sachtouris
            return pkg
338 f724cd35 Stavros Sachtouris
        except ImportError as ie:
339 f1d06d74 Stavros Sachtouris
            kloger.debug('\t...Failed')
340 d486baec Stavros Sachtouris
            continue
341 f724cd35 Stavros Sachtouris
    if not pkg:
342 5506d7aa Stavros Sachtouris
        msg = 'Loading command group %s failed: %s' % (spec, ie)
343 f1d06d74 Stavros Sachtouris
        msg += '\nHINT: use a text editor to remove all global.*_cli'
344 f1d06d74 Stavros Sachtouris
        msg += '\n\tsettings from the configuration file'
345 f1d06d74 Stavros Sachtouris
        kloger.debug(msg)
346 d486baec Stavros Sachtouris
    return pkg
347 d486baec Stavros Sachtouris
348 d486baec Stavros Sachtouris
349 d486baec Stavros Sachtouris
def _groups_help(arguments):
350 d486baec Stavros Sachtouris
    global _debug
351 aa5c0458 Stavros Sachtouris
    global kloger
352 d486baec Stavros Sachtouris
    descriptions = {}
353 a7aacf12 Stavros Sachtouris
    acceptable_groups = arguments['config'].groups
354 a7aacf12 Stavros Sachtouris
    for cmd_group, spec in arguments['config'].cli_specs:
355 d486baec Stavros Sachtouris
        pkg = _load_spec_module(spec, arguments, '_commands')
356 d486baec Stavros Sachtouris
        if pkg:
357 f724cd35 Stavros Sachtouris
            cmds = getattr(pkg, '_commands')
358 d486baec Stavros Sachtouris
            try:
359 d252a7a8 Stavros Sachtouris
                for cmd_tree in cmds:
360 d252a7a8 Stavros Sachtouris
                    if cmd_tree.name in acceptable_groups:
361 d252a7a8 Stavros Sachtouris
                        descriptions[cmd_tree.name] = cmd_tree.description
362 d486baec Stavros Sachtouris
            except TypeError:
363 d486baec Stavros Sachtouris
                if _debug:
364 f724cd35 Stavros Sachtouris
                    kloger.warning(
365 eb46e9a1 Stavros Sachtouris
                        'No cmd description (help) for module %s' % cmd_group)
366 d486baec Stavros Sachtouris
        elif _debug:
367 f724cd35 Stavros Sachtouris
            kloger.warning('Loading of %s cmd spec failed' % cmd_group)
368 d486baec Stavros Sachtouris
    print('\nOptions:\n - - - -')
369 d486baec Stavros Sachtouris
    print_dict(descriptions)
370 d486baec Stavros Sachtouris
371 d486baec Stavros Sachtouris
372 b6a99832 Stavros Sachtouris
def _load_all_commands(cmd_tree, arguments):
373 24ff0a35 Stavros Sachtouris
    _cnf = arguments['config']
374 a7aacf12 Stavros Sachtouris
    for cmd_group, spec in _cnf.cli_specs:
375 b6a99832 Stavros Sachtouris
        try:
376 b6a99832 Stavros Sachtouris
            spec_module = _load_spec_module(spec, arguments, '_commands')
377 b6a99832 Stavros Sachtouris
            spec_commands = getattr(spec_module, '_commands')
378 b6a99832 Stavros Sachtouris
        except AttributeError:
379 b6a99832 Stavros Sachtouris
            if _debug:
380 b6a99832 Stavros Sachtouris
                global kloger
381 f724cd35 Stavros Sachtouris
                kloger.warning('No valid description for %s' % cmd_group)
382 b6a99832 Stavros Sachtouris
            continue
383 b6a99832 Stavros Sachtouris
        for spec_tree in spec_commands:
384 f724cd35 Stavros Sachtouris
            if spec_tree.name == cmd_group:
385 b6a99832 Stavros Sachtouris
                cmd_tree.add_tree(spec_tree)
386 b6a99832 Stavros Sachtouris
                break
387 b6a99832 Stavros Sachtouris
388 b6a99832 Stavros Sachtouris
389 b6a99832 Stavros Sachtouris
#  Methods to be used by CLI implementations
390 b6a99832 Stavros Sachtouris
391 b6a99832 Stavros Sachtouris
392 b6a99832 Stavros Sachtouris
def print_subcommands_help(cmd):
393 d486baec Stavros Sachtouris
    printout = {}
394 eb46e9a1 Stavros Sachtouris
    for subcmd in cmd.subcommands.values():
395 4f6a21f6 Stavros Sachtouris
        spec, sep, print_path = subcmd.path.partition('_')
396 eb46e9a1 Stavros Sachtouris
        printout[print_path.replace('_', ' ')] = subcmd.help
397 d486baec Stavros Sachtouris
    if printout:
398 d486baec Stavros Sachtouris
        print('\nOptions:\n - - - -')
399 d486baec Stavros Sachtouris
        print_dict(printout)
400 d486baec Stavros Sachtouris
401 d486baec Stavros Sachtouris
402 b6a99832 Stavros Sachtouris
def update_parser_help(parser, cmd):
403 d486baec Stavros Sachtouris
    global _best_match
404 7c2247a0 Stavros Sachtouris
    parser.syntax = parser.syntax.split('<')[0]
405 7c2247a0 Stavros Sachtouris
    parser.syntax += ' '.join(_best_match)
406 d486baec Stavros Sachtouris
407 a71bb904 Stavros Sachtouris
    description = ''
408 d486baec Stavros Sachtouris
    if cmd.is_command:
409 eb46e9a1 Stavros Sachtouris
        cls = cmd.cmd_class
410 7c2247a0 Stavros Sachtouris
        parser.syntax += ' ' + cls.syntax
411 7c2247a0 Stavros Sachtouris
        parser.update_arguments(cls().arguments)
412 eb46e9a1 Stavros Sachtouris
        description = getattr(cls, 'long_description', '').strip()
413 d486baec Stavros Sachtouris
    else:
414 7c2247a0 Stavros Sachtouris
        parser.syntax += ' <...>'
415 eb46e9a1 Stavros Sachtouris
    parser.parser.description = (
416 eb46e9a1 Stavros Sachtouris
        cmd.help + ('\n' if description else '')) if cmd.help else description
417 d486baec Stavros Sachtouris
418 d486baec Stavros Sachtouris
419 3185cd6d Stavros Sachtouris
def print_error_message(cli_err, out=stderr):
420 d486baec Stavros Sachtouris
    errmsg = '%s' % cli_err
421 d486baec Stavros Sachtouris
    if cli_err.importance == 1:
422 d486baec Stavros Sachtouris
        errmsg = magenta(errmsg)
423 d486baec Stavros Sachtouris
    elif cli_err.importance == 2:
424 d486baec Stavros Sachtouris
        errmsg = yellow(errmsg)
425 d486baec Stavros Sachtouris
    elif cli_err.importance > 2:
426 d486baec Stavros Sachtouris
        errmsg = red(errmsg)
427 3185cd6d Stavros Sachtouris
    out.write(errmsg)
428 66f1ff99 Stavros Sachtouris
    for errmsg in cli_err.details:
429 3185cd6d Stavros Sachtouris
        out.write('|  %s\n' % errmsg)
430 3185cd6d Stavros Sachtouris
        out.flush()
431 d486baec Stavros Sachtouris
432 d486baec Stavros Sachtouris
433 b6a99832 Stavros Sachtouris
def exec_cmd(instance, cmd_args, help_method):
434 fd5db045 Stavros Sachtouris
    try:
435 fd5db045 Stavros Sachtouris
        return instance.main(*cmd_args)
436 fd5db045 Stavros Sachtouris
    except TypeError as err:
437 fd5db045 Stavros Sachtouris
        if err.args and err.args[0].startswith('main()'):
438 fd5db045 Stavros Sachtouris
            print(magenta('Syntax error'))
439 d486baec Stavros Sachtouris
            if _debug:
440 d486baec Stavros Sachtouris
                raise err
441 d486baec Stavros Sachtouris
            if _verbose:
442 fd5db045 Stavros Sachtouris
                print(unicode(err))
443 fd5db045 Stavros Sachtouris
            help_method()
444 fd5db045 Stavros Sachtouris
        else:
445 fd5db045 Stavros Sachtouris
            raise
446 fd5db045 Stavros Sachtouris
    return 1
447 fd5db045 Stavros Sachtouris
448 f247bcb4 Stavros Sachtouris
449 b6a99832 Stavros Sachtouris
def get_command_group(unparsed, arguments):
450 a7aacf12 Stavros Sachtouris
    groups = arguments['config'].groups
451 b6a99832 Stavros Sachtouris
    for term in unparsed:
452 b6a99832 Stavros Sachtouris
        if term.startswith('-'):
453 b6a99832 Stavros Sachtouris
            continue
454 b6a99832 Stavros Sachtouris
        if term in groups:
455 b6a99832 Stavros Sachtouris
            unparsed.remove(term)
456 b6a99832 Stavros Sachtouris
            return term
457 b6a99832 Stavros Sachtouris
        return None
458 b6a99832 Stavros Sachtouris
    return None
459 b6a99832 Stavros Sachtouris
460 b6a99832 Stavros Sachtouris
461 7c2247a0 Stavros Sachtouris
def set_command_params(parameters):
462 7c2247a0 Stavros Sachtouris
    """Add a parameters list to a command
463 7c2247a0 Stavros Sachtouris

464 7c2247a0 Stavros Sachtouris
    :param paramters: (list of str) a list of parameters
465 7c2247a0 Stavros Sachtouris
    """
466 d486baec Stavros Sachtouris
    global command
467 d486baec Stavros Sachtouris
    def_params = list(command.func_defaults)
468 7c2247a0 Stavros Sachtouris
    def_params[0] = parameters
469 d486baec Stavros Sachtouris
    command.func_defaults = tuple(def_params)
470 d486baec Stavros Sachtouris
471 d486baec Stavros Sachtouris
472 b6a99832 Stavros Sachtouris
#  CLI Choice:
473 d486baec Stavros Sachtouris
474 db03f805 Stavros Sachtouris
def run_one_cmd(exe_string, parser, cloud):
475 b6a99832 Stavros Sachtouris
    global _history
476 db03f805 Stavros Sachtouris
    _history = History(parser.arguments['config'].get_global('history_file'))
477 b6a99832 Stavros Sachtouris
    _history.add(' '.join([exe_string] + argv[1:]))
478 b6a99832 Stavros Sachtouris
    from kamaki.cli import one_command
479 db03f805 Stavros Sachtouris
    one_command.run(cloud, parser, _help)
480 d53062bd Stavros Sachtouris
481 d53062bd Stavros Sachtouris
482 db03f805 Stavros Sachtouris
def run_shell(exe_string, parser, cloud):
483 d53062bd Stavros Sachtouris
    from command_shell import _init_shell
484 db03f805 Stavros Sachtouris
    global kloger
485 db03f805 Stavros Sachtouris
    _cnf = parser.arguments['config']
486 db03f805 Stavros Sachtouris
    auth_base = init_cached_authenticator(
487 db03f805 Stavros Sachtouris
        _cnf.get_cloud(cloud, 'url'), _cnf.get_cloud(cloud, 'token').split(),
488 db03f805 Stavros Sachtouris
        _cnf, kloger)
489 6a2a28bd Stavros Sachtouris
    try:
490 6a2a28bd Stavros Sachtouris
        username, userid = (
491 6a2a28bd Stavros Sachtouris
            auth_base.user_term('name'), auth_base.user_term('id'))
492 6a2a28bd Stavros Sachtouris
    except Exception:
493 6a2a28bd Stavros Sachtouris
        username, userid = '', ''
494 6a2a28bd Stavros Sachtouris
    shell = _init_shell(exe_string, parser, username, userid)
495 074f5027 Stavros Sachtouris
    _load_all_commands(shell.cmd_tree, parser.arguments)
496 844a6bdb Stavros Sachtouris
    shell.run(auth_base, cloud, parser)
497 fd5db045 Stavros Sachtouris
498 1c1fd2fa Stavros Sachtouris
499 362adf50 Stavros Sachtouris
def is_non_API(parser):
500 362adf50 Stavros Sachtouris
    nonAPIs = ('history', 'config')
501 362adf50 Stavros Sachtouris
    for term in parser.unparsed:
502 362adf50 Stavros Sachtouris
        if not term.startswith('-'):
503 362adf50 Stavros Sachtouris
            if term in nonAPIs:
504 362adf50 Stavros Sachtouris
                return True
505 362adf50 Stavros Sachtouris
            return False
506 362adf50 Stavros Sachtouris
    return False
507 362adf50 Stavros Sachtouris
508 362adf50 Stavros Sachtouris
509 1c1fd2fa Stavros Sachtouris
def main():
510 71882bca Stavros Sachtouris
    try:
511 71882bca Stavros Sachtouris
        exe = basename(argv[0])
512 e0da0f90 Stavros Sachtouris
        parser = ArgumentParseManager(exe)
513 7c2247a0 Stavros Sachtouris
514 074f5027 Stavros Sachtouris
        if parser.arguments['version'].value:
515 71882bca Stavros Sachtouris
            exit(0)
516 71882bca Stavros Sachtouris
517 db03f805 Stavros Sachtouris
        _cnf = parser.arguments['config']
518 db03f805 Stavros Sachtouris
        log_file = _cnf.get_global('log_file')
519 f47417e7 Stavros Sachtouris
        if log_file:
520 7637d600 Stavros Sachtouris
            logger.set_log_filename(log_file)
521 9dc724e5 Stavros Sachtouris
        global filelog
522 9dc724e5 Stavros Sachtouris
        filelog = logger.add_file_logger(__name__.split('.')[0])
523 334338ce Stavros Sachtouris
        filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
524 9dc724e5 Stavros Sachtouris
525 db03f805 Stavros Sachtouris
        cloud = _init_session(parser.arguments, is_non_API(parser))
526 6fb4af77 Stavros Sachtouris
        from kamaki.cli.utils import suggest_missing
527 69691087 Stavros Sachtouris
        global _colors
528 69691087 Stavros Sachtouris
        exclude = ['ansicolors'] if not _colors == 'on' else []
529 69691087 Stavros Sachtouris
        suggest_missing(exclude=exclude)
530 6fb4af77 Stavros Sachtouris
531 b3dd8f4b Stavros Sachtouris
        if parser.unparsed:
532 db03f805 Stavros Sachtouris
            run_one_cmd(exe, parser, cloud)
533 71882bca Stavros Sachtouris
        elif _help:
534 e0da0f90 Stavros Sachtouris
            parser.parser.print_help()
535 074f5027 Stavros Sachtouris
            _groups_help(parser.arguments)
536 71882bca Stavros Sachtouris
        else:
537 db03f805 Stavros Sachtouris
            run_shell(exe, parser, cloud)
538 71882bca Stavros Sachtouris
    except CLIError as err:
539 b6a99832 Stavros Sachtouris
        print_error_message(err)
540 71882bca Stavros Sachtouris
        if _debug:
541 71882bca Stavros Sachtouris
            raise err
542 71882bca Stavros Sachtouris
        exit(1)
543 6069b53b Stavros Sachtouris
    except Exception as er:
544 6069b53b Stavros Sachtouris
        print('Unknown Error: %s' % er)
545 71882bca Stavros Sachtouris
        if _debug:
546 6069b53b Stavros Sachtouris
            raise
547 6069b53b Stavros Sachtouris
        exit(1)