package org.apache.helix.ui.resource;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import com.google.common.collect.ImmutableList;
import org.apache.helix.manager.zk.ZKUtil;
import org.apache.helix.model.ExternalView;
import org.apache.helix.model.IdealState;
import org.apache.helix.ui.api.*;
import org.apache.helix.ui.util.ClientCache;
import org.apache.helix.ui.util.DataCache;
import org.apache.helix.ui.view.ClusterView;
import org.apache.helix.ui.view.LandingView;
import org.apache.helix.ui.view.ResourceView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.*;
@Path("/")
@Produces(MediaType.TEXT_HTML)
public class DashboardResource {
private static final Logger LOG = LoggerFactory.getLogger(DashboardResource.class);
private static final List<String> REBALANCE_MODES = ImmutableList.of(
IdealState.RebalanceMode.SEMI_AUTO.toString(),
IdealState.RebalanceMode.FULL_AUTO.toString(),
IdealState.RebalanceMode.CUSTOMIZED.toString(),
IdealState.RebalanceMode.USER_DEFINED.toString(),
IdealState.RebalanceMode.TASK.toString());
private final boolean adminMode;
private final ClientCache clientCache;
private final DataCache dataCache;
private final List<String> zkAliases;
public DashboardResource(ClientCache clientCache,
DataCache dataCache,
boolean adminMode,
List<String> zkAliases) {
this.clientCache = clientCache;
this.dataCache = dataCache;
this.adminMode = adminMode;
this.zkAliases = zkAliases;
}
@GET
public Response getRoot() {
return Response.seeOther(URI.create("/dashboard")).build();
}
@GET
@Path("/dashboard")
public LandingView getLandingView() {
return new LandingView(zkAliases);
}
@GET
@Path("/dashboard/{zkAddress}")
public ClusterView getClusterView(@PathParam("zkAddress") String zkAddress) throws Exception {
clientCache.get(zkAddress); // n.b. will validate
return getClusterView(zkAddress, null);
}
@GET
@Path("/dashboard/{zkAddress}/{cluster}")
public ClusterView getClusterView(
@PathParam("zkAddress") String zkAddress,
@PathParam("cluster") String cluster) throws Exception {
ClusterConnection clusterConnection = clientCache.get(zkAddress);
// All clusters
List<String> clusters = dataCache.getClusterCache().get(zkAddress);
// The active cluster
String activeCluster = cluster == null ? clusters.get(0) : cluster;
ClusterSpec clusterSpec = new ClusterSpec(zkAddress, activeCluster);
// Check it
if (!ZKUtil.isClusterSetup(activeCluster, clusterConnection.getZkClient())) {
return new ClusterView(
adminMode,
zkAddress,
clusters,
false,
activeCluster,
null,
null,
null,
null,
null,
null);
}
// Resources in the active cluster
List<String> activeClusterResources = dataCache.getResourceCache().get(clusterSpec);
// Instances in active cluster
List<InstanceSpec> instanceSpecs = dataCache.getInstanceCache().get(clusterSpec);
// State models in active cluster
List<String> stateModels
= clusterConnection.getClusterSetup().getClusterManagementTool().getStateModelDefs(activeCluster);
// Config table
List<ConfigTableRow> configTable = dataCache.getConfigCache().get(clusterSpec);
// Controller leader
String controllerLeader = dataCache.getControllerLeaderCache().get(clusterSpec);
return new ClusterView(
adminMode,
zkAddress,
clusters,
true,
activeCluster,
activeClusterResources,
instanceSpecs,
configTable,
stateModels,
REBALANCE_MODES,
controllerLeader);
}
@GET
@Path("/dashboard/{zkAddress}/{cluster}/{resource}")
public ResourceView getResourceView(
@PathParam("zkAddress") String zkAddress,
@PathParam("cluster") String cluster,
@PathParam("resource") String resource) throws Exception {
ClusterConnection clusterConnection = clientCache.get(zkAddress);
// All clusters
List<String> clusters = dataCache.getClusterCache().get(zkAddress);
// The active cluster
String activeCluster = cluster == null ? clusters.get(0) : cluster;
ClusterSpec clusterSpec = new ClusterSpec(zkAddress, activeCluster);
// Check it
if (!ZKUtil.isClusterSetup(activeCluster, clusterConnection.getZkClient())) {
return new ResourceView(
adminMode, zkAddress, clusters, false, activeCluster, null, null, null, null, null, null, null);
}
// Resources in the active cluster
List<String> activeClusterResources = dataCache.getResourceCache().get(clusterSpec);
if (!activeClusterResources.contains(resource)) {
throw new NotFoundException("No resource " + resource + " in " + activeCluster);
}
// Instances in active cluster
List<InstanceSpec> instanceSpecs = dataCache.getInstanceCache().get(clusterSpec);
Map<String, InstanceSpec> instanceSpecMap = new HashMap<String, InstanceSpec>(instanceSpecs.size());
for (InstanceSpec instanceSpec : instanceSpecs) {
instanceSpecMap.put(instanceSpec.getInstanceName(), instanceSpec);
}
// Resource state
IdealState idealState
= clusterConnection.getClusterSetup().getClusterManagementTool().getResourceIdealState(cluster, resource);
ExternalView externalView
= clusterConnection.getClusterSetup().getClusterManagementTool().getResourceExternalView(cluster, resource);
ResourceStateSpec resourceStateSpec
= new ResourceStateSpec(resource, idealState, externalView, instanceSpecMap);
List<ResourceStateTableRow> resourceStateTable
= resourceStateSpec.getResourceStateTable();
// Resource config
List<ConfigTableRow> configTable = dataCache.getResourceConfigCache().get(new ResourceSpec(zkAddress, activeCluster, resource));
// Resource instances
Set<String> resourceInstances = new HashSet<String>();
for (ResourceStateTableRow row : resourceStateTable) {
resourceInstances.add(row.getInstanceName());
}
return new ResourceView(
adminMode,
zkAddress,
clusters,
true,
activeCluster,
activeClusterResources,
resource,
resourceStateTable,
resourceInstances,
configTable,
IdealStateSpec.fromIdealState(idealState),
instanceSpecs);
}
@POST
@Path("/dashboard/{zkAddress}/{cluster}/{resource}")
public Response resourceAction(
@PathParam("zkAddress") String zkAddress,
@PathParam("cluster") String cluster,
@PathParam("resource") String resource,
@QueryParam("action") @DefaultValue("reset") String action) {
ClusterConnection clusterConnection = clientCache.get(zkAddress);
if ("reset".equals(action)) {
clusterConnection
.getClusterSetup()
.getClusterManagementTool()
.resetResource(cluster, Collections.singletonList(resource));
LOG.info("Reset resource {} in cluster {}", resource, cluster);
return Response.ok().build();
} else {
return Response.status(Response.Status.BAD_REQUEST).entity("Unsupported action " + action).build();
}
}
}