#!/usr/bin/env python

# Copyright European Organization for Nuclear Research (CERN)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Authors:
# - Mario Lassnig, <mario.lassnig@cern.ch>, 2012-2013
# - Vincent Garonne, <vincent.garonne@cern.ch>, 2012-2013
# - Thomas Beermann, <thomas.beermann@cern.ch>, 2012-2013
# - Wen Guan, <wguan@cern.ch>, 2014

"""
Rucio Administration Utility
"""

import argcomplete
import argparse
import os
import sys
import time

from rucio.client.accountclient import AccountClient
from rucio.client.quotaclient import QuotaClient
from rucio.client.rseclient import RSEClient
from rucio.client.scopeclient import ScopeClient

from rucio import version

# If ../lib/rucio/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
                                   os.pardir,
                                   os.pardir))
if os.path.exists(os.path.join(possible_topdir, 'lib/rucio', '__init__.py')):
    sys.path.insert(0, possible_topdir)


SUCCESS = 0
FAILURE = 1
DEFAULT_PORT = 443


def add_account(args):
    """
    %(prog)s add [options] <field1=value1 field2=value2 ...>

    Adds a new account. Specify metadata fields as arguments.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        accountClient.add_account(account=args.account, type=args.accounttype)
        print 'Added new account: %s' % args.account
    except Exception, e:
            print 'Failed to add account %s' % args.account
            print e
            return FAILURE
    return SUCCESS


def delete_account(args):
    """
    %(prog)s disable [options] <field1=value1 field2=value2 ...>

    Delete account.

    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        accountClient.delete_account(args.acnt)
        print 'Deleted account: %s' % args.acnt
    except Exception, e:
            print 'Failed to disable account %s' % args.acnt
            print e
            return FAILURE
    return SUCCESS


def ban_account(args):
    """
    %(prog)s ban [options] <field1=value1 field2=value2 ...>

    Ban an account.

    """

    raise NotImplementedError('This method is not implemented yet')

    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.account,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        accountClient.ban_account(args.account)
        print 'Banned account: %s' % args.account
    except Exception, e:
            print 'Failed to ban account %s' % args.acnt
            print e
            return FAILURE
    return SUCCESS


def unban_account(args):
    """
    %(prog)s unban [options] <field1=value1 field2=value2 ...>

    Unban a banned account.

    """

    raise NotImplementedError('This method is not implemented yet')

    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.account,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        accountClient.unban_account(args.account)
        print 'Unbanned account: %s' % args.account
    except Exception, e:
            print 'Failed to unban account %s' % args.acnt
            print e
            return FAILURE
    return SUCCESS


def list_accounts(args):
    """
    %(prog)s list [options] <field1=value1 field2=value2 ...>

    List accounts.

    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None
    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        accounts = accountClient.list_accounts(identity=args.identity, account_type=args.account_type)
    except Exception, e:
            print 'Failed to list accounts'
            print e
            return FAILURE

    for account in accounts:
        print account['account']

    return SUCCESS


def info_account(args):
    """
    %(prog)s show [options] <field1=value1 field2=value2 ...>

    Show extended information of a given account

    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        info = accountClient.get_account(account=args.account)
    except Exception, e:
            print 'Failed to show account information'
            print e
            return FAILURE

    for k in info:
        print k.ljust(10) + ' : ' + str(info[k])

    return SUCCESS


def list_identities(args):
    """
    %(prog)s list-identities [options] <field1=value1 field2=value2 ...>

    List all identities on an account.
    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        identities = accountClient.list_identities(account=args.account)
    except Exception, e:
            print 'Failed to list identities for account %s' % args.account
            print e
            return FAILURE

    for identity in identities:
        print 'Identity: %(identity)s,\ttype: %(type)s' % identity

    return SUCCESS


def set_limits(args):
    """
    %(prog)s set-limits [options] <field1=value1 field2=value2 ...>

    Grant an identity access to an account.

    """
    raise NotImplementedError('This method is not implemented yet')
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                  account=args.issuer,
                  auth_type=args.auth_strategy, creds=creds,
                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        print 'Added new limits to account: %s' % (args.account)
    except Exception, e:
        print 'Failed add limits to an account'
        print e
        return FAILURE

    return SUCCESS


def get_limits(args):
    """
    %(prog)s get-limits [options] <field1=value1 field2=value2 ...>

    Grant an identity access to an account.

    """
    raise NotImplementedError('This method is not implemented yet')
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                  account=args.account,
                  auth_type=args.auth_strategy, creds=creds,
                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        print 'Added new limits to account: %s' % (args.account)
    except Exception, e:
        print 'Failed add limits to an account'
        print e
        return FAILURE

    return SUCCESS


def delete_limits(args):
    """
    %(prog)s delete-limits [options] <field1=value1 field2=value2 ...>

    Grant an identity access to an account.

    """
    raise NotImplementedError('This method is not implemented yet')
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                  account=args.issuer,
                  auth_type=args.auth_strategy, creds=creds,
                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        print 'Added new limits to account: %s' % (args.account)
    except Exception, e:
        print 'Failed add limits to an account'
        print e
        return FAILURE

    return SUCCESS


def identity_add(args):
    """
    %(prog)s del [options] <field1=value1 field2=value2 ...>

    Grant an identity access to an account.

    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    accountClient = AccountClient(rucio_host=args.host, auth_host=args.auth_host,
                                  account=args.issuer,
                                  auth_type=args.auth_strategy, creds=creds,
                                  ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        accountClient.add_identity(account=args.account, identity=args.identity, authtype=args.authtype, email=args.email)
        print 'Added new identity to account: %s-%s' % (args.identity, args.account)
    except Exception, e:
            print 'Failed to grant an identity access to an account'
            print e
            return FAILURE

    return SUCCESS


def identity_delete(args):
    """
    %(prog)s delete [options] <field1=value1 field2=value2 ...>

    Revoke an identity's access to an account.

    """
    pass


def add_rse(args):
    """
    %(prog)s add [options] <field1=value1 field2=value2 ...>

    Adds a new rse. Specify metadata fields as arguments.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        client.add_rse(args.rse)
        print 'Added new RSE: %s' % args.rse
    except Exception, e:
            print 'Failed to add rse %s' % args.rse
            print e
            return FAILURE
    return SUCCESS


def disable_rse(args):
    """
    %(prog)s del [options] <field1=value1 field2=value2 ...>

    Disable rse.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        client.delete_rse(args.rse)
    except Exception, e:
            print 'Failed to delete RSE %s' % args.rse
            print e
            return FAILURE
    return SUCCESS


def list_rses(args):
    """
    %(prog)s list [options] <field1=value1 field2=value2 ...>

    List rses.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        rses = client.list_rses()
    except Exception, e:
            print 'Failed to list RSEs'
            print e
            return FAILURE

    for rse in rses:
        print '%(rse)s' % rse

    return SUCCESS


def info_rse(args):
    """
    %(prog)s info [options] <field1=value1 field2=value2 ...>

    Show extended information of a given rse

    """
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    rseclient = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                          account=args.issuer,
                          auth_type=args.auth_strategy, creds=creds,
                          ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        rseinfo = rseclient.get_rse(rse=args.rse)
        attributes = rseclient.list_rse_attributes(rse=args.rse)
        usage = rseclient.get_rse_usage(rse=args.rse)
    except Exception, e:
            print 'Failed to get RSE info'
            print e
            return FAILURE

    print 'Settings:'
    print '========='
    for key in rseinfo:
        if key != 'protocols':
            print '  ' + key + ': ' + str(rseinfo[key])
    print 'Attributes:'
    print '==========='
    for k in attributes:
        print '  ' + k + ': ' + str(attributes[k])
    print 'Protocols:'
    print '=========='
    for protocol in rseinfo['protocols']:
        print '  ' + protocol['scheme']
        for item in protocol:
            print '    ' + item + ': ' + str(protocol[item])
    print 'Usage:'
    print '======'
    for elem in usage:
        print '  ' + elem + ': ' + str(usage[elem])

    return SUCCESS


def set_attribute_rse(args):
    """
    %(prog)s set-attribute [options] <field1=value1 field2=value2 ...>

    setattr RSE.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        client.add_rse_attribute(rse=args.rse, key=args.key, value=args.value)
        print 'Added new RSE attribute for %s: %s-%s ' % (args.rse, args.key, args.value)
    except Exception, e:
            print 'Failed to add RSE attribute'
            print e
            return FAILURE

    return SUCCESS


def get_attribute_rse(args):
    """
    %(prog)s get-attribute [options] <field1=value1 field2=value2 ...>

    getattr RSE.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        attributes = client.list_rse_attributes(rse=args.rse)
    except Exception, e:
            print 'Failed to get RSE attributes'
            print e
            return FAILURE

    for k in attributes:
        print k + ': ' + str(attributes[k])

    return SUCCESS


def delete_attribute_rse(args):
    """
    %(prog)s delete-attribute [options] <field1=value1 field2=value2 ...>

    setattr RSE.

    """
    # For the moment...
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}
    else:
        creds = None

    client = RSEClient(rucio_host=args.host, auth_host=args.auth_host,
                       account=args.issuer,
                       auth_type=args.auth_strategy, creds=creds,
                       ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        client.delete_rse_attribute(rse=args.rse, key=args.key)
        print 'Deleted RSE attribute for %s: %s-%s ' % (args.rse, args.key, args.value)
    except Exception, e:
            print 'Failed to delete RSE attribute'
            print e
            return FAILURE

    return SUCCESS


def add_scope(args):
    """
    %(prog)s add [options] <field1=value1 field2=value2 ...>

    Add scope.

    """
    # For the moment..
    creds = None
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}

    client = ScopeClient(rucio_host=args.host, auth_host=args.auth_host,
                         account=args.issuer,
                         auth_type=args.auth_strategy, creds=creds,
                         ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        client.add_scope(account=args.account, scope=args.scope)
        print 'Added new scope to account: %s-%s' % (args.scope, args.account)
    except Exception, e:
            print 'Failed to add scope'
            print e
            return FAILURE
    return SUCCESS


def list_scopes(args):
    """
    %(prog)s list [options] <field1=value1 field2=value2 ...>

    List scopes.

    """
    # For the moment..
    creds = None
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}

    client = ScopeClient(rucio_host=args.host, auth_host=args.auth_host,
                         account=args.issuer,
                         auth_type=args.auth_strategy, creds=creds,
                         ca_cert=args.ca_certificate, timeout=args.timeout)
    try:
        scopes = client.list_scopes()
    except Exception, e:
            print 'Failed to list scopes'
            print e
            return FAILURE

    for scope in scopes:
        print scope

    return SUCCESS


def set_quota(args):
    """
    %(prog)s set [options] <field1=value1 field2=value2 ...>

    Set quota for an account.
    """

    raise NotImplementedError('This method is not implemented yet')

    # For the moment..
    creds = None
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}

    client = QuotaClient(rucio_host=args.host, auth_host=args.auth_host,
                         account=args.account,
                         auth_type=args.auth_strategy, creds=creds,
                         ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        client.set_quota(account=args.account, quota=args.quota)
        print 'Set new quota for account %s: %s' % (args.account, args.quota)
    except Exception, e:
            print 'Failed to set quota'
            print e
            return FAILURE
    return SUCCESS


def get_quota(args):
    """
    %(prog)s get [options] <field1=value1 field2=value2 ...>

    Get quota for an account.
    """

    raise NotImplementedError('This method is not implemented yet')

    # For the moment..
    creds = None
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}

    client = QuotaClient(rucio_host=args.host, auth_host=args.auth_host,
                         account=args.issuer,
                         auth_type=args.auth_strategy, creds=creds,
                         ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        client.get_quota(account=args.account)
    except Exception, e:
            print 'Failed to get quota'
            print e
            return FAILURE
    return SUCCESS


def delete_quota(args):
    """
    %(prog)s delete [options] <field1=value1 field2=value2 ...>

    Delete quota for an account.
    """

    raise NotImplementedError('This method is not implemented yet')

    # For the moment..
    creds = None
    if args.auth_strategy == 'userpass':
        creds = {'username': args.username, 'password': args.password}

    client = QuotaClient(rucio_host=args.host, auth_host=args.auth_host,
                         account=args.issuer,
                         auth_type=args.auth_strategy, creds=creds,
                         ca_cert=args.ca_certificate, timeout=args.timeout)

    try:
        client.delete_quota(account=args.account, quota=args.quota)
        print 'Deleted quota for account %s: %s' % (args.account, args.quota)
    except Exception, e:
            print 'Failed to delete quota'
            print e
            return FAILURE
    return SUCCESS


if __name__ == '__main__':
    usage = """
%(prog)s

 <command> [options] [args]

Commands:

    help <command>  Output help for one of the commands below

"""
    oparser = argparse.ArgumentParser(prog=os.path.basename(sys.argv[0]), add_help=True)
    subparsers = oparser.add_subparsers()

    # Main arguments
    oparser.add_argument('--version', action='version', version='%(prog)s ' + version.version_string())
    oparser.add_argument('--verbose', '-v', default=False, action='store_true', help="Print more verbose output")
    oparser.add_argument('-H', '--host', dest="host", metavar="ADDRESS", help="The Rucio API host")
    oparser.add_argument('--auth_host', dest="auth_host", metavar="ADDRESS", help="The Rucio Authentication host")
    oparser.add_argument('-a', '--account', dest="issuer", metavar="ACCOUNT", help="Rucio account to use")
    oparser.add_argument('-S', '--auth-strategy', dest="auth_strategy", default=None, help="Authentication strategy (userpass or x509 or ...)")
    oparser.add_argument('-T', '--timeout', dest="timeout", type=float, default=None, help="Set all timeout values to SECONDS")

    # Options for the userpass auth_strategy
    oparser.add_argument('-u', '--user', dest='username', default=None, help='username')
    oparser.add_argument('-pwd', '--password', dest='password', default=None, help='password')

    # Options for the x509  auth_strategy
    oparser.add_argument('--certificate', dest='certificate', default=None, help='Client certificate file')
    oparser.add_argument('--ca-certificate', dest='ca_certificate', default=None, help='CA certificate to verify peer against (SSL)')

    # The account subparser
    account_parser = subparsers.add_parser('account', help='Account methods')
    account_subparser = account_parser.add_subparsers()

    # The list_accounts command
    list_account_parser = account_subparser.add_parser('list', help='List Rucio accounts')
    list_account_parser.add_argument('--type', dest='account_type', action='store', help='Account Type (USER, GROUP, SERVICE)')
    list_account_parser.add_argument('--id', dest='identity', action='store', help='Identity (e.g. DN)')

    list_account_parser.set_defaults(which='list_accounts')

    # The add_account command
    add_account_parser = account_subparser.add_parser('add', help='Add Rucio account')
    add_account_parser.set_defaults(which='add_account')
    add_account_parser.add_argument('account', action='store', help='Account name')
    add_account_parser.add_argument('--type', dest='accounttype', default='USER', help='Account Type')

    # The disable_account command
    delete_account_parser = account_subparser.add_parser('delete', help='Delete Rucio account')
    delete_account_parser.set_defaults(which='delete_account')
    delete_account_parser.add_argument('acnt', action='store', help='Account name')

    # The info_account command
    info_account_parser = account_subparser.add_parser('info', help='Show detailed information about an account')
    info_account_parser.set_defaults(which='info_account')
    info_account_parser.add_argument('account', action='store', help='Account name')

    # The list_account_identities command
    list_account_identities_parser = account_subparser.add_parser('list-identities', help='List all identities on an account')
    list_account_identities_parser.set_defaults(which='list_identities')
    list_account_identities_parser.add_argument('account', action='store', help='Account name')

    set_account_limits_parser = account_subparser.add_parser('set-limits', help='Set the limits for the provided account')
    set_account_limits_parser.set_defaults(which='set_limits')
    set_account_limits_parser.add_argument('--account', dest='acnt', action='store', help='Account name', required=True)
    set_account_limits_parser.add_argument('--rse-expr', dest='rse_expre', action='store', help='RSE boolean expression', required=True)
    set_account_limits_parser.add_argument('--value', dest='value', action='store', help='The total number of bytes that can be stored', required=True)

    ban_account_limits_parser = account_subparser.add_parser('ban', help='Ban an account')
    ban_account_limits_parser.set_defaults(which='ban_account')
    ban_account_limits_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)

    unban_account_limits_parser = account_subparser.add_parser('unban', help='Unban a banned account')
    unban_account_limits_parser.set_defaults(which='unban_account')
    unban_account_limits_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)

    # The identity subparser
    identity_parser = subparsers.add_parser('identity', help='Identity methods')
    identity_subparser = identity_parser.add_subparsers()

    # The identity_add command
    identity_add_parser = identity_subparser.add_parser('add', help='Grant an identity access to an account')
    identity_add_parser.set_defaults(which='identity_add')
    identity_add_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)
    identity_add_parser.add_argument('--type', dest='authtype', action='store', help='Authentivation type(e.g. X509, gss)', required=True)
    identity_add_parser.add_argument('--id', dest='identity', action='store', help='Identity', required=True)
    identity_add_parser.add_argument('--email', dest='email', action='store', help='Email address associated with the identity', required=True)

    # The identity_delete command
    identity_delete_parser = identity_subparser.add_parser('delete', help="Revoke an identity's access to an account")
    identity_delete_parser.set_defaults(which='identity_delete')
    identity_delete_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)
    identity_delete_parser.add_argument('--type', dest='authtype', action='store', help='Authentivation type(e.g. X509, gss)', required=True)
    identity_delete_parser.add_argument('--id', dest='identity', action='store', help='Identity', required=True)

    # The RSE subparser
    rse_parser = subparsers.add_parser('rse', help='RSE(Rucio Storage Element) methods')
    rse_subparser = rse_parser.add_subparsers()

    # The list_rses command
    list_rse_parser = rse_subparser.add_parser('list', help='List Rucio RSEs')
    list_rse_parser.set_defaults(which='list_rses')

    # The add_rse command
    add_rse_parser = rse_subparser.add_parser('add', help='Add RSE')
    add_rse_parser.set_defaults(which='add_rse')
    add_rse_parser.add_argument('rse', action='store', help='RSE name')

    # The info_rse command
    info_rse_parser = rse_subparser.add_parser('info', help='Information about RSE')
    info_rse_parser.set_defaults(which='info_rse')
    info_rse_parser.add_argument('rse', action='store', help='RSE name')

    # The set_attribute_rse command
    set_attribute_rse_parser = rse_subparser.add_parser('set-attribute', help='Add RSE attribute(key-value pair)')
    set_attribute_rse_parser.set_defaults(which='set_attribute_rse')
    set_attribute_rse_parser.add_argument('--rse', dest='rse', action='store', help='RSE name', required=True)
    set_attribute_rse_parser.add_argument('--key', dest='key', action='store', help='Attribute key', required=True)
    set_attribute_rse_parser.add_argument('--value', dest='value', action='store', help='Attribute value', required=True)

    # The delete_attribute_rse command
    delete_attribute_rse_parser = rse_subparser.add_parser('delete-attribute', help='Delete a RSE attribute(key-value pair)')
    delete_attribute_rse_parser.set_defaults(which='delete_attribute_rse')
    delete_attribute_rse_parser.add_argument('--rse', dest='rse', action='store', help='RSE name', required=True)
    delete_attribute_rse_parser.add_argument('--key', dest='key', action='store', help='Attribute key', required=True)
    delete_attribute_rse_parser.add_argument('--value', dest='value', action='store', help='Attribute value', required=True)

    # The get_attribute_rse command
    get_attribute_rse_parser = rse_subparser.add_parser('get-attribute', help='List RSE attributes')
    get_attribute_rse_parser.set_defaults(which='get_attribute_rse')
    get_attribute_rse_parser.add_argument(dest='rse', action='store', help='RSE name')

    # The disable_location command
    disable_rse_parser = rse_subparser.add_parser('delete', help='Disable RSE')
    disable_rse_parser.set_defaults(which='disable_rse')
    disable_rse_parser.add_argument('rse', action='store', help='RSE name')

    # The scope subparser
    scope_parser = subparsers.add_parser('scope', help='Scope methods')
    scope_subparser = scope_parser.add_subparsers()

    # The add_scope command
    add_scope_parser = scope_subparser.add_parser('add', help='Add scope')
    add_scope_parser.set_defaults(which='add_scope')
    add_scope_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)
    add_scope_parser.add_argument('--scope', dest='scope', action='store', help='Scope name', required=True)

    # The list_scope command
    list_scope_parser = scope_subparser.add_parser('list', help='List scopes')
    list_scope_parser.set_defaults(which='list_scopes')
    list_scope_parser.add_argument('--account', dest='account', action='store', help='Account name')

    # The quota subparser
    quota_parser = subparsers.add_parser('quota', help='Quota methods')
    quota_subparser = quota_parser.add_subparsers()

    # The set_quota command
    set_quota_parser = quota_subparser.add_parser('set', help='Set quota for an account')
    set_quota_parser.set_defaults(which='set_quota')
    set_quota_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)
    set_quota_parser.add_argument('--quota', dest='quota', action='store', help='Quota definition', required=True)

    # The get_quota command
    get_quota_parser = quota_subparser.add_parser('get', help='Get quota for an account')
    get_quota_parser.set_defaults(which='get_quota')
    get_quota_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)

    # The delete_quota command
    delete_quota_parser = quota_subparser.add_parser('delete', help='Delete quota for an account')
    delete_quota_parser.set_defaults(which='delete_quota')
    delete_quota_parser.add_argument('--account', dest='account', action='store', help='Account name', required=True)
    delete_quota_parser.add_argument('--quota', dest='quota', action='store', help='Quota definition', required=True)

    commands = {'add_account': add_account,
                'list_accounts': list_accounts,
                'delete_account': delete_account,
                'info_account': info_account,
                'ban_account': ban_account,
                'unban_account': unban_account,
                'set_limits': set_limits,
                'get_limits': get_limits,
                'delete_limits': delete_limits,
                'list_identities': list_identities,
                'identity_add': identity_add,
                'identity_delete': identity_delete,
                'add_rse': add_rse,
                'set_attribute_rse': set_attribute_rse,
                'get_attribute_rse': get_attribute_rse,
                'delete_attribute_rse': delete_attribute_rse,
                'list_rses': list_rses,
                'disable_rse': disable_rse,
                'add_scope': add_scope,
                'list_scopes': list_scopes,
                'set_quota': set_quota,
                'get_quota': get_quota,
                'delete_quota': delete_quota,
                'info_rse': info_rse
                }

    argcomplete.autocomplete(oparser)

    if len(sys.argv) == 1:
        oparser.print_help()
        sys.exit(FAILURE)

    args = oparser.parse_args(sys.argv[1:])

    try:
        start_time = time.time()
        command = commands.get(args.which)
        result = command(args)
        end_time = time.time()
        if args.verbose:
            print "Completed in %-0.4f sec." % (end_time - start_time)
        sys.exit(result)
    except (RuntimeError, NotImplementedError), e:
        print >> sys.stderr, "ERROR: ", e
        sys.exit(FAILURE)
