Я написал программу, которая может автоматически запускать сервер Ignite, когда ему предоставляется подробная информация (адрес машины, имя пользователя, пароль и т. Д.) Различных машин.В моем случае я пытаюсь сделать это на двух машинах, для простоты давайте назовем их X и Y. Я использую Ignite версии 1.9.
Код довольно прост и вызывает следующий API, предоставленный вКласс org.apache.ignite.IgniteCluster для запуска сервера 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, тогда как при запуске Ignite Server он выдает следующее исключениена компьютере Y:
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 () используется для определения, является ли ОС окнами или нет.Соответствующий снимок метода из исходного кода 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 ошибка возвращается в виде строки, а API возвращает ноль (как для машины X).Это приводит к тому, что Ignite определяет ОС Linux как Windows.
Я хочу узнать, как навсегда решить эту проблему.