#!/usr/bin/python
# -*- coding: UTF-8 -*-
import traceback
from json.decoder import JSONDecodeError
from utils.common.exception import HCCIException
import utils.common.log as logger
from plugins.DistributedStorage.common.RestClient import RestClient
from plugins.DistributedStorage.common.ResponseParse import ResponseParse


def singleton_with_ip(cls):
    _instance = {}

    def _singleton(*args, **kargs):
        float_ip = args[0].get("float_ip")
        if float_ip not in _instance:
            _instance_node = dict()
            _instance_node[cls] = cls(*args, **kargs)
            _instance[float_ip] = _instance_node
        else:
            if cls not in _instance[float_ip]:
                _instance[float_ip][cls] = cls(*args, **kargs)
        return _instance[float_ip][cls]
    return _singleton


@singleton_with_ip
class UpgradeOperate(object):
    def __init__(self, fs_info):
        self.float_ip = fs_info.get("float_ip")
        self.port = fs_info.get("port")
        self.rest_client = RestClient(self.float_ip, self.port)
        self.sys_esn = None
        self.https = "https://"

    def try_login(self, username, password):
        ret_result, ret_data = self.get_session()
        logger.info("current session(%s, %s)" % (ret_result, ret_data))
        if ret_result["code"] != 0:
            return self.login(username, password)
        for resp in ret_data:
            if resp["status"] != '1':
                return self.login(username, password)
        return 200, 0, ""

    def login(self, username, password):
        res = []
        try:
            res = self.rest_client.login(username, password)
            result = ResponseParse(res)
            status_code, error_code, error_des = result.get_res_code()
            if status_code == 200 and error_code == 0:
                token = result.get_login_token()
                self.sys_esn = result.get_system_esn()
                self.rest_client.set_cookie(token)
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621001, str(e))
        return status_code, error_code, error_des

    def logout(self):
        res = []
        uri = '/api/v2/aa/sessions?is_timeout=false'
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'delete')
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except Exception as exc:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            logger.error("logout failed, exc: {}".format(exc))
            return {"code": "-1"}, {}
        return ret_result, ret_data

    def get_session(self):
        res = []
        uri = '/api/v2/aa/current_session'
        url = self.https + self.float_ip + ":" + self.port + uri
        res = []
        try:
            res = self.rest_client.normal_request(url, 'get')
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except Exception as exc:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            logger.error("get_session failed, exc: {}".format(exc))
            return {"code": "-1"}, {}
        return ret_result, ret_data

    def package_validaty(self, package_name, package_size):
        res = []
        uri = "/api/v2/upgrade/upgrade_package_validaty"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {
            "package_name": package_name,
            "package_size": package_size
            }
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type, details: {}".format(str(res)))
        except Exception as e:
            logger.error(str(res))
            logger.error(traceback.format_exc())
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_upg_mode(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_mode"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: {}".format(str(res)))
        except Exception as e:
            logger.error(str(res))
            logger.error(traceback.format_exc())
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def set_upg_mode(self, mode="2"):
        res = []
        uri = "/api/v2/upgrade/upgrade_mode"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {
            "upgrade_mode": mode
            }
        try:
            res = self.rest_client.normal_request(url, 'put', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def upload_upg_pkg(self, pkg_path):
        res = []
        uri = "/api/v2/upgrade/upgrade_packages"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.upload_tar_request_stream(
                url, 'post', pkg_path)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def query_upg_pkg(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_packages"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(
                url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def del_upg_pkg(self, package_id):
        res = []
        uri = "/api/v2/upgrade/upgrade_packages?id=%s" % package_id
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(
                url, 'delete')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def pre_check(self):
        res = []
        uri = "/api/v2/upgrade/precheck"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_pre_check_status(self):
        res = []
        uri = "/api/v2/upgrade/precheck_status"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def upgrade_task(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_task"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_upgrade_task(self):
        res = []
        uri = "/api/v2/upgrade/task"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_upgrade_status(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_status"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def post_check(self):
        res = []
        uri = "/api/v2/upgrade/postcheck"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_post_check_result(self):
        res = []
        uri = "/api/v2/deploy_manager/micro_service_postcheck_result"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def retry_upgrade_task(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_retry_task"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def rollback_upgrade_task(self):
        res = []
        uri = "/api/v2/upgrade/rollback_task"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def upgrade_confirm(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_confirm"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_alarm(self, filter):
        res = []
        uri = "/api/v2/common/alarms" + "?filter=" + filter
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_alarm_count(self, filter=None):
        res = []
        if not filter:
            uri = "/api/v2/common/alarm_count"
        else:
            uri = "/api/v2/common/alarm_count" + "?filter=" + filter
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_storage_pool(self):
        res = []
        uri = "/dsware/service/v1.3/storagePool"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_result_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: %s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_node_disk(self, pool_id):
        res = []
        uri = "/dsware/service/cluster/storagepool/queryNodeDiskInfo" \
              "?poolId={}".format(pool_id)
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_result_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type, details: %s" % str(res))
        except Exception as e:
            logger.error(str(res))
            logger.error(traceback.format_exc())
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def start_inspection(self, nodes_list, inspections_list):
        res = []
        uri = "/api/v2/cluster/inspection"
        url = self.https + self.float_ip + ":" + self.port + uri
        data = {"items": inspections_list, "nodes": nodes_list}
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: {}".format(str(res)))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_inspection_status(self, task_id, inspections_list):
        res = []
        uri = "/api/v2/cluster/inspection/"
        url = self.https + self.float_ip + ":" + self.port + uri + task_id
        data = {
            "items": inspections_list
            }
        try:
            res = self.rest_client.normal_request(url, 'post', data)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_disk(self):
        res = []
        uri = "/dsware/service/v1.3/server/list"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_result_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_servers(self):
        res = []
        uri = "/api/v2/cluster/servers"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_pmi_resource(self, res_file):
        res = []
        uri = "/api/v2/cluster/resource_files" + "?resource_type=inspection"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.download_request(url, res_file)
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_download_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_product(self):
        res = []
        url = self.https + self.float_ip + ":" + self.port + "/api/v2/cluster/product"
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: {}".format(str(res)))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def download_inspection_result(self, task_id, res_file, item_id, node_ip):
        res = []
        uri = "/api/v2/cluster/inspection/" + task_id + "?item_id=" + item_id + "&node_ip=" + node_ip
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.download_request(url, res_file)
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_download_data()
        except JSONDecodeError:
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_upgrade_packages(self):
        res = []
        uri = "/api/v2/upgrade/upgrade_packages"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_esn(self):
        res = []
        uri = "/api/v2/common/esn"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def get_version(self):
        res = []
        uri = "/api/v2/cluster/product"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, 'get')
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                       "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data

    def handle_ignore_host(self, params=None, method="get"):
        res = []
        uri = "/api/v2/upgrade/ignorehosts"
        url = self.https + self.float_ip + ":" + self.port + uri
        try:
            res = self.rest_client.normal_request(url, method, data=params)
            logger.info(res.json())
            result = ResponseParse(res)
            _, ret_result, ret_data = result.get_rsp_data()
        except JSONDecodeError:
            logger.error(str(res))
            raise HCCIException(621004, "Response is not json type: "
                                        "%s" % str(res))
        except Exception as e:
            logger.error(traceback.format_exc())
            logger.error(str(res))
            raise HCCIException(621004, str(e))
        return ret_result, ret_data
