#!/usr/local/bin/python
import getopt
import isi.auth as auth
import sys

# auth.idmap_iter returns strings of the form:
#   ["ZID:1", "UID:100000", [["SID:S-1-2-3-4", 48]]]
def dump_mappings(zid):
    # create list containing zid and source item of mapping
    lst = map(lambda x: x[0:2], filter(lambda x: x, auth.idmap_iter()))
    if zid is not None:
        return filter(lambda x: x[0][4:] == zid, lst)
    else:
        return lst

def delete_mapping(mapping, opt_zid, opt_externals, opt_generated, opt_force):
    zid_str = mapping[0]
    persona_str = mapping[1]
    zid_str = zid_str[4:] # strip off ZID:

    if opt_zid is not None and zid_str != opt_zid:
        return False

    if (zid_str == "None"):
        zid = 0
        opts = auth.MAPPING_OPTIONS_MODIFY_GLOBAL
    else:
        zid = int(zid_str)
        opts = 0

    try:
        p = auth.persona(persona_str)
        if opt_force:
            opts = opts | (auth.MAPPING_OPTIONS_FORCE_DELETE)
        if opt_externals:
            opts = opts | (auth.MAPPING_OPTIONS_DELETE_EXTERNAL)
        if opt_generated:
            opts = opts | (auth.MAPPING_OPTIONS_DELETE_AUTO)
        p.remove_mapping(options=opts,zid=zid)
    except Exception:
        return False
    return True

def usage(errorMsg=None):
    if errorMsg:
        print errorMsg
    print 'Usage: isi_clean_idmap --clean-idmap [--only-externals] [--only-generated] [--zid id] [--force]'
    print ''
    print ' --clean-idmap    Necessary in order to run this command'
    print ' --only-externals Only delete mappings between two external sources'
    print ' --only-generated Only delete mappings that with auto-generated UID/GIDs'
    print ' --zid ID   Only clean mappings in zone with matching zone id'
    print ' --force    Delete entry even if marked "reserved" (e.g entries that include quota key info)'

def main(argv):
    opt_force = False
    opt_externals = False
    opt_generated = False
    opt_zid = None
    # Option handling

    hasArg = False
    for i in range(len(sys.argv)):
        if sys.argv[i] == '--clean-idmap':
            hasArg = True
        elif sys.argv[i] == '-h' or sys.argv[i] == '--help':
            usage()
            return 2
    if not hasArg:
        print 'Must specify --clean-idmap to clean the idmap database'
        print
        usage()
        return 2

    try:
        (options, args) = getopt.getopt(argv, '', [ 'clean-idmap',
                                             'only-externals',
                                             'only-generated',
                                             'zid=',
                                             'force' ])
    except getopt.GetoptError, e:
        usage(str(e))
        return 2

    success = 0
    failures = 0
    count = 0

    for option, value in options:
        if option == '--only-externals':
            opt_externals = True
        if option == '--only-generated':
            opt_generated = True
        if option == '--force':
            opt_force = True
        if option == '--zid':
            opt_zid = value

    mappings = dump_mappings(opt_zid)
    total = len(mappings)
    if total == 0:
        print "Idmap database is already clean"
        sys.exit(0)

    sys.stdout.write("Attempting to clean up to %d mappings"%total)
    for mapping in mappings:
        if count % 10 == 0:
            sys.stdout.write('.')
        if delete_mapping(mapping, opt_zid, opt_externals, opt_generated, opt_force):
            success += 1
        else:
            failures += 1
        count += 1
    sys.stdout.write('\n')
    print "Removed %d mappings."%success
    if failures:
        print "Failed to remove %d mappings."%failures
        sys.exit(1)
    sys.exit(0)


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
