使用自动启动功能时,Ignite将Linux OS检测为WIndows

时间:2018-06-13 11:48:38

标签: ssh ignite openssh gridgain

我已经编写了一个程序,可以在提供不同机器的详细信息(机器地址,用户名,密码等)时自动启动Ignite服务器。在我的情况下,我试图在两台机器上这样做,为了简单起见,我们称它们为X和Y.我使用的是Ignite版本1.9。

代码非常简单,并调用类org.apache.ignite.IgniteCluster中提供的以下API来启动远程计算机上的Ignite服务器:

Collection<ClusterStartNodeResult> org.apache.ignite.IgniteCluster.startNodes(Collection<Map<String, Object>> hosts, @Nullable Map<String, Object> dflts, boolean restart, int timeout, int maxConn) throws IgniteException

执行代码后,Ignite服务器在机器X上成功启动,而在机器Y上启动Ignite服务器时会抛出以下异常:

Caused by: com.abc.roc.exception.ROCException: One  of the Nodes failed to start properly, java.lang.UnsupportedOperationException: Apache Ignite cannot be auto-started on Windows from IgniteCluster.startNodes(â–’) API.
    at org.apache.ignite.internal.util.nodestart.StartNodeCallableImpl.call(StartNodeCallableImpl.java:138)
    at org.apache.ignite.internal.util.nodestart.StartNodeCallableImpl.call(StartNodeCallableImpl.java:47)
    at org.apache.ignite.internal.util.IgniteUtils.wrapThreadLoader(IgniteUtils.java:6618)
    at org.apache.ignite.internal.processors.closure.GridClosureProcessor$2.body(GridClosureProcessor.java:925)
    at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:110)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

我进入了类的源代码和抛出异常的方法StartNodeCallableImpl.call()。 Apache Ignite源代码中上述调用方法的相关快照如下:

    JSch ssh = new JSch();

    Session ses = null;

    try {
        if (spec.key() != null)
            ssh.addIdentity(spec.key().getAbsolutePath());

        ses = ssh.getSession(spec.username(), spec.host(), spec.port());

        if (spec.password() != null)
            ses.setPassword(spec.password());

        ses.setConfig("StrictHostKeyChecking", "no");

        ses.connect(timeout);

        boolean win = isWindows(ses);

        char separator = win ? '\\' : '/';

        spec.fixPaths(separator);

        String igniteHome = spec.igniteHome();

        if (igniteHome == null)
            igniteHome = win ? DFLT_IGNITE_HOME_WIN : DFLT_IGNITE_HOME_LINUX;

        String script = spec.script();

        if (script == null)
            script = DFLT_SCRIPT_LINUX;

        String cfg = spec.configuration();

        if (cfg == null)
            cfg = "";

        String startNodeCmd;
        String scriptOutputFileName = FILE_NAME_DATE_FORMAT.format(new Date()) + '-'
            + UUID.randomUUID().toString().substring(0, 8) + ".log";

        if (win)
            throw new UnsupportedOperationException("Apache Ignite cannot be auto-started on Windows from IgniteCluster.startNodes(…) API.");
        else { // Assume Unix.
            int spaceIdx = script.indexOf(' ');

isWindows()方法用于确定操作系统是否为Windows。来自Ignite源代码的方法的相关快照是:

private boolean isWindows(Session ses) throws JSchException {
    try {
        return exec(ses, "cmd.exe") != null;
    }
    catch (IOException ignored) {
        return false;
    }
}

内部使用的exec方法如下:

private String exec(Session ses, String cmd) throws JSchException, IOException {
    ChannelExec ch = null;

    try {
        ch = (ChannelExec)ses.openChannel("exec");

        ch.setCommand(cmd);

        ch.connect();

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(ch.getInputStream()))) {
            return reader.readLine();
        }
    }
    finally {
        if (ch != null && ch.isConnected())
            ch.disconnect();
    }
}

我使用了Ignite使用的相同代码并创建了一个测试程序,它将执行机器X和Y.编写的示例代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class JSCHSessionUtil {

public static boolean checkIgniteStyleWindow(String username, String password, String host, int port)
        throws JSchException, IOException {

    boolean isWindows = false;

    JSch ssh = new JSch();

    Session sess = ssh.getSession(username, host, port);

    sess.setPassword(password);

    sess.setConfig("StrictHostKeyChecking", "no");

    sess.connect();

    String cmd = "cmd.exe";

    ChannelExec ch = null;

    try {
        ch = (ChannelExec) sess.openChannel("exec");

        ch.setCommand(cmd);
        ch.connect();

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(ch.getInputStream()))) {

            String output = "";

            String currentLine;

            while (true) {
                currentLine = reader.readLine();
                if (currentLine == null) {
                    break;
                }
                output += currentLine;
            }

            if (output.trim().isEmpty()) {
                isWindows = false;
            }

            else {
                System.out.println("Command Output : \n"+output);
                isWindows = true;
            }

        }

    } finally {
        if (ch != null && ch.isConnected())
            ch.disconnect();
        if (sess != null && sess.isConnected())
            sess.disconnect();
    }

    return isWindows;

}

public static void main(String[] args) throws JSchException, IOException {

    boolean isWindows = checkIgniteStyleWindow("username", "password", "127.0.0.1", 22);

    if (isWindows) {
        System.out.println("\nThis is a Windows OS");
    }

    else {
        System.out.println("\nThis is a Linux OS");
    }

}

}

在两台机器上观察到的输出如下:

机器X的输出

这是一个Linux操作系统

机器Y的输出

命令输出: bash:cmd.exe:找不到命令

这是一个Windows操作系统

正如您所看到的,对于机器Y,错误将作为字符串返回,而不是返回null的API(对于机器X)。这导致Ignite将Linux操作系统检测为Windows。

我想知道永久解决此问题的方法。

1 个答案:

答案 0 :(得分:0)

我认为问题在于Machine Y的软件版本或配置。

您能否详细说明机器Y的配置方式以及与机器X的区别?我已经尝试过你的重现器,它正确地确定了Linux。

机器Y上使用了哪个sshd版本?