From 8a27c576bbbeea95fc5a0e7b509ce68133619a05 Mon Sep 17 00:00:00 2001 From: Shireesh Anjal Date: Sun, 31 Jul 2011 16:58:29 +0530 Subject: Renamed project and package com.gluster.storage.management.server to com.gluster.storage.management.gateway --- .../com.gluster.storage.management.gateway.cquery | 4 + .../com.gluster.storage.management.server.cquery | 4 - .../.project | 2 +- .../.pydevproject | 2 +- src/com.gluster.storage.management.server/.project | 2 +- .../.settings/org.eclipse.wst.common.component | 4 +- .../WebContent/WEB-INF/web.xml | 147 ++- .../build/glusterserver.ant | 2 +- .../gateway/constants/VolumeOptionsDefaults.java | 118 +++ .../management/gateway/data/ClusterInfo.java | 79 ++ .../management/gateway/data/GlusterDataSource.java | 48 + .../management/gateway/data/PersistenceDao.java | 113 +++ .../management/gateway/data/ServerInfo.java | 72 ++ .../management/gateway/filters/AuditFilter.java | 38 + .../filters/AuthenticationFailureFilter.java | 105 +++ .../filters/GlusterResourceFilterFactory.java | 31 + .../gateway/resources/v1_0/AbstractResource.java | 177 ++++ .../gateway/resources/v1_0/ClustersResource.java | 126 +++ .../resources/v1_0/DiscoveredServersResource.java | 150 ++++ .../resources/v1_0/GenericExceptionMapper.java | 54 ++ .../resources/v1_0/GlusterServersResource.java | 487 ++++++++++ .../gateway/resources/v1_0/KeysResource.java | 153 ++++ .../gateway/resources/v1_0/TasksResource.java | 194 ++++ .../gateway/resources/v1_0/UsersResource.java | 91 ++ .../gateway/resources/v1_0/VolumesResource.java | 988 +++++++++++++++++++++ .../security/GlusterUserDetailsService.java | 31 + .../management/gateway/security/UserAuthDao.java | 42 + .../gateway/services/ClusterService.java | 269 ++++++ .../gateway/services/GlusterServerService.java | 165 ++++ .../management/gateway/tasks/InitServerTask.java | 162 ++++ .../gateway/tasks/InitializeDiskTask.java | 168 ++++ .../management/gateway/tasks/MigrateBrickTask.java | 227 +++++ .../gateway/tasks/RebalanceVolumeTask.java | 134 +++ .../management/gateway/tasks/ServerSyncTask.java | 154 ++++ .../storage/management/gateway/tasks/Task.java | 112 +++ .../gateway/utils/AbstractStatsFactory.java | 168 ++++ .../management/gateway/utils/CpuStatsFactory.java | 36 + .../management/gateway/utils/GlusterUtil.java | 664 ++++++++++++++ .../gateway/utils/MemoryStatsFactory.java | 68 ++ .../gateway/utils/NetworkStatsFactory.java | 123 +++ .../management/gateway/utils/ServerUtil.java | 258 ++++++ .../storage/management/gateway/utils/SshUtil.java | 388 ++++++++ .../management/gateway/utils/StatsFactory.java | 31 + .../server/constants/VolumeOptionsDefaults.java | 118 --- .../management/server/data/ClusterInfo.java | 79 -- .../management/server/data/GlusterDataSource.java | 48 - .../management/server/data/PersistenceDao.java | 113 --- .../storage/management/server/data/ServerInfo.java | 72 -- .../management/server/filters/AuditFilter.java | 38 - .../filters/AuthenticationFailureFilter.java | 105 --- .../filters/GlusterResourceFilterFactory.java | 31 - .../server/resources/v1_0/AbstractResource.java | 177 ---- .../server/resources/v1_0/ClustersResource.java | 126 --- .../resources/v1_0/DiscoveredServersResource.java | 150 ---- .../resources/v1_0/GenericExceptionMapper.java | 54 -- .../resources/v1_0/GlusterServersResource.java | 487 ---------- .../server/resources/v1_0/KeysResource.java | 153 ---- .../server/resources/v1_0/TasksResource.java | 194 ---- .../server/resources/v1_0/UsersResource.java | 91 -- .../server/resources/v1_0/VolumesResource.java | 988 --------------------- .../server/security/GlusterUserDetailsService.java | 31 - .../management/server/security/UserAuthDao.java | 42 - .../management/server/services/ClusterService.java | 269 ------ .../server/services/GlusterServerService.java | 165 ---- .../management/server/tasks/InitServerTask.java | 162 ---- .../server/tasks/InitializeDiskTask.java | 168 ---- .../management/server/tasks/MigrateBrickTask.java | 227 ----- .../server/tasks/RebalanceVolumeTask.java | 134 --- .../management/server/tasks/ServerSyncTask.java | 154 ---- .../storage/management/server/tasks/Task.java | 112 --- .../server/utils/AbstractStatsFactory.java | 168 ---- .../management/server/utils/CpuStatsFactory.java | 36 - .../management/server/utils/GlusterUtil.java | 664 -------------- .../server/utils/MemoryStatsFactory.java | 68 -- .../server/utils/NetworkStatsFactory.java | 123 --- .../management/server/utils/ServerUtil.java | 258 ------ .../storage/management/server/utils/SshUtil.java | 388 -------- .../management/server/utils/StatsFactory.java | 31 - .../src/spring/gluster-server-base.xml | 16 +- 79 files changed, 6309 insertions(+), 6322 deletions(-) create mode 100644 src/com.gluster.storage.management.releng/com.gluster.storage.management.gateway.cquery delete mode 100644 src/com.gluster.storage.management.releng/com.gluster.storage.management.server.cquery create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ClusterInfo.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/PersistenceDao.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ServerInfo.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/AuditFilter.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/UserAuthDao.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/ClusterService.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/GlusterServerService.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/Task.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/ServerUtil.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/SshUtil.java create mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/StatsFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ClusterInfo.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/GlusterDataSource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/PersistenceDao.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ServerInfo.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuditFilter.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/GlusterResourceFilterFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/AbstractResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ClustersResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/DiscoveredServersResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/KeysResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/TasksResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/UsersResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/VolumesResource.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/GlusterUserDetailsService.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/UserAuthDao.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/GlusterServerService.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitServerTask.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateBrickTask.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/ServerSyncTask.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/Task.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/CpuStatsFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/NetworkStatsFactory.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java delete mode 100644 src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/StatsFactory.java (limited to 'src') diff --git a/src/com.gluster.storage.management.releng/com.gluster.storage.management.gateway.cquery b/src/com.gluster.storage.management.releng/com.gluster.storage.management.gateway.cquery new file mode 100644 index 00000000..346b39bf --- /dev/null +++ b/src/com.gluster.storage.management.releng/com.gluster.storage.management.gateway.cquery @@ -0,0 +1,4 @@ + + + + diff --git a/src/com.gluster.storage.management.releng/com.gluster.storage.management.server.cquery b/src/com.gluster.storage.management.releng/com.gluster.storage.management.server.cquery deleted file mode 100644 index 346b39bf..00000000 --- a/src/com.gluster.storage.management.releng/com.gluster.storage.management.server.cquery +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/com.gluster.storage.management.server.scripts/.project b/src/com.gluster.storage.management.server.scripts/.project index beda33b7..110db62b 100644 --- a/src/com.gluster.storage.management.server.scripts/.project +++ b/src/com.gluster.storage.management.server.scripts/.project @@ -1,6 +1,6 @@ - com.gluster.storage.management.server.scripts + com.gluster.storage.management.gateway.scripts diff --git a/src/com.gluster.storage.management.server.scripts/.pydevproject b/src/com.gluster.storage.management.server.scripts/.pydevproject index 0a912df5..c327cd69 100644 --- a/src/com.gluster.storage.management.server.scripts/.pydevproject +++ b/src/com.gluster.storage.management.server.scripts/.pydevproject @@ -5,6 +5,6 @@ Default python 3.0 -/com.gluster.storage.management.server.scripts/src +/com.gluster.storage.management.gateway.scripts/src diff --git a/src/com.gluster.storage.management.server/.project b/src/com.gluster.storage.management.server/.project index 259b3726..3e4dc06a 100644 --- a/src/com.gluster.storage.management.server/.project +++ b/src/com.gluster.storage.management.server/.project @@ -1,6 +1,6 @@ - com.gluster.storage.management.server + com.gluster.storage.management.gateway diff --git a/src/com.gluster.storage.management.server/.settings/org.eclipse.wst.common.component b/src/com.gluster.storage.management.server/.settings/org.eclipse.wst.common.component index dbf56d1e..3d5a50bf 100644 --- a/src/com.gluster.storage.management.server/.settings/org.eclipse.wst.common.component +++ b/src/com.gluster.storage.management.server/.settings/org.eclipse.wst.common.component @@ -1,10 +1,10 @@ - + - + diff --git a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml index e810c2ed..631788ff 100644 --- a/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml +++ b/src/com.gluster.storage.management.server/WebContent/WEB-INF/web.xml @@ -1,86 +1,73 @@ - - glustermg - - index.html - index.htm - index.jsp - default.html - default.htm - default.jsp - - - - - contextConfigLocation - + + glustermg + + index.html + index.htm + index.jsp + default.html + default.htm + default.jsp + + + contextConfigLocation + classpath:spring/gluster-server-security.xml classpath:spring/gluster-server-base.xml - - - org.springframework.web.context.ContextLoaderListener - - - org.springframework.web.context.request.RequestContextListener - - - - - gluster-resources-1.0 - - com.sun.jersey.spi.spring.container.servlet.SpringServlet - - com.sun.jersey.config.property.packages - com.gluster.storage.management.server.resources.v1_0 - - - com.sun.jersey.spi.container.ResourceFilters - com.gluster.storage.management.server.filters.GlusterResourceFilterFactory - - 1 - - - gluster-resources-1.0 - /1.0/* - - - - - JnlpDownloadServlet - jnlp.sample.servlet.JnlpDownloadServlet - - - JnlpDownloadServlet - *.jnlp - - - JnlpDownloadServlet - *.jar - - - - - springSecurityFilterChain - + + + org.springframework.web.context.ContextLoaderListener + + + org.springframework.web.context.request.RequestContextListener + + + gluster-resources-1.0 + com.sun.jersey.spi.spring.container.servlet.SpringServlet + + com.sun.jersey.config.property.packages + com.gluster.storage.management.gateway.resources.v1_0 + + + com.sun.jersey.spi.container.ResourceFilters + com.gluster.storage.management.gateway.filters.GlusterResourceFilterFactory + + 1 + + + gluster-resources-1.0 + /1.0/* + + + JnlpDownloadServlet + jnlp.sample.servlet.JnlpDownloadServlet + + + JnlpDownloadServlet + *.jnlp + + + JnlpDownloadServlet + *.jar + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy - - - springSecurityFilterChain - /* - - - - - Gluster Management Gateway - /* - - - CONFIDENTIAL - - - + + + springSecurityFilterChain + /* + + + + Gluster Management Gateway + /* + + + CONFIDENTIAL + + + \ No newline at end of file diff --git a/src/com.gluster.storage.management.server/build/glusterserver.ant b/src/com.gluster.storage.management.server/build/glusterserver.ant index e9b5b650..68a5bc08 100644 --- a/src/com.gluster.storage.management.server/build/glusterserver.ant +++ b/src/com.gluster.storage.management.server/build/glusterserver.ant @@ -1,4 +1,4 @@ - + diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java new file mode 100644 index 00000000..1f577c89 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/constants/VolumeOptionsDefaults.java @@ -0,0 +1,118 @@ +/** + * DefaultVolumeOptions.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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 options; + + public VolumeOptionsDefaults() { + } + + /** + * @return list of volume option information objects + */ + public List 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 getVolumeOptionsInfo() { + List volumeOptionsInfo = new ArrayList(); + + 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 . ", + "*: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.server/src/com/gluster/storage/management/gateway/data/ClusterInfo.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ClusterInfo.java new file mode 100644 index 00000000..3e5ea01a --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ClusterInfo.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 servers = new ArrayList(); + + 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 servers) { + this.servers = servers; + } + + public List 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.server/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java new file mode 100644 index 00000000..0802fe93 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/GlusterDataSource.java @@ -0,0 +1,48 @@ +/** + * GlusterDataSource.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/data/PersistenceDao.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/PersistenceDao.java new file mode 100644 index 00000000..eb7d6514 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/PersistenceDao.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 { + private Class type; + + private EntityManager entityManager; + + @PersistenceUnit + private EntityManagerFactory entityManagerFactory; + + public PersistenceDao(Class 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 findAll() { + return getEntityManager().createQuery("select t from " + type.getName() + " t").getResultList(); + } + + @SuppressWarnings("unchecked") + public List findBy(String whereClause) { + return getEntityManager().createQuery("select t from " + type.getName() + " t where " + whereClause) + .getResultList(); + } + + @SuppressWarnings("unchecked") + public List 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.server/src/com/gluster/storage/management/gateway/data/ServerInfo.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ServerInfo.java new file mode 100644 index 00000000..a3f8c920 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/data/ServerInfo.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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.server/src/com/gluster/storage/management/gateway/filters/AuditFilter.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/AuditFilter.java new file mode 100644 index 00000000..31810123 --- /dev/null +++ b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java new file mode 100644 index 00000000..73a1085e --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/AuthenticationFailureFilter.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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("1Authentication Failed!"); + } + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ + @Override + public void init(FilterConfig arg0) throws ServletException { + // TODO Auto-generated method stub + + } + +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/filters/GlusterResourceFilterFactory.java new file mode 100644 index 00000000..1c480f3f --- /dev/null +++ b/src/com.gluster.storage.management.server/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 create(AbstractMethod arg0) { + List filters = new ArrayList(); + filters.add(new AuditFilter()); + + return filters; + } +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/AbstractResource.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 base URI 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.server/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/ClustersResource.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 clusters = clusterService.getAllClusters(); + List clusterList = new ArrayList(); + 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.server/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/DiscoveredServersResource.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 discoveredServerNames = new ArrayList(); + + public List getDiscoveredServerNames() { + return discoveredServerNames; + } + + public void setDiscoveredServerNames(List 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 discoveredServers = getDiscoveredServerDetails(); + return okResponse(new ServerListResponse(discoveredServers), mediaType); + } catch(Exception e) { + return errorResponse(e.getMessage()); + } + } else { + return okResponse(new ServerNameListResponse(getDiscoveredServerNames()), mediaType); + } + } + + private List getDiscoveredServerDetails() { + List discoveredServers = new ArrayList(); + 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.server/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/GenericExceptionMapper.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 { + + /* (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.server/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/GlusterServersResource.java @@ -0,0 +1,487 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 glusterServers = new ArrayList(); + + 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 getServerNames(List glusterServers) { + List serverNames = new ArrayList(); + 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 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 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 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 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.server/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/KeysResource.java @@ -0,0 +1,153 @@ +/** + * KeysResource.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/TasksResource.java @@ -0,0 +1,194 @@ +/** + * TaskResource.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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 tasksMap = new HashMap(); + + public TasksResource() { + } + + public void addTask(Task task) { + tasksMap.put(task.getId(), task); + } + + public void removeTask(Task task) { + tasksMap.remove(task.getId()); + } + + public List getAllTasksInfo() { + List allTasksInfo = new ArrayList(); + for (Map.Entry 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 entry : tasksMap.entrySet()) { + if (entry.getValue().getId().equals(taskId)) { + return entry.getValue(); + } + } + return null; + } + + public List getAllTasks() { + List tasks = new ArrayList(); + for (Map.Entry 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.server/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java b/src/com.gluster.storage.management.server/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.server/src/com/gluster/storage/management/gateway/resources/v1_0/UsersResource.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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.server/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java new file mode 100644 index 00000000..fad19e7e --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/resources/v1_0/VolumesResource.java @@ -0,0 +1,988 @@ +/** + * VolumesResource.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.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()); + } + + 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()); + } + + 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 Status performOperation(String volumeName, String operation, GlusterServer onlineServer) { + if (operation.equals(TASK_START)) { + return glusterUtil.startVolume(volumeName, onlineServer.getName()); + } else if (operation.equals(TASK_STOP)) { + return glusterUtil.stopVolume(volumeName, onlineServer.getName()); + } else { + return new Status(Status.STATUS_CODE_FAILURE, "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 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 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 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 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.executeOnServer(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 bricks, boolean deleteFlag) { + Status result; + for (Brick brick : bricks) { + String brickDirectory = brick.getBrickDirectory(); + String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/")); + + result = (Status) serverUtil.executeOnServer(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 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 + Object responseObj = serverUtil.executeOnServer(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 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 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 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 messagesToRemove = new ArrayList(); + 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 logMessages, String severity) { + if (severity == null || severity.isEmpty()) { + return; + } + + List messagesToRemove = new ArrayList(); + for (VolumeLogMessage logMessage : logMessages) { + if (!logMessage.getSeverity().equals(severity)) { + messagesToRemove.add(logMessage); + } + } + logMessages.removeAll(messagesToRemove); + } + + private List getLogsForAllBricks(Volume volume, Integer lineCount) { + List logMessages; + logMessages = new ArrayList(); + // 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() { + @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 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.server/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java new file mode 100644 index 00000000..e806051c --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/GlusterUserDetailsService.java @@ -0,0 +1,31 @@ +/** + * GlusterUserDetailsService.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/security/UserAuthDao.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/UserAuthDao.java new file mode 100644 index 00000000..bdc3b19e --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/security/UserAuthDao.java @@ -0,0 +1,42 @@ +/** + * UserAuthDao.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/services/ClusterService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/ClusterService.java new file mode 100644 index 00000000..e01c5096 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/ClusterService.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 clusterDao; + + @Autowired + private PersistenceDao serverDao; + + @Autowired + private GlusterUtil glusterUtil; + + @Autowired + private SshUtil sshUtil; + + @Autowired + private ServerUtil serverUtil; + + private LRUCache onlineServerCache = new LRUCache(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 getAllClusters() { + return clusterDao.findAll(); + } + + public ClusterInfo getCluster(String clusterName) { + List clusters = clusterDao.findBy("UPPER(name) = ?1", clusterName.toUpperCase()); + if(clusters.size() == 0) { + return null; + } + + return clusters.get(0); + } + + public ClusterInfo getClusterForServer(String serverName) { + List 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 glusterServers = glusterUtil.getGlusterServers(server); + List servers = new ArrayList(); + 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 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.server/src/com/gluster/storage/management/gateway/services/GlusterServerService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/GlusterServerService.java new file mode 100644 index 00000000..d1437cec --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/services/GlusterServerService.java @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 getGlusterServers(String clusterName, boolean fetchDetails) { + List 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 getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails) { + List 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 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.server/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java new file mode 100644 index 00000000..6d525785 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitServerTask.java @@ -0,0 +1,162 @@ +/** + * GlusterServerInitializer.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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 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 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 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.server/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java new file mode 100644 index 00000000..f5cc5332 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/InitializeDiskTask.java @@ -0,0 +1,168 @@ +/** + * InitializeDiskTask.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.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 SshUtil sshUtil; + 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); + sshUtil = ctx.getBean(SshUtil.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(); + ProcessResult processResult = sshUtil.executeRemote(serverName, INITIALIZE_DISK_SCRIPT + fsTypeCommand + " " + + getDiskName()); + if (processResult.isSuccess()) { + TaskStatus taskStatus = new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput())); + taskStatus.setPercentageSupported((getFsType().equals(GlusterConstants.FSTYPE_XFS)) ? false : true); + getTaskInfo().setStatus(taskStatus); + return; + } + + // if we reach here, it means Initialize disk start failed. + throw new GlusterRuntimeException(processResult.toString()); + } + + @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.server/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java new file mode 100644 index 00000000..694067aa --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/MigrateBrickTask.java @@ -0,0 +1,227 @@ +/** + * MigrateDiskTask.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java new file mode 100644 index 00000000..3038f961 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/RebalanceVolumeTask.java @@ -0,0 +1,134 @@ +/** + * RebalanceVolumeTask.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.SshUtil; +import com.sun.jersey.core.util.Base64; + +public class RebalanceVolumeTask extends Task { + + private String layout; + private String serverName; + private SshUtil sshUtil; + 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(); + sshUtil = ctx.getBean(SshUtil.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"; + ProcessResult processResult = sshUtil.executeRemote(serverName, command); + if (processResult.isSuccess()) { + getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput()))); + return; + } + + // if we reach here, it means rebalance start failed. + throw new GlusterRuntimeException(processResult.toString()); + } + + @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.server/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java new file mode 100644 index 00000000..94c743aa --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/ServerSyncTask.java @@ -0,0 +1,154 @@ +/** + * ServerDiscoveryTask.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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:
+ * 1. Auto-discovery of servers eligible to be added to the Gluster cluster.
+ * 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 clusterDao; + + public void perform() { + discoverServers(); + syncClusterServerMapping(); + } + + private void syncClusterServerMapping() { + List clusters = clusterService.getAllClusters(); + for(ClusterInfo cluster : clusters) { + List servers = cluster.getServers(); + List actualServers = glusterServerService.getGlusterServers(cluster.getName(), false); + updateRemovedServers(cluster, servers, actualServers); + updateAddedServers(cluster, servers, actualServers); + } + } + + private void updateAddedServers(ClusterInfo cluster, List servers, List actualServers) { + List addedServers = findAddedServers(cluster.getName(), servers, actualServers); + for(String addedServer : addedServers) { + clusterService.mapServerToCluster(cluster.getName(), addedServer); + } + } + + private void updateRemovedServers(ClusterInfo cluster, List servers, List actualServers) { + List removedServers = findRemovedServers(servers, actualServers); + for(String removedServer : removedServers) { + clusterService.unmapServerFromCluster(cluster.getName(), removedServer); + } + } + + private List findRemovedServers(List servers, List actualServers) { + List removedServers = new ArrayList(); + + for(ServerInfo server : servers) { + if (!GlusterCoreUtil.containsEntityWithName(actualServers, server.getName(), true)) { + removedServers.add(server.getName()); + } + } + return removedServers; + } + + private List findAddedServers(String clusterName, List servers, List actualServers) { + List addedServers = new ArrayList(); + for(GlusterServer actualServer : actualServers) { + if(!serverExists(servers, actualServer.getName())) { + addedServers.add(actualServer.getName()); + } + } + return addedServers; + } + + private boolean serverExists(List 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 serverNameList = new ArrayList(); + + ProcessResult result = serverUtil.executeGlusterScript(true, discoveryMechanism + SCRIPT_NAME_SFX, new ArrayList()); + if(result.isSuccess()) { + List 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.server/src/com/gluster/storage/management/gateway/tasks/Task.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/Task.java new file mode 100644 index 00000000..1ba360bc --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/tasks/Task.java @@ -0,0 +1,112 @@ +/** + * Task.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.server/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java new file mode 100644 index 00000000..0e73297f --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/AbstractStatsFactory.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 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 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 addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) { + List serverStatsRows = statsToBeAdded.getRows(); + for (int rowNum = 0; rowNum < serverStatsRows.size() + && rowNum < targetStats.getMetadata().getRowCount(); rowNum++) { + ServerStatsRow row = serverStatsRows.get(rowNum); + List rowData = row.getUsageData(); + + List 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 rows = aggregatedStats.getRows(); + for(int rowNum = 0; rowNum < rows.size(); rowNum++) { + List 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 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.executeOnServer(true, serverName, getStatsScriptName() + argsStr + " " + period, ServerStats.class); + //String cpuUsageData = " 1310468100 300 1310471700 13 3 user system total 13104681002.23802952e-14.3747778209e-016.6128073384e-01 13104684002.3387347338e-014.4642717442e-016.8030064780e-01 13104687005.5043873220e+006.2462376636e+001.1750624986e+01 13104690002.4350593653e+012.6214585217e+015.0565178869e+01 13104693004.0786489953e+014.6784713828e+018.7571203781e+01 13104696004.1459955508e+015.2546309044e+019.4006264551e+01 13104699004.2312286165e+015.2390588332e+019.4702874497e+01 13104702004.2603794982e+015.1598861493e+019.4202656475e+01 13104705003.8238751290e+014.5312089966e+018.3550841256e+01 13104708001.7949961224e+012.1282058418e+013.9232019642e+01 13104711001.2330371421e-014.6347832868e-015.8678204289e-01 13104714001.6313260492e-015.4088119561e-017.0401380052e-01 1310471700NaNNaNNaN "; + //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.server/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java new file mode 100644 index 00000000..b6ef9ef2 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/CpuStatsFactory.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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.server/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java new file mode 100644 index 00000000..7622d283 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/GlusterUtil.java @@ -0,0 +1,664 @@ +/** + * GlusterUtil.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +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.NAS_PROTOCOL; +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; +import com.sun.jersey.api.core.InjectParam; + +@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: token: value + * + * @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 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 getGlusterServers(GlusterServer knownServer) { + String output = getPeerStatus(knownServer.getName()); + if (output == null) { + return null; + } + + knownServer.setUuid(getUuid(knownServer.getName())); + + List glusterServers = new ArrayList(); + 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 getGlusterServerNames(String knownServer) { + String output = getPeerStatus(knownServer); + if (output == null) { + return null; + } + + List glusterServerNames = new ArrayList(); + 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 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 options, String knownServer) { + String errors = ""; + if (options != null) { + for (Entry 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 getAllVolumes(String knownServer) { + return parseVolumeInfo(getVolumeInfo(knownServer)); + } + + private List parseVolumeInfo(String volumeInfoText) { + List volumes = new ArrayList(); + 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 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 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.executeOnServer(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 names = new GlusterUtil().getGlusterServerNames(); + // System.out.println(names); + List disks = new ArrayList(); + disks.add("server1:sda"); + disks.add("server1:sdb"); + new GlusterUtil().addBricks("Volume3", disks, "localhost"); + } +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java new file mode 100644 index 00000000..dc88bf52 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/MemoryStatsFactory.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 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.server/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java new file mode 100644 index 00000000..d3d47c58 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/NetworkStatsFactory.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 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 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 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.server/src/com/gluster/storage/management/gateway/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/ServerUtil.java new file mode 100644 index 00000000..0fae0078 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/ServerUtil.java @@ -0,0 +1,258 @@ +/** + * ServerUtil.java + * + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + */ +package com.gluster.storage.management.gateway.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +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; + + 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"; + + public void setSshUtil(SshUtil sshUtil) { + this.sshUtil = sshUtil; + } + + public ProcessResult executeGlusterScript(boolean runInForeground, String scriptName, List arguments) { + List command = new ArrayList(); + + command.add(SCRIPT_COMMAND); + command.add(getScriptPath(scriptName)); + command.addAll(arguments); + return new ProcessUtil().executeCommand(runInForeground, command); + } + + private String getScriptPath(String scriptName) { + String scriptPath = servletContext.getRealPath(SCRIPT_DIR) + CoreConstants.FILE_SEPARATOR + scriptName; + return scriptPath; + } + + /** + * 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 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 = executeOnServer(true, serverName, REMOTE_SCRIPT_GET_SERVER_DETAILS, Server.class); + if (response instanceof Status) { + throw new GlusterRuntimeException(((Status) response).getMessage()); + } + return response; + } + + /** + * 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) executeOnServer(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.server/src/com/gluster/storage/management/gateway/utils/SshUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/SshUtil.java new file mode 100644 index 00000000..39dd42f9 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/SshUtil.java @@ -0,0 +1,388 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 sshConnCache = new LRUCache(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.server/src/com/gluster/storage/management/gateway/utils/StatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/StatsFactory.java new file mode 100644 index 00000000..09851367 --- /dev/null +++ b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/gateway/utils/StatsFactory.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2011 Gluster, Inc. + * 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 + * . + *******************************************************************************/ +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 serverName, String period); +} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java deleted file mode 100644 index 5c9a6505..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/constants/VolumeOptionsDefaults.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * DefaultVolumeOptions.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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 options; - - public VolumeOptionsDefaults() { - } - - /** - * @return list of volume option information objects - */ - public List 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 getVolumeOptionsInfo() { - List volumeOptionsInfo = new ArrayList(); - - 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 . ", - "*: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.server/src/com/gluster/storage/management/server/data/ClusterInfo.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ClusterInfo.java deleted file mode 100644 index 1c3cd347..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ClusterInfo.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 servers = new ArrayList(); - - 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 servers) { - this.servers = servers; - } - - public List 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.server/src/com/gluster/storage/management/server/data/GlusterDataSource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/GlusterDataSource.java deleted file mode 100644 index e669a130..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/GlusterDataSource.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * GlusterDataSource.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/data/PersistenceDao.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/PersistenceDao.java deleted file mode 100644 index 85fefcdf..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/PersistenceDao.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 { - private Class type; - - private EntityManager entityManager; - - @PersistenceUnit - private EntityManagerFactory entityManagerFactory; - - public PersistenceDao(Class 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 findAll() { - return getEntityManager().createQuery("select t from " + type.getName() + " t").getResultList(); - } - - @SuppressWarnings("unchecked") - public List findBy(String whereClause) { - return getEntityManager().createQuery("select t from " + type.getName() + " t where " + whereClause) - .getResultList(); - } - - @SuppressWarnings("unchecked") - public List 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.server/src/com/gluster/storage/management/server/data/ServerInfo.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ServerInfo.java deleted file mode 100644 index 72818200..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/data/ServerInfo.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/filters/AuditFilter.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuditFilter.java deleted file mode 100644 index daaf8f33..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuditFilter.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - */ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java deleted file mode 100644 index 5f828f65..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/AuthenticationFailureFilter.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.filters; - -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.ws.rs.core.Response; - -/** - * @author root - * - */ -public class AuthenticationFailureFilter implements Filter { - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#destroy() - */ - @Override - public void destroy() { - // TODO Auto-generated method stub - - } - - public class CharResponseWrapper extends HttpServletResponseWrapper { - private CharArrayWriter output; - - public String toString() { - return output.toString(); - } - - public CharResponseWrapper(HttpServletResponse response) { - super(response); - output = new CharArrayWriter(); - } - - public PrintWriter getWriter() { - return new PrintWriter(output); - } - } - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, - * javax.servlet.FilterChain) - */ - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, - ServletException { - HttpServletRequest request = (HttpServletRequest) req; - if (request.getRequestURI().contains("download")) { - chain.doFilter(req, res); - return; - } - - CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) res); - chain.doFilter(req, wrapper); - - if(wrapper.getStatus() == Response.Status.UNAUTHORIZED.ordinal()) { - PrintWriter out = res.getWriter(); - out.println("1Authentication Failed!"); - } - } - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) - */ - @Override - public void init(FilterConfig arg0) throws ServletException { - // TODO Auto-generated method stub - - } - -} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/GlusterResourceFilterFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/GlusterResourceFilterFactory.java deleted file mode 100644 index 899ba16e..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/filters/GlusterResourceFilterFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * - */ -package com.gluster.storage.management.server.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 create(AbstractMethod arg0) { - List filters = new ArrayList(); - filters.add(new AuditFilter()); - - return filters; - } -} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/AbstractResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/AbstractResource.java deleted file mode 100644 index 21b95877..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/AbstractResource.java +++ /dev/null @@ -1,177 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 base URI 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.server/src/com/gluster/storage/management/server/resources/v1_0/ClustersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ClustersResource.java deleted file mode 100644 index 45125513..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/ClustersResource.java +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.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 clusters = clusterService.getAllClusters(); - List clusterList = new ArrayList(); - 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.server/src/com/gluster/storage/management/server/resources/v1_0/DiscoveredServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/DiscoveredServersResource.java deleted file mode 100644 index f6038b71..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/DiscoveredServersResource.java +++ /dev/null @@ -1,150 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server.utils.GlusterUtil; -import com.gluster.storage.management.server.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 discoveredServerNames = new ArrayList(); - - public List getDiscoveredServerNames() { - return discoveredServerNames; - } - - public void setDiscoveredServerNames(List 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 discoveredServers = getDiscoveredServerDetails(); - return okResponse(new ServerListResponse(discoveredServers), mediaType); - } catch(Exception e) { - return errorResponse(e.getMessage()); - } - } else { - return okResponse(new ServerNameListResponse(getDiscoveredServerNames()), mediaType); - } - } - - private List getDiscoveredServerDetails() { - List discoveredServers = new ArrayList(); - 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.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java deleted file mode 100644 index f9650902..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GenericExceptionMapper.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 { - - /* (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.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java deleted file mode 100644 index fa96c884..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/GlusterServersResource.java +++ /dev/null @@ -1,487 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.data.ServerInfo; -import com.gluster.storage.management.server.services.ClusterService; -import com.gluster.storage.management.server.services.GlusterServerService; -import com.gluster.storage.management.server.tasks.InitializeDiskTask; -import com.gluster.storage.management.server.utils.CpuStatsFactory; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.utils.MemoryStatsFactory; -import com.gluster.storage.management.server.utils.NetworkStatsFactory; -import com.gluster.storage.management.server.utils.ServerUtil; -import com.gluster.storage.management.server.utils.SshUtil; -import com.gluster.storage.management.server.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 glusterServers = new ArrayList(); - - 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 getServerNames(List glusterServers) { - List serverNames = new ArrayList(); - 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 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 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 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 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.server/src/com/gluster/storage/management/server/resources/v1_0/KeysResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/KeysResource.java deleted file mode 100644 index 807291be..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/KeysResource.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * KeysResource.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.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.server/src/com/gluster/storage/management/server/resources/v1_0/TasksResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/TasksResource.java deleted file mode 100644 index 0fa49dc3..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/TasksResource.java +++ /dev/null @@ -1,194 +0,0 @@ -/** - * TaskResource.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.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 tasksMap = new HashMap(); - - public TasksResource() { - } - - public void addTask(Task task) { - tasksMap.put(task.getId(), task); - } - - public void removeTask(Task task) { - tasksMap.remove(task.getId()); - } - - public List getAllTasksInfo() { - List allTasksInfo = new ArrayList(); - for (Map.Entry 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 entry : tasksMap.entrySet()) { - if (entry.getValue().getId().equals(taskId)) { - return entry.getValue(); - } - } - return null; - } - - public List getAllTasks() { - List tasks = new ArrayList(); - for (Map.Entry 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.server/src/com/gluster/storage/management/server/resources/v1_0/UsersResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/UsersResource.java deleted file mode 100644 index 1b5e8fad..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/UsersResource.java +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/resources/v1_0/VolumesResource.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/VolumesResource.java deleted file mode 100644 index 1d0963eb..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/resources/v1_0/VolumesResource.java +++ /dev/null @@ -1,988 +0,0 @@ -/** - * VolumesResource.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.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.server.constants.VolumeOptionsDefaults; -import com.gluster.storage.management.server.data.ClusterInfo; -import com.gluster.storage.management.server.services.ClusterService; -import com.gluster.storage.management.server.tasks.MigrateBrickTask; -import com.gluster.storage.management.server.tasks.RebalanceVolumeTask; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.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()); - } - - 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()); - } - - 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 Status performOperation(String volumeName, String operation, GlusterServer onlineServer) { - if (operation.equals(TASK_START)) { - return glusterUtil.startVolume(volumeName, onlineServer.getName()); - } else if (operation.equals(TASK_STOP)) { - return glusterUtil.stopVolume(volumeName, onlineServer.getName()); - } else { - return new Status(Status.STATUS_CODE_FAILURE, "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 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 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 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 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.executeOnServer(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 bricks, boolean deleteFlag) { - Status result; - for (Brick brick : bricks) { - String brickDirectory = brick.getBrickDirectory(); - String mountPoint = brickDirectory.substring(0, brickDirectory.lastIndexOf("/")); - - result = (Status) serverUtil.executeOnServer(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 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 - Object responseObj = serverUtil.executeOnServer(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 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 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 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 messagesToRemove = new ArrayList(); - 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 logMessages, String severity) { - if (severity == null || severity.isEmpty()) { - return; - } - - List messagesToRemove = new ArrayList(); - for (VolumeLogMessage logMessage : logMessages) { - if (!logMessage.getSeverity().equals(severity)) { - messagesToRemove.add(logMessage); - } - } - logMessages.removeAll(messagesToRemove); - } - - private List getLogsForAllBricks(Volume volume, Integer lineCount) { - List logMessages; - logMessages = new ArrayList(); - // 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() { - @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 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.server/src/com/gluster/storage/management/server/security/GlusterUserDetailsService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/GlusterUserDetailsService.java deleted file mode 100644 index 21c13a03..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/GlusterUserDetailsService.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * GlusterUserDetailsService.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/security/UserAuthDao.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/UserAuthDao.java deleted file mode 100644 index cfc6e572..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/security/UserAuthDao.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * UserAuthDao.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.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.server/src/com/gluster/storage/management/server/services/ClusterService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java deleted file mode 100644 index 47960827..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/ClusterService.java +++ /dev/null @@ -1,269 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.data.PersistenceDao; -import com.gluster.storage.management.server.data.ServerInfo; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.utils.ServerUtil; -import com.gluster.storage.management.server.utils.SshUtil; - -/** - * Service class for functionality related to clusters - */ -@Component -public class ClusterService { - @Autowired - private PersistenceDao clusterDao; - - @Autowired - private PersistenceDao serverDao; - - @Autowired - private GlusterUtil glusterUtil; - - @Autowired - private SshUtil sshUtil; - - @Autowired - private ServerUtil serverUtil; - - private LRUCache onlineServerCache = new LRUCache(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 getAllClusters() { - return clusterDao.findAll(); - } - - public ClusterInfo getCluster(String clusterName) { - List clusters = clusterDao.findBy("UPPER(name) = ?1", clusterName.toUpperCase()); - if(clusters.size() == 0) { - return null; - } - - return clusters.get(0); - } - - public ClusterInfo getClusterForServer(String serverName) { - List 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 glusterServers = glusterUtil.getGlusterServers(server); - List servers = new ArrayList(); - 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 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.server/src/com/gluster/storage/management/server/services/GlusterServerService.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/GlusterServerService.java deleted file mode 100644 index e8bea530..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/services/GlusterServerService.java +++ /dev/null @@ -1,165 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.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 getGlusterServers(String clusterName, boolean fetchDetails) { - List 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 getGlusterServers(String clusterName, GlusterServer onlineServer, boolean fetchDetails) { - List 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 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.server/src/com/gluster/storage/management/server/tasks/InitServerTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitServerTask.java deleted file mode 100644 index 3fe794f5..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitServerTask.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * GlusterServerInitializer.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.data.PersistenceDao; - -/** - * Initializes the Gluster Management Server. - */ -public class InitServerTask extends JdbcDaoSupport { - @Autowired - private PasswordEncoder passwordEncoder; - - @Autowired - private String appVersion; - - @Autowired - private PersistenceDao 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 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 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.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java deleted file mode 100644 index 4f168d66..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/InitializeDiskTask.java +++ /dev/null @@ -1,168 +0,0 @@ -/** - * InitializeDiskTask.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.services.ClusterService; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.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 SshUtil sshUtil; - 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); - sshUtil = ctx.getBean(SshUtil.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(); - ProcessResult processResult = sshUtil.executeRemote(serverName, INITIALIZE_DISK_SCRIPT + fsTypeCommand + " " - + getDiskName()); - if (processResult.isSuccess()) { - TaskStatus taskStatus = new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput())); - taskStatus.setPercentageSupported((getFsType().equals(GlusterConstants.FSTYPE_XFS)) ? false : true); - getTaskInfo().setStatus(taskStatus); - return; - } - - // if we reach here, it means Initialize disk start failed. - throw new GlusterRuntimeException(processResult.toString()); - } - - @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.server/src/com/gluster/storage/management/server/tasks/MigrateBrickTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateBrickTask.java deleted file mode 100644 index 8ca15fc9..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/MigrateBrickTask.java +++ /dev/null @@ -1,227 +0,0 @@ -/** - * MigrateDiskTask.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.services.ClusterService; -import com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java deleted file mode 100644 index 24c2f1b5..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/RebalanceVolumeTask.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * RebalanceVolumeTask.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.services.ClusterService; -import com.gluster.storage.management.server.utils.GlusterUtil; -import com.gluster.storage.management.server.utils.SshUtil; -import com.sun.jersey.core.util.Base64; - -public class RebalanceVolumeTask extends Task { - - private String layout; - private String serverName; - private SshUtil sshUtil; - 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(); - sshUtil = ctx.getBean(SshUtil.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"; - ProcessResult processResult = sshUtil.executeRemote(serverName, command); - if (processResult.isSuccess()) { - getTaskInfo().setStatus(new TaskStatus(new Status(Status.STATUS_CODE_RUNNING, processResult.getOutput()))); - return; - } - - // if we reach here, it means rebalance start failed. - throw new GlusterRuntimeException(processResult.toString()); - } - - @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.server/src/com/gluster/storage/management/server/tasks/ServerSyncTask.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/ServerSyncTask.java deleted file mode 100644 index feb02354..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/ServerSyncTask.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * ServerDiscoveryTask.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.data.ClusterInfo; -import com.gluster.storage.management.server.data.PersistenceDao; -import com.gluster.storage.management.server.data.ServerInfo; -import com.gluster.storage.management.server.resources.v1_0.DiscoveredServersResource; -import com.gluster.storage.management.server.services.ClusterService; -import com.gluster.storage.management.server.services.GlusterServerService; -import com.gluster.storage.management.server.utils.ServerUtil; - -/** - * Task for syncing server details. This performs two things:
- * 1. Auto-discovery of servers eligible to be added to the Gluster cluster.
- * 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 clusterDao; - - public void perform() { - discoverServers(); - syncClusterServerMapping(); - } - - private void syncClusterServerMapping() { - List clusters = clusterService.getAllClusters(); - for(ClusterInfo cluster : clusters) { - List servers = cluster.getServers(); - List actualServers = glusterServerService.getGlusterServers(cluster.getName(), false); - updateRemovedServers(cluster, servers, actualServers); - updateAddedServers(cluster, servers, actualServers); - } - } - - private void updateAddedServers(ClusterInfo cluster, List servers, List actualServers) { - List addedServers = findAddedServers(cluster.getName(), servers, actualServers); - for(String addedServer : addedServers) { - clusterService.mapServerToCluster(cluster.getName(), addedServer); - } - } - - private void updateRemovedServers(ClusterInfo cluster, List servers, List actualServers) { - List removedServers = findRemovedServers(servers, actualServers); - for(String removedServer : removedServers) { - clusterService.unmapServerFromCluster(cluster.getName(), removedServer); - } - } - - private List findRemovedServers(List servers, List actualServers) { - List removedServers = new ArrayList(); - - for(ServerInfo server : servers) { - if (!GlusterCoreUtil.containsEntityWithName(actualServers, server.getName(), true)) { - removedServers.add(server.getName()); - } - } - return removedServers; - } - - private List findAddedServers(String clusterName, List servers, List actualServers) { - List addedServers = new ArrayList(); - for(GlusterServer actualServer : actualServers) { - if(!serverExists(servers, actualServer.getName())) { - addedServers.add(actualServer.getName()); - } - } - return addedServers; - } - - private boolean serverExists(List 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 serverNameList = new ArrayList(); - - ProcessResult result = serverUtil.executeGlusterScript(true, discoveryMechanism + SCRIPT_NAME_SFX, new ArrayList()); - if(result.isSuccess()) { - List 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.server/src/com/gluster/storage/management/server/tasks/Task.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/Task.java deleted file mode 100644 index 119f6297..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/tasks/Task.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Task.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.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.server.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.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java deleted file mode 100644 index 6f1226aa..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/AbstractStatsFactory.java +++ /dev/null @@ -1,168 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 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 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 addServerStats(ServerStats statsToBeAdded, ServerStats targetStats, int[][] dataCount) { - List serverStatsRows = statsToBeAdded.getRows(); - for (int rowNum = 0; rowNum < serverStatsRows.size() - && rowNum < targetStats.getMetadata().getRowCount(); rowNum++) { - ServerStatsRow row = serverStatsRows.get(rowNum); - List rowData = row.getUsageData(); - - List 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 rows = aggregatedStats.getRows(); - for(int rowNum = 0; rowNum < rows.size(); rowNum++) { - List 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 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.executeOnServer(true, serverName, getStatsScriptName() + argsStr + " " + period, ServerStats.class); - //String cpuUsageData = " 1310468100 300 1310471700 13 3 user system total 13104681002.23802952e-14.3747778209e-016.6128073384e-01 13104684002.3387347338e-014.4642717442e-016.8030064780e-01 13104687005.5043873220e+006.2462376636e+001.1750624986e+01 13104690002.4350593653e+012.6214585217e+015.0565178869e+01 13104693004.0786489953e+014.6784713828e+018.7571203781e+01 13104696004.1459955508e+015.2546309044e+019.4006264551e+01 13104699004.2312286165e+015.2390588332e+019.4702874497e+01 13104702004.2603794982e+015.1598861493e+019.4202656475e+01 13104705003.8238751290e+014.5312089966e+018.3550841256e+01 13104708001.7949961224e+012.1282058418e+013.9232019642e+01 13104711001.2330371421e-014.6347832868e-015.8678204289e-01 13104714001.6313260492e-015.4088119561e-017.0401380052e-01 1310471700NaNNaNNaN "; - //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.server/src/com/gluster/storage/management/server/utils/CpuStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/CpuStatsFactory.java deleted file mode 100644 index 27e271e5..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/CpuStatsFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java deleted file mode 100644 index f5d09ac2..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/GlusterUtil.java +++ /dev/null @@ -1,664 +0,0 @@ -/** - * GlusterUtil.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.utils; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import 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.NAS_PROTOCOL; -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.server.resources.v1_0.TasksResource; -import com.sun.jersey.api.core.InjectParam; - -@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: token: value - * - * @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 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 getGlusterServers(GlusterServer knownServer) { - String output = getPeerStatus(knownServer.getName()); - if (output == null) { - return null; - } - - knownServer.setUuid(getUuid(knownServer.getName())); - - List glusterServers = new ArrayList(); - 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 getGlusterServerNames(String knownServer) { - String output = getPeerStatus(knownServer); - if (output == null) { - return null; - } - - List glusterServerNames = new ArrayList(); - 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 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 options, String knownServer) { - String errors = ""; - if (options != null) { - for (Entry 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 getAllVolumes(String knownServer) { - return parseVolumeInfo(getVolumeInfo(knownServer)); - } - - private List parseVolumeInfo(String volumeInfoText) { - List volumes = new ArrayList(); - 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 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 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.executeOnServer(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 names = new GlusterUtil().getGlusterServerNames(); - // System.out.println(names); - List disks = new ArrayList(); - disks.add("server1:sda"); - disks.add("server1:sdb"); - new GlusterUtil().addBricks("Volume3", disks, "localhost"); - } -} diff --git a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java deleted file mode 100644 index fcbf43d5..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/MemoryStatsFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 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.server/src/com/gluster/storage/management/server/utils/NetworkStatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/NetworkStatsFactory.java deleted file mode 100644 index 2a50d598..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/NetworkStatsFactory.java +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 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 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 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.server/src/com/gluster/storage/management/server/utils/ServerUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java deleted file mode 100644 index f0aab567..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/ServerUtil.java +++ /dev/null @@ -1,258 +0,0 @@ -/** - * ServerUtil.java - * - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - */ -package com.gluster.storage.management.server.utils; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -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; - - 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"; - - public void setSshUtil(SshUtil sshUtil) { - this.sshUtil = sshUtil; - } - - public ProcessResult executeGlusterScript(boolean runInForeground, String scriptName, List arguments) { - List command = new ArrayList(); - - command.add(SCRIPT_COMMAND); - command.add(getScriptPath(scriptName)); - command.addAll(arguments); - return new ProcessUtil().executeCommand(runInForeground, command); - } - - private String getScriptPath(String scriptName) { - String scriptPath = servletContext.getRealPath(SCRIPT_DIR) + CoreConstants.FILE_SEPARATOR + scriptName; - return scriptPath; - } - - /** - * 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 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 = executeOnServer(true, serverName, REMOTE_SCRIPT_GET_SERVER_DETAILS, Server.class); - if (response instanceof Status) { - throw new GlusterRuntimeException(((Status) response).getMessage()); - } - return response; - } - - /** - * 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) executeOnServer(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.server/src/com/gluster/storage/management/server/utils/SshUtil.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java deleted file mode 100644 index bf82bc6c..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/SshUtil.java +++ /dev/null @@ -1,388 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 sshConnCache = new LRUCache(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.server/src/com/gluster/storage/management/server/utils/StatsFactory.java b/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/StatsFactory.java deleted file mode 100644 index 85487602..00000000 --- a/src/com.gluster.storage.management.server/src/com/gluster/storage/management/server/utils/StatsFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Gluster, Inc. - * 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 - * . - *******************************************************************************/ -package com.gluster.storage.management.server.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 serverName, String period); -} diff --git a/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml b/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml index 3cf30ee4..c89eb2f0 100644 --- a/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml +++ b/src/com.gluster.storage.management.server/src/spring/gluster-server-base.xml @@ -7,7 +7,7 @@ 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"> - + @@ -69,19 +69,19 @@ - + - com.gluster.storage.management.server.data.ClusterInfo + com.gluster.storage.management.gateway.data.ClusterInfo - + - com.gluster.storage.management.server.data.ServerInfo + com.gluster.storage.management.gateway.data.ServerInfo - - - + \ No newline at end of file -- cgit