| /* |
| * ========================================================================= |
| * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * more patents listed at http://www.pivotal.io/patents. |
| * ======================================================================== |
| */ |
| package com.gemstone.gemfire.management.internal.cli.commands; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.Writer; |
| import java.net.ConnectException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.security.KeyStore; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| import javax.net.ssl.HttpsURLConnection; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.TrustManagerFactory; |
| |
| import org.springframework.shell.core.CommandMarker; |
| import org.springframework.shell.core.ExitShellRequest; |
| import org.springframework.shell.core.annotation.CliAvailabilityIndicator; |
| import org.springframework.shell.core.annotation.CliCommand; |
| import org.springframework.shell.core.annotation.CliOption; |
| |
| import com.gemstone.gemfire.distributed.internal.DistributionConfig; |
| import com.gemstone.gemfire.internal.ClassPathLoader; |
| import com.gemstone.gemfire.internal.DSFIDFactory; |
| import com.gemstone.gemfire.internal.lang.Initializer; |
| import com.gemstone.gemfire.internal.lang.StringUtils; |
| import com.gemstone.gemfire.internal.lang.SystemUtils; |
| import com.gemstone.gemfire.internal.util.IOUtils; |
| import com.gemstone.gemfire.internal.util.PasswordUtil; |
| import com.gemstone.gemfire.management.cli.CliMetaData; |
| import com.gemstone.gemfire.management.cli.ConverterHint; |
| import com.gemstone.gemfire.management.cli.Result; |
| import com.gemstone.gemfire.management.internal.JmxManagerLocatorRequest; |
| import com.gemstone.gemfire.management.internal.JmxManagerLocatorResponse; |
| import com.gemstone.gemfire.management.internal.SSLUtil; |
| import com.gemstone.gemfire.management.internal.cli.CliUtil; |
| import com.gemstone.gemfire.management.internal.cli.GfshParser; |
| import com.gemstone.gemfire.management.internal.cli.LogWrapper; |
| import com.gemstone.gemfire.management.internal.cli.annotation.CliArgument; |
| import com.gemstone.gemfire.management.internal.cli.converters.ConnectionEndpointConverter; |
| import com.gemstone.gemfire.management.internal.cli.domain.ConnectToLocatorResult; |
| import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; |
| import com.gemstone.gemfire.management.internal.cli.result.ErrorResultData; |
| import com.gemstone.gemfire.management.internal.cli.result.InfoResultData; |
| import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder; |
| import com.gemstone.gemfire.management.internal.cli.result.TabularResultData; |
| import com.gemstone.gemfire.management.internal.cli.shell.Gfsh; |
| import com.gemstone.gemfire.management.internal.cli.shell.JMXConnectionException; |
| import com.gemstone.gemfire.management.internal.cli.shell.JmxOperationInvoker; |
| import com.gemstone.gemfire.management.internal.cli.shell.OperationInvoker; |
| import com.gemstone.gemfire.management.internal.cli.shell.jline.GfshHistory; |
| import com.gemstone.gemfire.management.internal.cli.util.CauseFinder; |
| import com.gemstone.gemfire.management.internal.cli.util.ConnectionEndpoint; |
| import com.gemstone.gemfire.management.internal.web.domain.LinkIndex; |
| import com.gemstone.gemfire.management.internal.web.http.support.SimpleHttpRequester; |
| import com.gemstone.gemfire.management.internal.web.shell.HttpOperationInvoker; |
| import com.gemstone.gemfire.management.internal.web.shell.RestHttpOperationInvoker; |
| |
| /** |
| * @author Abhishek Chaudhari |
| * |
| * @since 7.0 |
| */ |
| public class ShellCommands implements CommandMarker { |
| |
| private Gfsh getGfsh() { |
| return Gfsh.getCurrentInstance(); |
| } |
| |
| @CliCommand(value = { CliStrings.EXIT, "quit" }, help = CliStrings.EXIT__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public ExitShellRequest exit() throws IOException { |
| Gfsh gfshInstance = getGfsh(); |
| |
| gfshInstance.stop(); |
| |
| ExitShellRequest exitShellRequest = gfshInstance.getExitShellRequest(); |
| if (exitShellRequest == null) { |
| // shouldn't really happen, but we'll fallback to this anyway |
| exitShellRequest = ExitShellRequest.NORMAL_EXIT; |
| } |
| |
| return exitShellRequest; |
| } |
| |
| // millis that connect --locator will wait for a response from the locator. |
| private final static int CONNECT_LOCATOR_TIMEOUT_MS = 60000; // see bug 45971 |
| |
| public static int getConnectLocatorTimeoutInMS() { |
| return ShellCommands.CONNECT_LOCATOR_TIMEOUT_MS; |
| } |
| |
| @CliCommand(value = { CliStrings.CONNECT }, help = CliStrings.CONNECT__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_MANAGER}) |
| public Result connect( |
| @CliOption(key = { CliStrings.CONNECT__LOCATOR }, |
| unspecifiedDefaultValue = ConnectionEndpointConverter.DEFAULT_LOCATOR_ENDPOINTS, |
| optionContext = ConnectionEndpoint.LOCATOR_OPTION_CONTEXT, |
| help = CliStrings.CONNECT__LOCATOR__HELP) ConnectionEndpoint locatorTcpHostPort, |
| @CliOption(key = { CliStrings.CONNECT__JMX_MANAGER }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| optionContext = ConnectionEndpoint.JMXMANAGER_OPTION_CONTEXT, |
| help = CliStrings.CONNECT__JMX_MANAGER__HELP) ConnectionEndpoint memberRmiHostPort, |
| @CliOption(key = { CliStrings.CONNECT__USE_HTTP }, |
| mandatory = false, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.CONNECT__USE_HTTP__HELP) boolean useHttp, |
| @CliOption(key = { CliStrings.CONNECT__URL }, |
| mandatory = false, |
| unspecifiedDefaultValue = CliStrings.CONNECT__DEFAULT_BASE_URL, |
| help = CliStrings.CONNECT__URL__HELP) String url, |
| @CliOption(key = { CliStrings.CONNECT__USERNAME }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__USERNAME__HELP) String userName, |
| @CliOption(key = { CliStrings.CONNECT__PASSWORD }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__PASSWORD__HELP) String password, |
| @CliOption(key = { CliStrings.CONNECT__KEY_STORE }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__KEY_STORE__HELP) String keystore, |
| @CliOption(key = { CliStrings.CONNECT__KEY_STORE_PASSWORD }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__KEY_STORE_PASSWORD__HELP) String keystorePassword, |
| @CliOption(key = { CliStrings.CONNECT__TRUST_STORE }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__TRUST_STORE__HELP) String truststore, |
| @CliOption(key = { CliStrings.CONNECT__TRUST_STORE_PASSWORD }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__TRUST_STORE_PASSWORD__HELP) String truststorePassword, |
| @CliOption(key = { CliStrings.CONNECT__SSL_CIPHERS }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__SSL_CIPHERS__HELP) String sslCiphers, |
| @CliOption(key = { CliStrings.CONNECT__SSL_PROTOCOLS }, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__SSL_PROTOCOLS__HELP) String sslProtocols, |
| @CliOption(key = CliStrings.CONNECT__SECURITY_PROPERTIES, |
| optionContext = ConverterHint.FILE_PATHSTRING, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| help = CliStrings.CONNECT__SECURITY_PROPERTIES__HELP) final String gfSecurityPropertiesPath, |
| @CliOption(key = { CliStrings.CONNECT__USE_SSL }, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.CONNECT__USE_SSL__HELP) final boolean useSsl) |
| { |
| Result result; |
| |
| String passwordToUse = decrypt(password); |
| String keystoreToUse = keystore; |
| String keystorePasswordToUse = keystorePassword; |
| String truststoreToUse = truststore; |
| String truststorePasswordToUse = truststorePassword; |
| String sslCiphersToUse = sslCiphers; |
| String sslProtocolsToUse = sslProtocols; |
| |
| // TODO shouldn't the condition be (getGfsh() != null && getGfsh().isConnectedAndReady())? |
| // otherwise, we have potential NullPointerException on the line with getGfsh().getOperationInvoker() |
| //if (getGfsh() == null || getGfsh().isConnectedAndReady()) { |
| if (getGfsh() != null && getGfsh().isConnectedAndReady()) { |
| try { |
| result = ResultBuilder.createInfoResult("Already connected to: " + getGfsh().getOperationInvoker().toString()); |
| } catch (Exception e) { |
| result = ResultBuilder.buildResult(ResultBuilder.createErrorResultData().setErrorCode( |
| ResultBuilder.ERRORCODE_DEFAULT).addLine(e.getMessage())); |
| } |
| } else if (useHttp) { |
| try{ |
| |
| final Map<String, String> sslConfigProps = this.readSSLConfiguration(useSsl, keystoreToUse,keystorePasswordToUse, |
| truststoreToUse, truststorePasswordToUse, sslCiphersToUse, sslProtocolsToUse, gfSecurityPropertiesPath); |
| |
| if (useSsl) { |
| configureHttpsURLConnection(sslConfigProps); |
| if (url.startsWith("http:")) { |
| url = url.replace("http:", "https:"); |
| } |
| } |
| |
| LogWrapper.getInstance().warning(String.format("Sending HTTP request for Link Index at (%1$s)...", url.concat("/index"))); |
| |
| LinkIndex linkIndex = new SimpleHttpRequester(CONNECT_LOCATOR_TIMEOUT_MS).get(url.concat("/index"), LinkIndex.class); |
| |
| LogWrapper.getInstance().warning(String.format("Received Link Index (%1$s)", linkIndex.toString())); |
| |
| Gfsh gemfireShell = getGfsh(); |
| |
| HttpOperationInvoker operationInvoker = new RestHttpOperationInvoker(linkIndex, gemfireShell, url); |
| |
| Initializer.init(operationInvoker); |
| gemfireShell.setOperationInvoker(operationInvoker); |
| |
| LogWrapper.getInstance().info(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, operationInvoker.toString())); |
| |
| Gfsh.redirectInternalJavaLoggers(); |
| result = ResultBuilder.createInfoResult(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, operationInvoker.toString())); |
| |
| } catch (IOException ioe) { |
| String errorMessage = ioe.getMessage(); |
| result = ResultBuilder.createConnectionErrorResult(errorMessage); |
| ioe.printStackTrace(); |
| } catch (Exception e) { |
| String errorMessage = e.getMessage(); |
| result = ResultBuilder.createConnectionErrorResult(errorMessage); |
| e.printStackTrace(); |
| } |
| } else { |
| |
| boolean isConnectingViaLocator = false; |
| |
| InfoResultData infoResultData = ResultBuilder.createInfoResultData(); |
| ConnectionEndpoint hostPortToConnect = null; |
| |
| try { |
| Gfsh gfshInstance = getGfsh(); |
| |
| // JMX Authentication Config |
| if (userName != null && userName.length() > 0) { |
| if (passwordToUse == null || passwordToUse.length() == 0) { |
| passwordToUse = gfshInstance.readWithMask("jmx password: ", '*'); |
| } |
| if (passwordToUse == null || passwordToUse.length() == 0) { |
| throw new IllegalArgumentException(CliStrings.CONNECT__MSG__JMX_PASSWORD_MUST_BE_SPECIFIED); |
| } |
| } |
| |
| final Map<String, String> sslConfigProps = this.readSSLConfiguration(useSsl, keystoreToUse,keystorePasswordToUse, |
| truststoreToUse, truststorePasswordToUse, sslCiphersToUse, sslProtocolsToUse, gfSecurityPropertiesPath); |
| |
| if (memberRmiHostPort != null) { |
| hostPortToConnect = memberRmiHostPort; |
| Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_MANAGER_AT_0, new Object[] {memberRmiHostPort.toString(false)})); |
| } else { |
| isConnectingViaLocator = true; |
| hostPortToConnect = locatorTcpHostPort; |
| Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_LOCATOR_AT_0, new Object[] {locatorTcpHostPort.toString(false)})); |
| |
| // Props required to configure a SocketCreator with SSL. |
| // Used for gfsh->locator connection & not needed for gfsh->manager connection |
| if (useSsl || !sslConfigProps.isEmpty()) { |
| //Fix for 51266 : Added an check for cluster-ssl-enabled proeprty |
| if(!sslConfigProps.containsKey(DistributionConfig.CLUSTER_SSL_ENABLED_NAME)) |
| sslConfigProps.put(DistributionConfig.SSL_ENABLED_NAME, String.valueOf(true)); |
| sslConfigProps.put(DistributionConfig.MCAST_PORT_NAME, String.valueOf(0)); |
| sslConfigProps.put(DistributionConfig.LOCATORS_NAME, ""); |
| |
| String sslInfoLogMsg = "Connecting to Locator via SSL."; |
| if (useSsl) { |
| sslInfoLogMsg = CliStrings.CONNECT__USE_SSL + " is set to true. " + sslInfoLogMsg; |
| } |
| gfshInstance.logToFile(sslInfoLogMsg, null); |
| } |
| |
| ConnectToLocatorResult connectToLocatorResult = connectToLocator(locatorTcpHostPort.getHost(), locatorTcpHostPort.getPort(), CONNECT_LOCATOR_TIMEOUT_MS, sslConfigProps); |
| memberRmiHostPort = connectToLocatorResult.getMemberEndpoint(); |
| hostPortToConnect = memberRmiHostPort; |
| Gfsh.printlnErr(connectToLocatorResult.getResultMessage()); |
| |
| // when locator is configured to use SSL (ssl-enabled=true) but manager is not (jmx-manager-ssl=false) |
| if ((useSsl || !sslConfigProps.isEmpty()) && !connectToLocatorResult.isJmxManagerSslEnabled()) { |
| gfshInstance.logInfo(CliStrings.CONNECT__USE_SSL + " is set to true. But JMX Manager doesn't support SSL, connecting without SSL.", null); |
| sslConfigProps.clear(); |
| } |
| } |
| |
| if (!sslConfigProps.isEmpty()) { |
| gfshInstance.logToFile("Connecting to manager via SSL.", null); |
| } |
| |
| JmxOperationInvoker operationInvoker = new JmxOperationInvoker(memberRmiHostPort.getHost(), memberRmiHostPort.getPort(), userName, passwordToUse, sslConfigProps); |
| gfshInstance.setOperationInvoker(operationInvoker); |
| infoResultData.addLine(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, memberRmiHostPort.toString(false))); |
| LogWrapper.getInstance().info(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, memberRmiHostPort.toString(false))); |
| result = ResultBuilder.buildResult(infoResultData); |
| } catch (Exception e) { |
| // TODO - Abhishek: Refactor to use catch blocks for instanceof checks |
| Gfsh gfshInstance = Gfsh.getCurrentInstance(); |
| String errorMessage = e.getMessage(); |
| boolean logAsFine = false; |
| if (CauseFinder.indexOfCause(e, javax.naming.ServiceUnavailableException.class, false) != -1) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__SERVICE_UNAVAILABLE_ERROR, hostPortToConnect.toString(false)); |
| } else if (e instanceof JMXConnectionException) { |
| JMXConnectionException jce = (JMXConnectionException)e; |
| if (jce.getExceptionType() == JMXConnectionException.MANAGER_NOT_FOUND_EXCEPTION) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__SERVICE_UNAVAILABLE_ERROR, hostPortToConnect.toString(false)); |
| } |
| } else if ((e instanceof ConnectException) && isConnectingViaLocator) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_CONNECT_TO_LOCATOR_0, hostPortToConnect.toString(false)); |
| } else if ( (e instanceof IllegalStateException) && isConnectingViaLocator) { |
| Throwable causeByType = CauseFinder.causeByType(e, ClassCastException.class, false); |
| if (causeByType != null) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_CONNECT_TO_LOCATOR_0_POSSIBLY_SSL_CONFIG_ERROR, |
| new Object[] { hostPortToConnect.toString(false)}); |
| if (gfshInstance.isLoggingEnabled()) { |
| errorMessage += " "+ getGfshLogsCheckMessage(gfshInstance.getLogFilePath()); |
| } |
| } else if (errorMessage == null) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_CONNECT_TO_LOCATOR_0, locatorTcpHostPort.toString(false)); |
| if (gfshInstance.isLoggingEnabled()) { |
| errorMessage += " "+ getGfshLogsCheckMessage(gfshInstance.getLogFilePath()); |
| } |
| } |
| } else if (e instanceof IOException) { |
| Throwable causeByType = CauseFinder.causeByType(e, java.rmi.ConnectIOException.class, false); |
| if (causeByType != null) { |
| // TODO - Abhishek : Is there a better way to know about a specific cause? |
| if (String.valueOf(causeByType.getMessage()).contains("non-JRMP server")) { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_CONNECT_TO_MANAGER_0_POSSIBLY_SSL_CONFIG_ERROR, |
| new Object[] { memberRmiHostPort.toString(false)}); |
| logAsFine = true; |
| } else { |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__ERROR, new Object[] {memberRmiHostPort.toString(false), ""}); |
| } |
| if (gfshInstance.isLoggingEnabled()) { |
| errorMessage += " "+ getGfshLogsCheckMessage(gfshInstance.getLogFilePath()); |
| } |
| } |
| } else if (e instanceof SecurityException) { |
| // the default exception message is clear enough |
| String msgPart = StringUtils.isBlank(userName) && StringUtils.isBlank(passwordToUse) ? "" : "appropriate "; |
| errorMessage += ". Please specify "+msgPart+"values for --"+CliStrings.CONNECT__USERNAME+" and --"+CliStrings.CONNECT__PASSWORD; |
| } else{ |
| errorMessage = CliStrings.format(CliStrings.CONNECT__MSG__ERROR, hostPortToConnect.toString(false), errorMessage); |
| } |
| result = ResultBuilder.createConnectionErrorResult(errorMessage); |
| if (logAsFine) { |
| LogWrapper.getInstance().fine(e.getMessage(), e); |
| } else { |
| LogWrapper.getInstance().severe(e.getMessage(), e); |
| } |
| } |
| |
| Gfsh.redirectInternalJavaLoggers(); |
| } |
| |
| return result; |
| } |
| |
| private String decrypt(String password) { |
| if (password != null) { |
| return PasswordUtil.decrypt(password); |
| } |
| return null; |
| } |
| |
| private void configureHttpsURLConnection(Map<String, String> sslConfigProps) throws Exception { |
| String keystoreToUse = sslConfigProps.get(Gfsh.SSL_KEYSTORE); |
| String keystorePasswordToUse = sslConfigProps.get(Gfsh.SSL_KEYSTORE_PASSWORD); |
| String truststoreToUse = sslConfigProps.get(Gfsh.SSL_TRUSTSTORE); |
| String truststorePasswordToUse = sslConfigProps.get(Gfsh.SSL_TRUSTSTORE_PASSWORD); |
| // Ciphers are not passed to HttpsURLConnection. Could not find a clean way |
| // to pass this attribute to socket layer (see #51645) |
| String sslCiphersToUse = sslConfigProps.get(DistributionConfig.CLUSTER_SSL_CIPHERS_NAME); |
| String sslProtocolsToUse = sslConfigProps.get(DistributionConfig.CLUSTER_SSL_PROTOCOLS_NAME); |
| |
| //Commenting the code to set cipher suites in GFSH rest connect (see #51645) |
| /* |
| if(sslCiphersToUse != null){ |
| System.setProperty("https.cipherSuites", sslCiphersToUse); |
| } |
| */ |
| FileInputStream keyStoreStream = null; |
| FileInputStream trustStoreStream = null; |
| try{ |
| |
| KeyManagerFactory keyManagerFactory = null; |
| if (!StringUtils.isBlank(keystoreToUse)) { |
| KeyStore clientKeys = KeyStore.getInstance("JKS"); |
| keyStoreStream = new FileInputStream(keystoreToUse); |
| clientKeys.load(keyStoreStream, keystorePasswordToUse.toCharArray()); |
| |
| keyManagerFactory = KeyManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
| keyManagerFactory.init(clientKeys, keystorePasswordToUse.toCharArray()); |
| } |
| |
| // load server public key |
| TrustManagerFactory trustManagerFactory = null; |
| if (!StringUtils.isBlank(truststoreToUse)) { |
| KeyStore serverPub = KeyStore.getInstance("JKS"); |
| trustStoreStream = new FileInputStream(truststoreToUse); |
| serverPub.load(trustStoreStream, truststorePasswordToUse.toCharArray()); |
| trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
| trustManagerFactory.init(serverPub); |
| } |
| |
| SSLContext ssl = SSLContext.getInstance(SSLUtil.getSSLAlgo(SSLUtil.readArray(sslProtocolsToUse))); |
| |
| ssl.init(keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null, |
| trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null, new java.security.SecureRandom()); |
| |
| HttpsURLConnection.setDefaultSSLSocketFactory(ssl.getSocketFactory()); |
| }finally{ |
| if(keyStoreStream != null){ |
| keyStoreStream.close(); |
| } |
| if(trustStoreStream != null ){ |
| trustStoreStream.close(); |
| } |
| |
| } |
| |
| |
| } |
| |
| /** |
| * Common code to read SSL information. Used by JMX, Locator & HTTP mode connect |
| */ |
| private Map<String, String> readSSLConfiguration(boolean useSsl, String keystoreToUse, String keystorePasswordToUse, |
| String truststoreToUse, String truststorePasswordToUse, String sslCiphersToUse, String sslProtocolsToUse, |
| String gfSecurityPropertiesPath) throws IOException { |
| |
| Gfsh gfshInstance = getGfsh(); |
| final Map<String, String> sslConfigProps = new LinkedHashMap<String, String>(); |
| |
| // JMX SSL Config 1: |
| // First from gfsecurity properties file if it's specified OR |
| // if the default gfsecurity.properties exists useSsl==true |
| if (useSsl || gfSecurityPropertiesPath != null) { |
| // reference to hold resolved gfSecurityPropertiesPath |
| String gfSecurityPropertiesPathToUse = CliUtil.resolvePathname(gfSecurityPropertiesPath); |
| URL gfSecurityPropertiesUrl = null; |
| |
| // Case 1: User has specified gfSecurity properties file |
| if (!StringUtils.isBlank(gfSecurityPropertiesPathToUse)) { |
| // User specified gfSecurity properties doesn't exist |
| if (!IOUtils.isExistingPathname(gfSecurityPropertiesPathToUse)) { |
| gfshInstance.printAsSevere(CliStrings.format(CliStrings.GEMFIRE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ", gfSecurityPropertiesPathToUse)); |
| } else { |
| gfSecurityPropertiesUrl = new File(gfSecurityPropertiesPathToUse).toURI().toURL(); |
| } |
| } else if (useSsl && gfSecurityPropertiesPath == null) { |
| // Case 2: User has specified to useSsl but hasn't specified |
| // gfSecurity properties file. Use default "gfsecurity.properties" |
| // in current dir, user's home or classpath |
| gfSecurityPropertiesUrl = getFileUrl("gfsecurity.properties"); |
| } |
| // if 'gfSecurityPropertiesPath' OR gfsecurity.properties has resolvable path |
| if (gfSecurityPropertiesUrl != null) { |
| gfshInstance.logToFile("Using security properties file : " |
| + CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath()), null); |
| Map<String, String> gfsecurityProps = loadPropertiesFromURL(gfSecurityPropertiesUrl); |
| // command line options (if any) would override props in gfsecurity.properties |
| sslConfigProps.putAll(gfsecurityProps); |
| } |
| } |
| |
| int numTimesPrompted = 0; |
| /* |
| * Using do-while here for a case when --use-ssl=true is specified but |
| * no SSL options were specified & there was no gfsecurity properties |
| * specified or readable in default gfsh directory. |
| * |
| * NOTE: 2nd round of prompting is done only when sslConfigProps map is |
| * empty & useSsl is true - so we won't over-write any previous values. |
| */ |
| do { |
| // JMX SSL Config 2: Now read the options |
| if (numTimesPrompted > 0) { |
| Gfsh.println("Please specify these SSL Configuration properties: "); |
| } |
| |
| if (numTimesPrompted > 0) { |
| //NOTE: sslConfigProps map was empty |
| keystoreToUse = readText(gfshInstance, CliStrings.CONNECT__KEY_STORE + ": "); |
| } |
| if (keystoreToUse != null && keystoreToUse.length() > 0) { |
| if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) { |
| // Check whether specified in gfsecurity props earlier |
| keystorePasswordToUse = sslConfigProps.get(Gfsh.SSL_KEYSTORE_PASSWORD); |
| if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) { |
| // not even in properties file, prompt user for it |
| keystorePasswordToUse = readPassword(gfshInstance, CliStrings.CONNECT__KEY_STORE_PASSWORD + ": "); |
| sslConfigProps.put(Gfsh.SSL_KEYSTORE_PASSWORD, keystorePasswordToUse); |
| } |
| }else{//For cases where password is already part of command option |
| sslConfigProps.put(Gfsh.SSL_KEYSTORE_PASSWORD, keystorePasswordToUse); |
| } |
| sslConfigProps.put(Gfsh.SSL_KEYSTORE, keystoreToUse); |
| } |
| |
| if (numTimesPrompted > 0) { |
| truststoreToUse = readText(gfshInstance, CliStrings.CONNECT__TRUST_STORE + ": "); |
| } |
| if (truststoreToUse != null && truststoreToUse.length() > 0) { |
| if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) { |
| // Check whether specified in gfsecurity props earlier? |
| truststorePasswordToUse = sslConfigProps.get(Gfsh.SSL_TRUSTSTORE_PASSWORD); |
| if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) { |
| // not even in properties file, prompt user for it |
| truststorePasswordToUse = readPassword(gfshInstance, CliStrings.CONNECT__TRUST_STORE_PASSWORD + ": "); |
| sslConfigProps.put(Gfsh.SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse); |
| } |
| }else{//For cases where password is already part of command option |
| sslConfigProps.put(Gfsh.SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse); |
| } |
| sslConfigProps.put(Gfsh.SSL_TRUSTSTORE, truststoreToUse); |
| } |
| |
| if (numTimesPrompted > 0) { |
| sslCiphersToUse = readText(gfshInstance, CliStrings.CONNECT__SSL_CIPHERS + ": "); |
| } |
| if (sslCiphersToUse != null && sslCiphersToUse.length() > 0) { |
| //sslConfigProps.put(DistributionConfig.CLUSTER_SSL_CIPHERS_NAME, sslCiphersToUse); |
| sslConfigProps.put(Gfsh.SSL_ENABLED_CIPHERS, sslCiphersToUse); |
| } |
| |
| if (numTimesPrompted > 0) { |
| sslProtocolsToUse = readText(gfshInstance, CliStrings.CONNECT__SSL_PROTOCOLS + ": "); |
| } |
| if (sslProtocolsToUse != null && sslProtocolsToUse.length() > 0) { |
| //sslConfigProps.put(DistributionConfig.CLUSTER_SSL_PROTOCOLS_NAME, sslProtocolsToUse); |
| sslConfigProps.put(Gfsh.SSL_ENABLED_PROTOCOLS, sslProtocolsToUse); |
| } |
| |
| // SSL is required to be used but no SSL config found |
| } while(useSsl && sslConfigProps.isEmpty() && (0 == numTimesPrompted++) && !gfshInstance.isQuietMode()); |
| return sslConfigProps; |
| } |
| |
| private static String getGfshLogsCheckMessage(String logFilePath) { |
| return CliStrings.format(CliStrings.GFSH__PLEASE_CHECK_LOGS_AT_0, logFilePath); |
| } |
| |
| private String readText(Gfsh gfsh, String textToPrompt) throws IOException { |
| if (!gfsh.isHeadlessMode() || !gfsh.isQuietMode()) { |
| return gfsh.interact(textToPrompt); |
| } else { |
| return null; |
| } |
| } |
| |
| private String readPassword(Gfsh gfsh, String textToPrompt) throws IOException { |
| if (!gfsh.isHeadlessMode() || !gfsh.isQuietMode()) { |
| return gfsh.readWithMask(textToPrompt, '*'); |
| } else { |
| return null; |
| } |
| } |
| |
| /* package-private */ static Map<String, String> loadPropertiesFromURL(URL gfSecurityPropertiesUrl) { |
| Map<String, String> propsMap = Collections.emptyMap(); |
| |
| if (gfSecurityPropertiesUrl != null) { |
| InputStream inputStream = null; |
| try { |
| Properties props = new Properties(); |
| inputStream = gfSecurityPropertiesUrl.openStream(); |
| props.load(inputStream); |
| if (!props.isEmpty()) { |
| Set<String> jmxSpecificProps = new HashSet<String>(); |
| propsMap = new LinkedHashMap<String, String>(); |
| Set<Entry<Object, Object>> entrySet = props.entrySet(); |
| for (Entry<Object, Object> entry : entrySet) { |
| |
| String key = (String)entry.getKey(); |
| if (key.endsWith(DistributionConfig.JMX_SSL_PROPS_SUFFIX)) { |
| key = key.substring(0, key.length() - DistributionConfig.JMX_SSL_PROPS_SUFFIX.length()); |
| jmxSpecificProps.add(key); |
| |
| propsMap.put(key, (String)entry.getValue()); |
| } else if (!jmxSpecificProps.contains(key)) {// Prefer properties ending with "-jmx" over default SSL props. |
| propsMap.put(key, (String)entry.getValue()); |
| } |
| } |
| props.clear(); |
| jmxSpecificProps.clear(); |
| } |
| } catch (IOException io) { |
| throw new RuntimeException(CliStrings.format( |
| CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0, |
| CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath())), io); |
| } finally { |
| IOUtils.close(inputStream); |
| } |
| } |
| return propsMap; |
| } |
| |
| // Copied from DistributedSystem.java |
| private static URL getFileUrl(String fileName) { |
| File file = new File(fileName); |
| |
| if (file.exists()) { |
| try { |
| return IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(file).toURI().toURL(); |
| } catch (MalformedURLException ignore) { |
| } |
| } |
| |
| file = new File(System.getProperty("user.home"), fileName); |
| |
| if (file.exists()) { |
| try { |
| return IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(file).toURI().toURL(); |
| } catch (MalformedURLException ignore) { |
| } |
| } |
| |
| return ClassPathLoader.getLatest().getResource(ShellCommands.class, fileName); |
| } |
| |
| public static ConnectToLocatorResult connectToLocator(String host, int port, int timeout, Map<String, String> props) |
| throws IOException |
| { |
| // register DSFID types first; invoked explicitly so that all message type |
| // initializations do not happen in first deserialization on a possibly |
| // "precious" thread |
| DSFIDFactory.registerTypes(); |
| |
| JmxManagerLocatorResponse locatorResponse = JmxManagerLocatorRequest.send(host, port, timeout, props); |
| |
| if (StringUtils.isBlank(locatorResponse.getHost()) || locatorResponse.getPort() == 0) { |
| Throwable locatorResponseException = locatorResponse.getException(); |
| String exceptionMessage = CliStrings.CONNECT__MSG__LOCATOR_COULD_NOT_FIND_MANAGER; |
| |
| if (locatorResponseException != null) { |
| String locatorResponseExceptionMessage = locatorResponseException.getMessage(); |
| locatorResponseExceptionMessage = (!StringUtils.isBlank(locatorResponseExceptionMessage) |
| ? locatorResponseExceptionMessage : locatorResponseException.toString()); |
| exceptionMessage = "Exception caused JMX Manager startup to fail because: '" |
| .concat(locatorResponseExceptionMessage).concat("'"); |
| } |
| |
| throw new IllegalStateException(exceptionMessage, locatorResponseException); |
| } |
| |
| ConnectionEndpoint memberEndpoint = new ConnectionEndpoint(locatorResponse.getHost(), locatorResponse.getPort()); |
| |
| String resultMessage = CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_MANAGER_AT_0, |
| memberEndpoint.toString(false)); |
| |
| return new ConnectToLocatorResult(memberEndpoint, resultMessage, locatorResponse.isJmxManagerSslEnabled()); |
| } |
| |
| |
| @CliCommand(value = { CliStrings.DISCONNECT }, help = CliStrings.DISCONNECT__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEMFIRE_JMX, CliStrings.TOPIC_GEMFIRE_MANAGER}) |
| public Result disconnect() { |
| Result result = null; |
| |
| if (getGfsh() != null && !getGfsh().isConnectedAndReady()) { |
| result = ResultBuilder.createInfoResult("Not connected."); |
| } else { |
| InfoResultData infoResultData = ResultBuilder.createInfoResultData(); |
| try { |
| Gfsh gfshInstance = getGfsh(); |
| if (gfshInstance.isConnectedAndReady()) { |
| OperationInvoker operationInvoker = gfshInstance.getOperationInvoker(); |
| Gfsh.println("Disconnecting from: " + operationInvoker); |
| operationInvoker.stop(); |
| infoResultData.addLine(CliStrings |
| .format(CliStrings.DISCONNECT__MSG__DISCONNECTED, operationInvoker.toString())); |
| LogWrapper.getInstance().info(CliStrings.format(CliStrings.DISCONNECT__MSG__DISCONNECTED, operationInvoker.toString())); |
| gfshInstance.setPromptPath(com.gemstone.gemfire.management.internal.cli.converters.RegionPathConverter.DEFAULT_APP_CONTEXT_PATH); |
| } else { |
| infoResultData.addLine(CliStrings.DISCONNECT__MSG__NOTCONNECTED); |
| } |
| result = ResultBuilder.buildResult(infoResultData); |
| } catch (Exception e) { |
| result = ResultBuilder.createConnectionErrorResult(CliStrings.format(CliStrings.DISCONNECT__MSG__ERROR, e.getMessage())); |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| @CliCommand(value = {CliStrings.DESCRIBE_CONNECTION}, help = CliStrings.DESCRIBE_CONNECTION__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEMFIRE_JMX}) |
| public Result describeConnection() { |
| Result result = null; |
| try { |
| TabularResultData tabularResultData = ResultBuilder.createTabularResultData(); |
| Gfsh gfshInstance = getGfsh(); |
| if (gfshInstance.isConnectedAndReady()) { |
| OperationInvoker operationInvoker = gfshInstance.getOperationInvoker(); |
| // tabularResultData.accumulate("Monitored GemFire DS", operationInvoker.toString()); |
| tabularResultData.accumulate("Connection Endpoints", operationInvoker.toString()); |
| } else { |
| tabularResultData.accumulate("Connection Endpoints", "Not connected"); |
| } |
| result = ResultBuilder.buildResult(tabularResultData); |
| } catch (Exception e) { |
| ErrorResultData errorResultData = |
| ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT) |
| .addLine(e.getMessage()); |
| result = ResultBuilder.buildResult(errorResultData); |
| } |
| |
| return result; |
| } |
| |
| |
| @CliCommand(value = { CliStrings.ECHO }, help = CliStrings.ECHO__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result echo( |
| @CliOption(key = {CliStrings.ECHO__STR, ""}, |
| unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, |
| specifiedDefaultValue = "", |
| mandatory = true, |
| help = CliStrings.ECHO__STR__HELP) String stringToEcho) { |
| Result result = null; |
| |
| if(stringToEcho.equals("$*")){ |
| Gfsh gfshInstance = getGfsh(); |
| Map<String, String> envMap = gfshInstance.getEnv(); |
| Set< Entry<String, String> > setEnvMap = envMap.entrySet(); |
| TabularResultData resultData = buildResultForEcho(setEnvMap); |
| |
| result = ResultBuilder.buildResult(resultData); |
| } else { |
| result = ResultBuilder.createInfoResult(stringToEcho); |
| } |
| |
| return result; |
| } |
| TabularResultData buildResultForEcho(Set< Entry<String, String> > propertyMap){ |
| TabularResultData resultData = ResultBuilder.createTabularResultData(); |
| Iterator <Entry<String, String>> it = propertyMap.iterator(); |
| |
| while(it.hasNext()){ |
| Entry<String, String> setEntry = it.next(); |
| resultData.accumulate("Property", setEntry.getKey()); |
| resultData.accumulate("Value", String.valueOf(setEntry.getValue())); |
| } |
| return resultData; |
| } |
| |
| |
| |
| @CliCommand(value = { CliStrings.SET_VARIABLE }, help = CliStrings.SET_VARIABLE__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result setVariable( |
| @CliOption(key = CliStrings.SET_VARIABLE__VAR, |
| mandatory=true, |
| help = CliStrings.SET_VARIABLE__VAR__HELP) |
| String var, |
| @CliOption(key = CliStrings.SET_VARIABLE__VALUE, |
| mandatory=true, |
| help = CliStrings.SET_VARIABLE__VALUE__HELP) |
| String value) { |
| Result result = null; |
| try { |
| getGfsh().setEnvProperty(var, String.valueOf(value)); |
| result = ResultBuilder.createInfoResult("Value for variable "+var+" is now: "+value+"."); |
| } catch (IllegalArgumentException e) { |
| ErrorResultData errorResultData = ResultBuilder.createErrorResultData(); |
| errorResultData.addLine(e.getMessage()); |
| result = ResultBuilder.buildResult(errorResultData); |
| } |
| |
| return result; |
| } |
| |
| //Enable when "use region" command is required. See #46110 |
| // @CliCommand(value = { CliStrings.USE_REGION }, help = CliStrings.USE_REGION__HELP) |
| // @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEMFIRE_REGION}) |
| // public Result useRegion( |
| // @CliArgument(name = CliStrings.USE_REGION__REGION, |
| // unspecifiedDefaultValue = "/", |
| // argumentContext = CliStrings.PARAM_CONTEXT_REGIONPATH, |
| // help = CliStrings.USE_REGION__REGION__HELP) |
| // String toRegion) { |
| // Gfsh gfsh = Gfsh.getCurrentInstance(); |
| // |
| // gfsh.setPromptPath(toRegion); |
| // return ResultBuilder.createInfoResult(""); |
| // } |
| |
| @CliCommand(value = { CliStrings.DEBUG }, help = CliStrings.DEBUG__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEMFIRE_DEBUG_UTIL }) |
| public Result debug( |
| @CliOption(key = CliStrings.DEBUG__STATE, |
| unspecifiedDefaultValue = "OFF", |
| mandatory = true, |
| optionContext = "debug", |
| help = CliStrings.DEBUG__STATE__HELP) |
| String state) { |
| Gfsh gfshInstance = Gfsh.getCurrentInstance(); |
| if (gfshInstance != null) { |
| // Handle state |
| if (state.equalsIgnoreCase("ON")) { |
| gfshInstance.setDebug(true); |
| } else if(state.equalsIgnoreCase("OFF")){ |
| gfshInstance.setDebug(false); |
| }else{ |
| return ResultBuilder.createUserErrorResult(CliStrings.format(CliStrings.DEBUG__MSG_0_INVALID_STATE_VALUE,state)) ; |
| } |
| |
| } else { |
| ErrorResultData errorResultData = ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT).addLine( |
| CliStrings.ECHO__MSG__NO_GFSH_INSTANCE); |
| return ResultBuilder.buildResult(errorResultData); |
| } |
| return ResultBuilder.createInfoResult(CliStrings.DEBUG__MSG_DEBUG_STATE_IS + state ); |
| } |
| |
| @CliCommand(value = CliStrings.HISTORY, help = CliStrings.HISTORY__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = { CliStrings.TOPIC_GFSH }) |
| public Result history( |
| @CliOption(key = { CliStrings.HISTORY__FILE }, unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.HISTORY__FILE__HELP) |
| String saveHistoryTo, |
| @CliOption(key = { CliStrings.HISTORY__CLEAR }, specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", help = CliStrings.HISTORY__CLEAR__HELP) Boolean clearHistory) { |
| |
| //process clear history |
| if (clearHistory ) { |
| return executeClearHistory(); |
| }else { |
| //Process file option |
| Gfsh gfsh = Gfsh.getCurrentInstance(); |
| ErrorResultData errorResultData = null; |
| StringBuilder contents = new StringBuilder(); |
| Writer output = null; |
| |
| int historySize = gfsh.getHistorySize(); |
| String historySizeString = String.valueOf(historySize); |
| int historySizeWordLength = historySizeString.length(); |
| |
| GfshHistory gfshHistory = gfsh.getGfshHistory(); |
| List<?> gfshHistoryList = gfshHistory.getHistoryList(); |
| Iterator<?> it = gfshHistoryList.iterator(); |
| boolean flagForLineNumbers = (saveHistoryTo != null && saveHistoryTo |
| .length() > 0) ? false : true; |
| long lineNumber = 0; |
| |
| while (it.hasNext()) { |
| String line = (String) it.next(); |
| if (line.isEmpty() == false) { |
| if (flagForLineNumbers) { |
| lineNumber++; |
| contents.append(String.format("%" + historySizeWordLength + "s ", |
| lineNumber)); |
| } |
| contents.append(line); |
| contents.append(GfshParser.LINE_SEPARATOR); |
| } |
| } |
| |
| try { |
| // write to a user file |
| if (saveHistoryTo != null && saveHistoryTo.length() > 0) { |
| File saveHistoryToFile = new File(saveHistoryTo); |
| output = new BufferedWriter(new FileWriter(saveHistoryToFile)); |
| |
| if (!saveHistoryToFile.exists()) { |
| errorResultData = ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT) |
| .addLine(CliStrings.HISTORY__MSG__FILE_DOES_NOT_EXISTS); |
| return ResultBuilder.buildResult(errorResultData); |
| } |
| if (!saveHistoryToFile.isFile()) { |
| errorResultData = ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT) |
| .addLine(CliStrings.HISTORY__MSG__FILE_SHOULD_NOT_BE_DIRECTORY); |
| return ResultBuilder.buildResult(errorResultData); |
| } |
| if (!saveHistoryToFile.canWrite()) { |
| errorResultData = ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT) |
| .addLine(CliStrings.HISTORY__MSG__FILE_CANNOT_BE_WRITTEN); |
| return ResultBuilder.buildResult(errorResultData); |
| } |
| |
| output.write(contents.toString()); |
| } |
| |
| } catch (IOException ex) { |
| return ResultBuilder.createInfoResult("File error " + ex.getMessage() |
| + " for file " + saveHistoryTo); |
| } finally { |
| try { |
| if (output != null) { |
| output.close(); |
| } |
| } catch (IOException e) { |
| errorResultData = ResultBuilder.createErrorResultData() |
| .setErrorCode(ResultBuilder.ERRORCODE_DEFAULT) |
| .addLine("exception in closing file"); |
| return ResultBuilder.buildResult(errorResultData); |
| } |
| } |
| if (saveHistoryTo != null && saveHistoryTo.length() > 0) { |
| // since written to file no need to display the content |
| return ResultBuilder.createInfoResult("Wrote successfully to file " |
| + saveHistoryTo); |
| } else { |
| return ResultBuilder.createInfoResult(contents.toString()); |
| } |
| } |
| |
| } |
| |
| Result executeClearHistory(){ |
| try{ |
| Gfsh gfsh = Gfsh.getCurrentInstance(); |
| GfshHistory gfshHistory = gfsh.getGfshHistory(); |
| gfshHistory.clear(); |
| }catch(Exception e){ |
| LogWrapper.getInstance().info(CliUtil.stackTraceAsString(e) ); |
| return ResultBuilder.createGemFireErrorResult("Exception occured while clearing history " + e.getMessage()); |
| } |
| return ResultBuilder.createInfoResult(CliStrings.HISTORY__MSG__CLEARED_HISTORY); |
| |
| } |
| |
| |
| |
| @CliCommand(value = { CliStrings.RUN }, help = CliStrings.RUN__HELP) |
| @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result executeScript( |
| @CliOption(key = CliStrings.RUN__FILE, |
| optionContext = ConverterHint.FILE, |
| mandatory = true, |
| help = CliStrings.RUN__FILE__HELP) |
| File file, |
| @CliOption(key = { CliStrings.RUN__QUIET }, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.RUN__QUIET__HELP) |
| boolean quiet, |
| @CliOption(key = { CliStrings.RUN__CONTINUEONERROR }, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.RUN__CONTINUEONERROR__HELP) |
| boolean continueOnError) { |
| Result result = null; |
| |
| Gfsh gfsh = Gfsh.getCurrentInstance(); |
| try { |
| result = gfsh.executeScript(file, quiet, continueOnError); |
| } catch (IllegalArgumentException e) { |
| result = ResultBuilder.createShellClientErrorResult(e.getMessage()); |
| } // let CommandProcessingException go to the caller |
| |
| return result; |
| } |
| |
| |
| @CliCommand(value = CliStrings.ENCRYPT, help = CliStrings.ENCRYPT__HELP) |
| @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GEMFIRE_DEBUG_UTIL}) |
| public Result encryptPassword( |
| @CliOption(key = CliStrings.ENCRYPT_STRING, |
| help = CliStrings.ENCRYPT_STRING__HELP, |
| mandatory = true) |
| String stringToEncrypt) { |
| return ResultBuilder.createInfoResult(PasswordUtil.encrypt(stringToEncrypt, false/*echo*/)); |
| } |
| |
| @CliCommand(value = { CliStrings.VERSION }, help = CliStrings.VERSION__HELP) |
| @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result version( |
| @CliOption(key = { CliStrings.VERSION__FULL }, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.VERSION__FULL__HELP) |
| boolean full) { |
| Gfsh gfsh = Gfsh.getCurrentInstance(); |
| |
| return ResultBuilder.createInfoResult(gfsh.getVersion(full)); |
| } |
| |
| @CliCommand(value = { CliStrings.SLEEP }, help = CliStrings.SLEEP__HELP) |
| @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result sleep( |
| @CliOption(key = { CliStrings.SLEEP__TIME }, |
| unspecifiedDefaultValue = "3", |
| help = CliStrings.SLEEP__TIME__HELP) |
| double time) { |
| try { |
| LogWrapper.getInstance().fine("Sleeping for " + time + "seconds."); |
| Thread.sleep( Math.round(time * 1000) ); |
| } catch (InterruptedException ignorable) {} |
| return ResultBuilder.createInfoResult(""); |
| } |
| |
| @CliCommand(value = { CliStrings.SH }, help = CliStrings.SH__HELP) |
| @CliMetaData(shellOnly=true, relatedTopic = {CliStrings.TOPIC_GFSH}) |
| public Result sh( |
| @CliArgument(name = CliStrings.SH__COMMAND, |
| mandatory = true, |
| help = CliStrings.SH__COMMAND__HELP) |
| String command, |
| @CliOption(key = CliStrings.SH__USE_CONSOLE, |
| specifiedDefaultValue = "true", |
| unspecifiedDefaultValue = "false", |
| help = CliStrings.SH__USE_CONSOLE__HELP) |
| boolean useConsole) { |
| Result result = null; |
| try { |
| result = ResultBuilder.buildResult(executeCommand(Gfsh.getCurrentInstance(), command, useConsole)); |
| } catch (IllegalStateException e) { |
| result = ResultBuilder.createUserErrorResult(e.getMessage()); |
| LogWrapper.getInstance().warning("Unable to execute command \"" + command + "\". Reason:" + e.getMessage() + "."); |
| } catch (IOException e) { |
| result = ResultBuilder.createUserErrorResult(e.getMessage()); |
| LogWrapper.getInstance().warning("Unable to execute command \"" + command + "\". Reason:" + e.getMessage() + "."); |
| } |
| return result; |
| } |
| |
| private static InfoResultData executeCommand(Gfsh gfsh, String userCommand, boolean useConsole) throws IOException { |
| InfoResultData infoResultData = ResultBuilder.createInfoResultData(); |
| |
| String cmdToExecute = userCommand; |
| String cmdExecutor = "/bin/sh"; |
| String cmdExecutorOpt = "-c"; |
| if (SystemUtils.isWindows()) { |
| cmdExecutor = "cmd"; |
| cmdExecutorOpt = "/c"; |
| } else if (useConsole) { |
| cmdToExecute = cmdToExecute + " </dev/tty >/dev/tty"; |
| } |
| String[] commandArray = { cmdExecutor, cmdExecutorOpt, cmdToExecute }; |
| |
| ProcessBuilder builder = new ProcessBuilder(); |
| builder.command(commandArray); |
| builder.directory(); |
| builder.redirectErrorStream(); |
| Process proc = builder.start(); |
| |
| BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream())); |
| |
| String lineRead = ""; |
| while ((lineRead = input.readLine()) != null) { |
| infoResultData.addLine(lineRead); |
| } |
| |
| proc.getOutputStream().close(); |
| |
| try { |
| if (proc.waitFor() != 0) { |
| gfsh.logWarning("The command '" + userCommand + "' did not complete successfully", null); |
| } |
| } catch (final InterruptedException e) { |
| throw new IllegalStateException(e); |
| } |
| return infoResultData; |
| } |
| |
| |
| @CliAvailabilityIndicator({CliStrings.CONNECT, CliStrings.DISCONNECT, CliStrings.DESCRIBE_CONNECTION}) |
| public boolean isAvailable() { |
| return true; |
| } |
| } |