summaryrefslogtreecommitdiffstats
path: root/src/com.gluster.storage.management.gateway
diff options
context:
space:
mode:
authorShireesh Anjal <shireesh@gluster.com>2011-08-01 11:54:01 +0530
committerShireesh Anjal <shireesh@gluster.com>2011-08-01 11:54:01 +0530
commit0d12b25f91cfcbb09687d774389d85b8c8ffa249 (patch)
tree2d0dd66c137f207c0cecbf583b873d8b9a9f76c7 /src/com.gluster.storage.management.gateway
parentdda8f6f9845787a16835cef9771263040add8216 (diff)
Renamed project and package com.gluster.storage.management.server to com.gluster.storage.management.gateway
Diffstat (limited to 'src/com.gluster.storage.management.gateway')
-rw-r--r--src/com.gluster.storage.management.gateway/.classpath15
-rw-r--r--src/com.gluster.storage.management.gateway/.project41
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/.jsdtscope12
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs3
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component10
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml20
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container1
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name1
-rw-r--r--src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs3
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF3
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jarbin0 -> 443432 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jarbin0 -> 4467 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jarbin0 -> 43033 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jarbin0 -> 559366 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jarbin0 -> 60841 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jarbin0 -> 2512189 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jarbin0 -> 165188 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jarbin0 -> 313898 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt87
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jarbin0 -> 248915 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jarbin0 -> 100884 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jarbin0 -> 4133342 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jarbin0 -> 171958 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jarbin0 -> 17065 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jarbin0 -> 485699 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jarbin0 -> 24745 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jarbin0 -> 633312 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jarbin0 -> 128096 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jarbin0 -> 455665 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jarbin0 -> 144810 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jarbin0 -> 49330 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jarbin0 -> 681117 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jarbin0 -> 17079 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jarbin0 -> 67758 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jarbin0 -> 61712 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jarbin0 -> 46367 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jarbin0 -> 10899 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jarbin0 -> 481534 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jarbin0 -> 38683 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jarbin0 -> 101958 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jarbin0 -> 321190 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jarbin0 -> 53082 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jarbin0 -> 35548 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jarbin0 -> 555410 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jarbin0 -> 668861 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jarbin0 -> 100870 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jarbin0 -> 382442 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jarbin0 -> 169752 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jarbin0 -> 1810 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jarbin0 -> 5728 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jarbin0 -> 385712 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jarbin0 -> 185312 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jarbin0 -> 334327 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jarbin0 -> 61379 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd21
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jarbin0 -> 205278 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jarbin0 -> 231922 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jarbin0 -> 395587 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jarbin0 -> 175412 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jarbin0 -> 418977 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jarbin0 -> 31404 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.client_1.0.0.jarbin0 -> 513103 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.core_1.0.0.jarbin0 -> 50608 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jarbin0 -> 176386 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jarbin0 -> 25496 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jarbin0 -> 185716 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jarbin0 -> 311038 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jarbin0 -> 242833 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml73
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql2
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql26
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql21
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql16
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/index.html8
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/scripts/Globals.py123
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/scripts/Protocol.py438
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/scripts/Utils.py1059
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py346
-rwxr-xr-xsrc/com.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py66
-rwxr-xr-xsrc/com.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py53
-rwxr-xr-xsrc/com.gluster.storage.management.gateway/WebContent/scripts/grun.py36
-rwxr-xr-xsrc/com.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py90
-rw-r--r--src/com.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystorebin0 -> 1380 bytes
-rw-r--r--src/com.gluster.storage.management.gateway/buckminster.cspex37
-rw-r--r--src/com.gluster.storage.management.gateway/build/glusterserver.ant65
-rw-r--r--src/com.gluster.storage.management.gateway/src/META-INF/persistence.xml5
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java118
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ClusterInfo.java79
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java48
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/PersistenceDao.java113
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ServerInfo.java72
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuditFilter.java38
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java105
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java31
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java177
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java126
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java150
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java54
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java487
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java153
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java194
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java91
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java989
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java31
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/UserAuthDao.java42
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/ClusterService.java269
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java165
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java162
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java164
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java227
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java129
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java154
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/Task.java112
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java169
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java36
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java662
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java68
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java123
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/ServerUtil.java286
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/SshUtil.java388
-rw-r--r--src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/StatsFactory.java31
-rw-r--r--src/com.gluster.storage.management.gateway/src/log4j.properties19
-rw-r--r--src/com.gluster.storage.management.gateway/src/spring/gluster-server-base.xml100
-rw-r--r--src/com.gluster.storage.management.gateway/src/spring/gluster-server-security.xml43
125 files changed, 9094 insertions, 0 deletions
diff --git a/src/com.gluster.storage.management.gateway/.classpath b/src/com.gluster.storage.management.gateway/.classpath
new file mode 100644
index 00000000..107e139d
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/.classpath
@@ -0,0 +1,15 @@
+<?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="/com.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 exported="true" kind="lib" path="/com.gluster.storage.management.client/lib/jersey-1.5/jersey-multipart-1.5.jar"/>
+ <classpathentry kind="output" path="WebContent/WEB-INF/classes"/>
+</classpath>
diff --git a/src/com.gluster.storage.management.gateway/.project b/src/com.gluster.storage.management.gateway/.project
new file mode 100644
index 00000000..3e4dc06a
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/.project
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.gluster.storage.management.gateway</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.python.pydev.PyDevBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <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/com.gluster.storage.management.gateway/.settings/.jsdtscope b/src/com.gluster.storage.management.gateway/.settings/.jsdtscope
new file mode 100644
index 00000000..3a28de0c
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..476db350
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 00000000..5d9c71b6
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.component
new file mode 100644
index 00000000..3d5a50bf
--- /dev/null
+++ b/src/com.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="com.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="/com.gluster.storage.management.gateway/build/classes"/>
+ <property name="context-root" value="glustermg"/>
+ </wb-module>
+</project-modules>
diff --git a/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 00000000..8f960f27
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 00000000..3bd5d0a4
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 00000000..05bd71b6
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs b/src/com.gluster.storage.management.gateway/.settings/org.eclipse.wst.ws.service.policy.prefs
new file mode 100644
index 00000000..e5ca6272
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF b/src/com.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..5e949512
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar
new file mode 100644
index 00000000..3702b645
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/antlr-2.7.6.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar
new file mode 100644
index 00000000..578b1a0c
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/aopalliance-1.0.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar
new file mode 100644
index 00000000..8217cae0
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/asm-3.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar
new file mode 100644
index 00000000..41e230fe
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-collections-3.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/commons-logging-1.1.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar
new file mode 100644
index 00000000..dc8ae8df
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derby.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar
new file mode 100644
index 00000000..ca367aae
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/derbytools.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar
new file mode 100644
index 00000000..c8c4dbb9
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/dom4j-1.6.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250-LICENSE.txt
new file mode 100644
index 00000000..3eddd42f
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
new file mode 100644
index 00000000..c0a9ac7b
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/ganymed-ssh2-build250.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar b/src/com.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/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar
new file mode 100644
index 00000000..c1c81141
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/hibernate3.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-core-asl-1.5.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-jaxrs-1.5.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-mapper-asl-1.5.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jackson-xc-1.5.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/javassist-3.12.0.GA.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar
new file mode 100644
index 00000000..62f790fa
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-client-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar
new file mode 100644
index 00000000..92b38466
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-core-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar
new file mode 100644
index 00000000..01d8c83b
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-json-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar
new file mode 100644
index 00000000..1c134f05
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-multipart-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar
new file mode 100644
index 00000000..a29d7409
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-server-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar
new file mode 100644
index 00000000..c79b4490
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jersey-spring-1.5.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar
new file mode 100644
index 00000000..e4e9c8c3
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jettison-1.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar
new file mode 100644
index 00000000..23782c02
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jnlp-servlet.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jsr311-api-1.1.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar
new file mode 100644
index 00000000..6d225b76
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/jta-1.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar
new file mode 100644
index 00000000..3f9d8476
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/log4j-1.2.16.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar
new file mode 100644
index 00000000..48cc9295
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/mimepull-1.3.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aop-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.asm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.aspects-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.beans-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.context.support-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.core-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.expression-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.instrument.tomcat-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jdbc-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.jms-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.orm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.oxm-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.spring-library-3.0.5.RELEASE.libd b/src/com.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/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.test-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.transaction-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.portlet-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.servlet-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/org.springframework.web.struts-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.client_1.0.0.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.client_1.0.0.jar
new file mode 100644
index 00000000..56222cbf
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.client_1.0.0.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.core_1.0.0.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.core_1.0.0.jar
new file mode 100644
index 00000000..d321e76c
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/plugins/com.gluster.storage.management.core_1.0.0.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar
new file mode 100644
index 00000000..e5bc672b
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/servlet-api.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/slf4j-api-1.6.1.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-config-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-core-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jar b/src/com.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/com.gluster.storage.management.gateway/WebContent/WEB-INF/lib/spring-security-web-3.0.5.RELEASE.jar
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml
new file mode 100644
index 00000000..631788ff
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/WEB-INF/web.xml
@@ -0,0 +1,73 @@
+<?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>
+ <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>com.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>com.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/*</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/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql b/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/0-version.sql
new file mode 100644
index 00000000..4c3d81d1
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql b/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql
new file mode 100644
index 00000000..fdde5823
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/1-security-schema.sql
@@ -0,0 +1,26 @@
+create table users(
+ username varchar(50) not null primary key,
+ password varchar(50) not null,
+ enabled smallint not null
+ );
+
+ create table authorities (
+ username varchar(50) 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(50) not null,
+ group_id bigint not null,
+ constraint fk_group_members_group foreign key(group_id) references groups(id));
diff --git a/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql b/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql
new file mode 100644
index 00000000..35ccf965
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/2-users-authorities-groups.sql
@@ -0,0 +1,21 @@
+-- Create users
+insert into users(username, password, enabled) values ('gluster','gluster',1);
+insert into users(username, password, enabled) values ('guest','guest',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');
+insert into authorities(username,authority) values ('guest','ROLE_USER');
+
+-- 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,'guest' from groups where group_name='Users';
+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/com.gluster.storage.management.gateway/WebContent/data/scripts/1.0.0/3-cluster-servers.sql b/src/com.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/com.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/com.gluster.storage.management.gateway/WebContent/index.html b/src/com.gluster.storage.management.gateway/WebContent/index.html
new file mode 100644
index 00000000..4c90162a
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>Gluster Management Console</title>
+</head>
+<body>
+TODO: Identify the client's platform-browser and invoke appropriate JNLP URL.
+</body>
+</html>
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/Globals.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/Globals.py
new file mode 100644
index 00000000..f8a07c25
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/Globals.py
@@ -0,0 +1,123 @@
+# Copyright (C) 2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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, see
+# <http://www.gnu.org/licenses/>.
+
+MULTICAST_GROUP = '224.224.1.1'
+MULTICAST_PORT = 5353
+GLUSTER_PLATFORM_VERSION = "3.2"
+
+## System configuration constants
+SYSCONFIG_NETWORK_DIR = "/etc/sysconfig/network-scripts"
+DNSMASQ_CONF_DIR = "/etc/dnsmasq.d"
+
+FSTAB_FILE = "/etc/fstab"
+NFS_EXPORTS_FILE = "/etc/exports"
+SAMBA_CONF_FILE = "/etc/samba/smb.conf"
+TIMEZONE_FILE = "/etc/timezone"
+ZONEINFO_DIR = "/usr/share/zoneinfo"
+LOCALTIME_FILE = "/etc/localtime"
+KERBEROS_CONF_FILE = "/etc/krb5.conf"
+NSSWITCH_CONF_FILE = "/etc/nsswitch.conf"
+NTP_CONF_FILE = "/etc/ntp.conf"
+MODPROBE_CONF_FILE = "/etc/modprobe.d/bonding.conf"
+SYSCONFIG_NETWORK_FILE = "/etc/sysconfig/network"
+RESOLV_CONF_FILE = "/etc/resolv.conf"
+DNSMASQ_LEASE_FILE = "/var/tmp/dnsmasq.leases"
+LIVE_MODE_FILE = "/etc/live"
+ADD_SERVER_COMPLETED_FILE = "/var/tmp/installation-completed"
+
+DNSMASQ_DNS_CONF_FILE = DNSMASQ_CONF_DIR + "/dns.conf"
+DNSMASQ_DHCP_CONF_FILE = DNSMASQ_CONF_DIR + "/dhcp.conf"
+##
+
+## Base constants
+MAX_PARTITION_SIZE = 16777216 # 16 TB
+OS_PARTITION_SIZE = 4000 # 4 GB
+SESSION_TIMEOUT = 1800 # 30 minutes
+SERVER_AGENT_PORT = 50000
+
+BOOT_PARTITION_LABEL = "GLUSTEROS"
+DATA_PARTITION_LABEL = "GLUSTERDATA"
+VOLUME_USER_DESCRIPTION = "Gluster Volume User"
+SERVER_AGENT_RUN_USERNAME = "gluster"
+INSTALLER_SERVER_NAME = "$installer$"
+
+GLUSTER_BASE_DIR = "/etc/glustermg"
+GLUSTER_LUN_DIR = "/data"
+REEXPORT_DIR = "/reexport"
+NFS_EXPORT_DIR = "/nfs"
+CIFS_EXPORT_DIR = "/cifs"
+WEBDAV_DOCUMENT_ROOT_DIR = "/var/www/html"
+UPDATES_DIR = "/UPDATES"
+TRANSPORT_HOME_DIR = "/transport"
+GLUSTERFS_LOG_DIR = "/var/log/glusterfs"
+LOG_DIR = "/var/log/glustermg"
+
+GLUSTER_UPDATES_FILE = "updates.xml"
+INSTALLER_STATUS_FILE = "/var/log/install-server-status.log"
+INSTALL_PLATFORM_LOCK_FILE = "/var/lock/install-gluster-platform.lock"
+LAST_ACCESSED_NETWORK_FILE = "last-accessed-network"
+PREPARE_DATA_DISK_LOCK_FILE = "/var/tmp/prepare-data-disk.lock"
+##
+
+## Derived constants
+GLUSTER_CONF_DIR = GLUSTER_BASE_DIR + "/conf"
+GLUSTER_TMP_DIR = GLUSTER_BASE_DIR + "/tmp"
+VOLUME_CONF_DIR = GLUSTER_BASE_DIR + "/volumes"
+SERVER_CONF_DIR = GLUSTER_BASE_DIR + "/servers"
+DNS_RECORDS_DIR = GLUSTER_BASE_DIR + "/dns-records"
+INSTALLER_CONF_DIR = SERVER_CONF_DIR + "/" + INSTALLER_SERVER_NAME
+
+GSN_USER_INFO_FILE = GLUSTER_BASE_DIR + "/gsn-user.info"
+GLUSTER_VERSION_FILE = GLUSTER_BASE_DIR + "/version"
+GLUSTER_UPDATE_SITE_FILE = GLUSTER_BASE_DIR + "/update-site"
+GLUSTER_DIRECTORY_SERVICE_CONF_FILE = GLUSTER_BASE_DIR + "/directory.xml"
+GLUSTER_TIME_CONF_FILE = GLUSTER_BASE_DIR + "/timeconfig.xml"
+TRANSACTION_KEY_FILE = GLUSTER_BASE_DIR + "/transaction.key"
+SERVER_COUNT_FILE = GLUSTER_BASE_DIR + "/server-count"
+SIGNATURE_FILE = GLUSTER_BASE_DIR + "/.signature"
+GLUSTER_SERVER_POOL_FILE = GLUSTER_BASE_DIR + "/pool"
+GLUSTER_ADMIN_FILE = GLUSTER_BASE_DIR + "/.password"
+
+VOLUME_SMBCONF_FILE = VOLUME_CONF_DIR + "/volumes.smbconf.list"
+
+GLOBAL_NETWORK_FILE = INSTALLER_CONF_DIR + "/network.xml"
+INSTALL_SERVER_CONF_FILE = INSTALLER_CONF_DIR + "/installer.xml"
+INSTALLER_INFO_FILE = INSTALLER_CONF_DIR + "/installer.info"
+INSTALLED_SERVER_COUNT_FILE = INSTALLER_CONF_DIR + "/installed-server-count"
+
+SESSION_FILE = GLUSTER_TMP_DIR + "/login.sessions"
+
+GENERAL_LOG_FILE = LOG_DIR + "/general.log"
+INSTALLER_LOG_FILE = LOG_DIR + "/installer.log"
+PEER_AGENT_LOG_FILE = LOG_DIR + "/peeragent.log"
+SERVER_AGENT_LOG_FILE = LOG_DIR + "/serveragent.log"
+TRANSPORT_AGENT_LOG_FILE = LOG_DIR + "/transport.log"
+##
+
+
+## Global variables
+## TODO: These should be removed
+DOWNLOAD_GLUSTER_UPDATE_PROCESS = None
+DOWNLOAD_GLUSTER_UPDATE_LEVEL = None
+DOWNLOAD_GLUSTER_CURRENT_UPDATE_LEVEL = None
+DOWNLOAD_GLUSTER_UPDATE_MD5SUM = None
+REQUEST_MAP = {}
+VERSION_DICTONARY = {}
+##
+
+AWS_WEB_SERVICE_URL = "http://169.254.169.254/latest"
+REAL_SAMBA_CONF_FILE = "/etc/samba/real.smb.conf"
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/Protocol.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/Protocol.py
new file mode 100644
index 00000000..ff073593
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/Protocol.py
@@ -0,0 +1,438 @@
+# Copyright (C) 2009 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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, see
+# <http://www.gnu.org/licenses/>.
+
+import xml
+import xml.parsers.expat
+import xml.dom.minidom as MDOM
+import os
+import Globals
+import copy
+import Utils
+
+XML_STRING = 0
+XML_FILE = 1
+
+class XDOM:
+ _domObj = None
+
+ def __init__(self):
+ self._domObj = MDOM.Document()
+ return
+
+ @classmethod
+ def getText(self, nodeList):
+ rc = ""
+ for node in nodeList:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc.strip()
+
+ def parseString(self, requestString):
+ try:
+ self._domObj = MDOM.parseString(requestString)
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML string parse error: %s" % str(e))
+ return False
+ return True
+
+ def parseFile(self, fileName):
+ try:
+ self._domObj = MDOM.parse(fileName)
+ except IOError, e:
+ Utils.log("error reading file: %s" % str(e))
+ return False
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML file %s parse error: %s" % (fileName, str(e)))
+ return False
+ return True
+
+ def setDomObj(self, dom):
+ if dom and type(dom) != type([]):
+ self._domObj = dom
+ return True
+ return False
+
+ def createTextNode(self, text):
+ if not self._domObj:
+ return False
+ if not text:
+ return False
+ return self._domObj.createTextNode(str(text))
+
+ def createTag(self, tag, text=None):
+ if not self._domObj:
+ return None
+ if tag == None:
+ return None
+
+ tagE = self._domObj.createElement(str(tag))
+ if text:
+ tagEText = self._domObj.createTextNode(str(text))
+ tagE.appendChild(tagEText)
+ return tagE
+
+ def addTag(self, tag):
+ if not self._domObj:
+ return False
+ if not tag:
+ return False
+
+ self._domObj.appendChild(tag)
+ return True
+
+ def createTagRoute(self, tagRoute, text=None):
+ if not tagRoute:
+ return False
+
+ tagList = tagRoute.split(".")
+ tag = None
+ previousTag = None
+ for tagName in tagList[:-1]:
+ newTag = self.createTag(tagName, None)
+ if not tag:
+ tag = newTag
+ previousTag = newTag
+ continue
+ previousTag.appendChild(newTag)
+ previousTag = newTag
+
+ if previousTag:
+ previousTag.appendChild(self.createTag(tagList[-1], text))
+ else:
+ tag = self.createTag(tagList[-1], text)
+ return tag
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._domObj:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._domObj
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+
+ def setTextByTagRoute(self, tagRoute, tagValue):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ tagE = self.getElementsByTagRoute(tagRoute)
+ if not tagE:
+ return False
+
+ parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1]))
+ if not parentTagE:
+ return False
+
+ parentTagE[0].childNodes.remove(tagE[0])
+ parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue))
+ return True
+
+ def getElementsByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ x = None
+ for tag in tagRoute.split("."):
+ if x is None:
+ x = self._domObj.getElementsByTagName(tag)
+ continue
+ if x == []:
+ break
+ x = x[0].getElementsByTagName(tag)
+ return x
+
+ def getTextByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ x = self.getElementsByTagRoute(tagRoute)
+ if x:
+ return self.getText(x[0].childNodes)
+ return None
+
+ def getElementsByTagName(self, name):
+ if not self._domObj:
+ return None
+ return self._domObj.getElementsByTagName(name)
+
+ def writexml(self, fileName, indent="", addindent="", newl=""):
+ if not self._domObj:
+ return None
+ try:
+ fp = open(fileName, "w")
+ self._domObj.writexml(fp, indent, addindent, newl)
+ fp.close()
+ return True
+ except IOError:
+ return False
+
+ def toString(self, indent=" ", newl="\n", encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toprettyxml(indent, newl, encoding)
+
+ def toxml(self, encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toxml(encoding)
+
+ def toprettyxml(self, indent=" ", newl="\n", encoding = None):
+ return self.toString(indent, newl, encoding)
+
+ def getAttribute(self, attributeName):
+ if not attributeName:
+ return None
+ try:
+ return self.getElementsByTagName("command")[0].getAttribute(attributeName)
+ except IndexError:
+ return False
+
+ def setAttribute(self, attributeName, attributeValue):
+ if not (attributeName and attributeValue):
+ return None
+ try:
+ return self.getElementsByTagName("command")[0].setAttribute(attributeName, attributeValue)
+ except IndexError:
+ return False
+
+ def getRequestCommand(self):
+ return self.getAttribute("request")
+
+ def getResponseCommand(self):
+ return self.getAttribute("response")
+
+ def getResponseCode(self):
+ return self.getAttribute("response-code")
+
+ def getMessageId(self):
+ return self.getAttribute("id")
+
+ def getVersion(self):
+ return self.getAttribute("version")
+
+ def getRequestAction(self):
+ return self.getAttribute("action")
+
+ def setVersion(self, value):
+ return self.setAttribute("version", value)
+
+ def setRequestAction(self, value):
+ return self.setAttribute("action", value)
+
+ def createCommandTag(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION):
+ commandTag = self._domObj.createElement("command")
+ commandTag.setAttribute("response", command)
+ commandTag.setAttribute("response-code", responseCode)
+ commandTag.setAttribute("id", id)
+ commandTag.setAttribute("version", version)
+ return commandTag
+##--end of XDOM
+
+class RequestXml(XDOM):
+ def __init__(self, requestString, type=None):
+ if None == requestString:
+ XDOM.__init__(self)
+ return
+ try:
+ if None == type:
+ if os.path.isfile(requestString):
+ self._domObj = MDOM.parse(requestString)
+ else:
+ self._domObj = MDOM.parseString(requestString)
+ elif XML_FILE == type:
+ self._domObj = MDOM.parse(requestString)
+ elif XML_STRING == type:
+ self._domObj = MDOM.parseString(requestString)
+ except IOError:
+ XDOM.__init__(self)
+ except xml.parsers.expat.ExpatError:
+ XDOM.__init__(self)
+
+##--end of RequestXML
+
+class ResponseXml(XDOM):
+ _commandTag = None
+ def __init__(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION):
+ XDOM.__init__(self)
+ if command and responseCode and id:
+ self._commandTag = self.createCommandTag(command, responseCode, id, version)
+ self._domObj.appendChild(self._commandTag)
+
+ def appendCommand(self, command, responseCode, id, version=Globals.GLUSTER_PLATFORM_VERSION):
+ if command and responseCode and id:
+ self._commandTag = self.createCommandTag(command, responseCode, id, version)
+ self._domObj.appendChild(self._commandTag)
+ return True
+ return False
+
+ def append(self, tagName, tagValue=None):
+ if not self._commandTag:
+ return False
+ tag = self.createTag(tagName, tagValue)
+ if tag:
+ self._commandTag.appendChild(tag)
+ return True
+ return False
+
+ def appendTag(self, tag):
+ if not tag:
+ return False
+ if not self._commandTag:
+ return False
+ self._commandTag.appendChild(tag)
+ return True
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._commandTag:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._commandTag
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(["command"] + tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+
+ def appendTagRouteOld(self, tagRoute, value=None):
+ if not tagRoute:
+ return False
+ if not self._commandTag:
+ return False
+
+ tmpTagRoute = ""
+ previousTagE = self._commandTag
+ tagE = None
+ for tagName in tagRoute.split("."):
+ if not tmpTagRoute:
+ tagE = self.getElementsByTagRoute("command." + tagName)
+ else:
+ tagE = self.getElementsByTagRoute("command." + tmpTagRoute + "." + tagName)
+ if not tagE:
+ break
+ if len(tagE) != 1:
+ return False
+ previousTagE = tagE[0]
+ if not tmpTagRoute:
+ tmpTagRoute = tagName
+ else:
+ tmpTagRoute = tmpTagRoute + "." + tagName
+
+ if tmpTagRoute == tagRoute:
+ return False
+ newTagRoute = tagRoute[len(tmpTagRoute):]
+ if newTagRoute[0] == '.':
+ newTagRoute = newTagRoute[1:]
+
+ if previousTagE.childNodes and previousTagE.childNodes[0].nodeType == previousTagE.TEXT_NODE:
+ return False
+ previousTagE.appendChild(self.createTagRoute(newTagRoute, value))
+ return True
+##--end of ResponseXml
+
+def test():
+ #volumes = RequestXml(VolumeFile, XML_FILE).getElementsByTagRoute("volume-list.volume")
+ requestStr = '''<command request="create-volume" id="123" version="3.1">
+<volume>
+<name>movies1</name>
+<type>cluster mirror</type>
+<start>512000</start>
+<server>zresearch</server>
+<vacl>192.168.20.*</vacl>
+<vacl>192.168.30.*</vacl>
+<nfs>
+<export>no</export>
+</nfs>
+<cifs>
+<export>no</export>
+</cifs>
+<webdav>
+<export>no</export>
+</webdav>
+</volume>
+</command>'''
+
+ requestXml = RequestXml(requestStr)
+ print requestXml.getAttribute("")
+
+def test1():
+ rs = ResponseXml("create-volume", "OK", "xyz")
+ rs.appendTagRoute("volume.detail.name", "music")
+ print rs.toprettyxml()
+ rs.append("volume", "data")
+ print rs.toprettyxml()
+ rs.appendTagRoute("volume.detail.ipaddr", "192.168.10.1")
+ print rs.toprettyxml()
+ print rs.appendTagRoute("volume.detail.ipaddr.v6", "ff:ff::ff::")
+ print rs.toprettyxml()
+
+ print rs.getTextByTagRoute("command.volume.detail")
+
+def test2():
+ rs = ResponseXml("download-volume-logs", "OK", "xyz")
+ te = rs.createTag("interface", None)
+ te.appendChild(rs.createTag("device", "DEVICE1"))
+ te.appendChild(rs.createTag("description", "my device one"))
+ rs.appendTag(te)
+
+ te = rs.createTag("interface", None)
+ te.appendChild(rs.createTag("device", "DEVICE2"))
+ te.appendChild(rs.createTag("description", "my device two"))
+ rs.appendTag(te)
+ print rs.toprettyxml()
+
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/Utils.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/Utils.py
new file mode 100644
index 00000000..3408c14a
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/Utils.py
@@ -0,0 +1,1059 @@
+# Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import re
+import socket
+import struct
+import syslog
+import subprocess
+#import spwd
+import time
+#import uuid
+import tempfile
+import grp
+import pwd
+import inspect
+from datetime import datetime
+import urllib
+
+import Globals
+import Protocol
+
+RUN_COMMAND_ERROR = -1024
+LOG_SYSLOG = 1
+SYSLOG_REQUIRED = False
+LOG_FILE_NAME = None
+LOG_FILE_OBJ = None
+
+
+def _getLogCode(priority):
+ if syslog.LOG_EMERG == priority:
+ return "M"
+ elif syslog.LOG_ALERT == priority:
+ return "A"
+ elif syslog.LOG_CRIT == priority:
+ return "C"
+ elif syslog.LOG_ERR == priority:
+ return "E"
+ elif syslog.LOG_WARNING == priority:
+ return "W"
+ elif syslog.LOG_NOTICE == priority:
+ return "N"
+ elif syslog.LOG_INFO == priority:
+ return "I"
+ elif syslog.LOG_DEBUG == priority:
+ return "D"
+ else: # UNKNOWN
+ return "X"
+
+
+def setLogFile(fileName):
+ global LOG_FILE_NAME
+
+ if fileName:
+ LOG_FILE_NAME = fileName
+ return True
+ return False
+
+
+def closeLog():
+ global LOG_FILE_OBJ
+ global SYSLOG_REQUIRED
+
+ if SYSLOG_REQUIRED:
+ syslog.closelog()
+ SYSLOG_REQUIRED = False
+ return True
+
+ if LOG_FILE_OBJ:
+ try:
+ LOG_FILE_OBJ.close()
+ LOG_FILE_OBJ = None
+ except IOError, e:
+ sys.stderr.write("Failed to close file: %s\n" % e)
+ return False
+ return True
+
+
+def openLog(fileName=None):
+ global LOG_FILE_NAME
+ global LOG_FILE_OBJ
+ global SYSLOG_REQUIRED
+
+ if fileName == LOG_SYSLOG:
+ syslog.openlog(os.path.basename(sys.argv[0]))
+ SYSLOG_REQUIRED = True
+ return True
+
+ if fileName:
+ LOG_FILE_NAME = fileName
+
+ if not LOG_FILE_NAME:
+ return False
+
+ closeLog()
+
+ try:
+ LOG_FILE_OBJ = open(LOG_FILE_NAME, "a")
+ except IOError, e:
+ sys.stderr.write("Failed to open file %s: %s\n" % (LOG_FILE_NAME, e))
+ return False
+ return True
+
+def record(priority, message=None):
+ global LOG_FILE_OBJ
+ global SYSLOG_REQUIRED
+
+ stack = inspect.stack()[1]
+ if stack[3] == "<module>":
+ prefix = "%s:%s:%s" % (stack[1], stack[2], stack[3])
+ else:
+ prefix = "%s:%s:%s()" % (stack[1], stack[2], stack[3])
+
+ if type(priority) == type("") or type(priority) == type(u""):
+ logPriority = syslog.LOG_INFO
+ logMessage = priority
+ else:
+ logPriority = priority
+ logMessage = message
+
+ if SYSLOG_REQUIRED:
+ syslog.syslog(logPriority, "[%s]: %s" % (prefix, logMessage))
+ return
+
+ fp = sys.stderr
+ if LOG_FILE_OBJ:
+ fp = LOG_FILE_OBJ
+
+ fp.write("[%s] %s [%s]: %s" % (str(datetime.now()), _getLogCode(logPriority), prefix, logMessage))
+ if logMessage[-1] != '\n':
+ fp.write("\n")
+ fp.flush()
+ return
+
+
+def trace(message):
+ if message:
+ log(syslog.LOG_DEBUG, message)
+
+
+def isString(value):
+ return (type(value) == type("") or type(value) == type(u""))
+
+
+def getTempFileName():
+ filedesc, filename = tempfile.mkstemp(prefix="GSP_")
+ os.close(filedesc)
+ return filename
+
+
+def runCommandBG(command, stdinFileObj=None, stdoutFileObj=None, stderrFileObj=None,
+ shell=False, root=None):
+ log("runCommandBG(): Trying to execute command [%s]" % command)
+
+ if shell:
+ if not isString(command):
+ return None
+ else:
+ if isString(command):
+ command = command.split()
+
+ if root == True:
+ if shell:
+ command = "sudo " + command
+ else:
+ command = ['sudo'] + command
+ elif isString(root):
+ if shell:
+ command = "sudo -u " + root + " " + command
+ else:
+ command = ['sudo', '-u', root] + command
+
+ if not stdinFileObj:
+ stdinFileObj=subprocess.PIPE
+ if not stdoutFileObj:
+ stdoutFileObj=subprocess.PIPE
+ if not stderrFileObj:
+ stderrFileObj=subprocess.PIPE
+
+ try:
+ process = subprocess.Popen(command,
+ bufsize=-1,
+ stdin=stdinFileObj,
+ stdout=stdoutFileObj,
+ stderr=stderrFileObj,
+ shell=shell)
+ return process
+ except OSError, e:
+ log("runCommandBG(): Failed to run command [%s]: %s" % (command, e))
+ return None
+
+
+def runCommand(command,
+ input='', output=False,
+ shell=False, root=None):
+ rv = {}
+ rv["Status"] = RUN_COMMAND_ERROR
+ rv["Stdout"] = None
+ rv["Stderr"] = None
+
+ try:
+ stdinFileName = getTempFileName()
+ stdinFileObj = open(stdinFileName, "w")
+ stdinFileObj.write(input)
+ stdinFileObj.close()
+ stdinFileObj = open(stdinFileName, "r")
+
+ stdoutFileName = getTempFileName()
+ stdoutFileObj = open(stdoutFileName, "w")
+
+ stderrFileName = getTempFileName()
+ stderrFileObj = open(stderrFileName, "w")
+ except IOError, e:
+ log("Failed to create temporary file for executing command [%s]: %s" % (command, e))
+ if output:
+ return rv
+ return rv["Status"]
+
+ stdoutContent = None
+ stderrContent = None
+
+ process = runCommandBG(command,
+ stdinFileObj=stdinFileObj,
+ stdoutFileObj=stdoutFileObj,
+ stderrFileObj=stderrFileObj,
+ shell=shell, root=root)
+ if process:
+ rv['Status'] = process.wait()
+ rv['Stdout'] = open(stdoutFileName).read()
+ rv['Stderr'] = open(stderrFileName).read()
+
+ os.remove(stdinFileName)
+ os.remove(stdoutFileName)
+ os.remove(stderrFileName)
+
+ log("runCommand(): execution status of command [%s] = [%s]" % (command, rv))
+
+ if output:
+ return rv
+ return rv["Status"]
+
+
+def runCommandFG(command, stdout=False, stderr=False,
+ shell=False, root=None):
+ if stdout or stderr:
+ output = True
+ else:
+ output = False
+ return runCommand(command, output=output, shell=shell, root=root)
+
+
+def IP2Number(ipString):
+ try:
+ return socket.htonl(struct.unpack("I", socket.inet_aton(ipString))[0])
+ except socket.error:
+ return None
+ except TypeError:
+ return None
+ except struct.error:
+ return None
+
+
+def Number2IP(number):
+ try:
+ return socket.inet_ntoa(struct.pack("I", socket.ntohl(number)))
+ except socket.error:
+ return None
+ except AttributeError:
+ return None
+ except ValueError:
+ return None
+
+
+def computeHostName(hostName):
+ if not hostName:
+ return False
+
+ hostPrefix = ""
+ for i in range(len(hostName), 0, -1):
+ pos = i - 1
+ if hostName[pos].isdigit():
+ continue
+ break
+ hostPrefix = hostName[:pos+1]
+ try:
+ hostIndex = int(hostName[pos+1:])
+ except ValueError:
+ hostIndex = 0
+ # TODO: Check the availablity of the (server) name
+ return "%s%s" % (hostPrefix, hostIndex + 1)
+
+
+def daemonize():
+ try:
+ pid = os.fork()
+ if pid > 0:
+ # exit first parent
+ sys.exit(0)
+ except OSError, e:
+ #sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+ return False
+
+ # decouple from parent environment
+ os.chdir("/")
+ os.setsid()
+ os.umask(0)
+
+ # do second fork
+ try:
+ pid = os.fork()
+ if pid > 0:
+ # exit from second parent
+ sys.exit(0)
+ except OSError, e:
+ #sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+ return False
+
+ # redirect standard file descriptors
+ sys.stdout.flush()
+ sys.stderr.flush()
+ si = file("/dev/null", 'r')
+ so = file("/dev/null", 'a+')
+ se = file("/dev/null", 'a+', 0)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ return True
+
+
+def getDownloadStatus(fileName):
+ try:
+ lines = [line for line in open(fileName)
+ if "saved" in line or "%" in line]
+ except IOError:
+ return 0
+ if not lines:
+ return 0
+ if "saved" in lines[-1]:
+ return 100
+ return lines[-1].split("%")[0].split()[-1]
+
+
+def getMeminfo():
+ """-> dict of data from meminfo (str:int).
+ Values are in kilobytes.
+ """
+ import re
+ re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB' )
+ result = {}
+ for line in open('/proc/meminfo'):
+ match = re_parser.match(line)
+ if not match:
+ continue # skip lines that don't parse
+ key, value = match.groups(['key', 'value'])
+ result[key] = int(value)
+ result['MemUsed'] = (result['MemTotal'] - result['MemFree'])
+ return result
+
+
+def getCpuUsage():
+ """-> dict of cpuid : (usertime, nicetime, systemtime, idletime)
+ cpuid "cpu" means the total for all CPUs.
+ cpuid "cpuN" means the value for CPU N.
+ """
+ wanted_records = [line for line in open('/proc/stat') if
+ line.startswith('cpu')]
+ result = {}
+ for cpuline in wanted_records:
+ fields = cpuline.split()[:5]
+ data = map(int, fields[1:])
+ result[fields[0]] = tuple(data)
+ return result
+
+def _getCpuStatList():
+ try:
+ fp = open("/proc/stat")
+ cpuStatList = map(float, fp.readline().split()[1:])
+ fp.close()
+ return cpuStatList
+ except IOError, e:
+ Utils.log("Failed to open /proc/stat: %s" % str(e))
+ return None
+
+def getCpuUsageAvg():
+ st1 = _getCpuStatList()
+ time.sleep(2)
+ st2 = _getCpuStatList()
+ if not (st1 and st2):
+ return None
+ delta = [st2[i] - st1[i] for i in range(len(st1))]
+ cpuPercent = sum(delta[:3]) / delta[3] * 100.0
+ return str('%.4f' % cpuPercent)
+
+def getLoadavg():
+ try:
+ loadavgstr = open('/proc/loadavg', 'r').readline().strip()
+ except IOError:
+ syslog.syslog(syslog.LOG_ERR, "failed to find cpu load")
+ return None
+
+ data = map(float, loadavgstr.split()[1:])
+ # returns 1 minute load average
+ return data[0]
+
+
+def getInfinibandPortStatus():
+
+ """ Check for availability of infiniband port
+ and return which port is active in a key pair value
+ """
+
+ # Check for existence of infiniband ports
+ value = os.popen ("ls /sys/class/infiniband").readline().strip()
+
+ if not value:
+ return None
+
+ portlist = os.popen ("echo /sys/class/infiniband/*/ports/*").readline().split()
+
+ portkeys = {}
+
+ for port in portlist:
+ value = os.popen ("cat %s/state" %
+ port.strip()).readline().split(':')[1].strip()
+ portkeys[port.strip()] = value
+
+ return portkeys
+
+
+def getServerCount():
+ try:
+ return int(open(Globals.SERVER_COUNT_FILE).read().strip())
+ except IOError:
+ log("failed to read file %s" % Globals.SERVER_COUNT_FILE)
+ return 1
+ except ValueError:
+ log("invalid number format in file %s" % Globals.SERVER_COUNT_FILE)
+ return 1
+
+
+def setServerCount(count):
+ try:
+ open(Globals.SERVER_COUNT_FILE, "w").write("%s\n" % count)
+ return True
+ except IOError:
+ log("failed to write file %s" % Globals.SERVER_COUNT_FILE)
+ return False
+
+
+def getInstalledServerCount():
+ try:
+ return int(open(Globals.INSTALLED_SERVER_COUNT_FILE).read().strip())
+ except IOError:
+ log("failed to read file %s" % Globals.INSTALLED_SERVER_COUNT_FILE)
+ return 1
+ except ValueError:
+ log("invalid number format in file %s" % Globals.INSTALLED_SERVER_COUNT_FILE)
+ return 1
+
+
+def setInstalledServerCount(count):
+ try:
+ open(Globals.INSTALLED_SERVER_COUNT_FILE, "w").write("%s\n" % count)
+ return True
+ except IOError:
+ log("failed to write file %s" % Globals.INSTALLED_SERVER_COUNT_FILE)
+ return False
+
+
+def getLastInstalledServerIpList():
+ ipList = {}
+ networkDom = Protocol.XDOM()
+ if not networkDom.parseFile(Globals.GLOBAL_NETWORK_FILE):
+ log("failed to parse file %s" % Globals.GLOBAL_NETWORK_FILE)
+ for tagE in networkDom.getElementsByTagRoute("server.interface"):
+ interfaceDom = Protocol.XDOM()
+ interfaceDom.setDomObj(tagE)
+ ipAddress = interfaceDom.getTextByTagRoute("ipaddr")
+ if ipAddress:
+ ipList[interfaceDom.getTextByTagRoute("device")] = ipAddress
+ return ipList
+
+
+def getFreeIpAddress(device=None):
+ serverCount = getServerCount()
+ installedServerCount = getInstalledServerCount()
+ if serverCount == installedServerCount:
+ return None
+
+ availableServerCount = serverCount - installedServerCount
+ ipList = getLastInstalledServerIpList()
+
+ if not ipList:
+ return None
+
+ if device:
+ if device not in ipList.keys():
+ return None
+ deviceIpAddress = ipList[device]
+ else:
+ deviceIpAddress = ipList.values()[0]
+ ipNumber = IP2Number(deviceIpAddress)
+
+ for i in range((ipNumber + availableServerCount), ipNumber, -1):
+ ipAddress = Number2IP(i)
+ if runCommandFG(["ping", "-qnc", "1", ipAddress]) != 0:
+ return ipAddress
+ return None
+
+
+def getPasswordHash(userName):
+ try:
+ #return spwd.getspnam(userName).sp_pwd
+ return "Not implimented"
+ except KeyError:
+ return None
+
+
+def getTransactionKey():
+ try:
+ tokens = open(Globals.TRANSACTION_KEY_FILE).read().split(',')
+ except IOError:
+ return None, None
+ return tokens
+
+
+def generateSignature():
+ #return str(uuid.uuid4()) + ('--%f' % time.time())
+ return ('--%f' % time.time())
+
+
+def getSignature():
+ try:
+ return open(Globals.SIGNATURE_FILE).read().strip()
+ except IOError:
+ log(syslog.LOG_ERR, "unable to read signaure from %s file" % Globals.SIGNATURE_FILE)
+ return False
+
+
+def storeSignature(signature, fileName=Globals.SIGNATURE_FILE):
+ try:
+ open(fileName, "w").write(signature + "\n")
+ except IOError:
+ log(syslog.LOG_ERR, "unable to write signature %s to %s file" % (signature, fileName))
+ return False
+ return True
+
+
+def isUserExist(userName):
+ try:
+ grp.getgrnam(userName).gr_gid
+ return True
+ except KeyError:
+ pass
+ try:
+ pwd.getpwnam(userName).pw_uid
+ return True
+ except KeyError:
+ pass
+ return False
+
+
+def getGsnUserInfo(fileName=Globals.GSN_USER_INFO_FILE):
+ userInfo = {}
+ userInfo["UserId"] = None
+ userInfo["Password"] = None
+ try:
+ for line in open(fileName):
+ line = line.strip()
+ k = line[:line.index("=")]
+ v = line[line.index("=") + 1:]
+ if v[0] == "'" or v[0] == '"':
+ v = v[1:]
+ if v[-1] == "'" or v[-1] == '"':
+ v = v[:-1]
+ if k.upper() == "GSN_ID":
+ userInfo["UserId"] = v
+ if k.upper() == "GSN_PASSWORD":
+ userInfo["Password"] = v
+ except IOError, e:
+ log("Failed to read file %s: %s" % (fileName, e))
+ return userInfo
+
+
+def setGsnUserInfo(userInfo, fileName=Globals.GSN_USER_INFO_FILE):
+ try:
+ fp = open(fileName, "w")
+ fp.write("GSN_ID=%s\n" % userInfo["UserId"])
+ fp.write("GSN_PASSWORD=%s\n" % userInfo["Password"])
+ fp.close()
+ return True
+ except IOError, e:
+ log("Failed to write file %s: %s" % (fileName, e))
+ return False
+
+
+def getPlatformVersion(fileName=Globals.GLUSTER_VERSION_FILE):
+ versionInfo = {}
+ versionInfo["Version"] = None
+ versionInfo["Update"] = None
+ try:
+ lines = open(Globals.GLUSTER_VERSION_FILE).readlines()
+ for line in open(fileName):
+ line = line.strip()
+ k = line[:line.index("=")]
+ v = line[line.index("=") + 1:]
+ if v[0] == "'" or v[0] == '"':
+ v = v[1:]
+ if v[-1] == "'" or v[-1] == '"':
+ v = v[:-1]
+ if k.upper() == "VERSION":
+ versionInfo["Version"] = v
+ if k.upper() == "UPDATE":
+ versionInfo["Update"] = v
+ except IOError, e:
+ log("Failed to read file %s: %s" % (fileName, e))
+ return versionInfo
+
+
+def setPlatformVersion(versionInfo, fileName=Globals.GLUSTER_VERSION_FILE):
+ if isString(versionInfo):
+ tokens = versionInfo.strip().split(".")
+ if len(tokens) < 2:
+ log("Invalid version format %s. Expecting <MAJOR>.<MINOR>.<PATCHLEVEL>" % versionInfo)
+ return False
+ version = ".".join(tokens[:2])
+ update = ".".join(tokens[2:])
+ if not update:
+ update = "0"
+ else:
+ version = versionInfo["Version"]
+ update = versionInfo["Update"]
+ try:
+ fp = open(fileName, "w")
+ fp.write("VERSION=%s\n" % version)
+ fp.write("UPDATE=%s\n" % update)
+ fp.close()
+ return True
+ except IOError, e:
+ log("Failed to write file %s: %s" % (fileName, e))
+ return False
+
+
+def getGlusterUpdateDom(serverVersion):
+ errorMessage = ""
+ updateInfoDom = None
+ try:
+ baseUrl = open(Globals.GLUSTER_UPDATE_SITE_FILE).read().strip()
+ except IOError, e:
+ log("Failed to read file %s: %s" % (Globals.GLUSTER_UPDATE_SITE_FILE, e))
+ errorMessage = "Failed to read update site file"
+ return updateInfoDom, errorMessage
+
+ try:
+ url = "%s/%s/%s" % (baseUrl, serverVersion, Globals.GLUSTER_UPDATES_FILE)
+ connection = urllib.urlopen(url)
+ if connection.getcode() != 200:
+ connection.close()
+ errorMessage = "Error received from server to open URL %s" % url
+ return updateInfoDom, errorMessage
+ updateInfoString = connection.read()
+ connection.close()
+ except IOError, e:
+ log("Failed to get update information from URL %s: %s" % (url, e))
+ errorMessage = "Error getting update information"
+ return updateInfoDom, errorMessage
+
+ updateInfoDom = Protocol.XDOM()
+ if not updateInfoDom.parseString(updateInfoString):
+ log("XML parse error on update information content [%s]" % updateInfoString)
+ errorMessage = "Parse error on update information"
+ updateInfoDom = None
+ return updateInfoDom, errorMessage
+
+
+def removeFile(fileName, root=False):
+ if root:
+ if runCommand("rm %s" % fileName, root=True) == 0:
+ return True
+ return False
+ try:
+ os.remove(fileName)
+ return True
+ except OSError, e:
+ log("Failed to remove file %s: %s" % (fileName, e))
+ return False
+
+
+def isLiveMode():
+ return os.path.exists(Globals.LIVE_MODE_FILE)
+
+def convertKbToMb(kb):
+ return kb / 1024.0
+
+
+def getIPIndex(indexFile):
+ try:
+ fp = open(indexFile)
+ line = fp.readline()
+ fp.close()
+ index = int(line)
+ except IOError:
+ index = 0
+ except ValueError:
+ index = False
+ return index
+
+def setIPIndex(index, indexFile):
+ try:
+ fp = open(indexFile, "w")
+ fp.write(str(index))
+ fp.close()
+ except IOError:
+ return False
+ return True
+
+def IP2Number(ipString):
+ try:
+ return socket.htonl(struct.unpack("I", socket.inet_aton(ipString))[0])
+ except socket.error:
+ return None
+ except TypeError:
+ return None
+ except struct.error:
+ return None
+
+def Number2IP(number):
+ try:
+ return socket.inet_ntoa(struct.pack("I", socket.ntohl(number)))
+ except socket.error:
+ return None
+ except AttributeError:
+ return None
+ except ValueError:
+ return None
+
+def hasEntryFoundInFile(searchString, dnsEntryFileName):
+ try:
+ addServerEntryList = open(dnsEntryFileName).read().split()
+ except IOError:
+ return None
+ if searchString in addServerEntryList:
+ return True
+ return False
+
+
+def computeIpAddress(ipAddress, startIp, endIp):
+ startIpNumber = IP2Number(startIp)
+ endIpNumber = IP2Number(endIp)
+ if not ipAddress:
+ return startIp
+ nextIpNumber = IP2Number(ipAddress)
+ while True:
+ nextIpNumber = nextIpNumber + 1
+ ipAddress = Number2IP(nextIpNumber)
+ rv = runCommandFG(["ping", "-qnc", "1", ipAddress])
+ if type(rv) == type(True):
+ return False
+ if rv != 0:
+ break
+
+ if nextIpNumber >= startIpNumber and nextIpNumber <= endIpNumber:
+ return ipAddress
+
+ nextIpNumber = IP2Number(startIp)
+ while True:
+ ipAddress = Number2IP(nextIpNumber)
+ nextIpNumber = nextIpNumber + 1
+ rv = runCommandFG(["ping", "-qnc", "1", ipAddress])
+ if type(rv) == type(True):
+ return False
+ if rv != 0:
+ break
+
+ if IP2Number(ipAddress) >= startIpNumber and IP2Number(ipAddress) <= endIpNumber:
+ return ipAddress
+ return False
+
+
+def setHostNameAndIp(hostName, ipAddress, lastAddServerDetailFile):
+ try:
+ fp = open(lastAddServerDetailFile, "w")
+ fp.write("HOSTNAME=" + hostName + "\n")
+ fp.write("IPADDRESS=" + ipAddress);
+ fp.close()
+ except IOError:
+ return False
+ return True
+
+def getPort():
+ try:
+ fd = open(Globals.PORT_FILE, "r")
+ portString = fd.readline()
+ fd.close()
+ port = int(portString)
+ except IOError:
+ port = Globals.DEFAULT_PORT - 2
+ except ValueError:
+ port = Globals.DEFAULT_PORT - 2
+ return port
+
+def setPort(port):
+ try:
+ fd = open(Globals.PORT_FILE, "w")
+ fd.write(str(port))
+ fd.close()
+ except IOError:
+ return False
+ return True
+
+def getServerAgentCredentials():
+ try:
+ lines = open(Globals.SERVERAGENT_AUTH_FILE).readlines()
+ except IOError:
+ return None,None
+
+ userName = None
+ password = None
+
+ for l in lines:
+ if l[-1] == '\n':
+ l = l[:-1]
+ k = l[:l.index('=')]
+ v = l[l.index('=') + 1:]
+ if v[0] == "'" or v[0] == '"':
+ v = v[1:]
+ if v[-1] == "'" or v[-1] == '"':
+ v = v[:-1]
+ if k.upper() == "AGENT_ID":
+ userName = v
+ if k.upper() == "AGENT_PASSWORD":
+ password = v
+
+ return userName, password
+
+def getGatewayAgentCredentials():
+ try:
+ lines = open(Globals.GATEWAYAGENT_AUTH_FILE).readlines()
+ except IOError:
+ return None
+
+ #userName = None
+ password = None
+
+ for l in lines:
+ if l[-1] == '\n':
+ l = l[:-1]
+ k = l[:l.index('=')]
+ v = l[l.index('=') + 1:]
+ if v[0] == "'" or v[0] == '"':
+ v = v[1:]
+ if v[-1] == "'" or v[-1] == '"':
+ v = v[:-1]
+ #if k.upper() == "AGENT_ID":
+ # userName = v
+ if k.upper() == "AGENT_PASSWORD":
+ password = v
+
+ return password
+
+def getWebAgentCredentials():
+ try:
+ lines = open(Globals.WEBAGENT_AUTH_FILE).readlines()
+ except IOError:
+ return None,None
+
+ userName = None
+ password = None
+
+ for l in lines:
+ if l[-1] == '\n':
+ l = l[:-1]
+ k = l[:l.index('=')]
+ v = l[l.index('=') + 1:]
+ if v[0] == "'" or v[0] == '"':
+ v = v[1:]
+ if v[-1] == "'" or v[-1] == '"':
+ v = v[:-1]
+ if k.upper() == "AGENT_ID":
+ userName = v
+ if k.upper() == "AGENT_PASSWORD":
+ password = v
+
+ return userName, password
+
+def daemonize():
+ try:
+ pid = os.fork()
+ if pid > 0:
+ # exit first parent
+ sys.exit(0)
+ except OSError, e:
+ #sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+ return False
+
+ # decouple from parent environment
+ os.chdir("/")
+ os.setsid()
+ os.umask(0)
+
+ # do second fork
+ try:
+ pid = os.fork()
+ if pid > 0:
+ # exit from second parent
+ sys.exit(0)
+ except OSError, e:
+ #sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+ return False
+
+ # redirect standard file descriptors
+ sys.stdout.flush()
+ sys.stderr.flush()
+ si = file("/dev/null", 'r')
+ so = file("/dev/null", 'a+')
+ se = file("/dev/null", 'a+', 0)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ return True
+
+def getFreeIpAddress():
+ startRange, endRange = getStoragePoolInfo()
+ if not (startRange and endRange):
+ return None
+
+ startIpNumber = IP2Number(startRange)
+ endIpNumber = IP2Number(endRange)
+
+ for ipNumber in range(endIpNumber, startIpNumber, -1):
+ rv = runCommandFG(["ping", "-qnc", "1", Number2IP(ipNumber)])
+ if type(rv) == type(True):
+ return None
+ if rv != 0:
+ return Number2IP(ipNumber)
+ return None
+
+def getDhcpServerStatus():
+ status = runCommandFG(["sudo", "service", "dnsmasq", " status"])
+ if type(status) == type(True) or 0 != status:
+ return False
+ return True
+
+def startDhcpServer():
+ status = runCommandFG(["sudo", "service", "dnsmasq", " start"])
+ if type(status) == type(True) or 0 != status:
+ return False
+ return True
+
+def stopDhcpServer():
+ status = runCommandFG(["sudo", "service", "dnsmasq", " stop"])
+ if type(status) == type(True) or 0 != status:
+ return False
+ return True
+
+def getStoragePoolInfo():
+ startRange = None
+ endRange = None
+ try:
+ for line in open(Globals.GLUSTER_SERVER_POOL_FILE):
+ tokens = line.split("=")
+ if tokens[0] == "STARTRANGE":
+ startRange = tokens[1].strip()
+ if tokens[0] == "ENDRANGE":
+ endRange = tokens[1].strip()
+ except IOError:
+ log(syslog.LOG_ERR, "unable to read %s file" % Globals.GLUSTER_SERVER_POOL_FILE)
+ return startRange, endRange
+
+def configureDnsmasq(serverIpAddress, dhcpIpAddress):
+ dnsmasqConfFile = Globals.GLUSTER_CONF_CONF_DIR + "/dnsmasq.conf"
+ serverPortString = "68"
+ try:
+ for arg in open("/proc/cmdline").read().strip().split():
+ token = arg.split("=")
+ if token[0] == "dhcp":
+ serverPortString = token[1]
+ break
+ except IOError:
+ log(syslog.LOG_ERR, "Failed to read /proc/cmdline. Continuing with default port 68")
+ try:
+ serverPort = int(serverPortString)
+ except ValueError:
+ log(syslog.LOG_ERR, "Invalid dhcp port '%s' in /proc/cmdline. Continuing with default port 68" % serverPortString)
+ serverPort = 68
+
+ try:
+ fp = open(dnsmasqConfFile, "w")
+ fp.write("no-hosts\n")
+ #fp.write("addn-hosts=%s\n" % Globals.GLUSTER_DNS_ENTRIES)
+ fp.write("bind-interfaces\n")
+ fp.write("except-interface=lo\n")
+ fp.write("dhcp-range=%s,%s\n" % (dhcpIpAddress, dhcpIpAddress))
+ fp.write("dhcp-lease-max=1\n")
+ #fp.write("dhcp-option=option:router,%s\n" % serverIp)
+ #fp.write("dhcp-option=option:ntp-server,%s\n" % serverIp)
+ fp.write("dhcp-alternate-port=%s\n" % serverPort)
+ fp.write("server=%s\n" % serverIpAddress)
+ fp.write("dhcp-script=/usr/sbin/server-info\n")
+ fp.close()
+ except IOError:
+ log(syslog.LOG_ERR, "unable to write dnsmasq configuration %s" % dnsmasqConfFile)
+ return False
+ status = runCommandFG(["sudo", "cp", "-f", Globals.GLUSTER_CONF_CONF_DIR + "/dnsmasq.conf", Globals.DNSMASQ_CONF_FILE])
+ if type(status) == type(True) or 0 != status:
+ log(syslog.LOG_ERR, "unable to copy dnsmasq configuration to " + Globals.DNSMASQ_CONF_FILE)
+ return False
+ return True
+
+def configureDhcpServer(serverIpAddress, dhcpIpAddress):
+ return configureDnsmasq(serverIpAddress, dhcpIpAddress)
+
+def log(priority, message=None):
+ if type(priority) == type(""):
+ logPriority = syslog.LOG_INFO
+ logMessage = priority
+ else:
+ logPriority = priority
+ logMessage = message
+ if not logMessage:
+ return
+ #if Globals.DEBUG:
+ # sys.stderr.write(logMessage)
+ else:
+ syslog.syslog(logPriority, logMessage)
+ return
+
+
+def stripEmptyLines(content):
+ ret = ""
+ for line in content.split("\n"):
+ if line.strip() != "":
+ ret += line
+ return ret
+
+
+def getDeviceFormatStatusFile(device):
+ return "/var/tmp/format_%s.status" % device.replace('/', '_')
+
+def getDeviceFormatLockFile(device):
+ return "/var/lock/format_%s.lock" % device.replace('/', '_')
+
+def getDeviceFormatOutputFile(device):
+ return "/var/tmp/format_%s.out" % device.replace('/', '_')
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py
new file mode 100644
index 00000000..72164ffb
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/XmlHandler.py
@@ -0,0 +1,346 @@
+# Copyright (C) 2009 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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, see
+# <http://www.gnu.org/licenses/>.
+
+import xml
+import xml.parsers.expat
+import xml.dom.minidom as MDOM
+import os
+import Globals
+import copy
+import Utils
+
+XML_STRING = 0
+XML_FILE = 1
+
+class XDOM:
+ _domObj = None
+
+ def __init__(self):
+ self._domObj = MDOM.Document()
+ return
+
+ @classmethod
+ def getText(self, nodeList):
+ rc = ""
+ for node in nodeList:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc
+
+ def parseString(self, requestString):
+ try:
+ self._domObj = MDOM.parseString(requestString)
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML string parse error: %s" % str(e))
+ return False
+ return True
+
+ def parseFile(self, fileName):
+ try:
+ self._domObj = MDOM.parse(fileName)
+ except IOError, e:
+ Utils.log("error reading file: %s" % str(e))
+ return False
+ except xml.parsers.expat.ExpatError, e:
+ Utils.log("XML file %s parse error: %s" % (fileName, str(e)))
+ return False
+ return True
+
+ def setDomObj(self, dom):
+ if dom and type(dom) != type([]):
+ self._domObj = dom
+ return True
+ return False
+
+ def createTag(self, tag, text=None):
+ if not self._domObj:
+ return None
+ if tag == None:
+ return None
+
+ tagE = self._domObj.createElement(str(tag))
+ if text:
+ tagEText = self._domObj.createTextNode(str(text))
+ tagE.appendChild(tagEText)
+ return tagE
+
+ def addTag(self, tag):
+ if not self._domObj:
+ return False
+ if not tag:
+ return False
+
+ self._domObj.appendChild(tag)
+ return True
+
+ def createTagRoute(self, tagRoute, text=None):
+ if not tagRoute:
+ return False
+
+ tagList = tagRoute.split(".")
+ tag = None
+ previousTag = None
+ for tagName in tagList[:-1]:
+ newTag = self.createTag(tagName, None)
+ if not tag:
+ tag = newTag
+ previousTag = newTag
+ continue
+ previousTag.appendChild(newTag)
+ previousTag = newTag
+
+ if previousTag:
+ previousTag.appendChild(self.createTag(tagList[-1], text))
+ else:
+ tag = self.createTag(tagList[-1], text)
+ return tag
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._domObj:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._domObj
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+
+ def setTextByTagRoute(self, tagRoute, tagValue):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ tagE = self.getElementsByTagRoute(tagRoute)
+ if not tagE:
+ return False
+
+ parentTagE = self.getElementsByTagRoute(".".join(tagRoute.split(".")[:-1]))
+ if not parentTagE:
+ return False
+
+ parentTagE[0].childNodes.remove(tagE[0])
+ parentTagE[0].appendChild(self.createTag(tagRoute.split(".")[-1], tagValue))
+ return True
+
+ def getElementsByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ if not tagRoute:
+ return None
+
+ x = None
+ for tag in tagRoute.split("."):
+ if x is None:
+ x = self._domObj.getElementsByTagName(tag)
+ continue
+ if x == []:
+ break
+ x = x[0].getElementsByTagName(tag)
+ return x
+
+ def getTextByTagRoute(self, tagRoute):
+ if not self._domObj:
+ return None
+
+ x = self.getElementsByTagRoute(tagRoute)
+ if x:
+ return self.getText(x[0].childNodes)
+ return None
+
+ def getElementsByTagName(self, name):
+ if not self._domObj:
+ return None
+ return self._domObj.getElementsByTagName(name)
+
+ def writexml(self, fileName, indent="", addindent="", newl=""):
+ if not self._domObj:
+ return None
+ try:
+ fp = open(fileName, "w")
+ self._domObj.writexml(fp, indent, addindent, newl)
+ fp.close()
+ return True
+ except IOError:
+ return False
+
+ def toString(self, indent=" ", newl="\n", encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toprettyxml(indent, newl, encoding)
+
+ def toxml(self, encoding = None):
+ if not self._domObj:
+ return None
+ return self._domObj.toxml(encoding)
+
+ def toprettyxml(self, indent=" ", newl="\n", encoding = None):
+ return self.toString(indent, newl, encoding)
+
+ def createResponseTag(self):
+ responseTag = self._domObj.createElement("response")
+ return responseTag
+##--end of XDOM
+
+class RequestXml(XDOM):
+ def __init__(self, requestString, type=None):
+ if None == requestString:
+ XDOM.__init__(self)
+ return
+ try:
+ if None == type:
+ if os.path.isfile(requestString):
+ self._domObj = MDOM.parse(requestString)
+ else:
+ self._domObj = MDOM.parseString(requestString)
+ elif XML_FILE == type:
+ self._domObj = MDOM.parse(requestString)
+ elif XML_STRING == type:
+ self._domObj = MDOM.parseString(requestString)
+ except IOError:
+ XDOM.__init__(self)
+ except xml.parsers.expat.ExpatError:
+ XDOM.__init__(self)
+
+##--end of RequestXML
+
+
+class ResponseXml(XDOM):
+ _responseTag = None
+ def __init__(self):
+ XDOM.__init__(self)
+ self._responseTag = self.createResponseTag()
+ self._domObj.appendChild(self._responseTag)
+
+ @classmethod
+ def errorResponse(self, message):
+ if not self.responseTag:
+ return False
+ self.appendTagRoute("status.code", "-1");
+ self.appendTagRoute("status.message", message)
+
+ def append(self, tagName, tagValue=None):
+ if not self._responseTag:
+ return False
+ tag = self.createTag(tagName, tagValue)
+ if tag:
+ self._responseTag.appendChild(tag)
+ return True
+ return False
+
+ def appendTag(self, tag):
+ if not tag:
+ return False
+ if not self._responseTag:
+ return False
+ self._responseTag.appendChild(tag)
+ return True
+
+ def appendTagRoute(self, tagRoute, value=None):
+ if not self._responseTag:
+ return None
+ if not tagRoute:
+ return None
+
+ parentTagE = self._responseTag
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return None
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return None
+ return newTagE
+
+ def appendTagRouteOld(self, tagRoute, value=None):
+ if not self._responseTag:
+ return False
+ if not tagRoute:
+ return False
+
+ parentTagE = self._responseTag
+
+ tagNameList = tagRoute.split(".")
+ newTagRoute = tagNameList.pop(-1)
+
+ for i in range(len(tagNameList), 0, -1):
+ tagE = self.getElementsByTagRoute(".".join(["response"] + tagNameList[:i]))
+ if tagE:
+ parentTagE = tagE[0]
+ break
+ newTagRoute = tagNameList[i-1] + "." + newTagRoute
+
+ newTagE = self.createTagRoute(newTagRoute, value)
+ if not newTagE:
+ return False
+ try:
+ parentTagE.appendChild(newTagE)
+ except xml.dom.HierarchyRequestErr, e:
+ Utils.log("error occured. %s" + str(e))
+ return False
+ return True
+##--end of ResponseXml
+
+def test():
+ rs = ResponseXml()
+ rs.appendTagRoute("status.code", "0");
+ rs.appendTagRoute("status.message", "SUCCESS")
+ serverTag = rs.appendTagRoute("server.name", "Server1")
+ networkInterfaces = rs.appendTagRoute("server.networkInterfaces", None)
+ networkTag = rs.createTag("networkInterface", None)
+ networkTag.appendChild(rs.createTag("name", "interface1"))
+ networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.40"))
+ networkInterfaces.appendChild(networkTag)
+ networkTag = rs.createTag("networkInterface", None)
+ networkTag.appendChild(rs.createTag("name", "interface2"))
+ networkTag.appendChild(rs.createTag("ipaddress", "192.168.1.41"))
+ networkInterfaces.appendChild(networkTag)
+ print rs.toprettyxml()
+
+#test()
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py
new file mode 100755
index 00000000..e4b48658
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/add_user_cifs_all.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Management Gateway.
+#
+
+import os
+import sys
+import Utils
+
+
+defaultUid = 1024000
+cifsUserFile = "/etc/glustermg/.users.cifs"
+
+
+def getLastUid():
+ if not os.path.exists(cifsUserFile):
+ return defaultUid
+ try:
+ fp = open(cifsUserFile)
+ content = fp.read()
+ fp.close()
+ except IOError, e:
+ Utils.log("failed to read file %s: %s" % (cifsUserFile, str(e)))
+ return False
+
+ lines = content.strip().split()
+ if not lines:
+ return defaultUid
+ return int(lines[-1].split(":")[0])
+
+
+def setUid(uid, userName):
+ try:
+ fp = open(cifsUserFile, "a")
+ fp.write("%s:%s\n" % (uid, userName))
+ fp.close()
+ return True
+ except IOError, e:
+ Utils.log("failed to write file %s: %s" % (cifsUserFile, str(e)))
+ return False
+
+
+def main():
+ if len(sys.argv) < 4:
+ sys.stderr.write("usage: %s SERVER_FILE USERNAME PASSWORD\n" % os.path.basename(sys.argv[0]))
+ sys.exit(-1)
+
+ serverFile = sys.argv[1]
+ userName = sys.argv[2]
+ password = sys.argv[3]
+
+ uid = getLastUid()
+ if not uid:
+ sys.exit(10)
+
+ uid += 1
+
+ rv = Utils.runCommand("grun.py %s add_user_cifs.py %s %s %s" % (serverFile, uid, userName, password))
+ if rv == 0:
+ if not setUid(uid, userName):
+ sys.exit(11)
+ sys.exit(rv)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py
new file mode 100755
index 00000000..38dd8109
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/delete_user_cifs_all.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Management Gateway.
+#
+
+import os
+import sys
+import Utils
+
+
+cifsUserFile = "/etc/glustermg/.users.cifs"
+
+
+def removeUser(userName):
+ try:
+ fp = open(cifsUserFile)
+ content = fp.read()
+ fp.close()
+ except IOError, e:
+ Utils.log("failed to read file %s: %s" % (cifsUserFile, str(e)))
+ return False
+
+ try:
+ fp = open(cifsUserFile, "w")
+ lines = content.strip().split()
+ for line in lines:
+ if line.split(":")[1] == userName:
+ continue
+ fp.write("%s\n" % line)
+ fp.close()
+ except IOError, e:
+ Utils.log("failed to write file %s: %s" % (cifsUserFile, str(e)))
+ return False
+ return True
+
+
+def main():
+ if len(sys.argv) < 3:
+ sys.stderr.write("usage: %s SERVER_LIST USERNAME\n" % os.path.basename(sys.argv[0]))
+ sys.exit(-1)
+
+ serverList = sys.argv[1]
+ userName = sys.argv[2]
+
+ rv = Utils.runCommand("grun.py %s delete_user_cifs.py %s" % (serverList, userName))
+ if rv == 0:
+ if not removeUser(userName):
+ sys.exit(10)
+ sys.exit(rv)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/grun.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/grun.py
new file mode 100755
index 00000000..ae93b7f2
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/grun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Management Gateway.
+#
+
+import os
+import sys
+import Utils
+
+
+def main():
+ sshCommandPrefix = "ssh -q -o BatchMode=yes -o GSSAPIAuthentication=no -o PasswordAuthentication=no -o StrictHostKeyChecking=no".split()
+
+ if len(sys.argv) < 3:
+ sys.stderr.write("usage: %s SERVER_FILE COMMAND [ARGUMENTS]\n" % os.path.basename(sys.argv[0]))
+ sys.exit(-1)
+ serverFile = sys.argv[1]
+ command = sys.argv[2:]
+
+ try:
+ fp = open(serverFile)
+ serverNameList = fp.readlines()
+ fp.close()
+ except IOError, e:
+ Utils.log("Failed to read server file %s: %s\n" % (serverFile, str(e)))
+ sys.exit(1)
+
+ for serverName in serverNameList:
+ rv = Utils.runCommand(sshCommandPrefix + [serverName.strip()] + command)
+ print rv
+
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py b/src/com.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py
new file mode 100755
index 00000000..ac434827
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/scripts/multicast-discover-servers.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+# Copyright (C) 2009 Gluster, Inc. <http://www.gluster.com>
+# This file is part of Gluster Storage Platform.
+#
+# Gluster Storage Platform 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 3 of
+# the License, or (at your option) any later version.
+#
+# Gluster Storage Platform 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, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+import socket
+import signal
+import struct
+import syslog
+import Globals
+import time
+import Utils
+from XmlHandler import *
+
+class TimeoutException(Exception):
+ pass
+
+def timeoutSignal(signum, frame):
+ raise TimeoutException, "Timed out"
+
+def serverDiscoveryRequest(multiCastGroup, port):
+ servers = []
+ # Sending request to all the servers
+ socketSend = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketSend.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
+ socketSend.sendto("ServerDiscovery", (multiCastGroup, port))
+
+ # Waiting for the response
+ socketReceive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+ socketReceive.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ socketReceive.bind(('', port))
+ mreq = struct.pack("4sl", socket.inet_aton(multiCastGroup), socket.INADDR_ANY)
+
+ socketReceive.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+ sendtime = time.time()
+ socketSend.sendto("<request><name>ServerDiscovery</name><time>%s</time></request>" % (sendtime), (multiCastGroup, port))
+
+ try:
+ while True:
+ response = socketReceive.recvfrom(200)
+ if not response:
+ continue
+ dom = XDOM()
+ dom.parseString(response[0])
+ if not dom:
+ continue
+ if dom.getTextByTagRoute("request.name"):
+ continue
+ responsetime = dom.getTextByTagRoute("response.time")
+ servername = dom.getTextByTagRoute("response.servername")
+ if responsetime == str(sendtime):
+ servers.append(servername)
+ signal.signal(signal.SIGALRM, timeoutSignal)
+ signal.alarm(3)
+ except TimeoutException:
+ return servers
+ return None
+
+def main():
+ syslog.openlog("discovery server request")
+ servers = serverDiscoveryRequest(Globals.MULTICAST_GROUP, Globals.MULTICAST_PORT)
+ if not servers:
+ Utils.log(syslog.LOG_ERR, "Failed to discover new servers")
+ sys.exit(-1)
+
+ servers = set(servers)
+ try:
+ for server in servers:
+ print server
+ except IOError:
+ Utils.log(syslog.LOG_ERR, "Unable to open file %s" % Globals.DISCOVERED_SERVER_LIST_FILENAME)
+ sys.exit(-1)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/com.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore b/src/com.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore
new file mode 100644
index 00000000..2efe19b0
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/WebContent/ssl/gmg-ssl.keystore
Binary files differ
diff --git a/src/com.gluster.storage.management.gateway/buckminster.cspex b/src/com.gluster.storage.management.gateway/buckminster.cspex
new file mode 100644
index 00000000..31eb9d67
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/build/glusterserver.ant b/src/com.gluster.storage.management.gateway/build/glusterserver.ant
new file mode 100644
index 00000000..68a5bc08
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/build/glusterserver.ant
@@ -0,0 +1,65 @@
+<project name="com.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>
+ <!-- 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/com.gluster.storage.management.gateway/src/META-INF/persistence.xml b/src/com.gluster.storage.management.gateway/src/META-INF/persistence.xml
new file mode 100644
index 00000000..36b252ea
--- /dev/null
+++ b/src/com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java
new file mode 100644
index 00000000..1f577c89
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java
@@ -0,0 +1,118 @@
+/**
+ * DefaultVolumeOptions.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 com.gluster.storage.management.gateway.constants;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.model.VolumeOptionInfo;
+
+@Component
+public class VolumeOptionsDefaults {
+ public List<VolumeOptionInfo> options;
+
+ public VolumeOptionsDefaults() {
+ }
+
+ /**
+ * @return list of volume option information objects
+ */
+ public List<VolumeOptionInfo> getDefaults() {
+ return getVolumeOptionsInfo();
+ }
+
+ /**
+ * Fetches the list of all volume options with their information from GlusterFS and returns the same
+ *
+ * @return List of volume option information objects
+ */
+ private List<VolumeOptionInfo> getVolumeOptionsInfo() {
+ List<VolumeOptionInfo> volumeOptionsInfo = new ArrayList<VolumeOptionInfo>();
+
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "cluster.stripe-block-size",
+ "This could be used in case of a stripe setup. Specifies the size of the stripe unit that will read from or written to the striped servers. "
+ + CoreConstants.NEWLINE
+ + "Optionally different stripe unit sizes can be specified for different fies, with the following pattern <filename-pattern:blk-size>. ",
+ "*:128KB"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "cluster.self-heal-window-size",
+ "Specifies the number of maximum number blocks per file for which self-heal process would be applied simultaneously.",
+ "16"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("cluster.data-self-heal-algorithm",
+ "cluster.data-self-heal-algorithm", "auto"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "network.frame-timeout",
+ "The time frame after which the operation has to be declared as dead, if the server does not respond for a particular operation.",
+ "1800"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("network.ping-timeout",
+ "The time duration for which the client waits to check if the server is responsive.", "42"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("auth.allow",
+ "'IP addresses/Host name' of the clients which should be allowed to access the the volume.", "*"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("auth.reject",
+ "'IP addresses/Host name' of the clients which should be denied to access the volume.", "NONE"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "performance.cache-refresh-timeout",
+ "The cached data for a file will be retained till 'cache-refresh-timeout' seconds, after which data re-validation is performed.",
+ "1"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("performance.cache-size", "Size of the read cache.", "32MB"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("performance.write-behind-window-size",
+ "Size of the per-file write-behind buffer.", "1MB"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("performance.cache-max-file-size",
+ "performance.cache-max-file-size", "-1"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("performance.cache-min-file-size",
+ "performance.cache-min-file-size", "0"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "performance.io-thread-count",
+ " Number of threads in the thread-pool in the bricks to improve the concurrency in I/O s of server side.",
+ "16"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "diagnostics.latency-measurement",
+ "Statistics related to the latency of each operation would be tracked inside GlusterFS data-structures.",
+ "off"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.dump-fd-stats",
+ "Statistics related to file-operations would be tracked inside GlusterFS data-structures.", "off"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.brick-log-level",
+ "Changes the log-level of the bricks (servers).", "INFO"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("diagnostics.client-log-level",
+ "Changes the log-level of the clients.", "INFO"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("nfs.enable-ino32",
+ "Use this option from the CLI to make Gluster NFS return 32-bit inode numbers instead of 64-bit.",
+ "off"));
+ volumeOptionsInfo
+ .add(new VolumeOptionInfo(
+ "nfs.mem-factor",
+ "This option specifies a multiple that determines the total amount of memory used. Increases this increases the performance of NFS.",
+ "15"));
+ volumeOptionsInfo.add(new VolumeOptionInfo("transport.keepalive", "transport.keepalive", "on"));
+
+ return volumeOptionsInfo;
+ }
+} \ No newline at end of file
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ClusterInfo.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ClusterInfo.java
new file mode 100644
index 00000000..3e5ea01a
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java
new file mode 100644
index 00000000..0802fe93
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/PersistenceDao.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/PersistenceDao.java
new file mode 100644
index 00000000..eb7d6514
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ServerInfo.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/data/ServerInfo.java
new file mode 100644
index 00000000..a3f8c920
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuditFilter.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuditFilter.java
new file mode 100644
index 00000000..31810123
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuditFilter.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package com.gluster.storage.management.gateway.filters;
+
+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 {
+
+ @Override
+ public ContainerRequestFilter getRequestFilter() {
+ return this;
+ }
+
+ @Override
+ public ContainerResponseFilter getResponseFilter() {
+ return this;
+ }
+
+ @Override
+ public ContainerRequest filter(ContainerRequest req) {
+ System.out.println("REQUEST: [" + req.getMethod() + "][" + req.getPath() + "]");
+ return req;
+ }
+
+ @Override
+ public ContainerResponse filter(ContainerRequest req, ContainerResponse response) {
+ System.out.println("RESPONSE: [" + req.getMethod() + "][" + req.getPath() + "]");
+ return response;
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java
new file mode 100644
index 00000000..73a1085e
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java
new file mode 100644
index 00000000..1c480f3f
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java
@@ -0,0 +1,31 @@
+/**
+ *
+ */
+package com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java
new file mode 100644
index 00000000..9fc4fceb
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java
new file mode 100644
index 00000000..d0da6696
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_CLUSTER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static com.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.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+import com.gluster.storage.management.core.response.ClusterNameListResponse;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.services.ClusterService;
+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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java
new file mode 100644
index 00000000..2d07bd24
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_DISCOVERED_SERVERS;
+
+import java.util.ArrayList;
+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.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.model.Server;
+import com.gluster.storage.management.core.response.ServerListResponse;
+import com.gluster.storage.management.core.response.ServerNameListResponse;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+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
+ protected ServerUtil serverUtil;
+
+ @InjectParam
+ protected GlusterUtil glusterUtil;
+
+ private List<String> discoveredServerNames = new ArrayList<String>();
+
+ 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);
+ }
+
+ @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 = getDiscoveredServerDetails();
+ return okResponse(new ServerListResponse(discoveredServers), mediaType);
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ } else {
+ return okResponse(new ServerNameListResponse(getDiscoveredServerNames()), mediaType);
+ }
+ }
+
+ private List<Server> getDiscoveredServerDetails() {
+ List<Server> discoveredServers = new ArrayList<Server>();
+ for (String serverName : getDiscoveredServerNames()) {
+ try {
+ discoveredServers.add(getDiscoveredServer(serverName));
+ } catch(Exception e) {
+ // TODO: Log the exception
+ // continue with next discovered server
+ }
+ }
+ return discoveredServers;
+ }
+
+ @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(getDiscoveredServer(serverName), mediaType);
+ } catch (Exception e) {
+ // TODO: Log the exception
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ private Server getDiscoveredServer(String serverName) {
+ Server server = new Server(serverName);
+ serverUtil.fetchServerDetails(server);
+ return server;
+ }
+
+ public static void main(String[] args) {
+ Response response = (Response)new DiscoveredServersResource().getDiscoveredServersXML(false);
+ System.out.println(response.getEntity());
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java
new file mode 100644
index 00000000..3a316c0c
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.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 com.gluster.storage.management.core.exceptions.GlusterValidationException;
+
+@Provider
+public class GenericExceptionMapper implements ExceptionMapper<Exception> {
+
+ /* (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() + "]";
+ }
+ }
+ return builder.entity(errMsg).type(MediaType.TEXT_PLAIN).build();
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java
new file mode 100644
index 00000000..e6e4f9d6
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java
@@ -0,0 +1,487 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FSTYPE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_INTERFACE;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_PERIOD;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TYPE;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_STATISTICS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_CPU;
+import static com.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_MEMORY;
+import static com.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.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.constants.RESTConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.ServerStats;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.gluster.storage.management.core.response.GlusterServerListResponse;
+import com.gluster.storage.management.core.response.ServerNameListResponse;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.data.ServerInfo;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.services.GlusterServerService;
+import com.gluster.storage.management.gateway.tasks.InitializeDiskTask;
+import com.gluster.storage.management.gateway.utils.CpuStatsFactory;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.MemoryStatsFactory;
+import com.gluster.storage.management.gateway.utils.NetworkStatsFactory;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+import com.gluster.storage.management.gateway.utils.SshUtil;
+import com.gluster.storage.management.gateway.utils.StatsFactory;
+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 DiscoveredServersResource discoveredServersResource;
+
+ @InjectParam
+ private TasksResource taskResource;
+
+ @InjectParam
+ private ClusterService clusterService;
+
+ @InjectParam
+ private SshUtil sshUtil;
+
+ @InjectParam
+ private CpuStatsFactory cpuStatsFactory;
+
+ @InjectParam
+ private MemoryStatsFactory memoryStatsFactory;
+
+ @InjectParam
+ private NetworkStatsFactory networkStatsFactory;
+
+ @InjectParam
+ private ServerUtil serverUtil;
+
+ @InjectParam
+ private GlusterUtil glusterUtil;
+
+ @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) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_JSON, details);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @QueryParam(QUERY_PARAM_DETAILS) Boolean details) {
+ return getGlusterServers(clusterName, MediaType.APPLICATION_XML, details);
+ }
+
+ private Response getGlusterServers(String clusterName, String mediaType, Boolean fetchDetails) {
+ if(fetchDetails == null) {
+ // by default, fetch the server details
+ fetchDetails = true;
+ }
+
+ 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);
+ } 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());
+ }
+ }
+
+ 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 (ConnectionException e) {
+ // 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(serverName, onlineServer.getName());
+ }
+ }
+
+ @POST
+ public Response addServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @FormParam(FORM_PARAM_SERVER_NAME) String serverName) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (serverName == null || serverName.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_SERVER_NAME + "] is missing in request!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ return notFoundResponse("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.
+ return errorResponse("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
+ try {
+ performAddServer(clusterName, hostName);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ } 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
+ }
+
+ try {
+ // add the cluster-server mapping
+ clusterService.mapServerToCluster(clusterName, serverName);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ // since the server is added to a cluster, it should not more be considered as a
+ // discovered server available to other clusters
+ discoveredServersResource.removeDiscoveredServer(serverName);
+
+ if (!publicKeyInstalled) {
+ try {
+ // install public key (this will also disable password based ssh login)
+ sshUtil.installPublicKey(serverName);
+ } catch (Exception e) {
+ return errorResponse("Public key could not be installed on [" + serverName + "]! Error: ["
+ + e.getMessage() + "]");
+ }
+ }
+
+ return createdResponse(serverName);
+ }
+
+ @DELETE
+ @Path("{" + PATH_PARAM_SERVER_NAME + "}")
+ public Response removeServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
+ @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
+ 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!");
+ }
+
+ ClusterInfo cluster = clusterService.getCluster(clusterName);
+ if (cluster == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ List<ServerInfo> servers = cluster.getServers();
+ if (servers == null || servers.isEmpty() || !containsServer(servers, serverName)) {
+ return badRequestResponse("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 {
+ try {
+ removeServerFromCluster(clusterName, serverName);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+ clusterService.unmapServerFromCluster(clusterName, serverName);
+
+ return noContentResponse();
+ }
+
+ private void removeServerFromCluster(String clusterName, String serverName) {
+ // 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 (ConnectionException e) {
+ // 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);
+ }
+
+ if (onlineServer.getName().equals(serverName)) {
+ // since the cached server has been removed from the cluster, remove it from the cache
+ clusterService.removeOnlineServer(clusterName);
+ }
+
+ // 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.
+ discoveredServersResource.addDiscoveredServer(serverName);
+ }
+
+ private boolean containsServer(List<ServerInfo> servers, String serverName) {
+ for (ServerInfo server : servers) {
+ if (server.getName().toUpperCase().equals(serverName.toUpperCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @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) {
+
+ 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()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_FSTYPE + "] is missing in request!");
+ }
+
+ InitializeDiskTask initializeTask = new InitializeDiskTask(clusterService, clusterName, serverName, diskName, fsType);
+ try {
+ initializeTask.start();
+ // Check the initialize disk status
+ TaskStatus taskStatus = initializeTask.checkStatus();
+ initializeTask.getTaskInfo().setStatus(taskStatus);
+ taskResource.addTask(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));
+ 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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java
new file mode 100644
index 00000000..34dad497
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java
@@ -0,0 +1,153 @@
+/**
+ * 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 com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.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 com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.utils.FileUtil;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.core.utils.ProcessUtil;
+import com.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 = System.getProperty("java.io.tmpdir");
+ String zipFile = targetDir + "ssh-keys.tar";
+ String sourcePemFile = SshUtil.PRIVATE_KEY_FILE.getAbsolutePath();
+ String sourcePubKeyFile = SshUtil.PUBLIC_KEY_FILE.getAbsolutePath();
+ String targetPemFile = 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", sourcePemFile, targetPemFile);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Failed to copy key files! [" + result.getOutput() + "]");
+ }
+ result = processUtil.executeCommand("cp", sourcePubKeyFile, 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", "/tmp", 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", targetPemFile, 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 pem 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 pem 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 pem and public key files.
+ ProcessResult output = processUtil.executeCommand("tar", "xvf", uploadedFile.getName(), "-C",
+ SshUtil.SSH_AUTHORIZED_KEYS_DIR_LOCAL);
+ uploadedFile.delete();
+ if (!output.isSuccess()) {
+ throw new GlusterRuntimeException(output.getOutput());
+ }
+ 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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java
new file mode 100644
index 00000000..e5874f4b
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java
@@ -0,0 +1,194 @@
+/**
+ * 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 com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_TASK_ID;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static com.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.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.RESTConstants;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.TaskInfo;
+import com.gluster.storage.management.core.response.TaskInfoListResponse;
+import com.gluster.storage.management.gateway.tasks.Task;
+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, Task> tasksMap = new HashMap<String, Task>();
+
+ public TasksResource() {
+ }
+
+ public void addTask(Task task) {
+ tasksMap.put(task.getId(), task);
+ }
+
+ public void removeTask(Task task) {
+ tasksMap.remove(task.getId());
+ }
+
+ public List<TaskInfo> getAllTasksInfo() {
+ List<TaskInfo> allTasksInfo = new ArrayList<TaskInfo>();
+ for (Map.Entry<String, Task> entry : tasksMap.entrySet()) {
+ checkTaskStatus(entry.getKey());
+ allTasksInfo.add(entry.getValue().getTaskInfo()); // TaskInfo with latest status
+ }
+ return allTasksInfo;
+ }
+
+ public Task getTask(String taskId) {
+ for (Map.Entry<String, Task> entry : tasksMap.entrySet()) {
+ if (entry.getValue().getId().equals(taskId)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ public List<Task> getAllTasks() {
+ List<Task> tasks = new ArrayList<Task>();
+ for (Map.Entry<String, Task> entry : tasksMap.entrySet()) {
+ checkTaskStatus(entry.getKey());
+ tasks.add( (Task) entry.getValue());
+ }
+ return tasks;
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response getTasks() {
+ try {
+ return okResponse(new TaskInfoListResponse(getAllTasksInfo()), 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_TASK_ID) String taskId) {
+ try {
+ Task task = checkTaskStatus(taskId);
+ return okResponse(task.getTaskInfo(), MediaType.APPLICATION_XML);
+ } catch (GlusterRuntimeException e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ private Task checkTaskStatus(String taskId) {
+ Task task = getTask(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(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(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_TASK_ID) String taskId,
+ @QueryParam(FORM_PARAM_OPERATION) String taskOperation) {
+ Task task = getTask(taskId);
+ if (task == null) {
+ return notFoundResponse("Task [" + taskId + "] not found!");
+ }
+
+ if(taskOperation == null || taskOperation.isEmpty()) {
+ 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 successfully stopping the task, we can delete (forget) it as it is no more useful
+ taskOperation = RESTConstants.TASK_DELETE;
+ }
+
+ if (taskOperation.equals(RESTConstants.TASK_DELETE)) {
+ removeTask(task);
+ }
+
+ return noContentResponse();
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java
new file mode 100644
index 00000000..4b2701f2
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_USER;
+import static com.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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.provisioning.JdbcUserDetailsManager;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.model.Status;
+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;
+
+ 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(@FormParam("oldpassword") String oldPassword,
+ @FormParam("newpassword") String newPassword) {
+ try {
+ jdbcUserService.changePassword(oldPassword, passwordEncoder.encodePassword(newPassword, null));
+ } catch (Exception ex) {
+ String errMsg = "Could not change password. Error: [" + ex.getMessage() + "]";
+ logger.error(errMsg, ex);
+ return errorResponse(errMsg);
+ }
+ return noContentResponse();
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java
new file mode 100644
index 00000000..45df1ae7
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java
@@ -0,0 +1,989 @@
+/**
+ * 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 com.gluster.storage.management.gateway.resources.v1_0;
+
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_ACCESS_PROTOCOLS;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_AUTO_COMMIT;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_BRICKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FIX_LAYOUT;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FORCED_DATA_MIGRATE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MIGRATE_DATA;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPERATION;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPTION_KEY;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_OPTION_VALUE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_REPLICA_COUNT;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SOURCE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_STRIPE_COUNT;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_TARGET;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_TRANSPORT_TYPE;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_OPTIONS;
+import static com.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_VOLUME_TYPE;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_VOLUME_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_BRICK_NAME;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DELETE_OPTION;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DOWNLOAD;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_FROM_TIMESTAMP;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LINE_COUNT;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_LOG_SEVERITY;
+import static com.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TO_TIMESTAMP;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_BRICKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DEFAULT_OPTIONS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DOWNLOAD;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_LOGS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_OPTIONS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
+import static com.gluster.storage.management.core.constants.RESTConstants.RESOURCE_VOLUMES;
+import static com.gluster.storage.management.core.constants.RESTConstants.TASK_START;
+import static com.gluster.storage.management.core.constants.RESTConstants.TASK_STOP;
+
+import java.io.File;
+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 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 com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.constants.RESTConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+import com.gluster.storage.management.core.model.Brick;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.Volume;
+import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import com.gluster.storage.management.core.model.VolumeLogMessage;
+import com.gluster.storage.management.core.response.GenericResponse;
+import com.gluster.storage.management.core.response.LogMessageListResponse;
+import com.gluster.storage.management.core.response.VolumeListResponse;
+import com.gluster.storage.management.core.response.VolumeOptionInfoListResponse;
+import com.gluster.storage.management.core.utils.DateUtil;
+import com.gluster.storage.management.core.utils.FileUtil;
+import com.gluster.storage.management.core.utils.ProcessUtil;
+import com.gluster.storage.management.gateway.constants.VolumeOptionsDefaults;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.tasks.MigrateBrickTask;
+import com.gluster.storage.management.gateway.tasks.RebalanceVolumeTask;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+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 String VOLUME_DIRECTORY_CLEANUP_SCRIPT = "clear_volume_directory.py";
+ private static final String VOLUME_BRICK_LOG_SCRIPT = "get_volume_brick_log.py";
+ private static final Logger logger = Logger.getLogger(VolumesResource.class);
+
+ @InjectParam
+ private ServerUtil serverUtil;
+
+ @InjectParam
+ private GlusterUtil glusterUtil;
+
+ @InjectParam
+ private ClusterService clusterService;
+
+ @InjectParam
+ private VolumeOptionsDefaults volumeOptionsDefaults;
+
+ @InjectParam
+ private TasksResource taskResource;
+
+ @GET
+ @Produces({MediaType.APPLICATION_XML})
+ public Response getVolumesXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ return getVolumes(clusterName, MediaType.APPLICATION_XML);
+ }
+
+ @GET
+ @Produces({MediaType.APPLICATION_JSON})
+ public Response getVolumesJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ return getVolumes(clusterName, MediaType.APPLICATION_JSON);
+ }
+
+ public Response getVolumes(String clusterName, String mediaType) {
+ 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) {
+ // no server added yet. return an empty array.
+ return okResponse(new VolumeListResponse(), mediaType);
+ }
+
+ return okResponse(getVolumes(clusterName), mediaType);
+ }
+
+ public VolumeListResponse getVolumes(String clusterName) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return new VolumeListResponse(new ArrayList<Volume>());
+ }
+
+ try {
+ return new VolumeListResponse(glusterUtil.getAllVolumes(onlineServer.getName()));
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return new VolumeListResponse(new ArrayList<Volume>());
+ }
+
+ return new VolumeListResponse(glusterUtil.getAllVolumes(onlineServer.getName()));
+ }
+ }
+
+ @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) {
+ if(clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ String missingParam = checkMissingParamsForCreateVolume(volumeName, volumeType, transportType, replicaCount, stripeCount, bricks, accessProtocols, options);
+ if(missingParam != null) {
+ return badRequestResponse("Parameter [" + missingParam + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ if (volumeType.equals(VOLUME_TYPE.DISTRIBUTED_MIRROR) && replicaCount <= 0) {
+ return badRequestResponse("Replica count must be a positive integer");
+ }
+
+ if (volumeType.equals(VOLUME_TYPE.DISTRIBUTED_STRIPE) && stripeCount <= 0) {
+ return badRequestResponse("Stripe count must be a positive integer");
+ }
+
+ try {
+ performCreateVolume(clusterName, volumeName, volumeType, transportType, replicaCount, stripeCount, bricks, accessProtocols,
+ options);
+ return createdResponse(volumeName);
+ } catch (Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ public void performCreateVolume(String clusterName, String volumeName, String volumeType, String transportType, Integer replicaCount,
+ Integer stripeCount, String bricks, String accessProtocols, String options) {
+ 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, replicaCount, stripeCount, bricks, accessProtocols, options);
+ } catch (ConnectionException 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 + "]");
+ }
+
+ glusterUtil.createVolume(onlineServer.getName(), volumeName, volumeType, transportType, replicaCount, stripeCount, bricks, accessProtocols, options);
+ }
+ }
+
+ /**
+ * Returns name of the missing parameter if any. If all parameters are present,
+ * @param volumeName
+ * @param volumeType
+ * @param transportType
+ * @param replicaCount
+ * @param stripeCount
+ * @param bricks
+ * @param accessProtocols
+ * @param options
+ * @return
+ */
+ private String checkMissingParamsForCreateVolume(String volumeName, String volumeType,
+ String transportType, Integer replicaCount, Integer stripeCount, 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 :
+ (replicaCount == null) ? FORM_PARAM_REPLICA_COUNT :
+ (stripeCount == null) ? FORM_PARAM_STRIPE_COUNT :
+ (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 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 getVolume(clusterName, volumeName, MediaType.APPLICATION_JSON);
+ }
+
+ private Response getVolume(String clusterName, String volumeName, String mediaType) {
+ Volume volume = null;
+
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ try {
+ volume = getVolume(clusterName, volumeName);
+ return okResponse(volume, mediaType);
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ private Volume getVolume(String clusterName, String volumeName) {
+ Volume volume;
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ volume = glusterUtil.getVolume(volumeName, onlineServer.getName());
+ } catch (ConnectionException 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 + "]");
+ }
+
+ volume = glusterUtil.getVolume(volumeName, onlineServer.getName());
+ }
+ return volume;
+ }
+
+ @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) {
+ 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 {
+ if (operation.equals(RESTConstants.TASK_REBALANCE_START)) {
+ String taskId = rebalanceStart(clusterName, volumeName, isFixLayout, isMigrateData, isForcedDataMigrate);
+ return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS
+ + "/" + taskId);
+ } else if (operation.equals(RESTConstants.TASK_REBALANCE_STOP)) {
+ rebalanceStop(clusterName, volumeName);
+ } else {
+ performVolumeOperation(clusterName, volumeName, operation);
+ }
+ return noContentResponse();
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+ }
+
+ private void performVolumeOperation(String clusterName, String volumeName, String operation) {
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ try {
+ if (onlineServer == null) {
+ throw new GlusterRuntimeException("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ performOperation(volumeName, operation, onlineServer);
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ performOperation(volumeName, operation, onlineServer);
+ }
+ }
+
+ private void performOperation(String volumeName, String operation, GlusterServer onlineServer) {
+ if (operation.equals(TASK_START)) {
+ glusterUtil.startVolume(volumeName, onlineServer.getName());
+ } else if (operation.equals(TASK_STOP)) {
+ glusterUtil.stopVolume(volumeName, onlineServer.getName());
+ } else {
+ throw new GlusterValidationException("Invalid operation code [" + operation + "]");
+ }
+ }
+
+ @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) {
+ 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!");
+ }
+
+ if (deleteFlag == null) {
+ deleteFlag = false;
+ }
+
+ Volume volume = null;
+ try {
+ volume = getVolume(clusterName, volumeName);
+ } catch (Exception e) {
+ // TODO: Log the exception
+ return errorResponse(e.getMessage());
+ }
+
+ List<Brick> bricks = volume.getBricks();
+ Status status = glusterUtil.deleteVolume(volumeName, clusterService.getOnlineServer(clusterName)
+ .getName());
+ if(!status.isSuccess()) {
+ return errorResponse("Couldn't delete volume [" + volumeName + "]. Error: " + status);
+ }
+
+ try {
+ postDelete(volumeName, bricks, deleteFlag);
+ } catch(Exception e) {
+ return errorResponse("Volume [" + volumeName
+ + "] deleted from cluster, however following errors happened: " + CoreConstants.NEWLINE
+ + e.getMessage());
+ }
+
+ 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) {
+ List<String> brickList = Arrays.asList(bricks.split(",")); // Convert from comma separated string (query
+ // parameter)
+ 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 (bricks == null || bricks.isEmpty()) {
+ return badRequestResponse("Parameter [" + QUERY_PARAM_BRICKS + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ if(deleteFlag == null) {
+ deleteFlag = false;
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ removeBricks(clusterName, volumeName, brickList, onlineServer);
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ try {
+ cleanupDirectories(brickList, volumeName, brickList.size(), deleteFlag);
+ } catch(Exception e) {
+ // append cleanup error to prepare brick error
+ return errorResponse(e.getMessage());
+ }
+
+ return noContentResponse();
+ }
+
+ public void removeBricks(String clusterName, String volumeName, List<String> brickList, GlusterServer onlineServer) {
+ Status status;
+ try {
+ status = glusterUtil.removeBricks(volumeName, brickList, onlineServer.getName());
+ } catch (ConnectionException 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 + "]");
+ }
+ status = glusterUtil.removeBricks(volumeName, brickList, onlineServer.getName());
+ }
+ if (!status.isSuccess()) {
+ throw new GlusterRuntimeException(status.toString());
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void cleanupDirectories(List<String> bricks, String volumeName, int maxIndex, boolean deleteFlag) {
+ Status result;
+ String errors = "";
+ for (int i = 0; i < maxIndex; i++) {
+ String[] brickInfo = bricks.get(i).split(":");
+ String serverName = brickInfo[0];
+ String brickDirectory = brickInfo[1];
+
+ String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/"));
+ Object response = serverUtil.executeScriptOnServer(true, serverName, VOLUME_DIRECTORY_CLEANUP_SCRIPT + " "
+ + mountPoint + " " + volumeName + " " + (deleteFlag ? "-d" : ""), GenericResponse.class);
+ if (response instanceof GenericResponse) {
+ result = ((GenericResponse) response).getStatus();
+ if (!result.isSuccess()) {
+ errors += "[" + mountPoint + "][" + volumeName + "] => " + result
+ + CoreConstants.NEWLINE;
+ }
+ } else {
+ Status errStatus = (Status) response;
+ errors += "[" + mountPoint + "][" + volumeName + "] => " + errStatus + CoreConstants.NEWLINE;
+ }
+ }
+ if(!errors.trim().isEmpty()) {
+ throw new GlusterRuntimeException("Volume directory cleanup errors: " + errors.trim());
+ }
+ }
+
+ private void postDelete(String volumeName, List<Brick> bricks, boolean deleteFlag) {
+ Status result;
+ for (Brick brick : bricks) {
+ String brickDirectory = brick.getBrickDirectory();
+ String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/"));
+
+ result = (Status) serverUtil.executeScriptOnServer(true, brick.getServerName(), VOLUME_DIRECTORY_CLEANUP_SCRIPT
+ + " " + mountPoint + " " + volumeName + (deleteFlag ? " -d" : ""), Status.class);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Error in post-delete operation of volume [" + volumeName + "]: "
+ + result);
+ }
+ }
+ }
+
+ @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) {
+ 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(key == null || key.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_OPTION_KEY + "] is missing in request!");
+ }
+
+ if(value == null || value.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_OPTION_VALUE + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.setOption(volumeName, key, value, onlineServer.getName());
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.setOption(volumeName, key, value, onlineServer.getName());
+ } catch(Exception e1) {
+ return errorResponse(e1.getMessage());
+ }
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ 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) {
+ 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!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.resetOptions(volumeName, onlineServer.getName());
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.resetOptions(volumeName, onlineServer.getName());
+ } catch(Exception e1) {
+ return errorResponse(e1.getMessage());
+ }
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ return noContentResponse();
+ }
+
+ @GET
+ @Path(RESOURCE_DEFAULT_OPTIONS)
+ @Produces(MediaType.APPLICATION_XML)
+ public VolumeOptionInfoListResponse getDefaultOptionsXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ // TODO: Fetch all volume options with their default values from GlusterFS
+ // whenever such a CLI command is made available in GlusterFS
+ return new VolumeOptionInfoListResponse(Status.STATUS_SUCCESS, volumeOptionsDefaults.getDefaults());
+ }
+
+ @GET
+ @Path(RESOURCE_DEFAULT_OPTIONS)
+ @Produces(MediaType.APPLICATION_JSON)
+ public VolumeOptionInfoListResponse getDefaultOptionsJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName) {
+ // TODO: Fetch all volume options with their default values from GlusterFS
+ // whenever such a CLI command is made available in GlusterFS
+ return new VolumeOptionInfoListResponse(Status.STATUS_SUCCESS, volumeOptionsDefaults.getDefaults());
+ }
+
+ 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.getBrickDirectory());
+ String logFilePath = logDir + CoreConstants.FILE_SEPARATOR + logFileName;
+
+ // Usage: get_volume_disk_log.py <volumeName> <diskName> <lineCount>
+ Object responseObj = serverUtil.executeScriptOnServer(true, brick.getServerName(), VOLUME_BRICK_LOG_SCRIPT
+ + " " + logFilePath + " " + lineCount, LogMessageListResponse.class);
+
+ LogMessageListResponse response = null;
+ if (responseObj instanceof LogMessageListResponse) {
+ response = (LogMessageListResponse) responseObj;
+ // populate disk and trim other fields
+ List<VolumeLogMessage> logMessages = response.getLogMessages();
+ for (VolumeLogMessage logMessage : logMessages) {
+ logMessage.setBrickDirectory(brick.getBrickDirectory());
+ }
+ return logMessages;
+ } else {
+ Status status = (Status) responseObj;
+ throw new GlusterRuntimeException(status.toString());
+ }
+ }
+
+ @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 = getVolume(clusterName, volumeName);
+ File archiveFile = new File(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;
+ }
+ }
+
+
+ private 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.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";
+ new ProcessUtil().executeCommand("tar", "czvf", gzipPath, "-C", tempDir.getParent(), tempDir.getName());
+
+ // delete the temp directory
+ FileUtil.recursiveDelete(tempDir);
+
+ return gzipPath;
+ }
+
+ @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);
+ }
+
+ public Response getLogs(String clusterName, String volumeName, String brickName, String severity,
+ String fromTimestamp, String toTimestamp, Integer lineCount, String mediaType) {
+ 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!");
+ }
+
+ List<VolumeLogMessage> logMessages = null;
+ Volume volume = null;
+ try {
+ volume = (Volume) getVolume(clusterName, volumeName);
+ } catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ 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 okResponse(new LogMessageListResponse(logMessages), mediaType);
+ }
+
+ 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;
+ }
+
+ @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) {
+ if (clusterName == null || clusterName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (volumeName == null || volumeName.isEmpty()) {
+ return badRequestResponse("Cluster name must not be empty!");
+ }
+
+ if (bricks == null || bricks.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_BRICKS + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ List<String> brickList = Arrays.asList(bricks.split(","));
+ try {
+ glusterUtil.addBricks(volumeName, brickList, onlineServer.getName());
+ } catch (ConnectionException e) {
+ // online server has gone offline! try with a different one.
+ onlineServer = clusterService.getNewOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ try {
+ glusterUtil.addBricks(volumeName, brickList, onlineServer.getName());
+ } catch(Exception e1) {
+ return errorResponse(e1.getMessage());
+ }
+ } catch(Exception e1) {
+ return errorResponse(e1.getMessage());
+ }
+
+ return createdResponse("");
+ }
+
+ @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) {
+
+ 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 (fromBrick == null || fromBrick.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_SOURCE + "] is missing in request!");
+ }
+
+ if (toBrick == null || toBrick.isEmpty()) {
+ return badRequestResponse("Parameter [" + FORM_PARAM_TARGET + "] is missing in request!");
+ }
+
+ if (clusterService.getCluster(clusterName) == null) {
+ return notFoundResponse("Cluster [" + clusterName + "] not found!");
+ }
+
+ GlusterServer onlineServer = clusterService.getOnlineServer(clusterName);
+ if (onlineServer == null) {
+ return errorResponse("No online servers found in cluster [" + clusterName + "]");
+ }
+
+ if(autoCommit == null) {
+ autoCommit = false;
+ }
+
+ String taskId = null;
+ try {
+ taskId = migrateBrickStart(clusterName, volumeName, fromBrick, toBrick, autoCommit);
+ }catch(Exception e) {
+ return errorResponse(e.getMessage());
+ }
+
+ return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + "/"
+ + taskId);
+ }
+
+ private String migrateBrickStart(String clusterName, String volumeName, String fromBrick, String toBrick,
+ Boolean autoCommit) {
+ MigrateBrickTask migrateDiskTask = new MigrateBrickTask(clusterService, clusterName, volumeName, fromBrick,
+ toBrick);
+ migrateDiskTask.setAutoCommit(autoCommit);
+ migrateDiskTask.start();
+ taskResource.addTask(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;
+ }
+
+ private 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(rebalanceTask);
+ return rebalanceTask.getId();
+ }
+
+ public void rebalanceStop(String clusterName, String volumeName) {
+ // TODO: arrive at the task id and fetch it
+ String taskId = "";
+
+ taskResource.getTask(taskId).stop();
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java
new file mode 100644
index 00000000..e806051c
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/UserAuthDao.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/UserAuthDao.java
new file mode 100644
index 00000000..bdc3b19e
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/security/UserAuthDao.java
@@ -0,0 +1,42 @@
+/**
+ * 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 com.gluster.storage.management.gateway.security;
+
+import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
+
+/**
+ * @author root
+ *
+ */
+public class UserAuthDao extends JdbcDaoImpl implements GlusterUserDetailsService {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.gluster.storage.management.gateway.security.GlusterUserDetailsService#changePassword(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void changePassword(String username, String password) {
+ getJdbcTemplate().update("UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?", password, username);
+ }
+
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/ClusterService.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/ClusterService.java
new file mode 100644
index 00000000..e01c5096
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.gluster.storage.management.gateway.services;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityTransaction;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import com.gluster.storage.management.core.utils.LRUCache;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.data.PersistenceDao;
+import com.gluster.storage.management.gateway.data.ServerInfo;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+import com.gluster.storage.management.gateway.utils.SshUtil;
+
+/**
+ * Service class for functionality related to clusters
+ */
+@Component
+public class ClusterService {
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ @Autowired
+ private PersistenceDao<ServerInfo> serverDao;
+
+ @Autowired
+ private GlusterUtil glusterUtil;
+
+ @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().equals(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().equals(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 = glusterUtil.getGlusterServers(server);
+ List<ServerInfo> servers = new ArrayList<ServerInfo>();
+ for(GlusterServer glusterServer : glusterServers) {
+ String serverName = glusterServer.getName();
+
+ 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().equals(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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
new file mode 100644
index 00000000..d1437cec
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/services/GlusterServerService.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.services;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.exceptions.GlusterValidationException;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+
+/**
+ *
+ */
+@Component
+public class GlusterServerService {
+ @Autowired
+ protected ServerUtil serverUtil;
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private GlusterUtil glusterUtil;
+
+ public void fetchServerDetails(GlusterServer server) {
+ try {
+ server.setStatus(SERVER_STATUS.ONLINE);
+ serverUtil.fetchServerDetails(server);
+ } catch (ConnectionException e) {
+ server.setStatus(SERVER_STATUS.OFFLINE);
+ }
+ }
+
+ public List<GlusterServer> getGlusterServers(String clusterName, boolean fetchDetails) {
+ 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);
+ } catch (ConnectionException 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 + "]");
+ }
+ glusterServers = getGlusterServers(clusterName, onlineServer, fetchDetails);
+ }
+ return glusterServers;
+ }
+
+ private List<GlusterServer> getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails) {
+ List<GlusterServer> glusterServers;
+ try {
+ glusterServers = glusterUtil.getGlusterServers(onlineServer);
+ } catch (ConnectionException 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 + "]");
+ }
+
+ glusterServers = glusterUtil.getGlusterServers(onlineServer);
+ }
+
+ if (fetchDetails) {
+ String errMsg = fetchDetailsOfServers(glusterServers, onlineServer);
+ if (!errMsg.isEmpty()) {
+ throw new GlusterRuntimeException("Couldn't fetch details for server(s): " + errMsg);
+ }
+ }
+ return glusterServers;
+ }
+
+ private String fetchDetailsOfServers(List<GlusterServer> glusterServers, GlusterServer onlineServer) {
+ String errMsg = "";
+
+ for (GlusterServer server : glusterServers) {
+ try {
+ fetchServerDetails(server);
+ } catch (Exception e) {
+ errMsg += CoreConstants.NEWLINE + server.getName() + " : [" + e.getMessage() + "]";
+ }
+ }
+ return errMsg;
+ }
+
+ 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 = glusterUtil.getGlusterServer(onlineServer, serverName);
+ } catch (ConnectionException 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 + "]");
+ }
+ server = glusterUtil.getGlusterServer(onlineServer, serverName);
+ }
+
+ if (fetchDetails && server.isOnline()) {
+ 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;
+ }
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java
new file mode 100644
index 00000000..6d525785
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java
@@ -0,0 +1,162 @@
+/**
+ * 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 com.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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.RowCallbackHandler;
+import org.springframework.jdbc.core.support.JdbcDaoSupport;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.data.PersistenceDao;
+
+/**
+ * Initializes the Gluster Management Server.
+ */
+public class InitServerTask extends JdbcDaoSupport {
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @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);
+ String encodedPassword = passwordEncoder.encodePassword(password, null);
+ 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();
+ }
+
+ // For development time debugging. To be removed later.
+ List<ClusterInfo> clusters = clusterDao.findAll();
+ logger.info(clusters.size());
+
+ if (clusters.size() > 0) {
+ for (ClusterInfo cluster : clusters) {
+ logger.info("Cluster: [" + cluster.getId() + "][" + cluster.getName() + "]");
+ }
+ } else {
+
+ }
+ }
+
+ 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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
new file mode 100644
index 00000000..e7da1de6
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java
@@ -0,0 +1,164 @@
+/**
+ * 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 com.gluster.storage.management.gateway.tasks;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.gluster.storage.management.core.constants.GlusterConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.TaskInfo;
+import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+import com.gluster.storage.management.gateway.utils.SshUtil;
+import com.sun.jersey.core.util.Base64;
+
+public class InitializeDiskTask extends Task {
+
+ private static final String INITIALIZE_DISK_SCRIPT = "format_device.py";
+
+ private String serverName;
+ private String diskName;
+ private String fsType;
+ private ServerUtil serverUtil;
+ private GlusterUtil glusterUtil;
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, String serverName, String diskName, String fsType) {
+ super(clusterService, clusterName, TASK_TYPE.DISK_FORMAT, diskName, "Initialize disk " + serverName + ":"
+ + diskName, false, false, false);
+
+ setServerName(serverName);
+ setDiskName(diskName);
+ setFsType(fsType);
+ taskInfo.setName(getId());
+ init();
+ }
+
+ public InitializeDiskTask(ClusterService clusterService, String clusterName, TaskInfo info) {
+ super(clusterService, clusterName, info);
+ init();
+ }
+
+ private void init() {
+ ApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
+ glusterUtil = ctx.getBean(GlusterUtil.class);
+ 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 fsTypeCommand = (getFsType().equals(GlusterConstants.FSTYPE_DEFAULT)) ? "" : " -t " + getFsType();
+
+ String output = (String) serverUtil.executeScriptOnServer(true, serverName, INITIALIZE_DISK_SCRIPT
+ + fsTypeCommand + " " + getDiskName(), String.class);
+ 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 glusterUtil.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()));
+ }
+ }
+
+ 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;
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
new file mode 100644
index 00000000..694067aa
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java
@@ -0,0 +1,227 @@
+/**
+ * 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 com.gluster.storage.management.gateway.tasks;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.sun.jersey.core.util.Base64;
+
+public class MigrateBrickTask extends Task {
+
+ private String fromBrick;
+ private String toBrick;
+ private Boolean autoCommit;
+ private GlusterUtil glusterUtil;
+
+ 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, "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();
+ glusterUtil = ctx.getBean(GlusterUtil.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 (ConnectionException e) {
+ // online server might have gone Offline. try with a new one.
+ startMigration(getNewOnlineServer().getName());
+ }
+ }
+
+ private void startMigration(String onlineServerName) {
+ ProcessResult processResult = glusterUtil.executeBrickMigration(onlineServerName, getTaskInfo().getReference(),
+ getFromBrick(), getToBrick(), "start");
+ if (processResult.getOutput().trim().matches(".*started successfully$")) {
+ getTaskInfo().setStatus(
+ new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput().trim())));
+ return;
+ }
+ }
+
+ @Override
+ public void pause() {
+ try {
+ pauseMigration(getOnlineServer().getName());
+ } catch (ConnectionException e) {
+ // online server might have gone offline. try with a new one.
+ pauseMigration(getNewOnlineServer().getName());
+ }
+ }
+
+ private void pauseMigration(String onlineServer) {
+ ProcessResult processResult = glusterUtil.executeBrickMigration(onlineServer, taskInfo.getReference(),
+ getFromBrick(), getToBrick(), "pause");
+ TaskStatus taskStatus = new TaskStatus();
+ if (processResult.getOutput().trim().matches(".*paused successfully$")) {
+ taskStatus.setCode(Status.STATUS_CODE_PAUSE);
+ taskStatus.setMessage(processResult.getOutput());
+ getTaskInfo().setStatus(taskStatus);
+ return;
+ }
+ }
+
+ @Override
+ public void resume() {
+ start();
+ }
+
+ @Override
+ public void commit() {
+ try {
+ commitMigration(getOnlineServer().getName());
+ } catch (ConnectionException e) {
+ // online server might have gone offline. try with a new one.
+ commitMigration(getNewOnlineServer().getName());
+ }
+ }
+
+ private void commitMigration(String serverName) {
+ ProcessResult processResult = glusterUtil.executeBrickMigration(serverName, getTaskInfo().getReference(),
+ getFromBrick(), getToBrick(), "commit");
+ TaskStatus taskStatus = new TaskStatus();
+ if (processResult.isSuccess()) {
+ if (processResult.getOutput().trim().matches(".*commit successful$")) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage(processResult.getOutput());
+ getTaskInfo().setStatus(taskStatus);
+ }
+ }
+ }
+
+ @Override
+ public void stop() {
+ try {
+ stopMigration(getOnlineServer().getName());
+ } catch (ConnectionException e) {
+ // online server might have gone offline. try with a new one.
+ stopMigration(getNewOnlineServer().getName());
+ }
+ }
+
+ private void stopMigration(String serverName) {
+ ProcessResult processResult = glusterUtil.executeBrickMigration(serverName, taskInfo.getReference(), getFromBrick(),
+ getToBrick(), "abort");
+ TaskStatus taskStatus = new TaskStatus();
+ if (processResult.getOutput().trim().matches(".*aborted successfully$")) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage(processResult.getOutput());
+ getTaskInfo().setStatus(taskStatus);
+ }
+ }
+
+ @Override
+ public TaskStatus checkStatus() {
+ try {
+ return checkMigrationStatus(getOnlineServer().getName());
+ } catch (ConnectionException e) {
+ // online server might have gone offline. try with a new one.
+ return checkMigrationStatus(getNewOnlineServer().getName());
+ }
+ }
+
+ private TaskStatus checkMigrationStatus(String serverName) {
+ if (getTaskInfo().getStatus().getCode() == Status.STATUS_CODE_PAUSE) {
+ return getTaskInfo().getStatus();
+ }
+ // For committed task, status command (CLI) is invalid, just return current status
+ if (getTaskInfo().getStatus().getCode() == Status.STATUS_CODE_SUCCESS) {
+ return getTaskInfo().getStatus();
+ }
+
+
+ TaskStatus taskStatus = new TaskStatus();
+ try {
+ ProcessResult processResult = glusterUtil.executeBrickMigration(serverName, getTaskInfo().getReference(),
+ getFromBrick(), getToBrick(), "status");
+ if (processResult.getOutput().trim().matches("^Number of files migrated.*Migration complete$")
+ || processResult.getOutput().trim().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);
+ if (autoCommit) {
+ commitMigration(serverName);
+ return getTaskInfo().getStatus(); // return the committed status
+ } else {
+ taskStatus.setMessage(processResult.getOutput().trim()
+ .replaceAll("Migration complete", "Commit pending"));
+ }
+ } else if (processResult.getOutput().trim().matches("^Number of files migrated.*Current file=.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ } else {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+ taskStatus.setMessage(processResult.getOutput());
+ } catch (Exception e) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ taskStatus.setMessage(e.getMessage());
+ }
+ taskInfo.setStatus(taskStatus); // Update the task status
+ return taskStatus;
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
new file mode 100644
index 00000000..c53f0252
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java
@@ -0,0 +1,129 @@
+/**
+ * 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 com.gluster.storage.management.gateway.tasks;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.web.context.ContextLoader;
+
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.utils.GlusterUtil;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+import com.gluster.storage.management.gateway.utils.SshUtil;
+import com.sun.jersey.core.util.Base64;
+
+public class RebalanceVolumeTask extends Task {
+
+ private String layout;
+ private String serverName;
+ private ServerUtil serverUtil;
+ private GlusterUtil 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(GlusterUtil.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(ConnectionException e) {
+ // online server might have gone offline. try with a new one
+ serverName = getNewOnlineServer().getName();
+ startRebalance(serverName);
+ }
+ }
+
+ private void startRebalance(String serverName) {
+ String command = "gluster volume rebalance " + getTaskInfo().getReference() + " " + getLayout() + " start";
+ String output = (String)serverUtil.executeOnServer(true, serverName, command, String.class);
+ 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 (ConnectionException e) {
+ // online server might have gone offline. update the failure status
+ getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_FAILURE, 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(ConnectionException e) {
+ // 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();
+ }
+ }
+
+ 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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java
new file mode 100644
index 00000000..94c743aa
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java
@@ -0,0 +1,154 @@
+/**
+ * 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 com.gluster.storage.management.gateway.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.constants.GlusterConstants;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.utils.GlusterCoreUtil;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.gateway.data.ClusterInfo;
+import com.gluster.storage.management.gateway.data.PersistenceDao;
+import com.gluster.storage.management.gateway.data.ServerInfo;
+import com.gluster.storage.management.gateway.resources.v1_0.DiscoveredServersResource;
+import com.gluster.storage.management.gateway.services.ClusterService;
+import com.gluster.storage.management.gateway.services.GlusterServerService;
+import com.gluster.storage.management.gateway.utils.ServerUtil;
+
+/**
+ * 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 DiscoveredServersResource discoveredServersResource;
+
+ @Autowired
+ private GlusterServerService glusterServerService;
+
+ @Autowired
+ private String discoveryMechanism;
+
+ @Autowired
+ private ClusterService clusterService;
+
+ @Autowired
+ private PersistenceDao<ClusterInfo> clusterDao;
+
+ public void perform() {
+ discoverServers();
+ syncClusterServerMapping();
+ }
+
+ private void syncClusterServerMapping() {
+ List<ClusterInfo> clusters = clusterService.getAllClusters();
+ for(ClusterInfo cluster : clusters) {
+ List<ServerInfo> servers = cluster.getServers();
+ List<GlusterServer> actualServers = glusterServerService.getGlusterServers(cluster.getName(), false);
+ updateRemovedServers(cluster, servers, actualServers);
+ updateAddedServers(cluster, servers, actualServers);
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ discoveredServersResource.setDiscoveredServerNames(serverNameList);
+ }
+} \ No newline at end of file
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/Task.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/Task.java
new file mode 100644
index 00000000..1ba360bc
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/tasks/Task.java
@@ -0,0 +1,112 @@
+/**
+ * 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 com.gluster.storage.management.gateway.tasks;
+
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.TaskInfo;
+import com.gluster.storage.management.core.model.TaskInfo.TASK_TYPE;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java
new file mode 100644
index 00000000..13a58729
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.ServerStats;
+import com.gluster.storage.management.core.model.ServerStatsRow;
+import com.gluster.storage.management.core.model.Status;
+
+/**
+ *
+ */
+@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);
+
+ for (String serverName : serverNames) {
+ try {
+ // fetch the stats and add to aggregated stats
+ addServerStats(fetchStats(serverName, period), aggregatedStats, dataCount);
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch performance stats from server [" + serverName + "]!", e);
+ continue;
+ }
+ }
+
+ 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++) {
+ 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.
+ aggregatedStatsRowData.set(i, aggregatedStatsRowData.get(i) + 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++) {
+ 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;
+ }
+ }
+ Object output = serverUtil.executeScriptOnServer(true, serverName, getStatsScriptName() + argsStr + " "
+ + period, ServerStats.class);
+ //String cpuUsageData = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> <xport> <meta> <start>1310468100</start> <step>300</step> <end>1310471700</end> <rows>13</rows> <columns>3</columns> <legend> <entry>user</entry> <entry>system</entry> <entry>total</entry> </legend> </meta> <data> <row><t>1310468100</t><v>2.23802952e-1</v><v>4.3747778209e-01</v><v>6.6128073384e-01</v></row> <row><t>1310468400</t><v>2.3387347338e-01</v><v>4.4642717442e-01</v><v>6.8030064780e-01</v></row> <row><t>1310468700</t><v>5.5043873220e+00</v><v>6.2462376636e+00</v><v>1.1750624986e+01</v></row> <row><t>1310469000</t><v>2.4350593653e+01</v><v>2.6214585217e+01</v><v>5.0565178869e+01</v></row> <row><t>1310469300</t><v>4.0786489953e+01</v><v>4.6784713828e+01</v><v>8.7571203781e+01</v></row> <row><t>1310469600</t><v>4.1459955508e+01</v><v>5.2546309044e+01</v><v>9.4006264551e+01</v></row> <row><t>1310469900</t><v>4.2312286165e+01</v><v>5.2390588332e+01</v><v>9.4702874497e+01</v></row> <row><t>1310470200</t><v>4.2603794982e+01</v><v>5.1598861493e+01</v><v>9.4202656475e+01</v></row> <row><t>1310470500</t><v>3.8238751290e+01</v><v>4.5312089966e+01</v><v>8.3550841256e+01</v></row> <row><t>1310470800</t><v>1.7949961224e+01</v><v>2.1282058418e+01</v><v>3.9232019642e+01</v></row> <row><t>1310471100</t><v>1.2330371421e-01</v><v>4.6347832868e-01</v><v>5.8678204289e-01</v></row> <row><t>1310471400</t><v>1.6313260492e-01</v><v>5.4088119561e-01</v><v>7.0401380052e-01</v></row> <row><t>1310471700</t><v>NaN</v><v>NaN</v><v>NaN</v></row> </data> </xport>";
+ //Object output = unmarshal(ServerStats.class, cpuUsageData, false);
+ if(output instanceof Status) {
+ throw new GlusterRuntimeException(((Status)output).toString());
+ }
+ return (ServerStats) output;
+ }
+
+ public abstract String getStatsScriptName();
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java
new file mode 100644
index 00000000..b6ef9ef2
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java
new file mode 100644
index 00000000..55909d54
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java
@@ -0,0 +1,662 @@
+/**
+ * GlusterUtil.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 com.gluster.storage.management.gateway.utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.constants.GlusterConstants;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.Brick;
+import com.gluster.storage.management.core.model.Brick.BRICK_STATUS;
+import com.gluster.storage.management.core.model.GlusterServer;
+import com.gluster.storage.management.core.model.InitDiskStatusResponse;
+import com.gluster.storage.management.core.model.InitDiskStatusResponse.FORMAT_STATUS;
+import com.gluster.storage.management.core.model.Server.SERVER_STATUS;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.model.TaskStatus;
+import com.gluster.storage.management.core.model.Volume;
+import com.gluster.storage.management.core.model.Volume.TRANSPORT_TYPE;
+import com.gluster.storage.management.core.model.Volume.VOLUME_STATUS;
+import com.gluster.storage.management.core.model.Volume.VOLUME_TYPE;
+import com.gluster.storage.management.core.utils.GlusterCoreUtil;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.core.utils.StringUtil;
+import com.gluster.storage.management.gateway.resources.v1_0.TasksResource;
+
+@Component
+public class GlusterUtil {
+ private static final String glusterFSminVersion = "3.1";
+
+ 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 = "Connected";
+
+ 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_OPTION_AUTH_ALLOW_PFX = "auth.allow:";
+ private static final String VOLUME_LOG_LOCATION_PFX = "log file location:";
+ private static final String VOLUME_TYPE_DISTRIBUTE = "Distribute";
+ private static final String VOLUME_TYPE_REPLICATE = "Replicate";
+ private static final String GLUSTERD_INFO_FILE = "/etc/glusterd/glusterd.info";
+
+ private static final GlusterCoreUtil glusterCoreUtil = new GlusterCoreUtil();
+
+ private static final String INITIALIZE_DISK_STATUS_SCRIPT = "get_format_device_status.py";
+
+ @Autowired
+ private SshUtil sshUtil;
+
+ @Autowired
+ private ServerUtil serverUtil;
+
+ @Autowired
+ private TasksResource taskResource;
+
+ public void setSshUtil(SshUtil sshUtil) {
+ this.sshUtil = sshUtil;
+ }
+
+ public SshUtil getSshUtil() {
+ return sshUtil;
+ }
+
+ /**
+ * Extract value of given token from given line. It is assumed that the token, if present, will be of the following
+ * form: <code>token: value</code>
+ *
+ * @param line
+ * Line to be analyzed
+ * @param token
+ * Token whose value is to be extracted
+ * @return Value of the token, if present in the line
+ */
+ private final String extractToken(String line, String token) {
+ if (line.contains(token)) {
+ return line.split(token)[1].trim();
+ }
+ return null;
+ }
+
+ public GlusterServer getGlusterServer(GlusterServer onlineServer, String serverName) {
+ List<GlusterServer> servers = getGlusterServers(onlineServer);
+ for (GlusterServer server : servers) {
+ if (server.getName().equals(serverName)) {
+ return server;
+ }
+ }
+ return null;
+ }
+
+ private String getUuid(String serverName) {
+ ProcessResult result = getSshUtil().executeRemote(serverName, "cat " + GLUSTERD_INFO_FILE);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Couldn't read file [" + GLUSTERD_INFO_FILE + "]. Error: "
+ + result.toString());
+ }
+ return result.getOutput().split("=")[1];
+ }
+
+ public List<GlusterServer> getGlusterServers(GlusterServer knownServer) {
+ String output = getPeerStatus(knownServer.getName());
+ if (output == null) {
+ return null;
+ }
+
+ knownServer.setUuid(getUuid(knownServer.getName()));
+
+ 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 = 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 = 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 = extractToken(line, HOSTNAME_PFX);
+ if (hostName != null) {
+ server.setName(hostName);
+ foundHost = true;
+ }
+ }
+
+ }
+ return glusterServers;
+ }
+
+ public List<String> getGlusterServerNames(String knownServer) {
+ String output = getPeerStatus(knownServer);
+ if (output == null) {
+ return null;
+ }
+
+ List<String> glusterServerNames = new ArrayList<String>();
+ for (String line : output.split(CoreConstants.NEWLINE)) {
+ String hostName = extractToken(line, HOSTNAME_PFX);
+ if (hostName != null) {
+ glusterServerNames.add(hostName);
+ }
+ }
+ return glusterServerNames;
+ }
+
+ /**
+ * @param knownServer
+ * A known server on which the gluster command will be executed to fetch peer status
+ * @return Outout of the "gluster peer status" command
+ */
+ private String getPeerStatus(String knownServer) {
+ String output;
+ ProcessResult result = getSshUtil().executeRemote(knownServer, "gluster peer status");
+ if (!result.isSuccess()) {
+ output = null;
+ }
+ output = result.getOutput();
+ return output;
+ }
+
+ public void addServer(String existingServer, String newServer) {
+ ProcessResult result = sshUtil.executeRemote(existingServer, "gluster peer probe " + newServer);
+ if(!result.isSuccess()) {
+ throw new GlusterRuntimeException("Couldn't probe server [" + newServer + "] from [" + existingServer
+ + "]. Error: " + result);
+ }
+
+ // reverse peer probe to ensure that host names appear in peer status on both sides
+ result = sshUtil.executeRemote(newServer, "gluster peer probe " + existingServer);
+ if(!result.isSuccess()) {
+ throw new GlusterRuntimeException("Couldn't _reverse_ probe server [" + existingServer + "] from ["
+ + newServer + "]. Error: " + result);
+ }
+ }
+
+ public Status startVolume(String volumeName, String knownServer) {
+ return new Status(sshUtil.executeRemote(knownServer, "gluster volume start " + volumeName));
+ }
+
+ public Status stopVolume(String volumeName, String knownServer) {
+ return new Status(sshUtil.executeRemote(knownServer, "gluster --mode=script volume stop " + volumeName));
+ }
+
+ public void resetOptions(String volumeName, String knownServer) {
+ ProcessResult result = sshUtil.executeRemote(knownServer, "gluster volume reset " + volumeName);
+ if(!result.isSuccess()) {
+ throw new GlusterRuntimeException("Couldn't reset options for volume [" + volumeName + "]! Error: "
+ + result);
+ }
+ }
+
+ public void createVolume(String knownServer, String volumeName, String volumeTypeStr, String transportTypeStr,
+ Integer replicaCount, Integer stripeCount, String bricks, String accessProtocols, String options) {
+
+ int count = 1; // replica or stripe count
+
+ VOLUME_TYPE volType = Volume.getVolumeTypeByStr(volumeTypeStr);
+ String volTypeArg = null;
+ if (volType == VOLUME_TYPE.DISTRIBUTED_MIRROR) {
+ volTypeArg = "replica";
+ count = replicaCount;
+ } else if (volType == VOLUME_TYPE.DISTRIBUTED_STRIPE) {
+ volTypeArg = "stripe";
+ count = stripeCount;
+ }
+
+ 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);
+ ProcessResult result = sshUtil.executeRemote(knownServer, command);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Error in creating volume [" + volumeName + "]: " + result);
+ }
+
+ 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();
+ }
+
+ 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());
+ }
+ }
+
+ public void setOption(String volumeName, String key, String value, String knownServer) {
+ ProcessResult result = sshUtil.executeRemote(knownServer, "gluster volume set " + volumeName + " " + key + " "
+ + "\"" + value + "\"");
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Volume [" + volumeName + "] set [" + key + "=" + value + "] => "
+ + result);
+ }
+ }
+
+ public Status deleteVolume(String volumeName, String knownServer) {
+ return new Status(sshUtil.executeRemote(knownServer, "gluster --mode=script volume delete " + volumeName));
+ }
+
+ private String getVolumeInfo(String volumeName, String knownServer) {
+ ProcessResult result = sshUtil.executeRemote(knownServer, "gluster volume info " + volumeName);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Command [gluster volume info " + volumeName + "] failed on ["
+ + knownServer + "] with error: " + result);
+ }
+ return result.getOutput();
+ }
+
+ private String getVolumeInfo(String knownServer) {
+ ProcessResult result = sshUtil.executeRemote(knownServer, "gluster volume info ");
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Command [gluster volume info] failed on [" + knownServer
+ + "] with error: " + result);
+ }
+ return result.getOutput();
+ }
+
+ private boolean readVolumeType(Volume volume, String line) {
+ String volumeType = extractToken(line, VOLUME_TYPE_PFX);
+ if (volumeType != null) {
+ if (volumeType.equals(VOLUME_TYPE_DISTRIBUTE)) {
+ volume.setVolumeType(VOLUME_TYPE.PLAIN_DISTRIBUTE);
+ } else if (volumeType.equals(VOLUME_TYPE_REPLICATE)) {
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_MIRROR);
+ volume.setReplicaCount(Volume.DEFAULT_REPLICA_COUNT);
+ } else {
+ volume.setVolumeType(VOLUME_TYPE.DISTRIBUTED_STRIPE);
+ volume.setStripeCount(Volume.DEFAULT_STRIPE_COUNT);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void readReplicaOrStripeCount(Volume volume, String line) {
+ if (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.DISTRIBUTED_STRIPE) {
+ volume.setStripeCount(count);
+ } else if (volume.getVolumeType() == VOLUME_TYPE.DISTRIBUTED_MIRROR) {
+ volume.setReplicaCount(count);
+ volume.setStripeCount(0);
+ }
+
+ }
+ return;
+ }
+
+ private boolean readVolumeStatus(Volume volume, String line) {
+ String volumeStatus = 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 = 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) {
+ //If brick directory has standard path, find and assign device name otherwise null
+ String stdBrickDirPattern = "^/export/.*/.*"; // e.g: /export/sdb/test
+ String deviceName = null;
+ if (Pattern.matches(stdBrickDirPattern, brickDir) ) {
+ deviceName = brickDir.split("/")[2].trim();
+ }
+ volume.addBrick(new Brick(serverName, status, deviceName, brickDir));
+ }
+
+ // Do not throw exception, Gracefully handle as Offline brick.
+ private BRICK_STATUS getBrickStatus(String serverName, String volumeName, String brick){
+ try {
+ ProcessResult output = getSshUtil().executeRemote(serverName, "get_brick_status.py" + " " + volumeName + " " + brick);
+
+ if (output.isSuccess() && output.getOutput().equals(CoreConstants.ONLINE)) {
+ return BRICK_STATUS.ONLINE;
+ } else {
+ return BRICK_STATUS.OFFLINE;
+ }
+ } catch(Exception e) { // Particularly interested on ConnectionExecption, if the server is offline
+ return BRICK_STATUS.OFFLINE;
+ }
+ }
+
+ private boolean readBrickGroup(String line) {
+ return extractToken(line, VOLUME_BRICKS_GROUP_PFX) != null;
+ }
+
+ private boolean readOptionReconfigGroup(String line) {
+ return 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;
+ }
+
+ public Volume getVolume(String volumeName, String knownServer) {
+ return parseVolumeInfo(getVolumeInfo(volumeName, knownServer)).get(0);
+ }
+
+ 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 = 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 (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;
+ }
+ }
+ }
+
+ if (volume != null) {// Adding the last volume parsed
+ volumes.add(volume);
+ }
+
+ return volumes;
+ }
+
+ 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);
+ }
+
+ ProcessResult result = sshUtil.executeRemote(knownServer, command.toString());
+ if(!result.isSuccess()) {
+ throw new GlusterRuntimeException("Error in volume [" + volumeName + "] add-brick [" + bricks + "]: "
+ + result);
+ }
+ }
+
+ public String getLogLocation(String volumeName, String brickName, String knownServer) {
+ String command = "gluster volume log locate " + volumeName + " " + brickName;
+ ProcessResult result = sshUtil.executeRemote(knownServer, command);
+ if (!result.isSuccess()) {
+ throw new GlusterRuntimeException("Command [" + command + "] failed with error: [" + result.getExitValue()
+ + "][" + result.getOutput() + "]");
+ }
+ String output = result.getOutput();
+ 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 + "]");
+ }
+
+ public String getLogFileNameForBrickDir(String brickDir) {
+ String logFileName = brickDir;
+ if (logFileName.startsWith(File.separator)) {
+ logFileName = logFileName.replaceFirst(File.separator, "");
+ }
+ logFileName = logFileName.replaceAll(File.separator, "-") + ".log";
+ return logFileName;
+ }
+
+ public Status 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);
+ }
+ return new Status(sshUtil.executeRemote(knownServer, command.toString()));
+ }
+
+ public void removeServer(String existingServer, String serverName) {
+ ProcessResult result = sshUtil.executeRemote(existingServer, "gluster --mode=script peer detach " + serverName);
+ if(!result.isSuccess()) {
+ throw new GlusterRuntimeException("Couldn't remove server [" + serverName + "]! Error: " + result);
+ }
+ }
+
+ public TaskStatus checkRebalanceStatus(String serverName, String volumeName) {
+ String command = "gluster volume rebalance " + volumeName + " status";
+ ProcessResult processResult = sshUtil.executeRemote(serverName, command);
+ TaskStatus taskStatus = new TaskStatus();
+ if (processResult.isSuccess()) {
+ if (processResult.getOutput().trim().matches("^rebalance completed.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ } else if(processResult.getOutput().trim().matches(".*in progress.*")) {
+ taskStatus.setCode(Status.STATUS_CODE_RUNNING);
+ } else {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+ } else {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ }
+ taskStatus.setMessage(processResult.getOutput()); // Common
+ return taskStatus;
+ }
+
+ public void stopRebalance(String serverName, String volumeName) {
+ String command = "gluster volume rebalance " + volumeName + " stop";
+ ProcessResult processResult = sshUtil.executeRemote(serverName, command);
+ TaskStatus taskStatus = new TaskStatus();
+ if (processResult.isSuccess()) {
+ taskStatus.setCode(Status.STATUS_CODE_SUCCESS);
+ taskStatus.setMessage(processResult.getOutput());
+ }
+ }
+
+ public TaskStatus getInitializingDeviceStatus(String serverName, String diskName) {
+ Object response = serverUtil.executeScriptOnServer(true, serverName, INITIALIZE_DISK_STATUS_SCRIPT + " "
+ + diskName, InitDiskStatusResponse.class);
+
+ TaskStatus taskStatus = new TaskStatus();
+ if (response instanceof Status) {
+ taskStatus.setCode(Status.STATUS_CODE_FAILURE);
+ taskStatus.setMessage(((Status) response).getMessage());
+ throw new GlusterRuntimeException(((Status) response).getMessage());
+ }
+
+ InitDiskStatusResponse initDiskStatusResponse = (InitDiskStatusResponse) response;
+
+ 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 ProcessResult executeBrickMigration(String onlineServerName, String volumeName, String fromBrick,
+ String toBrick, String operation) {
+ String command = "gluster volume replace-brick " + volumeName + " " + fromBrick + " " + toBrick + " " + operation;
+ ProcessResult processResult = sshUtil.executeRemote(onlineServerName, command);
+ if (!processResult.isSuccess()) {
+ throw new GlusterRuntimeException(processResult.toString());
+ }
+ return processResult;
+ }
+
+ public static void main(String args[]) {
+ // List<String> names = new GlusterUtil().getGlusterServerNames();
+ // System.out.println(names);
+ List<String> disks = new ArrayList<String>();
+ disks.add("server1:sda");
+ disks.add("server1:sdb");
+ new GlusterUtil().addBricks("Volume3", disks, "localhost");
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java
new file mode 100644
index 00000000..dc88bf52
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/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 com.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.model.ServerStats;
+import com.gluster.storage.management.core.model.ServerStatsRow;
+
+/**
+ *
+ */
+@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/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java
new file mode 100644
index 00000000..d3d47c58
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.NetworkInterface;
+import com.gluster.storage.management.core.model.Server;
+import com.gluster.storage.management.core.model.ServerStats;
+import com.gluster.storage.management.core.model.ServerStatsRow;
+
+/**
+ *
+ */
+@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);
+ 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;
+ }
+
+ for (String serverName : serverNames) {
+ try {
+ Server server = new Server(serverName);
+ serverUtil.fetchServerDetails(server);
+
+ for (NetworkInterface networkInterface : server.getNetworkInterfaces()) {
+ // fetch the stats and add to aggregated stats
+ addServerStats(fetchStats(serverName, period, networkInterface.getName()), aggregatedStats, dataCount);
+ }
+ } catch(Exception e) {
+ // server might be offline - continue with next one
+ logger.warn("Couldn't fetch Network stats from server [" + serverName + "]!", e);
+ continue;
+ }
+ }
+
+ averageAggregatedStats(aggregatedStats, dataCount);
+ }
+
+ @Override
+ public ServerStats fetchStats(String serverName, String period, String... args) {
+ ServerStats stats = super.fetchStats(serverName, period, args);
+
+ // the data returned by rrd contains "bytes" transferred in the given time step. Update the stats object to represent KiB/s
+ int step = stats.getMetadata().getStep();
+ 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 / step);
+ }
+ }
+
+ return stats;
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/ServerUtil.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/ServerUtil.java
new file mode 100644
index 00000000..91c7c81c
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/ServerUtil.java
@@ -0,0 +1,286 @@
+/**
+ * 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 com.gluster.storage.management.gateway.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.model.Server;
+import com.gluster.storage.management.core.model.ServerStats;
+import com.gluster.storage.management.core.model.ServerStatsRow;
+import com.gluster.storage.management.core.model.Status;
+import com.gluster.storage.management.core.response.GenericResponse;
+import com.gluster.storage.management.core.utils.ProcessResult;
+import com.gluster.storage.management.core.utils.ProcessUtil;
+
+@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_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, List<String> arguments) {
+ List<String> command = new ArrayList<String>();
+
+ command.add(SCRIPT_COMMAND);
+ command.add(getScriptPath(scriptName));
+ command.addAll(arguments);
+ return new 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) {
+ Object response = fetchServerDetails(server.getName());
+ server.copyFrom((Server) response); // Update the details in <Server> object
+ server.setDisks(((Server) response).getDisks());
+ }
+
+ public String fetchHostName(String serverName) {
+ Object response = fetchServerDetails(serverName);
+ return ((Server) response).getName();
+ }
+
+ private Object fetchServerDetails(String serverName) {
+ // fetch standard server details like cpu, disk, memory details
+ Object response = executeScriptOnServer(true, serverName, REMOTE_SCRIPT_GET_SERVER_DETAILS, Server.class);
+ if (response instanceof Status) {
+ throw new GlusterRuntimeException(((Status) response).getMessage());
+ }
+ return response;
+ }
+
+ /**
+ * 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 runInForeground
+ * @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. In case the remote execution fails
+ * ungracefully, an object of class {@link Status} will be returned.
+ */
+ public Object executeScriptOnServer(boolean runInForeground, String serverName, String scriptWithArgs,
+ @SuppressWarnings("rawtypes") Class expectedClass) {
+ return executeOnServer(runInForeground, serverName, getRemoteScriptDir() + File.separator + scriptWithArgs, expectedClass);
+ }
+
+ /**
+ * Executes given command on given server
+ *
+ * @param runInForeground
+ * @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("rawtypes")
+ public Object executeOnServer(boolean runInForeground, String serverName, String commandWithArgs,
+ Class expectedClass) {
+ try {
+ String output = executeOnServer(serverName, commandWithArgs);
+
+ // In case the script execution exits ungracefully, the agent would return a GenericResponse.
+ // hence pass last argument as true to try GenericResponse unmarshalling in such cases.
+ Object response = unmarshal(expectedClass, output, expectedClass != GenericResponse.class);
+ if (expectedClass != GenericResponse.class && response instanceof GenericResponse) {
+ // expected class was not GenericResponse, but that's what we got. This means the
+ // script failed ungracefully. Extract and return the status object from the response
+ return ((GenericResponse) response).getStatus();
+ }
+ return response;
+ } catch (RuntimeException e) {
+ // Except for connection exception, wrap any other exception in the a object and return it.
+ if (e instanceof ConnectionException) {
+ throw e;
+ } else {
+ // error during unmarshalling. return status with error from exception.
+ return new Status(e);
+ }
+ }
+ }
+
+ private 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
+ * @param tryGenericResponseOnFailure
+ * If true, and if the unmarshalling fails for given class, another unmarshalling will be attempted with
+ * class {@link GenericResponse}. If this also fails, a status object with exception message is created
+ * and returned.
+ * @return Object of given expected class, or a status object in case first unmarshalling fails.
+ */
+ @SuppressWarnings("rawtypes")
+ private Object unmarshal(Class expectedClass, String input, boolean tryGenericResponseOnFailure) {
+ try {
+ // create JAXB context and instantiate marshaller
+ JAXBContext context = JAXBContext.newInstance(expectedClass);
+ Unmarshaller um = context.createUnmarshaller();
+ return um.unmarshal(new ByteArrayInputStream(input.getBytes()));
+ } catch (JAXBException e) {
+ if (tryGenericResponseOnFailure) {
+ // unmarshalling failed. try to unmarshal a GenericResponse object
+ return unmarshal(GenericResponse.class, input, false);
+
+ }
+ return new Status(Status.STATUS_CODE_FAILURE, "Error during unmarshalling string [" + input
+ + "] for class [" + expectedClass.getName() + ": [" + e.getMessage() + "]");
+ }
+ }
+
+ /**
+ * @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 (Status) executeScriptOnServer(true, serverName, REMOTE_SCRIPT_GET_DISK_FOR_DIR + " " + brickDir, Status.class);
+ }
+
+ public static void main(String[] args) {
+// ServerStats stats = new ServerUtil().fetchCPUUsageData("s1", "1d");
+// for(ServerStatsRow row : stats.getRows()) {
+// System.out.println(row.getUsageData().get(2));
+// }
+// JAXBContext context;
+// try {
+// context = JAXBContext.newInstance(ServerStats.class);
+// Marshaller m = context.createMarshaller();
+// ByteArrayOutputStream out = new ByteArrayOutputStream();
+// m.marshal(stats, out);
+// ServerStats stats1 = (ServerStats)new ServerUtil().unmarshal(ServerStats.class, out.toString(), false);
+// for(ServerStatsRow row : stats1.getRows()) {
+// System.out.println(row.getUsageData().get(2));
+// }
+// } catch (JAXBException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/SshUtil.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/SshUtil.java
new file mode 100644
index 00000000..39dd42f9
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/SshUtil.java
@@ -0,0 +1,388 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.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.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;
+
+import com.gluster.storage.management.core.constants.CoreConstants;
+import com.gluster.storage.management.core.exceptions.ConnectionException;
+import com.gluster.storage.management.core.exceptions.GlusterRuntimeException;
+import com.gluster.storage.management.core.utils.FileUtil;
+import com.gluster.storage.management.core.utils.LRUCache;
+import com.gluster.storage.management.core.utils.ProcessResult;
+
+/**
+ *
+ */
+@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 + "id_rsa");
+ public static final File PUBLIC_KEY_FILE = new File(SSH_AUTHORIZED_KEYS_DIR_LOCAL + "id_rsa.pub");
+// private static final String SCRIPT_DISABLE_SSH_PASSWORD_AUTH = "disable-ssh-password-auth.sh";
+ private static final String PRIVATE_KEY_PASSPHRASE = "gluster";
+ 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);
+ return true;
+ } catch(ConnectionException e) {
+ return false;
+ }
+ }
+
+ public boolean isPublicKeyInstalled(String serverName) {
+ try {
+ getConnection(serverName);
+ return true;
+ } catch(ConnectionException 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 = getConnectionWithPassword(serverName);
+ 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.
+ }
+
+ byte[] publicKeyData;
+ try {
+ publicKeyData = FileUtil.readFileAsByteArray(PUBLIC_KEY_FILE);
+ } catch (Exception e) {
+ 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) {
+ 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);
+ }
+
+ // 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 Connection getConnectionWithPassword(String serverName) {
+ Connection conn = createConnection(serverName);
+ authenticateWithPassword(conn);
+ return conn;
+ }
+
+ private synchronized Connection getConnection(String serverName) {
+ Connection conn = sshConnCache.get(serverName);
+ if (conn != null) {
+ return conn;
+ }
+
+ conn = createConnection(serverName);
+ authenticateWithPublicKey(conn);
+ sshConnCache.put(serverName, conn);
+ return conn;
+ }
+
+ private void authenticateWithPublicKey(Connection conn) {
+ try {
+ if (!supportsPublicKeyAuthentication(conn)) {
+ throw new ConnectionException("Public key authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ if (!conn.authenticateWithPublicKey(USER_NAME, PRIVATE_KEY_FILE, PRIVATE_KEY_PASSPHRASE)) {
+ throw new ConnectionException("SSH Authentication (public key) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new ConnectionException("Exception during SSH authentication (public key) for server ["
+ + conn.getHostname() + "]", e);
+ }
+ }
+
+ private void authenticateWithPassword(Connection conn) {
+ try {
+ if (!supportsPasswordAuthentication(conn)) {
+ throw new ConnectionException("Password authentication not supported on [" + conn.getHostname()
+ + "]");
+ }
+
+ if (!conn.authenticateWithPassword(USER_NAME, DEFAULT_PASSWORD)) {
+ throw new ConnectionException("SSH Authentication (password) failed for server ["
+ + conn.getHostname() + "]");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ 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 Connection createConnection(String serverName) {
+ Connection conn;
+ conn = new Connection(serverName);
+ try {
+ conn.connect(null, sshConnectTimeout, sshKexTimeout);
+ } catch (IOException e) {
+ logger.error("Couldn't establish SSH connection with server [" + serverName + "]", e);
+ 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) {
+ try {
+ Session session = sshConnection.openSession();
+ BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(new StreamGobbler(
+ session.getStdout())));
+ BufferedReader stderrReader = new BufferedReader(new InputStreamReader(new StreamGobbler(
+ session.getStderr())));
+ session.execCommand(command);
+ ProcessResult result = getResultOfExecution(session, stdoutReader, stderrReader);
+ session.close();
+ return result;
+ } catch (IOException e) {
+ String errMsg = "Exception while executing command [" + command + "] on [" + sshConnection.getHostname()
+ + "]";
+ logger.error(errMsg, e);
+ throw new GlusterRuntimeException(errMsg, e);
+ }
+ }
+
+ 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) {
+ return executeCommand(getConnectionWithPassword(serverName), command);
+ }
+
+ private ProcessResult executeRemoteWithPubKey(String serverName, String command) {
+ try {
+ return executeCommand(getConnection(serverName), command);
+ } catch(GlusterRuntimeException e) {
+ Throwable cause = e.getCause();
+ if(cause != null && cause instanceof IOException) {
+ // cached ssh connection might have gone bad.
+ // remove it and try with a new one
+ sshConnCache.remove(serverName);
+ return executeCommand(getConnection(serverName), command);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * 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) {
+ try {
+ return executeRemoteWithPubKey(serverName, command);
+ } catch(ConnectionException e) {
+ // Couldn't connect with public key. Try with default password.
+ return executeRemoteWithPassword(serverName, command);
+ }
+ }
+
+ /**
+ * Checks if public key of management gateway is configured on given server
+ *
+ * @param serverName
+ * @return true if public key is configured, else false
+ */
+ public boolean isPublicKeySetup(String serverName) {
+ try {
+ getConnection(serverName);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public void cleanup() {
+ for (Connection conn : sshConnCache.values()) {
+ conn.close();
+ }
+ }
+}
diff --git a/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/StatsFactory.java b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/StatsFactory.java
new file mode 100644
index 00000000..09851367
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/com/gluster/storage/management/gateway/utils/StatsFactory.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com>
+ * This file is part of Gluster Management Console.
+ *
+ * Gluster Management Console is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Gluster Management Console is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *******************************************************************************/
+package com.gluster.storage.management.gateway.utils;
+
+import java.util.List;
+
+import com.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/com.gluster.storage.management.gateway/src/log4j.properties b/src/com.gluster.storage.management.gateway/src/log4j.properties
new file mode 100644
index 00000000..18e2e8b1
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/log4j.properties
@@ -0,0 +1,19 @@
+log4j.rootLogger=INFO, CONSOLE
+
+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=%p %t %c - %m%n
+
+log4j.logger.org=ERROR
+log4j.logger.com=ERROR
+log4j.logger.com.gluster=DEBUG \ No newline at end of file
diff --git a/src/com.gluster.storage.management.gateway/src/spring/gluster-server-base.xml b/src/com.gluster.storage.management.gateway/src/spring/gluster-server-base.xml
new file mode 100644
index 00000000..c89eb2f0
--- /dev/null
+++ b/src/com.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="com.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-->
+
+ <!-- Cluster environment. Valid values: vmware, aws, baremetal -->
+ <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="gluster" />
+ </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="com.gluster.storage.management.gateway.data.PersistenceDao">
+ <constructor-arg type="java.lang.Class">
+ <value>com.gluster.storage.management.gateway.data.ClusterInfo</value>
+ </constructor-arg>
+ </bean>
+
+ <bean id="serverDao" class="com.gluster.storage.management.gateway.data.PersistenceDao">
+ <constructor-arg type="java.lang.Class">
+ <value>com.gluster.storage.management.gateway.data.ServerInfo</value>
+ </constructor-arg>
+ </bean>
+
+ <!-- bean id="dataSourceFactory" class="com.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="com.gluster.storage.management.gateway.data.GlusterDataSource"
+ lazy-init="false" autowire="byType" / -->
+
+ <bean class="com.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/com.gluster.storage.management.gateway/src/spring/gluster-server-security.xml b/src/com.gluster.storage.management.gateway/src/spring/gluster-server-security.xml
new file mode 100644
index 00000000..abcd8c05
--- /dev/null
+++ b/src/com.gluster.storage.management.gateway/src/spring/gluster-server-security.xml
@@ -0,0 +1,43 @@
+<?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/**" 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.encoding.ShaPasswordEncoder"
+ id="passwordEncoder" />
+
+ <authentication-manager alias="authenticationManager">
+ <authentication-provider user-service-ref="jdbcUserService">
+ <!-- Passwords are SHA encrypted -->
+ <password-encoder hash="sha" />
+ </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