diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/AbstractCliCommandInvoker.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/AbstractCliCommandInvoker.java
new file mode 100644
index 0000000000000..8db6425db0b5a
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/AbstractCliCommandInvoker.java
@@ -0,0 +1,125 @@
+/*
+ * 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.commandline;
+
+import java.net.URL;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import javax.cache.configuration.Factory;
+import javax.net.ssl.SSLContext;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.management.api.Command;
+import org.apache.ignite.internal.management.api.CommandInvoker;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.spring.IgniteSpringHelperImpl;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.ssl.SslContextFactory;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * Adapter of new management API command for legacy {@code control.sh} execution flow.
+ */
+public abstract class AbstractCliCommandInvoker extends CommandInvoker
+ implements AutoCloseable {
+ /** */
+ protected final ConnectionAndSslParameters args;
+
+ /** */
+ protected final Function pwdReader;
+
+ /** */
+ protected AbstractCliCommandInvoker(
+ Command cmd,
+ ConnectionAndSslParameters args,
+ Function pwdReader
+ ) {
+ super(cmd, args.commandArg(), null);
+
+ this.args = args;
+ this.pwdReader = pwdReader;
+ }
+
+ /** @return Message text to show user for. {@code null} means that confirmantion is not required. */
+ public String confirmationPrompt() {
+ return cmd.confirmationPrompt(arg);
+ }
+
+ /** */
+ public abstract R invokeBeforeNodeStart(Consumer printer) throws Exception;
+
+ /**
+ * @param args Commond args.
+ * @return Ssl support factory.
+ */
+ protected Factory createSslSupportFactory(ConnectionAndSslParameters args) throws IgniteCheckedException {
+ if (!F.isEmpty(args.sslKeyStorePath()) && !F.isEmpty(args.sslFactoryConfigPath())) {
+ throw new IllegalArgumentException("Incorrect SSL configuration. " +
+ "SSL factory config path should not be specified simultaneously with other SSL options like keystore path.");
+ }
+
+ if (!F.isEmpty(args.sslFactoryConfigPath())) {
+ URL springCfg = IgniteUtils.resolveSpringUrl(args.sslFactoryConfigPath());
+
+ ApplicationContext ctx = IgniteSpringHelperImpl.applicationContext(springCfg);
+
+ return (Factory)ctx.getBean(Factory.class);
+ }
+
+ SslContextFactory factory = new SslContextFactory();
+
+ if (args.sslProtocol().length > 1)
+ factory.setProtocols(args.sslProtocol());
+ else
+ factory.setProtocol(args.sslProtocol()[0]);
+
+ factory.setKeyAlgorithm(args.sslKeyAlgorithm());
+ factory.setCipherSuites(args.getSslCipherSuites());
+ factory.setKeyStoreFilePath(args.sslKeyStorePath());
+
+ if (args.sslKeyStorePassword() != null)
+ factory.setKeyStorePassword(args.sslKeyStorePassword());
+ else {
+ char[] keyStorePwd = pwdReader.apply("SSL keystore password: ");
+
+ args.sslKeyStorePassword(keyStorePwd);
+ factory.setKeyStorePassword(keyStorePwd);
+ }
+
+ factory.setKeyStoreType(args.sslKeyStoreType());
+
+ if (F.isEmpty(args.sslTrustStorePath()))
+ factory.setTrustManagers(SslContextFactory.getDisabledTrustManager());
+ else {
+ factory.setTrustStoreFilePath(args.sslTrustStorePath());
+
+ if (args.sslTrustStorePassword() != null)
+ factory.setTrustStorePassword(args.sslTrustStorePassword());
+ else {
+ char[] trustStorePwd = pwdReader.apply("SSL truststore password: ");
+
+ args.sslTrustStorePassword(trustStorePwd);
+ factory.setTrustStorePassword(trustStorePwd);
+ }
+
+ factory.setTrustStoreType(args.sslTrustStoreType());
+ }
+
+ return factory;
+ }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
index 1a6e1d19cb95a..e6d7c8517b8e6 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/ArgumentParser.java
@@ -48,11 +48,13 @@
import org.apache.ignite.ssl.SslContextFactory;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
+import static org.apache.ignite.configuration.ConnectorConfiguration.DFLT_TCP_PORT;
import static org.apache.ignite.internal.client.GridClientConfiguration.DFLT_PING_INTERVAL;
import static org.apache.ignite.internal.client.GridClientConfiguration.DFLT_PING_TIMEOUT;
import static org.apache.ignite.internal.commandline.CommandHandler.DFLT_HOST;
import static org.apache.ignite.internal.commandline.CommandHandler.DFLT_PORT;
import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME;
+import static org.apache.ignite.internal.commandline.CommandHandler.useConnectorConnection;
import static org.apache.ignite.internal.commandline.argument.parser.CLIArgument.optionalArg;
import static org.apache.ignite.internal.management.api.CommandUtils.CMD_WORDS_DELIM;
import static org.apache.ignite.internal.management.api.CommandUtils.NAME_PREFIX;
@@ -184,7 +186,7 @@ public ArgumentParser(IgniteLogger log, IgniteCommandRegistry registry) {
"Whenever possible, use interactive prompt for password (just discard %s option).", name, name));
arg(CMD_HOST, "HOST_OR_IP", String.class, DFLT_HOST);
- arg(CMD_PORT, "PORT", Integer.class, DFLT_PORT, PORT_VALIDATOR);
+ arg(CMD_PORT, "PORT", Integer.class, useConnectorConnection() ? DFLT_TCP_PORT : DFLT_PORT, PORT_VALIDATOR);
arg(CMD_USER, "USER", String.class, null);
arg(CMD_PASSWORD, "PASSWORD", String.class, null, (BiConsumer)securityWarn);
arg(CMD_PING_INTERVAL, "PING_INTERVAL", Long.class, DFLT_PING_INTERVAL, POSITIVE_LONG);
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliCommandInvoker.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliCommandInvoker.java
index 816910569fa96..d06c4706f5a48 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliCommandInvoker.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliCommandInvoker.java
@@ -17,208 +17,89 @@
package org.apache.ignite.internal.commandline;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.Collection;
-import java.util.List;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.ignite.internal.client.GridClient;
-import org.apache.ignite.internal.client.GridClientBeforeNodeStart;
-import org.apache.ignite.internal.client.GridClientCompute;
-import org.apache.ignite.internal.client.GridClientConfiguration;
-import org.apache.ignite.internal.client.GridClientDisconnectedException;
-import org.apache.ignite.internal.client.GridClientException;
-import org.apache.ignite.internal.client.GridClientFactory;
+import java.util.function.Function;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.client.SslMode;
+import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.internal.client.GridClientNode;
+import org.apache.ignite.internal.client.GridClientNodeStateBeforeStart;
+import org.apache.ignite.internal.client.thin.TcpIgniteClient;
import org.apache.ignite.internal.dto.IgniteDataTransferObject;
import org.apache.ignite.internal.management.api.BeforeNodeStartCommand;
import org.apache.ignite.internal.management.api.Command;
-import org.apache.ignite.internal.management.api.CommandInvoker;
-import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.management.api.CommandUtils;
import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.lang.IgniteBiTuple;
-
-import static org.apache.ignite.internal.commandline.CommandHandler.DFLT_HOST;
+import org.jetbrains.annotations.Nullable;
/**
- * Adapter of new management API command for legacy {@code control.sh} execution flow.
+ * Adapter of new management API command for {@code control.sh} execution flow.
*/
-public class CliCommandInvoker extends CommandInvoker implements AutoCloseable {
- /** Client configuration. */
- private final GridClientConfiguration clientCfg;
-
+public class CliCommandInvoker extends AbstractCliCommandInvoker {
/** Client. */
- private GridClient client;
+ private final IgniteClient client;
/** @param cmd Command to execute. */
- public CliCommandInvoker(Command cmd, A arg, GridClientConfiguration clientCfg) {
- super(cmd, arg, null);
- this.clientCfg = clientCfg;
- }
-
- /**
- * @return Message text to show user for. {@code null} means that confirmantion is not required.
- */
- public String confirmationPrompt() {
- return cmd.confirmationPrompt(arg);
+ public CliCommandInvoker(
+ Command cmd,
+ ConnectionAndSslParameters args,
+ Function pwdReader
+ ) throws IgniteCheckedException {
+ super(cmd, args, pwdReader);
+
+ client = Ignition.startClient(clientConfiguration(args));
}
- /** */
- public R invokeBeforeNodeStart(Consumer printer) throws Exception {
- try (GridClientBeforeNodeStart client = startClientBeforeNodeStart(clientCfg)) {
- return ((BeforeNodeStartCommand)cmd).execute(client, arg, printer);
- }
- catch (GridClientDisconnectedException e) {
- throw new GridClientException(e.getCause());
- }
+ /** {@inheritDoc} */
+ @Override protected GridClientNode defaultNode() {
+ return CommandUtils.clusterToClientNode(client.cluster().forOldest().node());
}
/** {@inheritDoc} */
- @Override protected GridClientNode defaultNode() throws GridClientException {
- GridClientNode node;
-
- // Prefer node from connect string.
- final String cfgAddr = clientCfg.getServers().iterator().next();
-
- String[] parts = cfgAddr.split(":");
-
- if (DFLT_HOST.equals(parts[0])) {
- InetAddress addr;
-
- try {
- addr = IgniteUtils.getLocalHost();
- }
- catch (IOException e) {
- throw new GridClientException("Can't get localhost name.", e);
- }
-
- if (addr.isLoopbackAddress())
- throw new GridClientException("Can't find localhost name.");
-
- String origAddr = addr.getHostName() + ":" + parts[1];
-
- node = listHosts(client()).filter(tuple -> origAddr.equals(tuple.get2())).findFirst().map(IgniteBiTuple::get1).orElse(null);
-
- if (node == null)
- node = listHostsByClientNode(client()).filter(tuple -> tuple.get2().size() == 1 && cfgAddr.equals(tuple.get2().get(0))).
- findFirst().map(IgniteBiTuple::get1).orElse(null);
- }
- else
- node = listHosts(client()).filter(tuple -> cfgAddr.equals(tuple.get2())).findFirst().map(IgniteBiTuple::get1).orElse(null);
-
- // Otherwise choose random node.
- if (node == null)
- node = balancedNode(client().compute());
-
- return node;
+ @Override protected @Nullable IgniteClient client() {
+ return client;
}
/** {@inheritDoc} */
- @Override protected GridClient client() throws GridClientException {
- if (client != null && client.connected())
- return client;
-
- client = GridClientFactory.start(clientCfg);
-
- // If connection is unsuccessful, fail before doing any operations:
- if (!client.connected()) {
- GridClientException lastErr = client.checkLastError();
-
- try {
- client.close();
- }
- catch (Throwable e) {
- lastErr.addSuppressed(e);
+ @Override public R invokeBeforeNodeStart(Consumer printer) throws Exception {
+ return ((BeforeNodeStartCommand)cmd).execute(new GridClientNodeStateBeforeStart() {
+ @Override public void stopWarmUp() {
+ ((TcpIgniteClient)client).stopWarmUp();
}
-
- throw lastErr;
- }
-
- return client;
+ }, arg, printer);
}
/** {@inheritDoc} */
@Override public void close() {
- if (client != null)
- client.close();
+ client.close();
}
/**
- * Method to create thin client for communication with node before it starts.
- * If node has already started, there will be an error.
- *
- * @param clientCfg Thin client configuration.
- * @return Grid thin client instance which is already connected to node before it starts.
- * @throws Exception If error occur.
+ * @param args Common arguments.
+ * @return Thin client configuration to connect to cluster.
+ * @throws IgniteCheckedException If error occur.
*/
- private static GridClientBeforeNodeStart startClientBeforeNodeStart(
- GridClientConfiguration clientCfg
- ) throws Exception {
- GridClientBeforeNodeStart client = GridClientFactory.startBeforeNodeStart(clientCfg);
-
- // If connection is unsuccessful, fail before doing any operations:
- if (!client.connected()) {
- GridClientException lastErr = client.checkLastError();
+ private ClientConfiguration clientConfiguration(
+ ConnectionAndSslParameters args
+ ) throws IgniteCheckedException {
+ ClientConfiguration clientCfg = new ClientConfiguration();
- try {
- client.close();
- }
- catch (Throwable e) {
- lastErr.addSuppressed(e);
- }
+ clientCfg.setAddresses(args.host() + ":" + args.port());
- throw lastErr;
+ if (!F.isEmpty(args.userName())) {
+ clientCfg.setUserName(args.userName());
+ clientCfg.setUserPassword(args.password());
}
- return client;
- }
-
- /**
- * @param client Client.
- * @return List of hosts.
- */
- private static Stream> listHosts(GridClient client) throws GridClientException {
- return client.compute()
- .nodes(GridClientNode::connectable)
- .stream()
- .flatMap(node -> Stream.concat(
- node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
- node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
- ).map(addr -> new IgniteBiTuple<>(node, addr + ":" + node.tcpPort())));
- }
-
- /**
- * @param client Client.
- * @return List of hosts.
- */
- private static Stream>> listHostsByClientNode(
- GridClient client
- ) throws GridClientException {
- return client.compute().nodes(GridClientNode::connectable).stream()
- .map(
- node -> new IgniteBiTuple<>(
- node,
- Stream.concat(
- node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
- node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
- )
- .map(addr -> addr + ":" + node.tcpPort()).collect(Collectors.toList())
- )
- );
- }
-
- /**
- * @param compute instance
- * @return balanced node
- */
- private static GridClientNode balancedNode(GridClientCompute compute) throws GridClientException {
- Collection nodes = compute.nodes(GridClientNode::connectable);
+ if (!F.isEmpty(args.sslKeyStorePath()) || !F.isEmpty(args.sslFactoryConfigPath())) {
+ clientCfg.setSslContextFactory(createSslSupportFactory(args));
+ clientCfg.setSslMode(SslMode.REQUIRED);
+ }
- if (F.isEmpty(nodes))
- throw new GridClientDisconnectedException("Connectable node not found", null);
+ clientCfg.setClusterDiscoveryEnabled(false);
- return compute.balancer().balancedNode(nodes);
+ return clientCfg;
}
}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliGridClientCommandInvoker.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliGridClientCommandInvoker.java
new file mode 100644
index 0000000000000..82136772bc2c9
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CliGridClientCommandInvoker.java
@@ -0,0 +1,280 @@
+/*
+ * 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.commandline;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientBeforeNodeStart;
+import org.apache.ignite.internal.client.GridClientCompute;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.client.GridClientDisconnectedException;
+import org.apache.ignite.internal.client.GridClientException;
+import org.apache.ignite.internal.client.GridClientFactory;
+import org.apache.ignite.internal.client.GridClientNode;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.management.api.BeforeNodeStartCommand;
+import org.apache.ignite.internal.management.api.Command;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.plugin.security.SecurityCredentials;
+import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider;
+import org.apache.ignite.plugin.security.SecurityCredentialsProvider;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.internal.commandline.CommandHandler.DFLT_HOST;
+
+/**
+ * Adapter of new management API command for legacy {@code control.sh} execution flow.
+ */
+public class CliGridClientCommandInvoker extends AbstractCliCommandInvoker {
+ /** */
+ private final GridClientConfiguration clientCfg;
+
+ /** Client. */
+ private final GridClient client;
+
+ /** @param cmd Command to execute. */
+ public CliGridClientCommandInvoker(
+ Command cmd,
+ ConnectionAndSslParameters args,
+ Function pwdReader
+ ) throws Exception {
+ super(cmd, args, pwdReader);
+
+ clientCfg = clientConfiguration(args);
+
+ if (args.command() instanceof BeforeNodeStartCommand) {
+ client = null;
+
+ return;
+ }
+
+ client = GridClientFactory.start(clientCfg);
+
+ // If connection is unsuccessful, fail before doing any operations:
+ if (!client.connected()) {
+ GridClientException lastErr = client.checkLastError();
+
+ try {
+ client.close();
+ }
+ catch (Throwable e) {
+ lastErr.addSuppressed(e);
+ }
+
+ throw lastErr;
+ }
+ }
+
+ /** */
+ /** {@inheritDoc} */
+ @Override public R invokeBeforeNodeStart(Consumer printer) throws Exception {
+ try (GridClientBeforeNodeStart client = startClientBeforeNodeStart(clientCfg)) {
+ return ((BeforeNodeStartCommand)cmd).execute(client.beforeStartState(), arg, printer);
+ }
+ catch (GridClientDisconnectedException e) {
+ throw new GridClientException(e.getCause());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override protected GridClientNode defaultNode() throws GridClientException {
+ GridClientNode node;
+
+ // Prefer node from connect string.
+ final String cfgAddr = clientCfg.getServers().iterator().next();
+
+ String[] parts = cfgAddr.split(":");
+
+ if (DFLT_HOST.equals(parts[0])) {
+ InetAddress addr;
+
+ try {
+ addr = IgniteUtils.getLocalHost();
+ }
+ catch (IOException e) {
+ throw new GridClientException("Can't get localhost name.", e);
+ }
+
+ if (addr.isLoopbackAddress())
+ throw new GridClientException("Can't find localhost name.");
+
+ String origAddr = addr.getHostName() + ":" + parts[1];
+
+ node = listHosts(gridClient()).filter(tuple -> origAddr.equals(tuple.get2())).findFirst().map(IgniteBiTuple::get1).orElse(null);
+
+ if (node == null)
+ node = listHostsByClientNode(gridClient()).filter(tuple -> tuple.get2().size() == 1 && cfgAddr.equals(tuple.get2().get(0))).
+ findFirst().map(IgniteBiTuple::get1).orElse(null);
+ }
+ else
+ node = listHosts(gridClient()).filter(tuple -> cfgAddr.equals(tuple.get2())).findFirst().map(IgniteBiTuple::get1).orElse(null);
+
+ // Otherwise choose random node.
+ if (node == null)
+ node = balancedNode(gridClient().compute());
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected GridClient gridClient() {
+ return client;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ IgniteUtils.closeQuiet(client);
+ }
+
+ /**
+ * Method to create thin client for communication with node before it starts.
+ * If node has already started, there will be an error.
+ *
+ * @param clientCfg Thin client configuration.
+ * @return Grid thin client instance which is already connected to node before it starts.
+ * @throws Exception If error occur.
+ */
+ private static GridClientBeforeNodeStart startClientBeforeNodeStart(
+ GridClientConfiguration clientCfg
+ ) throws Exception {
+ GridClientBeforeNodeStart client = GridClientFactory.startBeforeNodeStart(clientCfg);
+
+ // If connection is unsuccessful, fail before doing any operations:
+ if (!client.connected()) {
+ GridClientException lastErr = client.checkLastError();
+
+ try {
+ client.close();
+ }
+ catch (Throwable e) {
+ lastErr.addSuppressed(e);
+ }
+
+ throw lastErr;
+ }
+
+ return client;
+ }
+
+ /**
+ * @param client Client.
+ * @return List of hosts.
+ */
+ private static Stream> listHosts(GridClient client) throws GridClientException {
+ return client.compute()
+ .nodes(GridClientNode::connectable)
+ .stream()
+ .flatMap(node -> Stream.concat(
+ node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
+ node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
+ ).map(addr -> new IgniteBiTuple<>(node, addr + ":" + node.tcpPort())));
+ }
+
+ /**
+ * @param client Client.
+ * @return List of hosts.
+ */
+ private static Stream>> listHostsByClientNode(
+ GridClient client
+ ) throws GridClientException {
+ return client.compute().nodes(GridClientNode::connectable).stream()
+ .map(
+ node -> new IgniteBiTuple<>(
+ node,
+ Stream.concat(
+ node.tcpAddresses() == null ? Stream.empty() : node.tcpAddresses().stream(),
+ node.tcpHostNames() == null ? Stream.empty() : node.tcpHostNames().stream()
+ )
+ .map(addr -> addr + ":" + node.tcpPort()).collect(Collectors.toList())
+ )
+ );
+ }
+
+ /**
+ * @param compute instance
+ * @return balanced node
+ */
+ private static GridClientNode balancedNode(GridClientCompute compute) throws GridClientException {
+ Collection nodes = compute.nodes(GridClientNode::connectable);
+
+ if (F.isEmpty(nodes))
+ throw new GridClientDisconnectedException("Connectable node not found", null);
+
+ return compute.balancer().balancedNode(nodes);
+ }
+
+ /**
+ * @param args Common arguments.
+ * @return Thin client configuration to connect to cluster.
+ * @throws IgniteCheckedException If error occur.
+ */
+ private GridClientConfiguration clientConfiguration(
+ ConnectionAndSslParameters args
+ ) throws IgniteCheckedException {
+ GridClientConfiguration clientCfg = new GridClientConfiguration();
+
+ clientCfg.setPingInterval(args.pingInterval());
+
+ clientCfg.setPingTimeout(args.pingTimeout());
+
+ clientCfg.setServers(Collections.singletonList(args.host() + ":" + args.port()));
+
+ if (!F.isEmpty(args.userName()))
+ clientCfg.setSecurityCredentialsProvider(getSecurityCredentialsProvider(args.userName(), args.password(), clientCfg));
+
+ if (!F.isEmpty(args.sslKeyStorePath()) || !F.isEmpty(args.sslFactoryConfigPath()))
+ clientCfg.setSslContextFactory(createSslSupportFactory(args));
+
+ return clientCfg;
+ }
+
+ /**
+ * @param userName User name for authorization.
+ * @param password Password for authorization.
+ * @param clientCfg Thin client configuration to connect to cluster.
+ * @return Security credentials provider with usage of given user name and password.
+ * @throws IgniteCheckedException If error occur.
+ */
+ @NotNull private SecurityCredentialsProvider getSecurityCredentialsProvider(
+ String userName,
+ String password,
+ GridClientConfiguration clientCfg
+ ) throws IgniteCheckedException {
+ SecurityCredentialsProvider securityCredential = clientCfg.getSecurityCredentialsProvider();
+
+ if (securityCredential == null)
+ return new SecurityCredentialsBasicProvider(new SecurityCredentials(userName, password));
+
+ final SecurityCredentials credential = securityCredential.credentials();
+ credential.setLogin(userName);
+ credential.setPassword(password);
+
+ return securityCredential;
+ }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
index 98c27b87667b1..93a94db8e3679 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
@@ -18,7 +18,6 @@
package org.apache.ignite.internal.commandline;
import java.lang.reflect.Field;
-import java.net.URL;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -31,15 +30,15 @@
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
-import javax.cache.configuration.Factory;
-import javax.net.ssl.SSLContext;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLogger;
-import org.apache.ignite.IgniteSystemProperties;
+import org.apache.ignite.client.ClientAuthenticationException;
+import org.apache.ignite.client.ClientConnectionException;
+import org.apache.ignite.configuration.ClientConnectorConfiguration;
+import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.internal.client.GridClientAuthenticationException;
import org.apache.ignite.internal.client.GridClientClosedException;
-import org.apache.ignite.internal.client.GridClientConfiguration;
import org.apache.ignite.internal.client.GridClientDisconnectedException;
import org.apache.ignite.internal.client.GridClientHandshakeException;
import org.apache.ignite.internal.client.GridServerUnreachableException;
@@ -58,23 +57,17 @@
import org.apache.ignite.internal.management.api.HelpCommand;
import org.apache.ignite.internal.management.api.Positional;
import org.apache.ignite.internal.management.cache.CacheCommand;
-import org.apache.ignite.internal.util.IgniteUtils;
-import org.apache.ignite.internal.util.spring.IgniteSpringHelperImpl;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteExperimental;
-import org.apache.ignite.plugin.security.SecurityCredentials;
-import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider;
-import org.apache.ignite.plugin.security.SecurityCredentialsProvider;
import org.apache.ignite.ssl.SslContextFactory;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.context.ApplicationContext;
import static java.lang.System.lineSeparator;
import static java.util.Objects.nonNull;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND;
+import static org.apache.ignite.IgniteSystemProperties.getBoolean;
import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
import static org.apache.ignite.internal.commandline.ArgumentParser.CMD_AUTO_CONFIRMATION;
@@ -131,7 +124,13 @@ public class CommandHandler {
public static final String DFLT_HOST = "127.0.0.1";
/** */
- public static final int DFLT_PORT = 11211;
+ public static final int DFLT_PORT = 10800;
+
+ /**
+ * System property for backward compatibility. Will be removed in future releases.
+ * Enables connection to {@link ConnectorConfiguration REST connector} and forcefully sets default port to 11211.
+ */
+ public static final String IGNITE_CONTROL_UTILITY_USE_CONNECTOR_CONNECTION = "IGNITE_CONTROL_UTILITY_USE_CONNECTOR_CONNECTION";
/** */
private final Scanner in = new Scanner(System.in);
@@ -253,6 +252,12 @@ public int execute(List rawArgs) {
ConnectionAndSslParameters args = new ArgumentParser(logger, registry).parseAndValidate(rawArgs);
+ if (args.command() instanceof HelpCommand) {
+ printUsage(logger, args.cmdPath().peekLast());
+
+ return EXIT_CODE_OK;
+ }
+
cmdName = toFormattedCommandName(args.cmdPath().peekLast().getClass()).toUpperCase();
int tryConnectMaxCnt = 3;
@@ -262,9 +267,9 @@ public int execute(List rawArgs) {
boolean credentialsRequested = false;
while (true) {
- try (
- CliCommandInvoker invoker =
- new CliCommandInvoker<>(args.command(), args.commandArg(), getClientConfiguration(args))
+ try (AbstractCliCommandInvoker invoker = useConnectorConnection() ?
+ new CliGridClientCommandInvoker<>(args.command(), args, this::requestPasswordFromConsole) :
+ new CliCommandInvoker<>(args.command(), args, this::requestPasswordFromConsole)
) {
if (!invoker.prepare(logger::info))
return EXIT_CODE_OK;
@@ -286,9 +291,7 @@ public int execute(List rawArgs) {
if (deprecationMsg != null)
logger.warning(deprecationMsg);
- if (args.command() instanceof HelpCommand)
- printUsage(logger, args.cmdPath().peekLast());
- else if (args.command() instanceof BeforeNodeStartCommand)
+ if (args.command() instanceof BeforeNodeStartCommand)
lastOperationRes = invoker.invokeBeforeNodeStart(logger::info);
else
lastOperationRes = invoker.invoke(logger::info, args.verbose());
@@ -348,8 +351,18 @@ else if (args.command() instanceof BeforeNodeStartCommand)
if (isSSLMisconfigurationError(cause))
e = cause;
- logger.error("Connection to cluster failed. " + errorMessage(e));
+ String errMsg = errorMessage(e);
+
+ logger.error("Connection to cluster failed. " + errMsg);
+ if (errMsg.contains("Channel is closed") || isSSLMisconfigurationError(cause)) {
+ logger.error("Make sure you are connecting to the client connector (configured on a node via '" +
+ ClientConnectorConfiguration.class.getName() + "'). Connection to the REST connector was " +
+ "deprecated and will be removed for the control utility in future releases. Set up the '" +
+ IGNITE_CONTROL_UTILITY_USE_CONNECTOR_CONNECTION + "' system property to the 'true' to " +
+ "forcefully connect to the REST connector (configured on a node via '" +
+ ConnectorConfiguration.class.getName() + "'). ");
+ }
}
logger.info("Command [" + cmdName + "] finished with code: " + EXIT_CODE_CONNECTION_FAILED);
@@ -446,6 +459,9 @@ private boolean isSSLMisconfigurationError(Throwable e) {
* to secured cluster.
*/
private boolean isConnectionClosedSilentlyException(Throwable e) {
+ if (e instanceof ClientConnectionException && "Channel is closed".equals(e.getMessage()))
+ return true;
+
if (!(e instanceof GridClientDisconnectedException))
return false;
@@ -495,130 +511,6 @@ private String argumentsToString(List rawArgs) {
return sb.toString();
}
- /**
- * @param args Common arguments.
- * @return Thin client configuration to connect to cluster.
- * @throws IgniteCheckedException If error occur.
- */
- @NotNull private GridClientConfiguration getClientConfiguration(
- ConnectionAndSslParameters args
- ) throws IgniteCheckedException {
- return getClientConfiguration(args.userName(), args.password(), args);
- }
-
- /**
- * @param userName User name for authorization.
- * @param password Password for authorization.
- * @param args Common arguments.
- * @return Thin client configuration to connect to cluster.
- * @throws IgniteCheckedException If error occur.
- */
- @NotNull private GridClientConfiguration getClientConfiguration(
- String userName,
- String password,
- ConnectionAndSslParameters args
- ) throws IgniteCheckedException {
- GridClientConfiguration clientCfg = new GridClientConfiguration();
-
- clientCfg.setPingInterval(args.pingInterval());
-
- clientCfg.setPingTimeout(args.pingTimeout());
-
- clientCfg.setServers(Collections.singletonList(args.host() + ":" + args.port()));
-
- if (!F.isEmpty(userName))
- clientCfg.setSecurityCredentialsProvider(getSecurityCredentialsProvider(userName, password, clientCfg));
-
- if (!F.isEmpty(args.sslKeyStorePath()) || !F.isEmpty(args.sslFactoryConfigPath())) {
- if (!F.isEmpty(args.sslKeyStorePath()) && !F.isEmpty(args.sslFactoryConfigPath()))
- throw new IgniteCheckedException("Incorrect SSL configuration. " +
- "SSL factory config path should not be specified simultaneously with other SSL options like keystore path.");
-
- clientCfg.setSslContextFactory(createSslSupportFactory(args));
- }
-
- return clientCfg;
- }
-
- /**
- * @param userName User name for authorization.
- * @param password Password for authorization.
- * @param clientCfg Thin client configuration to connect to cluster.
- * @return Security credentials provider with usage of given user name and password.
- * @throws IgniteCheckedException If error occur.
- */
- @NotNull private SecurityCredentialsProvider getSecurityCredentialsProvider(
- String userName,
- String password,
- GridClientConfiguration clientCfg
- ) throws IgniteCheckedException {
- SecurityCredentialsProvider securityCredential = clientCfg.getSecurityCredentialsProvider();
-
- if (securityCredential == null)
- return new SecurityCredentialsBasicProvider(new SecurityCredentials(userName, password));
-
- final SecurityCredentials credential = securityCredential.credentials();
- credential.setLogin(userName);
- credential.setPassword(password);
-
- return securityCredential;
- }
-
- /**
- * @param args Commond args.
- * @return Ssl support factory.
- */
- @NotNull private Factory createSslSupportFactory(ConnectionAndSslParameters args) throws IgniteCheckedException {
- if (!F.isEmpty(args.sslFactoryConfigPath())) {
- URL springCfg = IgniteUtils.resolveSpringUrl(args.sslFactoryConfigPath());
-
- ApplicationContext ctx = IgniteSpringHelperImpl.applicationContext(springCfg);
-
- return (Factory)ctx.getBean(Factory.class);
- }
-
- SslContextFactory factory = new SslContextFactory();
-
- if (args.sslProtocol().length > 1)
- factory.setProtocols(args.sslProtocol());
- else
- factory.setProtocol(args.sslProtocol()[0]);
-
- factory.setKeyAlgorithm(args.sslKeyAlgorithm());
- factory.setCipherSuites(args.getSslCipherSuites());
- factory.setKeyStoreFilePath(args.sslKeyStorePath());
-
- if (args.sslKeyStorePassword() != null)
- factory.setKeyStorePassword(args.sslKeyStorePassword());
- else {
- char[] keyStorePwd = requestPasswordFromConsole("SSL keystore password: ");
-
- args.sslKeyStorePassword(keyStorePwd);
- factory.setKeyStorePassword(keyStorePwd);
- }
-
- factory.setKeyStoreType(args.sslKeyStoreType());
-
- if (F.isEmpty(args.sslTrustStorePath()))
- factory.setTrustManagers(SslContextFactory.getDisabledTrustManager());
- else {
- factory.setTrustStoreFilePath(args.sslTrustStorePath());
-
- if (args.sslTrustStorePassword() != null)
- factory.setTrustStorePassword(args.sslTrustStorePassword());
- else {
- char[] trustStorePwd = requestPasswordFromConsole("SSL truststore password: ");
-
- args.sslTrustStorePassword(trustStorePwd);
- factory.setTrustStorePassword(trustStorePwd);
- }
-
- factory.setTrustStoreType(args.sslTrustStoreType());
- }
-
- return factory;
- }
-
/**
* Used for tests.
*
@@ -656,10 +548,11 @@ private boolean confirm(String str) {
/**
* @param e Exception to check.
- * @return {@code true} if specified exception is {@link GridClientAuthenticationException}.
+ * @return {@code true} if specified exception is an authentication exception.
*/
public static boolean isAuthError(Throwable e) {
- return X.hasCause(e, GridClientAuthenticationException.class);
+ return X.hasCause(e, GridClientAuthenticationException.class)
+ || X.hasCause(e, ClientAuthenticationException.class);
}
/**
@@ -671,7 +564,8 @@ private static boolean isConnectionError(Throwable e) {
e instanceof GridClientConnectionResetException ||
e instanceof GridClientDisconnectedException ||
e instanceof GridClientHandshakeException ||
- e instanceof GridServerUnreachableException;
+ e instanceof GridServerUnreachableException ||
+ X.hasCause(e, ClientConnectionException.class);
}
/**
@@ -708,7 +602,7 @@ private String requestDataFromConsole(String msg) {
/** @param rawArgs Arguments. */
private void printHelp(List rawArgs) {
boolean experimentalEnabled = rawArgs.stream().anyMatch(CMD_ENABLE_EXPERIMENTAL::equalsIgnoreCase) ||
- IgniteSystemProperties.getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND);
+ getBoolean(IGNITE_ENABLE_EXPERIMENTAL_COMMAND);
logger.info("Control utility script is used to execute admin commands on cluster or get common cluster info. " +
"The command has the following syntax:");
@@ -949,6 +843,11 @@ private static class LengthCalculator implements Consumer {
}
}
+ /** */
+ public static boolean useConnectorConnection() {
+ return getBoolean(IGNITE_CONTROL_UTILITY_USE_CONNECTOR_CONNECTION);
+ }
+
/** */
public static class CommandName implements Consumer