#!/usr/bin/python
import logging, time
from signal import alarm, signal, SIGALRM, SIGKILL
from subprocess import PIPE, Popen
import os, string, tempfile
from optparse import OptionParser
from urlparse import urlparse

import paramiko
import MySQLdb


keyfile = "/etc/cloudstack/management/key"
dbprop = "/etc/cloudstack/management/db.properties"
logFile = "/usr/share/cloudstack-management/patch.log"



class bash:
    def __init__(self, args, timeout=600):
        self.args = args
        # logging.debug("execute:%s" % args)
        self.timeout = timeout
        self.process = None
        self.success = False
        self.run()

    def run(self):
        class Alarm(Exception):
            pass

        def alarm_handler(signum, frame):
            raise Alarm

        try:
            self.process = Popen(self.args, shell=True, stdout=PIPE, stderr=PIPE)
            if self.timeout != -1:
                signal(SIGALRM, alarm_handler)
                alarm(self.timeout)

            try:
                self.stdout, self.stderr = self.process.communicate()
                if self.timeout != -1:
                    alarm(0)
            except Alarm:
                os.kill(self.process.pid, SIGKILL)

            self.success = self.process.returncode == 0
        except:
            pass

        if not self.success:
            logging.debug("Failed to execute:" + self.getErrMsg())

    def isSuccess(self):
        return self.success

    def getStdout(self):
        return self.stdout.strip("\n")

    def getLines(self):
        return self.stdout.split("\n")

    def getStderr(self):
        return self.stderr.strip("\n")

    def getErrMsg(self):
        if self.isSuccess():
            return ""

        if self.getStderr() is None or self.getStderr() == "":
            return self.getStdout()
        else:
            return self.getStderr()


def initLoging(logFile=None):
    try:
        if logFile is None:
            logging.basicConfig(level=logging.DEBUG)
        else:
            logging.basicConfig(filename=logFile, level=logging.DEBUG)
    except:
        logging.basicConfig(level=logging.DEBUG)


class remoteSSHClient(object):
    def __init__(self, host, port, user, passwd):
        self.host = host
        self.port = port
        self.user = user
        self.passwd = passwd
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        retries = 5
        try:
            for x in range(retries):
                logging.debug("Trying to connect %s" % (str(host)))
                self.ssh.connect(str(host), int(port), user, passwd)
                print "SUCCESS: Acquired connection to host %s successfully - PASS" % (str(host))
                logging.debug("Connected to %s" % (str(host)))
                break
        except paramiko.SSHException, sshex:
            print "ERROR: Connection to host %s - FAILED" % (str(host))
            logging.debug(repr(sshex))

    def execute(self, command):
        stdin, stdout, stderr = self.ssh.exec_command(command)
        output = stdout.readlines()
        errors = stderr.readlines()
        results = []
        if output is not None and len(output) == 0:
            if errors is not None and len(errors) > 0:
                for error in errors:
                    results.append(error.rstrip())

        else:
            for strOut in output:
                results.append(strOut.rstrip())

        return results

    def scp(self, srcFile, destPath):
        transport = paramiko.Transport((self.host, int(self.port)))
        transport.connect(username=self.user, password=self.passwd)
        sftp = paramiko.SFTPClient.from_transport(transport)
        try:
            sftp.put(srcFile, destPath)
            sftp.chmod(destPath, os.stat(srcFile).st_mode & 0777)
            print "SUCCESS: Copied changes to host successfully - PASS"
        except IOError, e:
            print "ERROR: Copied changes to host  - FAILED"
            raise e



def copyScriptToHost(hostip, username, passwd, script, destPath, cursor, hostid):
    logging.debug("Copying into %s with user: %s" % (hostip, username))
    sshClient = remoteSSHClient(hostip, "22", username, passwd)
    sshClient.scp(script, destPath)


def decrypt_password(enc_passwd, key):
    command = "java -classpath /usr/share/cloudstack-common/lib/jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI decrypt.sh input=%s password=%s verbose=false" % (
        enc_passwd, key)
    bash_cmd = bash(command)
    res = bash_cmd.getStdout()
    return res


if __name__ == '__main__':
    initLoging(logFile)
    with open(keyfile) as keys:
        key = keys.readline().strip("\n")
    keys.close()

    with open(dbprop) as dbprops:
        propsval = dbprops.readlines()
        for value in propsval:
            if value.split('=', 1)[0] == "db.cloud.host":
                db = value.split('=', 1)[-1].strip()
            if value.split('=', 1)[0] == "db.cloud.username":
                dbUsr = value.split('=', 1)[-1].strip()
            if value.split('=', 1)[0] == "db.usage.password":
                dbPasswd = value.split('=', 1)[-1].strip()[4:-1]
            if value.split('=', 1)[0] == "db.cloud.encrypt.secret":
                dbkey = decrypt_password(value.split('=', 1)[-1].strip()[4:-1],key)
    dbprops.close()

    if key is None or key == "":
        key = raw_input("Please enter Decryption Key: ")

    if db is None:
        logging.debug("unable to read db server details")
        os.sys.exit()

    if dbUsr is None:
        options.dbUsr = "cloud"

    if dbPasswd is None:
        options.dbPasswd = ""
    else:
        dbPasswd = decrypt_password(dbPasswd, key)

    try:
        db = MySQLdb.connect(db, dbUsr, dbPasswd, "cloud")
    except:
        logging.debug("Can't not connect to clouddb.Check hostname/credentials")
        os.sys.exit()
    c = db.cursor()

    c.execute("select version from version where id=(select MAX(id) from version)")
    result = c.fetchall()
    for ver in result:
        version = ver[0]

    c.execute("select id from data_center")
    result = c.fetchall()

    for dc in result:
        dcId = dc[0]
        c.execute(
            'select hypervisor_type,private_ip_address,id from host where removed is null and type = "Routing" and data_center_id = %s',
            (dcId,))
        hosts = c.fetchall()

        logging.debug("Found following routing hosts to execute on data center id - %s" % dcId)
        logging.debug(hosts)

        for host in hosts:
            if host[0] == "VMware":
                c.execute(
                    'select url from image_store where data_center_id = %s and protocol = "nfs" and removed IS NULL',
                    (dcId,))
                nfs_list = c.fetchall()
                mount_point = tempfile.mkdtemp(dir = "/tmp")
                command = "mkdir -p %s" % (mount_point)
                bash_cmd = bash(command)
                res = bash_cmd.getStderr()
                for nfs in nfs_list:
                    nfs_url = nfs[0][6:]
                    nfs_host = nfs_url.split('/', 1)[0]
                    nfs_path = nfs_url.split('/', 1)[1]
                    command = "mount -t nfs %s:/%s %s" % (nfs_host, nfs_path, mount_point)
                    bash_cmd = bash(command)
                    res = bash_cmd.getStderr()
                    if res != "":
                        print "ERROR: %s" % res
                        continue
                    else:
                        print "SUCCESS: Mounted secondary storage - %s successfully - PASS" % (nfs_url)
                    command = "rm -rf %s/systemvm/systemvm*.iso" % (mount_point)
                    bash_cmd = bash(command)
                    res = bash_cmd.getStderr()
                    print "SUCCESS: Cleaned up systemvm.iso successfully - PASS"
                    command = "/bin/cp -rf /usr/share/cloudstack-common/vms/systemvm.iso %s/systemvm/systemvm-%s.iso" % (
                    mount_point, version)
                    bash_cmd = bash(command)
                    res = bash_cmd.getStderr()
                    if res != "":
                        print "ERROR: %s" % res
                        continue
                    else:
                        print "SUCCESS: Copied the systemvm.iso successfully - PASS"
                    command = "umount %s" % (mount_point)
                    bash_cmd = bash(command)
                    res = bash_cmd.getStderr()
                command = "rm -rf %s" % (mount_point)
                bash_cmd = bash(command)
                res = bash_cmd.getStderr()
            c.execute("""select value from host_details where host_id=%s \
                                        and name="username" """, (host[2],))
            userName = c.fetchone()[0]
            c.execute("""select value from host_details where host_id=%s \
                                        and name="password" """, (host[2],))
            enc_password = c.fetchone()[0]
            password = decrypt_password(enc_password, dbkey)

            if host[0] == "XenServer":
                command = "rm -rf /opt/xensource/packages/iso/systemvm.iso"
                sshClient = remoteSSHClient(host[1], "22", userName, password)
                sshClient.execute(command)
                print "SUCCESS: Cleaned up systemvm.iso on Xenserver host - %s successfully - PASS" %(host[1])
                sshClient.scp("/usr/share/cloudstack-common/vms/systemvm.iso", "/opt/xensource/packages/iso/systemvm.iso")
                print "SUCCESS: copied systemvm iso to Xenserver host - %s successfully - PASS" %(host[1] )

            if host[0] == "KVM":
                command = "rm -rf /usr/share/cloudstack-common/vms/systemvm.iso"
                sshClient = remoteSSHClient(host[1], "22", userName, password)
                sshClient.execute(command)
                print "SUCCESS: Cleaned up systemvm.iso on KVM host - %s successfully - PASS" %(host[1])
                sshClient.scp("/usr/share/cloudstack-common/vms/systemvm.iso", "/usr/share/cloudstack-common/vms/systemvm.iso")
                print "SUCCESS: copied systemvm iso to KVM host - %s successfully - PASS" %(host[1] )

    print "Completed systemvm iso update"

