summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java1
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java (renamed from src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java)2
-rw-r--r--src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java1
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java1
-rw-r--r--src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt87
-rw-r--r--src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jarbin0 -> 248915 bytes
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java268
7 files changed, 359 insertions, 1 deletions
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java
index 8a1e1f37..b5e25ce7 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java
@@ -25,6 +25,7 @@ package com.gluster.storage.management.core.constants;
public class CoreConstants {
public static final String NEWLINE = System.getProperty("line.separator");
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+ public static final String USER_HOME = System.getProperty("user.home");
public static final String ENCODING_UTF8 = "UTF-8";
public static final String ALL = "ALL";
public static final String DATE_WITH_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss";
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java
index 3c805ac8..f3c9c72d 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/LRUCache.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/LRUCache.java
@@ -18,7 +18,7 @@
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
-package com.gluster.storage.management.gui.utils;
+package com.gluster.storage.management.core.utils;
import java.util.LinkedHashMap;
import java.util.Map;
diff --git a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java
index 6c8b857d..9d6ddc93 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/ProcessResult.java
@@ -28,6 +28,7 @@ import javax.xml.bind.annotation.XmlRootElement;
public class ProcessResult {
public static final int SUCCESS = 0;
+ public static final int FAILURE = 1;
private int exitValue;
private String output;
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java
index efa169de..d5e568b3 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java
@@ -24,6 +24,7 @@ import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;
+import com.gluster.storage.management.core.utils.LRUCache;
import com.gluster.storage.management.gui.Application;
/**
diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt
new file mode 100644
index 00000000..3eddd42f
--- /dev/null
+++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt
@@ -0,0 +1,87 @@
+Copyright (c) 2006 - 2010 Christian Plattner. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+a.) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+b.) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+c.) Neither the name of Christian Plattner nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+This software includes work that was released under the following license:
+
+Copyright (c) 2005 - 2006 Swiss Federal Institute of Technology (ETH Zurich),
+ Department of Computer Science (http://www.inf.ethz.ch),
+ Christian Plattner. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+a.) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+b.) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+c.) Neither the name of ETH Zurich nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+The Java implementations of the AES, Blowfish and 3DES ciphers have been
+taken (and slightly modified) from the cryptography package released by
+"The Legion Of The Bouncy Castle".
+
+Their license states the following:
+
+Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
+(http://www.bouncycastle.org)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
new file mode 100644
index 00000000..c0a9ac7b
--- /dev/null
+++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java
new file mode 100644
index 00000000..258bdea3
--- /dev/null
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.server.utils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Date;
+
+import ch.ethz.ssh2.ChannelCondition;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import ch.ethz.ssh2.StreamGobbler;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.utils.LRUCache;
+import com.gluster.storage.management.core.utils.ProcessResult;
+
+/**
+ *
+ */
+public class SshUtil {
+ private LRUCache<String, Connection> sshConnCache = new LRUCache<String, Connection>(10);
+ private static final File PEM_FILE = new File(CoreConstants.USER_HOME + "/" + ".ssh/id_rsa");
+ // TODO: Make user name configurable
+ private static final String USER_NAME = "root";
+ // TODO: Make default password configurable
+ private static final String DEFAULT_PASSWORD = "syst3m";
+
+ private Connection getConnectionWithPassword(String serverName) {
+ Connection conn = createConnection(serverName);
+ authenticateWithPassword(conn);
+ return conn;
+ }
+
+ private synchronized Connection getConnection(String serverName) {
+ Connection conn = sshConnCache.get(serverName);
+ if (conn != null) {
+ return conn;
+ }
+
+ conn = createConnection(serverName);
+ authenticateWithPublicKey(conn);
+ sshConnCache.put(serverName, conn);
+ return conn;
+ }
+
+ private void authenticateWithPublicKey(Connection conn) {
+ try {
+ if (!supportsPublicKeyAuthentication(conn)) {
+ throw new GlusterRuntimeException("Public key authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ // TODO: Introduce password for the PEM file (third argument) so that it is more secure
+ if (!conn.authenticateWithPublicKey(USER_NAME, PEM_FILE, null)) {
+ throw new GlusterRuntimeException("SSH Authentication (public key) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new GlusterRuntimeException("Exception during SSH authentication (public key) for server ["
+ + conn.getHostname() + "]", e);
+ }
+ }
+
+ private void authenticateWithPassword(Connection conn) {
+ try {
+ if (!supportsPasswordAuthentication(conn)) {
+ throw new GlusterRuntimeException("Password authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ // TODO: Introduce password for the PEM file (third argument) so that it is more secure
+ if (!conn.authenticateWithPassword(USER_NAME, DEFAULT_PASSWORD)) {
+ throw new GlusterRuntimeException("SSH Authentication (password) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new GlusterRuntimeException("Exception during SSH authentication (password) for server ["
+ + conn.getHostname() + "]", e);
+ }
+ }
+
+ private boolean supportsPasswordAuthentication(Connection conn) throws IOException {
+ return Arrays.asList(conn.getRemainingAuthMethods(USER_NAME)).contains("password");
+ }
+
+ private boolean supportsPublicKeyAuthentication(Connection conn) throws IOException {
+ return Arrays.asList(conn.getRemainingAuthMethods(USER_NAME)).contains("publickey");
+ }
+
+ private Connection createConnection(String serverName) {
+ Connection conn;
+ conn = new Connection(serverName);
+ try {
+ conn.connect();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new GlusterRuntimeException("Exception while creating SSH connection with server [" + serverName
+ + "]", e);
+ }
+ return conn;
+ }
+
+ private boolean wasTerminated(int condition) {
+ return ((condition | ChannelCondition.EXIT_SIGNAL) == condition);
+ }
+
+ private boolean hasErrors(int condition, Session session) {
+ return (hasErrorStream(condition) || (exitedGracefully(condition) && exitedWithError(session)));
+ }
+
+ private boolean exitedWithError(Session session) {
+ return session.getExitStatus() != ProcessResult.SUCCESS;
+ }
+
+ private boolean exitedGracefully(int condition) {
+ return (condition | ChannelCondition.EXIT_STATUS) == condition;
+ }
+
+ private boolean hasErrorStream(int condition) {
+ return (condition | ChannelCondition.STDERR_DATA) == condition;
+ }
+
+ private ProcessResult executeCommand(Connection sshConnection, String command) {
+ try {
+ Session session = sshConnection.openSession();
+ BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(new StreamGobbler(
+ session.getStdout())));
+ BufferedReader stderrReader = new BufferedReader(new InputStreamReader(new StreamGobbler(
+ session.getStderr())));
+ session.execCommand(command);
+ ProcessResult result = getResultOfExecution(session, stdoutReader, stderrReader);
+ session.close();
+ return result;
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private ProcessResult getResultOfExecution(Session session, BufferedReader stdoutReader, BufferedReader stderrReader) {
+ // Wait for program to come out either
+ // a) gracefully with an exit status, OR
+ // b) because of a termination signal
+ int condition = session.waitForCondition(ChannelCondition.EXIT_SIGNAL | ChannelCondition.EXIT_STATUS, 5000);
+ StringBuilder output = new StringBuilder();
+
+ try {
+ readFromStream(stdoutReader, output);
+ if (hasErrors(condition, session)) {
+ readFromStream(stderrReader, output);
+ }
+
+ return prepareProcessResult(session, condition, output);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private ProcessResult prepareProcessResult(Session session, int condition, StringBuilder output) {
+ ProcessResult result = null;
+ if (wasTerminated(condition)) {
+ result = new ProcessResult(ProcessResult.FAILURE, output.toString());
+ } else {
+ if (hasErrors(condition, session)) {
+ Integer exitStatus = session.getExitStatus();
+ int statusCode = (exitStatus == null ? ProcessResult.FAILURE : exitStatus);
+ result = new ProcessResult(statusCode, output.toString());
+ } else {
+ result = new ProcessResult(ProcessResult.SUCCESS, output.toString());
+ }
+ }
+ return result;
+ }
+
+ private void readFromStream(BufferedReader streamReader, StringBuilder output) throws IOException,
+ UnsupportedEncodingException {
+ while (true) {
+ String line = streamReader.readLine();
+ if (line == null) {
+ break;
+ }
+ output.append(line + CoreConstants.NEWLINE);
+ }
+ }
+
+ /**
+ * Executes given command on remote machine using password authentication
+ *
+ * @param serverName
+ * @param command
+ * @return Result of remote execution
+ */
+ public ProcessResult executeRemoteWithPassword(String serverName, String command) {
+ return executeCommand(getConnectionWithPassword(serverName), command);
+ }
+
+ /**
+ * Executes given command on remote machine using public key authentication
+ *
+ * @param serverName
+ * @param command
+ * @return Result of remote execution
+ */
+ public ProcessResult executeRemote(String serverName, String command) {
+ return executeCommand(getConnection(serverName), command);
+ }
+
+ /**
+ * Checks if public key of management gateway is configured on given server
+ *
+ * @param serverName
+ * @return true if public key is configured, else false
+ */
+ public boolean isPublicKeySetup(String serverName) {
+ try {
+ getConnection(serverName);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public void cleanup() {
+ for (Connection conn : sshConnCache.values()) {
+ conn.close();
+ }
+ }
+
+ public static void main(String[] args) {
+ SshUtil sshUtil = new SshUtil();
+ System.out.println(new Date());
+ ProcessResult result = sshUtil.executeRemote("dev.gluster.com", "/bin/pwd");
+ System.out.println(result.getOutput());
+ result = sshUtil.executeRemote("dev.gluster.com", "/bin/pwd1");
+ System.out.println(new Date() + " - " + result.getExitValue() + " - " + result.getOutput());
+ result = sshUtil.executeRemote("dev.gluster.com", "/bin/ls -lrt");
+ System.out.println(new Date() + " - " + result.getExitValue() + " - " + result.getOutput());
+
+ sshUtil.cleanup();
+ }
+}