# -*- coding:utf-8 -*-
import requests
import sys
import os
import logging
import base64
from FSSysconf import netPolicyParse
#from FSSecurity.crypt import decrypt
logger = logging.getLogger('__EBACKUP_CONFIG__')
logger.setLevel(level=logging.DEBUG)
logger.propagate = False
logger.handlers = []

log_file_path = os.path.abspath(__file__ + '/../dmk_driver.log')
if not os.path.isfile(log_file_path):
    os.mknod(log_file_path)

handler = logging.FileHandler(log_file_path)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [%(levelname)s] at %(filename)s,%(lineno)d: %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# handler = logging.StreamHandler(sys.stdout)
# handler.setLevel(logging.INFO)
# formatter = logging.Formatter('%(message)s')
# handler.setFormatter(formatter)
# logger.addHandler(handler)

VALID_VOLUME_DRIVER = ['cinder.volume.drivers.dsware.HuaweiDswareDriver',
                       'cinder.volume.drivers.huawei.vrm.vrm_driver.VRMDriver',
                       'cinder.volume.drivers.huawei.HuaweiISCSIDriver']
global CPS_BASE_URL
def get_cps_server_base_url():
    base_url = ""
    try:
        floating_ip = netPolicyParse.getComponentFloatingIp(compName="cps-server")
        floating_port = netPolicyParse.getComponentFloatingPort(compName="cps-server")
        if floating_ip.find(":") > 0:
            base_url = '[' + floating_ip + ']' + ":" + floating_port
        else:
            base_url = floating_ip + ":" + floating_port
        logger.info("Get base url by interface: %s" % base_url)
        return base_url.replace(' ', '')
    except Exception as e:
        logger.info("not found cps-server maybe it's cascaded %s!" % e)
        file_path = "/etc/huawei/fusionsphere/cfg/serverIp.ini"
        if os.path.exists(file_path):
            fp = open(file_path, 'r')
            print('use config file : %s' % fp)
            while True:
                line = fp.readline().strip('\n')
                if not line:
                    break
                key_value = line.split("=")
                if key_value[0].strip() == 'serverip':
                    base_url = key_value[1].strip()
                    base_url = base_url.replace("https://", "")
                    logger.info("Get base url from serverIP.ini: %s" % base_url)
            fp.close()
            return base_url.replace(' ', '')
        else:
            logger.error(file_path + "is not existed.")
            return ""
   
def get_cinder_backup_templates(cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to query all cinder backup template.")
        cinder_backup_templates = []
        url = "https://%s/cps/v1/services/all/componenttemplates?commit_state=commited" % CPS_BASE_URL
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }

        rsp = requests.get(url=url, headers=header, verify=False)
        if rsp.status_code == 200:
            rsp_dict = rsp.json()
            for service in rsp_dict["templates"]:
                if -1 == service["name"].find("cinder-backup"):
                    continue
                cinder_backup_templates.append(service["name"])
        else:
            logger.error("Response status code is not 200.The url is" + url)
            raise Exception("Response status code is not 200.")
        if 0 == len(cinder_backup_templates):
            logger.debug("There is no cinder backup template.")
            return True, []
        logger.info("Query all cinder backup template successfully.")
        return True, cinder_backup_templates
    except Exception as e:
        logger.error("Query all cinder backup template failed.The reason is " + str(e))
        return False, []


def get_supported_backup_templates(cinder_backup_templates, cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to query supported backup template.")
        supported_templates = []
        m_url = "https://%s/cps/v1/services/cinder/componenttemplates/EACH_TEMPLATE/params?commit_state=commited" % CPS_BASE_URL
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }
        for template in cinder_backup_templates:
            logger.info('start check template %s' % template)
            url = m_url.replace("EACH_TEMPLATE", template)
            logger.debug("The url is " + url)
            rsp = requests.get(url=url, headers=header, verify=False)
            if rsp.status_code == 200:
                template_params = rsp.json()["cfg"]
                volume_driver = template_params.get('volume_driver', '')
                other_storage_cfg = template_params.get('other_storage_cfg', '')
                logger.debug('volume_driver: %s' % volume_driver)
                logger.debug('other_storage_cfg: %s' % other_storage_cfg)
                valid_volume_driver = VALID_VOLUME_DRIVER
                other_volume_driver = ''
                if other_storage_cfg:
                    for poolid, poollist in other_storage_cfg.items():
                        for cfgkey, poolcfg in poollist.items():
                            if poolcfg.get('volume_driver', ''):
                                other_volume_driver = poolcfg.get('volume_driver', '')
                logger.debug('other_volume_driver: %s' % other_volume_driver)
                if volume_driver in valid_volume_driver or (other_volume_driver in valid_volume_driver):
                    supported_templates.append(template)
                else:
                    logger.debug('There is not valid volume driver %s in template %s' % (volume_driver,template) )
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")
        if 0 == len(supported_templates):
            logger.error("There are no supported templates.")
            return False, []
        logger.info("The supported templates are: " + str(supported_templates))
        return True, supported_templates
    except Exception as e:
        logger.error("Query supported template failed,the reason is " + str(e))
        return False, []


def get_supported_role(supported_templates):
    supported_role = []
    for template in supported_templates:
        try:
            temp = template.split('-')
            if len(temp) > 2:
                supported_role.append("blockstorage-driver-" + temp[2])
            else:
                supported_role.append("blockstorage-driver")
        except Exception as e:
            logger.info("An exception occurred when get supported role.The exception is " + str(e))
    return supported_role


def get_ebackup_driver_node(supported_role, cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to query eBackup driver node by supported role.")
        url = "https://%s/cps/v1/hosts" % CPS_BASE_URL
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }
        ebackup_driver_nodes = []
        rsp = requests.get(url=url, headers=header, verify=False)
        if rsp.status_code == 200:
            host_dict = rsp.json()
            for host in host_dict["hosts"]:
                omip = host["omip"]
                if omip is not None and omip != '':
                    roles = str(host["roles"])
                    logger.debug("The roles of host(%s) are:%s" % (omip, str(roles)))
                    for role in supported_role:
                        if role in roles:
                            ebackup_driver_nodes.append(omip)
                            break
        else:
            logger.error("Response status code is not 200.The url is" + url)
            raise Exception("Response status code is not 200.")
        logger.info("Query eBackup driver successfully.The eBackup driver nodes are "
                    + str(ebackup_driver_nodes))
        if 0 == len(ebackup_driver_nodes):
            logger.error("There is no ebackup driver node.")
            return False, []
        logger.info("Query eBackup driver node successfully.The eBackup driver node are:" + str(ebackup_driver_nodes))
        return True, ebackup_driver_nodes
    except Exception as e:
        logger.error("Query eBackup driver node failed,the reason is " + str(e))
        return False, []


def get_ebackup_driver_node2(supported_templates, cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to query eBackup driver node by supported template.")
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }
        ebackup_driver_nodes = []
        for template in supported_templates:
            url = "https://%s/cps/v1/instances?service=cinder&template=%s" % (CPS_BASE_URL, template)
            rsp = requests.get(url=url, headers=header, verify=False)
            if rsp.status_code == 200:
                instance_list = rsp.json()["instances"]
                for host in instance_list:
                    omip = host["omip"]
                    if omip is not None and omip != '' and omip not in ebackup_driver_nodes:
                        ebackup_driver_nodes.append(omip)
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")

        if 0 == len(ebackup_driver_nodes):
            logger.error("There is no ebackup driver node.")
            return False, []
        logger.info("Query eBackup driver node successfully.The eBackup driver node are:" + str(ebackup_driver_nodes))
        return True, ebackup_driver_nodes
    except Exception as e:
        logger.error("Query eBackup driver node failed,the reason is " + str(e))
        return False, []


def get_cps_server_node(cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to query cps server nodes.")
        url = "https://%s/cps/v1/instances?service=cps-server&template=cps-server" % CPS_BASE_URL
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }
        cps_server = []
        rsp = requests.get(url=url, headers=header, verify=False)

        if rsp.status_code == 200:
            rsp_dict = rsp.json()
            for cps in rsp_dict["instances"]:
                omip = cps["omip"]
                if omip is not None and omip != '':
                    cps_server.append(omip)
        else:
            logger.info("The cps-server service name is cps")
            url = "https://%s/cps/v1/instances?service=cps&template=cps-server" % CPS_BASE_URL
            rsp = requests.get(url=url, headers=header, verify=False)
            if rsp.status_code == 200:
                rsp_dict = rsp.json()
                for cps in rsp_dict["instances"]:
                    omip = cps["omip"]
                    if omip is not None and omip != '':
                        cps_server.append(omip)
            else:
                logger.error("Response status code is not 200.The url is" + url)
                raise Exception("Response status code is not 200.")
        if 0 == len(cps_server):
            logger.error("There is no cps server.")
            return False, []
        logger.info("Query cps server nodes successfully.The cps server are:" + str(cps_server))
        return True, cps_server
    except Exception as e:
        logger.error("Query cps server nodes failed,the reason is " + str(e))
        return False, []


def generate_host_file(operation, output_file, driver_host, cps_server=None):
    try:
        logger.info("Begin to generate host file")
        fp = open(output_file, 'w+')
        if operation == "upgrade":
            fp.write("[cpsnode]" + '\n')
            index = 1
            for ip in cps_server:
                fp.write("CpsServer%s ansible_ssh_host='%s'" % (str(index), ip) + '\n')
                index += 1
            fp.write("[eBackupDriver]" + '\n')
        elif operation == "install":
            fp.write("[FspBecascadeDriver]" + '\n')

        index = 1
        for ip in driver_host:
            fp.write("eBackupDriver%s ansible_ssh_host='%s'" % (str(index), ip) + '\n')
            index += 1
        fp.close()
        logger.info("Generate host file successfully!")
        return True
    except Exception as e:
        logger.info("Generate host file failed!")
        return False


def print_host_info(operation, driver_host, cps_server=None):
    try:
        logger.info("Begin to print host info")
        cps_host_string = ""
        cps_dict_string = ""
        if operation == "upgrade":
            for ip in cps_server:
                cps_host_string += '\"%s\", ' % ip
            cps_host_string = cps_host_string.strip().strip(",")
            cps_dict_string = '{"cpsnode":[%s]}' % cps_host_string
            print cps_dict_string
        logger.info(cps_dict_string)
        driver_host_string = ""
        for ip in driver_host:
            driver_host_string += '\"%s\", ' % ip
        driver_host_string = driver_host_string.strip().strip(",")
        driver_dict_string = '{"eBackupDriver":[%s]}' % driver_host_string
        logger.info(driver_dict_string)
        print str(driver_dict_string)
        logger.info("Print host info successfully!")
        return True
    except Exception as e:
        logger.info("Print host info failed!The reason is:" + str(e))
        return False


def check_cps_admin_password(cps_username, cps_password):
    global CPS_BASE_URL
    try:
        logger.info("Begin to check the password of the %s user." % cps_username)
        url = "https://%s/cps/v1/haproxylocalurl" % CPS_BASE_URL
        header = {
            "Content-Type": "application/json",
            "X-Auth-User": cps_username,
            "X-Auth-Password": cps_password
        }

        rsp = requests.get(url=url, headers=header, verify=False)
        if rsp.status_code == 200:
            rsp_dict = rsp.json()
            if -1 != str(rsp_dict).lower().find("failed"):
                logger.error("Authenticate Failed!")
                return False
        else:
            logger.error("Response status code is not 200.The url is" + url)
            raise Exception("Response status code is not 200.")

        logger.info(cps_username + "Authenticate successfully.")
        return True
    except Exception as e:
        logger.error("Authenticate Failed!The reason is: " + str(e))
        return False


if __name__ == "__main__":
    if sys.argv.__len__() != 4:
        logger.error("Parameter is Invalid.")
        print("ERROR: Parameter is Invalid.")
        exit(1)
    CPS_BASE_URL = get_cps_server_base_url()
    cps_username = sys.argv[1]
    cps_password = sys.argv[2]
    operation = sys.argv[3]
    try:
        cps_password = base64.b64decode(cps_password)
        is_true = check_cps_admin_password(cps_username, cps_password)
        if not is_true:
            logger.error("Check the password of the %s user failed." % cps_username)
            print("ERROR: Authenticate Failed!Please check the password of the %s user" % cps_username)
            exit(1)
    except Exception as e:
        logger.error("Decode the password of the cps_admin user failed.")
        print("ERROR: Decode the password of the cps_admin user failed.")
        exit(1)
    valid_operation = ["upgrade", "install", "query_role"]
    if operation not in valid_operation:
        logger.error("Operation is invalid.")
        print("ERROR: Operation is invalid.The valid operation are:" + str(valid_operation))
        exit(1)
    
    is_true, backup_templates = get_cinder_backup_templates(cps_username, cps_password)
    if not is_true:
        logger.error("Get cinder backup templates failed.")
        print("ERROR: Get cinder backup templates failed.")
        exit(1)
    if 0 == len(backup_templates):
        logger.debug("There is no supported cinder backup templates")
        print("DEBUG: Unsupported-eBackup.")
    is_true, supported_templates = get_supported_backup_templates(backup_templates, cps_username, cps_password)
    if not is_true:
        logger.error("Get cinder backup templates which support eBackup failed.")
        print("ERROR: Get cinder backup templates which support eBackup failed.")
        exit(1)
    supported_role = get_supported_role(supported_templates)
    if 0 == len(supported_role):
        logger.error("Get supported role failed.")
        print("ERROR: Get supported role failed.")
        exit(1)
    if operation == "query_role":
        print supported_role
        exit(0)
    else:
        # output_file = os.path.abspath(__file__ + '/../node_ip_for_driver')
        # if not os.path.isfile(output_file):
        #     os.mknod(output_file)
        #is_true, driver_nodes = get_ebackup_driver_node(supported_role, cps_username, cps_password)
        is_true, driver_nodes = get_ebackup_driver_node2(supported_templates, cps_username, cps_password)
        if 0 == len(driver_nodes):
            logger.error("Get ebackup driver node failed.")
            print("ERROR: Get ebackup driver node failed.")
            exit(1)
        if operation == "upgrade":
            is_true, cps_server = get_cps_server_node(cps_username, cps_password)
            if not is_true:
                logger.error("Get cps server failed.")
                print("ERROR: Get cps server failed.")
                exit(1)
            #is_true = generate_host_file(operation, output_file, driver_nodes, cps_server)
            is_true = print_host_info(operation, driver_nodes, cps_server)
            if not is_true:
                logger.error("Query driver nodes and cps server failed.")
                print("ERROR: Query driver nodes and cps server failed.")
                exit(1)
            exit(0)
        elif operation == "install":
            #is_true = generate_host_file(operation, output_file, driver_nodes, cps_server=None)
            is_true = print_host_info(operation, driver_nodes, cps_server=None)
            if not is_true:
                logger.error("Query driver nodes failed.")
                print("ERROR: Query driver nodes failed.")
                exit(1)
            exit(0)



