Implement user 1-level commands with astakosclient
authorStavros Sachtouris <saxtouri@admin.grnet.gr>
Wed, 16 Oct 2013 14:04:33 +0000 (17:04 +0300)
committerStavros Sachtouris <saxtouri@admin.grnet.gr>
Wed, 16 Oct 2013 14:04:33 +0000 (17:04 +0300)
Refs: #4340

kamaki/cli/commands/astakos.py
kamaki/cli/commands/errors.py
kamaki/cli/errors.py

index 8950aac..91dcd68 100644 (file)
 # or implied, of GRNET S.A.command
 
 from kamaki.cli import command
-from kamaki.clients.astakos import AstakosClient
+from kamaki.clients.astakos import AstakosClient, SynnefoAstakosClient
 from kamaki.cli.commands import (
     _command_init, errors, _optional_json, addLogSettings)
 from kamaki.cli.command_tree import CommandTree
 from kamaki.cli.errors import CLIBaseUrlError, CLIError
+from kamaki.cli.argument import FlagArgument
+from kamaki.cli.utils import format_size
 
-user_cmds = CommandTree('user', 'Astakos API commands')
-_commands = [user_cmds]
+user_commands = CommandTree('user', 'Astakos/Identity API commands')
+admin_commands = CommandTree('admin', 'Astakos/Account API commands')
+project_commands = CommandTree('project', 'Astakos project API commands')
+_commands = [user_commands, admin_commands, project_commands]
 
 
-class _user_init(_command_init):
-
-    def _write_main_token(self, token):
-        tokens = self.config.get_cloud(self.cloud, 'token').split()
-        if token in tokens:
-            tokens.remove(token)
-        tokens.insert(0, token)
-        self.config.set_cloud(self.cloud, 'token', ' '.join(tokens))
-        self.config.write()
-
+class _init_synnefo_astakosclient(_command_init):
     @errors.generic.all
     @errors.user.load
+    @errors.user.astakosclient
     @addLogSettings
     def _run(self):
-        if getattr(self, 'cloud', False):
+        if getattr(self, 'cloud', None):
             base_url = self._custom_url('astakos')
             if base_url:
                 token = self._custom_token(
                     'astakos') or self.config.get_cloud(self.cloud, 'token')
                 token = token.split()[0] if ' ' in token else token
-                self.client = AstakosClient(base_url=base_url, token=token)
+                self.client = SynnefoAstakosClient(
+                    auth_url=base_url, token=token)
                 return
         else:
             self.cloud = 'default'
-        if getattr(self, 'auth_base', False):
-            self.client = self.auth_base
+        if getattr(self, 'auth_base', None):
+            self.client = SynnefoAstakosClient(
+                auth_url=self.auth_base.base_url, token=self.auth_base.token)
             return
         raise CLIBaseUrlError(service='astakos')
 
@@ -75,103 +73,86 @@ class _user_init(_command_init):
         self._run()
 
 
-@command(user_cmds)
-class user_authenticate(_user_init, _optional_json):
-    """Authenticate a user
-    Get user information (e.g., unique account name) from token
-    Token should be set in settings:
-    *  check if a token is set    /config whoami cloud.default.token
-    *  permanently set a token    /config set cloud.default.token <token>
-    Token can also be provided as a parameter
-    (In case of another named cloud, use its name instead of default)
-    """
+@command(user_commands)
+class user_info(_init_synnefo_astakosclient, _optional_json):
+    """Authenticate a user and get info"""
 
     @errors.generic.all
     @errors.user.authenticate
+    @errors.user.astakosclient
     def _run(self, custom_token=None):
         token_bu = self.client.token
         try:
-            r = self.client.authenticate(custom_token)
-            if (token_bu != self.client.token and self.ask_user(
-                    'Permanently save token as cloud.%s.token ?' % (
-                        self.cloud))):
-                self._write_main_token(self.client.token)
-        except Exception:
-            #recover old token
+            self.client.token = custom_token or token_bu
+            self._print(
+                self.client.get_user_info(), self.print_dict)
+        finally:
             self.client.token = token_bu
-            raise
-
-        def _print_access(r, out):
-            self.print_dict(r['access'], out=out)
 
-        self._print(r, _print_access)
-
-    def main(self, custom_token=None):
+    def main(self, token=None):
         super(self.__class__, self)._run()
-        self._run(custom_token)
+        self._run(custom_token=token)
 
 
-@command(user_cmds)
-class user_list(_user_init, _optional_json):
-    """List all authenticated users"""
+@command(user_commands)
+class user_uuid2username(_init_synnefo_astakosclient, _optional_json):
+    """Get username(s) from uuid(s)"""
 
     @errors.generic.all
-    def _run(self, custom_token=None):
-        self._print(self.client.list_users())
-
-    def main(self):
+    @errors.user.astakosclient
+    def _run(self, uuids):
+        r = self.client.get_usernames(uuids)
+        self._print(r, self.print_dict)
+        unresolved = set(uuids).difference(r)
+        if unresolved:
+            self.error('Unresolved uuids: %s' % ', '.join(unresolved))
+
+    def main(self, uuid, *more_uuids):
         super(self.__class__, self)._run()
-        self._run()
+        self._run(uuids=((uuid, ) + more_uuids))
 
 
-@command(user_cmds)
-class user_whoami(_user_init, _optional_json):
-    """Get current session user information"""
+@command(user_commands)
+class user_username2uuid(_init_synnefo_astakosclient, _optional_json):
+    """Get uuid(s) from username(s)"""
 
     @errors.generic.all
-    def _run(self):
-        self._print(self.client.user_info(), self.print_dict)
-
-    def main(self):
+    @errors.user.astakosclient
+    def _run(self, usernames):
+        r = self.client.get_uuids(usernames)
+        self._print(r, self.print_dict)
+        unresolved = set(usernames).difference(r)
+        if unresolved:
+            self.error('Unresolved usernames: %s' % ', '.join(unresolved))
+
+    def main(self, username, *more_usernames):
         super(self.__class__, self)._run()
-        self._run()
+        self._run(usernames=((username, ) + more_usernames))
+
+
+@command(user_commands)
+class user_quotas(_init_synnefo_astakosclient, _optional_json):
+    """Get user quotas"""
+
+    _to_format = set(['cyclades.disk', 'pithos.diskspace', 'cyclades.ram'])
 
+    arguments = dict(
+        bytes=FlagArgument('Show data size in bytes', '--bytes')
+    )
 
-@command(user_cmds)
-class user_set(_user_init, _optional_json):
-    """Set session user by id
-    To enrich your options, authenticate more users:
-    /user authenticate <other user token>
-    To list authenticated users
-    /user list
-    To get the current session user
-    /user whoami
-    """
+    def _print_quotas(self, quotas, *args, **kwargs):
+        if not self['bytes']:
+            for category in quotas.values():
+                for service in self._to_format.intersection(category):
+                    for attr, v in category[service].items():
+                        category[service][attr] = format_size(v)
+        self.print_dict(quotas, *args, **kwargs)
 
     @errors.generic.all
-    def _run(self, uuid):
-        for user in self.client.list_users():
-            if user.get('id', None) in (uuid,):
-                ntoken = user['auth_token']
-                if ntoken == self.client.token:
-                    self.error('%s (%s) is already the session user' % (
-                        self.client.user_term('name'),
-                        self.client.user_term('id')))
-                    return
-                self.client.token = user['auth_token']
-                self.error('Session user set to %s (%s)' % (
-                        self.client.user_term('name'),
-                        self.client.user_term('id')))
-                if self.ask_user(
-                        'Permanently make %s the main user?' % (
-                            self.client.user_term('name'))):
-                    self._write_main_token(self.client.token)
-                return
-        raise CLIError(
-            'User with UUID %s not authenticated in current session' % uuid,
-            details=[
-                'To authenticate a user', '  /user authenticate <t0k3n>'])
+    @errors.user.astakosclient
+    def _run(self):
+        self._print(self.client.get_quotas(), self._print_quotas)
 
-    def main(self, uuid):
+    def main(self):
         super(self.__class__, self)._run()
-        self._run(uuid)
+        self._run()
index 5e336e4..22d381f 100644 (file)
@@ -32,6 +32,7 @@
 # or implied, of GRNET S.A.command
 
 from traceback import print_stack, print_exc
+from astakosclient import AstakosClientException
 
 from kamaki.clients import ClientError
 from kamaki.cli.errors import CLIError, raiseCLIError, CLISyntaxError
@@ -101,6 +102,16 @@ class user(object):
         '*  (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):
         def _raise(self, *args, **kwargs):
             r = foo(self, *args, **kwargs)
@@ -112,7 +123,7 @@ class user(object):
                 kloger.warning(
                     'No permanent token (try:'
                     ' kamaki config set cloud.default.token <tkn>)')
-            if not getattr(client, 'base_url', False):
+            if not getattr(client, 'astakos_base_url', False):
                 msg = 'Missing synnefo authentication URL'
                 raise CLIError(msg, importance=3, details=[
                     'Check if authentication URL is correct',
@@ -128,12 +139,11 @@ class user(object):
         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
index ec92804..16f22d3 100644 (file)
@@ -136,7 +136,11 @@ def raiseCLIError(err, message='', importance=0, details=[]):
     details = list(details) if (
         isinstance(details, list) or isinstance(details, tuple)) else [
             '%s' % details]
-    details += getattr(err, 'details', [])
+    err_details = getattr(err, 'details', [])
+    if not isinstance(details, list) or isinstance(details, tuple):
+        details.append('%s' % err_details)
+    else:
+        details += list(err_details)
 
     origerr = (('%s' % err) or '%s' % type(err)) if err else stack[0]
     message = '%s' % message or origerr