blob: c5cc6d9cdf21139afb8d5a956033c5523b20208f [file] [log] [blame]
/*
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*/
package org.apache.hadoop.ozone.recon.api;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
import org.apache.hadoop.ozone.recon.MetricsServiceProviderFactory;
import org.apache.hadoop.ozone.recon.api.types.PipelineMetadata;
import org.apache.hadoop.ozone.recon.api.types.PipelinesResponse;
import org.apache.hadoop.ozone.recon.metrics.Metric;
import org.apache.hadoop.ozone.recon.scm.ReconPipelineManager;
import org.apache.hadoop.ozone.recon.spi.MetricsServiceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.UUID;
/**
* Endpoint to fetch details about Pipelines.
*/
@Path("/pipelines")
@Produces(MediaType.APPLICATION_JSON)
public class PipelineEndpoint {
private static final Logger LOG =
LoggerFactory.getLogger(PipelineEndpoint.class);
private ReconPipelineManager pipelineManager;
private MetricsServiceProvider metricsServiceProvider;
@Inject
PipelineEndpoint(OzoneStorageContainerManager reconSCM,
MetricsServiceProviderFactory
metricsServiceProviderFactory) {
this.pipelineManager = (ReconPipelineManager) reconSCM.getPipelineManager();
this.metricsServiceProvider =
metricsServiceProviderFactory.getMetricsServiceProvider();
}
/**
* Return the list of pipelines with detailed information about each pipeline.
* @return {@link Response}
*/
@GET
public Response getPipelines() {
List<PipelineMetadata> pipelinesList = new ArrayList<>();
List<Pipeline> pipelines = pipelineManager.getPipelines();
pipelines.forEach(pipeline -> {
UUID pipelineId = pipeline.getId().getId();
List<String> datanodes = new ArrayList<>();
PipelineMetadata.Builder builder = PipelineMetadata.newBuilder();
pipeline.getNodes().forEach(node -> datanodes.add(node.getHostName()));
long duration =
Instant.now().toEpochMilli() -
pipeline.getCreationTimestamp().toEpochMilli();
try {
String leaderNode = pipeline.getLeaderNode().getHostName();
builder.setLeaderNode(leaderNode);
} catch (IOException ioEx) {
LOG.warn("Cannot get leader node for pipeline {}",
pipelineId, ioEx);
}
try {
int containers =
pipelineManager.getNumberOfContainers(pipeline.getId());
builder.setContainers(containers);
} catch (IOException ioEx) {
LOG.warn("Cannot get containers for pipeline {} ", pipelineId, ioEx);
}
PipelineMetadata.Builder pipelineBuilder =
builder.setPipelineId(pipelineId)
.setDatanodes(datanodes)
.setDuration(duration)
.setStatus(pipeline.getPipelineState())
.setReplicationConfig(pipeline.getReplicationConfig());
// If any metrics service providers like Prometheus
// is configured, then query it for metrics and populate
// leader election count and last leader election time
if (metricsServiceProvider != null) {
// Extract last part of pipelineId to get its group Id.
// ex. group id of 48981bf7-8bea-4fbd-9857-79df51ee872d
// is group-79DF51EE872D
String[] splits = pipelineId.toString().split("-");
String groupId = "group-" + splits[splits.length - 1].toUpperCase();
Long leaderElectionCount = getElectionCountMetricValue(groupId);
pipelineBuilder.setLeaderElections(leaderElectionCount);
Long lastLeaderElectionElapsedTime
= getLastLeaderElectionElapsedTimeMetricValue(groupId,
pipeline.getLeaderId());
pipelineBuilder.setLastLeaderElection(lastLeaderElectionElapsedTime);
}
pipelinesList.add(pipelineBuilder.build());
});
PipelinesResponse pipelinesResponse =
new PipelinesResponse(pipelinesList.size(), pipelinesList);
return Response.ok(pipelinesResponse).build();
}
private Long getElectionCountMetricValue(String groupId) {
Long electionCount = 0L;
String metricsQuery = String.format(
"query=ratis_leader_election_electionCount{group=\"%s\"}", groupId);
try {
List<Metric> metrics = metricsServiceProvider.getMetricsInstant(
metricsQuery);
if (!metrics.isEmpty()) {
for (Metric m : metrics) {
TreeMap<Double, Double> values = (TreeMap<Double, Double>)
m.getValues();
if (!values.isEmpty()) {
electionCount += values.firstEntry().getValue().longValue();
}
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled()) {
LOG.error("Unable to get metrics value for " +
"ratis_leader_election_electionCount", ex);
}
}
return electionCount;
}
private Long getLastLeaderElectionElapsedTimeMetricValue(String groupId,
UUID uuid) {
String metricsQuery = String.format(
"query=ratis_leader_election_lastLeaderElectionElapsedTime{group=" +
"\"%s\",exported_instance=\"%s\"}", groupId,
uuid.toString());
try {
List<Metric> metrics = metricsServiceProvider.getMetricsInstant(
metricsQuery);
if (!metrics.isEmpty()) {
TreeMap<Double, Double> values = (TreeMap<Double, Double>)
metrics.get(0).getValues();
if (!values.isEmpty()) {
return values.firstEntry().getValue().longValue();
}
}
} catch (Exception ex) {
if (LOG.isErrorEnabled()) {
LOG.error("Unable to get metrics value for " +
"ratis_leader_election_lastLeaderElectionElapsedTime", ex);
}
}
return 0L;
}
}