1 # Copyright 2011-2012 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
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.
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.
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
34 from traceback import print_stack, print_exc
37 from kamaki.clients import ClientError
38 from kamaki.cli.errors import CLIError, raiseCLIError, CLISyntaxError
39 from kamaki.cli import _debug, kloger
41 sendlog = logging.getLogger('clients.send')
42 datasendlog = logging.getLogger('data.send')
43 recvlog = logging.getLogger('clients.recv')
44 datarecvlog = logging.getLogger('data.recv')
47 class generic(object):
51 def _raise(self, *args, **kwargs):
53 return foo(self, *args, **kwargs)
54 except Exception as e:
62 def _connection(this, foo, base_url):
63 def _raise(self, *args, **kwargs):
65 foo(self, *args, **kwargs)
66 except ClientError as ce:
68 raiseCLIError(ce, 'Authorization failed', details=[
69 'Make sure a valid token is provided:',
70 ' to check if token is valid: /astakos authenticate',
71 ' to set token: /config set [.server.]token <token>',
72 ' to get current token: /config get [server.]token'])
73 elif ce.status in range(-12, 200) + [403, 302, 500]:
74 raiseCLIError(ce, importance=3, details=[
75 'Check if service is up or set to url %s' % base_url,
76 ' to get url: /config get %s' % base_url,
77 ' to set url: /config set %s <URL>' % base_url])
78 elif ce.status == 404\
79 and 'kamakihttpresponse' in ('%s' % ce).lower():
80 client = getattr(self, 'client', None)
83 url = getattr(client, 'base_url', '<empty>')
85 'Invalid service url %s' % url,
87 'Please, check if service url is correctly set',
88 '* to get current url: /config get compute.url',
89 '* to set url: /config set compute.url <URL>'])
94 class astakos(object):
97 'To check default token: /config get token',
98 'If set/update a token:',
99 '* (permanent): /config set token <token>',
100 '* (temporary): re-run with <token> parameter']
104 def _raise(self, *args, **kwargs):
105 r = foo(self, *args, **kwargs)
107 client = getattr(self, 'client')
108 except AttributeError as ae:
109 raiseCLIError(ae, 'Client setup failure', importance=3)
110 if not getattr(client, 'token', False):
112 'No permanent token (try: kamaki config set token <tkn>)')
113 if not getattr(client, 'base_url', False):
114 raise CLIError('Missing astakos server URL',
116 details=['Check if astakos.url is set correctly',
117 'To get astakos url: /config get astakos.url',
118 'To set astakos url: /config set astakos.url <URL>'])
123 def authenticate(this, foo):
124 def _raise(self, *args, **kwargs):
126 r = foo(self, *args, **kwargs)
127 except ClientError as ce:
129 token = kwargs.get('custom_token', 0) or self.client.token
131 'Authorization failed for token %s' % token if token\
132 else 'No token provided',
133 details=[] if token else this._token_details)
139 class history(object):
142 def _raise(self, *args, **kwargs):
143 r = foo(self, *args, **kwargs)
144 if not hasattr(self, 'history'):
145 raise CLIError('Failed to load history', importance=2)
150 def _get_cmd_ids(this, foo):
151 def _raise(self, cmd_ids, *args, **kwargs):
153 raise CLISyntaxError('Usage: <id1|id1-id2> [id3|id3-id4] ...',
154 details=self.__doc__.split('\n'))
155 return foo(self, cmd_ids, *args, **kwargs)
159 class cyclades(object):
161 'How to pick a valid flavor id:',
162 '* get a list of flavor ids: /flavor list',
163 '* details of flavor: /flavor info <flavor id>']
166 'How to pick a valid network id:',
167 '* get a list of network ids: /network list',
168 '* details of network: /network info <network id>']
171 def connection(this, foo):
172 return generic._connection(foo, 'compute.url')
176 def _raise(self, *args, **kwargs):
178 return foo(self, *args, **kwargs)
179 except ClientError as ce:
180 if ce.status == 400 and 'changes-since' in ('%s' % ce):
182 'Incorrect date format for --since',
183 details=['Accepted date format: d/m/y'])
188 def network_id(this, foo):
189 def _raise(self, *args, **kwargs):
190 network_id = kwargs.get('network_id', None)
192 network_id = int(network_id)
193 return foo(self, *args, **kwargs)
194 except ValueError as ve:
195 raiseCLIError(ve, 'Invalid network id %s ' % network_id,
196 details='network id must be a positive integer',
198 except ClientError as ce:
199 if network_id and ce.status == 404 and\
200 'network' in ('%s' % ce).lower():
202 'No network with id %s found' % network_id,
203 details=this.about_network_id)
208 def network_max(this, foo):
209 def _raise(self, *args, **kwargs):
211 return foo(self, *args, **kwargs)
212 except ClientError as ce:
215 'Cannot create another network',
216 details=['Maximum number of networks reached',
217 '* to get a list of networks: /network list',
218 '* to delete a network: /network delete <net id>'])
223 def network_in_use(this, foo):
224 def _raise(self, *args, **kwargs):
225 network_id = kwargs.get('network_id', None)
227 return foo(self, *args, **kwargs)
228 except ClientError as ce:
229 if network_id or ce.status == 421:
231 'Network with id %s is in use' % network_id,
233 'Disconnect all nics/VMs of this network first',
234 '* to get nics: /network info %s' % network_id,
235 '. (under "attachments" section)',
236 '* to disconnect: /network disconnect <nic id>'])
241 def flavor_id(this, foo):
242 def _raise(self, *args, **kwargs):
243 flavor_id = kwargs.get('flavor_id', None)
245 flavor_id = int(flavor_id)
246 return foo(self, *args, **kwargs)
247 except ValueError as ve:
248 raiseCLIError(ve, 'Invalid flavor id %s ' % flavor_id,
249 details='Flavor id must be a positive integer',
251 except ClientError as ce:
252 if flavor_id and ce.status == 404 and\
253 'flavor' in ('%s' % ce).lower():
255 'No flavor with id %s found' % flavor_id,
256 details=this.about_flavor_id)
261 def server_id(this, foo):
262 def _raise(self, *args, **kwargs):
263 server_id = kwargs.get('server_id', None)
265 server_id = int(server_id)
266 return foo(self, *args, **kwargs)
267 except ValueError as ve:
269 'Invalid server(VM) id %s' % server_id,
270 details=['id must be a positive integer'],
272 except ClientError as ce:
273 err_msg = ('%s' % ce).lower()
274 if (ce.status == 404 and 'server' in err_msg)\
275 or (ce.status == 400 and 'not found' in err_msg):
277 'server(VM) with id %s not found' % server_id,
279 '* to get existing VM ids: /server list',
280 '* to get VM details: /server info <VM id>'])
285 def firewall(this, foo):
286 def _raise(self, *args, **kwargs):
287 profile = kwargs.get('profile', None)
289 return foo(self, *args, **kwargs)
290 except ClientError as ce:
291 if ce.status == 400 and profile\
292 and 'firewall' in ('%s' % ce).lower():
294 '%s is an invalid firewall profile term' % profile,
295 details=['Try one of the following:',
296 '* DISABLED: Shutdown firewall',
297 '* ENABLED: Firewall in normal mode',
298 '* PROTECTED: Firewall in secure mode'])
303 def nic_id(this, foo):
304 def _raise(self, *args, **kwargs):
306 return foo(self, *args, **kwargs)
307 except ClientError as ce:
308 nic_id = kwargs.get('nic_id', None)
309 if nic_id and ce.status == 404\
310 and 'network interface' in ('%s' % ce).lower():
311 server_id = kwargs.get('server_id', '<no server>')
312 err_msg = 'No nic %s on server(VM) with id %s' % (
315 raiseCLIError(ce, err_msg, details=[
316 '* check server(VM) with id %s: /server info %s' % (
319 '* list nics for server(VM) with id %s:' % server_id,
320 ' /server addr %s' % server_id])
325 def nic_format(this, foo):
326 def _raise(self, *args, **kwargs):
328 return foo(self, *args, **kwargs)
329 except IndexError as ie:
330 nic_id = kwargs.get('nic_id', None)
332 'Invalid format for network interface (nic) %s' % nic_id,
335 'nid_id format: nic-<server id>-<nic id>',
336 '* get nics of a network: /network info <net id>',
337 ' (listed the "attachments" section)'])
341 def metadata(this, foo):
342 def _raise(self, *args, **kwargs):
343 key = kwargs.get('key', None)
345 foo(self, *args, **kwargs)
346 except ClientError as ce:
347 if key and ce.status == 404\
348 and 'metadata' in ('%s' % ce).lower():
349 raiseCLIError(ce, 'No VM metadata with key %s' % key)
354 class plankton(object):
356 about_image_id = ['How to pick a suitable image:',
357 '* get a list of image ids: /image list',
358 '* details of image: /flavor info <image id>']
361 def connection(this, foo):
362 return generic._connection(foo, 'image.url')
366 def _raise(self, *args, **kwargs):
367 image_id = kwargs.get('image_id', None)
369 foo(self, *args, **kwargs)
370 except ClientError as ce:
371 if image_id and (ce.status == 404\
372 or (ce.status == 400 and
373 'image not found' in ('%s' % ce).lower())\
374 or ce.status == 411):
376 'No image with id %s found' % image_id,
377 details=this.about_image_id)
382 def metadata(this, foo):
383 def _raise(self, *args, **kwargs):
384 key = kwargs.get('key', None)
386 foo(self, *args, **kwargs)
387 except ClientError as ce:
388 if ce.status == 404 or ((ce.status == 400\
389 and 'metadata' in ('%s' % ce).lower())):
391 'No properties with key %s in this image' % key)