Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / __init__.py @ e9c73313

History | View | Annotate | Download (11.1 kB)

1
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.command
33

    
34
from kamaki.cli.logger import get_logger
35
from kamaki.cli.utils import (
36
    print_list, print_dict, print_json, print_items, ask_user,
37
    filter_dicts_by_dict)
38
from kamaki.cli.argument import FlagArgument, ValueArgument
39
from sys import stdin, stdout, stderr
40

    
41
log = get_logger(__name__)
42

    
43

    
44
def DontRaiseKeyError(foo):
45
    def wrap(*args, **kwargs):
46
        try:
47
            return foo(*args, **kwargs)
48
        except KeyError:
49
            return None
50
    return wrap
51

    
52

    
53
def addLogSettings(foo):
54
    def wrap(self, *args, **kwargs):
55
        try:
56
            return foo(self, *args, **kwargs)
57
        finally:
58
            self._set_log_params()
59
            self._update_max_threads
60
    return wrap
61

    
62

    
63
class _command_init(object):
64

    
65
    def __init__(
66
            self,
67
            arguments={}, auth_base=None, cloud=None,
68
            _in=None, _out=None, _err=None):
69
        self._in, self._out, self._err = (
70
            _in or stdin, _out or stdout, _err or stderr)
71
        if hasattr(self, 'arguments'):
72
            arguments.update(self.arguments)
73
        if isinstance(self, _optional_output_cmd):
74
            arguments.update(self.oo_arguments)
75
        if isinstance(self, _optional_json):
76
            arguments.update(self.oj_arguments)
77
        if isinstance(self, _name_filter):
78
            arguments.update(self.nf_arguments)
79
        if isinstance(self, _id_filter):
80
            arguments.update(self.if_arguments)
81
        try:
82
            arguments.update(self.wait_arguments)
83
        except AttributeError:
84
            pass
85
        self.arguments = dict(arguments)
86
        try:
87
            self.config = self['config']
88
        except KeyError:
89
            pass
90
        self.auth_base = auth_base or getattr(self, 'auth_base', None)
91
        self.cloud = cloud or getattr(self, 'cloud', None)
92

    
93
    def write(self, s):
94
        self._out.write(u'%s' % s)
95
        self._out.flush()
96

    
97
    def writeln(self, s=''):
98
        self.write(u'%s\n' % s)
99

    
100
    def error(self, s=''):
101
        self._err.write(u'%s\n' % s)
102
        self._err.flush()
103

    
104
    def print_list(self, *args, **kwargs):
105
        kwargs.setdefault('out', self._out)
106
        return print_list(*args, **kwargs)
107

    
108
    def print_dict(self, *args, **kwargs):
109
        kwargs.setdefault('out', self._out)
110
        return print_dict(*args, **kwargs)
111

    
112
    def print_json(self, *args, **kwargs):
113
        kwargs.setdefault('out', self._out)
114
        return print_json(*args, **kwargs)
115

    
116
    def print_items(self, *args, **kwargs):
117
        kwargs.setdefault('out', self._out)
118
        return print_items(*args, **kwargs)
119

    
120
    def ask_user(self, *args, **kwargs):
121
        kwargs.setdefault('user_in', self._in)
122
        kwargs.setdefault('out', self._out)
123
        return ask_user(*args, **kwargs)
124

    
125
    @DontRaiseKeyError
126
    def _custom_url(self, service):
127
        return self.config.get_cloud(self.cloud, '%s_url' % service)
128

    
129
    @DontRaiseKeyError
130
    def _custom_token(self, service):
131
        return self.config.get_cloud(self.cloud, '%s_token' % service)
132

    
133
    @DontRaiseKeyError
134
    def _custom_type(self, service):
135
        return self.config.get_cloud(self.cloud, '%s_type' % service)
136

    
137
    @DontRaiseKeyError
138
    def _custom_version(self, service):
139
        return self.config.get_cloud(self.cloud, '%s_version' % service)
140

    
141
    def _uuids2usernames(self, uuids):
142
        return self.auth_base.post_user_catalogs(uuids).json['uuid_catalog']
143

    
144
    def _usernames2uuids(self, username):
145
        return self.auth_base.post_user_catalogs(
146
            displaynames=username).json['displayname_catalog']
147

    
148
    def _uuid2username(self, uuid):
149
        return self._uuids2usernames([uuid]).get(uuid, None)
150

    
151
    def _username2uuid(self, username):
152
        return self._usernames2uuids([username]).get(username, None)
153

    
154
    def _set_log_params(self):
155
        try:
156
            self.client.LOG_TOKEN = (
157
                self['config'].get_global('log_token').lower() == 'on')
158
        except Exception as e:
159
            log.debug('Failed to read custom log_token setting:'
160
                '%s\n default for log_token is off' % e)
161
        try:
162
            self.client.LOG_DATA = (
163
                self['config'].get_global('log_data').lower() == 'on')
164
        except Exception as e:
165
            log.debug('Failed to read custom log_data setting:'
166
                '%s\n default for log_data is off' % e)
167
        try:
168
            self.client.LOG_PID = (
169
                self['config'].get_global('log_pid').lower() == 'on')
170
        except Exception as e:
171
            log.debug('Failed to read custom log_pid setting:'
172
                '%s\n default for log_pid is off' % e)
173

    
174
    def _update_max_threads(self):
175
        if getattr(self, 'client', None):
176
            max_threads = int(self['config'].get_global('max_threads'))
177
            assert max_threads > 0, 'invalid max_threads config option'
178
            self.client.MAX_THREADS = max_threads
179

    
180
    def _safe_progress_bar(self, msg, arg='progress_bar', timeout=False):
181
        """Try to get a progress bar, but do not raise errors"""
182
        try:
183
            progress_bar = self.arguments[arg]
184
            progress_bar.file = self._err
185
            gen = progress_bar.get_generator(msg, timeout=timeout)
186
        except Exception:
187
            return (None, None)
188
        return (progress_bar, gen)
189

    
190
    def _safe_progress_bar_finish(self, progress_bar):
191
        try:
192
            progress_bar.finish()
193
        except Exception:
194
            pass
195

    
196
    def __getitem__(self, argterm):
197
        """
198
        :param argterm: (str) the name/label of an argument in self.arguments
199

200
        :returns: the value of the corresponding Argument (not the argument
201
            object)
202

203
        :raises KeyError: if argterm not in self.arguments of this object
204
        """
205
        return self.arguments[argterm].value
206

    
207
    def __setitem__(self, argterm, arg):
208
        """Install an argument as argterm
209
        If argterm points to another argument, the other argument is lost
210

211
        :param argterm: (str)
212

213
        :param arg: (Argument)
214
        """
215
        if not hasattr(self, 'arguments'):
216
            self.arguments = {}
217
        self.arguments[argterm] = arg
218

    
219
    def get_argument_object(self, argterm):
220
        """
221
        :param argterm: (str) the name/label of an argument in self.arguments
222

223
        :returns: the arument object
224

225
        :raises KeyError: if argterm not in self.arguments of this object
226
        """
227
        return self.arguments[argterm]
228

    
229
    def get_argument(self, argterm):
230
        """
231
        :param argterm: (str) the name/label of an argument in self.arguments
232

233
        :returns: the value of the arument object
234

235
        :raises KeyError: if argterm not in self.arguments of this object
236
        """
237
        return self[argterm]
238

    
239

    
240
#  feature classes - inherit them to get special features for your commands
241

    
242

    
243
class _optional_output_cmd(object):
244

    
245
    oo_arguments = dict(
246
        with_output=FlagArgument('show response headers', ('--with-output')),
247
        json_output=FlagArgument('show headers in json', ('-j', '--json'))
248
    )
249

    
250
    def _optional_output(self, r):
251
        if self['json_output']:
252
            print_json(r, out=self._out)
253
        elif self['with_output']:
254
            print_items([r] if isinstance(r, dict) else r, out=self._out)
255

    
256

    
257
class _optional_json(object):
258

    
259
    oj_arguments = dict(
260
        json_output=FlagArgument('show headers in json', ('-j', '--json'))
261
    )
262

    
263
    def _print(self, output, print_method=print_items, **print_method_kwargs):
264
        if self['json_output']:
265
            print_json(output, out=self._out)
266
        else:
267
            print_method_kwargs.setdefault('out', self._out)
268
            print_method(output, **print_method_kwargs)
269

    
270

    
271
class _name_filter(object):
272

    
273
    nf_arguments = dict(
274
        name=ValueArgument('filter by name', '--name'),
275
        name_pref=ValueArgument(
276
            'filter by name prefix (case insensitive)', '--name-prefix'),
277
        name_suff=ValueArgument(
278
            'filter by name suffix (case insensitive)', '--name-suffix'),
279
        name_like=ValueArgument(
280
            'print only if name contains this (case insensitive)',
281
            '--name-like')
282
    )
283

    
284
    def _non_exact_name_filter(self, items):
285
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
286
        return [item for item in items if (
287
            (not np) or item['name'].lower().startswith(np.lower())) and (
288
            (not ns) or item['name'].lower().endswith(ns.lower())) and (
289
            (not nl) or nl.lower() in item['name'].lower())]
290

    
291
    def _exact_name_filter(self, items):
292
        return filter_dicts_by_dict(items, dict(name=self['name'])) if (
293
            self['name']) else items
294

    
295
    def _filter_by_name(self, items):
296
        return self._non_exact_name_filter(self._exact_name_filter(items))
297

    
298

    
299
class _id_filter(object):
300

    
301
    if_arguments = dict(
302
        id=ValueArgument('filter by id', '--id'),
303
        id_pref=ValueArgument(
304
            'filter by id prefix (case insensitive)', '--id-prefix'),
305
        id_suff=ValueArgument(
306
            'filter by id suffix (case insensitive)', '--id-suffix'),
307
        id_like=ValueArgument(
308
            'print only if id contains this (case insensitive)',
309
            '--id-like')
310
    )
311

    
312
    def _non_exact_id_filter(self, items):
313
        np, ns, nl = self['id_pref'], self['id_suff'], self['id_like']
314
        return [item for item in items if (
315
            (not np) or (
316
                '%s' % item['id']).lower().startswith(np.lower())) and (
317
            (not ns) or ('%s' % item['id']).lower().endswith(ns.lower())) and (
318
            (not nl) or nl.lower() in ('%s' % item['id']).lower())]
319

    
320
    def _exact_id_filter(self, items):
321
        return filter_dicts_by_dict(items, dict(id=self['id'])) if (
322
            self['id']) else items
323

    
324
    def _filter_by_id(self, items):
325
        return self._non_exact_id_filter(self._exact_id_filter(items))