package org.zstack.core.ansible;

import org.apache.commons.lang.StringUtils;
import org.zstack.core.CoreGlobalProperty;
import org.zstack.core.Platform;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.utils.StringDSL;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import org.zstack.utils.ssh.Ssh;
import org.zstack.utils.ssh.SshException;
import org.zstack.utils.ssh.SshResult;

import static org.zstack.core.Platform.operr;
import static org.zstack.utils.StringDSL.ln;

/**
 * Created by mingjian.deng on 2019/6/12.
 */
public class CallBackNetworkChecker implements AnsibleChecker {
    private static final CLogger logger = Utils.getLogger(CallBackNetworkChecker.class);

    private String username;
    private String password;
    private String targetIp;
    private String privateKey;
    private int port = 22;

    private String callbackIp = Platform.getManagementServerIp();
    private int callBackPort = 8080;

    private static StringDSL.StringWrapper script = ln(
            "sudo nmap -sS -P0 -n -p {0} {1}|grep \"1 host up\""
    );

    @Override
    public boolean needDeploy() {
        return false;
    }

    @Override
    public void deleteDestFile() {

    }

    @Override
    public ErrorCode stopAnsible() {
        if (CoreGlobalProperty.UNIT_TEST_ON || !AnsibleGlobalConfig.CHECK_MANAGEMENT_CALLBACK.value(Boolean.class)) {
            return null;
        }
        Ssh ssh = new Ssh();
        ssh.setUsername(username).setPrivateKey(privateKey)
                .setPassword(password).setPort(port)
                .setHostname(targetIp);
        String srcScript = script.format(callBackPort, callbackIp);
        try {
            SshResult ret = ssh.shell(srcScript).setTimeout(5).runAndClose();
            ret.raiseExceptionIfFailed();

            if (StringUtils.isEmpty(ret.getStdout())) {
                logger.debug(String.format("nmap return: %s", ret.toString()));
                return operr("cannot nmap from agent: %s to callback address: %s:%s", targetIp, callbackIp, callBackPort);
            }

            logger.debug(ret.getStdout());
            return null;
        } catch (SshException e) {
            return operr(e.getMessage());
        }
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        this.privateKey = privateKey;
    }

    public String getTargetIp() {
        return targetIp;
    }

    public void setTargetIp(String targetIp) {
        this.targetIp = targetIp;
    }

    public String getCallbackIp() {
        return callbackIp;
    }

    public void setCallbackIp(String callbackIp) {
        this.callbackIp = callbackIp;
    }

    public int getCallBackPort() {
        return callBackPort;
    }

    public void setCallBackPort(int callBackPort) {
        this.callBackPort = callBackPort;
    }

}

@@ -961,16 +961,119 @@
  8080;%0A%0A
+    private static StringDSL.StringWrapper ncScript = ln(%0A            %22echo %7C sudo nc %7B0%7D %7B1%7D%22%0A    );%0A%0A
     priv
@@ -1335,349 +1335,352 @@
     
-@Override%0A    public ErrorCode stopAnsible() %7B%0A        if (CoreGlobalProperty.UNIT_TEST_ON %7C%7C !AnsibleGlobalConfig.CHECK_MANAGEMENT_CALLBACK.value(Boolean.class)) %7B%0A            return null;%0A        %7D%0A        Ssh ssh = new Ssh();%0A        ssh.setUsername(username).setPrivateKey(privateKey)%0A                .setPassword(password).setPort(p
+private ErrorCode useNcatToTestConnection(Ssh ssh) %7B%0A        String srcScript = ncScript.format(callbackIp, callBackPort);%0A%0A        SshResult ret = ssh.shell(srcScript).setTimeout(5).runAndClose();%0A        ret.raiseExceptionIfFailed();%0A%0A        logger.debug(String.format(%22nc test host connection to %25s:%25s success%22, callbackIp, callBackP
 ort)
+);%0A
 %0A   
@@ -1688,39 +1688,84 @@
     
-        .setHostname(targetIp);
+return null;%0A    %7D%0A%0A    private ErrorCode useNmapToTestConnection(Ssh ssh) %7B
 %0A   
@@ -1833,26 +1833,9 @@
 p);%0A
-        try %7B%0A    
+%0A
     
@@ -1908,28 +1908,24 @@
 ();%0A        
-    
 ret.raiseExc
@@ -1947,72 +1947,8 @@
 );%0A%0A
-            if (StringUtils.isEmpty(ret.getStdout())) %7B%0A        
     
@@ -2011,28 +2011,77 @@
 String()));%0A
+%0A
     
+    if (StringUtils.isEmpty(ret.getStdout())) %7B%0A
             
@@ -2199,81 +2199,669 @@
     
-    %7D%0A%0A            logger.debug(ret.getStdout());%0A            return null
+%7D%0A%0A        return null;%0A    %7D%0A%0A    @Override%0A    public ErrorCode stopAnsible() %7B%0A        if (CoreGlobalProperty.UNIT_TEST_ON %7C%7C !AnsibleGlobalConfig.CHECK_MANAGEMENT_CALLBACK.value(Boolean.class)) %7B%0A            return null;%0A        %7D%0A        Ssh ssh = new Ssh();%0A        ssh.setUsername(username).setPrivateKey(privateKey)%0A                .setPassword(password).setPort(port)%0A                .setHostname(targetIp);%0A%0A        try %7B%0A            ErrorCode errorCode = useNcatToTestConnection(ssh);%0A%0A            if (errorCode == null) %7B%0A                return null;%0A            %7D%0A%0A            errorCode = useNmapToTestConnection(ssh);%0A%0A            return errorCode
 ;%0A  

Add nc for agent call back network checker