summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java8
-rw-r--r--src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java8
-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/constants/RESTConstants.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.core/src/com/gluster/storage/management/core/utils/StringUtil.java2
-rw-r--r--src/com.gluster.storage.management.gui/plugin.xml2
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java6
-rw-r--r--src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java2
-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.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java62
-rw-r--r--src/com.gluster.storage.management.server.scripts/src/nodes/Disk.py3
-rwxr-xr-xsrc/com.gluster.storage.management.server.scripts/src/nodes/get_server_details.py (renamed from src/com.gluster.storage.management.server.scripts/src/nodes/GetServerDetails.py)10
-rw-r--r--src/com.gluster.storage.management.server/.project1
-rw-r--r--src/com.gluster.storage.management.server/.pydevproject7
-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/WebContent/WEB-INF/web.xml8
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java105
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java39
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java3
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java43
-rw-r--r--src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java271
24 files changed, 592 insertions, 81 deletions
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
index 0051d427..f98509f4 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterDataModelManager.java
@@ -113,13 +113,13 @@ public class GlusterDataModelManager {
servers.add(server);
}
- public void initializeModel(String securityToken) {
+ public void initializeModel(String securityToken, String knownServer) {
model = new GlusterDataModel("Gluster Data Model");
setSecurityToken(securityToken);
Cluster cluster = new Cluster("Home", model);
- initializeGlusterServers(cluster);
+ initializeGlusterServers(cluster, knownServer);
initializeVolumes(cluster);
initializeAutoDiscoveredServers(cluster);
@@ -228,8 +228,8 @@ public class GlusterDataModelManager {
volume5.addDisk("server5:sdb");
}
- private void initializeGlusterServers(Cluster cluster) {
- cluster.setServers(new GlusterServersClient(securityToken).getServers());
+ private void initializeGlusterServers(Cluster cluster, String knownServer) {
+ cluster.setServers(new GlusterServersClient(securityToken).getServers(knownServer));
}
private void initializeAutoDiscoveredServers(Cluster cluster) {
diff --git a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java
index d4809daf..98b8878c 100644
--- a/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java
+++ b/src/com.gluster.storage.management.client/src/com/gluster/storage/management/client/GlusterServersClient.java
@@ -44,8 +44,10 @@ public class GlusterServersClient extends AbstractClient {
return RESOURCE_NAME;
}
- public List<GlusterServer> getServers() {
- GlusterServerListResponse response = (GlusterServerListResponse) fetchResource(GlusterServerListResponse.class);
+ public List<GlusterServer> getServers(String knownServer) {
+ MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
+ queryParams.add(RESTConstants.QUERY_PARAM_KNOWN_SERVER, knownServer);
+ GlusterServerListResponse response = (GlusterServerListResponse) fetchResource(queryParams, GlusterServerListResponse.class);
return response.getServers();
}
@@ -76,7 +78,7 @@ public class GlusterServersClient extends AbstractClient {
if (usersClient.authenticate("gluster", "gluster").isSuccess()) {
GlusterServersClient serverResource = new GlusterServersClient(usersClient.getSecurityToken());
- List<GlusterServer> glusterServers = serverResource.getServers();
+ List<GlusterServer> glusterServers = serverResource.getServers("127.0.0.1");
for (GlusterServer server : glusterServers) {
System.out.println(server.getName());
}
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.core/src/com/gluster/storage/management/core/constants/RESTConstants.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
index d5c1bad3..c25d186a 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/constants/RESTConstants.java
@@ -56,6 +56,7 @@ public class RESTConstants {
public static final String QUERY_PARAM_TO_TIMESTAMP = "toTimestamp";
public static final String QUERY_PARAM_DOWNLOAD = "download";
public static final String QUERY_PARAM_SERVER_NAME = "serverName";
+ public static final String QUERY_PARAM_KNOWN_SERVER = "knownServer";
// Running tasks resource
public static final String RESOURCE_PATH_RUNNING_TASKS = "/cluster/runningtasks";
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.core/src/com/gluster/storage/management/core/utils/StringUtil.java b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java
index 34cbfb3b..556c12de 100644
--- a/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java
+++ b/src/com.gluster.storage.management.core/src/com/gluster/storage/management/core/utils/StringUtil.java
@@ -37,7 +37,7 @@ public class StringUtil {
output.append(element).append(delimiter);
}
String outputStr = output.toString();
- int endIndex = (list.size() > 1) ? outputStr.length() - (delimiter.length() + 1) : outputStr.length() - 1;
+ int endIndex = (list.size() > 1) ? outputStr.length() - (delimiter.length() + 1) : outputStr.length() - delimiter.length();
return outputStr.substring(0, endIndex);
}
diff --git a/src/com.gluster.storage.management.gui/plugin.xml b/src/com.gluster.storage.management.gui/plugin.xml
index 0c6fc60e..7a8c07e0 100644
--- a/src/com.gluster.storage.management.gui/plugin.xml
+++ b/src/com.gluster.storage.management.gui/plugin.xml
@@ -385,7 +385,7 @@
definitionId="org.eclipse.ui.window.preferences"
icon="icons/preferences.png"
id="com.gluster.storage.management.gui.actions.AddServerAction"
- label="&amp;Preferences"
+ label="&amp;Settings"
menubarPath="com.gluster.storage.management.gui.menu.edit/edit"
mode="FORCE_TEXT"
pulldown="false"
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java
index 9b2bb8bc..b0645990 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/dialogs/CreateVolumePage1.java
@@ -102,8 +102,8 @@ public class CreateVolumePage1 extends WizardPage {
createTypeLabel(container);
createTypeCombo(container);
- createTransportTypeLabel(container);
- createTransportTypeValueLabel(container);
+// createTransportTypeLabel(container);
+// createTransportTypeValueLabel(container);
createDisksLabel(container);
createDisksCustomizeLink(container);
@@ -293,7 +293,7 @@ public class CreateVolumePage1 extends WizardPage {
IStructuredSelection selection = (IStructuredSelection)typeComboViewer.getSelection();
volume.setVolumeType((VOLUME_TYPE)selection.getFirstElement());
- volume.setTransportType(TRANSPORT_TYPE.ETHERNET);
+ volume.setTransportType(TRANSPORT_TYPE.ETHERNET); // Support only for Ethernet
Set<NAS_PROTOCOL> nasProtocols = new HashSet<Volume.NAS_PROTOCOL>();
nasProtocols.add(NAS_PROTOCOL.GLUSTERFS);
nasProtocols.add(NAS_PROTOCOL.NFS);
diff --git a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java
index c6ffa8d5..7705a631 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/login/LoginDialog.java
@@ -193,7 +193,7 @@ public class LoginDialog extends Dialog {
UsersClient usersClient = new UsersClient();
if (usersClient.authenticate(user, password).isSuccess()) {
try {
- GlusterDataModelManager.getInstance().initializeModel(usersClient.getSecurityToken());
+ GlusterDataModelManager.getInstance().initializeModel(usersClient.getSecurityToken(), "127.0.0.1");
super.okPressed();
} catch (Exception e) {
setReturnCode(RETURN_CODE_ERROR);
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.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java
index 3c633bf4..b8356ed0 100644
--- a/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java
+++ b/src/com.gluster.storage.management.gui/src/com/gluster/storage/management/gui/views/VolumeSummaryView.java
@@ -1,5 +1,6 @@
package com.gluster.storage.management.gui.views;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
@@ -29,14 +30,18 @@ import org.eclipse.ui.part.ViewPart;
import com.gluster.storage.management.client.GlusterDataModelManager;
import com.gluster.storage.management.client.VolumesClient;
import com.gluster.storage.management.core.model.Alert;
+import com.gluster.storage.management.core.model.Cluster;
import com.gluster.storage.management.core.model.DefaultClusterListener;
import com.gluster.storage.management.core.model.Event;
import com.gluster.storage.management.core.model.Event.EVENT_TYPE;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
import com.gluster.storage.management.core.model.Status;
import com.gluster.storage.management.core.model.Volume;
import com.gluster.storage.management.core.model.Volume.NAS_PROTOCOL;
import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
import com.gluster.storage.management.core.utils.NumberUtil;
+import com.gluster.storage.management.core.utils.StringUtil;
import com.gluster.storage.management.core.utils.ValidationUtil;
import com.gluster.storage.management.gui.IImageKeys;
import com.gluster.storage.management.gui.toolbar.GlusterToolbarManager;
@@ -56,6 +61,7 @@ public class VolumeSummaryView extends ViewPart {
private ControlDecoration errDecoration;
private Composite parent;
private static final String COURIER_FONT = "Courier";
+ private Cluster cluster = GlusterDataModelManager.getInstance().getModel().getCluster();
@Override
public void createPartControl(Composite parent) {
@@ -139,42 +145,36 @@ public class VolumeSummaryView extends ViewPart {
private void createVolumeMountingInfoSection() {
String glusterFs = "Gluster:";
String nfs = "NFS:";
- String glusterFsSyntax = "mount -t glusterfs <SERVER-NAME>:/<VOLUME-NAME> <MOUNT-POINT>";
- String nfsSyntax = "mount -t nfs <SERVER-NAME>:/nfs/<VOLUME-NAME> <MOUNT-POINT>";
- String info = "<SERVER-NAME> - Any server name in the storage cloud";
- String volumeName = volume.getName().trim();
- String serverName = volume.getDisks().get(0).split(":")[0].trim(); // disk if the form of: "server:disk"
-
- Composite section = guiHelper.createSection(form, toolkit, "Mounting Information", null, 2, false);
-
- Label lbl = toolkit.createLabel(section, "Syntax");
- final int defaultFontSize = lbl.getFont().getFontData()[0].getHeight();
- final String defaultFontName = lbl.getFont().getFontData()[0].name;
+ String onlineServers = getOnlineServers(10); // Limited to 10 servers
+ String firstOnlineServer = onlineServers.split(",")[0].trim();
+ String glusterFsMountInfo = "mount -t glusterfs " + firstOnlineServer + ":/" + volume.getName() + " <mount-point>";
+ String nfsMountInfo = "mount -t nfs " + firstOnlineServer + ":/" + volume.getName() + " <mount-point>";
+ String info = "Server can be any server name in the storage cloud eg. <" + onlineServers + ">"; //TODO: if more than 10 servers...
- setLabelStyle(lbl, defaultFontName, defaultFontSize, SWT.BOLD);
- toolkit.createLabel(section, "");
+ Composite section = guiHelper.createSection(form, toolkit, "Mounting Information", null, 2, false);
- setLabelStyle(toolkit.createLabel(section, glusterFs), defaultFontName, defaultFontSize, SWT.NORMAL);
- setLabelStyle(toolkit.createLabel(section, glusterFsSyntax, SWT.NONE), COURIER_FONT, 10, SWT.NONE);
+ toolkit.createLabel(section, glusterFs, SWT.NORMAL);
+ setLabelStyle(toolkit.createLabel(section, glusterFsMountInfo, SWT.NONE), COURIER_FONT, 10, SWT.NONE);
// TODO: Check required if nfs is optional
- setLabelStyle(toolkit.createLabel(section, nfs), defaultFontName, defaultFontSize, SWT.NORMAL);
- setLabelStyle(toolkit.createLabel(section, nfsSyntax, SWT.NONE), COURIER_FONT, 10, SWT.NONE);
-
- toolkit.createLabel(section, "");
- setLabelStyle(toolkit.createLabel(section, info), defaultFontName, (defaultFontSize - 1), SWT.NONE);
+ toolkit.createLabel(section, nfs, SWT.NORMAL);
+ setLabelStyle(toolkit.createLabel(section, nfsMountInfo, SWT.NONE), COURIER_FONT, 10, SWT.NONE);
- setLabelStyle(toolkit.createLabel(section, "Example"), defaultFontName, defaultFontSize, SWT.BOLD);
toolkit.createLabel(section, "");
+ toolkit.createLabel(section, info, SWT.NONE);
+ }
- setLabelStyle(toolkit.createLabel(section, glusterFs), defaultFontName, defaultFontSize, SWT.NORMAL);
- setLabelStyle(toolkit.createLabel(section, "#mount -t glusterfs " + serverName + ":/" + volumeName + " /mnt"),
- COURIER_FONT, 10, SWT.NONE);
-
- // TODO: Check required if nfs is optional
- setLabelStyle(toolkit.createLabel(section, nfs), defaultFontName, defaultFontSize, SWT.NORMAL);
- setLabelStyle(toolkit.createLabel(section, "#mount -t nfs " + serverName + ":/" + volumeName + " /mnt"),
- COURIER_FONT, 10, SWT.NONE);
+ private String getOnlineServers(int maxServers) {
+ List<String> OnlineServers = new ArrayList<String>();
+ for (GlusterServer server : cluster.getServers()) {
+ if (server.getStatus() == SERVER_STATUS.ONLINE) {
+ OnlineServers.add(server.getName());
+ if (OnlineServers.size() >= maxServers) {
+ break;
+ }
+ }
+ }
+ return StringUtil.ListToString(OnlineServers, ", ") + ((OnlineServers.size() > maxServers) ? "..." : "");
}
/**
@@ -196,7 +196,7 @@ public class VolumeSummaryView extends ViewPart {
createNumOfDisksField(section);
createDiskSpaceField(section);
- createTransportTypeField(section);
+// createTransportTypeField(section);
createNASProtocolField(section);
createAccessControlField(section);
createStatusField(section);
@@ -398,7 +398,7 @@ public class VolumeSummaryView extends ViewPart {
private void updateVolumeStatusLabel() {
lblStatusValue.setText(volume.getStatusStr());
- lblStatusValue.setImage(volume.getStatus() == Volume.VOLUME_STATUS.ONLINE ? guiHelper
+ lblStatusValue.setImage((volume.getStatus() == Volume.VOLUME_STATUS.ONLINE) ? guiHelper
.getImage(IImageKeys.STATUS_ONLINE) : guiHelper.getImage(IImageKeys.STATUS_OFFLINE));
lblStatusValue.redraw();
}
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/Disk.py b/src/com.gluster.storage.management.server.scripts/src/nodes/Disk.py
index d5d8de31..6a4c2998 100644
--- a/src/com.gluster.storage.management.server.scripts/src/nodes/Disk.py
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/Disk.py
@@ -99,7 +99,8 @@ class Disk:
'description': str(parent.GetProperty('storage.model')) + " " + str(parent.GetProperty('storage.vendor')),
'size' : str(int(dev.GetProperty('volume.size')) / 1024**2),
'totalsize' : str(int(parent.GetProperty('storage.size')) / 1024**2),
- 'drive_type': str(parent.GetProperty('storage.drive_type'))
+ 'drive_type': str(parent.GetProperty('storage.drive_type')),
+ 'mount_point': str(dev.GetProperty('volume.mount_point'))
})
def _get_device(self, udi):
diff --git a/src/com.gluster.storage.management.server.scripts/src/nodes/GetServerDetails.py b/src/com.gluster.storage.management.server.scripts/src/nodes/get_server_details.py
index 440347a4..67148586 100755
--- a/src/com.gluster.storage.management.server.scripts/src/nodes/GetServerDetails.py
+++ b/src/com.gluster.storage.management.server.scripts/src/nodes/get_server_details.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python
# Copyright (C) 2009 Gluster, Inc. <http://www.gluster.com>
# This file is part of Gluster Storage Platform.
#
@@ -188,6 +189,7 @@ def getServerDetails():
continue
partitionTag = responseDom.createTag("disk", None)
partitionTag.appendChild(responseDom.createTag("name", os.path.basename(disk['device'])))
+ partitionTag.appendChild(responseDom.createTag("mountPoint", disk['mount_point']))
partitionTag.appendChild(responseDom.createTag("serverName", serverName))
partitionTag.appendChild(responseDom.createTag("description", disk['description']))
total, used, free = getDiskSizeInfo(disk['device'])
@@ -204,5 +206,9 @@ def getServerDetails():
serverTag.appendChild(responseDom.createTag("diskSpaceInUse", str(diskSpaceInUse)))
return serverTag
-def test():
- print getServerDetails().toxml()
+def main():
+ print getServerDetails().toprettyxml()
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.server/.project b/src/com.gluster.storage.management.server/.project
index 86d34a3b..259b3726 100644
--- a/src/com.gluster.storage.management.server/.project
+++ b/src/com.gluster.storage.management.server/.project
@@ -37,6 +37,5 @@
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
- <nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
diff --git a/src/com.gluster.storage.management.server/.pydevproject b/src/com.gluster.storage.management.server/.pydevproject
deleted file mode 100644
index a9cca037..00000000
--- a/src/com.gluster.storage.management.server/.pydevproject
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?eclipse-pydev version="1.0"?>
-
-<pydev_project>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
-</pydev_project>
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/WebContent/WEB-INF/web.xml b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
index 6d7d1406..7c7d42d3 100644
--- a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
+++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml
@@ -64,6 +64,14 @@
<!-- Spring Security -->
<filter>
+ <filter-name>authFailureFilter</filter-name>
+ <filter-class>com.gluster.storage.management.server.filters.AuthenticationFailureFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>authFailureFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java
new file mode 100644
index 00000000..5f828f65
--- /dev/null
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.filters;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.ws.rs.core.Response;
+
+/**
+ * @author root
+ *
+ */
+public class AuthenticationFailureFilter implements Filter {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#destroy()
+ */
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public class CharResponseWrapper extends HttpServletResponseWrapper {
+ private CharArrayWriter output;
+
+ public String toString() {
+ return output.toString();
+ }
+
+ public CharResponseWrapper(HttpServletResponse response) {
+ super(response);
+ output = new CharArrayWriter();
+ }
+
+ public PrintWriter getWriter() {
+ return new PrintWriter(output);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse,
+ * javax.servlet.FilterChain)
+ */
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
+ ServletException {
+ HttpServletRequest request = (HttpServletRequest) req;
+ if (request.getRequestURI().contains("download")) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) res);
+ chain.doFilter(req, wrapper);
+
+ if(wrapper.getStatus() == Response.Status.UNAUTHORIZED.ordinal()) {
+ PrintWriter out = res.getWriter();
+ out.println("<status><code>1</code><message>Authentication Failed!</message></status>");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+ */
+ @Override
+ public void init(FilterConfig arg0) throws ServletException {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java
index 4f2850ee..3092e80d 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/GlusterServersResource.java
@@ -32,6 +32,7 @@ import javax.ws.rs.core.MediaType;
import org.springframework.stereotype.Component;
+import com.gluster.storage.management.core.constants.RESTConstants;
import com.gluster.storage.management.core.model.GlusterServer;
import com.gluster.storage.management.core.model.GlusterServer.SERVER_STATUS;
import com.gluster.storage.management.core.model.Server;
@@ -39,21 +40,32 @@ import com.gluster.storage.management.core.model.Status;
import com.gluster.storage.management.core.response.GlusterServerListResponse;
import com.gluster.storage.management.core.response.GlusterServerResponse;
import com.gluster.storage.management.server.utils.GlusterUtil;
+import com.gluster.storage.management.server.utils.SshUtil;
+import com.sun.jersey.api.core.InjectParam;
import com.sun.jersey.spi.resource.Singleton;
@Component
@Singleton
@Path("/cluster/servers")
public class GlusterServersResource extends AbstractServersResource {
- private GlusterUtil glusterUtil = new GlusterUtil();
+ @InjectParam
+ private GlusterUtil glusterUtil;
+
public static final String HOSTNAMETAG = "hostname:";
- private List<GlusterServer> getServerDetails() {
- List<GlusterServer> glusterServers = glusterUtil.getGlusterServers();
+ public void setGlusterUtil(GlusterUtil glusterUtil) {
+ this.glusterUtil = glusterUtil;
+ }
+
+ public GlusterUtil getGlusterUtil() {
+ return glusterUtil;
+ }
+
+ private List<GlusterServer> getServerDetails(String knownServer) {
+ List<GlusterServer> glusterServers = glusterUtil.getGlusterServers(knownServer);
for (GlusterServer server : glusterServers) {
if (server.getStatus() == SERVER_STATUS.ONLINE) {
fetchServerDetails(server);
- // server.setPreferredNetworkInterface(server.getNetworkInterfaces().get(0));
}
}
return glusterServers;
@@ -61,17 +73,17 @@ public class GlusterServersResource extends AbstractServersResource {
@GET
@Produces(MediaType.TEXT_XML)
- public GlusterServerListResponse getGlusterServers() {
- return new GlusterServerListResponse(Status.STATUS_SUCCESS, getServerDetails());
+ public GlusterServerListResponse getGlusterServers(@QueryParam(RESTConstants.QUERY_PARAM_KNOWN_SERVER) String knownServer) {
+ return new GlusterServerListResponse(Status.STATUS_SUCCESS, getServerDetails(knownServer));
}
@GET
@Path("{serverName}")
@Produces(MediaType.TEXT_XML)
public GlusterServer getGlusterServer(@PathParam("serverName") String serverName) {
+ // TODO: Implement logic to fetch details of a single gluster server (peer)
GlusterServer server = new GlusterServer(serverName);
fetchServerDetails(server);
- // server.setPreferredNetworkInterface(server.getNetworkInterfaces().get(0));
server.setStatus(SERVER_STATUS.ONLINE);
return server;
}
@@ -93,8 +105,8 @@ public class GlusterServersResource extends AbstractServersResource {
@POST
@Produces(MediaType.TEXT_XML)
- public GlusterServerResponse addServer(@FormParam("serverName") String serverName) {
- Status status = glusterUtil.addServer(serverName);
+ public GlusterServerResponse addServer(@FormParam("serverName") String serverName, @FormParam("existingServer") String existingServer) {
+ Status status = glusterUtil.addServer(serverName, existingServer);
if (!status.isSuccess()) {
return new GlusterServerResponse(status, null);
@@ -110,10 +122,13 @@ public class GlusterServersResource extends AbstractServersResource {
public static void main(String[] args) {
GlusterServersResource glusterServersResource = new GlusterServersResource();
- System.out.println(glusterServersResource.getServerDetails());
+ GlusterUtil glusterUtil = new GlusterUtil();
+ glusterUtil.setSshUtil(new SshUtil());
+ glusterServersResource.setGlusterUtil(glusterUtil);
+ System.out.println(glusterServersResource.getServerDetails("127.0.0.1").size());
// To add a server
- GlusterServerResponse response = glusterServersResource.addServer("my-server");
- System.out.println(response.getData().getName());
+// GlusterServerResponse response = glusterServersResource.addServer("my-server");
+// System.out.println(response.getData().getName());
}
}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java
index 51134317..5e9c1945 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/UsersResource.java
@@ -69,8 +69,9 @@ public class UsersResource {
@Path("{user}")
@GET
@Produces(MediaType.TEXT_XML)
- public Status login(@PathParam("user") String user) {
+ public Status authenticate(@PathParam("user") String user) {
// success only if the user passed in query is same as the one passed in security header
+ // spring security would have already authenticated the user credentials
return (SecurityContextHolder.getContext().getAuthentication().getName().equals(user) ? Status.STATUS_SUCCESS
: Status.STATUS_FAILURE);
}
diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
index 6db6bffc..91f809b8 100644
--- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java
@@ -20,11 +20,13 @@
*/
package com.gluster.storage.management.server.utils;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gluster.storage.management.core.constants.CoreConstants;
@@ -56,11 +58,22 @@ public class GlusterUtil {
private static final String VOLUME_TRANSPORT_TYPE_PFX = "Transport-type:";
private static final String VOLUME_BRICKS_GROUP_PFX = "Bricks";
private static final String VOLUME_OPTIONS_RECONFIG_PFX = "Options Reconfigured";
- private static final String VOLUME_OPTION_AUTH_ALLOW = "auth.allow:";
+ private static final String VOLUME_OPTION_AUTH_ALLOW_PFX = "auth.allow:";
private static final String VOLUME_LOG_LOCATION_PFX = "log file location:";
private static final String VOLUME_TYPE_DISTRIBUTE = "Distribute";
private static final String VOLUME_TYPE_REPLICATE = "Replicate";
private static final ProcessUtil processUtil = new ProcessUtil();
+
+ @Autowired
+ private SshUtil sshUtil;
+
+ public void setSshUtil(SshUtil sshUtil) {
+ this.sshUtil = sshUtil;
+ }
+
+ public SshUtil getSshUtil() {
+ return sshUtil;
+ }
/**
* Extract value of given token from given line. It is assumed that the token, if present, will be of the following
@@ -79,8 +92,8 @@ public class GlusterUtil {
return null;
}
- public List<GlusterServer> getGlusterServers() {
- String output = getPeerStatus();
+ public List<GlusterServer> getGlusterServers(String knownServer) {
+ String output = getPeerStatus(knownServer);
if (output == null) {
return null;
}
@@ -127,8 +140,8 @@ public class GlusterUtil {
return glusterServers;
}
- public List<String> getGlusterServerNames() {
- String output = getPeerStatus();
+ public List<String> getGlusterServerNames(String knownServer) {
+ String output = getPeerStatus(knownServer);
if (output == null) {
return null;
}
@@ -143,9 +156,15 @@ public class GlusterUtil {
return glusterServerNames;
}
- private String getPeerStatus() {
+ /**
+ * @param knownServer
+ * A known server on which the gluster command will be executed to fetch peer status
+ * @return Outout of the "gluster peer status" command
+ */
+ private String getPeerStatus(String knownServer) {
String output;
- ProcessResult result = processUtil.executeCommand("gluster", "peer", "status");
+ //ProcessResult result = processUtil.executeCommand("gluster", "peer", "status");
+ ProcessResult result = getSshUtil().executeRemote(knownServer, "gluster peer status");
if (!result.isSuccess()) {
output = null;
}
@@ -153,8 +172,8 @@ public class GlusterUtil {
return output;
}
- public Status addServer(String serverName) {
- return new Status(processUtil.executeCommand("gluster", "peer", "probe", serverName));
+ public Status addServer(String serverName, String existingServer) {
+ return new Status(sshUtil.executeRemote(existingServer, "gluster peer probe " + serverName));
}
public Status startVolume(String volumeName) {
@@ -460,10 +479,10 @@ public class GlusterUtil {
public String getLogFileNameForBrickDir(String brickDir) {
String logFileName = brickDir;
- if (logFileName.startsWith(CoreConstants.FILE_SEPARATOR)) {
- logFileName = logFileName.replaceFirst(CoreConstants.FILE_SEPARATOR, "");
+ if (logFileName.startsWith(File.separator)) {
+ logFileName = logFileName.replaceFirst(File.separator, "");
}
- logFileName = logFileName.replaceAll(CoreConstants.FILE_SEPARATOR, "-") + ".log";
+ logFileName = logFileName.replaceAll(File.separator, "-") + ".log";
return logFileName;
}
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..5816533b
--- /dev/null
+++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * 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 org.springframework.stereotype.Component;
+
+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;
+
+/**
+ *
+ */
+@Component
+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();
+ }
+}