Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / __init__.py @ 1757c616

History | View | Annotate | Download (10 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 print_json, print_items, filter_dicts_by_dict
36
from kamaki.cli.argument import FlagArgument, ValueArgument
37
from sys import stdin, stdout
38

    
39
log = get_logger(__name__)
40

    
41

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

    
50

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

    
60

    
61
class _command_init(object):
62

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

    
89
    @DontRaiseKeyError
90
    def _custom_url(self, service):
91
        return self.config.get_cloud(self.cloud, '%s_url' % service)
92

    
93
    @DontRaiseKeyError
94
    def _custom_token(self, service):
95
        return self.config.get_cloud(self.cloud, '%s_token' % service)
96

    
97
    @DontRaiseKeyError
98
    def _custom_type(self, service):
99
        return self.config.get_cloud(self.cloud, '%s_type' % service)
100

    
101
    @DontRaiseKeyError
102
    def _custom_version(self, service):
103
        return self.config.get_cloud(self.cloud, '%s_version' % service)
104

    
105
    def _uuids2usernames(self, uuids):
106
        return self.auth_base.post_user_catalogs(uuids).json['uuid_catalog']
107

    
108
    def _usernames2uuids(self, username):
109
        return self.auth_base.post_user_catalogs(
110
            displaynames=username).json['displayname_catalog']
111

    
112
    def _uuid2username(self, uuid):
113
        return self._uuids2usernames([uuid]).get(uuid, None)
114

    
115
    def _username2uuid(self, username):
116
        return self._usernames2uuids([username]).get(username, None)
117

    
118
    def _set_log_params(self):
119
        try:
120
            self.client.LOG_TOKEN = (
121
                self['config'].get_global('log_token').lower() == 'on')
122
        except Exception as e:
123
            log.debug('Failed to read custom log_token setting:'
124
                '%s\n default for log_token is off' % e)
125
        try:
126
            self.client.LOG_DATA = (
127
                self['config'].get_global('log_data').lower() == 'on')
128
        except Exception as e:
129
            log.debug('Failed to read custom log_data setting:'
130
                '%s\n default for log_data is off' % e)
131
        try:
132
            self.client.LOG_PID = (
133
                self['config'].get_global('log_pid').lower() == 'on')
134
        except Exception as e:
135
            log.debug('Failed to read custom log_pid setting:'
136
                '%s\n default for log_pid is off' % e)
137

    
138
    def _update_max_threads(self):
139
        if getattr(self, 'client', None):
140
            max_threads = int(self['config'].get_global('max_threads'))
141
            assert max_threads > 0, 'invalid max_threads config option'
142
            self.client.MAX_THREADS = max_threads
143

    
144
    def _safe_progress_bar(self, msg, arg='progress_bar'):
145
        """Try to get a progress bar, but do not raise errors"""
146
        try:
147
            progress_bar = self.arguments[arg]
148
            gen = progress_bar.get_generator(msg)
149
        except Exception:
150
            return (None, None)
151
        return (progress_bar, gen)
152

    
153
    def _safe_progress_bar_finish(self, progress_bar):
154
        try:
155
            progress_bar.finish()
156
        except Exception:
157
            pass
158

    
159
    def __getitem__(self, argterm):
160
        """
161
        :param argterm: (str) the name/label of an argument in self.arguments
162

163
        :returns: the value of the corresponding Argument (not the argument
164
            object)
165

166
        :raises KeyError: if argterm not in self.arguments of this object
167
        """
168
        return self.arguments[argterm].value
169

    
170
    def __setitem__(self, argterm, arg):
171
        """Install an argument as argterm
172
        If argterm points to another argument, the other argument is lost
173

174
        :param argterm: (str)
175

176
        :param arg: (Argument)
177
        """
178
        if not hasattr(self, 'arguments'):
179
            self.arguments = {}
180
        self.arguments[argterm] = arg
181

    
182
    def get_argument_object(self, argterm):
183
        """
184
        :param argterm: (str) the name/label of an argument in self.arguments
185

186
        :returns: the arument object
187

188
        :raises KeyError: if argterm not in self.arguments of this object
189
        """
190
        return self.arguments[argterm]
191

    
192
    def get_argument(self, argterm):
193
        """
194
        :param argterm: (str) the name/label of an argument in self.arguments
195

196
        :returns: the value of the arument object
197

198
        :raises KeyError: if argterm not in self.arguments of this object
199
        """
200
        return self[argterm]
201

    
202

    
203
#  feature classes - inherit them to get special features for your commands
204

    
205

    
206
class _optional_output_cmd(object):
207

    
208
    oo_arguments = dict(
209
        with_output=FlagArgument('show response headers', ('--with-output')),
210
        json_output=FlagArgument('show headers in json', ('-j', '--json'))
211
    )
212

    
213
    def _optional_output(self, r):
214
        if self['json_output']:
215
            print_json(r, out=self._out)
216
        elif self['with_output']:
217
            print_items([r] if isinstance(r, dict) else r, out=self._out)
218

    
219

    
220
class _optional_json(object):
221

    
222
    oj_arguments = dict(
223
        json_output=FlagArgument('show headers in json', ('-j', '--json'))
224
    )
225

    
226
    def _print(self, output, print_method=print_items, **print_method_kwargs):
227
        if self['json_output']:
228
            print_json(output, out=self._out)
229
        else:
230
            print_method(output, out=self._out, **print_method_kwargs)
231

    
232

    
233
class _name_filter(object):
234

    
235
    nf_arguments = dict(
236
        name=ValueArgument('filter by name', '--name'),
237
        name_pref=ValueArgument(
238
            'filter by name prefix (case insensitive)', '--name-prefix'),
239
        name_suff=ValueArgument(
240
            'filter by name suffix (case insensitive)', '--name-suffix'),
241
        name_like=ValueArgument(
242
            'print only if name contains this (case insensitive)',
243
            '--name-like')
244
    )
245

    
246
    def _non_exact_name_filter(self, items):
247
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
248
        return [item for item in items if (
249
            (not np) or item['name'].lower().startswith(np.lower())) and (
250
            (not ns) or item['name'].lower().endswith(ns.lower())) and (
251
            (not nl) or nl.lower() in item['name'].lower())]
252

    
253
    def _exact_name_filter(self, items):
254
        return filter_dicts_by_dict(items, dict(name=self['name'])) if (
255
            self['name']) else items
256

    
257
    def _filter_by_name(self, items):
258
        return self._non_exact_name_filter(self._exact_name_filter(items))
259

    
260

    
261
class _id_filter(object):
262

    
263
    if_arguments = dict(
264
        id=ValueArgument('filter by id', '--id'),
265
        id_pref=ValueArgument(
266
            'filter by id prefix (case insensitive)', '--id-prefix'),
267
        id_suff=ValueArgument(
268
            'filter by id suffix (case insensitive)', '--id-suffix'),
269
        id_like=ValueArgument(
270
            'print only if id contains this (case insensitive)',
271
            '--id-like')
272
    )
273

    
274
    def _non_exact_id_filter(self, items):
275
        np, ns, nl = self['id_pref'], self['id_suff'], self['id_like']
276
        return [item for item in items if (
277
            (not np) or (
278
                '%s' % item['id']).lower().startswith(np.lower())) and (
279
            (not ns) or ('%s' % item['id']).lower().endswith(ns.lower())) and (
280
            (not nl) or nl.lower() in ('%s' % item['id']).lower())]
281

    
282
    def _exact_id_filter(self, items):
283
        return filter_dicts_by_dict(items, dict(id=self['id'])) if (
284
            self['id']) else items
285

    
286
    def _filter_by_id(self, items):
287
        return self._non_exact_id_filter(self._exact_id_filter(items))