#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Created on 25 Feb 2014

@author: karli.sjoberg@slu.se

version: 1.0
comment: This script takes care of destroying a machine when it's not wanted any more.
'''

import sys
import os.path
import re
import subprocess
import time
import logging
import ldap
logging.basicConfig(filename='/var/log/vpscreate.log', format='%(asctime)s: %(message)s', level=logging.DEBUG)
from kira.api import DestroyClass, CreateClass
from kira.api import api

def usage():
    basename0 = os.path.basename(sys.argv[0])
    print ''
    print 'Usage: %s [USER_ID] [VM_NAME]' % (basename0)
    print 'Example: %s perma testvm' % (basename0)

def query_yes_no(question, default="no"):
    """Ask a yes/no question via raw_input() and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits <Enter>.
        It must be "no" (the default), "yes" or None (meaning
        an answer is required of the user).

    The "answer" return value is one of "yes" or "no".
    """
    valid = {"yes":True, "y":True, "no":False, "n":False}
    if default == None:
        prompt = " (y/n): "
    elif default == "yes":
        prompt = " (y/n) [yes]: "
    elif default == "no":
        prompt = " (y/n) [no]: "
    else:
        raise ValueError("invalid default answer: '%s'" % default)

    while True:
        sys.stdout.write(question + prompt)
        choice = raw_input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write('Please respond with "yes/y" or "no/n". Default is "' + default + '".\n')

def findUserPrincipal(CUSTOMER_ID):
    SERVER_NAME = 'ad'
    DOMAIN_NAME = 'slu.se'
    BASE_DN = "DC=AD,DC=SLU,DC=SE"
    
    BIND_USER = 'studentradius'
    BIND_PASSWORD = 'Password12.'

    LDAP_SERVER = 'ldap://%s.%s' % (SERVER_NAME,DOMAIN_NAME)
    LDAP_USERNAME = '%s@%s.%s' % (BIND_USER,SERVER_NAME,DOMAIN_NAME)
    LDAP_PASSWORD = BIND_PASSWORD

    try:
        ldap_client = ldap.initialize(LDAP_SERVER)
        ldap_client.set_option(ldap.OPT_REFERRALS,0)
        ldap_client.simple_bind_s(LDAP_USERNAME, LDAP_PASSWORD)
        retrieveAttributes = ['userPrincipalName']
        searchFilter = "sAMAccountName=%s" % (CUSTOMER_ID)
        rawSearch = ldap_client.search_s(BASE_DN, ldap.SCOPE_SUBTREE, searchFilter, retrieveAttributes)
    except ldap.SIZELIMIT_EXCEEDED:
        pass
    except ldap.OPERATIONS_ERROR:
        print "Operations error"
        exit(1)
    except ldap.INVALID_CREDENTIALS:
        print "Wrong user name or password"
        exit(2)
    except ldap.SERVER_DOWN:
        print "Server unavailable"
        exit(3)
    for entry in rawSearch[0]:
        if isinstance(entry, dict):
            for key, value in entry.items():
                if key == "userPrincipalName":
                    split_userPrincipalName = value[0].split('@')
                    userPrincipalName = split_userPrincipalName[0]
                    return userPrincipalName
    ldap_client.unbind()

if __name__ == '__main__':

    try:
        str(sys.argv[1])
    except IndexError:
        print 'Error: Variable "USER_ID" was empty. Aborting.'
        usage()
        exit(1)

    try:
        str(sys.argv[2])
    except IndexError:
        print 'Error: Variable "VM_NAME" was empty. Aborting.'
        usage()
        exit(1)

    CUSTOMER_ID = sys.argv[1]
    VM_NAME = sys.argv[2]

    print 'Initial tests passed:'
    print '"USER_ID" is "%s"' % (CUSTOMER_ID)
    print '"VM_NAME" is "%s"' % (VM_NAME)
    if query_yes_no("Confirm: Are we ready for takeoff?") == False:
        print 'Manual VPS Deletion sequence aborted for user "%s" on VM "%s"' % (CUSTOMER_ID,VM_NAME)
        exit(1)

    cc = CreateClass()
    dc = DestroyClass()

    HOSTNAME = dc.GetHostname(VM_NAME)
    ALIAS = VM_NAME + '.vps.slu.se'

    logging.debug('Manual VPS Deletion sequence started for user "%s" on VM "%s"' % (CUSTOMER_ID,VM_NAME))
    print 'Manual VPS Deletion sequence started for user "%s" on VM "%s"' % (CUSTOMER_ID,VM_NAME)

    if not api.vms.get(VM_NAME):
        if not api.vms.get(VM_NAME.lower()):
            logging.debug('Error: VM "%s" does not exist' % (VM_NAME.lower()))
            print 'Error: VM "%s" does not exist' % (VM_NAME.lower())
            exit(1)
        else:
            VM_NAME = VM_NAME.lower()
    else:
        print 'Found matching VM registered in oVirt: "%s". Proceeding.' % (VM_NAME)

    try:
        print 'Getting userPrincipalName from USER_ID'
        PRINCIPAL_NAME = findUserPrincipal(CUSTOMER_ID)
    except Exception as e:
        print 'Failed to find userPrincipalName.'
        print e
        exit(1)

    if not PRINCIPAL_NAME:
        print 'Failed to find userPrincipalName.'
        exit(1)

    try:
        for USER_LIST_OBJECT in api.users.list(query='*'):
            try:
                USER_OBJECT_ID = USER_LIST_OBJECT.get_id()
                USER_EMAIL_ADDRESS = api.users.get(id='%s' % (USER_OBJECT_ID)).get_email()
                SPLIT_EMAIL_ADDRESS = USER_EMAIL_ADDRESS.split("@")[0]
                if SPLIT_EMAIL_ADDRESS == PRINCIPAL_NAME:
                    user = SPLIT_EMAIL_ADDRESS
                    logging.debug('Found matching user name registered in oVirt: "%s". Proceeding.' % (user))
                    print 'Found matching user name registered in oVirt: "%s". Proceeding.' % (user)
            except AttributeError:
                pass
        try:
            if not user:
                pass
        except NameError:
            logging.debug('User name is not registered in oVirt: "%s". Aborting.' % (CUSTOMER_ID))
            print 'User name is not registered in oVirt: "%s". Aborting.' % (CUSTOMER_ID)
            exit(1)
    except Exception as e:
        logging.debug('Unhandled exception:\n%s' % str(e))
        print 'Unhandled exception:\n%s' % str(e)
        exit(1)

    try:
        for VM_PERMISSIONS_LIST_OBJECT in api.vms.get(VM_NAME).permissions.list():
            try:
                USER_NAME_ID = VM_PERMISSIONS_LIST_OBJECT.get_user().get_id()
                USER_EMAIL_ADDRESS = api.users.get(id='%s' % (USER_NAME_ID)).get_email()
                SPLIT_EMAIL_ADDRESS = USER_EMAIL_ADDRESS.split("@")[0]
                if SPLIT_EMAIL_ADDRESS == PRINCIPAL_NAME:
                    owner = SPLIT_EMAIL_ADDRESS
                    logging.debug('Found matching user name in VM Permissions list: "%s". Proceeding.' % (owner))
                    print 'Found matching user name in VM ("%s") Permissions list: "%s". Proceeding.' % (VM_NAME, owner)
            except AttributeError:
                pass
        try:
            if not owner:
                pass
        except NameError:
            logging.debug('User name not found in VM Permissions list: "%s". Aborting.' % (CUSTOMER_ID))
            print 'User name not found in VM ("%s") Permissions list: "%s". Aborting.' % (VM_NAME, CUSTOMER_ID)
            exit(1)
    except Exception as e:
        logging.debug('Unhandled exception:\n%s' % str(e))
        print 'Unhandled exception:\n%s' % str(e)
        exit(1)

    try:
        print 'Checking if VM is started so it can be reached over the network'
        cc.StartVM(VM_NAME)
    except Exception as e:
        logging.debug('Failed to Start VM:\n%s' % str(e))
        print 'Failed to Start VM:\n%s' % str(e)
        exit(1)

    try:
        logging.debug('Trying to reach VM over the network')
        print 'Trying to reach VM over the network'
        host = subprocess.Popen(['/usr/bin/host', ALIAS], stdout=subprocess.PIPE).communicate()[0]
        while not re.search('has address', host):
            time.sleep(1)
            host = subprocess.Popen(['/usr/bin/host', ALIAS], stdout=subprocess.PIPE).communicate()[0]
    except Exception as e:
        logging.debug('Failed to reach VM over the network:\n%s' % str(e))
        print 'Failed to reach VM over the network:\n%s' % str(e)
        exit(1)

    try:
        host = subprocess.Popen(['/usr/bin/host', ALIAS], stdout=subprocess.PIPE).communicate()[0]
        if re.search('%s is an alias for %s' % (ALIAS,HOSTNAME), host):
            logging.debug('Alias "%s" is registered in DNS. De-registering alias.' % (ALIAS))
            print 'Alias "%s" is registered in DNS. De-registering alias.' % (ALIAS)
            try:
                dc.SendAliasDeregistration(CUSTOMER_ID, VM_NAME, HOSTNAME)
            except Exception as e:
                logging.debug('Failed to send alias de-registration email to domainmaster:\n%s' % str(e))
                print 'Failed to send alias de-registration email to domainmaster:\n%s' % str(e)
                exit(1)
        else:
            logging.debug('Alias name "%s" not found in DNS. De-registering real DNS record instead.' % (ALIAS))
            print 'Alias name "%s" not found in DNS. De-registering real DNS record instead.' % (ALIAS)
            try:
                dc.DeRegisterAddress(VM_NAME)
            except Exception as e:
                logging.debug('Failed to de-register domain name "%s.vps.slu.se":\n%s' % VM_NAME,str(e))
                print 'Failed to de-register domain name "%s.vps.slu.se":\n%s' % VM_NAME,str(e)
                exit(1)
    except Exception as e:
        logging.debug('Unhandled exception:\n%s' % str(e))
        print 'Unhandled exception:\n%s' % str(e)
        exit(1)

    try:
        print 'Trying to remove the user as owner of the VM'
        dc.RemoveOwner(CUSTOMER_ID, HOSTNAME, VM_NAME)
    except Exception as e:
        logging.debug('Failed to remove user as owner:\n%s'  % str(e))
        print 'Failed to remove user as owner:\n%s'  % str(e)
        exit(1)

    try:
        print 'Trying to delete VM'
        dc.deleteVM(VM_NAME)
    except Exception as e:
        logging.debug('Failed to delete VM:\n%s' % str(e))
        print 'Failed to delete VM:\n%s' % str(e)
        exit(1)

    logging.debug('Manual VPS Deletion sequence complete for user "%s" on VM "%s"' % (CUSTOMER_ID,VM_NAME))
    print 'Manual VPS Deletion sequence complete for user "%s" on VM "%s"' % (CUSTOMER_ID,VM_NAME)

