diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/CoreConstants.java | 1 | ||||
| -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.java | 1 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/utils/ImageUtil.java | 1 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt | 87 | ||||
| -rw-r--r-- | src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar | bin | 0 -> 248915 bytes | |||
| -rw-r--r-- | src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java | 268 |
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 Binary files differnew file mode 100644 index 00000000..c0a9ac7b --- /dev/null +++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar 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(); + } +} |
