-# Copyright 2011-2012 GRNET S.A. All rights reserved.
+# Copyright 2011-2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# or implied, of GRNET S.A.command
from traceback import print_stack, print_exc
-import logging
+from astakosclient import AstakosClientException
from kamaki.clients import ClientError
from kamaki.cli.errors import CLIError, raiseCLIError, CLISyntaxError
from kamaki.cli import _debug, kloger
from kamaki.cli.utils import format_size
-sendlog = logging.getLogger('clients.send')
-datasendlog = logging.getLogger('data.send')
-recvlog = logging.getLogger('clients.recv')
-datarecvlog = logging.getLogger('data.recv')
+CLOUDNAME = [
+ 'Note: If you use a named cloud, use its name instead of "default"']
class generic(object):
if _debug:
print_stack()
print_exc(e)
- raiseCLIError(e)
+ if isinstance(e, CLIError) or isinstance(e, ClientError):
+ raiseCLIError(e)
+ raiseCLIError(e, details=['%s, -d for debug info' % type(e)])
return _raise
@classmethod
- def _connection(this, foo, base_url):
+ def _connection(this, foo):
def _raise(self, *args, **kwargs):
try:
foo(self, *args, **kwargs)
if ce.status == 401:
raiseCLIError(ce, 'Authorization failed', details=[
'Make sure a valid token is provided:',
- ' to check if token is valid: /astakos authenticate',
- ' to set token: /config set [.server.]token <token>',
- ' to get current token: /config get [server.]token'])
+ ' to check if token is valid: /user authenticate',
+ ' to set token:',
+ ' /config set cloud.default.token <token>',
+ ' to get current token:',
+ ' /config get cloud.default.token'] + CLOUDNAME)
elif ce.status in range(-12, 200) + [302, 401, 403, 500]:
raiseCLIError(ce, importance=3, details=[
- 'Check if service is up or set to url %s' % base_url,
- ' to get url: /config get %s' % base_url,
- ' to set url: /config set %s <URL>' % base_url])
+ 'Check if service is up'])
elif ce.status == 404 and 'kamakihttpresponse' in ce_msg:
client = getattr(self, 'client', None)
if not client:
raise
url = getattr(client, 'base_url', '<empty>')
- msg = 'Invalid service url %s' % url
+ msg = 'Invalid service URL %s' % url
raiseCLIError(ce, msg, details=[
- 'Please, check if service url is correctly set',
- '* to get current url: /config get compute.url',
- '* to set url: /config set compute.url <URL>'])
+ 'Check if authentication URL is correct',
+ ' check current URL:',
+ ' /config get cloud.default.url',
+ ' set new authentication URL:',
+ ' /config set cloud.default.url'] + CLOUDNAME)
raise
return _raise
-class astakos(object):
+class user(object):
_token_details = [
- 'To check default token: /config get token',
+ 'To check default token: /config get cloud.default.token',
'If set/update a token:',
- '* (permanent): /config set token <token>',
- '* (temporary): re-run with <token> parameter']
+ '* (permanent): /config set cloud.default.token <token>',
+ '* (temporary): re-run with <token> parameter'] + CLOUDNAME
+
+ @classmethod
+ def astakosclient(this, foo):
+ def _raise(self, *args, **kwargs):
+ try:
+ r = foo(self, *args, **kwargs)
+ except AstakosClientException as ace:
+ raiseCLIError(ace, 'Error in synnefo-AstakosClient')
+ return r
+ return _raise
@classmethod
def load(this, foo):
raiseCLIError(ae, 'Client setup failure', importance=3)
if not getattr(client, 'token', False):
kloger.warning(
- 'No permanent token (try: kamaki config set token <tkn>)')
- if not getattr(client, 'base_url', False):
- msg = 'Missing astakos server URL'
+ 'No permanent token (try:'
+ ' kamaki config set cloud.default.token <tkn>)')
+ if not getattr(client, 'astakos_base_url', False):
+ msg = 'Missing synnefo authentication URL'
raise CLIError(msg, importance=3, details=[
- 'Check if astakos.url is set correctly',
- 'To get astakos url: /config get astakos.url',
- 'To set astakos url: /config set astakos.url <URL>'])
+ 'Check if authentication URL is correct',
+ ' check current URL:',
+ ' /config get cloud.default.url',
+ ' set new auth. URL:',
+ ' /config set cloud.default.url'] + CLOUDNAME)
return r
return _raise
def _raise(self, *args, **kwargs):
try:
return foo(self, *args, **kwargs)
- except ClientError as ce:
+ except (ClientError, AstakosClientException) as ce:
if ce.status == 401:
token = kwargs.get('custom_token', 0) or self.client.token
- msg = (
- 'Authorization failed for token %s' % token
- ) if token else 'No token provided',
+ msg = ('Authorization failed for token %s' % token) if (
+ token) else 'No token provided',
details = [] if token else this._token_details
raiseCLIError(ce, msg, details=details)
+ raise ce
self._raise = foo
return _raise
'* get a list of network ids: /network list',
'* details of network: /network info <network id>']
+ net_types = ('CUSTOM', 'MAC_FILTERED', 'IP_LESS_ROUTED', 'PHYSICAL_VLAN')
+
@classmethod
def connection(this, foo):
- return generic._connection(foo, 'compute.url')
+ return generic._connection(foo)
@classmethod
def date(this, foo):
return _raise
@classmethod
+ def cluster_size(this, foo):
+ def _raise(self, *args, **kwargs):
+ size = kwargs.get('size', None)
+ try:
+ size = int(size)
+ assert size > 0, 'Cluster size must be a positive integer'
+ return foo(self, *args, **kwargs)
+ except ValueError as ve:
+ msg = 'Invalid cluster size value %s' % size
+ raiseCLIError(ve, msg, importance=1, details=[
+ 'Cluster size must be a positive integer'])
+ except AssertionError as ae:
+ raiseCLIError(
+ ae, 'Invalid cluster size %s' % size, importance=1)
+ except ClientError:
+ raise
+ return _raise
+
+ @classmethod
def network_id(this, foo):
def _raise(self, *args, **kwargs):
network_id = kwargs.get('network_id', None)
return foo(self, *args, **kwargs)
except ValueError as ve:
msg = 'Invalid network id %s ' % network_id
- details = ['network id must be a positive integer']
+ details = 'network id must be a positive integer'
raiseCLIError(ve, msg, details=details, importance=1)
except ClientError as ce:
if network_id and ce.status == 404 and (
return _raise
@classmethod
+ def network_type(this, foo):
+ def _raise(self, *args, **kwargs):
+ network_type = kwargs.get('network_type', None)
+ msg = 'Invalid network type %s.\nValid types: %s' % (
+ network_type, ' '.join(this.net_types))
+ assert network_type in this.net_types, msg
+ return foo(self, *args, **kwargs)
+ return _raise
+
+ @classmethod
def network_max(this, foo):
def _raise(self, *args, **kwargs):
try:
try:
return foo(self, *args, **kwargs)
except ClientError as ce:
- if network_id and ce.status == 400:
+ if network_id and ce.status in (400, ):
msg = 'Network with id %s does not exist' % network_id,
- raiseCLIError(ce, msg, details=self.about_network_id)
- elif network_id or ce.status == 421:
+ raiseCLIError(ce, msg, details=this.about_network_id)
+ elif network_id or ce.status in (421, ):
msg = 'Network with id %s is in use' % network_id,
raiseCLIError(ce, msg, details=[
- 'Disconnect all nics/VMs of this network first',
+ 'Disconnect all nics/servers of this network first',
'* to get nics: /network info %s' % network_id,
'. (under "attachments" section)',
'* to disconnect: /network disconnect <nic id>'])
return foo(self, *args, **kwargs)
except ValueError as ve:
msg = 'Invalid flavor id %s ' % flavor_id,
- details = 'Flavor id must be a positive integer',
+ details = 'Flavor id must be a positive integer'
raiseCLIError(ve, msg, details=details, importance=1)
except ClientError as ce:
if flavor_id and ce.status == 404 and (
server_id = int(server_id)
return foo(self, *args, **kwargs)
except ValueError as ve:
- msg = 'Invalid server(VM) id %s' % server_id,
- details = ['id must be a positive integer'],
+ msg = 'Invalid virtual server id %s' % server_id,
+ details = 'Server id must be a positive integer'
raiseCLIError(ve, msg, details=details, importance=1)
except ClientError as ce:
err_msg = ('%s' % ce).lower()
) or (
ce.status == 400 and 'not found' in err_msg
):
- msg = 'server(VM) with id %s not found' % server_id,
+ msg = 'virtual server with id %s not found' % server_id,
raiseCLIError(ce, msg, details=[
- '* to get existing VM ids: /server list',
- '* to get VM details: /server info <VM id>'])
+ '* to get ids of all servers: /server list',
+ '* to get server details: /server info <server id>'])
raise
return _raise
'network interface' in ('%s' % ce).lower()
):
server_id = kwargs.get('server_id', '<no server>')
- err_msg = 'No nic %s on server(VM) with id %s' % (
+ err_msg = 'No nic %s on virtual server with id %s' % (
nic_id,
server_id)
raiseCLIError(ce, err_msg, details=[
- '* check server(VM) with id %s: /server info %s' % (
+ '* check v. server with id %s: /server info %s' % (
server_id,
server_id),
- '* list nics for server(VM) with id %s:' % server_id,
+ '* list nics for v. server with id %s:' % server_id,
' /server addr %s' % server_id])
raise
return _raise
if key and ce.status == 404 and (
'metadata' in ('%s' % ce).lower()
):
- raiseCLIError(ce, 'No VM metadata with key %s' % key)
+ raiseCLIError(
+ ce, 'No virtual server metadata with key %s' % key)
raise
return _raise
about_image_id = [
'How to pick a suitable image:',
'* get a list of image ids: /image list',
- '* details of image: /flavor info <image id>']
+ '* details of image: /image meta <image id>']
@classmethod
def connection(this, foo):
- return generic._connection(foo, 'image.url')
+ return generic._connection(foo)
@classmethod
def id(this, foo):
def _raise(self, *args, **kwargs):
key = kwargs.get('key', None)
try:
- foo(self, *args, **kwargs)
+ return foo(self, *args, **kwargs)
except ClientError as ce:
ce_msg = ('%s' % ce).lower()
if ce.status == 404 or (
class pithos(object):
container_howto = [
'To specify a container:',
- ' 1. Set store.container variable (permanent)',
- ' /config set store.container <container>',
- ' 2. --container=<container> (temporary, overrides 1)',
- ' 3. Use the container:path format (temporary, overrides all)',
- 'For a list of containers: /store list']
+ ' 1. --container=<container> (temporary, overrides all)',
+ ' 2. Use the container:path format (temporary, overrides 3)',
+ ' 3. Set pithos_container variable (permanent)',
+ ' /config set pithos_container <container>',
+ 'For a list of containers: /file list']
@classmethod
def connection(this, foo):
- return generic._connection(foo, 'store.url')
+ return generic._connection(foo)
+
+ @classmethod
+ def account(this, foo):
+ def _raise(self, *args, **kwargs):
+ try:
+ return foo(self, *args, **kwargs)
+ except ClientError as ce:
+ if ce.status == 403:
+ raiseCLIError(
+ ce,
+ 'Invalid account credentials for this operation',
+ details=['Check user account settings'])
+ raise
+ return _raise
@classmethod
def quota(this, foo):
if ce.status == 413:
raiseCLIError(ce, 'User quota exceeded', details=[
'* get quotas:',
- ' * upper total limit: /store quota',
- ' * container limit: /store quota <container>',
- '* set a higher quota (if permitted):',
- ' /store setquota <quota>[unit] <container>'
- ' as long as <container quota> <= <total quota>'])
+ ' * upper total limit: /file quota',
+ ' * container limit:',
+ ' /file containerlimit get <container>',
+ '* set a higher container limit:',
+ ' /file containerlimit set <limit> <container>'])
raise
return _raise
return _raise
@classmethod
+ def local_path_download(this, foo):
+ def _raise(self, *args, **kwargs):
+ try:
+ return foo(self, *args, **kwargs)
+ except IOError as ioe:
+ msg = 'Failed to access a file',
+ raiseCLIError(ioe, msg, importance=2, details=[
+ 'Check if the file exists. Also check if the remote',
+ 'directories exist. All directories in a remote path',
+ 'must exist to succesfully download a container or a',
+ 'directory.',
+ 'To create a remote directory:',
+ ' [kamaki] file mkdir REMOTE_DIRECTORY_PATH'])
+ return _raise
+
+ @classmethod
def local_path(this, foo):
def _raise(self, *args, **kwargs):
- local_path = kwargs.get('local_path', '<None>')
+ local_path = kwargs.get('local_path', None)
try:
return foo(self, *args, **kwargs)
except IOError as ioe: