summaryrefslogtreecommitdiffstats
path: root/src/org.gluster.storage.management.gateway
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-11-25 20:13:35 +0530
commit1142b0e41de39010de7845cf70d71dbb001fc1dc (patch)
tree3513487f65c1a7df47996bd2852393aceaac1b8a /src/org.gluster.storage.management.gateway
parent92c52d8edf285945d31e446503fc742fde9dcc49 (diff)
Renamed projects / packages com.gluster.* to org.gluster.*
Diffstat (limited to 'src/org.gluster.storage.management.gateway')
-rw-r--r--src/org.gluster.storage.management.gateway/.classpath14
-rw-r--r--src/org.gluster.storage.management.gateway/.project36
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/.jsdtscope12
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs3
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component10
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml20
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container1
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name1
-rw-r--r--src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs3
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF3
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-LICENSE.txt135
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-third-party-license-readme.txt188
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jarbin0 -> 443432 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jarbin0 -> 4467 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jarbin0 -> 43033 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jarbin0 -> 559366 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jarbin0 -> 60841 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jarbin0 -> 2512189 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jarbin0 -> 165188 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jarbin0 -> 313898 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt87
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jarbin0 -> 248915 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jarbin0 -> 100884 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jarbin0 -> 4133342 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jarbin0 -> 171958 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jarbin0 -> 17065 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jarbin0 -> 485699 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jarbin0 -> 24745 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jarbin0 -> 633312 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jarbin0 -> 128096 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jarbin0 -> 455665 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jarbin0 -> 144810 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jarbin0 -> 49330 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jarbin0 -> 681117 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jarbin0 -> 17079 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jarbin0 -> 67758 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jarbin0 -> 61712 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jarbin0 -> 46367 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jarbin0 -> 10899 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jarbin0 -> 481534 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jarbin0 -> 38683 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jarbin0 -> 101958 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jarbin0 -> 321190 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jarbin0 -> 53082 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jarbin0 -> 35548 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jarbin0 -> 555410 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jarbin0 -> 668861 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jarbin0 -> 100870 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jarbin0 -> 382442 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jarbin0 -> 169752 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jarbin0 -> 1810 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jarbin0 -> 5728 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jarbin0 -> 385712 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jarbin0 -> 185312 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jarbin0 -> 334327 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jarbin0 -> 61379 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd21
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jarbin0 -> 205278 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jarbin0 -> 231922 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jarbin0 -> 395587 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jarbin0 -> 175412 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jarbin0 -> 418977 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jarbin0 -> 31404 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jarbin0 -> 176386 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jarbin0 -> 25496 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-framework-3.0.5.RELEASE-LICENSE.txt201
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-3.0.5.RELEASE-LICENSE.txt201
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jarbin0 -> 185716 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jarbin0 -> 311038 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jarbin0 -> 242833 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml76
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql2
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql26
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql18
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql16
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/index.html158
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/Globals.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/Protocol.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/Utils.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/create_volume_cifs_all.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/delete_volume_cifs_all.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/get_volume_user_cifs.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/gmg-reset-password.sh1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/grun.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/remove_server_volume_cifs_config.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/setup_cifs_config_all.py1
l---------src/org.gluster.storage.management.gateway/WebContent/scripts/update_volume_cifs_all.py1
-rw-r--r--src/org.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystorebin0 -> 1380 bytes
-rw-r--r--src/org.gluster.storage.management.gateway/buckminster.cspex37
-rw-r--r--src/org.gluster.storage.management.gateway/build/glusterserver.ant70
-rw-r--r--src/org.gluster.storage.management.gateway/src/META-INF/persistence.xml5
-rw-r--r--src/org.gluster.storage.management.gateway/src/log4j.properties20
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ClusterInfo.java79
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/GlusterDataSource.java48
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/PersistenceDao.java113
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ServerInfo.java72
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuditFilter.java48
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java105
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java31
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/listeners/ShutdownListener.java48
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java177
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java126
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java101
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java60
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java343
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/KeysResource.java155
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/TasksResource.java226
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/UsersResource.java124
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java383
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/GlusterUserDetailsService.java31
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/UserAuthDao.java57
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/AbstractGlusterInterface.java38
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/ClusterService.java269
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/DiscoveredServerService.java130
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/Gluster323InterfaceService.java598
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterface.java369
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterfaceService.java256
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterServerService.java530
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/VolumeService.java984
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java161
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java198
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java220
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java141
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java168
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java113
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/AbstractStatsFactory.java162
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/CpuStatsFactory.java36
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/DBUtil.java84
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/MemoryStatsFactory.java68
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/NetworkStatsFactory.java173
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/PasswordManager.java83
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/ServerUtil.java370
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/SshUtil.java463
-rw-r--r--src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/StatsFactory.java32
-rw-r--r--src/org.gluster.storage.management.gateway/src/rebel.xml16
-rw-r--r--src/org.gluster.storage.management.gateway/src/spring/gluster-server-base.xml100
-rw-r--r--src/org.gluster.storage.management.gateway/src/spring/gluster-server-security.xml49
143 files changed, 9528 insertions, 0 deletions
diff --git a/src/org.gluster.storage.management.gateway/.classpath b/src/org.gluster.storage.management.gateway/.classpath
new file mode 100644
index 00000000..894a6c4d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0">
+ <attributes>
+ <attribute name="owner.project.facets" value="jst.web"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
+ <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/org.gluster.storage.management.core"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="output" path="WebContent/WEB-INF/classes"/>
+</classpath>
diff --git a/src/org.gluster.storage.management.gateway/.project b/src/org.gluster.storage.management.gateway/.project
new file mode 100644
index 00000000..c0861c4e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.gluster.storage.management.gateway</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <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>
+ </natures>
+</projectDescription>
diff --git a/src/org.gluster.storage.management.gateway/.settings/.jsdtscope b/src/org.gluster.storage.management.gateway/.settings/.jsdtscope
new file mode 100644
index 00000000..3a28de0c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/.jsdtscope
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="WebContent"/>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
+ <attributes>
+ <attribute name="hide" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
+ <classpathentry kind="output" path=""/>
+</classpath>
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.core.resources.prefs b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..d159aeca
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Tue Sep 20 14:10:09 IST 2011
+eclipse.preferences.version=1
+encoding//src/rebel.xml=UTF-8
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..476db350
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Dec 29 14:57:23 IST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 00000000..5d9c71b6
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Mon Jan 31 15:29:36 IST 2011
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component
new file mode 100644
index 00000000..5d8e9376
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.gluster.storage.management.gateway">
+ <wb-resource deploy-path="/" source-path="/WebContent"/>
+ <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
+ <wb-resource deploy-path="/WEB-INF/classes" source-path="/junit"/>
+ <property name="java-output-path" value="/org.gluster.storage.management.gateway/build/classes"/>
+ <property name="context-root" value="glustermg"/>
+ </wb-module>
+</project-modules>
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 00000000..8f960f27
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright (c) 2011 IBM Corporation and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ IBM Corporation - initial API and implementation
+ -->
+
+<faceted-project>
+ <runtime name="Apache Tomcat v7.0"/>
+ <fixed facet="wst.jsdt.web"/>
+ <fixed facet="jst.web"/>
+ <fixed facet="java"/>
+ <installed facet="java" version="1.6"/>
+ <installed facet="jst.web" version="3.0"/>
+ <installed facet="wst.jsdt.web" version="1.0"/>
+</faceted-project>
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 00000000..3bd5d0a4
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 00000000..05bd71b6
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs
new file mode 100644
index 00000000..e5ca6272
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs
@@ -0,0 +1,3 @@
+#Mon Jan 31 15:29:36 IST 2011
+eclipse.preferences.version=1
+org.eclipse.wst.ws.service.policy.projectEnabled=false
diff --git a/src/org.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF b/src/org.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..5e949512
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-LICENSE.txt b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-LICENSE.txt
new file mode 100644
index 00000000..d24fbfdb
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-LICENSE.txt
@@ -0,0 +1,135 @@
+The GNU General Public License (GPL) Version 2, June 1991
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+ One line to give the program's name and a brief idea of what it does.
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ signature of Ty Coon, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL VERSION 2
+
+Certain source files distributed by Oracle are subject to the following clarification and special exception to the GPL Version 2, but only where Oracle has expressly included in the particular source file's header the words "Oracle designates this particular file as subject to the "Classpath" exception as provided by Oracle in the License file that accompanied this code."
+
+Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License Version 2 cover the whole combination.
+
+As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-third-party-license-readme.txt b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-third-party-license-readme.txt
new file mode 100644
index 00000000..b3acf520
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/Jersey-third-party-license-readme.txt
@@ -0,0 +1,188 @@
+
+DO NOT TRANSLATE OR LOCALIZE.
+
+%% The following software may be included in this product: ASM
+ Use of any of this software is governed by the terms of the license below:
+
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the copyright holders 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 following software may be included in this product: Jettison
+ Use of any of this software is governed by the terms of the license below:
+
+
+Copyright 2006 Envoi Solutions LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+--------------------------------------------------------------------------
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+
+
+
+%% The following software may be included in this product: Jackson
+ Use of any of this software is governed by the terms of the license below:
+
+
+Jackson is dual-licensed under two alternative popular Open Source licenses: Apache (AL 2.0) and Gnu Lesser GPL (LGPL 2.1). You choose one or the other, as necessary (if you want to redistribute the code ¿ for use, you do not need license), and abide by the license rules as defined by the respective license agreement (and only that one).
+
+--------------------------------------------------------------------------
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+ 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+ 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+ 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+
+
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar
new file mode 100644
index 00000000..3702b645
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar
new file mode 100644
index 00000000..578b1a0c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar
new file mode 100644
index 00000000..8217cae0
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar
new file mode 100644
index 00000000..41e230fe
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jar
new file mode 100644
index 00000000..8758a96b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar
new file mode 100644
index 00000000..dc8ae8df
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar
new file mode 100644
index 00000000..ca367aae
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar
new file mode 100644
index 00000000..c8c4dbb9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt
new file mode 100644
index 00000000..3eddd42f
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/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/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
new file mode 100644
index 00000000..c0a9ac7b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar
new file mode 100644
index 00000000..4c9ac4e9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar
new file mode 100644
index 00000000..c1c81141
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jar
new file mode 100644
index 00000000..a3248188
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jar
new file mode 100644
index 00000000..faf12cf6
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jar
new file mode 100644
index 00000000..ca612580
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jar
new file mode 100644
index 00000000..57c2c670
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jar
new file mode 100644
index 00000000..8f692f4f
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar
new file mode 100644
index 00000000..62f790fa
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar
new file mode 100644
index 00000000..92b38466
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar
new file mode 100644
index 00000000..01d8c83b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar
new file mode 100644
index 00000000..1c134f05
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar
new file mode 100644
index 00000000..a29d7409
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar
new file mode 100644
index 00000000..c79b4490
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar
new file mode 100644
index 00000000..e4e9c8c3
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar
new file mode 100644
index 00000000..23782c02
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jar
new file mode 100644
index 00000000..ec8bc818
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar
new file mode 100644
index 00000000..6d225b76
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar
new file mode 100644
index 00000000..3f9d8476
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar
new file mode 100644
index 00000000..48cc9295
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar
new file mode 100644
index 00000000..a5d37aa1
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..db6f529f
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..7cd3a626
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..11fc11b9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..f2e2e927
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..bd1367d8
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..e46f9eb8
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..ea9500d6
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..6ef99d8d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..e149290e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..dcd1e4d9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..f7a3b837
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..9cea2aef
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..d0550ccd
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..1688cf74
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd
new file mode 100644
index 00000000..b3aa6af8
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd
@@ -0,0 +1,21 @@
+Library-SymbolicName: org.springframework.spring
+Library-Version: 3.0.5.RELEASE
+Library-Name: Spring Framework
+Import-Bundle:
+ org.springframework.aop;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.asm;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.aspects;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.beans;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.context;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.context.support;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.core;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.expression;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.jdbc;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.jms;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.orm;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.oxm;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.transaction;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.web;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.web.servlet;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ org.springframework.web.portlet;version="[3.0.5.RELEASE, 3.0.5.RELEASE]",
+ com.springsource.org.aopalliance;version="[1.0.0, 1.0.0]"
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..237995c5
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..2f52122b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..5a2381a0
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..6ec9d681
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..6d13bd40
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..e351ae7b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar
new file mode 100644
index 00000000..e5bc672b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jar
new file mode 100644
index 00000000..f1f4fdd2
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-framework-3.0.5.RELEASE-LICENSE.txt b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-framework-3.0.5.RELEASE-LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-framework-3.0.5.RELEASE-LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-3.0.5.RELEASE-LICENSE.txt b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-3.0.5.RELEASE-LICENSE.txt
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-3.0.5.RELEASE-LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..78818fc5
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..a8077d5d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jar b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jar
new file mode 100644
index 00000000..26611b55
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml
new file mode 100644
index 00000000..4903f01d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
+ <display-name>glustermg</display-name>
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ <welcome-file>index.htm</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+ <welcome-file>default.html</welcome-file>
+ <welcome-file>default.htm</welcome-file>
+ <welcome-file>default.jsp</welcome-file>
+ </welcome-file-list>
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>
+ classpath:spring/gluster-server-security.xml
+ classpath:spring/gluster-server-base.xml
+ </param-value>
+ </context-param>
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+ <listener>
+ <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
+ </listener>
+ <listener>
+ <listener-class>org.gluster.storage.management.gateway.listeners.ShutdownListener</listener-class>
+ </listener>
+ <servlet>
+ <servlet-name>gluster-resources-1.0</servlet-name>
+ <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
+ <init-param>
+ <param-name>com.sun.jersey.config.property.packages</param-name>
+ <param-value>org.gluster.storage.management.gateway.resources.v1_0</param-value>
+ </init-param>
+ <init-param>
+ <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
+ <param-value>org.gluster.storage.management.gateway.filters.GlusterResourceFilterFactory</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>gluster-resources-1.0</servlet-name>
+ <url-pattern>/1.0.0/*</url-pattern>
+ </servlet-mapping>
+ <servlet>
+ <servlet-name>JnlpDownloadServlet</servlet-name>
+ <servlet-class>jnlp.sample.servlet.JnlpDownloadServlet</servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>JnlpDownloadServlet</servlet-name>
+ <url-pattern>*.jnlp</url-pattern>
+ </servlet-mapping>
+ <servlet-mapping>
+ <servlet-name>JnlpDownloadServlet</servlet-name>
+ <url-pattern>*.jar</url-pattern>
+ </servlet-mapping>
+ <filter>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <filter-class>
+ org.springframework.web.filter.DelegatingFilterProxy
+ </filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>springSecurityFilterChain</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Gluster Management Gateway</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+</web-app> \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql
new file mode 100644
index 00000000..4c3d81d1
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql
@@ -0,0 +1,2 @@
+create table version (version varchar(16) not null primary key);
+insert into version(version) values('1.0.0'); \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql
new file mode 100644
index 00000000..4f61fc9d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql
@@ -0,0 +1,26 @@
+create table users(
+ username varchar(32) not null primary key,
+ password varchar(124) not null,
+ enabled smallint not null
+ );
+
+ create table authorities (
+ username varchar(32) not null,
+ authority varchar(50) not null,
+ constraint fk_authorities_users foreign key(username) references users(username));
+ create unique index ix_auth_username on authorities (username,authority);
+
+create table groups (
+ id bigint generated by default as identity(start with 0) primary key,
+ group_name varchar(50) not null);
+
+create table group_authorities (
+ group_id bigint not null,
+ authority varchar(50) not null,
+ constraint fk_group_authorities_group foreign key(group_id) references groups(id));
+
+create table group_members (
+ id bigint generated by default as identity(start with 0) primary key,
+ username varchar(32) not null,
+ group_id bigint not null,
+ constraint fk_group_members_group foreign key(group_id) references groups(id));
diff --git a/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql
new file mode 100644
index 00000000..5bd73813
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql
@@ -0,0 +1,18 @@
+-- Create users
+insert into users(username, password, enabled) values ('gluster','syst3m',1);
+
+-- Assign authorities to users (to be removed after implementing user group functionality)
+insert into authorities(username,authority) values ('gluster','ROLE_USER');
+insert into authorities(username,authority) values ('gluster','ROLE_ADMIN');
+
+-- Create user groups
+insert into groups(group_name) values ('Users');
+insert into groups(group_name) values ('Administrators');
+
+-- Add authorities to groups (functionality not yet implemented in code)
+insert into group_authorities(group_id, authority) select id,'ROLE_USER' from groups where group_name='Users';
+insert into group_authorities(group_id, authority) select id,'ROLE_USER' from groups where group_name='Administrators';
+insert into group_authorities(group_id, authority) select id,'ROLE_ADMIN' from groups where group_name='Administrators';
+
+-- Assign group members
+insert into group_members(group_id, username) select id,'gluster' from groups where group_name='Administrators'; \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql
new file mode 100644
index 00000000..17ca62d2
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql
@@ -0,0 +1,16 @@
+create table cluster_info (
+ id bigint generated by default as identity,
+ name varchar(255),
+ primary key (id));
+
+create unique index ix_cluster_name on cluster_info (name);
+
+create table server_info (
+ id bigint generated by default as identity,
+ name varchar(255),
+ cluster_id bigint,
+ primary key (id));
+
+create unique index ix_cluster_server on server_info (name, cluster_id);
+
+alter table server_info add constraint FK_CLUSTER_ID foreign key (cluster_id) references cluster_info(id); \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/index.html b/src/org.gluster.storage.management.gateway/WebContent/index.html
new file mode 100644
index 00000000..5947cf11
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/index.html
@@ -0,0 +1,158 @@
+<html>
+<head>
+ <title>Gluster Management Console</title>
+
+ <script type="text/javascript">
+
+ // Try to identify operating system (os), windowing system (ws) and CPU architecture (arch)
+ // If found, automatically redirect to appropriate JNLP url.
+ // If not, provide hyperlinks for all available options
+ function startGMC()
+ {
+ var OSName="Unknown OS";
+ if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
+ if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
+ if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
+ if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
+
+ var os = "unknown";
+ var ws = "unknown";
+ var arch = "unknown";
+
+ if ( navigator.platform != null ) {
+ platform = navigator.platform.toLowerCase();
+ if ( platform.indexOf( "win32" ) != -1 || platform.indexOf( "win64" ) != -1 ) {
+ os = "win32";
+ ws = "win32";
+ arch = "x86";
+ if ( platform.indexOf( "win64" ) != -1 ) {
+ arch = "x86_64";
+ }
+ } else if ( platform.indexOf( "linux" ) != -1 ) {
+ os = "linux";
+ ws = "gtk";
+ arch = "x86";
+ if ( platform.indexOf ("x86_64") != -1 || platform.indexOf ( "i686" ) != -1 ) {
+ arch = "x86_64";
+ }
+ } else if ( platform.indexOf( "mac" ) != -1 ) {
+ os = "macosx";
+ ws = "cocoa";
+ // There is no known way of finding CPU architecture in Mac as of now!
+ }
+ }
+
+ // In windows, cpuClass can indicate the CPU architecture, though not always!
+ if ( navigator.cpuClass != null ) {
+ var cpuClass = navigator.cpuClass.toLowerCase();
+ if ( cpuClass.indexOf ( "x64" ) != -1 || cpuClass.indexOf ( "x86_64" ) != -1 ) {
+ arch = "x86_64";
+ }
+ }
+
+ // 32 bit IE running in compatibility mode in 64 bit windows may return arch as x86.
+ // following code verifies this by looking at text WOW64/Win64 in userAgent
+ if ( navigator.userAgent != null ) {
+ var userAgent = navigator.userAgent.toLowerCase();
+ if( userAgent.indexOf ( "wow64" ) != -1 ) {
+ // browser running in compatibility mode (32 bit) inside a 64 bit Windows OS
+ // In such cases, we should re-direct to the 32 bit URL as the java webstart
+ // plug-in in the browser will also be 32 bit.
+ arch = "x86";
+ } else if ( userAgent.indexOf ( "win64" ) != -1 || userAgent.indexOf ( "x64" ) != -1 ) {
+ arch = "x86_64";
+ }
+ }
+
+ // hide the "loading" message
+ var element = document.getElementById('loading');
+ element.style.display = "none";
+
+ if ( os == "unknown" ) {
+ var element = document.getElementById('unknown_os');
+ element.style.display = "block";
+
+ // show the links for various os-arch combinations
+ element = document.getElementById('all_links');
+ element.style.display = "block";
+ }
+
+ if ( os != "unknown" && arch == "unknown" ) {
+ var element = document.getElementById('unknown_arch');
+ element.style.display = "block";
+ }
+
+ if ( os == "macosx" && arch == "unknown" ) {
+ var element = document.getElementById('macosx');
+ element.style.display = "block";
+ }
+
+ if ( os == "win32" && arch == "unknown" ) {
+ var element = document.getElementById('win32');
+ element.style.display = "block";
+ }
+
+ if ( os == "linux" && arch == "unknown" ) {
+ var element = document.getElementById('linux');
+ element.style.display = "block";
+ }
+
+ if ( os != "unknown" && ws != "unknown" && arch != "unknown" ) {
+ // os-ws-arch detected. redirect to appropriate jnlp
+ var element = document.getElementById('all_ok');
+ element.style.display = "block";
+
+ // show the links for various os-arch combinations
+ element = document.getElementById('all_links');
+ element.style.display = "block";
+
+ url = os + "." + ws + "." + arch + "/gluster-management-console.jnlp";
+ document.location.href = url;
+ }
+ }
+ </script>
+</head>
+
+<body onload="startGMC()">
+ <h3>Gluster Management Console</h3>
+ <DIV ID="loading" style="display: block">
+ Identifying your Operating System and CPU architecture...
+ </DIV>
+ <DIV ID="all_ok" style="display: none">
+ Gluster Management Console will download and start automatically. If it doesn't, click on an appropriate link below to manually start the same: <br><br>
+ </DIV>
+ <DIV ID="unknown_os" style="display: none">
+ Could not identify your Operating System. Please click on the appropriate link below to invoke Gluster Management Console!
+ </DIV>
+ <DIV ID="unknown_arch" style="display: none">
+ Could not identify your CPU architecture. Please click on the appropriate link below to invoke Gluster Management Console!
+ </DIV><br>
+ <DIV ID="win32" style="display: none">
+ <table style="width: 479px; ">
+ <tr><td style="width: 100px;">Windows</td><td style="width: 60px;"><a href="win32.win32.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="win32.win32.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ </table>
+ </DIV>
+
+ <DIV ID="linux" style="display: none">
+ <table style="width: 479px; ">
+ <tr><td style="width: 100px;">Linux</td><td style="width: 60px;"><a href="linux.gtk.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="linux.gtk.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ </table>
+ </DIV>
+
+ <DIV ID="macosx" style="display: none">
+ <table style="width: 479px; ">
+ <tr><td style="width: 100px;">Mac OS X</td><td style="width: 60px;"><a href="macosx.cocoa.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="macosx.cocoa.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ </table>
+ </DIV>
+
+ <DIV ID="all_links" style="display: none">
+ <table style="width: 479px; ">
+ <tr><td style="width: 100px;">Linux</td><td style="width: 60px;"><a href="linux.gtk.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="linux.gtk.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ <tr><td style="width: 100px;">Mac OS X</td><td style="width: 60px;"><a href="macosx.cocoa.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="macosx.cocoa.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ <tr><td style="width: 100px;">Windows</td><td style="width: 60px;"><a href="win32.win32.x86/gluster-management-console.jnlp">32 bit</a></td><td style="width: 60px;"><a href="win32.win32.x86_64/gluster-management-console.jnlp">64 bit</a></td></tr>
+ </table>
+ </DIV>
+
+</body>
+
+</html>
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/Globals.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/Globals.py
new file mode 120000
index 00000000..7d230498
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/Globals.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/common/Globals.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/Protocol.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/Protocol.py
new file mode 120000
index 00000000..7ecad84d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/Protocol.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/common/Protocol.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/Utils.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/Utils.py
new file mode 120000
index 00000000..df26ff44
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/Utils.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/common/Utils.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py
new file mode 120000
index 00000000..880349a1
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/common/XmlHandler.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py
new file mode 120000
index 00000000..fec57917
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/add_user_cifs_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/create_volume_cifs_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/create_volume_cifs_all.py
new file mode 120000
index 00000000..03752d57
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/create_volume_cifs_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/create_volume_cifs_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py
new file mode 120000
index 00000000..d517e46c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/delete_user_cifs_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_volume_cifs_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_volume_cifs_all.py
new file mode 120000
index 00000000..be9e627c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/delete_volume_cifs_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/delete_volume_cifs_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/get_volume_user_cifs.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/get_volume_user_cifs.py
new file mode 120000
index 00000000..3eff03fd
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/get_volume_user_cifs.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/get_volume_user_cifs.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/gmg-reset-password.sh b/src/org.gluster.storage.management.gateway/WebContent/scripts/gmg-reset-password.sh
new file mode 120000
index 00000000..13b9a40b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/gmg-reset-password.sh
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/gmg-reset-password.sh \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/grun.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/grun.py
new file mode 120000
index 00000000..5e56bfbb
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/grun.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/grun.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py
new file mode 120000
index 00000000..6288f182
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/multicast-discover-servers.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/remove_server_volume_cifs_config.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/remove_server_volume_cifs_config.py
new file mode 120000
index 00000000..32d1dec4
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/remove_server_volume_cifs_config.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/remove_server_volume_cifs_config.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/setup_cifs_config_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/setup_cifs_config_all.py
new file mode 120000
index 00000000..e3f44800
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/setup_cifs_config_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/setup_cifs_config_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/scripts/update_volume_cifs_all.py b/src/org.gluster.storage.management.gateway/WebContent/scripts/update_volume_cifs_all.py
new file mode 120000
index 00000000..8496fae4
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/scripts/update_volume_cifs_all.py
@@ -0,0 +1 @@
+../../../com.gluster.storage.management.gateway.scripts/src/gateway/update_volume_cifs_all.py \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore b/src/org.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore
new file mode 100644
index 00000000..2efe19b0
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore
Binary files differ
diff --git a/src/org.gluster.storage.management.gateway/buckminster.cspex b/src/org.gluster.storage.management.gateway/buckminster.cspex
new file mode 100644
index 00000000..31eb9d67
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/buckminster.cspex
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<cspecExtension
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:bc="http://www.eclipse.org/buckminster/Common-1.0"
+ xmlns="http://www.eclipse.org/buckminster/CSpec-1.0">
+ <dependencies>
+ <!-- Place your Dependencies here -->
+ </dependencies>
+ <generators>
+ <!-- Place your Generators here -->
+ </generators>
+ <artifacts>
+ <!-- Place your Artifacts here -->
+ </artifacts>
+ <actions>
+ <public name="archive" actor="ant">
+ <actorProperties>
+ <property key="buildFile" value="build/glusterserver.ant"/>
+ </actorProperties>
+ </public>
+ </actions>
+ <groups>
+ <!-- Place your Groups here -->
+ </groups>
+ <alterDependencies>
+ <!-- Place your Dependency alterations here -->
+ </alterDependencies>
+ <alterArtifacts>
+ <!-- Place your Artifact alterations here -->
+ </alterArtifacts>
+ <alterActions>
+ <!-- Place your Action alterations here -->
+ </alterActions>
+ <alterGroups>
+ <!-- Place your Group alterations here -->
+ </alterGroups>
+</cspecExtension>
diff --git a/src/org.gluster.storage.management.gateway/build/glusterserver.ant b/src/org.gluster.storage.management.gateway/build/glusterserver.ant
new file mode 100644
index 00000000..9ba36f55
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/build/glusterserver.ant
@@ -0,0 +1,70 @@
+<project name="org.gluster.storage.management.gateway" basedir="." default="archive">
+ <echo message="basedir=${basedir}" />
+ <echo message="buckminster.output=${buckminster.output}" />
+ <property name="WEB-INF" value="${basedir}/WebContent/WEB-INF" />
+ <property name="OUT" value="${buckminster.output}/glusterserver/" />
+ <property name="WAR_FILE_NAME" value="glustermg.war" />
+ <property name="TEMP" value="${buckminster.output}/temp" />
+
+ <target name="help">
+ <echo>
+ --------------------------------------------------
+ compile - Compile
+ archive - Generate WAR file
+ --------------------------------------------------
+ </echo>
+ </target>
+
+ <target name="init">
+ <delete dir="${WEB-INF}/classes" />
+ <mkdir dir="${WEB-INF}/classes" />
+ <mkdir dir="${WEB-INF}/classes/spring" />
+ <mkdir dir="${WEB-INF}/classes/META-INF" />
+ </target>
+
+ <target name="compile" depends="init">
+ <!-- flatten=true means ignore directory structure and copy files directly to destination -->
+ <copy todir="${WEB-INF}/lib" flatten="true">
+ <fileset dir="${buckminster.output}/.." casesensitive="yes">
+ <include name="**/*.jar" />
+ </fileset>
+ </copy>
+ <copy todir="${WEB-INF}/classes/spring">
+ <fileset dir="${basedir}/src/spring" casesensitive="yes">
+ <include name="**/*.xml" />
+ </fileset>
+ </copy>
+ <copy todir="${WEB-INF}/classes/META-INF">
+ <fileset dir="${basedir}/src/META-INF" casesensitive="yes">
+ <include name="**/*.xml" />
+ </fileset>
+ </copy>
+ <copy todir="${WEB-INF}/classes">
+ <fileset dir="${basedir}/src" casesensitive="yes">
+ <include name="log4j.properties" />
+ </fileset>
+ </copy>
+ <!-- TODO: make debug option configurable in jenkins -->
+ <javac srcdir="${basedir}/src" destdir="${WEB-INF}/classes" classpathref="libs" debug="true" debuglevel="lines,vars,source"/>
+ </target>
+
+ <target name="archive" depends="compile">
+ <delete dir="${OUT}" />
+ <mkdir dir="${OUT}" />
+ <delete dir="${TEMP}" />
+ <mkdir dir="${TEMP}" />
+ <copy todir="${TEMP}">
+ <fileset dir="${basedir}/WebContent">
+ <!-- servlet-api.jar is required during compilation. At runtime, it is picked from tomcat lib directory -->
+ <exclude name="**/servlet-api.jar" />
+ </fileset>
+ </copy>
+ <war destfile="${OUT}/${WAR_FILE_NAME}" basedir="${TEMP}" compress="true" webxml="${TEMP}/WEB-INF/web.xml" />
+ <delete dir="${TEMP}" />
+ </target>
+
+ <path id="libs">
+ <fileset includes="*.jar" dir="${WEB-INF}/lib" />
+ </path>
+
+</project>
diff --git a/src/org.gluster.storage.management.gateway/src/META-INF/persistence.xml b/src/org.gluster.storage.management.gateway/src/META-INF/persistence.xml
new file mode 100644
index 00000000..36b252ea
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/META-INF/persistence.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+ <persistence-unit name="gluster-management-gateway" transaction-type="RESOURCE_LOCAL" />
+</persistence> \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/log4j.properties b/src/org.gluster.storage.management.gateway/src/log4j.properties
new file mode 100644
index 00000000..3ffa6b9e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/log4j.properties
@@ -0,0 +1,20 @@
+log4j.rootLogger=INFO, R
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.immediateFlush=true
+log4j.appender.CONSOLE.target=System.out
+log4j.appender.CONSOLE.threshold=DEBUG
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd MMM, yyyy HH:mm:ss} %p: %c %t - %m%n
+
+log4j.appender.R=org.apache.log4j.RollingFileAppender
+log4j.appender.R.File=/var/log/glustermg/glustermg.log
+log4j.appender.R.MaxFileSize=10MB
+log4j.appender.R.MaxBackupIndex=10
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%d{dd MMM, yyyy HH:mm:ss} %p: %c %t - %m%n
+#log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
+
+log4j.logger.org=ERROR
+log4j.logger.com=ERROR
+log4j.logger.org.gluster=DEBUG \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ClusterInfo.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ClusterInfo.java
new file mode 100644
index 00000000..ba197b92
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ClusterInfo.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+import org.hibernate.cfg.AnnotationConfiguration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+@Entity(name="cluster_info")
+public class ClusterInfo {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ private String name;
+
+ @OneToMany(mappedBy="cluster")
+ private List<ServerInfo> servers = new ArrayList<ServerInfo>();
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setServers(List<ServerInfo> servers) {
+ this.servers = servers;
+ }
+
+ public List<ServerInfo> getServers() {
+ return servers;
+ }
+
+ public void addServer(ServerInfo server) {
+ servers.add(server);
+ }
+
+ public static void main(String args[]) {
+ AnnotationConfiguration config = new AnnotationConfiguration();
+ config.addAnnotatedClass(ClusterInfo.class);
+ config.addAnnotatedClass(ServerInfo.class);
+ config.configure();
+ new SchemaExport(config).create(true, true);
+ }
+
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/GlusterDataSource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/GlusterDataSource.java
new file mode 100644
index 00000000..f0b0311e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/GlusterDataSource.java
@@ -0,0 +1,48 @@
+/**
+ * GlusterDataSource.java
+ *
+ * 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 org.gluster.storage.management.gateway.data;
+
+import javax.servlet.ServletContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.stereotype.Component;
+
+@Component
+public class GlusterDataSource extends DriverManagerDataSource {
+ @Autowired
+ ServletContext servletContext;
+
+ public GlusterDataSource() {
+ setDriverClassName(org.apache.derby.jdbc.EmbeddedDriver.class.getName());
+
+ setUsername("gluster");
+ // TODO: change to a stronger (encrypted) password
+ setPassword("gluster");
+ }
+
+ public DriverManagerDataSource getDataSource() {
+ // Database directory = work/data relative to context root
+ setUrl("jdbc:derby:" + servletContext.getRealPath("data") + ";create=true");
+
+ return this;
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/PersistenceDao.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/PersistenceDao.java
new file mode 100644
index 00000000..49348084
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/PersistenceDao.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.data;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.PersistenceUnit;
+import javax.persistence.Query;
+
+/**
+ *
+ */
+public class PersistenceDao<T> {
+ private Class<T> type;
+
+ private EntityManager entityManager;
+
+ @PersistenceUnit
+ private EntityManagerFactory entityManagerFactory;
+
+ public PersistenceDao(Class<T> type) {
+ this.type = type;
+ }
+
+ public EntityTransaction startTransaction() {
+ EntityTransaction txn = getEntityManager().getTransaction();
+ txn.begin();
+ return txn;
+ }
+
+ private synchronized EntityManager getEntityManager() {
+ if (entityManager == null) {
+ entityManager = entityManagerFactory.createEntityManager();
+ }
+ return entityManager;
+ }
+
+ public Object getSingleResult(String query) {
+ return getEntityManager().createQuery(query).getSingleResult();
+ }
+
+ public Object getSingleResult(String queryString, String... params) {
+ return createQuery(queryString, params).getSingleResult();
+ }
+
+ private Query createQuery(String queryString, String... params) {
+ Query query = getEntityManager().createQuery(queryString);
+ for (int i = 0; i < params.length; i++) {
+ query.setParameter(i + 1, params[i]);
+ }
+ return query;
+ }
+
+ public Object getSingleResultFromSQL(String sqlQuery) {
+ return getEntityManager().createNativeQuery(sqlQuery).getSingleResult();
+ }
+
+ @SuppressWarnings("rawtypes")
+ public List findBySQL(String sqlQuery) {
+ return getEntityManager().createNativeQuery(sqlQuery).getResultList();
+ }
+
+ public T findById(int id) {
+ return getEntityManager().find(type, id);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<T> findAll() {
+ return getEntityManager().createQuery("select t from " + type.getName() + " t").getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<T> findBy(String whereClause) {
+ return getEntityManager().createQuery("select t from " + type.getName() + " t where " + whereClause)
+ .getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<T> findBy(String whereClause, String... params) {
+ return createQuery("select t from " + type.getName() + " t where " + whereClause, params).getResultList();
+ }
+
+ public void save(Object obj) {
+ getEntityManager().persist(obj);
+ }
+
+ public T update(T obj) {
+ return getEntityManager().merge(obj);
+ }
+
+ public void delete(Object obj) {
+ getEntityManager().remove(obj);
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ServerInfo.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ServerInfo.java
new file mode 100644
index 00000000..84df2f1a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/data/ServerInfo.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.data;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+/**
+ *
+ */
+@Entity(name="server_info")
+public class ServerInfo {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ private String name;
+
+ @ManyToOne
+ @JoinColumn(name="cluster_id")
+ private ClusterInfo cluster;
+
+ public ServerInfo() {
+ }
+
+ public ServerInfo(String name) {
+ setName(name);
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setCluster(ClusterInfo cluster) {
+ this.cluster = cluster;
+ }
+
+ public ClusterInfo getCluster() {
+ return cluster;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuditFilter.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuditFilter.java
new file mode 100644
index 00000000..76b329ee
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuditFilter.java
@@ -0,0 +1,48 @@
+/**
+ *
+ */
+package org.gluster.storage.management.gateway.filters;
+
+import java.security.Principal;
+
+import org.apache.log4j.Logger;
+
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerRequestFilter;
+import com.sun.jersey.spi.container.ContainerResponse;
+import com.sun.jersey.spi.container.ContainerResponseFilter;
+import com.sun.jersey.spi.container.ResourceFilter;
+
+/**
+ * Resource filter for maintaining audit trail of resource access
+ */
+public class AuditFilter implements ResourceFilter, ContainerRequestFilter, ContainerResponseFilter {
+ private static final Logger logger = Logger.getLogger(AuditFilter.class);
+
+ @Override
+ public ContainerRequestFilter getRequestFilter() {
+ return this;
+ }
+
+ @Override
+ public ContainerResponseFilter getResponseFilter() {
+ return this;
+ }
+
+ @Override
+ public ContainerRequest filter(ContainerRequest req) {
+ Principal principal = req.getUserPrincipal();
+ if(principal != null) {
+ logger.info("REQUEST from [" + principal.getName() + "] : [" + req.getMethod() + "][" + req.getPath() + "]");
+ } else {
+ logger.info("REQUEST [" + req.getMethod() + "][" + req.getPath() + "]");
+ }
+ return req;
+ }
+
+ @Override
+ public ContainerResponse filter(ContainerRequest req, ContainerResponse response) {
+ logger.info("RESPONSE: [" + req.getMethod() + "][" + req.getPath() + "]");
+ return response;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java
new file mode 100644
index 00000000..4bb7f37c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/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 org.gluster.storage.management.gateway.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/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java
new file mode 100644
index 00000000..8772cdcd
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+package org.gluster.storage.management.gateway.filters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.sun.jersey.api.model.AbstractMethod;
+import com.sun.jersey.spi.container.ResourceFilter;
+import com.sun.jersey.spi.container.ResourceFilterFactory;
+
+/**
+ * Gluster resource filter factory. As of now, this creates only one filter - the audit filter {@code AuditFilter}
+ */
+public class GlusterResourceFilterFactory implements ResourceFilterFactory {
+
+ public GlusterResourceFilterFactory() {
+ }
+
+ /* (non-Javadoc)
+ * @see com.sun.jersey.spi.container.ResourceFilterFactory#create(com.sun.jersey.api.model.AbstractMethod)
+ */
+ @Override
+ public List<ResourceFilter> create(AbstractMethod arg0) {
+ List<ResourceFilter> filters = new ArrayList<ResourceFilter>();
+ filters.add(new AuditFilter());
+
+ return filters;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/listeners/ShutdownListener.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/listeners/ShutdownListener.java
new file mode 100644
index 00000000..8c6bb42b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/listeners/ShutdownListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.listeners;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.gluster.storage.management.gateway.utils.DBUtil;
+
+
+/**
+ * Shuts down the Derby database when gateway is being stopped.
+ */
+public class ShutdownListener implements ServletContextListener {
+
+ /* (non-Javadoc)
+ * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
+ */
+ @Override
+ public void contextDestroyed(ServletContextEvent arg0) {
+ // Embedded derby must be shut down when the gateway stops.
+ DBUtil.shutdownDerby();
+ System.gc();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
+ */
+ @Override
+ public void contextInitialized(ServletContextEvent arg0) {
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java
new file mode 100644
index 00000000..8e26c838
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.StreamingOutput;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ *
+ */
+public class AbstractResource {
+ @Context
+ protected UriInfo uriInfo;
+
+ /**
+ * Creates a response with HTTP status code of 201 (created) and sets the "location" header to the URI created using
+ * the given path relative to current path.
+ *
+ * @param relativePath
+ * relative path of the created resource - will be set in the "location" header of response.
+ * @return the {@link Response} object
+ */
+ protected Response createdResponse(String relativePath) {
+ return Response.created(createRelatriveURI(relativePath)).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 204 (no content)
+ * @return the {@link Response} object
+ */
+ protected Response noContentResponse() {
+ return Response.noContent().build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 202 (accepted), also setting the location header to given location.
+ * This is typically done while triggering long running tasks
+ *
+ * @param locationURI
+ * URI to be appended to the base URI
+ * @return the {@link Response} object
+ */
+ protected Response acceptedResponse(String locationURI) {
+ return Response.status(Status.ACCEPTED).location(createAbsoluteURI(locationURI)).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 404 (not found), also setting the given message in the response body
+ *
+ * @param message
+ * Message to be set in the response body
+ * @return the {@link Response} object
+ */
+ protected Response notFoundResponse(String message) {
+ return Response.status(Status.NOT_FOUND).type(MediaType.TEXT_HTML).entity(message).build();
+ }
+
+ /**
+ * Creates a new URI that is relative to the <b>base URI</b> of the application
+ * @param uriString URI String to be appended to the base URI
+ * @return newly created URI
+ */
+ private URI createAbsoluteURI(String uriString) {
+ return uriInfo.getBaseUriBuilder().path(uriString).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 204 (no content), also setting the location header to given location
+ * @param location path of the location to be set relative to current path
+ * @return the {@link Response} object
+ */
+ protected Response noContentResponse(String location) {
+ return Response.noContent().location(createRelatriveURI(location)).build();
+ }
+
+ /**
+ * Creates a URI relative to current URI
+ * @param location path relative to current URI
+ * @return newly created URI
+ */
+ protected URI createRelatriveURI(String location) {
+ return uriInfo.getAbsolutePathBuilder().path(location).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 500 (internal server error) and sets the error message in the
+ * response body
+ *
+ * @param errMessage
+ * Error message to be set in the response body
+ * @return the {@link Response} object
+ */
+ protected Response errorResponse(String errMessage) {
+ return Response.serverError().type(MediaType.TEXT_HTML).entity(errMessage).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 400 (bad request) and sets the error message in the
+ * response body
+ *
+ * @param errMessage
+ * Error message to be set in the response body
+ * @return the {@link Response} object
+ */
+ protected Response badRequestResponse(String errMessage) {
+ return Response.status(Status.BAD_REQUEST).type(MediaType.TEXT_HTML).entity(errMessage).build();
+ }
+
+ /**
+ * Creates a response with HTTP status code of 401 (unauthorized)
+ *
+ * @return the {@link Response} object
+ */
+ protected Response unauthorizedResponse() {
+ return Response.status(Status.UNAUTHORIZED).build();
+ }
+
+ /**
+ * Creates an OK response and sets the entity in the response body.
+ *
+ * @param entity
+ * Entity to be set in the response body
+ * @param mediaType
+ * Media type to be set on the response
+ * @return the {@link Response} object
+ */
+ protected Response okResponse(Object entity, String mediaType) {
+ return Response.ok(entity).type(mediaType).build();
+ }
+
+ /**
+ * Creates a streaming output response and sets the given streaming output in the response. Typically used for
+ * "download" requests
+ *
+ * @param entity
+ * Entity to be set in the response body
+ * @param mediaType
+ * Media type to be set on the response
+ * @return the {@link Response} object
+ */
+ protected Response streamingOutputResponse(StreamingOutput output) {
+ return Response.ok(output).type(MediaType.APPLICATION_OCTET_STREAM).build();
+ }
+
+ protected StreamingOutput createStreamingOutput(final byte[] data) {
+ return new StreamingOutput() {
+ @Override
+ public void write(OutputStream output) throws IOException {
+ output.write(data);
+ }
+ };
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java
new file mode 100644
index 00000000..3c9b3bd2
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CLUSTER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.response.ClusterNameListResponse;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.api.core.InjectParam;
+import com.sun.jersey.spi.resource.Singleton;
+
+/**
+ *
+ */
+@Component
+@Singleton
+@Path(RESOURCE_PATH_CLUSTERS)
+public class ClustersResource extends AbstractResource {
+ @InjectParam
+ private ClusterService clusterService;
+ private static final Logger logger = Logger.getLogger(ClustersResource.class);
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public ClusterNameListResponse getClusters() {
+ List<ClusterInfo> clusters = clusterService.getAllClusters();
+ List<String> clusterList = new ArrayList<String>();
+ for (ClusterInfo cluster : clusters) {
+ clusterList.add(cluster.getName());
+ }
+ return new ClusterNameListResponse(clusterList);
+ }
+
+ @POST
+ public Response createCluster(@FormParam(FORM_PARAM_CLUSTER_NAME) String clusterName) {
+ if(clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_CLUSTER_NAME + "] is missing in request!");
+ }
+
+ if(clusterService.getCluster(clusterName) != null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] already exists!");
+ }
+
+ clusterService.createCluster(clusterName);
+ return createdResponse(clusterName);
+ }
+
+ @PUT
+ public Response registerCluster(@FormParam(FORM_PARAM_CLUSTER_NAME) String clusterName,
+ @FormParam(FORM_PARAM_SERVER_NAME) String knownServer) {
+ if(clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_CLUSTER_NAME + "] is missing in request!");
+ }
+
+ if(knownServer == null || knownServer.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_SERVER_NAME + "] is missing in request!");
+ }
+
+ if(clusterService.getCluster(clusterName) != null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] already exists!");
+ }
+
+ ClusterInfo mappedCluster = clusterService.getClusterForServer(knownServer);
+ if(mappedCluster != null) {
+ throw new GlusterValidationException("Server [" + knownServer + "] is already present in cluster ["
+ + mappedCluster.getName() + "]!");
+ }
+
+ clusterService.registerCluster(clusterName, knownServer);
+ return noContentResponse(clusterName);
+ }
+
+ @Path("{" + PATH_PARAM_CLUSTER_NAME + "}")
+ @DELETE
+ public Response unregisterCluster(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ if(clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_CLUSTER_NAME + "] is missing in request!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if(cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] does not exist!");
+ }
+
+ clusterService.unregisterCluster(cluster);
+ return noContentResponse();
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java
new file mode 100644
index 00000000..12358f56
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_DISCOVERED_SERVERS;
+
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.response.ServerListResponse;
+import org.gluster.storage.management.core.response.ServerNameListResponse;
+import org.gluster.storage.management.gateway.services.DiscoveredServerService;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.api.core.InjectParam;
+import com.sun.jersey.spi.resource.Singleton;
+
+@Component
+@Singleton
+@Path(RESOURCE_PATH_DISCOVERED_SERVERS)
+public class DiscoveredServersResource extends AbstractResource {
+ @InjectParam
+ private DiscoveredServerService discoveredServerService;
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getDiscoveredServersXML(@QueryParam(QUERY_PARAM_DETAILS) Boolean details) {
+ return getDiscoveredServersResponse(details, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getDiscoveredServersJSON(@QueryParam(QUERY_PARAM_DETAILS) Boolean details) {
+ return getDiscoveredServersResponse(details, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getDiscoveredServersResponse(Boolean details, String mediaType) {
+ if(details != null && details == true) {
+ try {
+ List<Server> discoveredServers = discoveredServerService.getDiscoveredServerDetails();
+ return okResponse(new ServerListResponse(discoveredServers), mediaType);
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ } else {
+ return okResponse(new ServerNameListResponse(discoveredServerService.getDiscoveredServerNames()), mediaType);
+ }
+ }
+
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getDiscoveredServerXML(@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ return getDiscoveredServerResponse(serverName, MediaType.APPLICATION_XML);
+ }
+
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getDiscoveredServerJSON(@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ return getDiscoveredServerResponse(serverName, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getDiscoveredServerResponse(String serverName, String mediaType) {
+ if(serverName == null || serverName.isEmpty()) {
+ return badRequestResponse("Server name must not be empty!");
+ }
+ try {
+ return okResponse(discoveredServerService.getDiscoveredServer(serverName), mediaType);
+ } catch (Exception e) {
+ // TODO: Log the exception
+ return errorResponse(e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java
new file mode 100644
index 00000000..dfe4c85c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+
+
+@Provider
+public class GenericExceptionMapper implements ExceptionMapper<Exception> {
+ private static final Logger logger = Logger.getLogger(GenericExceptionMapper.class);
+
+ /* (non-Javadoc)
+ * @see javax.ws.rs.ext.ExceptionMapper#toResponse(java.lang.Throwable)
+ */
+ @Override
+ public Response toResponse(Exception exception) {
+ ResponseBuilder builder;
+ if (exception instanceof GlusterValidationException) {
+ builder = Response.status(Response.Status.BAD_REQUEST);
+ } else {
+ builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
+ }
+
+ String errMsg = exception.getMessage();
+ if(errMsg == null) {
+ errMsg = "Following exception occurred : " + exception.getClass().getName();
+ StackTraceElement[] stackTrace = exception.getStackTrace();
+ if(stackTrace.length > 0) {
+ errMsg += " at [" + stackTrace[0].getClassName() + "][" + stackTrace[0].getLineNumber() + "]";
+ }
+ }
+
+ logger.error(errMsg, exception);
+
+ return builder.entity(errMsg).type(MediaType.TEXT_PLAIN).build();
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java
new file mode 100644
index 00000000..1b9a3b71
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java
@@ -0,0 +1,343 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FSTYPE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MOUNTPOINT;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_INTERFACE;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_MAX_COUNT;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_NEXT_TO;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_PERIOD;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TYPE;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_FSTYPES;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_STATISTICS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_CPU;
+import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_MEMORY;
+import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_NETWORK;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.constants.RESTConstants;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.response.FsTypeListResponse;
+import org.gluster.storage.management.core.response.GlusterServerListResponse;
+import org.gluster.storage.management.core.response.ServerNameListResponse;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.GlusterServerService;
+import org.gluster.storage.management.gateway.tasks.InitializeDiskTask;
+import org.gluster.storage.management.gateway.utils.CpuStatsFactory;
+import org.gluster.storage.management.gateway.utils.MemoryStatsFactory;
+import org.gluster.storage.management.gateway.utils.NetworkStatsFactory;
+import org.gluster.storage.management.gateway.utils.StatsFactory;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.api.core.InjectParam;
+import com.sun.jersey.spi.resource.Singleton;
+
+@Component
+@Singleton
+@Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_SERVERS)
+public class GlusterServersResource extends AbstractResource {
+
+ public static final String HOSTNAMETAG = "hostname:";
+
+ @InjectParam
+ private TasksResource taskResource;
+
+ @InjectParam
+ private ClusterService clusterService;
+
+ @InjectParam
+ private CpuStatsFactory cpuStatsFactory;
+
+ @InjectParam
+ private MemoryStatsFactory memoryStatsFactory;
+
+ @InjectParam
+ private NetworkStatsFactory networkStatsFactory;
+
+ @InjectParam
+ private GlusterServerService glusterServerService;
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_DETAILS) Boolean details, @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
+ @QueryParam(QUERY_PARAM_NEXT_TO) String previousServerName) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_JSON, details, maxCount, previousServerName);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_DETAILS) Boolean details, @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
+ @QueryParam(QUERY_PARAM_NEXT_TO) String previousServerName) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_XML, details, maxCount, previousServerName);
+ }
+
+ private Response getGlusterServers(String clusterName, String mediaType, Boolean fetchDetails, Integer maxCount,
+ String previousServerName) {
+ if(fetchDetails == null) {
+ // by default, fetch the server list
+ fetchDetails = false;
+ }
+
+ List<GlusterServer> glusterServers = new ArrayList<GlusterServer>();
+
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ if (cluster.getServers().size() == 0) {
+ return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
+ }
+
+ try {
+ glusterServers = glusterServerService.getGlusterServers(clusterName, fetchDetails, maxCount, previousServerName);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ if(fetchDetails) {
+ return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
+ } else {
+ // no details to be fetched. Return list of server names.
+ return okResponse(new ServerNameListResponse(getServerNames(glusterServers)), mediaType);
+ }
+ }
+
+ private List<String> getServerNames(List<GlusterServer> glusterServers) {
+ List<String> serverNames = new ArrayList<String>();
+ for(GlusterServer server : glusterServers) {
+ serverNames.add(server.getName());
+ }
+ return serverNames;
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getGlusterServerXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getGlusterServerJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getGlusterServerResponse(String clusterName, String serverName, String mediaType) {
+ try {
+ return okResponse(glusterServerService.getGlusterServer(clusterName, serverName, true), mediaType);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ @POST
+ public Response addServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @FormParam(FORM_PARAM_SERVER_NAME) String serverName) {
+ return createdResponse(glusterServerService.addServerToCluster(clusterName, serverName));
+ }
+
+ @DELETE
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ public Response removeServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ glusterServerService.removeServerFromCluster(clusterName, serverName);
+ return noContentResponse();
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_FSTYPES)
+ public FsTypeListResponse getFsTypes(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ List<String> fsTypes = glusterServerService.getFsTypes(clusterName, serverName);
+ return new FsTypeListResponse(fsTypes);
+ }
+
+ @PUT
+ @Produces(MediaType.APPLICATION_XML)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_DISKS + "/{" + PATH_PARAM_DISK_NAME + "}")
+ public Response initializeDisk(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_SERVER_NAME) String serverName, @PathParam(PATH_PARAM_DISK_NAME) String diskName,
+ @FormParam(FORM_PARAM_FSTYPE) String fsType, @FormParam(FORM_PARAM_MOUNTPOINT) String mountPoint) {
+
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ return badRequestResponse("Server name must not be empty!");
+ }
+
+ if (diskName == null || diskName.isEmpty()) {
+ return badRequestResponse("Disk name must not be empty!");
+ }
+
+ if (fsType == null || fsType.isEmpty()) {
+ fsType = GlusterConstants.FSTYPE_DEFAULT;
+ // return badRequestResponse("Parameter [" + FORM_PARAM_FSTYPE + "] is missing in request!");
+ }
+
+ InitializeDiskTask initializeTask = new InitializeDiskTask(clusterService, clusterName, serverName, diskName, fsType, mountPoint);
+ try {
+ initializeTask.start();
+ // Check the initialize disk status
+ TaskStatus taskStatus = initializeTask.checkStatus();
+ initializeTask.getTaskInfo().setStatus(taskStatus);
+ taskResource.addTask(clusterName, initializeTask);
+
+ return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + "/"
+ + initializeTask.getId());
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ @Path(RESOURCE_STATISTICS)
+ public Response getAggregatedPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period) {
+ return getAggregaredPerformanceData(clusterName, type, period, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path(RESOURCE_STATISTICS)
+ public Response getAggregaredPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period) {
+ return getAggregaredPerformanceData(clusterName, type, period, MediaType.APPLICATION_JSON);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
+ public Response getPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName,
+ @QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period,
+ @QueryParam(QUERY_PARAM_INTERFACE) String networkInterface) {
+ return getPerformanceData(clusterName, serverName, type, period, networkInterface, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
+ public Response getPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName,
+ @QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period,
+ @QueryParam(QUERY_PARAM_INTERFACE) String networkInterface) {
+ return getPerformanceData(clusterName, serverName, type, period, networkInterface, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getAggregaredPerformanceData(String clusterName, String type, String period, String mediaType) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (type == null || type.isEmpty()) {
+ throw new GlusterValidationException("Statistics type name must not be empty!");
+ }
+
+ if (period == null || period.isEmpty()) {
+ throw new GlusterValidationException("Statistics period name must not be empty! Valid values are 1d/1w/1m/1y");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ if (cluster.getServers().isEmpty()) {
+ // cluster is empty. return empty stats.
+ return okResponse(new ServerStats(), mediaType);
+ }
+
+ List<String> serverNames = getServerNames(glusterServerService.getGlusterServers(clusterName, false, null, null));
+ return okResponse(getStatsFactory(type).fetchAggregatedStats(serverNames, period), mediaType);
+ }
+
+ private Response getPerformanceData(String clusterName, String serverName, String type, String period, String networkInterface, String mediaType) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ throw new GlusterValidationException("Server name must not be empty!");
+ }
+
+ if (type == null || type.isEmpty()) {
+ throw new GlusterValidationException("Statistics type name must not be empty!");
+ }
+
+ if (period == null || period.isEmpty()) {
+ throw new GlusterValidationException("Statistics period name must not be empty! Valid values are 1d/1w/1m/1y");
+ }
+
+ return okResponse(getStatsFactory(type).fetchStats(serverName, period, networkInterface), mediaType);
+ }
+
+ private StatsFactory getStatsFactory(String type) {
+ if(type.equals(STATISTICS_TYPE_CPU)) {
+ return cpuStatsFactory;
+ } else if(type.equals(STATISTICS_TYPE_MEMORY)) {
+ return memoryStatsFactory;
+ } else if(type.equals(STATISTICS_TYPE_NETWORK)) {
+ return networkStatsFactory;
+ } else {
+ throw new GlusterValidationException("Invalid server statistics type [" + type + "]. Valid values are ["
+ + STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]");
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/KeysResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/KeysResource.java
new file mode 100644
index 00000000..3063c23e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/KeysResource.java
@@ -0,0 +1,155 @@
+/**
+ * KeysResource.java
+ *
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_KEYS;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.utils.FileUtil;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.gluster.storage.management.gateway.utils.SshUtil;
+
+import com.sun.jersey.multipart.FormDataParam;
+
+@Path(RESOURCE_PATH_KEYS)
+public class KeysResource extends AbstractResource {
+ private static final Logger logger = Logger.getLogger(KeysResource.class);
+ private ProcessUtil processUtil = new ProcessUtil();
+
+ @GET
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ public Response exportSshkeys() {
+ File archiveFile = new File(createSskKeyZipFile());
+ byte[] data = FileUtil.readFileAsByteArray(archiveFile);
+ archiveFile.delete();
+ return streamingOutputResponse(createStreamingOutput(data));
+ }
+
+ private String createSskKeyZipFile() {
+ String targetDir = FileUtil.getTempDirName();
+ String zipFile = targetDir + File.separator + "ssh-keys.tar";
+ String sourcePrivateKeyFile = SshUtil.PRIVATE_KEY_FILE.getAbsolutePath();
+ String sourcePublicKeyFile = SshUtil.PUBLIC_KEY_FILE.getAbsolutePath();
+ String targetPrivateKeyFile = targetDir + File.separator + SshUtil.PRIVATE_KEY_FILE.getName();
+ String targetPubKeyFile = targetDir + File.separator + SshUtil.PUBLIC_KEY_FILE.getName();
+
+ if (!SshUtil.PRIVATE_KEY_FILE.isFile()) {
+ throw new GlusterRuntimeException("No private key file [" + SshUtil.PRIVATE_KEY_FILE.getName() + "] found!");
+ }
+
+ if (!SshUtil.PUBLIC_KEY_FILE.isFile()) {
+ throw new GlusterRuntimeException("No public key file [" + SshUtil.PUBLIC_KEY_FILE.getName() + "] found!");
+ }
+
+ // Copy keys to temp folder
+ ProcessResult result = processUtil.executeCommand("cp", sourcePrivateKeyFile, targetPrivateKeyFile);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Failed to copy key files! [" + result.getOutput() + "]");
+ }
+ result = processUtil.executeCommand("cp", sourcePublicKeyFile, targetPubKeyFile);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Failed to copy key files! [" + result.getOutput() + "]");
+ }
+
+ // To compress the key files
+ result = processUtil.executeCommand("tar", "cvf", zipFile, "-C", targetDir, SshUtil.PRIVATE_KEY_FILE.getName(),
+ SshUtil.PUBLIC_KEY_FILE.getName());
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Failed to compress key files! [" + result.getOutput() + "]");
+ }
+
+ // To remove the copied key files
+ try {
+ processUtil.executeCommand("rm", "-f", targetPrivateKeyFile, targetPubKeyFile); // Ignore the errors if any
+ } catch (Exception e) {
+ logger.warn(e.toString());
+ }
+ return zipFile;
+ }
+
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response importSshKeys(@FormDataParam("file") InputStream uploadedInputStream) {
+ File uploadedFile = new File(System.getProperty("java.io.tmpdir") + File.separator + "keys.tar");
+ String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+
+ writeToFile(uploadedInputStream, uploadedFile.getAbsolutePath());
+
+ // To backup existing SSH private and public keys, if exist.
+ if (SshUtil.PRIVATE_KEY_FILE.isFile()) {
+ if (!SshUtil.PRIVATE_KEY_FILE.renameTo(new File(SshUtil.PRIVATE_KEY_FILE.getAbsolutePath() + "-" + timestamp))) {
+ throw new GlusterRuntimeException("Unable to backup private key!");
+ }
+ }
+
+ if (SshUtil.PUBLIC_KEY_FILE.isFile()) {
+ if (!SshUtil.PUBLIC_KEY_FILE
+ .renameTo(new File(SshUtil.PUBLIC_KEY_FILE.getAbsolutePath() + "-" + timestamp))) {
+ throw new GlusterRuntimeException("Unable to backup public key!");
+ }
+ }
+ // Extract SSH private and public key files.
+ ProcessResult output = processUtil.executeCommand("tar", "xvf", uploadedFile.getAbsolutePath(), "-C",
+ SshUtil.SSH_AUTHORIZED_KEYS_DIR_LOCAL);
+ uploadedFile.delete();
+ if (!output.isSuccess()) {
+ String errMsg = "Error in importing SSH keys: [" + output.toString() + "]";
+ logger.error(errMsg);
+ throw new GlusterRuntimeException(errMsg);
+ }
+ return createdResponse("SSH Key imported successfully");
+ }
+
+ // save uploaded file to the file (with path)
+ private void writeToFile(InputStream inputStream, String toFile) {
+ try {
+ int read = 0;
+ byte[] bytes = new byte[1024];
+
+ OutputStream out = new FileOutputStream(new File(toFile));
+ while ((read = inputStream.read(bytes)) != -1) {
+ out.write(bytes, 0, read);
+ }
+ out.flush();
+ out.close();
+ } catch (IOException e) {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/TasksResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/TasksResource.java
new file mode 100644
index 00000000..b57232fe
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/TasksResource.java
@@ -0,0 +1,226 @@
+/**
+ * TaskResource.java
+ *
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_TASK_ID;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.gluster.storage.management.core.constants.RESTConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.response.TaskInfoListResponse;
+import org.gluster.storage.management.gateway.tasks.Task;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.spi.resource.Singleton;
+
+@Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_TASKS)
+@Singleton
+@Component
+
+public class TasksResource extends AbstractResource {
+ private Map<String, Map<String, Task>> tasksMap = new HashMap<String, Map<String, Task>>();
+
+ public TasksResource() {
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void addTask(String clusterName, Task task) {
+ Map clusterTaskMap = tasksMap.get(clusterName);
+ if(clusterTaskMap == null) {
+ clusterTaskMap = new HashMap<String, Task>();
+ tasksMap.put(clusterName, clusterTaskMap);
+ }
+ // Remove the task if already exist
+ if (clusterTaskMap.containsKey(task.getId())) {
+ removeTask(clusterName, task);
+ }
+ clusterTaskMap.put(task.getId(), task);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public void removeTask(String clusterName, Task task) {
+ Map clusterTaskMap = tasksMap.get(clusterName);
+ if (clusterTaskMap != null) {
+ clusterTaskMap.remove(task.getId());
+ }
+ }
+
+ public List<TaskInfo> getAllTasksInfo(String clusterName) {
+ Map<String, Task> clusterTasksMap = tasksMap.get(clusterName);
+ List<TaskInfo> allTasksInfo = new ArrayList<TaskInfo>();
+ if ( clusterTasksMap == null) {
+ return allTasksInfo;
+ }
+ for (Map.Entry<String, Task> entry : clusterTasksMap.entrySet()) {
+ checkTaskStatus(clusterName, entry.getKey());
+ allTasksInfo.add(entry.getValue().getTaskInfo()); // TaskInfo with latest status
+ }
+ return allTasksInfo;
+ }
+
+ public Task getTask(String clusterName, String taskId) {
+ Map<String, Task> clusterTasksMap = tasksMap.get(clusterName);
+ for (Map.Entry<String, Task> entry : clusterTasksMap.entrySet()) {
+ if (entry.getValue().getId().equals(taskId)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ public List<Task> getAllTasks(String clusterName) {
+ Map<String, Task> clusterTasksMap = tasksMap.get(clusterName);
+ List<Task> tasks = new ArrayList<Task>();
+ for (Map.Entry<String, Task> entry : clusterTasksMap.entrySet()) {
+ checkTaskStatus(clusterName, entry.getKey());
+ tasks.add( (Task) entry.getValue());
+ }
+ return tasks;
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getTasks(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ try {
+ return okResponse(new TaskInfoListResponse(getAllTasksInfo(clusterName)), MediaType.APPLICATION_XML);
+ } catch (GlusterRuntimeException e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ @GET
+ @Path("/{" + PATH_PARAM_TASK_ID + "}")
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getTaskStatus(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_TASK_ID) String taskId) {
+ try {
+ Task task = checkTaskStatus(clusterName, taskId);
+ return okResponse(task.getTaskInfo(), MediaType.APPLICATION_XML);
+ } catch (GlusterRuntimeException e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ private Task checkTaskStatus(String clusterName, String taskId) {
+ Task task = getTask(clusterName, taskId);
+ // No status check required if the task already complete or failure
+ if (task.getTaskInfo().getStatus().getCode() == Status.STATUS_CODE_FAILURE
+ || task.getTaskInfo().getStatus().getCode() == Status.STATUS_CODE_SUCCESS) {
+ return task;
+ }
+ task.getTaskInfo().setStatus(task.checkStatus());
+ return task;
+ }
+
+ @PUT
+ @Path("/{" + PATH_PARAM_TASK_ID + "}")
+ @Produces(MediaType.APPLICATION_XML)
+ public Response performTask(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_TASK_ID) String taskId, @FormParam(FORM_PARAM_OPERATION) String taskOperation) {
+ Task task = getTask(clusterName, taskId);
+
+ try {
+ if (taskOperation.equals(RESTConstants.TASK_RESUME)) {
+ task.resume();
+ } else if (taskOperation.equals(RESTConstants.TASK_PAUSE)) {
+ task.pause();
+ } else if (taskOperation.equals(RESTConstants.TASK_STOP)) {
+ // task.stop();
+ clearTask(clusterName, taskId, taskOperation); // Stop and remove from the task list
+ } else if (taskOperation.equals(RESTConstants.TASK_COMMIT)) {
+ task.commit();
+ }
+ return (Response) noContentResponse();
+ } catch(GlusterValidationException ve) {
+ return badRequestResponse(ve.getMessage());
+ } catch (GlusterRuntimeException e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ @DELETE
+ @Path("/{" + PATH_PARAM_TASK_ID + "}")
+ @Produces(MediaType.APPLICATION_XML)
+ public Response clearTask(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_TASK_ID) String taskId, @QueryParam(FORM_PARAM_OPERATION) String taskOperation) {
+ Task task = getTask(clusterName, taskId);
+ if (task == null) {
+ return notFoundResponse("Requested task not found!");
+ }
+
+ if(clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Parameter [" + PATH_PARAM_CLUSTER_NAME + "] is missing in request!");
+ }
+
+ if(taskOperation == null || taskOperation.isEmpty()) {
+ int taskStatus = task.getTaskInfo().getStatus().getCode();
+ if (taskStatus == Status.STATUS_CODE_SUCCESS || taskStatus == Status.STATUS_CODE_FAILURE) {
+ taskOperation = RESTConstants.TASK_DELETE;
+ } else {
+ taskOperation = RESTConstants.TASK_STOP;
+ }
+// return badRequestResponse("Parameter [" + FORM_PARAM_OPERATION + "] is missing in request!");
+ }
+
+ if(!taskOperation.equals(RESTConstants.TASK_STOP) && !taskOperation.equals(RESTConstants.TASK_DELETE)) {
+ return badRequestResponse("Invalid value [" + taskOperation + "] for parameter [" + FORM_PARAM_OPERATION
+ + "]");
+ }
+
+ try {
+ if (taskOperation.equals(RESTConstants.TASK_STOP)) {
+ task.stop();
+ // On successful, intentionally stopped task can be removed from task list also
+ taskOperation = RESTConstants.TASK_DELETE;
+ }
+
+ if (taskOperation.equals(RESTConstants.TASK_DELETE)) {
+ removeTask(clusterName, task);
+ }
+
+ return noContentResponse();
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/UsersResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/UsersResource.java
new file mode 100644
index 00000000..6594ed0f
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/UsersResource.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_NEW_PASSWORD;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OLD_PASSWORD;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_USER;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_USERS;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.Status;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.dao.SaltSource;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.provisioning.JdbcUserDetailsManager;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.spi.resource.Singleton;
+
+@Singleton
+@Component
+@Path(RESOURCE_PATH_USERS)
+public class UsersResource extends AbstractResource {
+ @Autowired
+ private JdbcUserDetailsManager jdbcUserService;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private SaltSource saltSource;
+
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ private static final Logger logger = Logger.getLogger(UsersResource.class);
+
+ @Path("{" + PATH_PARAM_USER + "}")
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response authenticateXML(@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 getAuthenticationResponse(user, MediaType.APPLICATION_XML);
+ }
+
+ @Path("{" + PATH_PARAM_USER + "}")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response authenticateJSON(@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 getAuthenticationResponse(user, MediaType.APPLICATION_JSON);
+ }
+
+ public Response getAuthenticationResponse(String user, String mediaType) {
+ return (SecurityContextHolder.getContext().getAuthentication().getName().equals(user) ? okResponse(
+ Status.STATUS_SUCCESS, mediaType) : unauthorizedResponse());
+ }
+
+ @Path("{" + PATH_PARAM_USER + "}")
+ @PUT
+ public Response changePassword(@PathParam(PATH_PARAM_USER) String username,
+ @FormParam(FORM_PARAM_OLD_PASSWORD) String oldPassword,
+ @FormParam(FORM_PARAM_NEW_PASSWORD) String newPassword) {
+ try {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ String loggedInUser = ((UserDetails)auth.getPrincipal()).getUsername();
+ if(!loggedInUser.equals(username)) {
+ // Temporary check as we currently have only one user.
+ throw new GlusterValidationException("User [" + loggedInUser
+ + "] is not allowed to change password of user [" + username + "]!");
+ }
+
+ UserDetails user = userDetailsService.loadUserByUsername(username);
+ Object salt = saltSource.getSalt(user);
+
+ String actualOldPasswordEncoded = ((UserDetails)auth.getPrincipal()).getPassword();
+ String oldPasswordEncoded = passwordEncoder.encodePassword(oldPassword, salt);
+ if(!oldPasswordEncoded.equals(actualOldPasswordEncoded)) {
+ throw new GlusterValidationException("Invalid old password!");
+ }
+
+ String encodedNewPassword = passwordEncoder.encodePassword(newPassword, salt);
+ jdbcUserService.changePassword(oldPassword, encodedNewPassword);
+ } catch (Exception ex) {
+ String errMsg = "Could not change password. Error: [" + ex.getMessage() + "]";
+ logger.error(errMsg, ex);
+ throw new GlusterRuntimeException(errMsg);
+ }
+ return noContentResponse();
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java
new file mode 100644
index 00000000..18ed0314
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java
@@ -0,0 +1,383 @@
+/**
+ * VolumesResource.java
+ *
+ * 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 org.gluster.storage.management.gateway.resources.v1_0;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_ACCESS_PROTOCOLS;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_AUTO_COMMIT;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_BRICKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CIFS_ENABLE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CIFS_USERS;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FIX_LAYOUT;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FORCE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MIGRATE_DATA;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_REPLICA_COUNT;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SOURCE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_STRIPE_COUNT;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_TARGET;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_TRANSPORT_TYPE;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_OPTIONS;
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_TYPE;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICK_NAME;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DOWNLOAD;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_FROM_TIMESTAMP;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LOG_SEVERITY;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_MAX_COUNT;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_NEXT_TO;
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TO_TIMESTAMP;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_BRICKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DEFAULT_OPTIONS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DOWNLOAD;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_LOGS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_OPTIONS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_VOLUMES;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.RESTConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeLogMessage;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.response.LogMessageListResponse;
+import org.gluster.storage.management.core.response.VolumeListResponse;
+import org.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+import org.gluster.storage.management.core.utils.FileUtil;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.VolumeService;
+
+import com.sun.jersey.api.core.InjectParam;
+import com.sun.jersey.spi.resource.Singleton;
+
+@Singleton
+@Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_VOLUMES)
+public class VolumesResource extends AbstractResource {
+ private static final Logger logger = Logger.getLogger(VolumesResource.class);
+
+ @InjectParam
+ private ClusterService clusterService;
+
+ @InjectParam
+ private VolumeService volumeService;
+
+ @GET
+ @Produces({ MediaType.APPLICATION_XML })
+ public Response getVolumesXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
+ @QueryParam(QUERY_PARAM_NEXT_TO) String previousVolumeName) {
+ return okResponse(new VolumeListResponse(volumeService.getVolumes(clusterName, maxCount, previousVolumeName)),
+ MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON })
+ public Response getVolumesJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
+ @QueryParam(QUERY_PARAM_NEXT_TO) String previousVolumeName) {
+ return okResponse(new VolumeListResponse(volumeService.getVolumes(clusterName, maxCount, previousVolumeName)),
+ MediaType.APPLICATION_JSON);
+ }
+
+ @POST
+ @Produces(MediaType.APPLICATION_XML)
+ public Response createVolume(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @FormParam(FORM_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_VOLUME_TYPE) String volumeType,
+ @FormParam(FORM_PARAM_TRANSPORT_TYPE) String transportType,
+ @FormParam(FORM_PARAM_REPLICA_COUNT) Integer replicaCount,
+ @FormParam(FORM_PARAM_STRIPE_COUNT) Integer stripeCount, @FormParam(FORM_PARAM_BRICKS) String bricks,
+ @FormParam(FORM_PARAM_ACCESS_PROTOCOLS) String accessProtocols,
+ @FormParam(FORM_PARAM_VOLUME_OPTIONS) String options, @FormParam(FORM_PARAM_CIFS_USERS) String cifsUsers) {
+ int count = 0;
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ String missingParam = checkMissingParamsForCreateVolume(volumeName, volumeType, transportType, bricks,
+ accessProtocols, options);
+ if (missingParam != null) {
+ throw new GlusterValidationException("Parameter [" + missingParam + "] is missing in request!");
+ }
+
+ // For missing parameter, let default value
+ if (volumeType.equals(VOLUME_TYPE.REPLICATE.toString())
+ || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_REPLICATE.toString())) {
+ count = (replicaCount == null) ? Volume.DEFAULT_REPLICA_COUNT : replicaCount;
+ } else if (volumeType.equals(VOLUME_TYPE.STRIPE.toString())
+ || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_STRIPE.toString())) {
+ count = (stripeCount == null) ? Volume.DEFAULT_STRIPE_COUNT : stripeCount;
+ }
+
+ volumeService.createVolume(clusterName, volumeName, volumeType, transportType, count, bricks, accessProtocols,
+ options, cifsUsers);
+ return createdResponse(volumeName);
+ }
+
+ /**
+ * Returns name of the missing parameter if any. If all parameters are present,
+ */
+ private String checkMissingParamsForCreateVolume(String volumeName, String volumeType,
+ String transportType, String bricks, String accessProtocols,
+ String options) {
+
+ return (volumeName == null || volumeName.isEmpty()) ? FORM_PARAM_VOLUME_NAME :
+ (volumeType == null || volumeType.isEmpty()) ? FORM_PARAM_VOLUME_TYPE :
+ (transportType == null || transportType.isEmpty()) ? FORM_PARAM_TRANSPORT_TYPE :
+ (bricks == null || bricks.isEmpty()) ? FORM_PARAM_BRICKS :
+ (accessProtocols == null || accessProtocols.isEmpty()) ? FORM_PARAM_ACCESS_PROTOCOLS :
+ (options == null || options.isEmpty()) ? FORM_PARAM_VOLUME_OPTIONS :
+ null;
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}")
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getVolumeXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) {
+ return okResponse(volumeService.getVolume(clusterName, volumeName), MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getVolumeJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) {
+ return okResponse(volumeService.getVolume(clusterName, volumeName), MediaType.APPLICATION_JSON);
+ }
+
+ @PUT
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}")
+ public Response performOperation(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_OPERATION) String operation,
+ @FormParam(FORM_PARAM_FIX_LAYOUT) Boolean isFixLayout,
+ @FormParam(FORM_PARAM_MIGRATE_DATA) Boolean isMigrateData,
+ @FormParam(FORM_PARAM_FORCED_DATA_MIGRATE) Boolean isForcedDataMigrate,
+ @FormParam(FORM_PARAM_CIFS_ENABLE) Boolean enableCifs, @FormParam(FORM_PARAM_CIFS_USERS) String cifsUsers,
+ @FormParam(FORM_PARAM_BRICKS) String bricks, @FormParam(FORM_PARAM_FORCE) Boolean force) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ try {
+ if (operation.equals(RESTConstants.TASK_REBALANCE_START)) {
+ String taskId = volumeService.rebalanceStart(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate);
+ return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS
+ + "/" + taskId);
+ } else if (operation.equals(RESTConstants.TASK_REBALANCE_STOP)) {
+ volumeService.rebalanceStop(clusterName, volumeName);
+ } else if (operation.equals(RESTConstants.FORM_PARAM_CIFS_CONFIG)) {
+ Volume newVolume = volumeService.getVolume(clusterName, volumeName);
+ if (enableCifs) {
+ // After add/modify volume cifs users, start/restart the cifs service
+ volumeService.createCIFSUsers(clusterName, volumeName, cifsUsers);
+ if (newVolume.getStatus() == VOLUME_STATUS.ONLINE) {
+ volumeService.startCifsReExport(clusterName, volumeName);
+ }
+ } else {
+ // Stop the Cifs service and delete the users (!important)
+ if (newVolume.getStatus() == VOLUME_STATUS.ONLINE) {
+ volumeService.stopCifsReExport(clusterName, volumeName);
+ }
+ volumeService.deleteCifsUsers(clusterName, volumeName);
+ }
+ } else if (operation.equals(RESTConstants.TASK_LOG_ROTATE)) {
+ List<String> brickList = Arrays.asList(bricks.split(","));
+ volumeService.logRotate(clusterName, volumeName, brickList);
+ } else {
+ if (force == null) {
+ force = false;
+ }
+ volumeService.performVolumeOperation(clusterName, volumeName, operation, force);
+ }
+ return noContentResponse();
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ @DELETE
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}")
+ public Response deleteVolume(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName,
+ @QueryParam(QUERY_PARAM_DELETE_OPTION) Boolean deleteFlag) {
+ volumeService.deleteVolume(clusterName, volumeName, deleteFlag);
+
+ return noContentResponse();
+ }
+
+ @DELETE
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_BRICKS)
+ public Response removeBricks(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @QueryParam(QUERY_PARAM_BRICKS) String bricks,
+ @QueryParam(QUERY_PARAM_DELETE_OPTION) Boolean deleteFlag) {
+ volumeService.removeBricksFromVolume(clusterName, volumeName, bricks, deleteFlag);
+ return noContentResponse();
+ }
+
+ @POST
+ @Path("{" + PATH_PARAM_VOLUME_NAME + " }/" + RESOURCE_OPTIONS)
+ public Response setOption(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName,
+ @FormParam(RESTConstants.FORM_PARAM_OPTION_KEY) String key,
+ @FormParam(RESTConstants.FORM_PARAM_OPTION_VALUE) String value) {
+ volumeService.setVolumeOption(clusterName, volumeName, key, value);
+
+ return createdResponse(key);
+ }
+
+ @PUT
+ @Path("{" + PATH_PARAM_VOLUME_NAME + " }/" + RESOURCE_OPTIONS)
+ public Response resetOptions(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName) {
+ volumeService.resetVolumeOptions(clusterName, volumeName);
+ return noContentResponse();
+ }
+
+ @GET
+ @Path(RESOURCE_DEFAULT_OPTIONS)
+ @Produces(MediaType.APPLICATION_XML)
+ public VolumeOptionInfoListResponse getOptionsInfoXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ return volumeService.getVolumeOptionsInfo(clusterName);
+ }
+
+ @GET
+ @Path(RESOURCE_DEFAULT_OPTIONS)
+ @Produces(MediaType.APPLICATION_JSON)
+ public VolumeOptionInfoListResponse getOptionsInfoJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ return volumeService.getVolumeOptionsInfo(clusterName);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_LOGS + "/" + RESOURCE_DOWNLOAD)
+ public Response downloadLogs(@PathParam(PATH_PARAM_CLUSTER_NAME) final String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) final String volumeName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ return badRequestResponse("Volume name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ try {
+ final Volume volume = volumeService.getVolume(clusterName, volumeName);
+ File archiveFile = new File(volumeService.downloadLogs(volume));
+ byte[] data = FileUtil.readFileAsByteArray(archiveFile);
+ archiveFile.delete();
+ return streamingOutputResponse(createStreamingOutput(data));
+ } catch (Exception e) {
+ logger.error("Volume [" + volumeName + "] doesn't exist in cluster [" + clusterName + "]! ["
+ + e.getStackTrace() + "]");
+ throw (GlusterRuntimeException) e;
+ }
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_LOGS)
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getLogsXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @QueryParam(QUERY_PARAM_BRICK_NAME) String brickName,
+ @QueryParam(QUERY_PARAM_LOG_SEVERITY) String severity,
+ @QueryParam(QUERY_PARAM_FROM_TIMESTAMP) String fromTimestamp,
+ @QueryParam(QUERY_PARAM_TO_TIMESTAMP) String toTimestamp,
+ @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount, @QueryParam(QUERY_PARAM_DOWNLOAD) Boolean download) {
+ return getLogs(clusterName, volumeName, brickName, severity, fromTimestamp, toTimestamp, lineCount, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_LOGS)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getLogsJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @QueryParam(QUERY_PARAM_BRICK_NAME) String brickName,
+ @QueryParam(QUERY_PARAM_LOG_SEVERITY) String severity,
+ @QueryParam(QUERY_PARAM_FROM_TIMESTAMP) String fromTimestamp,
+ @QueryParam(QUERY_PARAM_TO_TIMESTAMP) String toTimestamp,
+ @QueryParam(QUERY_PARAM_LINE_COUNT) Integer lineCount, @QueryParam(QUERY_PARAM_DOWNLOAD) Boolean download) {
+ return getLogs(clusterName, volumeName, brickName, severity, fromTimestamp, toTimestamp, lineCount, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getLogs(String clusterName, String volumeName, String brickName, String severity,
+ String fromTimestamp, String toTimestamp, Integer lineCount, String mediaType) {
+ List<VolumeLogMessage> logMessages = volumeService.getLogs(clusterName, volumeName, brickName, severity,
+ fromTimestamp, toTimestamp, lineCount);
+
+ return okResponse(new LogMessageListResponse(logMessages), mediaType);
+ }
+
+ @POST
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_BRICKS)
+ public Response addBricks(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_BRICKS) String bricks) {
+ volumeService.addBricksToVolume(clusterName, volumeName, bricks);
+
+ return createdResponse(volumeName + "/" + RESOURCE_BRICKS);
+ }
+
+ @PUT
+ @Path("{" + PATH_PARAM_VOLUME_NAME + "}/" + RESOURCE_BRICKS)
+ public Response migrateBrick(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_VOLUME_NAME) String volumeName, @FormParam(FORM_PARAM_SOURCE) String fromBrick,
+ @FormParam(FORM_PARAM_TARGET) String toBrick, @FormParam(FORM_PARAM_AUTO_COMMIT) Boolean autoCommit) {
+
+ String taskId = volumeService.migrateBrickStart(clusterName, volumeName, fromBrick, toBrick, autoCommit);
+
+ return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + "/"
+ + taskId);
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/GlusterUserDetailsService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/GlusterUserDetailsService.java
new file mode 100644
index 00000000..a73f2d61
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/GlusterUserDetailsService.java
@@ -0,0 +1,31 @@
+/**
+ * GlusterUserDetailsService.java
+ *
+ * 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 org.gluster.storage.management.gateway.security;
+
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+/**
+ *
+ */
+public interface GlusterUserDetailsService extends UserDetailsService {
+ void changePassword(String username, String password);
+}
+
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/UserAuthDao.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/UserAuthDao.java
new file mode 100644
index 00000000..b0473f0c
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/security/UserAuthDao.java
@@ -0,0 +1,57 @@
+/**
+ * UserAuthDao.java
+ *
+ * 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 org.gluster.storage.management.gateway.security;
+
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+
+
+/**
+ *
+ */
+public class UserAuthDao extends JdbcDaoImpl implements GlusterUserDetailsService {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.gluster.storage.management.gateway.security.GlusterUserDetailsService#changePassword(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void changePassword(String username, String password) {
+ DataSourceTransactionManager txnManager = new DataSourceTransactionManager();
+ txnManager.setDataSource(getDataSource());
+
+ TransactionDefinition def = new DefaultTransactionDefinition();
+ TransactionStatus status = txnManager.getTransaction(def);
+ try {
+ getJdbcTemplate().update("UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?", password, username);
+ txnManager.commit(status);
+ } catch(Exception e) {
+ txnManager.rollback(status);
+ throw new GlusterRuntimeException("Exception while changing password of user [" + username + "]. Error: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/AbstractGlusterInterface.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/AbstractGlusterInterface.java
new file mode 100644
index 00000000..99935749
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/AbstractGlusterInterface.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+/**
+ * Abstract Gluster Interface - provides functionality common across all versions of GlusterFS e.g. version check.
+ */
+public abstract class AbstractGlusterInterface implements GlusterInterface {
+
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ @Override
+ public String getVersion(String serverName) {
+ return serverUtil.executeOnServer(serverName, "gluster --version").split("\n")[0].replaceAll("glusterfs ", "")
+ .replaceAll(" built.*", "");
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/ClusterService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/ClusterService.java
new file mode 100644
index 00000000..e7a5af3d
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/ClusterService.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityTransaction;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.utils.LRUCache;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.PersistenceDao;
+import org.gluster.storage.management.gateway.data.ServerInfo;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.gluster.storage.management.gateway.utils.SshUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Service class for functionality related to clusters
+ */
+@Component
+public class ClusterService {
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ @Autowired
+ private PersistenceDao<ServerInfo> serverDao;
+
+ @Autowired
+ private GlusterServerService glusterServerService;
+
+ @Autowired
+ private SshUtil sshUtil;
+
+ @Autowired
+ private ServerUtil serverUtil;
+
+ private LRUCache<String, GlusterServer> onlineServerCache = new LRUCache<String, GlusterServer>(3);
+
+ private static final Logger logger = Logger.getLogger(ClusterService.class);
+
+ public void addOnlineServer(String clusterName, GlusterServer server) {
+ onlineServerCache.put(clusterName, server);
+ }
+
+ public void removeOnlineServer(String clusterName) {
+ onlineServerCache.remove(clusterName);
+ }
+
+ // uses cache
+ public GlusterServer getOnlineServer(String clusterName, String exceptServerName) {
+ GlusterServer server = onlineServerCache.get(clusterName);
+ if (server != null && !server.getName().equalsIgnoreCase(exceptServerName)) {
+ return server;
+ }
+
+ return getNewOnlineServer(clusterName, exceptServerName);
+ }
+
+ public GlusterServer getNewOnlineServer(String clusterName) {
+ return getNewOnlineServer(clusterName, "");
+ }
+
+ public GlusterServer getOnlineServer(String clusterName) {
+ return getOnlineServer(clusterName, "");
+ }
+
+ // Doesn't use cache
+ public GlusterServer getNewOnlineServer(String clusterName, String exceptServerName) {
+ ClusterInfo cluster = getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterRuntimeException("Cluster [" + clusterName + "] is not found!");
+ }
+
+ for (ServerInfo serverInfo : cluster.getServers()) {
+ GlusterServer server = new GlusterServer(serverInfo.getName());
+ try {
+ serverUtil.fetchServerDetails(server); // Online status come with server details
+ // server is online. add it to cache and return
+ if (server.isOnline() && !server.getName().equalsIgnoreCase(exceptServerName)) {
+ addOnlineServer(clusterName, server);
+ return server;
+ }
+ } catch (ConnectionException e) {
+ // server is offline. continue checking next one.
+ continue;
+ }
+ }
+
+ // no online server found.
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+
+ public List<ClusterInfo> getAllClusters() {
+ return clusterDao.findAll();
+ }
+
+ public ClusterInfo getCluster(String clusterName) {
+ List<ClusterInfo> clusters = clusterDao.findBy("UPPER(name) = ?1", clusterName.toUpperCase());
+ if(clusters.size() == 0) {
+ return null;
+ }
+
+ return clusters.get(0);
+ }
+
+ public ClusterInfo getClusterForServer(String serverName) {
+ List<ServerInfo> servers = serverDao.findBy("UPPER(name) = ?1", serverName.toUpperCase());
+ if(servers.size() == 0) {
+ return null;
+ }
+
+ return servers.get(0).getCluster();
+ }
+
+ public void createCluster(String clusterName) {
+ EntityTransaction txn = clusterDao.startTransaction();
+ ClusterInfo cluster = new ClusterInfo();
+ cluster.setName(clusterName);
+
+ try {
+ clusterDao.save(cluster);
+ txn.commit();
+ } catch (RuntimeException e) {
+ txn.rollback();
+ logger.error("Exception while trying to save cluster [" + clusterName + "] : [" + e.getMessage() + "]", e);
+ throw e;
+ }
+ }
+
+ public void registerCluster(String clusterName, String knownServer) {
+ EntityTransaction txn = clusterDao.startTransaction();
+ ClusterInfo cluster = new ClusterInfo();
+ cluster.setName(clusterName);
+
+ GlusterServer server = new GlusterServer(knownServer);
+ try {
+ List<GlusterServer> glusterServers = glusterServerService.getGlusterServers(server.getName());
+ List<ServerInfo> servers = new ArrayList<ServerInfo>();
+ for(GlusterServer glusterServer : glusterServers) {
+ String serverName = glusterServer.getName();
+
+ serverUtil.fetchServerDetails(glusterServer);
+ if(glusterServer.isOnline()) {
+ checkAndSetupPublicKey(serverName);
+ }
+
+ ServerInfo serverInfo = new ServerInfo(serverName);
+ serverInfo.setCluster(cluster);
+ clusterDao.save(serverInfo);
+ servers.add(serverInfo);
+ }
+ cluster.setServers(servers);
+ clusterDao.save(cluster);
+ txn.commit();
+ } catch(RuntimeException e) {
+ logger.error("Error in registering cluster [" + clusterName + "] : " + e.getMessage(), e);
+ txn.rollback();
+ logger.error("Error in registering cluster [" + clusterName + "] : " + e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ private void checkAndSetupPublicKey(String serverName) {
+ if(sshUtil.isPublicKeyInstalled(serverName)) {
+ return;
+ }
+
+ if(!sshUtil.hasDefaultPassword(serverName)) {
+ // public key not installed, default password doesn't work. can't install public key
+ throw new GlusterRuntimeException(
+ "Gluster Management Gateway uses the default password to set up keys on the server."
+ + CoreConstants.NEWLINE + "However it seems that the password on server [" + serverName
+ + "] has been changed manually." + CoreConstants.NEWLINE
+ + "Please reset it back to the standard default password and try again.");
+ }
+
+ // install public key (this will also disable password based ssh login)
+ sshUtil.installPublicKey(serverName);
+ }
+
+ public void unregisterCluster(String clusterName) {
+ ClusterInfo cluster = getCluster(clusterName);
+
+ if (cluster == null) {
+ throw new GlusterRuntimeException("Cluster [" + clusterName + "] doesn't exist!");
+ }
+
+ unregisterCluster(cluster);
+ }
+
+ public void unregisterCluster(ClusterInfo cluster) {
+ EntityTransaction txn = clusterDao.startTransaction();
+ try {
+ for(ServerInfo server : cluster.getServers()) {
+ clusterDao.delete(server);
+ }
+ cluster.getServers().clear();
+ clusterDao.update(cluster);
+ clusterDao.delete(cluster);
+ txn.commit();
+ } catch (RuntimeException e) {
+ logger.error("Error in unregistering cluster [" + cluster.getName() + "] : " + e.getMessage(), e);
+ txn.rollback();
+ throw e;
+ }
+ }
+
+ public void mapServerToCluster(String clusterName, String serverName) {
+ EntityTransaction txn = clusterDao.startTransaction();
+ ClusterInfo cluster = getCluster(clusterName);
+ ServerInfo server = new ServerInfo(serverName);
+ server.setCluster(cluster);
+ try {
+ clusterDao.save(server);
+ cluster.addServer(server);
+ clusterDao.update(cluster);
+ txn.commit();
+ } catch (Exception e) {
+ txn.rollback();
+ throw new GlusterRuntimeException("Couldn't create cluster-server mapping [" + clusterName + "]["
+ + serverName + "]! Error: " + e.getMessage(), e);
+ }
+ }
+
+ public void unmapServerFromCluster(String clusterName, String serverName) {
+ EntityTransaction txn = clusterDao.startTransaction();
+ ClusterInfo cluster = getCluster(clusterName);
+ List<ServerInfo> servers = cluster.getServers();
+ for(ServerInfo server : servers) {
+ if(server.getName().equalsIgnoreCase(serverName)) {
+ servers.remove(server);
+ clusterDao.delete(server);
+ break;
+ }
+ }
+ try {
+ clusterDao.update(cluster);
+ txn.commit();
+ } catch(Exception e) {
+ txn.rollback();
+ throw new GlusterRuntimeException("Couldn't unmap server [" + serverName + "] from cluster [" + clusterName
+ + "]! Error: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/DiscoveredServerService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/DiscoveredServerService.java
new file mode 100644
index 00000000..95a8eecb
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/DiscoveredServerService.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class DiscoveredServerService {
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ private List<String> discoveredServerNames = new ArrayList<String>();
+ private static final Logger logger = Logger.getLogger(DiscoveredServerService.class);
+
+ public List<Server> getDiscoveredServerDetails() {
+ try {
+ List<Server> discoveredServers = Collections.synchronizedList(new ArrayList<Server>());
+ List<Thread> threads = createThreads(discoveredServers);
+ ProcessUtil.waitForThreads(threads);
+ return discoveredServers;
+ } catch (Exception e) {
+ String errMsg = "Exception while fetching details of discovered servers! Error: [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ /**
+ * Creates threads that will run in parallel and fetch details of all discovered servers
+ * @param discoveredServers The list to be populated with details of discovered servers
+ * @return
+ * @throws InterruptedException
+ */
+ private List<Thread> createThreads(List<Server> discoveredServers) throws InterruptedException {
+ List<String> discoveredServerNames = getDiscoveredServerNames();
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = discoveredServerNames.size() - 1; i >= 0; i--) {
+ Thread thread = new DiscoveredServerDetailsThread(discoveredServers, discoveredServerNames.get(i));
+ threads.add(thread);
+ thread.start();
+ if (i >= 5 && i % 5 == 0) {
+ // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
+ Thread.sleep(1000);
+ }
+ }
+ return threads;
+ }
+
+ public List<String> getDiscoveredServerNames() {
+ return discoveredServerNames;
+ }
+
+ public void setDiscoveredServerNames(List<String> discoveredServerNames) {
+ synchronized (discoveredServerNames) {
+ this.discoveredServerNames = discoveredServerNames;
+ }
+ }
+
+ public void removeDiscoveredServer(String serverName) {
+ discoveredServerNames.remove(serverName);
+ }
+
+ public void addDiscoveredServer(String serverName) {
+ discoveredServerNames.add(serverName);
+ }
+
+ public Server getDiscoveredServer(String serverName) {
+ Server server = new Server(serverName);
+ serverUtil.fetchServerDetails(server);
+ return server;
+ }
+
+ public class DiscoveredServerDetailsThread extends Thread {
+ private List<Server> servers;
+ private String serverName;
+ private final Logger logger = Logger.getLogger(DiscoveredServerDetailsThread.class);
+
+ /**
+ * Private constructor called on each thread
+ * @param servers The list to be populated with fetched server details
+ * @param serverName Name of the server whose details should be fetched by this thread
+ */
+ private DiscoveredServerDetailsThread(List<Server> servers, String serverName) {
+ this.servers = servers;
+ this.serverName = serverName;
+ }
+
+ @Override
+ public void run() {
+ try {
+ logger.info("fetching details of discovered server [" + serverName + "] - start");
+ servers.add(getDiscoveredServer(serverName));
+ logger.info("fetching details of discovered server [" + serverName + "] - end");
+ } catch(Exception e) {
+ logger.warn("fetching details of discovered server [" + serverName + "] - error", e);
+ // eat the exception as we can't consider this server as a discovered server any more
+ }
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/Gluster323InterfaceService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/Gluster323InterfaceService.java
new file mode 100644
index 00000000..ec7ae77e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/Gluster323InterfaceService.java
@@ -0,0 +1,598 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import org.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+import org.gluster.storage.management.core.utils.StringUtil;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Gluster Interface for GlusterFS version 3.2.3
+ */
+@Component
+@Lazy(value=true)
+public class Gluster323InterfaceService extends AbstractGlusterInterface {
+
+ private static final String VOLUME_NAME_PFX = "Volume Name:";
+ private static final String VOLUME_TYPE_PFX = "Type:";
+ private static final String VOLUME_STATUS_PFX = "Status:";
+ private static final String VOLUME_NUMBER_OF_BRICKS = "Number of Bricks:";
+ 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_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 String VOLUME_TYPE_DISTRIBUTED_REPLICATTE = "Distributed-Replicate";
+ private static final String VOLUME_TYPE_STRIPE = "Stripe";
+ private static final String VOLUME_TYPE_DISTRIBUTED_STRIPE = "Distributed-Stripe";
+
+ private static final String BRICK_STATUS_SCRIPT = "get_brick_status.py";
+ private static final Logger logger = Logger.getLogger(Gluster323InterfaceService.class);
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#addServer(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void addServer(String existingServer, String newServer) {
+ serverUtil.executeOnServer(existingServer, "gluster peer probe " + newServer);
+ // reverse peer probe to ensure that host names appear in peer status on both sides
+ serverUtil.executeOnServer(newServer, "gluster peer probe " + existingServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#startVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startVolume(String volumeName, String knownServer, Boolean force) {
+ serverUtil.executeOnServer(knownServer, "gluster volume start " + volumeName + ((force) ? " force" : ""));
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#stopVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopVolume(String volumeName, String knownServer, Boolean force) {
+ serverUtil.executeOnServer(knownServer, "gluster --mode=script volume stop " + volumeName
+ + ((force) ? " force" : ""));
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#resetOptions(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void resetOptions(String volumeName, String knownServer) {
+ serverUtil.executeOnServer(knownServer, "gluster volume reset " + volumeName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#createVolume(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void createVolume(String knownServer, String volumeName, String volumeTypeStr, String transportTypeStr,
+ Integer count, String bricks, String accessProtocols, String options) {
+
+ // TODO: Disable NFS if required depending on value of accessProtocols
+ VOLUME_TYPE volType = Volume.getVolumeTypeByStr(volumeTypeStr);
+ String volTypeArg = null;
+ if (volType == VOLUME_TYPE.REPLICATE || volType == VOLUME_TYPE.DISTRIBUTED_REPLICATE) {
+ volTypeArg = "replica";
+ } else if (volType == VOLUME_TYPE.STRIPE || volType == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ volTypeArg = "stripe";
+ }
+
+ String transportTypeArg = null;
+ TRANSPORT_TYPE transportType = Volume.getTransportTypeByStr(transportTypeStr);
+ transportTypeArg = (transportType == TRANSPORT_TYPE.ETHERNET) ? "tcp" : "rdma";
+
+ String command = prepareVolumeCreateCommand(volumeName, StringUtil.extractList(bricks, ","), count,
+ volTypeArg, transportTypeArg);
+
+ serverUtil.executeOnServer(knownServer, command);
+
+ try {
+ createOptions(volumeName, StringUtil.extractMap(options, ",", "="), knownServer);
+ } catch(Exception e) {
+ throw new GlusterRuntimeException(
+ "Volume created successfully, however following errors occurred while setting options: "
+ + CoreConstants.NEWLINE + e.getMessage());
+ }
+ }
+
+ private String prepareVolumeCreateCommand(String volumeName, List<String> brickDirectories, int count,
+ String volumeType, String transportTypeStr) {
+ StringBuilder command = new StringBuilder("gluster volume create " + volumeName + " ");
+ if (volumeType != null) {
+ command.append(volumeType + " " + count + " ");
+ }
+ command.append("transport " + transportTypeStr);
+ for (String brickDir : brickDirectories) {
+ command.append(" " + brickDir);
+ }
+ return command.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#createOptions(java.lang.String, java.util.Map, java.lang.String)
+ */
+ @Override
+ public void createOptions(String volumeName, Map<String, String> options, String knownServer) {
+ String errors = "";
+ if (options != null) {
+ for (Entry<String, String> option : options.entrySet()) {
+ String key = option.getKey();
+ String value = option.getValue();
+
+ try {
+ setOption(volumeName, key, value, knownServer);
+ } catch(Exception e) {
+ // append error
+ errors += e.getMessage() + CoreConstants.NEWLINE;
+ }
+ }
+ }
+ if (!errors.trim().isEmpty()) {
+ throw new GlusterRuntimeException("Errors while setting option(s) on volume [" + volumeName + "] : "
+ + errors.trim());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#setOption(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void setOption(String volumeName, String key, String value, String knownServer) {
+ serverUtil.executeOnServer(knownServer, "gluster volume set " + volumeName + " " + key + " " + "\""
+ + value + "\"");
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#deleteVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void deleteVolume(String volumeName, String knownServer) {
+ serverUtil.executeOnServer(knownServer, "gluster --mode=script volume delete " + volumeName);
+ }
+
+ private String getVolumeInfo(String volumeName, String knownServer) {
+ return serverUtil.executeOnServer(knownServer, "gluster volume info " + volumeName, String.class);
+ }
+
+ private String getVolumeInfo(String knownServer) {
+ return serverUtil.executeOnServer(knownServer, "gluster volume info", String.class);
+ }
+
+ private boolean readVolumeType(Volume volume, String line) {
+ String volumeType = StringUtil.extractToken(line, VOLUME_TYPE_PFX);
+ if (volumeType != null) {
+ if (volumeType.equals(VOLUME_TYPE_DISTRIBUTE)) {
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTE);
+
+ } else if (volumeType.equals(VOLUME_TYPE_REPLICATE)) {
+ volume.setVolumeType(VOLUME_TYPE.REPLICATE);
+ volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT);
+
+ } else if ( volumeType.equals(VOLUME_TYPE_DISTRIBUTED_REPLICATTE) ){
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_REPLICATE);
+ volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT);
+
+ } else if ( volumeType.equals(VOLUME_TYPE_STRIPE) ){
+ volume.setVolumeType(VOLUME_TYPE.STRIPE);
+ volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT);
+
+ } else if ( volumeType.equals(VOLUME_TYPE_DISTRIBUTED_STRIPE) ){
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_STRIPE);
+ volume.setReplicaCount(Volume.DEFAULT_STRIPE_COUNT);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void readReplicaOrStripeCount(Volume volume, String line) {
+ if (StringUtil.extractToken(line, "x") != null) {
+ // expected formated of line is "Number of Bricks: 3 x 2 = 6"
+ int count = Integer.parseInt(line.split("x")[1].split("=")[0].trim());
+ if (volume.getVolumeType() == VOLUME_TYPE.STRIPE
+ || volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ volume.setStripeCount(count);
+ } else if (volume.getVolumeType() == VOLUME_TYPE.REPLICATE
+ || volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_REPLICATE) {
+ volume.setReplicaCount(count);
+ volume.setStripeCount(0);
+ }
+ }
+ return;
+ }
+
+ private boolean readVolumeStatus(Volume volume, String line) {
+ String volumeStatus = StringUtil.extractToken(line, VOLUME_STATUS_PFX);
+ if (volumeStatus != null) {
+ volume.setStatus(volumeStatus.equals("Started") ? VOLUME_STATUS.ONLINE : VOLUME_STATUS.OFFLINE);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean readTransportType(Volume volume, String line) {
+ String transportType = StringUtil.extractToken(line, VOLUME_TRANSPORT_TYPE_PFX);
+ if (transportType != null) {
+ volume.setTransportType(transportType.equals("tcp") ? TRANSPORT_TYPE.ETHERNET : TRANSPORT_TYPE.INFINIBAND);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean readBrick(Volume volume, String brickLine) {
+ BRICK_STATUS brickStatus;
+ if (brickLine.matches("Brick[0-9]+:.*")) {
+ // line: "Brick1: server1:/export/md0/volume-name"
+ String brickName = brickLine.split(": ")[1];
+ String[] brickParts = brickLine.split(":");
+ String serverName = brickParts[1].trim();
+ String brickDir = brickParts[2].trim();
+ //To get the brick status
+ brickStatus = getBrickStatus(serverName, volume.getName(), brickName);
+
+ addBrickToVolume(volume, serverName, brickDir, brickStatus);
+ return true;
+ }
+ return false;
+ }
+
+ private void addBrickToVolume(Volume volume, String serverName, String brickDir, BRICK_STATUS status) {
+ volume.addBrick(new Brick(serverName, status, brickDir));
+ }
+
+ // Do not throw exception, Gracefully handle as Offline brick.
+ private BRICK_STATUS getBrickStatus(String serverName, String volumeName, String brick){
+ try {
+ String output = serverUtil.executeScriptOnServer(serverName, BRICK_STATUS_SCRIPT + " " + volumeName
+ + " " + brick, String.class);
+ if (output.equals(CoreConstants.ONLINE)) {
+ return BRICK_STATUS.ONLINE;
+ } else {
+ return BRICK_STATUS.OFFLINE;
+ }
+ } catch(Exception e) { // Particularly interested on ConnectionExecption, if the server is offline
+ logger.warn("Exception while fetching brick status for [" + volumeName + "][" + brick
+ + "]. Marking it as offline!", e);
+ return BRICK_STATUS.OFFLINE;
+ }
+ }
+
+ private boolean readBrickGroup(String line) {
+ return StringUtil.extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null;
+ }
+
+ private boolean readOptionReconfigGroup(String line) {
+ return StringUtil.extractToken(line, VOLUME_OPTIONS_RECONFIG_PFX) != null;
+ }
+
+ private boolean readOption(Volume volume, String line) {
+ if (line.matches("^[^:]*:.*$")) {
+ int index = line.indexOf(':');
+ volume.setOption(line.substring(0, index).trim(), line.substring(index + 1, line.length()).trim());
+
+ if (line.substring(0, index).trim().equals(Volume.OPTION_NFS_DISABLE)) {
+ if (line.substring(index + 1, line.length()).trim().equals(GlusterConstants.ON)) {
+ volume.disableNFS();
+ } else {
+ volume.enableNFS();
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public Volume getVolume(String volumeName, String knownServer) {
+ return parseVolumeInfo(getVolumeInfo(volumeName, knownServer)).get(0);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getAllVolumes(java.lang.String)
+ */
+ @Override
+ public List<Volume> getAllVolumes(String knownServer) {
+ return parseVolumeInfo(getVolumeInfo(knownServer));
+ }
+
+ private List<Volume> parseVolumeInfo(String volumeInfoText) {
+ List<Volume> volumes = new ArrayList<Volume>();
+ boolean isBricksGroupFound = false;
+ boolean isOptionReconfigFound = false;
+ Volume volume = null;
+
+ for (String line : volumeInfoText.split(CoreConstants.NEWLINE)) {
+ String volumeName = StringUtil.extractToken(line, VOLUME_NAME_PFX);
+ if (volumeName != null) {
+ if (volume != null) {
+ volumes.add(volume);
+ }
+
+ // prepare next volume to be read
+ volume = new Volume();
+ volume.setName(volumeName);
+ isBricksGroupFound = isOptionReconfigFound = false;
+ continue;
+ }
+
+ if (readVolumeType(volume, line))
+ continue;
+ if (StringUtil.extractToken(line, VOLUME_NUMBER_OF_BRICKS) != null) {
+ readReplicaOrStripeCount(volume, line);
+ }
+ if (readVolumeStatus(volume, line))
+ continue;
+ if (readTransportType(volume, line))
+ continue;
+ if (readBrickGroup(line)) {
+ isBricksGroupFound = true;
+ continue;
+ }
+
+ if (isBricksGroupFound) {
+ if (readBrick(volume, line)) {
+ continue;
+ } else {
+ isBricksGroupFound = false;
+ }
+ }
+
+ if (readOptionReconfigGroup(line)) {
+ isOptionReconfigFound = true;
+ continue;
+ }
+
+ if (isOptionReconfigFound) {
+ if (readOption(volume, line)) {
+ continue;
+ } else {
+ isOptionReconfigFound = false;
+ }
+ }
+ }
+
+ // add the last read volume
+ if (volume != null) {
+ volumes.add(volume);
+ }
+
+ return volumes;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#addBricks(java.lang.String, java.util.List, java.lang.String)
+ */
+ @Override
+ public void addBricks(String volumeName, List<String> bricks, String knownServer) {
+ StringBuilder command = new StringBuilder("gluster volume add-brick " + volumeName);
+ for (String brickDir : bricks) {
+ command.append(" " + brickDir);
+ }
+
+ serverUtil.executeOnServer(knownServer, command.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getLogLocation(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public String getLogLocation(String volumeName, String brickName, String knownServer) {
+ String command = "gluster volume log locate " + volumeName + " " + brickName;
+ String output = serverUtil.executeOnServer(knownServer, command, String.class);
+ if (output.startsWith(VOLUME_LOG_LOCATION_PFX)) {
+ return output.substring(VOLUME_LOG_LOCATION_PFX.length()).trim();
+ }
+
+ throw new GlusterRuntimeException("Couldn't parse output of command [" + command + "]. Output [" + output
+ + "] doesn't start with prefix [" + VOLUME_LOG_LOCATION_PFX + "]");
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getLogFileNameForBrickDir(java.lang.String)
+ */
+ @Override
+ public String getLogFileNameForBrickDir(String serverName, String brickDir) {
+ String logFileName = brickDir;
+ if (logFileName.length() > 0 && logFileName.charAt(0) == '/') {
+ logFileName = logFileName.replaceFirst("/", "");
+ }
+ logFileName = logFileName.replaceAll("/", "-") + ".log";
+ return logFileName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#removeBricks(java.lang.String, java.util.List, java.lang.String)
+ */
+ @Override
+ public void removeBricks(String volumeName, List<String> bricks, String knownServer) {
+ StringBuilder command = new StringBuilder("gluster --mode=script volume remove-brick " + volumeName);
+ for (String brickDir : bricks) {
+ command.append(" " + brickDir);
+ }
+ serverUtil.executeOnServer(knownServer, command.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#removeServer(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void removeServer(String existingServer, String serverName) {
+ serverUtil.executeOnServer(existingServer, "gluster --mode=script peer detach " + serverName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#checkRebalanceStatus(java.lang.String, java.lang.String)
+ */
+ @Override
+ public TaskStatus checkRebalanceStatus(String serverName, String volumeName) {
+ String command = "gluster volume rebalance " + volumeName + " status";
+ String output = serverUtil.executeOnServer(serverName, command, String.class).trim();
+ TaskStatus taskStatus = new TaskStatus();
+ if (output.matches("^rebalance completed.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ } else if (output.matches(".*in progress.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ } else {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+ taskStatus.setMessage(output);
+ return taskStatus;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#stopRebalance(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopRebalance(String serverName, String volumeName) {
+ String command = "gluster volume rebalance " + volumeName + " stop";
+ serverUtil.executeOnServer(serverName, command);
+ }
+
+ /**
+ * Performs given Brick Migration (replace-brick) Operation on given volume
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume on which the Brick Migration Operation is to be executed
+ * @param fromBrick
+ * The source Brick (being replaced)
+ * @param toBrick
+ * The destination Brick (which is replacing the source Brick)
+ * @param operation
+ * @return
+ */
+ private String performBrickMigrationOperation(String serverName, String volumeName, String fromBrick,
+ String toBrick, String operation) {
+ String command = "gluster volume replace-brick " + volumeName + " " + fromBrick + " " + toBrick + " "
+ + operation;
+ return serverUtil.executeOnServer(serverName, command, String.class);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#executeBrickMigration(java.lang.String,
+ * java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ performBrickMigrationOperation(serverName, volumeName, fromBrick, toBrick, "start");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#pauseBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void pauseBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ performBrickMigrationOperation(serverName, volumeName, fromBrick, toBrick, "pause");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#stopBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ performBrickMigrationOperation(serverName, volumeName, fromBrick, toBrick, "abort");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#commitBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void commitBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ performBrickMigrationOperation(serverName, volumeName, fromBrick, toBrick, "commit");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#checkBrickMigrationStatus(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public TaskStatus checkBrickMigrationStatus(String serverName, String volumeName, String fromBrick, String toBrick) {
+ String output = performBrickMigrationOperation(serverName, volumeName, fromBrick, toBrick, "status");
+
+ TaskStatus taskStatus = new TaskStatus();
+ if (output.matches("^Number of files migrated.*Migration complete$")
+ || output.matches("^Number of files migrated = 0 .*Current file=")) {
+ // Note: Workaround - if no file in the volume brick to migrate,
+ // Gluster CLI is not giving proper (complete) status
+ taskStatus.setCode(Status.STATUS_CODE_COMMIT_PENDING);
+ taskStatus.setMessage(output.replaceAll("Migration complete", "Commit pending"));
+ } else if (output.matches("^Number of files migrated.*Current file=.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ } else if (output.matches("^replace brick has been paused.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_PAUSE);
+ } else {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+
+ taskStatus.setMessage(output);
+ return taskStatus;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getVolumeOptionsInfo(java.lang.String)
+ */
+ @Override
+ public VolumeOptionInfoListResponse getVolumeOptionsInfo(String serverName) {
+ return serverUtil.executeOnServer(serverName, "gluster volume set help-xml", VolumeOptionInfoListResponse.class);
+ }
+
+ public void logRotate(String volumeName, List<String> brickList, String knownServer) {
+ if (brickList == null || brickList.size() > 0) {
+ for (String brickDir : brickList) {
+ serverUtil.executeOnServer(knownServer, "gluster volume log rotate " + volumeName + " " + brickDir);
+ }
+ } else {
+ serverUtil.executeOnServer(knownServer, "gluster volume log rotate " + volumeName);
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterface.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterface.java
new file mode 100644
index 00000000..71c9e081
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterface.java
@@ -0,0 +1,369 @@
+package org.gluster.storage.management.gateway.services;
+
+import java.util.List;
+import java.util.Map;
+
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+
+
+/**
+ * Interface for interacting with GlusterFS. Every version of GlusterFS supported by the Gluster Management Gateway will
+ * have a corresponding implementation of this interface.
+ */
+public interface GlusterInterface {
+
+ /**
+ * Returns the GlusterFS version on given server.
+ *
+ * @param serverName
+ * Server on which Gluster version is to be checked.
+ * @return
+ */
+ public abstract String getVersion(String serverName);
+
+ /**
+ * Adds the new server to an existing cluster.
+ *
+ * @param existingServer
+ * Server part of the existing cluster.
+ * @param newServer
+ * Server to be added to the cluster.
+ */
+ public abstract void addServer(String existingServer, String newServer);
+
+ /**
+ * Removes given server from the cluster by executing appropriate Gluster command on given server.
+ *
+ * @param existingServer
+ * Server part of the existing cluster.
+ * @param serverName
+ * Server to be removed from the cluster.
+ */
+ public abstract void removeServer(String existingServer, String serverName);
+
+ /**
+ * Starts the given volume by executing appropriate Gluster command on given server.
+ *
+ * @param volumeName
+ * Volume to be started.
+ * @param serverName
+ * Server on which the Gluster command is to be executed. This server must be part of the cluster to
+ * which the volume belongs.
+ * @param force
+ * Flag indicating whether the "force" option should be used for starting the Volume. This is typically
+ * used when Volume is already started, but at least one of its bricks is offline, and results in
+ * bringing up the offline bricks.
+ */
+ public abstract void startVolume(String volumeName, String serverName, Boolean force);
+
+ /**
+ * Stops the given volume by executing appropriate Gluster command on given server.
+ *
+ * @param volumeName
+ * Volume to be stopped.
+ * @param serverName
+ * Server on which the Gluster command is to be executed. This server must be part of the cluster to
+ * which the volume belongs.
+ * @param force
+ * Flag indicating whether the Volume should be stopped forcefully. This is typically used if the regular
+ * stop option fails because of issues like rebalance / brick migration / geo-replication being in
+ * progress. This results in forcefully stopping the volume, leaving the other processes intact.
+ */
+ public abstract void stopVolume(String volumeName, String serverName, Boolean force);
+
+ /**
+ * Resets volume options on the given volume by executing appropriate Gluster command on given server.
+ *
+ * @param volumeName
+ * Volume on which options are to be reset.
+ * @param serverName
+ * Server on which the Gluster command is to be executed. This server must be part of the cluster to
+ * which the volume belongs.
+ */
+ public abstract void resetOptions(String volumeName, String serverName);
+
+ /**
+ * Creates a volume on given volume using given properties.
+ *
+ * @param serverName
+ * Server on which the Gluster command for creating the volume will be executed. This must be part of the
+ * cluster in which the volume is to be created.
+ * @param volumeName
+ * Name of the volume.
+ * @param volumeType
+ * Type of the volume e.g. DISTRIBUTE, REPLICATE, STRIPE, etc. See {@link VOLUME_TYPE} for full list of
+ * valid values.
+ * @param transportType
+ * Transport type of the volume e.g. ETHERNET. See {@link TRANSPORT_TYPE} for full list of valid values.
+ * @param replOrStripeCount
+ * Replica Count or Stripe count depending on the volume type. Ignored in case of pure distribute volumes
+ * (no replicate, no stripe).
+ * @param bricks
+ * Comma separated list of volume brick directories in following format: <br>
+ * server1:dir1,server2:dir2,server3:dir3,...,servern:dirn
+ * @param accessProtocols
+ * Optional parameter indicating access protocols to be enabled for the volume. If empty/null, GLUSTERFS
+ * and NFS will be enabled.
+ * @param options
+ * A comma separated list of volume options to be set on the newly created volume in following format: <br>
+ * key1=value1,key2=value2,key3=value3,...,keyn=valuen
+ */
+ public abstract void createVolume(String serverName, String volumeName, String volumeType, String transportType,
+ Integer replOrStripeCount, String bricks, String accessProtocols, String options);
+
+ /**
+ * Creates / Sets the given options on the given volume by executing appropriate Gluster command on the given
+ * server.
+ *
+ * @param volumeName
+ * Volume on which the options are to be set.
+ * @param options
+ * Map containing the volume options to be set. Key = option key, Value = option value.
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void createOptions(String volumeName, Map<String, String> options, String serverName);
+
+ /**
+ * Sets the given option on given volume by executing appropriate Gluster command on the given server.
+ *
+ * @param volumeName
+ * Volume on which the option is to be set.
+ * @param key
+ * Option key (name)
+ * @param value
+ * Option value
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void setOption(String volumeName, String key, String value, String serverName);
+
+ /**
+ * Deletes the given volume by executing appropriate Gluster command on the given server.
+ *
+ * @param volumeName
+ * Volume to be deleted.
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void deleteVolume(String volumeName, String serverName);
+
+ /**
+ * Fetches properties of the given Volume by executing appropriate Gluster command on the given server.
+ *
+ * @param volumeName
+ * Volume whose properties are to be fetched.
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @return A {@link Volume} object containing all properties of the given volume
+ */
+ public abstract Volume getVolume(String volumeName, String serverName);
+
+ /**
+ * Fetches the list of all volumes (along with their properties) by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @return A list of {@link Volume} objects representing every volume present in the cluster to which the given
+ * server belongs.
+ */
+ public abstract List<Volume> getAllVolumes(String serverName);
+
+ /**
+ * Adds given list of bricks to given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param volumeName
+ * Volume to which the bricks are to be added.
+ * @param bricks
+ * List of bricks to be added, each in the format serverName:brickDirectory
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void addBricks(String volumeName, List<String> bricks, String serverName);
+
+ /**
+ * Removes given list of bricks from given volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param volumeName
+ * Volume from which the bricks are to be removed
+ * @param bricks
+ * List of bricks to be removed, each in the format serverName:brickDirectory
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void removeBricks(String volumeName, List<String> bricks, String serverName);
+
+ /**
+ * Returns the log location of given brick of given volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param volumeName
+ * Volume for which log location is to be fetched.
+ * @param brickName
+ * Brick of the volume for which log location is to be fetched.
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @return Full path of the log file location (directory) for the given Volume Brick.
+ */
+ public abstract String getLogLocation(String volumeName, String brickName, String serverName);
+
+ /**
+ * Returns the log file name for given brick directory.
+ *
+ * @param serverName
+ * Server to which the brick belongs
+ * @param brickDir
+ * Brick directory for which log file name is to be returned.
+ * @return The log file name (without path) for the given brick directory.
+ */
+ public abstract String getLogFileNameForBrickDir(String serverName, String brickDir);
+
+ /**
+ * Checks the status of "Rebalance" operation on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose rebalance status is to be checked.
+ * @return Object of {@link TaskStatus} representing the status of Volume Rebalance.
+ */
+ public abstract TaskStatus checkRebalanceStatus(String serverName, String volumeName);
+
+ /**
+ * Stops "Rebalance" operation running on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Rebalance is to be stopped.
+ */
+ public abstract void stopRebalance(String serverName, String volumeName);
+
+ /**
+ * Starts Brick Migration (replace-brick) on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Brick is to be migrated/replaced.
+ * @param fromBrick
+ * The source Brick (to be replaced).
+ * @param toBrick
+ * The destination Brick (will replace the source Brick).
+ */
+ public abstract void startBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick);
+
+ /**
+ * Pauses Brick Migration (replace-brick) running on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Brick is being migrated/replaced.
+ * @param fromBrick
+ * The source Brick (being replaced).
+ * @param toBrick
+ * The destination Brick (which is replacing the source Brick).
+ */
+ public abstract void pauseBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick);
+
+ /**
+ * Aborts Brick Migration (replace-brick) running on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Brick is being migrated/replaced.
+ * @param fromBrick
+ * The source Brick (being replaced).
+ * @param toBrick
+ * The destination Brick (which is replacing the source Brick)
+ */
+ public abstract void stopBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick);
+
+ /**
+ * Commits Brick Migration (replace-brick) running on given Volume by executing appropriate Gluster command on the
+ * given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Brick is being migrated/replaced.
+ * @param fromBrick
+ * The source Brick (being replaced).
+ * @param toBrick
+ * The destination Brick (which is replacing the source Brick)
+ */
+ public abstract void commitBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick);
+
+ /**
+ * Checks status of Brick Migration (replace-brick) running on given Volume by executing appropriate Gluster command
+ * on the given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @param volumeName
+ * Volume whose Brick is being migrated/replaced.
+ * @param fromBrick
+ * The source Brick (being replaced).
+ * @param toBrick
+ * The destination Brick (which is replacing the source Brick)
+ * @return A {@link TaskStatus} object representing the status of Brick Migration
+ */
+ public abstract TaskStatus checkBrickMigrationStatus(String serverName, String volumeName, String fromBrick,
+ String toBrick);
+
+ /**
+ * Returns information about all the supported Volume Options by executing appropriate Gluster command
+ * on the given server.
+ *
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ * @return A {@link VolumeOptionInfoListResponse} object containing information about each and every supported
+ * Volume Option
+ */
+ public abstract VolumeOptionInfoListResponse getVolumeOptionsInfo(String serverName);
+
+ /**
+ * Rotates the logs for given Bricks of given Volume by executing appropriate Gluster command
+ * on the given server.
+ *
+ * @param volumeName
+ * Volume whose logs are to be rotated.
+ * @param brickList
+ * List of bricks whose logs are to be rotated, each in the format serverName:brickDirectory <br>
+ * This is an optional parameter. If null or empty, all logs of the Volume will be rotated.
+ * @param serverName
+ * The server on which the Gluster command will be executed. This must be part of the cluster to which
+ * the volume belongs.
+ */
+ public abstract void logRotate(String volumeName, List<String> brickList, String serverName);
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterfaceService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterfaceService.java
new file mode 100644
index 00000000..07e152b8
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterInterfaceService.java
@@ -0,0 +1,256 @@
+/**
+ * GlusterInterfaceService.java
+ *
+ * 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 org.gluster.storage.management.gateway.services;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class GlusterInterfaceService extends AbstractGlusterInterface {
+ private HashMap<String, GlusterInterface> glusterInterfaces = new HashMap<String, GlusterInterface>();
+
+ /**
+ * Returns an instance of the Gluster Interface for given version of GlusterFS
+ * @param glusterFsVersion
+ * @return
+ */
+ private GlusterInterface getGlusterInterfaceForVersion(String glusterFsVersion) {
+ GlusterInterface glusterInterface = glusterInterfaces.get(glusterFsVersion);
+ if(glusterInterface != null) {
+ return glusterInterface;
+ }
+
+ glusterInterface = serverUtil.getBean(Gluster323InterfaceService.class);
+ glusterInterfaces.put(glusterFsVersion, glusterInterface);
+ return glusterInterface;
+ }
+
+ /**
+ * Returns an instance of Gluster Interface for the version of GlusterFS installed on given server.
+ *
+ * @param serverName
+ * @return
+ */
+ private GlusterInterface getGlusterInterface(String serverName) {
+ return getGlusterInterfaceForVersion(getVersion(serverName));
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#addServer(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void addServer(String existingServer, String newServer) {
+ getGlusterInterface(existingServer).addServer(existingServer, newServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#startVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startVolume(String volumeName, String knownServer, Boolean force) {
+ getGlusterInterface(knownServer).startVolume(volumeName, knownServer, force);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#stopVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopVolume(String volumeName, String knownServer, Boolean force) {
+ getGlusterInterface(knownServer).stopVolume(volumeName, knownServer, force);
+ }
+
+ public void logRotate(String volumeName, List<String> brickList, String knownServer) {
+ getGlusterInterface(knownServer).logRotate(volumeName, brickList, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#resetOptions(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void resetOptions(String volumeName, String knownServer) {
+ getGlusterInterface(knownServer).resetOptions(volumeName, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#createVolume(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void createVolume(String knownServer, String volumeName, String volumeTypeStr, String transportTypeStr,
+ Integer count, String bricks, String accessProtocols, String options) {
+ getGlusterInterface(knownServer).createVolume(knownServer, volumeName, volumeTypeStr, transportTypeStr, count,
+ bricks, accessProtocols, options);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#createOptions(java.lang.String, java.util.Map, java.lang.String)
+ */
+ @Override
+ public void createOptions(String volumeName, Map<String, String> options, String knownServer) {
+ getGlusterInterface(knownServer).createOptions(volumeName, options, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#setOption(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void setOption(String volumeName, String key, String value, String knownServer) {
+ getGlusterInterface(knownServer).setOption(volumeName, key, value, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#deleteVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void deleteVolume(String volumeName, String knownServer) {
+ getGlusterInterface(knownServer).deleteVolume(volumeName, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getVolume(java.lang.String, java.lang.String)
+ */
+ @Override
+ public Volume getVolume(String volumeName, String knownServer) {
+ return getGlusterInterface(knownServer).getVolume(volumeName, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getAllVolumes(java.lang.String)
+ */
+ @Override
+ public List<Volume> getAllVolumes(String knownServer) {
+ return getGlusterInterface(knownServer).getAllVolumes(knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#addBricks(java.lang.String, java.util.List, java.lang.String)
+ */
+ @Override
+ public void addBricks(String volumeName, List<String> bricks, String knownServer) {
+ getGlusterInterface(knownServer).addBricks(volumeName, bricks, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getLogLocation(java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public String getLogLocation(String volumeName, String brickName, String knownServer) {
+ return getGlusterInterface(knownServer).getLogLocation(volumeName, brickName, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getLogFileNameForBrickDir(java.lang.String)
+ */
+ @Override
+ public String getLogFileNameForBrickDir(String serverName, String brickDir) {
+ return getGlusterInterface(serverName).getLogFileNameForBrickDir(serverName, brickDir);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#removeBricks(java.lang.String, java.util.List, java.lang.String)
+ */
+ @Override
+ public void removeBricks(String volumeName, List<String> bricks, String knownServer) {
+ getGlusterInterface(knownServer).removeBricks(volumeName, bricks, knownServer);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#removeServer(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void removeServer(String existingServer, String serverName) {
+ getGlusterInterface(serverName).removeServer(existingServer, serverName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#checkRebalanceStatus(java.lang.String, java.lang.String)
+ */
+ @Override
+ public TaskStatus checkRebalanceStatus(String serverName, String volumeName) {
+ return getGlusterInterface(serverName).checkRebalanceStatus(serverName, volumeName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#stopRebalance(java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopRebalance(String serverName, String volumeName) {
+ getGlusterInterface(serverName).stopRebalance(serverName, volumeName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#executeBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void startBrickMigration(String onlineServerName, String volumeName, String fromBrick, String toBrick) {
+ getGlusterInterface(onlineServerName).startBrickMigration(onlineServerName, volumeName, fromBrick, toBrick);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#pauseBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void pauseBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ getGlusterInterface(serverName).pauseBrickMigration(serverName, volumeName, fromBrick, toBrick);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#stopBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void stopBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ getGlusterInterface(serverName).stopBrickMigration(serverName, volumeName, fromBrick, toBrick);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#commitBrickMigration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void commitBrickMigration(String serverName, String volumeName, String fromBrick, String toBrick) {
+ getGlusterInterface(serverName).commitBrickMigration(serverName, volumeName, fromBrick, toBrick);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.services.GlusterInterface#checkBrickMigrationStatus(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public TaskStatus checkBrickMigrationStatus(String serverName, String volumeName, String fromBrick, String toBrick) {
+ return getGlusterInterface(serverName).checkBrickMigrationStatus(serverName, volumeName, fromBrick, toBrick);
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getVolumeOptionsInfo(java.lang.String)
+ */
+ @Override
+ public VolumeOptionInfoListResponse getVolumeOptionsInfo(String serverName) {
+ return getGlusterInterface(serverName).getVolumeOptionsInfo(serverName);
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterServerService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterServerService.java
new file mode 100644
index 00000000..58482958
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/GlusterServerService.java
@@ -0,0 +1,530 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.response.StringListResponse;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.gluster.storage.management.core.utils.StringUtil;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.ServerInfo;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.gluster.storage.management.gateway.utils.SshUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class GlusterServerService {
+ private static final String HOSTNAME_PFX = "Hostname:";
+ private static final String UUID_PFX = "Uuid:";
+ private static final String STATE_PFX = "State:";
+ private static final String GLUSTER_SERVER_STATUS_ONLINE = "Peer in Cluster (Connected)";
+ private static final String GLUSTERD_INFO_FILE = "/etc/glusterd/glusterd.info";
+
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private GlusterInterfaceService glusterUtil;
+
+ @Autowired
+ private SshUtil sshUtil;
+
+ @Autowired
+ private VolumeService volumeService;
+
+ @Autowired
+ private DiscoveredServerService discoveredServerService;
+
+ private static final Logger logger = Logger.getLogger(GlusterServerService.class);
+
+ public List<GlusterServer> getGlusterServers(String clusterName, boolean fetchDetails, Integer maxCount,
+ String previousServerName) {
+ List<GlusterServer> glusterServers;
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails, maxCount, previousServerName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails, maxCount, previousServerName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+
+ }
+ return glusterServers;
+ }
+
+ private List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails,
+ Integer maxCount, String previousServerName) {
+ List<GlusterServer> glusterServers;
+ try {
+ glusterServers = getGlusterServers(onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterServers = getGlusterServers(onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+
+ // skip the servers by maxCount / previousServerName
+ glusterServers = GlusterCoreUtil.skipEntities(glusterServers, maxCount, previousServerName);
+
+ if (fetchDetails) {
+ String errMsg = fetchDetailsOfServers(Collections.synchronizedList(glusterServers));
+ if (!errMsg.isEmpty()) {
+ throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg);
+ }
+ }
+ return glusterServers;
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getGlusterServer(org.gluster.storage.management.core.model.GlusterServer, java.lang.String)
+ */
+ public GlusterServer getGlusterServer(String onlineServer, String serverName) {
+ List<GlusterServer> servers = getGlusterServers(onlineServer);
+ for (GlusterServer server : servers) {
+ if (server.getName().equalsIgnoreCase(serverName)) {
+ return server;
+ }
+ }
+
+ // Server not found. It's possible that the server name returned by glusterfs is actually IP address
+ // Hence fetch details of all servers and then compare the host names again.
+ String errMsg = fetchDetailsOfServers(Collections.synchronizedList(servers));
+ if (!errMsg.isEmpty()) {
+ throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg);
+ }
+ for (GlusterServer server : servers) {
+ if (server.getName().equalsIgnoreCase(serverName)) {
+ return server;
+ }
+ }
+
+ // still not found!
+ return null;
+ }
+
+ private String getUuid(String serverName) {
+ return serverUtil.executeOnServer(serverName, "cat " + GLUSTERD_INFO_FILE, String.class).split("=")[1];
+ }
+
+ /* (non-Javadoc)
+ * @see org.gluster.storage.management.gateway.utils.GlusterInterface#getGlusterServers(org.gluster.storage.management.core.model.GlusterServer)
+ */
+ public List<GlusterServer> getGlusterServers(String knownServerName) {
+ String output = getPeerStatus(knownServerName);
+
+ GlusterServer knownServer = new GlusterServer(knownServerName);
+ knownServer.setUuid(getUuid(knownServerName));
+
+ List<GlusterServer> glusterServers = new ArrayList<GlusterServer>();
+ glusterServers.add(knownServer);
+
+ GlusterServer server = null;
+ boolean foundHost = false;
+ boolean foundUuid = false;
+ for (String line : output.split(CoreConstants.NEWLINE)) {
+ if (foundHost && foundUuid) {
+ // Host and UUID is found, we should look for state
+ String state = StringUtil.extractToken(line, STATE_PFX);
+ if (state != null) {
+ server.setStatus(state.contains(GLUSTER_SERVER_STATUS_ONLINE) ? SERVER_STATUS.ONLINE
+ : SERVER_STATUS.OFFLINE);
+ // Completed populating current server. Add it to the list
+ // and reset all related variables.
+ glusterServers.add(server);
+
+ foundHost = false;
+ foundUuid = false;
+ server = null;
+ }
+ } else if (foundHost) {
+ // Host is found, look for UUID
+ String uuid = StringUtil.extractToken(line, UUID_PFX);
+ if (uuid != null) {
+ server.setUuid(uuid);
+ foundUuid = true;
+ }
+ } else {
+ // Look for the next host
+ if (server == null) {
+ server = new GlusterServer();
+ }
+ String hostName = StringUtil.extractToken(line, HOSTNAME_PFX);
+ if (hostName != null) {
+ server.setName(hostName);
+ foundHost = true;
+ }
+ }
+
+ }
+ return glusterServers;
+ }
+
+ /**
+ * @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) {
+ return serverUtil.executeOnServer(knownServer, "gluster peer status", String.class);
+ }
+
+ private String fetchDetailsOfServers(List<GlusterServer> glusterServers) {
+ try {
+ List<String> errors = Collections.synchronizedList(new ArrayList<String>());
+
+ List<Thread> threads = createThreads(glusterServers, errors);
+ ProcessUtil.waitForThreads(threads);
+
+ return prepareErrorMessage(errors);
+ } catch(InterruptedException e) {
+ String errMsg = "Exception while fetching details of servers! Error: [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ private String prepareErrorMessage(List<String> errors) {
+ String errMsg = "";
+ for(String error : errors) {
+ if(!errMsg.isEmpty()) {
+ errMsg += CoreConstants.NEWLINE;
+ }
+ errMsg += error;
+ }
+
+ return errMsg;
+ }
+
+ /**
+ * Creates threads that will run in parallel and fetch details of given gluster servers
+ * @param discoveredServers The list to be populated with details of gluster servers
+ * @param errors List to be populated with errors if any
+ * @return
+ * @throws InterruptedException
+ */
+ private List<Thread> createThreads(List<GlusterServer> glusterServers, List<String> errors)
+ throws InterruptedException {
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = glusterServers.size()-1; i >= 0 ; i--) {
+ Thread thread = new ServerDetailsThread(glusterServers.get(i), errors);
+ threads.add(thread);
+ thread.start();
+ if(i >= 5 && i % 5 == 0) {
+ // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
+ Thread.sleep(1000);
+ }
+ }
+ return threads;
+ }
+
+ public class ServerDetailsThread extends Thread {
+ private List<String> errors;
+ private GlusterServer server;
+ private final Logger logger = Logger.getLogger(ServerDetailsThread.class);
+
+ /**
+ * Private constructor called on each thread
+ * @param server The server whose details are to be fetched by this thread
+ * @param errors
+ */
+ private ServerDetailsThread(GlusterServer server, List<String> errors) {
+ this.errors = errors;
+ this.server = server;
+ }
+
+ @Override
+ public void run() {
+ try {
+ logger.info("fetching details of server [" + server.getName() + "] - start");
+ serverUtil.fetchServerDetails(server);
+ logger.info("fetching details of server [" + server.getName() + "] - end");
+ } catch (Exception e) {
+ logger.error("fetching details of server [" + server.getName() + "] - error", e);
+ errors.add(server.getName() + " : [" + e.getMessage() + "]");
+ }
+ }
+ }
+
+ public GlusterServer getGlusterServer(String clusterName, String serverName, Boolean fetchDetails) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ throw new GlusterValidationException("Server name must not be empty!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterRuntimeException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ return getGlusterServer(clusterName, serverName, onlineServer, fetchDetails);
+ }
+
+ private GlusterServer getGlusterServer(String clusterName, String serverName, GlusterServer onlineServer,
+ Boolean fetchDetails) {
+ GlusterServer server = null;
+ try {
+ server = getGlusterServer(onlineServer.getName(), serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ server = getGlusterServer(onlineServer.getName(), serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+
+ if (fetchDetails && server.isOnline()) {
+ serverUtil.fetchServerDetails(server);
+ }
+ return server;
+ }
+
+ public boolean isValidServer(String clusterName, String serverName) {
+ try {
+ GlusterServer server = getGlusterServer(clusterName, serverName, false);
+ return server != null;
+ } catch(Exception e) {
+ return false;
+ }
+ }
+
+ public void removeServerFromCluster(String clusterName, String serverName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ throw new GlusterValidationException("Server name must not be empty!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ List<ServerInfo> servers = cluster.getServers();
+ if (servers == null || servers.isEmpty() || !containsServer(servers, serverName)) {
+ throw new GlusterValidationException("Server [" + serverName + "] is not attached to cluster ["
+ + clusterName + "]!");
+ }
+
+ if (servers.size() == 1) {
+ // Only one server mapped to the cluster, no "peer detach" required.
+ // remove the cached online server for this cluster if present
+ clusterService.removeOnlineServer(clusterName);
+ } else {
+ // get an online server that is not same as the server being removed
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName, serverName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.removeServer(onlineServer.getName(), serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName, serverName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.removeServer(onlineServer.getName(), serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+
+ clusterService.unmapServerFromCluster(clusterName, serverName);
+
+ // since the server is removed from the cluster, it is now available to be added to other clusters.
+ // Hence add it back to the discovered servers list.
+ discoveredServerService.addDiscoveredServer(serverName);
+
+ try {
+ if (serverUtil.isServerOnline(new Server(serverName))) {
+ volumeService.clearCifsConfiguration(clusterName, onlineServer.getName(), serverName);
+ }
+ } catch (Exception e1) {
+ throw new GlusterRuntimeException(
+ "Server removed from cluster, however deleting cifs configuration failed ! [ "
+ + e1.getMessage() + "]");
+ }
+ if (onlineServer.getName().equals(serverName)) {
+ // since the cached server has been removed from the cluster, remove it from the cache
+ clusterService.removeOnlineServer(clusterName);
+ }
+ }
+ }
+
+ private boolean containsServer(List<ServerInfo> servers, String serverName) {
+ for (ServerInfo server : servers) {
+ if (server.getName().toUpperCase().equals(serverName.toUpperCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds given server to cluster and returns its host name. e.g. If serverName passed is an IP address, this method
+ * will return the host name of the machine with given IP address.
+ *
+ * @param clusterName
+ * @param serverName
+ * @return
+ */
+ public String addServerToCluster(String clusterName, String serverName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + FORM_PARAM_SERVER_NAME + "] is missing in request!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ boolean publicKeyInstalled = sshUtil.isPublicKeyInstalled(serverName);
+ if (!publicKeyInstalled && !sshUtil.hasDefaultPassword(serverName)) {
+ // public key not installed, default password doesn't work. return with error.
+ throw new GlusterRuntimeException("Gluster Management Gateway uses the default password to set up keys on the server."
+ + CoreConstants.NEWLINE + "However it seems that the password on server [" + serverName
+ + "] has been changed manually." + CoreConstants.NEWLINE
+ + "Please reset it back to the standard default password and try again.");
+ }
+
+ String hostName = serverUtil.fetchHostName(serverName);
+ List<ServerInfo> servers = cluster.getServers();
+ if (servers != null && !servers.isEmpty()) {
+ // cluster has at least one existing server, so that peer probe can be performed
+ performAddServer(clusterName, hostName);
+ } else {
+ // this is the first server to be added to the cluster, which means no
+ // gluster CLI operation required. just add it to the cluster-server mapping
+ }
+
+ // add the cluster-server mapping
+ clusterService.mapServerToCluster(clusterName, hostName);
+
+ // since the server is added to a cluster, it should not more be considered as a
+ // discovered server available to other clusters
+ discoveredServerService.removeDiscoveredServer(hostName);
+
+ if (!publicKeyInstalled) {
+ try {
+ // install public key (this will also disable password based ssh login)
+ sshUtil.installPublicKey(hostName);
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Public key could not be installed on [" + hostName + "]! Error: ["
+ + e.getMessage() + "]");
+ }
+ }
+ return hostName;
+ }
+
+ private void performAddServer(String clusterName, String serverName) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.addServer(onlineServer.getName(), serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online server found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.addServer(onlineServer.getName(), serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ public List<String> getFsTypes(String clusterName, String serverName) {
+ if (isValidServer(clusterName, serverName)) {
+ return serverUtil.getFsTypes(serverName);
+ } else {
+ throw new GlusterRuntimeException(serverName + " does not belong to the cluster [" + clusterName + "]");
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/VolumeService.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/VolumeService.java
new file mode 100644
index 00000000..4235d674
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/services/VolumeService.java
@@ -0,0 +1,984 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.services;
+
+import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICKS;
+import static org.gluster.storage.management.core.constants.RESTConstants.TASK_START;
+import static org.gluster.storage.management.core.constants.RESTConstants.TASK_STOP;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.exceptions.GlusterValidationException;
+import org.gluster.storage.management.core.model.Brick;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.Volume;
+import org.gluster.storage.management.core.model.VolumeLogMessage;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.model.Volume.NAS_PROTOCOL;
+import org.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import org.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import org.gluster.storage.management.core.response.LogMessageListResponse;
+import org.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+import org.gluster.storage.management.core.utils.DateUtil;
+import org.gluster.storage.management.core.utils.FileUtil;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.resources.v1_0.TasksResource;
+import org.gluster.storage.management.gateway.tasks.MigrateBrickTask;
+import org.gluster.storage.management.gateway.tasks.RebalanceVolumeTask;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class VolumeService {
+ private static final String ALL_SERVERS_FILE_NAME = "servers";
+ private static final String VOLUME_GET_CIFS_USERS_SCRIPT = "get_volume_user_cifs.py";
+ private static final String VOLUME_CIFS_GRUN_SCRIPT = "grun.py";
+ private static final String VOLUME_CREATE_CIFS_SCRIPT = "create_volume_cifs_all.py";
+ private static final String VOLUME_MODIFY_CIFS_SCRIPT = "update_volume_cifs_all.py";
+ private static final String VOLUME_START_CIFS_PEER_SCRIPT = "start_volume_cifs.py";
+ private static final String VOLUME_STOP_CIFS_PEER_SCRIPT = "stop_volume_cifs.py";
+ private static final String VOLUME_DELETE_CIFS_SCRIPT = "delete_volume_cifs_all.py";
+ private static final String VOLUME_BRICK_LOG_SCRIPT = "get_volume_brick_log.py";
+ private static final String VOLUME_DIRECTORY_CLEANUP_SCRIPT = "clear_volume_directory.py";
+ private static final String REMOVE_SERVER_VOLUME_CIFS_CONFIG = "remove_server_volume_cifs_config.py";
+ private static final String ALL_ONLINE_VOLUMES_FILE_NAME = "volumes";
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private GlusterInterfaceService glusterUtil;
+
+ @Autowired
+ private GlusterServerService glusterServerService;
+
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ // TODO: To be replaced with taskService
+ @Autowired
+ private TasksResource taskResource;
+
+ private static final Logger logger = Logger.getLogger(VolumeService.class);
+
+ public void addBricksToVolume(String clusterName, String volumeName, String bricks) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (bricks == null || bricks.isEmpty()) {
+ throw new GlusterValidationException("Bricks must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ List<String> brickList = Arrays.asList(bricks.split(","));
+ try {
+ glusterUtil.addBricks(volumeName, brickList, onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.addBricks(volumeName, brickList, onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ public Volume getVolume(String clusterName, String volumeName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ Volume volume;
+ try {
+ volume = glusterUtil.getVolume(volumeName, onlineServer.getName());
+ // Collect the CIFS users if CIFS Re-exported
+ fetchVolumeCifsUsers(clusterName, volume);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ volume = glusterUtil.getVolume(volumeName, onlineServer.getName());
+ // Collect the CIFS users if CIFS Re-exported
+ fetchVolumeCifsUsers(clusterName, volume);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ return volume;
+ }
+
+ public List<Volume> getVolumes(String clusterName, Integer maxCount, String previousVolumeName) {
+ List<Volume> volumes = getVolumes(clusterName);
+ // Skip the volumes by maxCount / previousServerName
+ volumes = GlusterCoreUtil.skipEntities(volumes, maxCount, previousVolumeName);
+ // fetch CIFS users of the volumes
+ fetchCifsUsers(clusterName, volumes);
+
+ return volumes;
+ }
+
+ private List<Volume> getVolumes(String clusterName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ if(cluster.getServers().size() == 0) {
+ // no server added yet. return an empty array.
+ return new ArrayList<Volume>();
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ return glusterUtil.getAllVolumes(onlineServer.getName());
+ } catch (Exception e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ return glusterUtil.getAllVolumes(onlineServer.getName());
+ }
+ }
+
+ private void fetchVolumeCifsUsers(String clusterName, Volume volume) {
+ List<String> users = new ArrayList<String>();
+ try {
+ ProcessResult result = serverUtil
+ .executeGlusterScript(true, VOLUME_GET_CIFS_USERS_SCRIPT, volume.getName());
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ String output = result.getOutput().trim();
+ if (output.isEmpty()) {
+ volume.disableCifs();
+ } else {
+ users = Arrays.asList(output.split(CoreConstants.NEWLINE));
+ volume.enableCifs();
+ volume.setCifsUsers(users);
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in fetching CIFS users [" + volume.getName() + "]: "
+ + e.getMessage());
+ }
+ return;
+ }
+
+ private void fetchCifsUsers(String clusterName, List<Volume> volumes) {
+ for (Volume volume: volumes) {
+ fetchVolumeCifsUsers(clusterName, volume);
+ }
+ }
+
+ private File createOnlineServerList(String clusterName) {
+ String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+ String clusterServersListFile = FileUtil.getTempDirName() + CoreConstants.FILE_SEPARATOR
+ + ALL_SERVERS_FILE_NAME + "_" + timestamp;
+
+ try {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ List<GlusterServer> glusterServers = glusterServerService.getGlusterServers(onlineServer.getName());
+ File serversFile = new File(clusterServersListFile);
+ FileOutputStream fos = new FileOutputStream(serversFile);
+ for (GlusterServer server : glusterServers) {
+ if (server.getStatus() == SERVER_STATUS.ONLINE) {
+ fos.write((server.getName() + CoreConstants.NEWLINE).getBytes());
+ }
+ }
+ fos.close();
+ return serversFile;
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in preparing server list: [" + e.getMessage() + "]");
+ }
+ }
+
+ public void startCifsReExport(String clusterName, String volumeName) {
+ try {
+ File file = createOnlineServerList(clusterName);
+ ProcessResult result = serverUtil.executeGlusterScript(true, VOLUME_CIFS_GRUN_SCRIPT,
+ file.getAbsolutePath(), VOLUME_START_CIFS_PEER_SCRIPT, volumeName);
+ file.delete();
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in starting CIFS services for volume [" + volumeName + "]: "
+ + e.getMessage());
+ }
+ }
+
+ public void stopCifsReExport(String clusterName, String volumeName) {
+ try {
+ File file = createOnlineServerList(clusterName);
+ ProcessResult result = serverUtil.executeGlusterScript(true, VOLUME_CIFS_GRUN_SCRIPT,
+ file.getAbsolutePath(), VOLUME_STOP_CIFS_PEER_SCRIPT, volumeName);
+ file.delete();
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in stoping CIFS services for volume [" + volumeName + "]: "
+ + e.getMessage());
+ }
+ }
+
+ public void deleteCifsUsers(String clusterName, String volumeName) {
+ try {
+ File file = createOnlineServerList(clusterName);
+ ProcessResult result = serverUtil.executeGlusterScript(true, VOLUME_DELETE_CIFS_SCRIPT,
+ file.getAbsolutePath(), volumeName);
+ file.delete();
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in deleting CIFS configuration [" + volumeName + "]: "
+ + e.getMessage());
+ }
+ }
+
+ public void createCIFSUsers(String clusterName, String volumeName, String cifsUsers) {
+ try {
+ File file = createOnlineServerList(clusterName);
+ List<String> arguments = new ArrayList<String>();
+ arguments.add(file.getAbsolutePath());
+ arguments.add(volumeName);
+ arguments.addAll( Arrays.asList(cifsUsers.replaceAll(" ", "").split(",")));
+ ProcessResult result = serverUtil.executeGlusterScript(true, VOLUME_CREATE_CIFS_SCRIPT, arguments);
+ file.delete();
+ Volume volume = getVolume(clusterName, volumeName);
+ // If the volume service is already in running, create user may start CIFS re-export automatically.
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ startCifsReExport(clusterName, volumeName);
+ }
+ /*
+ * else { stopCifsReExport(clusterName, volumeName); }
+ */
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in creating CIFS configuration [" + volumeName + "]: "
+ + e.getMessage());
+ }
+ }
+
+ @Deprecated
+ public void modifyCIFSUsers(String clusterName, String volumeName, String cifsUsers) {
+ try {
+ File file = createOnlineServerList(clusterName);
+ List<String> arguments = new ArrayList<String>();
+ arguments.add(file.getAbsolutePath());
+ arguments.add(volumeName);
+ arguments.addAll( Arrays.asList(cifsUsers.split(",")));
+ ProcessResult result = serverUtil.executeGlusterScript(true, VOLUME_MODIFY_CIFS_SCRIPT, arguments);
+ file.delete();
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in updating CIFS configuration [" + volumeName + "]: "
+ + e.getMessage());
+ }
+ }
+
+ // To clear all the volume CIFS configurations from the server
+ public void clearCifsConfiguration(String clusterName, String onlineServerName, String serverName) {
+ File volumesFile = createOnlineVolumeList(clusterName, onlineServerName);
+ if (volumesFile == null) {
+ return;
+ }
+ try {
+ removeServerVolumeCifsConfig(serverName, volumesFile.getAbsolutePath());
+ volumesFile.delete();
+ } catch(Exception e) {
+ volumesFile.delete();
+ throw new GlusterRuntimeException("Error in clearing volume CIFS configuration: [" + e.getMessage() + "]");
+ }
+ }
+
+ private File createOnlineVolumeList(String clusterName, String onlineServerName) {
+ String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+ String volumeListFileName = FileUtil.getTempDirName() + CoreConstants.FILE_SEPARATOR
+ + ALL_ONLINE_VOLUMES_FILE_NAME + "_" + timestamp;
+ try {
+ List<Volume> volumes = getVolumes(clusterName);
+ if (volumes == null || volumes.size() == 0) {
+ return null;
+ }
+ File volumesFile = new File(volumeListFileName);
+ FileOutputStream fos = new FileOutputStream(volumesFile);
+ for (Volume volume : volumes) {
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ fos.write((volume.getName() + CoreConstants.NEWLINE).getBytes());
+ }
+ }
+ fos.close();
+ return volumesFile;
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Error in preparing volume list: [" + e.getMessage() + "]");
+ }
+ }
+
+
+ public void removeServerVolumeCifsConfig(String serverName, String volumesFileName) {
+ ProcessResult result = serverUtil.executeGlusterScript(true, REMOVE_SERVER_VOLUME_CIFS_CONFIG, serverName,
+ volumesFileName);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException(result.toString());
+ }
+ }
+
+ public void createVolume(String clusterName, String volumeName, String volumeType, String transportType,
+ Integer count, String bricks, String accessProtocols, String options,
+ String cifsUsers) {
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ if ((volumeType.equals(VOLUME_TYPE.REPLICATE.toString()) || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_REPLICATE
+ .toString())) && count <= 0) {
+ throw new GlusterValidationException("Replica count must be a positive integer");
+ }
+
+ if ((volumeType.equals(VOLUME_TYPE.STRIPE.toString()) || volumeType.equals(VOLUME_TYPE.DISTRIBUTED_STRIPE
+ .toString())) && count <= 0) {
+ throw new GlusterValidationException("Stripe count must be a positive integer");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.createVolume(onlineServer.getName(), volumeName, volumeType, transportType, count,
+ bricks, accessProtocols, options);
+
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.createVolume(onlineServer.getName(), volumeName, volumeType, transportType, count,
+ bricks, accessProtocols, options);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+
+ List<String> nasProtocols = Arrays.asList(accessProtocols.split(","));
+ // if cifs enabled
+ if (nasProtocols.contains(NAS_PROTOCOL.CIFS.toString())) {
+ try {
+ createCIFSUsers(clusterName, volumeName, cifsUsers);
+ } catch (Exception e) {
+ throw new GlusterRuntimeException(CoreConstants.NEWLINE + e.getMessage());
+ }
+ }
+ }
+
+ public String downloadLogs(Volume volume) {
+ // create temporary directory
+ File tempDir = FileUtil.createTempDir();
+ String tempDirPath = tempDir.getPath();
+
+ for (Brick brick : volume.getBricks()) {
+ String logDir = glusterUtil.getLogLocation(volume.getName(), brick.getQualifiedName(),
+ brick.getServerName());
+ String logFileName = glusterUtil.getLogFileNameForBrickDir(brick.getServerName(), brick.getBrickDirectory());
+ String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName;
+
+ serverUtil.getFileFromServer(brick.getServerName(), logFilePath, tempDirPath);
+
+ String fetchedLogFile = tempDirPath + File.separator + logFileName;
+ // append log file name with server name so that log files don't overwrite each other
+ // in cases where the brick log file names are same on multiple servers
+ String localLogFile = tempDirPath + File.separator + brick.getServerName() + "-" + logFileName;
+
+ FileUtil.renameFile(fetchedLogFile, localLogFile);
+ }
+
+ String gzipPath = FileUtil.getTempDirName() + CoreConstants.FILE_SEPARATOR + volume.getName() + "-logs.tar.gz";
+ ProcessUtil.executeCommand("tar", "czvf", gzipPath, "-C", tempDir.getParent(), tempDir.getName());
+
+ // delete the temp directory
+ FileUtil.recursiveDelete(tempDir);
+
+ return gzipPath;
+ }
+
+ public List<VolumeLogMessage> getLogs(String clusterName, String volumeName, String brickName, String severity,
+ String fromTimestamp, String toTimestamp, Integer lineCount) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ if (lineCount == null || lineCount == 0) {
+ lineCount = 100;
+ }
+
+ List<VolumeLogMessage> logMessages = null;
+ Volume volume = getVolume(clusterName, volumeName);
+
+ if (brickName == null || brickName.isEmpty() || brickName.equals(CoreConstants.ALL)) {
+ logMessages = getLogsForAllBricks(volume, lineCount);
+ } else {
+ // fetch logs for given brick of the volume
+ for (Brick brick : volume.getBricks()) {
+ if (brick.getQualifiedName().equals(brickName)) {
+ logMessages = getBrickLogs(volume, brick, lineCount);
+ break;
+ }
+ }
+ }
+
+ filterLogsBySeverity(logMessages, severity);
+ filterLogsByTime(logMessages, fromTimestamp, toTimestamp);
+ return logMessages;
+ }
+
+ private void filterLogsByTime(List<VolumeLogMessage> logMessages, String fromTimestamp, String toTimestamp) {
+ Date fromTime = null, toTime = null;
+
+ if (fromTimestamp != null && !fromTimestamp.isEmpty()) {
+ fromTime = DateUtil.stringToDate(fromTimestamp);
+ }
+
+ if (toTimestamp != null && !toTimestamp.isEmpty()) {
+ toTime = DateUtil.stringToDate(toTimestamp);
+ }
+
+ List<VolumeLogMessage> messagesToRemove = new ArrayList<VolumeLogMessage>();
+ for (VolumeLogMessage logMessage : logMessages) {
+ Date logTimestamp = logMessage.getTimestamp();
+ if (fromTime != null && logTimestamp.before(fromTime)) {
+ messagesToRemove.add(logMessage);
+ continue;
+ }
+
+ if (toTime != null && logTimestamp.after(toTime)) {
+ messagesToRemove.add(logMessage);
+ }
+ }
+ logMessages.removeAll(messagesToRemove);
+ }
+
+ private void filterLogsBySeverity(List<VolumeLogMessage> logMessages, String severity) {
+ if (severity == null || severity.isEmpty()) {
+ return;
+ }
+
+ List<VolumeLogMessage> messagesToRemove = new ArrayList<VolumeLogMessage>();
+ for (VolumeLogMessage logMessage : logMessages) {
+ if (!logMessage.getSeverity().equals(severity)) {
+ messagesToRemove.add(logMessage);
+ }
+ }
+ logMessages.removeAll(messagesToRemove);
+ }
+
+ private List<VolumeLogMessage> getLogsForAllBricks(Volume volume, Integer lineCount) {
+ List<VolumeLogMessage> logMessages;
+ logMessages = new ArrayList<VolumeLogMessage>();
+ // fetch logs for every brick of the volume
+ for (Brick brick : volume.getBricks()) {
+ logMessages.addAll(getBrickLogs(volume, brick, lineCount));
+ }
+
+ // Sort the log messages based on log timestamp
+ Collections.sort(logMessages, new Comparator<VolumeLogMessage>() {
+ @Override
+ public int compare(VolumeLogMessage message1, VolumeLogMessage message2) {
+ return message1.getTimestamp().compareTo(message2.getTimestamp());
+ }
+ });
+
+ return logMessages;
+ }
+
+ private List<VolumeLogMessage> getBrickLogs(Volume volume, Brick brick, Integer lineCount)
+ throws GlusterRuntimeException {
+ String logDir = glusterUtil.getLogLocation(volume.getName(), brick.getQualifiedName(), brick.getServerName());
+ String logFileName = glusterUtil.getLogFileNameForBrickDir(brick.getServerName(), brick.getBrickDirectory());
+ String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName;
+
+ // Usage: get_volume_disk_log.py <volumeName> <diskName> <lineCount>
+ LogMessageListResponse response = serverUtil.executeScriptOnServer(brick.getServerName(),
+ VOLUME_BRICK_LOG_SCRIPT + " " + logFilePath + " " + lineCount, LogMessageListResponse.class);
+
+ // populate disk and trim other fields
+ List<VolumeLogMessage> logMessages = response.getLogMessages();
+ for (VolumeLogMessage logMessage : logMessages) {
+ logMessage.setBrick(brick.getQualifiedName());
+ }
+ return logMessages;
+ }
+
+ public String migrateBrickStart(String clusterName, String volumeName, String fromBrick, String toBrick,
+ Boolean autoCommit) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if (fromBrick == null || fromBrick.isEmpty()) {
+ throw new GlusterValidationException("From brick must not be empty!");
+ }
+
+ if (toBrick == null || toBrick.isEmpty()) {
+ throw new GlusterValidationException("To brick must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ if(autoCommit == null) {
+ autoCommit = false;
+ }
+
+ MigrateBrickTask migrateDiskTask = new MigrateBrickTask(clusterService, clusterName, volumeName, fromBrick,
+ toBrick);
+ migrateDiskTask.setAutoCommit(autoCommit);
+ migrateDiskTask.start();
+ taskResource.addTask(clusterName, migrateDiskTask);
+ return migrateDiskTask.getTaskInfo().getName(); // Return Task ID
+ }
+
+ private String getLayout(Boolean isFixLayout, Boolean isMigrateData,
+ Boolean isForcedDataMigrate) {
+ String layout = "";
+ if (isForcedDataMigrate) {
+ layout = "forced-data-migrate";
+ } else if (isMigrateData) {
+ layout = "migrate-data";
+ } else if (isFixLayout) {
+ layout = "fix-layout";
+ }
+ return layout;
+ }
+
+ public String rebalanceStart(String clusterName, String volumeName, Boolean isFixLayout, Boolean isMigrateData,
+ Boolean isForcedDataMigrate) {
+ RebalanceVolumeTask rebalanceTask = new RebalanceVolumeTask(clusterService, clusterName, volumeName, getLayout(
+ isFixLayout, isMigrateData, isForcedDataMigrate));
+ rebalanceTask.start();
+ taskResource.addTask(clusterName, rebalanceTask);
+ return rebalanceTask.getId();
+ }
+
+ public void rebalanceStop(String clusterName, String volumeName) {
+ // TODO: arrive at the task id and fetch it
+ String taskId = "";
+
+ taskResource.getTask(clusterName, taskId).stop();
+ }
+
+ public void startVolume(String clusterName, GlusterServer onlineServer, Volume volume, Boolean force) {
+ glusterUtil.startVolume(volume.getName(), onlineServer.getName(), force);
+
+ // call the start_volume_cifs.py script only if the volume is cifs enabled
+ if (volume.isCifsEnable()) {
+ startCifsReExport(clusterName, volume.getName());
+ }
+ }
+
+ public void stopVolume(String clusterName, GlusterServer onlineServer, Volume volume, Boolean force) {
+ glusterUtil.stopVolume(volume.getName(), onlineServer.getName(), force);
+
+ // call the stop_volume_cifs.py script only if the volume is cifs enabled
+ if (volume.isCifsEnable()) {
+ stopCifsReExport(clusterName, volume.getName());
+ }
+ }
+
+ public void logRotate(String clusterName, String volumeName, List<String> brickList) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ try {
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ glusterUtil.logRotate(volumeName, brickList, onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ glusterUtil.logRotate(volumeName, brickList, onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException("Volume [" + volumeName + "] log rotation failed!", e);
+ }
+ }
+ }
+
+ public void performVolumeOperation(String clusterName, String volumeName, String operation, Boolean force) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ try {
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ performOperation(clusterName, volumeName, operation, onlineServer, force);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ performOperation(clusterName, volumeName, operation, onlineServer, force);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void performOperation(String clusterName, String volumeName, String operation, GlusterServer onlineServer,
+ Boolean force) {
+ Volume volume = null;
+ try {
+ volume = getVolume(clusterName, volumeName);
+ } catch (Exception e) {
+ throw new GlusterRuntimeException("Could not fetch volume info for volume [" + volumeName + "]"
+ + e.getMessage());
+ }
+
+ if (operation.equals(TASK_START)) {
+ startVolume(clusterName, onlineServer, volume, force);
+ } else if (operation.equals(TASK_STOP)) {
+ stopVolume(clusterName, onlineServer, volume, force);
+ } else {
+ throw new GlusterValidationException("Invalid operation code [" + operation + "]");
+ }
+ }
+
+ public void removeBricksFromVolume(String clusterName, String volumeName, String bricks, Boolean deleteFlag) {
+ // Convert from comma separated string (query parameter)
+ List<String> brickList = Arrays.asList(bricks.split(","));
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if (bricks == null || bricks.isEmpty()) {
+ throw new GlusterValidationException("Parameter [" + QUERY_PARAM_BRICKS + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ if(deleteFlag == null) {
+ deleteFlag = false;
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ removeBricks(clusterName, volumeName, brickList, onlineServer);
+ cleanupDirectories(brickList, volumeName, brickList.size(), deleteFlag);
+ }
+
+ private void removeBricks(String clusterName, String volumeName, List<String> brickList, GlusterServer onlineServer) {
+ try {
+ glusterUtil.removeBricks(volumeName, brickList, onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.removeBricks(volumeName, brickList, onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void cleanupDirectories(List<String> bricks, String volumeName, int maxIndex, boolean deleteFlag) {
+ String errors = "";
+ for (int i = 0; i < maxIndex; i++) {
+ String[] brickInfo = bricks.get(i).split(":");
+ String serverName = brickInfo[0];
+ String brickDirectory = brickInfo[1];
+
+ try {
+ serverUtil.executeScriptOnServer(serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " "
+ + brickDirectory + " " + (deleteFlag ? "-d" : ""));
+ } catch(Exception e) {
+ logger.error("Error while cleaning brick [" + serverName + ":" + brickDirectory + "] of volume ["
+ + volumeName + "] : " + e.getMessage(), e);
+ errors += "[" + brickDirectory + "] => " + e.getMessage() + CoreConstants.NEWLINE;
+ }
+ }
+ if(!errors.trim().isEmpty()) {
+ throw new GlusterRuntimeException("Volume directory cleanup errors: " + errors.trim());
+ }
+ }
+
+ public void deleteVolume(String clusterName, String volumeName, Boolean deleteFlag) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if(onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ if (deleteFlag == null) {
+ deleteFlag = false;
+ }
+
+ Volume volume = getVolume(clusterName, volumeName);
+
+ List<Brick> bricks = volume.getBricks();
+ glusterUtil.deleteVolume(volumeName, onlineServer.getName());
+
+ try {
+ postDelete(volumeName, bricks, deleteFlag);
+ if (volume.isCifsEnable()) {
+ if (volume.getStatus() == VOLUME_STATUS.ONLINE) {
+ stopCifsReExport(clusterName, volumeName);
+ }
+ deleteCifsUsers(clusterName, volumeName);
+ }
+ } catch(Exception e) {
+ throw new GlusterRuntimeException("Volume [" + volumeName
+ + "] deleted from cluster, however following error(s) occurred: " + CoreConstants.NEWLINE
+ + e.getMessage());
+ }
+ }
+
+ private void postDelete(String volumeName, List<Brick> bricks, boolean deleteFlag) {
+ for (Brick brick : bricks) {
+ String brickDirectory = brick.getBrickDirectory();
+ // String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/"));
+
+ serverUtil.executeScriptOnServer(brick.getServerName(), VOLUME_DIRECTORY_CLEANUP_SCRIPT + " "
+ + brickDirectory + " " + (deleteFlag ? "-d" : ""));
+ }
+ }
+
+ public void resetVolumeOptions(String clusterName, String volumeName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if(volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.resetOptions(volumeName, onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ glusterUtil.resetOptions(volumeName, onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+
+ }
+ }
+
+ public void setVolumeOption(String clusterName, String volumeName, String key, String value) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ if(volumeName == null || volumeName.isEmpty()) {
+ throw new GlusterValidationException("Volume name must not be empty!");
+ }
+
+ if(key == null || key.isEmpty()) {
+ throw new GlusterValidationException("Option key must not be empty!");
+ }
+
+ if(value == null || value.isEmpty()) {
+ throw new GlusterValidationException("Option value must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ throw new GlusterRuntimeException("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.setOption(volumeName, key, value, onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+ glusterUtil.setOption(volumeName, key, value, onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ public VolumeOptionInfoListResponse getVolumeOptionsInfo(String clusterName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ throw new GlusterValidationException("Cluster name must not be empty!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] not found!");
+ }
+
+ if(cluster.getServers().isEmpty()) {
+ throw new GlusterValidationException("Cluster [" + clusterName + "] is empty! Can't fetch Volume Options Information!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ return glusterUtil.getVolumeOptionsInfo(onlineServer.getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(onlineServer) == false) {
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ return glusterUtil.getVolumeOptionsInfo(onlineServer.getName());
+ } else {
+ throw new GlusterRuntimeException("Fetching volume options info failed! [" + e.getMessage() + "]");
+ }
+ }
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java
new file mode 100644
index 00000000..3193d926
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitServerTask.java
@@ -0,0 +1,161 @@
+/**
+ * GlusterServerInitializer.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+
+import org.apache.derby.tools.ij;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.PersistenceDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.RowCallbackHandler;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+import org.springframework.security.authentication.dao.SaltSource;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+
+/**
+ * Initializes the Gluster Management Server.
+ */
+public class InitServerTask extends JdbcDaoSupport {
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private SaltSource saltSource;
+
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ private String appVersion;
+
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ @Autowired
+ ServletContext servletContext;
+
+ private static final String SCRIPT_DIR = "data/scripts/";
+
+ public void securePasswords() {
+ getJdbcTemplate().query("select username, password from users", new RowCallbackHandler() {
+ @Override
+ public void processRow(ResultSet rs) throws SQLException {
+ String username = rs.getString(1);
+ String password = rs.getString(2);
+ UserDetails user = userDetailsService.loadUserByUsername(username);
+
+ String encodedPassword = passwordEncoder.encodePassword(password, saltSource.getSalt(user));
+ getJdbcTemplate().update("update users set password = ? where username = ?", encodedPassword, username);
+ logger.debug("Updating password for username: " + username);
+ }
+ });
+ }
+
+ private void executeScript(File script) {
+ ByteArrayOutputStream sqlOut = new ByteArrayOutputStream();
+ int numOfExceptions;
+ try {
+ numOfExceptions = ij.runScript(getJdbcTemplate().getDataSource().getConnection(), new FileInputStream(
+ script), CoreConstants.ENCODING_UTF8, sqlOut, CoreConstants.ENCODING_UTF8);
+ String output = sqlOut.toString();
+ sqlOut.close();
+ logger.debug("Data script [" + script.getName() + "] returned with exit status [" + numOfExceptions
+ + "] and output [" + output + "]");
+ if (numOfExceptions != 0) {
+ throw new GlusterRuntimeException("Server data initialization script [ " + script.getName()
+ + "] failed with [" + numOfExceptions + "] exceptions! [" + output + "]");
+ }
+ } catch (Exception ex) {
+ throw new GlusterRuntimeException("Server data initialization script [" + script.getName() + "] failed!",
+ ex);
+ }
+ }
+
+ private void initDatabase() {
+ logger.info("Initializing server data...");
+ executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + appVersion));
+
+ securePasswords(); // encrypt the passwords
+ }
+
+ private File getDirFromRelativePath(String relativePath) {
+ String scriptDirPath = servletContext.getRealPath(relativePath);
+ File scriptDir = new File(scriptDirPath);
+ return scriptDir;
+ }
+
+ private void executeScriptsFrom(File scriptDir) {
+ if (!scriptDir.exists()) {
+ throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] doesn't exist!");
+ }
+
+ List<File> scripts = Arrays.asList(scriptDir.listFiles());
+ if(scripts.size() == 0) {
+ throw new GlusterRuntimeException("Script directory [" + scriptDir.getAbsolutePath() + "] is empty!");
+ }
+
+ Collections.sort(scripts);
+ for (File script : scripts) {
+ executeScript(script);
+ }
+ }
+
+ /**
+ * Initializes the server database, if running for the first time.
+ */
+ public synchronized void initServer() {
+ try {
+ String dbVersion = getDBVersion();
+ if (!appVersion.equals(dbVersion)) {
+ logger.info("App version [" + appVersion + "] differs from data version [" + dbVersion
+ + "]. Trying to upgrade data...");
+ upgradeData(dbVersion, appVersion);
+ }
+ } catch (Exception ex) {
+ logger.info("No cluster created yet. DB version query failed with error [" + ex.getMessage() + "]", ex);
+ // Database not created yet. Create it!
+ initDatabase();
+ }
+ }
+
+ private void upgradeData(String fromVersion, String toVersion) {
+ executeScriptsFrom(getDirFromRelativePath(SCRIPT_DIR + fromVersion + "-" + toVersion));
+ }
+
+ private String getDBVersion() {
+ return (String) clusterDao.getSingleResultFromSQL("select version from version");
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
new file mode 100644
index 00000000..45be980a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
@@ -0,0 +1,198 @@
+/**
+ * InitializeDiskTask.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.model.InitDiskStatusResponse;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.InitDiskStatusResponse.FORMAT_STATUS;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class InitializeDiskTask extends Task {
+
+ private static final String INITIALIZE_DISK_SCRIPT = "format_device.py";
+ private static final String INITIALIZE_DISK_STATUS_SCRIPT = "get_format_device_status.py";
+
+ private String serverName;
+ private String diskName;
+ private String fsType;
+ private String mountPoint;
+ private ServerUtil serverUtil;
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, String serverName, String diskName,
+ String fsType, String mountPoint) {
+ // Reference contains "Server:disk"
+ super(clusterService, clusterName, TASK_TYPE.DISK_FORMAT, serverName + ":" + diskName, "Initialize disk "
+ + serverName + ":" + diskName, false, false, false);
+
+ setServerName(serverName);
+ setDiskName(diskName);
+ setFsType(fsType);
+ setMountpoint(mountPoint);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, TaskInfo info) {
+ super(clusterService, clusterName, info);
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ serverUtil = ctx.getBean(ServerUtil.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(
+ Base64.encode(getClusterName() + "-" + taskInfo.getType() + "-" + serverName + ":" + diskName));
+ }
+
+ @Override
+ public void resume() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void stop() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void pause() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Stop/Pause/Resume is not supported in Disk Initialization")));
+ }
+
+ @Override
+ public void commit() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public TASK_TYPE getType() {
+ return TASK_TYPE.DISK_FORMAT;
+ }
+
+
+ @Override
+ public void start() {
+ try {
+ startInitializeDisk(serverName);
+ } catch(ConnectionException e) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ }
+ }
+
+ private void startInitializeDisk(String serverName) {
+ String output = serverUtil.executeScriptOnServer(serverName, INITIALIZE_DISK_SCRIPT + " " + getFsType() + " \""
+ + getMountpoint() + "\" " + getDiskName() );
+ TaskStatus taskStatus = new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, output));
+ taskStatus.setPercentageSupported((getFsType().equals(GlusterConstants.FSTYPE_XFS)) ? false : true);
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+
+ try {
+ return getInitializingDeviceStatus(serverName, getDiskName());
+ } catch(ConnectionException e) {
+ // online server might have gone offline. update the failure status
+ return new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage()));
+ }
+ }
+
+ private TaskStatus getInitializingDeviceStatus(String serverName, String diskName) {
+ InitDiskStatusResponse initDiskStatusResponse;
+ TaskStatus taskStatus = new TaskStatus();
+
+ try {
+ initDiskStatusResponse = serverUtil.executeScriptOnServer(serverName, INITIALIZE_DISK_STATUS_SCRIPT + " "
+ + diskName, InitDiskStatusResponse.class);
+ } catch(RuntimeException e) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ taskStatus.setMessage(e.getMessage());
+ throw e;
+ }
+
+ if (initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.COMPLETED) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ } else if (initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.IN_PROGRESS) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ taskStatus.setPercentCompleted(Math.round(initDiskStatusResponse.getCompletedBlocks()
+ / initDiskStatusResponse.getTotalBlocks() * 100));
+ } else if(initDiskStatusResponse.getFormatStatus() == FORMAT_STATUS.NOT_RUNNING) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+
+ taskStatus.setMessage(initDiskStatusResponse.getMessage());
+ return taskStatus;
+ }
+
+ public void setDiskName(String diskName) {
+ this.diskName = diskName;
+ }
+
+ public String getDiskName() {
+ return diskName;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public void setFsType(String fsType) {
+ this.fsType = fsType;
+ }
+
+ public String getFsType() {
+ return fsType;
+ }
+
+ public void setMountpoint(String deviceMountPoint) {
+ this.mountPoint = deviceMountPoint;
+ }
+
+ public String getMountpoint() {
+ return mountPoint;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
new file mode 100644
index 00000000..8a31f9a9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
@@ -0,0 +1,220 @@
+/**
+ * MigrateDiskTask.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.GlusterInterfaceService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class MigrateBrickTask extends Task {
+
+ private String fromBrick;
+ private String toBrick;
+ private Boolean autoCommit;
+ private GlusterInterfaceService glusterInterface;
+ protected ServerUtil serverUtil;
+
+ public String getFromBrick() {
+ return fromBrick;
+ }
+
+ public void setFromBrick(String fromBrick) {
+ this.fromBrick = fromBrick;
+ }
+
+ public String getToBrick() {
+ return toBrick;
+ }
+
+ public void setToBrick(String toBrick) {
+ this.toBrick = toBrick;
+ }
+
+ public Boolean getAutoCommit() {
+ return autoCommit;
+ }
+
+ public void setAutoCommit(Boolean autoCommit) {
+ this.autoCommit = autoCommit;
+ }
+
+ public MigrateBrickTask(ClusterService clusterService, String clusterName, String volumeName, String fromBrick,
+ String toBrick) {
+ super(clusterService, clusterName, TASK_TYPE.BRICK_MIGRATE, volumeName + "#" + fromBrick + "#" + toBrick,
+ "Brick Migration on volume [" + volumeName + "] from [" + fromBrick + "] to [" + toBrick + "]", true,
+ true, true);
+ setFromBrick(fromBrick);
+ setToBrick(toBrick);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ glusterInterface = ctx.getBean(GlusterInterfaceService.class);
+ serverUtil = ctx.getBean(ServerUtil.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(Base64.encode(clusterName + "-" + taskInfo.getType() + "-" + taskInfo.getReference() + "-" + fromBrick + "-"
+ + toBrick));
+ }
+
+ @Override
+ public void start() {
+ try {
+ startMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone Offline. try with a new one.
+ startMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void startMigration(String onlineServerName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.startBrickMigration(onlineServerName, volumeName, getFromBrick(), getToBrick());
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, "Brick Migration Started.")));
+ }
+
+ @Override
+ public void pause() {
+ try {
+ pauseMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ pauseMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void pauseMigration(String onlineServer) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.pauseBrickMigration(onlineServer, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_PAUSE);
+ taskStatus.setMessage("Brick Migration Paused");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public void resume() {
+ start();
+ }
+
+ @Override
+ public void commit() {
+ try {
+ commitMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ commitMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void commitMigration(String serverName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.commitBrickMigration(serverName, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage("Brick Migration Committed.");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public void stop() {
+ try {
+ stopMigration(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ stopMigration(getNewOnlineServer().getName());
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void stopMigration(String serverName) {
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ glusterInterface.stopBrickMigration(serverName, volumeName, getFromBrick(), getToBrick());
+ TaskStatus taskStatus = new TaskStatus();
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage("Brick Migration Stopped");
+ getTaskInfo().setStatus(taskStatus);
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+ try {
+ return checkMigrationStatus(getOnlineServer().getName());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one.
+ return checkMigrationStatus(getNewOnlineServer().getName());
+ }
+ }
+ return null;
+ }
+
+ private TaskStatus checkMigrationStatus(String serverName) {
+ // For committed task, status command (CLI) is invalid, just return current status
+ if (taskInfo.getStatus().getCode() == Status.STATUS_CODE_SUCCESS) {
+ return taskInfo.getStatus();
+ }
+
+ String volumeName = getTaskInfo().getReference().split("#")[0];
+ TaskStatus taskStatus = glusterInterface.checkBrickMigrationStatus(serverName, volumeName, getFromBrick(),
+ getToBrick());
+ if (autoCommit && taskStatus.isCommitPending()) {
+ commitMigration(serverName);
+ return taskInfo.getStatus(); // return the committed status
+ }
+
+ taskInfo.setStatus(taskStatus); // Update the task status
+ return taskStatus;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
new file mode 100644
index 00000000..288179e9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
@@ -0,0 +1,141 @@
+/**
+ * RebalanceVolumeTask.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.GlusterInterfaceService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.sun.jersey.core.util.Base64;
+
+public class RebalanceVolumeTask extends Task {
+
+ private String layout;
+ private String serverName;
+ private ServerUtil serverUtil;
+ private GlusterInterfaceService glusterUtil;
+
+ public RebalanceVolumeTask(ClusterService clusterService, String clusterName, String volumeName, String layout) {
+ super(clusterService, clusterName, TASK_TYPE.VOLUME_REBALANCE, volumeName, "Volume " + volumeName
+ + " Rebalance", false, true, false);
+ setLayout(layout);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ serverUtil = ctx.getBean(ServerUtil.class);
+ glusterUtil = ctx.getBean(GlusterInterfaceService.class);
+ }
+
+ @Override
+ public String getId() {
+ return new String(Base64.encode(getClusterName() + "-" + taskInfo.getType() + "-" + taskInfo.getReference()));
+ }
+
+ @Override
+ public void start() {
+ try {
+ serverName = getOnlineServer().getName();
+ startRebalance(serverName);
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. try with a new one
+ serverName = getNewOnlineServer().getName();
+ startRebalance(serverName);
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ private void startRebalance(String serverName) {
+ String command = "gluster volume rebalance " + getTaskInfo().getReference() + " " + getLayout() + " start";
+ String output = serverUtil.executeOnServer(serverName, command);
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, output)));
+ }
+
+ @Override
+ public void resume() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Pause/Resume is not supported in Volume Rebalance")));
+ }
+
+ @Override
+ public void stop() {
+ try {
+ glusterUtil.stopRebalance(serverName, getTaskInfo().getReference());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ } else {
+ throw new GlusterRuntimeException(e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void pause() {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_FAILURE,
+ "Pause/Resume is not supported in Volume Rebalance")));
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+ try {
+ return glusterUtil.checkRebalanceStatus(serverName, getTaskInfo().getReference());
+ } catch (Exception e) {
+ // check if online server has gone offline. If yes, try again one more time.
+ if (e instanceof ConnectionException || serverUtil.isServerOnline(getOnlineServer()) == false) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, e.getMessage())));
+ return getTaskInfo().getStatus();
+ }
+ }
+ return null;
+ }
+
+ public void setLayout(String layout) {
+ this.layout = layout;
+ }
+
+ public String getLayout() {
+ return layout;
+ }
+
+ @Override
+ public void commit() {
+ // TODO Auto-generated method stub
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java
new file mode 100644
index 00000000..c3073d97
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/ServerSyncTask.java
@@ -0,0 +1,168 @@
+/**
+ * ServerDiscoveryTask.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.constants.GlusterConstants;
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.utils.GlusterCoreUtil;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.gluster.storage.management.gateway.data.ClusterInfo;
+import org.gluster.storage.management.gateway.data.PersistenceDao;
+import org.gluster.storage.management.gateway.data.ServerInfo;
+import org.gluster.storage.management.gateway.services.ClusterService;
+import org.gluster.storage.management.gateway.services.DiscoveredServerService;
+import org.gluster.storage.management.gateway.services.GlusterServerService;
+import org.gluster.storage.management.gateway.utils.ServerUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * Task for syncing server details. This performs two things: <br>
+ * 1. Auto-discovery of servers eligible to be added to the Gluster cluster. <br>
+ * 2. Syncing of cluster-server mapping with actual servers of the cluster. This mapping can go out of sync if user
+ * adds/removes servers manually using the CLI.
+ */
+@Component
+public class ServerSyncTask {
+ private static final String SCRIPT_NAME_SFX = "-discover-servers.py";
+
+ @Autowired
+ private ServerUtil serverUtil;
+
+ @Autowired
+ private DiscoveredServerService discoveredServersService;
+
+ @Autowired
+ private GlusterServerService glusterServerService;
+
+ @Autowired
+ private String discoveryMechanism;
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ private static final Logger logger = Logger.getLogger(ServerSyncTask.class);
+
+ public void perform() {
+ discoverServers();
+ syncClusterServerMapping();
+ }
+
+ private void syncClusterServerMapping() {
+ List<ClusterInfo> clusters = clusterService.getAllClusters();
+ for(ClusterInfo cluster : clusters) {
+ try {
+ List<ServerInfo> servers = cluster.getServers();
+ if(servers.isEmpty()) {
+ logger.info("Cluster [" + cluster.getName() + "] is empty, nothing to sync!");
+ continue;
+ }
+ List<GlusterServer> actualServers = glusterServerService.getGlusterServers(cluster.getName(), false,
+ null, null);
+ updateRemovedServers(cluster, servers, actualServers);
+ updateAddedServers(cluster, servers, actualServers);
+ } catch(Exception e) {
+ // log error and continue with next cluster
+ logger.error("Couldn't sync cluster-server mapping for cluster [" + cluster.getName() + "]!", e);
+ continue;
+ }
+ }
+ }
+
+ private void updateAddedServers(ClusterInfo cluster, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> addedServers = findAddedServers(cluster.getName(), servers, actualServers);
+ for(String addedServer : addedServers) {
+ clusterService.mapServerToCluster(cluster.getName(), addedServer);
+ }
+ }
+
+ private void updateRemovedServers(ClusterInfo cluster, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> removedServers = findRemovedServers(servers, actualServers);
+ for(String removedServer : removedServers) {
+ clusterService.unmapServerFromCluster(cluster.getName(), removedServer);
+ }
+ }
+
+ private List<String> findRemovedServers(List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> removedServers = new ArrayList<String>();
+
+ for(ServerInfo server : servers) {
+ if (!GlusterCoreUtil.containsEntityWithName(actualServers, server.getName(), true)) {
+ removedServers.add(server.getName());
+ }
+ }
+ return removedServers;
+ }
+
+ private List<String> findAddedServers(String clusterName, List<ServerInfo> servers, List<GlusterServer> actualServers) {
+ List<String> addedServers = new ArrayList<String>();
+ for(GlusterServer actualServer : actualServers) {
+ if(!serverExists(servers, actualServer.getName())) {
+ addedServers.add(actualServer.getName());
+ }
+ }
+ return addedServers;
+ }
+
+ private boolean serverExists(List<ServerInfo> servers, String name) {
+ for(ServerInfo server : servers) {
+ if(server.getName().equalsIgnoreCase(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void discoverServers() {
+ if(discoveryMechanism.equals(GlusterConstants.NONE)) {
+ return;
+ }
+
+ List<String> serverNameList = new ArrayList<String>();
+
+ ProcessResult result = serverUtil.executeGlusterScript(true, discoveryMechanism + SCRIPT_NAME_SFX, new ArrayList<String>());
+ if(result.isSuccess()) {
+ List<String> existingServers = clusterDao.findBySQL("select name from server_info");
+ String serverNames = result.getOutput();
+ String[] parts = serverNames.split(CoreConstants.NEWLINE);
+ for(String serverName : parts) {
+ // The server discovery mechanism will return every server that has not been "peer probed". However we
+ // need to filter out those servers that are the "first" server of a new cluster, and hence are still
+ // not peer probed.
+ if(!existingServers.contains(serverName)) {
+ serverNameList.add(serverName);
+ }
+ }
+ }
+
+ discoveredServersService.setDiscoveredServerNames(serverNameList);
+ }
+} \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java
new file mode 100644
index 00000000..0fee3c2e
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/tasks/Task.java
@@ -0,0 +1,113 @@
+/**
+ * Task.java
+ *
+ * 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 org.gluster.storage.management.gateway.tasks;
+
+import org.gluster.storage.management.core.model.GlusterServer;
+import org.gluster.storage.management.core.model.TaskInfo;
+import org.gluster.storage.management.core.model.TaskStatus;
+import org.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import org.gluster.storage.management.gateway.services.ClusterService;
+
+
+public abstract class Task {
+ public String[] TASK_TYPE_STR = { "Format Disk", "Migrate Brick", "Volume Rebalance" };
+
+ protected TaskInfo taskInfo;
+ protected String clusterName;
+ private ClusterService clusterService;
+
+ public Task(ClusterService clusterService, String clusterName, TASK_TYPE type, String reference, String desc,
+ boolean canPause, boolean canStop, boolean canCommit) {
+ TaskInfo taskInfo = new TaskInfo();
+ taskInfo.setType(type);
+ taskInfo.setReference(reference);
+ taskInfo.setDescription(desc);
+ taskInfo.setPauseSupported(canPause);
+ taskInfo.setStopSupported(canStop);
+ taskInfo.setCommitSupported(canCommit);
+
+ init(clusterService, clusterName, taskInfo);
+
+ }
+
+ public Task(ClusterService clusterService, String clusterName, TaskInfo taskInfo) {
+ init(clusterService, clusterName, taskInfo);
+ }
+
+ private void init(ClusterService clusterService, String clusterName, TaskInfo taskInfo) {
+ this.clusterService = clusterService;
+ setClusterName(clusterName);
+ setTaskInfo(taskInfo);
+ }
+
+ protected GlusterServer getOnlineServer() {
+ return clusterService.getOnlineServer(clusterName);
+ }
+
+ protected GlusterServer getNewOnlineServer() {
+ return clusterService.getNewOnlineServer(clusterName);
+ }
+
+ protected GlusterServer getNewOnlineServer(String exceptServerName) {
+ return clusterService.getNewOnlineServer(clusterName, exceptServerName);
+ }
+
+ public String getTypeStr() {
+ return TASK_TYPE_STR[taskInfo.getType().ordinal()];
+ }
+
+ public TASK_TYPE getType() {
+ return getTaskInfo().getType();
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ this.clusterName = clusterName;
+ }
+
+ public TaskInfo getTaskInfo() {
+ return taskInfo;
+ }
+
+ public void setTaskInfo(TaskInfo info) {
+ this.taskInfo = info;
+ }
+
+ public abstract String getId();
+
+ public abstract void start();
+
+ public abstract void resume();
+
+ public abstract void stop();
+
+ public abstract void pause();
+
+ public abstract void commit();
+
+ /**
+ * This method should check current status of the task and update it's taskInfo accordingly
+ */
+ public abstract TaskStatus checkStatus();
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/AbstractStatsFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/AbstractStatsFactory.java
new file mode 100644
index 00000000..ebc1ccba
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/AbstractStatsFactory.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.ServerStatsRow;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public abstract class AbstractStatsFactory implements StatsFactory {
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ private Logger logger = Logger.getLogger(AbstractStatsFactory.class);
+
+ protected ServerStats getFirstOnlineServerStats(List<String> serverNames, String period,
+ boolean removeServerOnError, boolean removeOnlineServer) {
+ for(int i = serverNames.size() - 1; i >= 0; i--) {
+ String serverName = serverNames.get(i);
+ try {
+ ServerStats stats = fetchStats(serverName, period);
+ if(removeOnlineServer) {
+ serverNames.remove(serverName);
+ }
+ return stats;
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch stats from server [" + serverName + "]!", e);
+ if(removeServerOnError) {
+ serverNames.remove(serverName);
+ }
+ continue;
+ }
+ }
+ throw new GlusterRuntimeException("All servers offline!");
+ }
+
+ protected void aggregateStats(List<String> serverNames, ServerStats aggregatedStats, String period) {
+ if(serverNames.isEmpty()) {
+ return;
+ }
+
+ int rowCount = aggregatedStats.getMetadata().getRowCount();
+ int columnCount = aggregatedStats.getMetadata().getLegend().size();
+ int[][] dataCount = initDataCountArray(rowCount, columnCount);
+
+ List<ServerStats> allStats = serverUtil.executeScriptOnServers(serverNames, getStatsScriptName() + " " + period, ServerStats.class, false);
+
+ for (ServerStats stats : allStats) {
+ // add to aggregated stats
+ addServerStats(stats, aggregatedStats, dataCount);
+ }
+
+ averageAggregatedStats(aggregatedStats, dataCount);
+ }
+
+ /**
+ *
+ * @param statsToBeAdded
+ * @param targetStats
+ * @param dataCount Each element of this matrix will be incremented for every valid element added
+ * @return
+ */
+ protected List<ServerStatsRow> addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) {
+ List<ServerStatsRow> serverStatsRows = statsToBeAdded.getRows();
+ for (int rowNum = 0; rowNum < serverStatsRows.size() && rowNum < targetStats.getMetadata().getRowCount()
+ && rowNum < dataCount.length; rowNum++) {
+ ServerStatsRow row = serverStatsRows.get(rowNum);
+ List<Double> rowData = row.getUsageData();
+
+ List<Double> aggregatedStatsRowData = targetStats.getRows().get(rowNum).getUsageData();
+ for(int i = 1; i < targetStats.getMetadata().getLegend().size(); i++) {
+ // Add the data
+ Double data = rowData.get(i);
+ if(!data.isNaN()) {
+ // data is available. add it.
+ Double oldData = aggregatedStatsRowData.get(i);
+ if(oldData.isNaN()) {
+ oldData = 0d;
+ }
+ aggregatedStatsRowData.set(i, oldData + data);
+ // increment record count. this will be used for calculating average of aggregated data.
+ dataCount[rowNum][i]++;
+ }
+ }
+ }
+ return serverStatsRows;
+ }
+
+ protected void averageAggregatedStats(ServerStats aggregatedStats, int[][] dataCount) {
+ List<ServerStatsRow> rows = aggregatedStats.getRows();
+ for(int rowNum = 0; rowNum < rows.size() && rowNum < dataCount.length; rowNum++) {
+ List<Double> data = rows.get(rowNum).getUsageData();
+ for(int columnNum = 0; columnNum < data.size(); columnNum++) {
+ data.set(columnNum, data.get(columnNum) / dataCount[rowNum][columnNum]);
+ }
+ }
+ }
+
+ protected int[][] initDataCountArray(int rowCount, int columnCount) {
+ int[][] dataCount = new int[rowCount][columnCount];
+ // initialize all data counts to 1
+ for(int rowNum = 0; rowNum < rowCount; rowNum++) {
+ for(int columnNum = 0; columnNum < columnCount; columnNum++) {
+ dataCount[rowNum][columnNum] = 1;
+ }
+ }
+ return dataCount;
+ }
+
+ @Override
+ public ServerStats fetchAggregatedStats(List<String> serverNames, String period) {
+ if(serverNames == null || serverNames.size() == 0) {
+ throw new GlusterRuntimeException("No server names passed to fetchAggregaredStats!");
+ }
+
+ ServerStats firstServerStats = getFirstOnlineServerStats(serverNames, period, true, true);
+
+ ServerStats aggregatedStats = new ServerStats(firstServerStats);
+ aggregateStats(serverNames, aggregatedStats, period);
+ return aggregatedStats;
+ }
+
+ @Override
+ public ServerStats fetchStats(String serverName, String period, String...args) {
+ String argsStr = "";
+ for (String arg : args) {
+ if(arg != null) {
+ argsStr += " " + arg;
+ }
+ }
+ return serverUtil.executeScriptOnServer(serverName, getStatsScriptName() + argsStr + " " + period,
+ ServerStats.class);
+ }
+
+ public abstract String getStatsScriptName();
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/CpuStatsFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/CpuStatsFactory.java
new file mode 100644
index 00000000..412794eb
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/CpuStatsFactory.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ */
+@Component
+public class CpuStatsFactory extends AbstractStatsFactory {
+
+ private static final String CPU_STATS_SCRIPT = "get_rrd_cpu_details.py";
+
+ @Override
+ public String getStatsScriptName() {
+ return CPU_STATS_SCRIPT;
+ }
+
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/DBUtil.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/DBUtil.java
new file mode 100644
index 00000000..1c186a0a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/DBUtil.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+
+
+/**
+ *
+ */
+public class DBUtil {
+ private static final Logger logger = Logger.getLogger(DBUtil.class);
+ public static void shutdownDerby() {
+ try {
+ // the shutdown=true attribute shuts down Derby
+ DriverManager.getConnection("jdbc:derby:;shutdown=true");
+
+ // To shut down a specific database only, but keep the
+ // engine running (for example for connecting to other
+ // databases), specify a database in the connection URL:
+ //DriverManager.getConnection("jdbc:derby:" + dbName + ";shutdown=true");
+ } catch (Exception e) {
+ if(e instanceof SQLException) {
+ SQLException se = (SQLException) e;
+ if (((se.getErrorCode() == 50000) && ("XJ015".equals(se.getSQLState())))) {
+ // we got the expected exception
+ logger.info("Derby shut down normally");
+ // Note that for single database shutdown, the expected
+ // SQL state is "08006", and the error code is 45000.
+ } else {
+ // if the error code or SQLState is different, we have
+ // an unexpected exception (shutdown failed)
+ logger.error("Derby did not shut down normally!" + inspectSQLException(se), se);
+ }
+ } else {
+ logger.error("Derby did not shut down normally! [" + e.getMessage() + "]", e);
+ }
+ }
+ // force garbage collection to unload the EmbeddedDriver
+ // so Derby can be restarted
+ System.gc();
+ }
+
+ /**
+ * Extracts details of an SQLException chain to <code>String</code>.
+ * Details included are SQL State, Error code, Exception message.
+ *
+ * @param e the SQLException from which to print details.
+ */
+ private static String inspectSQLException(SQLException e)
+ {
+ // Unwraps the entire exception chain to unveil the real cause of the
+ // Exception.
+ String errMsg = "";
+ while (e != null)
+ {
+ errMsg += "\n----- SQLException -----" + CoreConstants.NEWLINE + " SQL State: " + e.getSQLState()
+ + CoreConstants.NEWLINE + " Error Code: " + e.getErrorCode() + CoreConstants.NEWLINE
+ + " Message: " + e.getMessage();
+ e = e.getNextException();
+ }
+ return errMsg;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/MemoryStatsFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/MemoryStatsFactory.java
new file mode 100644
index 00000000..691662e6
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/MemoryStatsFactory.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.ServerStatsRow;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class MemoryStatsFactory extends AbstractStatsFactory {
+
+ private static final String MEM_STATS_SCRIPT = "get_rrd_memory_details.py";
+
+ @Override
+ public String getStatsScriptName() {
+ return MEM_STATS_SCRIPT;
+ }
+
+ @Override
+ public ServerStats fetchStats(String serverName, String period, String... args) {
+ ServerStats stats = super.fetchStats(serverName, period, args);
+
+ // stats returned by rrd script contains five columns - user, free, cache, buffer, total
+ // out of this, the "user" memory includes cached and buffer. We remove them to get the
+ // actual memory used by "user"
+ for(ServerStatsRow row : stats.getRows()) {
+ List<Double> data = row.getUsageData();
+ Double user = data.get(0);
+ Double free = data.get(1);
+ Double cache = data.get(2);
+ Double buffer = data.get(3);
+ Double total = data.get(4);
+
+ Double actualUser = user - cache - buffer;
+
+ // convert all figures from bytes to percentages
+ data.set(0, (actualUser * 100) / total);
+ data.set(1, (free * 100) / total);
+ data.set(2, (cache * 100) / total);
+ data.set(3, (buffer * 100) / total);
+ data.set(4, (total * 100) / total);
+ }
+
+ return stats;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/NetworkStatsFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/NetworkStatsFactory.java
new file mode 100644
index 00000000..03c252a9
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/NetworkStatsFactory.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.NetworkInterface;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.ServerStats;
+import org.gluster.storage.management.core.model.ServerStatsRow;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *
+ */
+@Component
+public class NetworkStatsFactory extends AbstractStatsFactory {
+ private static final Logger logger = Logger.getLogger(NetworkStatsFactory.class);
+ private static final String NETWORK_STATS_SCRIPT = "get_rrd_net_details.py";
+ private int[][] dataCount;
+
+ @Override
+ public String getStatsScriptName() {
+ return NETWORK_STATS_SCRIPT;
+ }
+
+ @Override
+ protected ServerStats getFirstOnlineServerStats(List<String> serverNames, String period,
+ boolean removeServerOnError, boolean removeOnlineServer) {
+ ServerStats firstOnlineServerStats = null;
+ for(int i = serverNames.size() - 1; i >= 0; i--) {
+ String serverName = serverNames.get(i);
+ Server server = new Server(serverName);
+ serverUtil.fetchServerDetails(server);
+ if(!server.isOnline()) {
+ if(removeServerOnError) {
+ // server is offline. no point in trying to fetch it's details.
+ serverNames.remove(serverName);
+ }
+ continue;
+ }
+ try {
+ for(NetworkInterface networkInterface : server.getNetworkInterfaces()) {
+ ServerStats stats = fetchStats(serverName, period, networkInterface.getName());
+ if(firstOnlineServerStats == null) {
+ firstOnlineServerStats = stats;
+ int rowCount = firstOnlineServerStats.getMetadata().getRowCount();
+ int columnCount = firstOnlineServerStats.getMetadata().getLegend().size();
+ dataCount = initDataCountArray(rowCount, columnCount);
+ } else {
+ addServerStats(stats, firstOnlineServerStats, dataCount);
+ }
+ }
+
+ if(removeOnlineServer) {
+ serverNames.remove(serverName);
+ }
+ return firstOnlineServerStats;
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch stats from server [" + serverName + "]!", e);
+ if(removeServerOnError) {
+ serverNames.remove(serverName);
+ }
+ continue;
+ }
+ }
+ throw new GlusterRuntimeException("All servers offline!");
+ }
+
+ protected void aggregateStats(List<String> serverNames, ServerStats aggregatedStats, String period) {
+ if(serverNames.isEmpty()) {
+ return;
+ }
+
+ List<ServerStats> statsList = Collections.synchronizedList(new ArrayList<ServerStats>());
+ try {
+ List<Thread> threads = createThreads(serverNames, period, statsList);
+ ProcessUtil.waitForThreads(threads);
+ for(ServerStats stats : statsList) {
+ addServerStats(stats, aggregatedStats, dataCount);
+ }
+ } catch (InterruptedException e) {
+ String errMsg = "Exception while aggregating network statistics on servers [" + serverNames
+ + "] for period [" + period + "]! Error: [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+
+ averageAggregatedStats(aggregatedStats, dataCount);
+ }
+
+ private <T> List<Thread> createThreads(List<String> serverNames, String period, List<ServerStats> statsList)
+ throws InterruptedException {
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = serverNames.size()-1; i >= 0 ; i--) {
+ Thread thread = new NetworkStatsThread(serverNames.get(i), period, statsList);
+ threads.add(thread);
+ thread.start();
+ if(i >= 5 && i % 5 == 0) {
+ // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
+ Thread.sleep(1000);
+ }
+ }
+ return threads;
+ }
+
+ public class NetworkStatsThread extends Thread {
+ private String serverName;
+ private String period;
+ private List<ServerStats> statsList;
+
+ public NetworkStatsThread(String serverName, String period, List<ServerStats> statsList) {
+ this.serverName = serverName;
+ this.period = period;
+ this.statsList = statsList;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Server server = new Server(serverName);
+ serverUtil.fetchServerDetails(server);
+
+ for (NetworkInterface networkInterface : server.getNetworkInterfaces()) {
+ // fetch the stats and add to aggregated stats
+ statsList.add(fetchStats(serverName, period, networkInterface.getName()));
+ }
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch Network stats from server [" + serverName + "]!", e);
+ }
+ }
+ }
+
+ @Override
+ public ServerStats fetchStats(String serverName, String period, String... args) {
+ ServerStats stats = super.fetchStats(serverName, period, args);
+
+ // the data returned by rrd contains "bytes/sec". Update the stats object to represent KiB/s
+ for(ServerStatsRow row : stats.getRows()) {
+ List<Double> data = row.getUsageData();
+ for (int i = 0; i < data.size(); i++) {
+ Double val = data.get(i);
+ data.set(i, val / 1024);
+ }
+ }
+
+ return stats;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/PasswordManager.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/PasswordManager.java
new file mode 100644
index 00000000..a44b5bf3
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/PasswordManager.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import org.apache.derby.jdbc.EmbeddedDriver;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.gateway.security.UserAuthDao;
+import org.springframework.jdbc.datasource.SimpleDriverDataSource;
+import org.springframework.security.authentication.dao.ReflectionSaltSource;
+import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
+
+
+/**
+ * Tool to reset password of default user gluster
+ */
+public class PasswordManager {
+ private static final int USAGE_ERR = 1;
+ private static final int SQL_ERR = 2;
+
+ private void resetPassword(String username) {
+ try {
+ UserAuthDao userAuthDao = createUserAuthDao();
+ ReflectionSaltSource saltSource = createSaltSource();
+
+ String encodedPassword = new ShaPasswordEncoder(256).encodePassword(CoreConstants.DEFAULT_PASSWORD,
+ saltSource.getSalt(userAuthDao.loadUserByUsername(username)));
+
+ userAuthDao.changePassword(username, encodedPassword);
+
+ System.out.println("Password for user [" + username + "] reset successsfully to default value of ["
+ + CoreConstants.DEFAULT_PASSWORD + "]." + CoreConstants.NEWLINE);
+
+ DBUtil.shutdownDerby();
+ } catch (Exception e) {
+ System.err.println(CoreConstants.NEWLINE + CoreConstants.NEWLINE + "Password reset for user [" + username
+ + "] failed! " + CoreConstants.NEWLINE
+ + "Make sure that the Management Gateway is not running while performing password reset."
+ + CoreConstants.NEWLINE);
+ System.exit(SQL_ERR);
+ }
+ }
+
+ private ReflectionSaltSource createSaltSource() {
+ ReflectionSaltSource saltSource = new ReflectionSaltSource();
+ saltSource.setUserPropertyToUse("username");
+ return saltSource;
+ }
+
+ private UserAuthDao createUserAuthDao() throws InstantiationException, IllegalAccessException,
+ ClassNotFoundException {
+ UserAuthDao authDao = new UserAuthDao();
+ EmbeddedDriver driver = (EmbeddedDriver) Class.forName(EmbeddedDriver.class.getName()).newInstance();
+ SimpleDriverDataSource dataSource = new SimpleDriverDataSource(driver, "jdbc:derby:/opt/glustermg/data", "gluster", "syst3m");
+
+ authDao.setDataSource(dataSource);
+ return authDao;
+ }
+
+ public static void main(String args[]) {
+ if (args.length != 2 || !args[0].equals("reset")) {
+ System.err.println("Usage: java " + PasswordManager.class.getName() + " reset <username>\n");
+ System.exit(USAGE_ERR);
+ }
+
+ new PasswordManager().resetPassword(args[1]);
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/ServerUtil.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/ServerUtil.java
new file mode 100644
index 00000000..f65c5640
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/ServerUtil.java
@@ -0,0 +1,370 @@
+/**
+ * ServerUtil.java
+ *
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.model.Server;
+import org.gluster.storage.management.core.model.Status;
+import org.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import org.gluster.storage.management.core.response.StringListResponse;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.gluster.storage.management.core.utils.ProcessUtil;
+import org.gluster.storage.management.gateway.services.GlusterInterfaceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.ContextLoader;
+
+
+@Component
+public class ServerUtil {
+ @Autowired
+ ServletContext servletContext;
+
+ @Autowired
+ private SshUtil sshUtil;
+
+ @Autowired
+ private String appVersion;
+
+ private static final Logger logger = Logger.getLogger(ServerUtil.class);
+
+ private static final String SCRIPT_DIR = "scripts";
+ private static final String SCRIPT_COMMAND = "python";
+ private static final String REMOTE_SCRIPT_GET_DISK_FOR_DIR = "get_disk_for_dir.py";
+ private static final String REMOTE_SCRIPT_GET_SERVER_DETAILS = "get_server_details.py";
+ private static final String REMOTE_SCRIPT_GET_FILE_SYSTEM_TYPE = "get_filesystem_type.py";
+ private static final String REMOTE_SCRIPT_BASE_DIR = "/opt/glustermg";
+ private static final String REMOTE_SCRIPT_DIR_NAME = "backend";
+
+ public void setSshUtil(SshUtil sshUtil) {
+ this.sshUtil = sshUtil;
+ }
+
+ public ProcessResult executeGlusterScript(boolean runInForeground, String scriptName, String...arguments) {
+ return executeGlusterScript(runInForeground, scriptName, Arrays.asList(arguments));
+ }
+
+ public ProcessResult executeGlusterScript(boolean runInForeground, String scriptName, List<String> arguments) {
+ List<String> command = new ArrayList<String>();
+
+ command.add(SCRIPT_COMMAND);
+ command.add(getScriptPath(scriptName));
+ command.addAll(arguments);
+ return ProcessUtil.executeCommand(runInForeground, command);
+ }
+
+ private String getScriptPath(String scriptName) {
+ return servletContext.getRealPath(SCRIPT_DIR) + CoreConstants.FILE_SEPARATOR + scriptName;
+ }
+
+ private String getRemoteScriptDir() {
+ return REMOTE_SCRIPT_BASE_DIR + File.separator + appVersion + File.separator + REMOTE_SCRIPT_DIR_NAME;
+ }
+
+ /**
+ * Fetch details of the given server. The server name must be populated in the object before calling this method.
+ *
+ * @param server
+ * Server whose details are to be fetched
+ */
+ public void fetchServerDetails(Server server) {
+ try {
+ Server serverDetails = fetchServerDetails(server.getName());
+ server.copyFrom(serverDetails); // Update the details in <Server> object
+ server.setDisks(serverDetails.getDisks());
+ } catch (ConnectionException e) {
+ logger.warn("Couldn't connect to server [" + server.getName() + "]. Marking it offline!", e);
+ server.setStatus(SERVER_STATUS.OFFLINE);
+ }
+ }
+
+ public boolean isServerOnline(Server server) {
+ // fetch latest details and check if server is still online
+ fetchServerDetails(server);
+ return server.isOnline();
+ }
+
+ public String fetchHostName(String serverName) {
+ Object response = fetchServerDetails(serverName);
+ return ((Server) response).getName();
+ }
+
+ private Server fetchServerDetails(String serverName) {
+ // fetch standard server details like cpu, disk, memory details
+ return executeScriptOnServer(serverName, REMOTE_SCRIPT_GET_SERVER_DETAILS, Server.class);
+ }
+
+ /**
+ * Executes given script on all given servers in parallel, collects the output in objects of given class, and
+ * returns a list of all returned objects.
+ *
+ * @param serverNames
+ * @param scriptWithArgs
+ * @param expectedClass
+ * @param failOnError
+ * If true, an exception will be thrown as soon as the script execution fails on any of the servers. If
+ * false, the exception will be caught and logged. Execution on all other servers will continue.
+ * @return
+ */
+ public <T> List<T> executeScriptOnServers(List<String> serverNames, String scriptWithArgs,
+ Class<T> expectedClass, boolean failOnError) {
+ List<T> result = Collections.synchronizedList(new ArrayList<T>());
+ try {
+ List<Thread> threads = createScriptExecutionThreads(serverNames, getRemoteScriptDir() + File.separator
+ + scriptWithArgs, expectedClass, result, failOnError);
+ ProcessUtil.waitForThreads(threads);
+ return result;
+ } catch (InterruptedException e) {
+ String errMsg = "Exception while executing script [" + scriptWithArgs + "] on servers [" + serverNames + "]! Error: [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ /**
+ * Creates threads that will run in parallel and execute the given command on each of the given servers
+ *
+ * @param serverNames
+ * @param commandWithArgs
+ * @param expectedClass
+ * @param result
+ * @param failOnError
+ * If true, an exception will be thrown as soon as the script execution fails on any of the servers. If
+ * false, the exception will be caught and logged. Execution on all other servers will continue.
+ * @return
+ * @throws InterruptedException
+ */
+ private <T> List<Thread> createScriptExecutionThreads(List<String> serverNames, String commandWithArgs, Class<T> expectedClass, List<T> result,
+ boolean failOnError)
+ throws InterruptedException {
+ List<Thread> threads = new ArrayList<Thread>();
+ for (int i = serverNames.size()-1; i >= 0 ; i--) {
+ Thread thread = new RemoteExecutionThread<T>(serverNames.get(i), commandWithArgs, expectedClass, result, failOnError);
+ threads.add(thread);
+ thread.start();
+ if(i >= 5 && i % 5 == 0) {
+ // After every 5 servers, wait for 1 second so that we don't end up with too many running threads
+ Thread.sleep(1000);
+ }
+ }
+ return threads;
+ }
+
+
+ public class RemoteExecutionThread<T> extends Thread {
+ private String serverName;
+ private String commandWithArgs;
+ private List<T> result;
+ private Class<T> expectedClass;
+ private boolean failOnError = false;
+
+ public RemoteExecutionThread(String serverName, String commandWithArgs, Class<T> expectedClass, List<T> result,
+ boolean failOnError) {
+ this.serverName = serverName;
+ this.commandWithArgs = commandWithArgs;
+ this.result = result;
+ this.expectedClass = expectedClass;
+ this.failOnError = failOnError;
+ }
+
+ @Override
+ public void run() {
+ try {
+ result.add(executeOnServer(serverName, commandWithArgs, expectedClass));
+ } catch(Exception e) {
+ String errMsg = "Couldn't execute command [" + commandWithArgs + "] on [" + serverName + "]!";
+ logger.error(errMsg, e);
+ if(failOnError) {
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Executes given script on given server. Since the remote server may contain multiple versions of backend, this
+ * method will invoke the script present in directory of same version as the gateway.
+ *
+ * @param serverName
+ * @param scriptWithArgs
+ * The script name followed by arguments to be passed. Note that the script name should not contain path
+ * as it will be automatically identified by the method.
+ * @param expectedClass
+ * Class of the object expected from script execution
+ * @return Output (console/error) from the script execution
+ * @throws GlusterRuntimeException in case the remote execution fails.
+ */
+ public String executeScriptOnServer(String serverName, String scriptWithArgs) {
+ return executeOnServer(serverName, getRemoteScriptDir() + File.separator + scriptWithArgs, String.class);
+ }
+
+ /**
+ * Executes given script on given server. Since the remote server may contain multiple versions of backend, this
+ * method will invoke the script present in directory of same version as the gateway.
+ *
+ * @param serverName
+ * @param scriptWithArgs
+ * The script name followed by arguments to be passed. Note that the script name should not contain path
+ * as it will be automatically identified by the method.
+ * @param expectedClass
+ * Class of the object expected from script execution
+ * @return Object of the expected class from remote execution of the command.
+ * @throws GlusterRuntimeException in case the remote execution fails.
+ */
+ public <T> T executeScriptOnServer(String serverName, String scriptWithArgs,
+ Class<T> expectedClass) {
+ return executeOnServer(serverName, getRemoteScriptDir() + File.separator + scriptWithArgs,
+ expectedClass);
+ }
+
+ /**
+ * Executes given command on given server
+ *
+ * @param serverName
+ * @param commandWithArgs
+ * @param expectedClass
+ * Class of the object expected from script execution
+ * @return Object of the expected class from remote execution of the command. In case the remote execution fails
+ * ungracefully, an object of class {@link Status} will be returned.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T executeOnServer(String serverName, String commandWithArgs,
+ Class<T> expectedClass) {
+ String output = executeOnServer(serverName, commandWithArgs);
+ if (expectedClass == String.class) {
+ return (T) output;
+ }
+
+ return unmarshal(expectedClass, output);
+ }
+
+ public String executeOnServer(String serverName, String commandWithArgs) {
+ ProcessResult result = sshUtil.executeRemote(serverName, commandWithArgs);
+
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Command [" + commandWithArgs + "] failed on [" + serverName
+ + "] with error [" + result.getExitValue() + "][" + result.getOutput() + "]");
+ }
+ return result.getOutput();
+ }
+
+ // This is the old executeOnServer that used socket communication.
+ // We can keep it commented for the time being.
+ // private String executeOnServerUsingSocket(String serverName, String commandWithArgs) {
+ // try {
+ // InetAddress address = InetAddress.getByName(serverName);
+ // Socket connection = new Socket(address, 50000);
+ //
+ // PrintWriter writer = new PrintWriter(connection.getOutputStream(), true);
+ // writer.println(commandWithArgs);
+ // writer.println(); // empty line means end of request
+ //
+ // InputStream inputStream = connection.getInputStream();
+ // int available = inputStream.available();
+ //
+ // StringBuffer output = new StringBuffer();
+ // if( available > 0 ) {
+ // // This happens when PeerAgent sends complete file
+ // byte[] responseData = new byte[available];
+ // inputStream.read(responseData);
+ // output.append(new String(responseData, "UTF-8"));
+ // } else {
+ // // This happens in case of normal XML response from PeerAgent
+ // BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+ //
+ // String line;
+ // while (!(line = reader.readLine()).trim().isEmpty()) {
+ // output.append(line + CoreConstants.NEWLINE);
+ // }
+ // }
+ // connection.close();
+ //
+ // return output.toString();
+ // } catch (Exception e) {
+ // throw new GlusterRuntimeException("Error during remote execution: [" + e.getMessage() + "]");
+ // }
+ // }
+
+ public void getFileFromServer(String serverName, String remoteFileName, String localDirName) {
+ sshUtil.getFile(serverName, remoteFileName, localDirName);
+ }
+
+ /**
+ * Unmarshals given input string into object of given class
+ *
+ * @param expectedClass
+ * Class whose object is expected
+ * @param input
+ * Input string
+ * @return Object of given expected class
+ */
+ public <T> T unmarshal(Class<T> expectedClass, String input) {
+ try {
+ // create JAXB context and instantiate marshaller
+ JAXBContext context = JAXBContext.newInstance(expectedClass);
+ Unmarshaller um = context.createUnmarshaller();
+ return (T)um.unmarshal(new ByteArrayInputStream(input.getBytes()));
+ } catch (JAXBException e) {
+ String errMsg = "Error during unmarshalling string [" + input + "] for class [" + expectedClass.getName()
+ + ": [" + e.getMessage() + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ /**
+ * @param serverName
+ * Server on which the directory is present
+ * @param brickDir
+ * Directory whose disk is to be fetched
+ * @return Status object containing the disk name, or error message in case the remote script fails.
+ */
+ public Status getDiskForDir(String serverName, String brickDir) {
+ return executeScriptOnServer(serverName, REMOTE_SCRIPT_GET_DISK_FOR_DIR + " " + brickDir, Status.class);
+ }
+
+ public <T> T getBean(Class<T> clazz) {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ return ctx.getBean(clazz);
+ }
+
+ public List<String> getFsTypes(String serverName) {
+ String output = executeScriptOnServer(serverName, REMOTE_SCRIPT_GET_FILE_SYSTEM_TYPE);
+ return Arrays.asList(output.trim().split(CoreConstants.NEWLINE));
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/SshUtil.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/SshUtil.java
new file mode 100644
index 00000000..074cbd5b
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/SshUtil.java
@@ -0,0 +1,463 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import org.apache.log4j.Logger;
+import org.gluster.storage.management.core.constants.CoreConstants;
+import org.gluster.storage.management.core.exceptions.ConnectionException;
+import org.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import org.gluster.storage.management.core.utils.FileUtil;
+import org.gluster.storage.management.core.utils.LRUCache;
+import org.gluster.storage.management.core.utils.ProcessResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.ssh2.ChannelCondition;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.SCPClient;
+import ch.ethz.ssh2.Session;
+import ch.ethz.ssh2.StreamGobbler;
+
+
+/**
+ *
+ */
+@Component
+public class SshUtil {
+ private static final String TEMP_DIR = "/tmp/";
+ public static final String SSH_AUTHORIZED_KEYS_DIR_LOCAL = "/opt/glustermg/keys/";
+ public static final String SSH_AUTHORIZED_KEYS_DIR_REMOTE = "/root/.ssh/";
+ private static final String SSH_AUTHORIZED_KEYS_FILE = "authorized_keys";
+ private static final String SSH_AUTHORIZED_KEYS_PATH_REMOTE = SSH_AUTHORIZED_KEYS_DIR_REMOTE + SSH_AUTHORIZED_KEYS_FILE;
+ public static final File PRIVATE_KEY_FILE = new File(SSH_AUTHORIZED_KEYS_DIR_LOCAL + "gluster.pem");
+ public static final File PUBLIC_KEY_FILE = new File(SSH_AUTHORIZED_KEYS_DIR_LOCAL + "gluster.pub");
+ private LRUCache<String, Connection> sshConnCache = new LRUCache<String, Connection>(10);
+
+ // 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 static final Logger logger = Logger.getLogger(SshUtil.class);
+
+ @Autowired
+ private Integer sshConnectTimeout;
+ @Autowired
+ private Integer sshKexTimeout;
+ @Autowired
+ private Integer sshExecTimeout;
+
+ public boolean hasDefaultPassword(String serverName) {
+ try {
+ getConnectionWithPassword(serverName).close();
+ return true;
+ } catch(Exception e) {
+ logger.warn("Couldn't connect to [" + serverName + "] with default password!", e);
+ return false;
+ }
+ }
+
+ /**
+ * 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 isPublicKeyInstalled(String serverName) {
+ try {
+ getConnectionWithPubKey(serverName).close();
+ return true;
+ } catch(ConnectionException e) {
+ logger.warn("Couldn't connect to [" + serverName + "] with public key!", e);
+ return false;
+ }
+ }
+
+ public void getFile(String serverName, String remoteFile, String localDir) {
+ try {
+ Connection conn = getConnection(serverName);
+ SCPClient scpClient = new SCPClient(conn);
+ scpClient.get(remoteFile, localDir);
+ } catch (IOException e) {
+ throw new GlusterRuntimeException("Error while fetching file [" + remoteFile + "] from server ["
+ + serverName + "]", e);
+ }
+ }
+
+ public synchronized void installPublicKey(String serverName) {
+ Connection conn = null;
+ try {
+ conn = getConnectionWithPassword(serverName);
+ } catch(Exception e) {
+ // authentication failed. close the connection.
+ conn.close();
+ if (e instanceof GlusterRuntimeException) {
+ throw (GlusterRuntimeException) e;
+ } else {
+ throw new GlusterRuntimeException("Exception during authentication with public key on server ["
+ + serverName + "]", e);
+ }
+ }
+ SCPClient scpClient = new SCPClient(conn);
+
+ // delete file if it exists
+ File localTempFile = new File(TEMP_DIR + SSH_AUTHORIZED_KEYS_FILE);
+ if(localTempFile.exists()) {
+ localTempFile.delete();
+ }
+
+ try {
+ // get authorized_keys from server
+ scpClient.get(SSH_AUTHORIZED_KEYS_PATH_REMOTE, TEMP_DIR);
+ } catch (IOException e) {
+ // file doesn't exist. it will get created.
+ // create the .ssh directory in case it doesn't exist
+ logger.info("Couldn't fetch file [" + SSH_AUTHORIZED_KEYS_PATH_REMOTE +"].", e);
+ logger.info("Creating /root/.ssh on [" + serverName + "] in case it doesn't exist.");
+ String command = "mkdir -p " + SSH_AUTHORIZED_KEYS_DIR_REMOTE;
+ ProcessResult result = executeCommand(conn, command);
+ if(!result.isSuccess()) {
+ String errMsg = "Command [" + command + "] failed on server [" + serverName + "] with error: " + result;
+ logger.error(errMsg);
+ throw new GlusterRuntimeException(errMsg);
+ }
+ }
+
+ byte[] publicKeyData;
+ try {
+ publicKeyData = FileUtil.readFileAsByteArray(PUBLIC_KEY_FILE);
+ } catch (Exception e) {
+ conn.close();
+ throw new GlusterRuntimeException("Couldn't load public key file [" + PUBLIC_KEY_FILE + "]", e);
+ }
+
+ try {
+ // append it
+ FileOutputStream outputStream = new FileOutputStream(localTempFile, true);
+ outputStream.write(CoreConstants.NEWLINE.getBytes());
+ outputStream.write(publicKeyData);
+ outputStream.close();
+ } catch (Exception e) {
+ conn.close();
+ throw new GlusterRuntimeException("Couldnt append file [" + localTempFile + "] with public key!", e);
+ }
+
+ try {
+ scpClient.put(localTempFile.getAbsolutePath(), SSH_AUTHORIZED_KEYS_FILE, SSH_AUTHORIZED_KEYS_DIR_REMOTE, "0600");
+ } catch (IOException e) {
+ throw new GlusterRuntimeException("Couldn't add public key to server [" + serverName + "]", e);
+ } finally {
+ conn.close();
+ localTempFile.delete();
+ }
+
+ // It was decided NOT to disable password login as this may not be acceptable in a bare-metal environment
+ // disableSshPasswordLogin(serverName, scpClient);
+ }
+
+// private void disableSshPasswordLogin(String serverName, SCPClient scpClient) {
+// ProcessResult result = executeRemote(serverName, SCRIPT_DISABLE_SSH_PASSWORD_AUTH);
+// if(!result.isSuccess()) {
+// throw new GlusterRuntimeException("Couldn't disable SSH password authentication on [" + serverName
+// + "]. Error: " + result);
+// }
+// }
+
+ private synchronized Connection getConnectionWithPassword(String serverName) {
+ Connection conn = createConnection(serverName);
+ if(!authenticateWithPassword(conn)) {
+ conn.close();
+ throw new ConnectionException("SSH Authentication (password) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ return conn;
+ }
+
+ private synchronized Connection getConnectionWithPubKey(String serverName) {
+ Connection conn = createConnection(serverName);
+ if(!authenticateWithPublicKey(conn)) {
+ conn.close();
+ throw new ConnectionException("SSH Authentication (public key) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ return conn;
+ }
+
+ private synchronized Connection getConnection(String serverName) {
+ Connection conn = sshConnCache.get(serverName);
+ if (conn != null) {
+ return conn;
+ }
+
+ conn = createConnection(serverName);
+ try {
+ if(!authenticateWithPublicKey(conn)) {
+ if(!authenticateWithPassword(conn)) {
+ conn.close();
+ throw new ConnectionException("SSH authentication failed on server [" + serverName + "]!");
+ }
+ }
+ } catch(Exception e) {
+ // authentication failed. close the connection.
+ conn.close();
+ if(e instanceof GlusterRuntimeException) {
+ throw (GlusterRuntimeException)e;
+ } else {
+ throw new GlusterRuntimeException("Exception during authentication on server [" + serverName + "]", e);
+ }
+ }
+
+ sshConnCache.put(serverName, conn);
+ return conn;
+ }
+
+ private boolean authenticateWithPublicKey(Connection conn) {
+ try {
+ if (!supportsPublicKeyAuthentication(conn)) {
+ throw new ConnectionException("Public key authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ if (!conn.authenticateWithPublicKey(USER_NAME, PRIVATE_KEY_FILE, null)) {
+ return false;
+ }
+
+ return true;
+ } catch (IOException e) {
+ throw new ConnectionException("Exception during SSH authentication (public key) for server ["
+ + conn.getHostname() + "]", e);
+ }
+ }
+
+ private boolean authenticateWithPassword(Connection conn) {
+ try {
+ if (!supportsPasswordAuthentication(conn)) {
+ throw new ConnectionException("Password authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ if (!conn.authenticateWithPassword(USER_NAME, DEFAULT_PASSWORD)) {
+ return false;
+ }
+ return true;
+ } catch (IOException e) {
+ throw new ConnectionException("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 synchronized Connection createConnection(String serverName) {
+ Connection conn = new Connection(serverName);
+ try {
+ conn.connect(null, sshConnectTimeout, sshKexTimeout);
+ } catch (IOException e) {
+ logger.error("Couldn't establish SSH connection with server [" + serverName + "]", e);
+ conn.close();
+ throw new ConnectionException("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 timedOut(int condition) {
+ return (condition == ChannelCondition.TIMEOUT);
+ }
+
+ 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) {
+ Session session = null;
+ try {
+ 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);
+ return result;
+ } catch (Exception e) {
+ String errMsg = "Exception while executing command [" + command + "] on [" + sshConnection.getHostname()
+ + "]";
+ logger.error(errMsg, e);
+
+ // remove the connection from cache and close it
+ sshConnCache.remove(sshConnection.getHostname());
+ sshConnection.close();
+ if(e instanceof IllegalStateException || e instanceof IOException) {
+ // The connection is no more valid. Create and throw a connection exception.
+ throw new ConnectionException("Couldn't open SSH session on [" + sshConnection.getHostname() + "]!", e);
+ } else {
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ } finally {
+ if(session != null) {
+ session.close();
+ }
+ }
+ }
+
+ 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
+ // c) command takes to long to exit (timeout)
+ int condition = session.waitForCondition(ChannelCondition.EXIT_SIGNAL | ChannelCondition.EXIT_STATUS,
+ sshExecTimeout);
+ StringBuilder output = new StringBuilder();
+
+ try {
+ if(!timedOut(condition)) {
+ readFromStream(stdoutReader, output);
+ if (hasErrors(condition, session)) {
+ readFromStream(stderrReader, output);
+ }
+ }
+
+ return prepareProcessResult(session, condition, output.toString().trim());
+ } catch (IOException e) {
+ String errMsg = "Error while reading output stream from SSH connection!";
+ logger.error(errMsg, e);
+ return new ProcessResult(ProcessResult.FAILURE, errMsg);
+ }
+ }
+
+ private ProcessResult prepareProcessResult(Session session, int condition, String output) {
+ ProcessResult result = null;
+
+ if (wasTerminated(condition)) {
+ result = new ProcessResult(ProcessResult.FAILURE, output);
+ } else if (timedOut(condition)) {
+ result = new ProcessResult(ProcessResult.FAILURE, "Command timed out!");
+ } else if (hasErrors(condition, session)) {
+ Integer exitStatus = session.getExitStatus();
+ int statusCode = (exitStatus == null ? ProcessResult.FAILURE : exitStatus);
+ result = new ProcessResult(statusCode, output);
+ } else {
+ result = new ProcessResult(ProcessResult.SUCCESS, output);
+ }
+
+ return result;
+ }
+
+ private void readFromStream(BufferedReader streamReader, StringBuilder output) throws IOException {
+ 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) {
+ logger.info("Executing command [" + command + "] on server [" + serverName + "] with default password.");
+ Connection conn = null;
+ try {
+ conn = getConnectionWithPassword(serverName);
+ return executeCommand(conn, command);
+ } finally {
+ // we don't cache password based connections. hence the connection must be closed.
+ if(conn != null) {
+ conn.close();
+ }
+ }
+ }
+
+ /**
+ * 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) {
+ logger.info("Executing command [" + command + "] on server [" + serverName + "]");
+ return executeCommand(getConnection(serverName), command);
+ }
+
+ public void cleanup() {
+ for (Connection conn : sshConnCache.values()) {
+ conn.close();
+ }
+ }
+
+ public Integer getSshConnectTimeout() {
+ return sshConnectTimeout;
+ }
+
+ public void setSshConnectTimeout(Integer sshConnectTimeout) {
+ this.sshConnectTimeout = sshConnectTimeout;
+ }
+
+ public Integer getSshKexTimeout() {
+ return sshKexTimeout;
+ }
+
+ public void setSshKexTimeout(Integer sshKexTimeout) {
+ this.sshKexTimeout = sshKexTimeout;
+ }
+
+ public Integer getSshExecTimeout() {
+ return sshExecTimeout;
+ }
+
+ public void setSshExecTimeout(Integer sshExecTimeout) {
+ this.sshExecTimeout = sshExecTimeout;
+ }
+}
diff --git a/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/StatsFactory.java b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/StatsFactory.java
new file mode 100644
index 00000000..f856c05a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/org/gluster/storage/management/gateway/utils/StatsFactory.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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 org.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.gluster.storage.management.core.model.ServerStats;
+
+
+/**
+ *
+ */
+public interface StatsFactory {
+ public ServerStats fetchStats(String serverName, String period, String...args);
+ public ServerStats fetchAggregatedStats(List<String> serverName, String period);
+}
diff --git a/src/org.gluster.storage.management.gateway/src/rebel.xml b/src/org.gluster.storage.management.gateway/src/rebel.xml
new file mode 100644
index 00000000..08707b75
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/rebel.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
+
+ <classpath>
+ <dir name="${rebel.workspace.path}/console/src/org.gluster.storage.management.gateway/WebContent/WEB-INF/classes">
+ </dir>
+ </classpath>
+
+ <web>
+ <link target="/">
+ <dir name="${rebel.workspace.path}/console/src/org.gluster.storage.management.gateway/WebContent">
+ </dir>
+ </link>
+ </web>
+
+</application>
diff --git a/src/org.gluster.storage.management.gateway/src/spring/gluster-server-base.xml b/src/org.gluster.storage.management.gateway/src/spring/gluster-server-base.xml
new file mode 100644
index 00000000..ea3754f5
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/spring/gluster-server-base.xml
@@ -0,0 +1,100 @@
+
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
+ http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+ <context:component-scan base-package="org.gluster.storage.management.gateway" />
+ <task:scheduler id="taskScheduler" />
+ <task:executor id="taskExecutor" pool-size="1" />
+ <task:annotation-driven executor="taskExecutor" scheduler="taskScheduler" />
+
+ <!-- Syncs discovered servers and cluster-server mapping. -->
+ <task:scheduled-tasks>
+ <task:scheduled ref="serverSyncTask" method="perform" fixed-delay="60000" />
+ </task:scheduled-tasks>
+
+ <!-- This task keeps checking status of disk migration tasks (wherever auto-commit is set to true)
+ so that auto-commit can be performed as soon as the migration is complete -->
+ <!-- task:scheduled-tasks>
+ <task:scheduled ref="brickMigrationStatusTask" method="checkMigrationStatus" fixed-delay="60000" />
+ </task:scheduled-tasks-->
+
+ <!-- Discovery mechanism. Valid values: multicast, none -->
+ <bean id="discoveryMechanism" class="java.lang.String">
+ <constructor-arg value="multicast" />
+ </bean>
+
+ <!-- SSH timeouts - all in milliseconds. zero means no timeout. -->
+ <!-- Connect the underlying TCP socket to the server with the given timeout value (SSH) -->
+ <bean id="sshConnectTimeout" class="java.lang.Integer">
+ <constructor-arg value="10000" />
+ </bean>
+ <!-- Timeout for complete connection establishment (SSH) -->
+ <bean id="sshKexTimeout" class="java.lang.Integer">
+ <constructor-arg value="60000" />
+ </bean>
+ <!-- Command execution timeout (SSH) -->
+ <bean id="sshExecTimeout" class="java.lang.Integer">
+ <constructor-arg value="120000" />
+ </bean>
+
+ <!-- Gluster Management Gateway Version -->
+ <bean id="appVersion" class="java.lang.String">
+ <constructor-arg value="1.0.0" />
+ </bean>
+
+ <!-- Derby embedded data source -->
+ <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="false">
+ <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
+ <property name="url" value="jdbc:derby:/opt/glustermg/data;create=true" />
+ <property name="username" value="gluster" />
+ <property name="password" value="syst3m" />
+ </bean>
+
+ <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+ <property name="dataSource" ref="dataSource" />
+ <property name="jpaVendorAdapter">
+ <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
+ <property name="showSql" value="true" />
+ <property name="generateDdl" value="false" />
+ <property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect" />
+ </bean>
+ </property>
+ </bean>
+
+ <bean
+ class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
+
+ <bean id="clusterDao" class="org.gluster.storage.management.gateway.data.PersistenceDao">
+ <constructor-arg type="java.lang.Class">
+ <value>org.gluster.storage.management.gateway.data.ClusterInfo</value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="serverDao" class="org.gluster.storage.management.gateway.data.PersistenceDao">
+ <constructor-arg type="java.lang.Class">
+ <value>org.gluster.storage.management.gateway.data.ServerInfo</value>
+ </constructor-arg>
+ </bean>
+
+ <!-- bean id="dataSourceFactory" class="org.gluster.storage.management.gateway.data.GlusterDataSource" />
+ <bean id="dataSource" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+ <property name="targetObject">
+ <ref local="dataSourceFactory" />
+ </property>
+ <property name="targetMethod">
+ <value>getDataSource</value>
+ </property>
+ </bean -->
+
+ <!-- bean id="dataSource" class="org.gluster.storage.management.gateway.data.GlusterDataSource"
+ lazy-init="false" autowire="byType" / -->
+
+ <bean class="org.gluster.storage.management.gateway.tasks.InitServerTask" init-method="initServer" depends-on="dataSource">
+ <property name="dataSource" ref="dataSource" />
+ </bean>
+</beans> \ No newline at end of file
diff --git a/src/org.gluster.storage.management.gateway/src/spring/gluster-server-security.xml b/src/org.gluster.storage.management.gateway/src/spring/gluster-server-security.xml
new file mode 100644
index 00000000..e160d31a
--- /dev/null
+++ b/src/org.gluster.storage.management.gateway/src/spring/gluster-server-security.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/security"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
+ xmlns:jdbc="http://www.springframework.org/schema/jdbc"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
+ http://www.springframework.org/schema/security
+ http://www.springframework.org/schema/security/spring-security-3.0.xsd
+ ">
+
+ <http auto-config="true" use-expressions="true">
+ <!-- SSL Protection -->
+ <intercept-url pattern="/1.0.0/**" access="hasRole('ROLE_ADMIN') and fullyAuthenticated" requires-channel="https" />
+ <intercept-url pattern="*.jnlp" access="hasRole('ROLE_ADMIN') and fullyAuthenticated" requires-channel="any" />
+ <!-- intercept-url pattern="/*" access="permitAll" requires-channel="any" / -->
+ <port-mappings>
+ <port-mapping http="8080" https="8443" />
+ </port-mappings>
+
+ <!-- HTTP basic authentication -->
+ <http-basic />
+ </http>
+
+ <beans:bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
+ <beans:property name="userPropertyToUse" value="username" />
+ </beans:bean>
+
+ <beans:bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder">
+ <beans:constructor-arg value="256" />
+ </beans:bean>
+
+ <authentication-manager alias="authenticationManager">
+ <authentication-provider user-service-ref="jdbcUserService">
+ <!-- Passwords are SHA encrypted -->
+ <password-encoder ref="passwordEncoder" hash="sha">
+ <salt-source ref="saltSource" />
+ </password-encoder>
+ </authentication-provider>
+ </authentication-manager>
+
+ <beans:bean id="jdbcUserService"
+ class="org.springframework.security.provisioning.JdbcUserDetailsManager"
+ lazy-init="false">
+ <beans:property name="dataSource" ref="dataSource" />
+ <beans:property name="authenticationManager" ref="authenticationManager" />
+ </beans:bean>
+</beans:beans> \ No newline at end of file