Merge branch 'ignite-sprint-3' into ignite-676
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/f67abe75 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/f67abe75 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/f67abe75 Branch: refs/heads/ignite-676 Commit: f67abe752f42d545a4fa1440ad4a27a543e7c754 Parents: 19cd11f 2f458d2 Author: Artem Shutak <ashu...@gridgain.com> Authored: Wed Apr 8 18:38:01 2015 +0300 Committer: Artem Shutak <ashu...@gridgain.com> Committed: Wed Apr 8 18:38:01 2015 +0300 ---------------------------------------------------------------------- .../java/org/apache/ignite/IgniteCluster.java | 9 +- .../ignite/cluster/ClusterStartNodeResult.java | 46 +++ .../apache/ignite/internal/IgniteKernal.java | 11 +- .../cluster/ClusterStartNodeResultImpl.java | 87 +++++ .../cluster/IgniteClusterAsyncImpl.java | 5 +- .../internal/cluster/IgniteClusterImpl.java | 37 +-- .../processors/cache/GridCacheProcessor.java | 11 +- .../util/nodestart/IgniteNodeCallable.java | 30 -- .../util/nodestart/IgniteSshHelper.java | 2 +- .../util/nodestart/StartNodeCallable.java | 30 ++ .../util/nodestart/IgniteNodeCallableImpl.java | 325 ------------------ .../util/nodestart/IgniteSshHelperImpl.java | 4 +- .../util/nodestart/StartNodeCallableImpl.java | 326 +++++++++++++++++++ ...gniteProjectionStartStopRestartSelfTest.java | 261 ++++++++------- .../IgniteStartStopRestartTestSuite.java | 1 + .../commands/start/VisorStartCommand.scala | 4 +- 16 files changed, 664 insertions(+), 525 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/f67abe75/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java ---------------------------------------------------------------------- diff --cc modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java index 0000000,7c6010f..31a4cf7 mode 000000,100644..100644 --- a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java +++ b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/StartNodeCallableImpl.java @@@ -1,0 -1,309 +1,326 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.apache.ignite.internal.util.nodestart; + + import com.jcraft.jsch.*; + import org.apache.ignite.*; + import org.apache.ignite.cluster.*; + import org.apache.ignite.internal.*; + import org.apache.ignite.internal.cluster.*; + import org.apache.ignite.internal.util.typedef.*; + import org.apache.ignite.internal.util.typedef.internal.*; + import org.apache.ignite.resources.*; + + import java.io.*; + import java.text.*; + import java.util.*; + + import static org.apache.ignite.IgniteSystemProperties.*; + + /** + * SSH-based node starter. + */ + public class StartNodeCallableImpl implements StartNodeCallable { + /** Default Ignite home path for Windows (taken from environment variable). */ + private static final String DFLT_IGNITE_HOME_WIN = "%IGNITE_HOME%"; + + /** Default Ignite home path for Linux (taken from environment variable). */ + private static final String DFLT_IGNITE_HOME_LINUX = "$IGNITE_HOME"; + + /** Default start script path for Linux. */ + private static final String DFLT_SCRIPT_LINUX = "bin/ignite.sh -v"; + + /** Date format for log file name. */ + private static final SimpleDateFormat FILE_NAME_DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy--HH-mm-ss"); + + /** Specification. */ + private final IgniteRemoteStartSpecification spec; + + /** Connection timeout. */ + private final int timeout; + + /** Logger. */ + @LoggerResource + private IgniteLogger log; + ++ public static String fName; ++ + /** + * Required by Externalizable. + */ + public StartNodeCallableImpl() { + spec = null; + timeout = 0; + + assert false; + } + + /** + * Constructor. + * + * @param spec Specification. + * @param timeout Connection timeout. + */ + public StartNodeCallableImpl(IgniteRemoteStartSpecification spec, int timeout) { + assert spec != null; + + this.spec = spec; + this.timeout = timeout; + } + + /** {@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); + } ++ ++ fName = igniteHome + "/" + scriptOutputFileName; + + 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 &"). ++ a(!cfg.isEmpty() ? " \"" : "").a(cfg).a(!cfg.isEmpty() ? "\"" : "").a(rmtLogArgs).a(" > ").a(fName).a(" 2>& 1 &"). + toString(); + } + + info("Starting remote node with SSH command: " + startNodeCmd, spec.logger(), log); + + shell(ses, startNodeCmd); ++ ++ log.info(">>>>> Shelled"); + + 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(); + } + } + + /** + * 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; ++ ++ log.info(">>>>> Shell. ses=" + ses + ", cmd=" + cmd); + + try { + ch = (ChannelShell)ses.openChannel("shell"); + + ch.connect(); + ++ log.info(">>>>> Shell. Connected"); ++ + try (PrintStream out = new PrintStream(ch.getOutputStream(), true)) { ++ log.info(">>>>> Shell. Printing to out"); ++ + out.println(cmd); + ++ log.info(">>>>> Shell. Printed"); ++ + U.sleep(1000); + } + } + finally { - if (ch != null && ch.isConnected()) ++ if (ch != null && ch.isConnected()) { ++ log.info(">>>>> Shell. Disconnecting"); ++ + ch.disconnect(); ++ ++ log.info(">>>>> Shell. Disconnected"); ++ } + } + } + + /** + * Checks whether host is running Windows OS. + * + * @param ses SSH session. + * @return Whether host is running Windows OS. + * @throws JSchException In case of SSH error. + */ + private boolean isWindows(Session ses) throws JSchException { + try { + return exec(ses, "cmd.exe") != null; + } + catch (IOException ignored) { + return false; + } + } + + /** + * Gets the value of the specified environment variable. + * + * @param ses SSH session. + * @param name environment variable name. + * @param dflt default value. + * @return environment variable value. + * @throws JSchException In case of SSH error. + */ + private String env(Session ses, String name, String dflt) throws JSchException { + try { + return exec(ses, "echo " + name); + } + catch (IOException ignored) { + return dflt; + } + } + + /** + * 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(); + } + } + + /** + * Builds ignite.sh attributes to set up SSH username and password and log directory for started node. + * + * @param username SSH user name. + * @param host Host. + * @return {@code ignite.sh} script arguments. + */ + private String buildRemoteLogArguments(String username, String host) { + assert username != null; + assert host != null; + + SB sb = new SB(); + + sb.a(" -J-D").a(IGNITE_SSH_HOST).a("=\"").a(host).a("\""). + a(" -J-D").a(IGNITE_SSH_USER_NAME).a("=\"").a(username).a("\""); + + return sb.toString(); + } + + /** + * @param log Logger. + * @return This callable for chaining method calls. + */ + public StartNodeCallable setLogger(IgniteLogger log) { + this.log = log; + + return this; + } + + /** + * Log info message to loggers. + * + * @param msg Message text. + * @param loggers Loggers. + */ + private void info(String msg, IgniteLogger... loggers) { + for (IgniteLogger logger : loggers) + if (logger != null && logger.isInfoEnabled()) + logger.info(msg); + } + } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/f67abe75/modules/ssh/src/test/java/org/apache/ignite/internal/IgniteProjectionStartStopRestartSelfTest.java ---------------------------------------------------------------------- diff --cc modules/ssh/src/test/java/org/apache/ignite/internal/IgniteProjectionStartStopRestartSelfTest.java index 636f9c7,7fa5b4b..4a72811 --- a/modules/ssh/src/test/java/org/apache/ignite/internal/IgniteProjectionStartStopRestartSelfTest.java +++ b/modules/ssh/src/test/java/org/apache/ignite/internal/IgniteProjectionStartStopRestartSelfTest.java @@@ -205,10 -204,10 +204,10 @@@ public class IgniteProjectionStartStopR /** * @throws Exception If failed. */ - public void testStartThreeNodes() throws Exception { + public void _testStartThreeNodes() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, DFLT_TIMEOUT, 1); @@@ -235,10 -234,10 +234,10 @@@ /** * @throws Exception If failed. */ - public void testStartThreeNodesAndDoEmptyCall() throws Exception { + public void _testStartThreeNodesAndDoEmptyCall() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -276,10 -275,10 +275,10 @@@ /** * @throws Exception If failed. */ - public void testStartThreeNodesAndTryToStartOneNode() throws Exception { + public void _testStartThreeNodesAndTryToStartOneNode() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -317,10 -316,10 +316,10 @@@ /** * @throws Exception If failed. */ - public void testStartFiveNodesInTwoCalls() throws Exception { + public void _testStartFiveNodesInTwoCalls() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -371,10 -370,10 +370,10 @@@ /** * @throws Exception If failed. */ - public void testStartFiveWithTwoSpecs() throws Exception { + public void _testStartFiveWithTwoSpecs() throws Exception { joinedLatch = new CountDownLatch(5); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), F.asList(map(HOST, SSH_UNAME, pwd, key, 2, U.getIgniteHome(), CFG_NO_ATTR, null), map(HOST, SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null)), @@@ -402,10 -401,10 +401,10 @@@ /** * @throws Exception If failed. */ - public void testStartThreeNodesAndRestart() throws Exception { + public void _testStartThreeNodesAndRestart() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -512,10 -493,10 +511,10 @@@ /** * @throws Exception If failed. */ - public void testStopNodes() throws Exception { + public void _testStopNodes() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, null, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -547,10 -528,10 +546,10 @@@ /** * @throws Exception If failed. */ - public void testStopNodesFiltered() throws Exception { + public void _testStopNodesFiltered() throws Exception { joinedLatch = new CountDownLatch(2); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 2, U.getIgniteHome(), CFG_ATTR, null), null, false, 0, 16); @@@ -610,10 -591,10 +609,10 @@@ /** * @throws Exception If failed. */ - public void testStopNodeById() throws Exception { + public void _testStopNodeById() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -645,10 -626,10 +644,10 @@@ /** * @throws Exception If failed. */ - public void testStopNodesByIds() throws Exception { + public void _testStopNodesByIds() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -687,10 -668,10 +686,10 @@@ /** * @throws Exception If failed. */ - public void testStopNodesByIdsC() throws Exception { + public void _testStopNodesByIdsC() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -724,10 -705,10 +723,10 @@@ /** * @throws Exception If failed. */ - public void testRestartNodes() throws Exception { + public void _testRestartNodes() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -761,10 -742,10 +760,10 @@@ /** * @throws Exception If failed. */ - public void testRestartNodesFiltered() throws Exception { + public void _testRestartNodesFiltered() throws Exception { joinedLatch = new CountDownLatch(2); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 2, U.getIgniteHome(), CFG_ATTR, null), null, false, 0, 16); @@@ -827,10 -808,10 +826,10 @@@ /** * @throws Exception If failed. */ - public void testRestartNodeById() throws Exception { + public void _testRestartNodeById() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -864,10 -845,10 +863,10 @@@ /** * @throws Exception If failed. */ - public void testRestartNodesByIds() throws Exception { + public void _testRestartNodesByIds() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); @@@ -903,10 -884,10 +902,10 @@@ /** * @throws Exception If failed. */ - public void testRestartNodesByIdsC() throws Exception { + public void _testRestartNodesByIdsC() throws Exception { joinedLatch = new CountDownLatch(3); - Collection<GridTuple3<String, Boolean, String>> res = + Collection<ClusterStartNodeResult> res = startNodes(ignite.cluster(), maps(Collections.singleton(HOST), SSH_UNAME, pwd, key, 3, U.getIgniteHome(), CFG_NO_ATTR, null), null, false, 0, 16); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/f67abe75/modules/ssh/src/test/java/org/apache/ignite/internal/IgniteStartStopRestartTestSuite.java ----------------------------------------------------------------------