#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from typing import List

from installer.components.vrm.params import GLOBAL, PARAMS
from installer.components.local_info import LOCAL_INFO
from installer.constants.vrm import CREATE_IPTABLES_TASK
from installer.framework.error import ProcessError
from installer.framework.step import Step
from installer.rest.services import host as HostService
from installer.utils import log
from installer.utils.node import WaitTask, wait_task, open_sftp
from installer.utils.shell import run_cmd_status, RemoteClient
from installer.utils.file import copy_file, find_file, chown_file

VMTOOLS_RPM_DIR = "/opt/galax/patch/internal/vmtools"
VMTOOLS_RPM_CNA_DIR = "/opt/patch/programfiles/vmtools"


class VrmVirtualConfigHost(Step):

    def __init__(self, name: str):
        super().__init__(name, 'vrm')
        self.is_added_master = False
        self.is_added_slave = False
        self.cna_master_ip = ''
        self.cna_slave_ip = ''
        self.local_ip = ''

    def check_env(self):
        """
        检查环境
        """
        self.cna_master_ip = str(PARAMS.cna.master_ip)
        self.cna_slave_ip = str(PARAMS.cna.slave_ip)
        self.local_ip = str(LOCAL_INFO.ip)
        resp: HostService.QueryHostsResponse = HostService.query_hosts()
        for host in resp.hosts:
            if host.ip == self.cna_master_ip:
                self.is_added_master = True
                log.info("Master cna has been added.")
            elif host.ip == self.cna_slave_ip:
                self.is_added_slave = True
                log.info("Slave cna has been added.")

    def work(self):
        result = None
        for i in range(1, 3):
            # 串行添加主机
            # 因为添加主机时，会绑定主机管理IP，需要重启主机网络。此时同步添加备机，会需要主备通信，当访问不到主机时，会报错.
            if not self.is_added_master:
                # x86需要在主备主机上放置vmtools包
                if not LOCAL_INFO.is_arm():
                    self.sftp_files_to_host(self.cna_master_ip, PARAMS.cna.master_root_password)
                log.info("start add master cna")
                req: HostService.AddHostRequest = HostService.AddHostRequest()
                req.name = GLOBAL.master_cna_hostname
                req.clusterUrn = GLOBAL.cluster_urn
                req.ip = self.cna_master_ip
                req.rootPassword = PARAMS.cna.master_root_password
                master_resp: HostService.AddHostResponse = HostService.add_host(req)
                result = wait_task(WaitTask(master_resp.taskUrn, '300401', self.cna_master_ip))
                if not result.status:
                    log.warn("Conflict between adding host task and registering license service. "
                     "Retry adding host task after a 4-minute wait.")
                    time.sleep(240)
                    continue
                log.info("success for add master cna")
            if PARAMS.is_double() and not self.is_added_slave:
                # x86需要在主备主机上放置vmtools包
                if not LOCAL_INFO.is_arm():
                    self.sftp_files_to_host(self.cna_slave_ip, PARAMS.cna.slave_root_password)
                log.info("start add slave cna")
                req: HostService.AddHostRequest = HostService.AddHostRequest()
                req.clusterUrn = GLOBAL.cluster_urn
                req.name = GLOBAL.slave_cna_hostname
                req.ip = self.cna_slave_ip
                req.rootPassword = PARAMS.cna.slave_root_password
                slave_resp: HostService.AddHostResponse = HostService.add_host(req)
                result = wait_task(WaitTask(slave_resp.taskUrn, '300401', self.cna_slave_ip))
                if not result.status:
                    log.warn("Conflict between adding host task and registering license service. "
                     "Retry adding host task after a 4-minute wait.")
                    time.sleep(240)
                    continue
                log.info("success for add slave cna")
            break
        if result and not result.status:
            raise result.error
        log.info('Will update global data.')
        self.__update_global()

    def sftp_files_to_host(self, host_ip, root_pass) -> None:
        log.info(f'Copy the vmtools package to {host_ip} cna start')
        if self.local_ip == host_ip:
            status, file = find_file('uvp-vmtools-(.*).rpm', VMTOOLS_RPM_DIR)
            if not status:
                raise ProcessError('301605')
            copy_file(f'{VMTOOLS_RPM_DIR}/{file}', f'{VMTOOLS_RPM_CNA_DIR}/{file}')
            chown_file(f'{VMTOOLS_RPM_CNA_DIR}/{file}', 'root', 'root')
            log.info('Copy the vmtools package to local cna success')
        else:
            open_sftp(host_ip, root_pass)
            log.info(f'open {host_ip} cna sftp success')
            remote_client = RemoteClient(host_ip, 'root', root_pass)
            if not remote_client.sftp_dir(VMTOOLS_RPM_DIR, VMTOOLS_RPM_CNA_DIR):
                log.error(f'Failed to upload the vmtools file to {host_ip} cna')
                raise ProcessError('301605')
            log.info(f'Copy the vmtools package to {host_ip} cna success')

    def __update_global(self):
        resp: HostService.QueryHostsResponse = HostService.query_hosts()
        for host in resp.hosts:
            if host.ip == self.cna_master_ip:
                GLOBAL.master_host_urn = host.urn
                GLOBAL.master_host_mhz = host.cpu_mhz
                log.info("update global master host urn")
            elif host.ip == self.cna_slave_ip:
                GLOBAL.slave_host_urn = host.urn
                GLOBAL.slave_host_mhz = host.cpu_mhz
                log.info("update global slave host urn")
        GLOBAL.save()

    def rollback(self):
        if not run_cmd_status(CREATE_IPTABLES_TASK):
            log.error('Repair MCNA iptables failed.')
            raise ProcessError('300401')
        log.info('Repair MCNA iptables successfully.')
