/*******************************************************************************
* Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com>
* This file is part of Gluster Management Gateway.
*
* Gluster Management Gateway is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* Gluster Management Gateway is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*******************************************************************************/
package org.gluster.storage.management.gateway.resources.v1_0;
import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_FSTYPE;
import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_MOUNTPOINT;
import static org.gluster.storage.management.core.constants.RESTConstants.FORM_PARAM_SERVER_NAME;
import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_CLUSTER_NAME;
import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_DISK_NAME;
import static org.gluster.storage.management.core.constants.RESTConstants.PATH_PARAM_SERVER_NAME;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_DETAILS;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_INTERFACE;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_MAX_COUNT;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_NEXT_TO;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_PERIOD;
import static org.gluster.storage.management.core.constants.RESTConstants.QUERY_PARAM_TYPE;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_DISKS;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_FSTYPES;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_PATH_CLUSTERS;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_SERVERS;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_STATISTICS;
import static org.gluster.storage.management.core.constants.RESTConstants.RESOURCE_TASKS;
import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_CPU;
import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_MEMORY;
import static org.gluster.storage.management.core.constants.RESTConstants.STATISTICS_TYPE_NETWORK;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.gluster.storage.management.core.constants.GlusterConstants;
import org.gluster.storage.management.core.constants.RESTConstants;
import org.gluster.storage.management.core.exceptions.GlusterValidationException;
import org.gluster.storage.management.core.model.GlusterServer;
import org.gluster.storage.management.core.model.ServerStats;
import org.gluster.storage.management.core.model.TaskStatus;
import org.gluster.storage.management.core.response.FsTypeListResponse;
import org.gluster.storage.management.core.response.GlusterServerListResponse;
import org.gluster.storage.management.core.response.ServerNameListResponse;
import org.gluster.storage.management.gateway.data.ClusterInfo;
import org.gluster.storage.management.gateway.services.ClusterService;
import org.gluster.storage.management.gateway.services.GlusterServerService;
import org.gluster.storage.management.gateway.tasks.InitializeDiskTask;
import org.gluster.storage.management.gateway.utils.CpuStatsFactory;
import org.gluster.storage.management.gateway.utils.MemoryStatsFactory;
import org.gluster.storage.management.gateway.utils.NetworkStatsFactory;
import org.gluster.storage.management.gateway.utils.StatsFactory;
import org.springframework.stereotype.Component;
import com.sun.jersey.api.core.InjectParam;
import com.sun.jersey.spi.resource.Singleton;
@Component
@Singleton
@Path(RESOURCE_PATH_CLUSTERS + "/{" + PATH_PARAM_CLUSTER_NAME + "}/" + RESOURCE_SERVERS)
public class GlusterServersResource extends AbstractResource {
public static final String HOSTNAMETAG = "hostname:";
@InjectParam
private TasksResource taskResource;
@InjectParam
private ClusterService clusterService;
@InjectParam
private CpuStatsFactory cpuStatsFactory;
@InjectParam
private MemoryStatsFactory memoryStatsFactory;
@InjectParam
private NetworkStatsFactory networkStatsFactory;
@InjectParam
private GlusterServerService glusterServerService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getGlusterServersJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@QueryParam(QUERY_PARAM_DETAILS) Boolean details, @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
@QueryParam(QUERY_PARAM_NEXT_TO) String previousServerName) {
return getGlusterServers(clusterName, MediaType.APPLICATION_JSON, details, maxCount, previousServerName);
}
@GET
@Produces(MediaType.APPLICATION_XML)
public Response getGlusterServersXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@QueryParam(QUERY_PARAM_DETAILS) Boolean details, @QueryParam(QUERY_PARAM_MAX_COUNT) Integer maxCount,
@QueryParam(QUERY_PARAM_NEXT_TO) String previousServerName) {
return getGlusterServers(clusterName, MediaType.APPLICATION_XML, details, maxCount, previousServerName);
}
private Response getGlusterServers(String clusterName, String mediaType, Boolean fetchDetails, Integer maxCount,
String previousServerName) {
if(fetchDetails == null) {
// by default, fetch the server list
fetchDetails = false;
}
List<GlusterServer> glusterServers = new ArrayList<GlusterServer>();
if (clusterName == null || clusterName.isEmpty()) {
return badRequestResponse("Cluster name must not be empty!");
}
ClusterInfo cluster = clusterService.getCluster(clusterName);
if (cluster == null) {
return notFoundResponse("Cluster [" + clusterName + "] not found!");
}
if (cluster.getServers().size() == 0) {
return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
}
try {
glusterServers = glusterServerService.getGlusterServers(clusterName, fetchDetails, maxCount, previousServerName);
} catch (Exception e) {
return errorResponse(e.getMessage());
}
if(fetchDetails) {
return okResponse(new GlusterServerListResponse(glusterServers), mediaType);
} else {
// no details to be fetched. Return list of server names.
return okResponse(new ServerNameListResponse(getServerNames(glusterServers)), mediaType);
}
}
private List<String> getServerNames(List<GlusterServer> glusterServers) {
List<String> serverNames = new ArrayList<String>();
for(GlusterServer server : glusterServers) {
serverNames.add(server.getName());
}
return serverNames;
}
@GET
@Path("{" + PATH_PARAM_SERVER_NAME + "}")
@Produces(MediaType.APPLICATION_XML)
public Response getGlusterServerXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_XML);
}
@GET
@Path("{" + PATH_PARAM_SERVER_NAME + "}")
@Produces(MediaType.APPLICATION_JSON)
public Response getGlusterServerJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
return getGlusterServerResponse(clusterName, serverName, MediaType.APPLICATION_JSON);
}
private Response getGlusterServerResponse(String clusterName, String serverName, String mediaType) {
try {
return okResponse(glusterServerService.getGlusterServer(clusterName, serverName, true), mediaType);
} catch (Exception e) {
return errorResponse(e.getMessage());
}
}
@POST
public Response addServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@FormParam(FORM_PARAM_SERVER_NAME) String serverName) {
return createdResponse(glusterServerService.addServerToCluster(clusterName, serverName));
}
@DELETE
@Path("{" + PATH_PARAM_SERVER_NAME + "}")
public Response removeServer(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
glusterServerService.removeServerFromCluster(clusterName, serverName);
return noContentResponse();
}
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_FSTYPES)
public FsTypeListResponse getFsTypes(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName) {
List<String> fsTypes = glusterServerService.getFsTypes(clusterName, serverName);
return new FsTypeListResponse(fsTypes);
}
@PUT
@Produces(MediaType.APPLICATION_XML)
@Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_DISKS + "/{" + PATH_PARAM_DISK_NAME + "}")
public Response initializeDisk(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@PathParam(PATH_PARAM_SERVER_NAME) String serverName, @PathParam(PATH_PARAM_DISK_NAME) String diskName,
@FormParam(FORM_PARAM_FSTYPE) String fsType, @FormParam(FORM_PARAM_MOUNTPOINT) String mountPoint) {
if (clusterName == null || clusterName.isEmpty()) {
return badRequestResponse("Cluster name must not be empty!");
}
if (serverName == null || serverName.isEmpty()) {
return badRequestResponse("Server name must not be empty!");
}
if (diskName == null || diskName.isEmpty()) {
return badRequestResponse("Disk name must not be empty!");
}
if (fsType == null || fsType.isEmpty()) {
fsType = GlusterConstants.FSTYPE_DEFAULT;
// return badRequestResponse("Parameter [" + FORM_PARAM_FSTYPE + "] is missing in request!");
}
InitializeDiskTask initializeTask = new InitializeDiskTask(clusterService, clusterName, serverName, diskName, fsType, mountPoint);
try {
initializeTask.start();
// Check the initialize disk status
TaskStatus taskStatus = initializeTask.checkStatus();
initializeTask.getTaskInfo().setStatus(taskStatus);
taskResource.addTask(clusterName, initializeTask);
return acceptedResponse(RESTConstants.RESOURCE_PATH_CLUSTERS + "/" + clusterName + "/" + RESOURCE_TASKS + "/"
+ initializeTask.getId());
} catch (Exception e) {
return errorResponse(e.getMessage());
}
}
@GET
@Produces(MediaType.APPLICATION_XML)
@Path(RESOURCE_STATISTICS)
public Response getAggregatedPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period) {
return getAggregaredPerformanceData(clusterName, type, period, MediaType.APPLICATION_XML);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path(RESOURCE_STATISTICS)
public Response getAggregaredPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName,
@QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period) {
return getAggregaredPerformanceData(clusterName, type, period, MediaType.APPLICATION_JSON);
}
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
public Response getPerformanceDataXML(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName,
@QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period,
@QueryParam(QUERY_PARAM_INTERFACE) String networkInterface) {
return getPerformanceData(clusterName, serverName, type, period, networkInterface, MediaType.APPLICATION_XML);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{" + PATH_PARAM_SERVER_NAME + "}/" + RESOURCE_STATISTICS)
public Response getPerformanceDataJSON(@PathParam(PATH_PARAM_CLUSTER_NAME) String clusterName, @PathParam(PATH_PARAM_SERVER_NAME) String serverName,
@QueryParam(QUERY_PARAM_TYPE) String type, @QueryParam(QUERY_PARAM_PERIOD) String period,
@QueryParam(QUERY_PARAM_INTERFACE) String networkInterface) {
return getPerformanceData(clusterName, serverName, type, period, networkInterface, MediaType.APPLICATION_JSON);
}
private Response getAggregaredPerformanceData(String clusterName, String type, String period, String mediaType) {
if (clusterName == null || clusterName.isEmpty()) {
throw new GlusterValidationException("Cluster name must not be empty!");
}
if (type == null || type.isEmpty()) {
throw new GlusterValidationException("Statistics type name must not be empty!");
}
if (period == null || period.isEmpty()) {
throw new GlusterValidationException("Statistics period name must not be empty! Valid values are 1d/1w/1m/1y");
}
ClusterInfo cluster = clusterService.getCluster(clusterName);
if (cluster == null) {
return notFoundResponse("Cluster [" + clusterName + "] not found!");
}
if (cluster.getServers().isEmpty()) {
// cluster is empty. return empty stats.
return okResponse(new ServerStats(), mediaType);
}
List<String> serverNames = getServerNames(glusterServerService.getGlusterServers(clusterName, false, null, null));
return okResponse(getStatsFactory(type).fetchAggregatedStats(serverNames, period), mediaType);
}
private Response getPerformanceData(String clusterName, String serverName, String type, String period, String networkInterface, String mediaType) {
if (clusterName == null || clusterName.isEmpty()) {
throw new GlusterValidationException("Cluster name must not be empty!");
}
if (serverName == null || serverName.isEmpty()) {
throw new GlusterValidationException("Server name must not be empty!");
}
if (type == null || type.isEmpty()) {
throw new GlusterValidationException("Statistics type name must not be empty!");
}
if (period == null || period.isEmpty()) {
throw new GlusterValidationException("Statistics period name must not be empty! Valid values are 1d/1w/1m/1y");
}
return okResponse(getStatsFactory(type).fetchStats(serverName, period, networkInterface), mediaType);
}
private StatsFactory getStatsFactory(String type) {
if(type.equals(STATISTICS_TYPE_CPU)) {
return cpuStatsFactory;
} else if(type.equals(STATISTICS_TYPE_MEMORY)) {
return memoryStatsFactory;
} else if(type.equals(STATISTICS_TYPE_NETWORK)) {
return networkStatsFactory;
} else {
throw new GlusterValidationException("Invalid server statistics type [" + type + "]. Valid values are ["
+ STATISTICS_TYPE_CPU + ", " + STATISTICS_TYPE_NETWORK + ", " + STATISTICS_TYPE_MEMORY + "]");
}
}
}