# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description  : expansion_impl_with_cm_local.py
#############################################################################

import os
import subprocess

from gspylib.common.Common import DefaultValue
from impl.expansion.expansion_impl_with_cm import ExpansionImplWithCm, change_user_executor


class ExpansionImplWithCmLocal(ExpansionImplWithCm):
    """
    This is expand subclass for add node with CM component
    """
    def __init__(self, expansion):
        super(ExpansionImplWithCmLocal, self).__init__(expansion)

    def _get_local_node_cluster_commit_id(self):
        """
        Get local node version
        """
        self.logger.log("Start get commit ID on local host.")
        # gp_home = self.context.clusterInfoDict["toolPath"]
        # version_file = os.path.realpath(os.path.join(gp_home, "version.cfg"))
        gsql_cmd = "source {0} ; gsql -V".format(self.envFile)
        status, output = subprocess.getstatusoutput(gsql_cmd)
        if status != 0 or not output.strip():
            self.logger.error("Gsql command error: {0}".format(output))
            raise Exception("Current node gsql command failed. {0}".format(output))
        self.logger.debug("Get current node gsql command successfully. "
                          "output is : {0}".format(output))
        # gsql version display like (gsql (openGauss x.x.0 build xxxxxxx)
        # compiled at 2029-02-26 02:07:00 commit 0 last mr xxxx)
        commit_id = output.strip().split(")")[0].split()[-1]
        self.logger.log("Current commit ID is : {0}".format(commit_id))
        return commit_id

    def _get_remote_node_commit_id(self):
        """
        Get local node version
        """
        self.logger.log("Start get commit ID on remote host.")
        # gp_home = self.context.clusterInfoDict["toolPath"]
        # version_file = os.path.realpath(os.path.join(gp_home, "version.cfg"))
        gsql_cmd = "source {0} ; gsql -V".format(self.envFile)
        result_map, output_collect = \
            self.ssh_tool.getSshStatusOutput(gsql_cmd,
                                             hostList=self.get_node_names(self.new_nodes))

        self.logger.debug("Check remote nodes commit ID , "
                          "result_map is : {0}".format(result_map))
        self.logger.debug("Check remote nodes commit ID , "
                          "output_collect is : {0}".format(output_collect))
        if DefaultValue.FAILURE in result_map.values():
            self.logger.error("Get commit ID on remote node failed. output: "
                              "{0}".format(result_map))
            raise Exception("Get commit ID on remote node failed. output: {0}".format(result_map))
        result_dict = self._parse_ssh_tool_output_collect(output_collect)
        if len(list(set(result_dict.values()))) != 1:
            self.logger.debug("The database version on the remote node is inconsistent. "
                              "result {0}".format(result_dict))
            raise Exception("The database version on the remote node is inconsistent.")
        self.logger.debug("result dict is : {0}".format(result_dict))
        return list(result_dict.values())[0]

    def check_remote_host_cluster_version(self):
        """
        Check remote node cluster version.
        """
        current_commit_id = self._get_local_node_cluster_commit_id()
        remote_commit_id = self._get_remote_node_commit_id()
        if current_commit_id != remote_commit_id:
            self.logger.error("The commit ID [{0}] of the new node is "
                              "inconsistent with the local ID "
                              "[{1}].".format(remote_commit_id, current_commit_id))
            raise Exception("The commit ID [{0}] of the new node is "
                            "inconsistent with the local ID "
                            "[{1}].".format(remote_commit_id, current_commit_id))

    def check_remote_host_cm_component(self):
        """
        Check remote node is contain CM component.
        """
        self.logger.log("Start check CM component on remote node.")
        for new_node in self.new_nodes:
            cm_agent_conf = os.path.realpath(os.path.join(new_node.cmagents[0].datadir,
                                                          "cm_agent.conf"))
            cmd = "ls {0} | wc -l".format(cm_agent_conf)
            _, output_collect = self.ssh_tool.getSshStatusOutput(cmd, hostList=[new_node.name])
            result_dict = self._parse_ssh_tool_output_collect(output_collect)
            if new_node.name not in result_dict.keys():
                self.logger.error("Check remote node [{0}] cm_agent.conf failed. "
                                  "output: {1}".format(new_node.name, result_dict))
                raise Exception("Check remote node [{0}] cm_agent.conf failed. "
                                  "output: {1}".format(new_node.name, result_dict))
            if result_dict.get(new_node.name) != '1':
                self.logger.error("Check remote node [{0}] result failed. "
                                  "output: {1}".format(new_node.name, result_dict))
                raise Exception("Check remote node [{0}] result failed. "
                                "output: {1}".format(new_node.name, result_dict))
            self.logger.log("Check cm_agent.conf on node [{0}] "
                            "successfully.".format(new_node.name))
        self.logger.log("Check remote node CM compent successfully.")

    def expansion_check(self):
        """
        Check cluster for expansion local mode
        """
        self.checkUserAndGroupExists()
        self.checkXmlFileAccessToUser()
        self.checkClusterStatus()
        self.validNodeInStandbyList()
        self.check_remote_host_cluster_version()
        self.check_remote_host_cm_component()

    def do_config(self, p_value):
        """
        Config instance on new nodes
        """
        self._change_user_without_root()
        self._config_instance()
        if DefaultValue.is_create_grpc(self.logger,
                                       self.static_cluster_info.appPath):
            self.logger.log("Generate GRPC cert file.")
            self.generateGRPCCert()
        p_value.value = 1

    def run(self):
        """
        This is class enter.
        """
        self.sendSoftToHosts(send_pkg=False)
        self.send_xml()
        self.expansion_check()
        self._set_expansion_success()
        change_user_executor(self.do_config)
        change_user_executor(self.do_start)
        change_user_executor(self.check_tblspc_directory)
        self.check_new_node_state(True)
