# ignite-149: WIP.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/67376020 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/67376020 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/67376020 Branch: refs/heads/ignite-188 Commit: 673760208f800118608cf372ff3052fcd9ecb14b Parents: bb8b07d Author: vozerov-gridgain <voze...@gridgain.com> Authored: Thu Feb 5 17:49:45 2015 +0300 Committer: vozerov-gridgain <voze...@gridgain.com> Committed: Thu Feb 5 17:49:45 2015 +0300 ---------------------------------------------------------------------- bin/include/IgniteService.exe | Bin 0 -> 6144 bytes bin/include/ggservice.exe | Bin 5632 -> 0 bytes .../java/org/apache/ignite/IgniteCluster.java | 6 +- .../apache/ignite/internal/IgniteKernal.java | 16 +- .../ignite/internal/util/IgniteUtils.java | 2 +- .../util/nodestart/GridNodeCallable.java | 29 - .../util/nodestart/GridNodeStartUtils.java | 390 ------- .../nodestart/GridRemoteStartSpecification.java | 279 ----- .../util/nodestart/IgniteNodeCallable.java | 30 + .../util/nodestart/IgniteNodeStartUtils.java | 391 +++++++ .../IgniteRemoteStartSpecification.java | 279 +++++ .../util/nodestart/IgniteSshProcessor.java | 2 +- .../core/src/test/bin/start-nodes-custom.bat | 2 +- modules/core/src/test/config/start-nodes.ini | 6 +- .../util/nodestart/GridNodeCallableImpl.java | 344 ------ .../util/nodestart/IgniteNodeCallableImpl.java | 344 ++++++ .../util/nodestart/IgniteSshProcessorImpl.java | 4 +- .../internal/GridNodeStartUtilsSelfTest.java | 89 -- .../GridProjectionStartStopRestartSelfTest.java | 1032 ------------------ .../internal/IgniteNodeStartUtilsSelfTest.java | 88 ++ ...gniteProjectionStartStopRestartSelfTest.java | 1032 ++++++++++++++++++ .../IgniteStartStopRestartTestSuite.java | 4 +- .../commands/start/VisorStartCommand.scala | 4 +- modules/winservice/.gitignore | 2 + modules/winservice/IgniteService.sln | 22 + .../winservice/IgniteService/IgniteService.cs | 170 +++ .../IgniteService/IgniteService.csproj | 90 ++ 27 files changed, 2471 insertions(+), 2186 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/bin/include/IgniteService.exe ---------------------------------------------------------------------- diff --git a/bin/include/IgniteService.exe b/bin/include/IgniteService.exe new file mode 100644 index 0000000..66deb9c Binary files /dev/null and b/bin/include/IgniteService.exe differ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/bin/include/ggservice.exe ---------------------------------------------------------------------- diff --git a/bin/include/ggservice.exe b/bin/include/ggservice.exe deleted file mode 100644 index 7d3783b..0000000 Binary files a/bin/include/ggservice.exe and /dev/null differ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java index d8f16ed..0350487 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java @@ -232,7 +232,7 @@ public interface IgniteCluster extends ClusterGroup, IgniteAsyncSupport { * </td> * </tr> * <tr> - * <td><b>ggHome</b></td> + * <td><b>igniteHome</b></td> * <td>String</td> * <td> * Path to GridGain installation folder. If not defined, IGNITE_HOME @@ -242,13 +242,13 @@ public interface IgniteCluster extends ClusterGroup, IgniteAsyncSupport { * <tr> * <td><b>cfg</b></td> * <td>String</td> - * <td>Path to configuration file (relative to {@code ggHome}).</td> + * <td>Path to configuration file (relative to {@code igniteHome}).</td> * </tr> * <tr> * <td><b>script</b></td> * <td>String</td> * <td> - * Custom startup script file name and path (relative to {@code ggHome}). + * Custom startup script file name and path (relative to {@code igniteHome}). * You can also specify a space-separated list of parameters in the same * string (for example: {@code "bin/my-custom-script.sh -v"}). * </td> http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 2b0d014..5dc4bc8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -98,7 +98,7 @@ import static org.apache.ignite.internal.GridNodeAttributes.*; import static org.apache.ignite.internal.GridProductImpl.*; import static org.apache.ignite.internal.IgniteComponentType.*; import static org.apache.ignite.internal.processors.license.GridLicenseSubsystem.*; -import static org.apache.ignite.internal.util.nodestart.GridNodeStartUtils.*; +import static org.apache.ignite.internal.util.nodestart.IgniteNodeStartUtils.*; import static org.apache.ignite.lifecycle.LifecycleEventType.*; /** @@ -2713,9 +2713,9 @@ public class IgniteKernal extends ClusterGroupAdapter implements IgniteEx, Ignit try { IgniteSshProcessor sshProcessor = IgniteComponentType.SSH.create(false); - Map<String, Collection<GridRemoteStartSpecification>> specsMap = specifications(hosts, dflts); + Map<String, Collection<IgniteRemoteStartSpecification>> specsMap = specifications(hosts, dflts); - Map<String, ConcurrentLinkedQueue<GridNodeCallable>> runMap = new HashMap<>(); + Map<String, ConcurrentLinkedQueue<IgniteNodeCallable>> runMap = new HashMap<>(); int nodeCallCnt = 0; @@ -2760,11 +2760,11 @@ public class IgniteKernal extends ClusterGroupAdapter implements IgniteEx, Ignit startIdx = neighbors.size() + 1; } - ConcurrentLinkedQueue<GridNodeCallable> nodeRuns = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue<IgniteNodeCallable> nodeRuns = new ConcurrentLinkedQueue<>(); runMap.put(host, nodeRuns); - for (GridRemoteStartSpecification spec : specsMap.get(host)) { + for (IgniteRemoteStartSpecification spec : specsMap.get(host)) { assert spec.host().equals(host); for (int i = startIdx; i <= spec.nodes(); i++) { @@ -2790,7 +2790,7 @@ public class IgniteKernal extends ClusterGroupAdapter implements IgniteEx, Ignit AtomicInteger cnt = new AtomicInteger(nodeCallCnt); // Limit maximum simultaneous connection number per host. - for (ConcurrentLinkedQueue<GridNodeCallable> queue : runMap.values()) { + for (ConcurrentLinkedQueue<IgniteNodeCallable> queue : runMap.values()) { for (int i = 0; i < maxConn; i++) { if (!runNextNodeCallable(queue, fut, cnt)) break; @@ -2839,10 +2839,10 @@ public class IgniteKernal extends ClusterGroupAdapter implements IgniteEx, Ignit * @param cnt Atomic counter to check if all futures are added to compound future. * @return {@code True} if task was started, {@code false} if queue was empty. */ - private boolean runNextNodeCallable(final ConcurrentLinkedQueue<GridNodeCallable> queue, + private boolean runNextNodeCallable(final ConcurrentLinkedQueue<IgniteNodeCallable> queue, final GridCompoundFuture<GridTuple3<String, Boolean, String>, Collection<GridTuple3<String, Boolean, String>>> comp, final AtomicInteger cnt) { - GridNodeCallable call = queue.poll(); + IgniteNodeCallable call = queue.poll(); if (call == null) return false; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index e322979..c9577d4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -2533,7 +2533,7 @@ public abstract class IgniteUtils { if (ggHome0 != null && !ggHome0.equals(path)) throw new IgniteException("Failed to set IGNITE_HOME after it has been already resolved " + - "[ggHome=" + ggHome0 + ", newGgHome=" + path + ']'); + "[igniteHome=" + ggHome0 + ", newIgniteHome=" + path + ']'); } /** http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallable.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallable.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallable.java deleted file mode 100644 index a76c861..0000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 org.apache.ignite.internal.util.lang.*; - -import java.util.concurrent.*; - -/** - * SSH-based node starter, returns tuple which contains hostname, success flag and error message - * if attempt was not successful. - */ -public interface GridNodeCallable extends Callable<GridTuple3<String, Boolean, String>> { -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeStartUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeStartUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeStartUtils.java deleted file mode 100644 index 44306ab..0000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeStartUtils.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * 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 org.apache.ignite.*; -import org.apache.ignite.internal.util.typedef.*; -import org.apache.ignite.internal.util.typedef.internal.*; -import org.apache.ignite.lang.*; -import org.jetbrains.annotations.*; - -import java.io.*; -import java.util.*; -import java.util.concurrent.*; - -/** - * Util methods for {@code GridProjection.startNodes(..)} methods. - */ -public class GridNodeStartUtils { - /** Key for hostname. */ - public static final String HOST = "host"; - - /** Key for port number. */ - public static final String PORT = "port"; - - /** Key for username. */ - public static final String UNAME = "uname"; - - /** Key for password. */ - public static final String PASSWD = "passwd"; - - /** Key for private key file. */ - public static final String KEY = "key"; - - /** Key for number of nodes. */ - public static final String NODES = "nodes"; - - /** Key for GridGain home folder. */ - public static final String IGNITE_HOME = "ggHome"; - - /** Key for configuration path. */ - public static final String CFG = "cfg"; - - /** Key for script path. */ - public static final String SCRIPT = "script"; - - /** Key for logger. */ - public static final String LOGGER = "logger"; - - /** Default connection timeout. */ - public static final int DFLT_TIMEOUT = 10000; - - /** Default maximum number of parallel connections. */ - public static final int DFLT_MAX_CONN = 5; - - /** Symbol that specifies range of IPs. */ - private static final String RANGE_SMB = "~"; - - /** Default port. */ - private static final int DFLT_PORT = 22; - - /** Default number of nodes. */ - private static final int DFLT_NODES = 1; - - /** Default configuration path. */ - private static final String DFLT_CFG = ""; - - /** Defaults section name. */ - private static final String DFLT_SECTION = "defaults"; - - /** - * Ensure singleton. - */ - private GridNodeStartUtils() { - // No-op. - } - - /** - * Parses INI file. - * - * @param file File. - * @return Tuple with host maps and default values. - * @throws IgniteCheckedException In case of error. - */ - public static IgniteBiTuple<Collection<Map<String, Object>>, Map<String, Object>> parseFile( - File file) throws IgniteCheckedException { - assert file != null; - assert file.exists(); - assert file.isFile(); - - BufferedReader br = null; - - int lineCnt = 1; - - try { - br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); - - String section = null; - - Collection<Map<String, Object>> hosts = new LinkedList<>(); - Map<String, Object> dflts = null; - Map<String, Object> props = null; - - for (String line; (line = br.readLine()) != null; lineCnt++) { - String l = line.trim(); - - if (l.isEmpty() || l.startsWith("#") || l.startsWith(";")) - continue; - - if (l.startsWith("[") && l.endsWith("]")) { - Map<String, Object> dfltsTmp = processSection(section, hosts, dflts, props); - - if (dfltsTmp != null) - dflts = dfltsTmp; - - props = new HashMap<>(); - - section = l.substring(1, l.length() - 1); - } - else if (l.contains("=")) { - if (section == null) - throw new IgniteCheckedException("GridGain ini format doesn't support unnamed section."); - - String key = l.substring(0, l.indexOf('=')); - String val = line.substring(line.indexOf('=') + 1); - - switch (key) { - case HOST: - case UNAME: - case PASSWD: - case IGNITE_HOME: - case CFG: - case SCRIPT: - props.put(key, val); - break; - - case PORT: - case NODES: - props.put(key, Integer.valueOf(val)); - break; - - case KEY: - props.put(KEY, new File(val)); - break; - } - } - else - throw new IgniteCheckedException("Failed to parse INI file (line " + lineCnt + ")."); - } - - Map<String, Object> dfltsTmp = processSection(section, hosts, dflts, props); - - if (dfltsTmp != null) - dflts = dfltsTmp; - - return F.t(hosts, dflts); - } - catch (IOException | NumberFormatException e) { - throw new IgniteCheckedException("Failed to parse INI file (line " + lineCnt + ").", e); - } - finally { - U.closeQuiet(br); - } - } - - /** - * Processes section of parsed INI file. - * - * @param section Name of the section. - * @param hosts Already parsed properties for sections excluding default. - * @param dflts Parsed properties for default section. - * @param props Current properties. - * @return Default properties if specified section is default, {@code null} otherwise. - * @throws IgniteCheckedException If INI file contains several default sections. - */ - private static Map<String, Object> processSection(String section, Collection<Map<String, Object>> hosts, - Map<String, Object> dflts, Map<String, Object> props) throws IgniteCheckedException { - if (section == null || props == null) - return null; - - if (DFLT_SECTION.equalsIgnoreCase(section)) { - if (dflts != null) - throw new IgniteCheckedException("Only one '" + DFLT_SECTION + "' section is allowed."); - - return props; - } - else { - hosts.add(props); - - return null; - } - } - - /** - * Makes specifications. - * - * @param hosts Host configurations. - * @param dflts Default values. - * @return Specification grouped by hosts. - * @throws IgniteCheckedException In case of error. - */ - public static Map<String, Collection<GridRemoteStartSpecification>> specifications( - Collection<Map<String, Object>> hosts, @Nullable Map<String, Object> dflts) - throws IgniteCheckedException { - Map<String, Collection<GridRemoteStartSpecification>> specsMap = U.newHashMap(hosts.size()); - - GridRemoteStartSpecification dfltSpec = processDefaults(dflts); - - for (Map<String, Object> host : hosts) { - Collection<GridRemoteStartSpecification> specs = processHost(host, dfltSpec); - - for (GridRemoteStartSpecification spec : specs) - F.addIfAbsent(specsMap, spec.host(), new Callable<Collection<GridRemoteStartSpecification>>() { - @Override public Collection<GridRemoteStartSpecification> call() throws Exception { - return new HashSet<>(); - } - }).add(spec); - } - - return specsMap; - } - - /** - * Converts properties map to default specification. - * - * @param dflts Properties. - * @return Specification. - * @throws IgniteCheckedException If properties are invalid. - */ - private static GridRemoteStartSpecification processDefaults(@Nullable Map<String, Object> dflts) - throws IgniteCheckedException { - int port = DFLT_PORT; - String uname = System.getProperty("user.name"); - String passwd = null; - File key = null; - int nodes = DFLT_NODES; - String ggHome = null; - String cfg = DFLT_CFG; - String script = null; - IgniteLogger log = null; - - if (dflts != null) { - if (dflts.get(PORT) != null) - port = (Integer)dflts.get(PORT); - - if (dflts.get(UNAME) != null) - uname = (String)dflts.get(UNAME); - - if (dflts.get(PASSWD) != null) - passwd = (String)dflts.get(PASSWD); - - if (dflts.get(KEY) != null) - key = (File)dflts.get(KEY); - - if (dflts.get(NODES) != null) - nodes = (Integer)dflts.get(NODES); - - if (dflts.get(IGNITE_HOME) != null) - ggHome = (String)dflts.get(IGNITE_HOME); - - if (dflts.get(CFG) != null) - cfg = (String)dflts.get(CFG); - - if (dflts.get(SCRIPT) != null) - script = (String)dflts.get(SCRIPT); - - if (dflts.get(LOGGER) != null) - log = (IgniteLogger)dflts.get(LOGGER); - } - - if (port <= 0) - throw new IgniteCheckedException("Invalid port number: " + port); - - if (nodes <= 0) - throw new IgniteCheckedException("Invalid number of nodes: " + nodes); - - return new GridRemoteStartSpecification(null, port, uname, passwd, - key, nodes, ggHome, cfg, script, log); - } - - /** - * Converts properties map to specification. - * - * @param props Properties. - * @param dfltSpec Default specification. - * @return Specification. - * @throws IgniteCheckedException If properties are invalid. - */ - private static Collection<GridRemoteStartSpecification> processHost(Map<String, Object> props, - GridRemoteStartSpecification dfltSpec) throws IgniteCheckedException { - assert props != null; - assert dfltSpec != null; - - if (props.get(HOST) == null) - throw new IgniteCheckedException("Host must be specified."); - - Set<String> hosts = expandHost((String)props.get(HOST)); - int port = props.get(PORT) != null ? (Integer)props.get(PORT) : dfltSpec.port(); - String uname = props.get(UNAME) != null ? (String)props.get(UNAME) : dfltSpec.username(); - String passwd = props.get(PASSWD) != null ? (String)props.get(PASSWD) : dfltSpec.password(); - File key = props.get(KEY) != null ? (File)props.get(KEY) : dfltSpec.key(); - int nodes = props.get(NODES) != null ? (Integer)props.get(NODES) : dfltSpec.nodes(); - String ggHome = props.get(IGNITE_HOME) != null ? (String)props.get(IGNITE_HOME) : dfltSpec.ggHome(); - String cfg = props.get(CFG) != null ? (String)props.get(CFG) : dfltSpec.configuration(); - String script = props.get(SCRIPT) != null ? (String)props.get(SCRIPT) : dfltSpec.script(); - - if (port<= 0) - throw new IgniteCheckedException("Invalid port number: " + port); - - if (nodes <= 0) - throw new IgniteCheckedException("Invalid number of nodes: " + nodes); - - if (passwd == null && key == null) - throw new IgniteCheckedException("Password or private key file must be specified."); - - if (passwd != null && key != null) - passwd = null; - - Collection<GridRemoteStartSpecification> specs = - new ArrayList<>(hosts.size()); - - for (String host : hosts) - specs.add(new GridRemoteStartSpecification(host, port, uname, passwd, - key, nodes, ggHome, cfg, script, dfltSpec.logger())); - - return specs; - } - - /** - * Parses and expands range of IPs, if needed. Host names without the range - * returned as is. - * - * @param addr Host with or without `~` range. - * @return Set of individual host names (IPs). - * @throws IgniteCheckedException In case of error. - */ - public static Set<String> expandHost(String addr) throws IgniteCheckedException { - assert addr != null; - - Set<String> addrs = new HashSet<>(); - - if (addr.contains(RANGE_SMB)) { - String[] parts = addr.split(RANGE_SMB); - - if (parts.length != 2) - throw new IgniteCheckedException("Invalid IP range: " + addr); - - int lastDot = parts[0].lastIndexOf('.'); - - if (lastDot < 0) - throw new IgniteCheckedException("Invalid IP range: " + addr); - - String base = parts[0].substring(0, lastDot); - String begin = parts[0].substring(lastDot + 1); - String end = parts[1]; - - try { - int a = Integer.valueOf(begin); - int b = Integer.valueOf(end); - - if (a > b) - throw new IgniteCheckedException("Invalid IP range: " + addr); - - for (int i = a; i <= b; i++) - addrs.add(base + "." + i); - } - catch (NumberFormatException e) { - throw new IgniteCheckedException("Invalid IP range: " + addr, e); - } - } - else - addrs.add(addr); - - return addrs; - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridRemoteStartSpecification.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridRemoteStartSpecification.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridRemoteStartSpecification.java deleted file mode 100644 index f0d7862..0000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/GridRemoteStartSpecification.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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 org.apache.ignite.*; -import org.apache.ignite.internal.util.typedef.*; -import org.jetbrains.annotations.*; - -import java.io.*; - -/** - * Host data. - */ -public class GridRemoteStartSpecification { - /** Hostname. */ - private final String host; - - /** Port number. */ - private final int port; - - /** Username. */ - private final String uname; - - /** Password. */ - private final String passwd; - - /** Private key file. */ - private final File key; - - /** Private key filename. */ - private final String keyName; - - /** Number of nodes to start. */ - private final int nodes; - - /** GridGain installation folder. */ - private String ggHome; - - /** Configuration path. */ - private String cfg; - - /** Configuration filename. */ - private String cfgName; - - /** Script path. */ - private String script; - - /** Custom logger. */ - private IgniteLogger logger; - - /** Valid flag */ - private boolean valid; - - /** - * @param host Hostname. - * @param port Port number. - * @param uname Username. - * @param passwd Password (can be {@code null} if private key authentication is used). - * @param key Private key file path. - * @param nodes Number of nodes to start. - * @param ggHome GridGain installation folder. - * @param cfg Configuration path. - * @param script Script path. - */ - public GridRemoteStartSpecification(@Nullable String host, int port, @Nullable String uname, - @Nullable String passwd, @Nullable File key, int nodes, @Nullable String ggHome, - @Nullable String cfg, @Nullable String script) { - this(host, port, uname, passwd, key, nodes, ggHome, cfg, script, null); - } - - /** - * @param host Hostname. - * @param port Port number. - * @param uname Username. - * @param passwd Password (can be {@code null} if private key authentication is used). - * @param key Private key file path. - * @param nodes Number of nodes to start. - * @param ggHome GridGain installation folder. - * @param cfg Configuration path. - * @param script Script path. - * @param logger Custom logger. - */ - public GridRemoteStartSpecification(@Nullable String host, int port, @Nullable String uname, - @Nullable String passwd, @Nullable File key, int nodes, @Nullable String ggHome, - @Nullable String cfg, @Nullable String script, @Nullable IgniteLogger logger) { - assert port > 0; - assert nodes > 0; - - this.host = !F.isEmpty(host) ? host : null; - this.port = port; - this.uname = !F.isEmpty(uname) ? uname : null; - this.passwd = !F.isEmpty(passwd) ? passwd : null; - this.key = key; - this.nodes = nodes; - this.ggHome = !F.isEmpty(ggHome) ? ggHome : null; - this.cfg = !F.isEmpty(cfg) ? cfg : null; - cfgName = cfg == null ? null : shorten(cfg); - keyName = key == null ? "" : shorten(key.getAbsolutePath()); - this.script = !F.isEmpty(script) ? script : null; - this.logger = logger; - } - - /** {@inheritDoc} */ - @Override public boolean equals(Object o) { - if (this == o) return true; - - if (!(o instanceof GridRemoteStartSpecification)) return false; - - GridRemoteStartSpecification that = (GridRemoteStartSpecification)o; - - return (host == null ? that.host == null : host.equals(that.host)) && - (uname == null ? that.uname == null : uname.equals(that.uname)) && - (passwd == null ? that.passwd == null : passwd.equals(that.passwd)) && - (key == null ? that.key == null : key.equals(that.key)) && - (ggHome == null ? that.ggHome == null : ggHome.equals(that.ggHome)) && - (cfg == null ? that.cfg == null : cfg.equals(that.cfg)) && - (script == null ? that.script == null : script.equals(that.script)) && - port == that.port && nodes == that.nodes; - } - - /** {@inheritDoc} */ - @Override public int hashCode() { - int res = host == null ? 0 : host.hashCode(); - - res = 31 * res + (uname == null ? 0 : uname.hashCode()); - res = 31 * res + (passwd == null ? 0 : passwd.hashCode()); - res = 31 * res + (key == null ? 0 : key.hashCode()); - res = 31 * res + (ggHome == null ? 0 : ggHome.hashCode()); - res = 31 * res + (cfg == null ? 0 : cfg.hashCode()); - res = 31 * res + (script == null ? 0 : script.hashCode()); - res = 31 * res + port; - res = 31 * res + nodes; - - return res; - } - - /** - * Get filename from path. - * - * @param path Path. - * @return Filename. - */ - private static String shorten(String path) { - int idx1 = path.lastIndexOf('/'); - int idx2 = path.lastIndexOf('\\'); - int idx = Math.max(idx1, idx2); - - return idx == -1 ? path : path.substring(idx + 1); - } - - /** - * @return Hostname. - */ - public String host() { - return host; - } - - /** - * @return Port number. - */ - public int port() { - return port; - } - - /** - * @return Username. - */ - public String username() { - return uname; - } - - /** - * @return Password. - */ - public String password() { - return passwd; - } - - /** - * @return Private key file path. - */ - public File key() { - return key; - } - - /** - * @return Private key file name. - */ - public String keyName() { - return keyName; - } - - /** - * @return Number of nodes to start. - */ - public int nodes() { - return nodes; - } - - /** - * @return GridGain installation folder. - */ - public String ggHome() { - return ggHome; - } - - /** - * @return Configuration full path. - */ - public String configuration() { - return cfg; - } - - /** - * @return Configuration path short version - just file name. - */ - public String configurationName() { - return cfgName; - } - - /** - * @return Script path. - */ - public String script() { - return script; - } - - /** - * @return Custom logger. - */ - public IgniteLogger logger() { - return logger; - } - - /** - * @return Valid flag. - */ - public boolean valid() { - return valid; - } - - /** - * @param valid Valid flag. - */ - public void valid(boolean valid) { - this.valid = valid; - } - - /** - * Sets correct separator in paths. - * - * @param separator Separator. - */ - public void fixPaths(char separator) { - if (ggHome != null) - ggHome = ggHome.replace('\\', separator).replace('/', separator); - - if (script != null) - script = script.replace('\\', separator).replace('/', separator); - - if (cfg != null) - cfg = cfg.replace('\\', separator).replace('/', separator); - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallable.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallable.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallable.java new file mode 100644 index 0000000..6c34efb --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallable.java @@ -0,0 +1,30 @@ +/* + * 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 org.apache.ignite.internal.util.lang.*; + +import java.util.concurrent.*; + +/** + * SSH-based node starter, returns tuple which contains hostname, success flag and error message + * if attempt was not successful. + */ +public interface IgniteNodeCallable extends Callable<GridTuple3<String, Boolean, String>> { + // No-op. +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeStartUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeStartUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeStartUtils.java new file mode 100644 index 0000000..c91ca21 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeStartUtils.java @@ -0,0 +1,391 @@ +/* + * 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 org.apache.ignite.*; +import org.apache.ignite.internal.util.typedef.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.lang.*; +import org.jetbrains.annotations.*; + +import java.io.*; +import java.util.*; +import java.util.concurrent.*; + +/** + * Util methods for {@code IgniteCluster.startNodes(..)} methods. + */ +public class IgniteNodeStartUtils { + /** Key for hostname. */ + public static final String HOST = "host"; + + /** Key for port number. */ + public static final String PORT = "port"; + + /** Key for username. */ + public static final String UNAME = "uname"; + + /** Key for password. */ + public static final String PASSWD = "passwd"; + + /** Key for private key file. */ + public static final String KEY = "key"; + + /** Key for number of nodes. */ + public static final String NODES = "nodes"; + + /** Key for Ignite home folder. */ + public static final String IGNITE_HOME = "igniteHome"; + + /** Key for configuration path. */ + public static final String CFG = "cfg"; + + /** Key for script path. */ + public static final String SCRIPT = "script"; + + /** Key for logger. */ + public static final String LOGGER = "logger"; + + /** Default connection timeout. */ + public static final int DFLT_TIMEOUT = 10000; + + /** Default maximum number of parallel connections. */ + public static final int DFLT_MAX_CONN = 5; + + /** Symbol that specifies range of IPs. */ + private static final String RANGE_SMB = "~"; + + /** Default port. */ + private static final int DFLT_PORT = 22; + + /** Default number of nodes. */ + private static final int DFLT_NODES = 1; + + /** Default configuration path. */ + private static final String DFLT_CFG = ""; + + /** Defaults section name. */ + private static final String DFLT_SECTION = "defaults"; + + /** + * Ensure singleton. + */ + private IgniteNodeStartUtils() { + // No-op. + } + + /** + * Parses INI file. + * + * @param file File. + * @return Tuple with host maps and default values. + * @throws IgniteCheckedException In case of error. + */ + public static IgniteBiTuple<Collection<Map<String, Object>>, Map<String, Object>> parseFile( + File file) throws IgniteCheckedException { + assert file != null; + assert file.exists(); + assert file.isFile(); + + BufferedReader br = null; + + int lineCnt = 1; + + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); + + String section = null; + + Collection<Map<String, Object>> hosts = new LinkedList<>(); + Map<String, Object> dflts = null; + Map<String, Object> props = null; + + for (String line; (line = br.readLine()) != null; lineCnt++) { + String l = line.trim(); + + if (l.isEmpty() || l.startsWith("#") || l.startsWith(";")) + continue; + + if (l.startsWith("[") && l.endsWith("]")) { + Map<String, Object> dfltsTmp = processSection(section, hosts, dflts, props); + + if (dfltsTmp != null) + dflts = dfltsTmp; + + props = new HashMap<>(); + + section = l.substring(1, l.length() - 1); + } + else if (l.contains("=")) { + if (section == null) + throw new IgniteCheckedException("Ignite ini format doesn't support unnamed section."); + + String key = l.substring(0, l.indexOf('=')); + String val = line.substring(line.indexOf('=') + 1); + + switch (key) { + case HOST: + case UNAME: + case PASSWD: + case IGNITE_HOME: + case CFG: + case SCRIPT: + props.put(key, val); + break; + + case PORT: + case NODES: + props.put(key, Integer.valueOf(val)); + break; + + case KEY: + props.put(KEY, new File(val)); + break; + } + } + else + throw new IgniteCheckedException("Failed to parse INI file (line " + lineCnt + ")."); + } + + Map<String, Object> dfltsTmp = processSection(section, hosts, dflts, props); + + if (dfltsTmp != null) + dflts = dfltsTmp; + + return F.t(hosts, dflts); + } + catch (IOException | NumberFormatException e) { + throw new IgniteCheckedException("Failed to parse INI file (line " + lineCnt + ").", e); + } + finally { + U.closeQuiet(br); + } + } + + /** + * Processes section of parsed INI file. + * + * @param section Name of the section. + * @param hosts Already parsed properties for sections excluding default. + * @param dflts Parsed properties for default section. + * @param props Current properties. + * @return Default properties if specified section is default, {@code null} otherwise. + * @throws IgniteCheckedException If INI file contains several default sections. + */ + private static Map<String, Object> processSection(String section, Collection<Map<String, Object>> hosts, + Map<String, Object> dflts, Map<String, Object> props) throws IgniteCheckedException { + if (section == null || props == null) + return null; + + if (DFLT_SECTION.equalsIgnoreCase(section)) { + if (dflts != null) + throw new IgniteCheckedException("Only one '" + DFLT_SECTION + "' section is allowed."); + + return props; + } + else { + hosts.add(props); + + return null; + } + } + + /** + * Makes specifications. + * + * @param hosts Host configurations. + * @param dflts Default values. + * @return Specification grouped by hosts. + * @throws IgniteCheckedException In case of error. + */ + @SuppressWarnings("ConstantConditions") + public static Map<String, Collection<IgniteRemoteStartSpecification>> specifications( + Collection<Map<String, Object>> hosts, @Nullable Map<String, Object> dflts) + throws IgniteCheckedException { + Map<String, Collection<IgniteRemoteStartSpecification>> specsMap = U.newHashMap(hosts.size()); + + IgniteRemoteStartSpecification dfltSpec = processDefaults(dflts); + + for (Map<String, Object> host : hosts) { + Collection<IgniteRemoteStartSpecification> specs = processHost(host, dfltSpec); + + for (IgniteRemoteStartSpecification spec : specs) + F.addIfAbsent(specsMap, spec.host(), new Callable<Collection<IgniteRemoteStartSpecification>>() { + @Override public Collection<IgniteRemoteStartSpecification> call() throws Exception { + return new HashSet<>(); + } + }).add(spec); + } + + return specsMap; + } + + /** + * Converts properties map to default specification. + * + * @param dflts Properties. + * @return Specification. + * @throws IgniteCheckedException If properties are invalid. + */ + private static IgniteRemoteStartSpecification processDefaults(@Nullable Map<String, Object> dflts) + throws IgniteCheckedException { + int port = DFLT_PORT; + String uname = System.getProperty("user.name"); + String passwd = null; + File key = null; + int nodes = DFLT_NODES; + String igniteHome = null; + String cfg = DFLT_CFG; + String script = null; + IgniteLogger log = null; + + if (dflts != null) { + if (dflts.get(PORT) != null) + port = (Integer)dflts.get(PORT); + + if (dflts.get(UNAME) != null) + uname = (String)dflts.get(UNAME); + + if (dflts.get(PASSWD) != null) + passwd = (String)dflts.get(PASSWD); + + if (dflts.get(KEY) != null) + key = (File)dflts.get(KEY); + + if (dflts.get(NODES) != null) + nodes = (Integer)dflts.get(NODES); + + if (dflts.get(IGNITE_HOME) != null) + igniteHome = (String)dflts.get(IGNITE_HOME); + + if (dflts.get(CFG) != null) + cfg = (String)dflts.get(CFG); + + if (dflts.get(SCRIPT) != null) + script = (String)dflts.get(SCRIPT); + + if (dflts.get(LOGGER) != null) + log = (IgniteLogger)dflts.get(LOGGER); + } + + if (port <= 0) + throw new IgniteCheckedException("Invalid port number: " + port); + + if (nodes <= 0) + throw new IgniteCheckedException("Invalid number of nodes: " + nodes); + + return new IgniteRemoteStartSpecification(null, port, uname, passwd, + key, nodes, igniteHome, cfg, script, log); + } + + /** + * Converts properties map to specification. + * + * @param props Properties. + * @param dfltSpec Default specification. + * @return Specification. + * @throws IgniteCheckedException If properties are invalid. + */ + private static Collection<IgniteRemoteStartSpecification> processHost(Map<String, Object> props, + IgniteRemoteStartSpecification dfltSpec) throws IgniteCheckedException { + assert props != null; + assert dfltSpec != null; + + if (props.get(HOST) == null) + throw new IgniteCheckedException("Host must be specified."); + + Set<String> hosts = expandHost((String)props.get(HOST)); + int port = props.get(PORT) != null ? (Integer)props.get(PORT) : dfltSpec.port(); + String uname = props.get(UNAME) != null ? (String)props.get(UNAME) : dfltSpec.username(); + String passwd = props.get(PASSWD) != null ? (String)props.get(PASSWD) : dfltSpec.password(); + File key = props.get(KEY) != null ? (File)props.get(KEY) : dfltSpec.key(); + int nodes = props.get(NODES) != null ? (Integer)props.get(NODES) : dfltSpec.nodes(); + String igniteHome = props.get(IGNITE_HOME) != null ? (String)props.get(IGNITE_HOME) : dfltSpec.igniteHome(); + String cfg = props.get(CFG) != null ? (String)props.get(CFG) : dfltSpec.configuration(); + String script = props.get(SCRIPT) != null ? (String)props.get(SCRIPT) : dfltSpec.script(); + + if (port<= 0) + throw new IgniteCheckedException("Invalid port number: " + port); + + if (nodes <= 0) + throw new IgniteCheckedException("Invalid number of nodes: " + nodes); + + if (passwd == null && key == null) + throw new IgniteCheckedException("Password or private key file must be specified."); + + if (passwd != null && key != null) + passwd = null; + + Collection<IgniteRemoteStartSpecification> specs = + new ArrayList<>(hosts.size()); + + for (String host : hosts) + specs.add(new IgniteRemoteStartSpecification(host, port, uname, passwd, + key, nodes, igniteHome, cfg, script, dfltSpec.logger())); + + return specs; + } + + /** + * Parses and expands range of IPs, if needed. Host names without the range + * returned as is. + * + * @param addr Host with or without `~` range. + * @return Set of individual host names (IPs). + * @throws IgniteCheckedException In case of error. + */ + public static Set<String> expandHost(String addr) throws IgniteCheckedException { + assert addr != null; + + Set<String> addrs = new HashSet<>(); + + if (addr.contains(RANGE_SMB)) { + String[] parts = addr.split(RANGE_SMB); + + if (parts.length != 2) + throw new IgniteCheckedException("Invalid IP range: " + addr); + + int lastDot = parts[0].lastIndexOf('.'); + + if (lastDot < 0) + throw new IgniteCheckedException("Invalid IP range: " + addr); + + String base = parts[0].substring(0, lastDot); + String begin = parts[0].substring(lastDot + 1); + String end = parts[1]; + + try { + int a = Integer.valueOf(begin); + int b = Integer.valueOf(end); + + if (a > b) + throw new IgniteCheckedException("Invalid IP range: " + addr); + + for (int i = a; i <= b; i++) + addrs.add(base + "." + i); + } + catch (NumberFormatException e) { + throw new IgniteCheckedException("Invalid IP range: " + addr, e); + } + } + else + addrs.add(addr); + + return addrs; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteRemoteStartSpecification.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteRemoteStartSpecification.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteRemoteStartSpecification.java new file mode 100644 index 0000000..b3f9bb1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteRemoteStartSpecification.java @@ -0,0 +1,279 @@ +/* + * 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 org.apache.ignite.*; +import org.apache.ignite.internal.util.typedef.*; +import org.jetbrains.annotations.*; + +import java.io.*; + +/** + * Host data. + */ +public class IgniteRemoteStartSpecification { + /** Hostname. */ + private final String host; + + /** Port number. */ + private final int port; + + /** Username. */ + private final String uname; + + /** Password. */ + private final String passwd; + + /** Private key file. */ + private final File key; + + /** Private key filename. */ + private final String keyName; + + /** Number of nodes to start. */ + private final int nodes; + + /** Ignite installation folder. */ + private String igniteHome; + + /** Configuration path. */ + private String cfg; + + /** Configuration filename. */ + private String cfgName; + + /** Script path. */ + private String script; + + /** Custom logger. */ + private IgniteLogger logger; + + /** Valid flag */ + private boolean valid; + + /** + * @param host Hostname. + * @param port Port number. + * @param uname Username. + * @param passwd Password (can be {@code null} if private key authentication is used). + * @param key Private key file path. + * @param nodes Number of nodes to start. + * @param igniteHome Ignite installation folder. + * @param cfg Configuration path. + * @param script Script path. + */ + public IgniteRemoteStartSpecification(@Nullable String host, int port, @Nullable String uname, + @Nullable String passwd, @Nullable File key, int nodes, @Nullable String igniteHome, + @Nullable String cfg, @Nullable String script) { + this(host, port, uname, passwd, key, nodes, igniteHome, cfg, script, null); + } + + /** + * @param host Hostname. + * @param port Port number. + * @param uname Username. + * @param passwd Password (can be {@code null} if private key authentication is used). + * @param key Private key file path. + * @param nodes Number of nodes to start. + * @param igniteHome Ignite installation folder. + * @param cfg Configuration path. + * @param script Script path. + * @param logger Custom logger. + */ + public IgniteRemoteStartSpecification(@Nullable String host, int port, @Nullable String uname, + @Nullable String passwd, @Nullable File key, int nodes, @Nullable String igniteHome, + @Nullable String cfg, @Nullable String script, @Nullable IgniteLogger logger) { + assert port > 0; + assert nodes > 0; + + this.host = !F.isEmpty(host) ? host : null; + this.port = port; + this.uname = !F.isEmpty(uname) ? uname : null; + this.passwd = !F.isEmpty(passwd) ? passwd : null; + this.key = key; + this.nodes = nodes; + this.igniteHome = !F.isEmpty(igniteHome) ? igniteHome : null; + this.cfg = !F.isEmpty(cfg) ? cfg : null; + cfgName = cfg == null ? null : shorten(cfg); + keyName = key == null ? "" : shorten(key.getAbsolutePath()); + this.script = !F.isEmpty(script) ? script : null; + this.logger = logger; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) return true; + + if (!(o instanceof IgniteRemoteStartSpecification)) return false; + + IgniteRemoteStartSpecification that = (IgniteRemoteStartSpecification)o; + + return (host == null ? that.host == null : host.equals(that.host)) && + (uname == null ? that.uname == null : uname.equals(that.uname)) && + (passwd == null ? that.passwd == null : passwd.equals(that.passwd)) && + (key == null ? that.key == null : key.equals(that.key)) && + (igniteHome == null ? that.igniteHome == null : igniteHome.equals(that.igniteHome)) && + (cfg == null ? that.cfg == null : cfg.equals(that.cfg)) && + (script == null ? that.script == null : script.equals(that.script)) && + port == that.port && nodes == that.nodes; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + int res = host == null ? 0 : host.hashCode(); + + res = 31 * res + (uname == null ? 0 : uname.hashCode()); + res = 31 * res + (passwd == null ? 0 : passwd.hashCode()); + res = 31 * res + (key == null ? 0 : key.hashCode()); + res = 31 * res + (igniteHome == null ? 0 : igniteHome.hashCode()); + res = 31 * res + (cfg == null ? 0 : cfg.hashCode()); + res = 31 * res + (script == null ? 0 : script.hashCode()); + res = 31 * res + port; + res = 31 * res + nodes; + + return res; + } + + /** + * Get filename from path. + * + * @param path Path. + * @return Filename. + */ + private static String shorten(String path) { + int idx1 = path.lastIndexOf('/'); + int idx2 = path.lastIndexOf('\\'); + int idx = Math.max(idx1, idx2); + + return idx == -1 ? path : path.substring(idx + 1); + } + + /** + * @return Hostname. + */ + public String host() { + return host; + } + + /** + * @return Port number. + */ + public int port() { + return port; + } + + /** + * @return Username. + */ + public String username() { + return uname; + } + + /** + * @return Password. + */ + public String password() { + return passwd; + } + + /** + * @return Private key file path. + */ + public File key() { + return key; + } + + /** + * @return Private key file name. + */ + public String keyName() { + return keyName; + } + + /** + * @return Number of nodes to start. + */ + public int nodes() { + return nodes; + } + + /** + * @return Ignite installation folder. + */ + public String igniteHome() { + return igniteHome; + } + + /** + * @return Configuration full path. + */ + public String configuration() { + return cfg; + } + + /** + * @return Configuration path short version - just file name. + */ + public String configurationName() { + return cfgName; + } + + /** + * @return Script path. + */ + public String script() { + return script; + } + + /** + * @return Custom logger. + */ + public IgniteLogger logger() { + return logger; + } + + /** + * @return Valid flag. + */ + public boolean valid() { + return valid; + } + + /** + * @param valid Valid flag. + */ + public void valid(boolean valid) { + this.valid = valid; + } + + /** + * Sets correct separator in paths. + * + * @param separator Separator. + */ + public void fixPaths(char separator) { + if (igniteHome != null) + igniteHome = igniteHome.replace('\\', separator).replace('/', separator); + + if (script != null) + script = script.replace('\\', separator).replace('/', separator); + + if (cfg != null) + cfg = cfg.replace('\\', separator).replace('/', separator); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessor.java index 3b68ee8..9f59fa2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessor.java @@ -30,5 +30,5 @@ public interface IgniteSshProcessor { * @param timeout Connection timeout. * @return {@link Callable} starting node using SSH. */ - public GridNodeCallable nodeStartCallable(GridRemoteStartSpecification spec, int timeout); + public IgniteNodeCallable nodeStartCallable(IgniteRemoteStartSpecification spec, int timeout); } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/test/bin/start-nodes-custom.bat ---------------------------------------------------------------------- diff --git a/modules/core/src/test/bin/start-nodes-custom.bat b/modules/core/src/test/bin/start-nodes-custom.bat index 51fbce0..554e9a6 100644 --- a/modules/core/src/test/bin/start-nodes-custom.bat +++ b/modules/core/src/test/bin/start-nodes-custom.bat @@ -18,5 +18,5 @@ set SCRIPT_DIR=%~dp0 if %SCRIPT_DIR:~-1,1% == \ set SCRIPT_DIR=%SCRIPT_DIR:~0,-1% :: -np option is mandatory, if it is not provided then we will wait for a user input, -:: as a result ggservice windows service hangs forever +:: as a result igniteservice windows service hangs forever call "%SCRIPT_DIR%\..\..\..\..\..\bin\ignite.bat" -v -np modules\core\src\test\config\spring-start-nodes-attr.xml http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/core/src/test/config/start-nodes.ini ---------------------------------------------------------------------- diff --git a/modules/core/src/test/config/start-nodes.ini b/modules/core/src/test/config/start-nodes.ini index 8f75e68..8b5922c 100644 --- a/modules/core/src/test/config/start-nodes.ini +++ b/modules/core/src/test/config/start-nodes.ini @@ -5,7 +5,7 @@ uname=uname1 passwd=passwd1 key=key1 nodes=1 -ggHome=ggHome1 +igniteHome=ggHome1 cfg=cfg1 script=script1 @@ -16,7 +16,7 @@ uname=uname2 passwd=passwd2 key=key2 nodes=2 -ggHome=ggHome2 +igniteHome=ggHome2 cfg=cfg2 script=script2 @@ -26,6 +26,6 @@ uname=uname3 passwd=passwd3 key=key3 nodes=3 -ggHome=ggHome3 +igniteHome=ggHome3 cfg=cfg3 script=script3 http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/67376020/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallableImpl.java ---------------------------------------------------------------------- diff --git a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallableImpl.java b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallableImpl.java deleted file mode 100644 index 044d11e..0000000 --- a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/GridNodeCallableImpl.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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.internal.*; -import org.apache.ignite.internal.util.lang.*; -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 GridNodeCallableImpl implements GridNodeCallable { - /** Default GridGain home path for Windows (taken from environment variable). */ - private static final String DFLT_IGNITE_HOME_WIN = "%IGNITE_HOME%"; - - /** Default GridGain home path for Linux (taken from environment variable). */ - private static final String DFLT_IGNITE_HOME_LINUX = "$IGNITE_HOME"; - - /** Default start script path for Windows. */ - private static final String DFLT_SCRIPT_WIN = "bin\\ignite.bat -v -np"; - - /** Default start script path for Linux. */ - private static final String DFLT_SCRIPT_LINUX = "bin/ignite.sh -v"; - - /** - * Logs folder for Windows. - * Folder for linux is configured in {@code ignite-log4j.xml}. - */ - private static final String LOG_DIR_WIN = "work\\log"; - - /** Windows service executable. */ - private static final String SVC_EXE = "bin\\include\\ggservice.exe"; - - /** 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 GridRemoteStartSpecification spec; - - /** Connection timeout. */ - private final int timeout; - - /** Logger. */ - @IgniteLoggerResource - private IgniteLogger log; - - /** - * Required by Externalizable. - */ - public GridNodeCallableImpl() { - spec = null; - timeout = 0; - - assert false; - } - - /** - * Constructor. - * - * @param spec Specification. - * @param timeout Connection timeout. - */ - public GridNodeCallableImpl(GridRemoteStartSpecification spec, int timeout) { - assert spec != null; - - this.spec = spec; - this.timeout = timeout; - } - - /** {@inheritDoc} */ - @Override public GridTuple3<String, Boolean, String> 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 ggHome = spec.ggHome(); - - if (ggHome == null) - ggHome = win ? DFLT_IGNITE_HOME_WIN : DFLT_IGNITE_HOME_LINUX; - - String script = spec.script(); - - if (script == null) - script = win ? DFLT_SCRIPT_WIN : 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) { - String logDir = ggHome + '\\' + LOG_DIR_WIN; - String tmpDir = env(ses, "%TMP%", logDir); - String scriptOutputDir = tmpDir + "\\gridgain-startNodes"; - - shell(ses, "mkdir " + logDir); - shell(ses, "mkdir " + scriptOutputDir); - - UUID id = UUID.randomUUID(); - - String svcName = "GridGain-" + id; - String svcPath = ggHome + '\\' + SVC_EXE; - - startNodeCmd = new SB(). - a("cmd /c if exist \"").a(svcPath).a("\""). - a(" sc create ").a(svcName). - a(" binPath= \"").a(svcPath).a("\""). - a(" && "). - a("sc start ").a(svcName). - a(" ").a(svcName). - a(" \"").a(ggHome).a('\\').a(script). - a(" ").a(cfg).a("\""). - a(" \"").a(logDir).a("\\gridgain.").a(id). - a(".log\" > ").a(scriptOutputDir).a("\\").a(scriptOutputFileName). - toString(); - } - 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 + "gridgain-startNodes"; - - shell(ses, "mkdir " + scriptOutputDir); - - // Mac os don't support ~ in double quotes. Trying get home path from remote system. - if (ggHome.startsWith("~")) { - String homeDir = env(ses, "$HOME", "~"); - - ggHome = ggHome.replaceFirst("~", homeDir); - } - - startNodeCmd = new SB(). - // Console output is consumed, started nodes must use Grid file appenders for log. - a("nohup "). - a("\"").a(ggHome).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 GridTuple3<>(spec.host(), true, null); - } - catch (IgniteInterruptedCheckedException e) { - return new GridTuple3<>(spec.host(), false, e.getMessage()); - } - catch (Exception e) { - return new GridTuple3<>(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 org.apache.ignite.internal.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(); - } - } - - /** - * 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 GridNodeCallable 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/67376020/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallableImpl.java ---------------------------------------------------------------------- diff --git a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallableImpl.java b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallableImpl.java new file mode 100644 index 0000000..9d7d091 --- /dev/null +++ b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteNodeCallableImpl.java @@ -0,0 +1,344 @@ +/* + * 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.internal.*; +import org.apache.ignite.internal.util.lang.*; +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 IgniteNodeCallableImpl implements IgniteNodeCallable { + /** 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 Windows. */ + private static final String DFLT_SCRIPT_WIN = "bin\\ignite.bat -v -np"; + + /** Default start script path for Linux. */ + private static final String DFLT_SCRIPT_LINUX = "bin/ignite.sh -v"; + + /** + * Logs folder for Windows. + * Folder for linux is configured in {@code ignite-log4j.xml}. + */ + private static final String LOG_DIR_WIN = "work\\log"; + + /** Windows service executable. */ + private static final String SVC_EXE = "bin\\include\\igniteservice.exe"; + + /** 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. */ + @IgniteLoggerResource + private IgniteLogger log; + + /** + * Required by Externalizable. + */ + public IgniteNodeCallableImpl() { + spec = null; + timeout = 0; + + assert false; + } + + /** + * Constructor. + * + * @param spec Specification. + * @param timeout Connection timeout. + */ + public IgniteNodeCallableImpl(IgniteRemoteStartSpecification spec, int timeout) { + assert spec != null; + + this.spec = spec; + this.timeout = timeout; + } + + /** {@inheritDoc} */ + @Override public GridTuple3<String, Boolean, String> 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 = win ? DFLT_SCRIPT_WIN : 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) { + String logDir = igniteHome + '\\' + LOG_DIR_WIN; + String tmpDir = env(ses, "%TMP%", logDir); + String scriptOutputDir = tmpDir + "\\ignite-startNodes"; + + shell(ses, "mkdir " + logDir); + shell(ses, "mkdir " + scriptOutputDir); + + UUID id = UUID.randomUUID(); + + String svcName = "Ignite-" + id; + String svcPath = igniteHome + '\\' + SVC_EXE; + + startNodeCmd = new SB(). + a("cmd /c if exist \"").a(svcPath).a("\""). + a(" sc create ").a(svcName). + a(" binPath= \"").a(svcPath).a("\""). + a(" && "). + a("sc start ").a(svcName). + a(" ").a(svcName). + a(" \"").a(igniteHome).a('\\').a(script). + a(" ").a(cfg).a("\""). + a(" \"").a(logDir).a("\\ignite.").a(id). + a(".log\" > ").a(scriptOutputDir).a("\\").a(scriptOutputFileName). + toString(); + } + 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 GridTuple3<>(spec.host(), true, null); + } + catch (IgniteInterruptedCheckedException e) { + return new GridTuple3<>(spec.host(), false, e.getMessage()); + } + catch (Exception e) { + return new GridTuple3<>(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 org.apache.ignite.internal.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(); + } + } + + /** + * 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 IgniteNodeCallable 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/67376020/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessorImpl.java b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessorImpl.java index 4d867c0..723ce35 100644 --- a/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessorImpl.java +++ b/modules/ssh/src/main/java/org/apache/ignite/internal/util/nodestart/IgniteSshProcessorImpl.java @@ -22,7 +22,7 @@ package org.apache.ignite.internal.util.nodestart; */ public class IgniteSshProcessorImpl implements IgniteSshProcessor { /** {@inheritDoc} */ - @Override public GridNodeCallable nodeStartCallable(GridRemoteStartSpecification spec, int timeout) { - return new GridNodeCallableImpl(spec, timeout); + @Override public IgniteNodeCallable nodeStartCallable(IgniteRemoteStartSpecification spec, int timeout) { + return new IgniteNodeCallableImpl(spec, timeout); } }