我已经编写了一个程序,可以在提供不同机器的详细信息(机器地址,用户名,密码等)时自动启动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");
}
}
}
在两台机器上观察到的输出如下:
这是一个Linux操作系统
命令输出: bash:cmd.exe:找不到命令
这是一个Windows操作系统
正如您所看到的,对于机器Y,错误将作为字符串返回,而不是返回null的API(对于机器X)。这导致Ignite将Linux操作系统检测为Windows。
我想知道永久解决此问题的方法。
答案 0 :(得分:0)
我认为问题在于Machine Y的软件版本或配置。
您能否详细说明机器Y的配置方式以及与机器X的区别?我已经尝试过你的重现器,它正确地确定了Linux。
机器Y上使用了哪个sshd
版本?