#!/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-2014
# - Vincent Garonne, <vincent.garonne@cern.ch>, 2012-2013
# - Thomas Beermann, <thomas.beermann@cern.ch>, 2012-2013
# - Wen Guan, <wguan@cern.ch>, 2014
# - Martin Barisits, <martin.barisits@cern.ch>, 2014
# - David Cameron, <david.cameron@cern.ch>, 2014

"""
Rucio Administration Utility
"""

import argcomplete
import argparse
import json
import os
import sys
import time

from rucio.client.accountclient import AccountClient
from rucio.client.accountlimitclient import AccountLimitClient
from rucio.client.configclient import ConfigClient
from rucio.client.rseclient import RSEClient
from rucio.client.scopeclient import ScopeClient
from rucio.client.subscriptionclient import SubscriptionClient

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_account_limit(args):
    """
    %(prog)s set [options] <field1=value1 field2=value2 ...>

    Set account limit for an account and rse.
    """

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

    client = AccountLimitClient(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.set_account_limit(account=args.limit_account, rse=args.rse, bytes=args.bytes)
        print 'Set account limit for account %s on RSE %s: %s' % (args.limit_account, args.rse, args.bytes)
    except Exception, e:
            print 'Failed to set account limit'
            print e
            return FAILURE
    return SUCCESS


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

    Delete account limit for an account and rse.
    """

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

    client = AccountLimitClient(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_account_limit(account=args.limit_account, rse=args.rse)
        print 'Deleted account limit for account %s and RSE %s' % (args.limit_account, args.rse)
    except Exception, e:
            print 'Failed to delete account limit'
            print e
            return FAILURE
    return SUCCESS


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

    Get the configuration. Either everything, or matching the given section/option.
    """

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

    client = ConfigClient(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:
        res = client.get_config(section=args.section, option=args.option)
        if not isinstance(res, dict):
            print '[%s]\n%s=%s' % (args.section, args.option, str(res))
        else:
            print_header = True
            for i in res.keys():
                if print_header:
                    if args.section is not None:
                        print '[%s]' % args.section
                    else:
                        print '[%s]' % i
                if not isinstance(res[i], dict):
                    print '%s=%s' % (i, str(res[i]))
                    print_header = False
                else:
                    for j in res[i].keys():
                        print '%s=%s' % (j, str(res[i][j]))
    except Exception, e:
            print 'Failed to get configuration:', e
            return FAILURE
    return SUCCESS


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

    Set the configuration value for a matching section/option. Missing section/option will be created.
    """

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

    client = ConfigClient(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.set_config_option(section=args.section, option=args.option, value=args.value)
        print 'Set configuration: %s.%s=%s' % (args.section, args.option, args.value)
    except Exception, e:
            print 'Failed to set configuration'
            print e
            return FAILURE
    return SUCCESS


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

    Delete a configuration option from a section
    """

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

    client = ConfigClient(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:
        if client.delete_config_option(section=args.section, option=args.option):
            print 'Deleted section \'%s\' option \'%s\'' % (args.section, args.option)
        else:
            print 'Section \'%s\' option \'%s\' not found' % (args.section, args.option)
    except Exception, e:
            print 'Failed to delete option'
            print e
            return FAILURE
    return SUCCESS


def add_subscription(args):
    """
    %(prog)s add [options] name filter replication_rules

    Add subscription.

    """

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

    client = SubscriptionClient(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_subscription(args.name, json.loads(args.filter), json.loads(args.replication_rules),
                                'tier0', args.lifetime, False, False)
        print 'Subscription added'
    except Exception, e:
        print 'Failed to add subscription'
        print e
        return FAILURE

    return SUCCESS


def list_subscriptions(args):
    """
    %(prog)s list [options] [name]

    List subscriptions.

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

    client = SubscriptionClient(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:
        subs = client.list_subscriptions(name=args.name, account=args.subs_account)
        for sub in subs:
            if (args.long):
                print '\n'.join('%s: %s' % (str(k),str(v)) for (k,v) in sub.items())
                print
            else:
                print "%s: %s %s\n  filter: %s\n  rules: %s" % (sub['account'], sub['name'], sub['state'], sub['filter'], sub['replication_rules'])
    except Exception, e:
        print 'Failed to list subscription'
        print e
        return FAILURE

    return SUCCESS


def update_subscription(args):
    """
    %(prog)s update [options] name filter replication_rules

    Update a subscription.

    """

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

    client = SubscriptionClient(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.update_subscription(args.name, json.loads(args.filter), json.loads(args.replication_rules),
                                   'tier0', args.lifetime, False, False)
        print 'Subscription updated'
    except Exception, e:
        print 'Failed to update subscription'
        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 account-limit subparser
    account_limit_parser = subparsers.add_parser('account-limit', help='Account limits')
    account_limit_subparser = account_limit_parser.add_subparsers()

    # The set_account_limit command
    set_account_limit_parser = account_limit_subparser.add_parser('set', help='Set account limit for an account and rse.')
    set_account_limit_parser.set_defaults(which='set_account_limit')
    set_account_limit_parser.add_argument('limit_account', action='store', help='Account name')
    set_account_limit_parser.add_argument('rse', action='store', help='RSE name')
    set_account_limit_parser.add_argument('bytes', action='store', help='Account limit in bytes')

    # The delete_quota command
    delete_account_limit_parser = account_limit_subparser.add_parser('delete', help='Delete quota for an account')
    delete_account_limit_parser.set_defaults(which='delete_account_limit')
    delete_account_limit_parser.add_argument('limit_account', action='store', help='Account name')
    delete_account_limit_parser.add_argument('rse', action='store', help='RSE name')

    # The config subparser
    config_parser = subparsers.add_parser('config', help='Configuration methods')
    config_subparser = config_parser.add_subparsers()

    # The get_config command
    get_config_parser = config_subparser.add_parser('get', help='Get matching configuration')
    get_config_parser.set_defaults(which='get_config')
    get_config_parser.add_argument('--section', dest='section', action='store', help='Section name', required=False)
    get_config_parser.add_argument('--option', dest='option', action='store', help='Option name', required=False)

    # The set_config_option command
    set_config_parser = config_subparser.add_parser('set', help='Set matching configuration')
    set_config_parser.set_defaults(which='set_config_option')
    set_config_parser.add_argument('--section', dest='section', action='store', help='Section name', required=True)
    set_config_parser.add_argument('--option', dest='option', action='store', help='Option name', required=True)
    set_config_parser.add_argument('--value', dest='value', action='store', help='String-encoded value', required=True)

    # The delete_config_option command
    delete_config_parser = config_subparser.add_parser('delete', help='Delete matching configuration')
    delete_config_parser.set_defaults(which='delete_config_option')
    delete_config_parser.add_argument('--section', dest='section', action='store', help='Section name', required=True)
    delete_config_parser.add_argument('--option', dest='option', action='store', help='Option name', required=True)

    # The subscription parser
    subs_parser = subparsers.add_parser('subscription', help='Subscription methods')
    subs_subparser = subs_parser.add_subparsers()

    # The add-subscription command
    add_sub_parser = subs_subparser.add_parser('add', help='Add subscription')
    add_sub_parser.set_defaults(which='add_subscription')
    add_sub_parser.add_argument(dest='name', action='store', help='Subscription name')
    add_sub_parser.add_argument(dest='filter', action='store', help='DID filter (eg \'{"scope": ["tests"], "project": ["data12_8TeV"]}\')')
    add_sub_parser.add_argument(dest='replication_rules', action='store', help='Replication rules (eg \'[{"copies": 2, "rse_expression": "tier=2", "lifetime": 3600}]\')')
    add_sub_parser.add_argument('--lifetime', dest='lifetime', action='store', type=int, help='Subscription lifetime (in days)')
    # subscription policy, retroactive and dry_run hard-coded for now

    # The list-subscriptions command
    list_sub_parser = subs_subparser.add_parser('list', help='List subscriptions')
    list_sub_parser.set_defaults(which='list_subscriptions')
    list_sub_parser.add_argument('--account', dest='subs_account', action='store', help='Account name')
    list_sub_parser.add_argument('--long', dest='long', action='store_true', help='Long listing')
    list_sub_parser.add_argument(dest='name', nargs='?', action='store', help='Subscription name')

    # The update-subscription command
    update_sub_parser = subs_subparser.add_parser('update', help='Update subscription')
    update_sub_parser.set_defaults(which='update_subscription')
    update_sub_parser.add_argument(dest='name', action='store', help='Subscription name')
    update_sub_parser.add_argument(dest='filter', action='store', help='DID filter (eg \'{"scope": ["tests"], "project": ["data12_8TeV"]}\')')
    update_sub_parser.add_argument(dest='replication_rules', action='store', help='Replication rules (eg \'[{"copies": 2, "rse_expression": "tier=2", "lifetime": 3600}]\')')
    update_sub_parser.add_argument('--lifetime', dest='lifetime', action='store', type=int, help='Subscription lifetime (in days)')
    # subscription policy, retroactive and dry_run hard-coded for now

    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_account_limit': set_account_limit,
                'delete_account_limit': delete_account_limit,
                'info_rse': info_rse,
                'info_rse': info_rse,
                'get_config': get_config,
                'set_config_option': set_config_option,
                'delete_config_option': delete_config_option,
                'add_subscription': add_subscription,
                'list_subscriptions': list_subscriptions,
                'update_subscription': update_subscription
                }

    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)
