/** * Gets the value of the specified environment variable. * * @param ses SSH session. * @param cmd environment variable name. * @return environment variable value. * @throws JSchException In case of SSH error. * @throws IOException If failed. */ 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(); } }
/** * Executes command using {@code shell} channel. * * @param ses SSH session. * @param cmd Command. * @throws JSchException In case of SSH error. * @throws IOException If IO error occurs. * @throws IgniteInterruptedCheckedException If thread was interrupted while waiting. */ private void shell(Session ses, String cmd) throws JSchException, IOException, IgniteInterruptedCheckedException { ChannelShell ch = null; try { ch = (ChannelShell) ses.openChannel("shell"); ch.connect(); try (PrintStream out = new PrintStream(ch.getOutputStream(), true)) { out.println(cmd); U.sleep(1000); } } finally { if (ch != null && ch.isConnected()) ch.disconnect(); } }
/** {@inheritDoc} */ @Override public ClusterStartNodeResult call() { 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(' '); String scriptPath = spaceIdx > -1 ? script.substring(0, spaceIdx) : script; String scriptArgs = spaceIdx > -1 ? script.substring(spaceIdx + 1) : ""; String rmtLogArgs = buildRemoteLogArguments(spec.username(), spec.host()); String tmpDir = env(ses, "$TMPDIR", "/tmp/"); String scriptOutputDir = tmpDir + "ignite-startNodes"; shell(ses, "mkdir " + scriptOutputDir); // Mac os don't support ~ in double quotes. Trying get home path from remote system. if (igniteHome.startsWith("~")) { String homeDir = env(ses, "$HOME", "~"); igniteHome = igniteHome.replaceFirst("~", homeDir); } startNodeCmd = new SB() . // Console output is consumed, started nodes must use Ignite file appenders for log. a("nohup ") .a("\"") .a(igniteHome) .a('/') .a(scriptPath) .a("\"") .a(" ") .a(scriptArgs) .a(!cfg.isEmpty() ? " \"" : "") .a(cfg) .a(!cfg.isEmpty() ? "\"" : "") .a(rmtLogArgs) .a(" > ") .a(scriptOutputDir) .a("/") .a(scriptOutputFileName) .a(" 2>& 1 &") .toString(); } info("Starting remote node with SSH command: " + startNodeCmd, spec.logger(), log); shell(ses, startNodeCmd); return new ClusterStartNodeResultImpl(spec.host(), true, null); } catch (IgniteInterruptedCheckedException e) { return new ClusterStartNodeResultImpl(spec.host(), false, e.getMessage()); } catch (Exception e) { return new ClusterStartNodeResultImpl(spec.host(), false, X.getFullStackTrace(e)); } finally { if (ses != null && ses.isConnected()) ses.disconnect(); } }