blob: b17106d2dde68d95eeb00d1171e9ab2a06e79b34 [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
*
* 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.
*/
package org.apache.accumulo.monitor.rest.problems;
import static org.apache.accumulo.monitor.util.ParameterValidator.ALPHA_NUM_REGEX_TABLE_ID;
import static org.apache.accumulo.monitor.util.ParameterValidator.PROBLEM_TYPE_REGEX;
import static org.apache.accumulo.monitor.util.ParameterValidator.RESOURCE_REGEX;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
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.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.accumulo.core.clientImpl.Tables;
import org.apache.accumulo.core.data.TableId;
import org.apache.accumulo.monitor.Monitor;
import org.apache.accumulo.server.problems.ProblemReport;
import org.apache.accumulo.server.problems.ProblemReports;
import org.apache.accumulo.server.problems.ProblemType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Generates a problem summary and details as a JSON object
*
* @since 2.0.0
*/
@Path("/problems")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class ProblemsResource {
@Inject
private Monitor monitor;
/**
* Generates a list with the problem summary
*
* @return problem summary list
*/
@GET
@Path("summary")
public ProblemSummary getSummary() {
ProblemSummary problems = new ProblemSummary();
if (monitor.getProblemException() == null) {
for (Entry<TableId,Map<ProblemType,Integer>> entry : monitor.getProblemSummary().entrySet()) {
Integer readCount = null, writeCount = null, loadCount = null;
for (ProblemType pt : ProblemType.values()) {
Integer pcount = entry.getValue().get(pt);
if (pt.equals(ProblemType.FILE_READ)) {
readCount = pcount;
} else if (pt.equals(ProblemType.FILE_WRITE)) {
writeCount = pcount;
} else if (pt.equals(ProblemType.TABLET_LOAD)) {
loadCount = pcount;
}
}
String tableName = Tables.getPrintableTableInfoFromId(monitor.getContext(), entry.getKey());
problems.addProblemSummary(new ProblemSummaryInformation(tableName, entry.getKey(),
readCount, writeCount, loadCount));
}
}
return problems;
}
/**
* REST call to clear problem reports from a table
*
* @param tableID
* Table ID to clear problems
*/
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Path("summary")
public void clearTableProblems(
@QueryParam("s") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX_TABLE_ID) String tableID) {
Logger log = LoggerFactory.getLogger(Monitor.class);
try {
ProblemReports.getInstance(monitor.getContext()).deleteProblemReports(TableId.of(tableID));
} catch (Exception e) {
log.error("Failed to delete problem reports for table "
+ (tableID.isEmpty() ? "" : sanitize(tableID)), e);
}
}
/**
* Generates a list of the problem details as a JSON object
*
* @return problem details list
*/
@GET
@Path("details")
public ProblemDetail getDetails() {
ProblemDetail problems = new ProblemDetail();
if (monitor.getProblemException() == null) {
for (Entry<TableId,Map<ProblemType,Integer>> entry : monitor.getProblemSummary().entrySet()) {
ArrayList<ProblemReport> problemReports = new ArrayList<>();
Iterator<ProblemReport> iter =
entry.getKey() == null ? ProblemReports.getInstance(monitor.getContext()).iterator()
: ProblemReports.getInstance(monitor.getContext()).iterator(entry.getKey());
while (iter.hasNext()) {
problemReports.add(iter.next());
}
for (ProblemReport pr : problemReports) {
String tableName =
Tables.getPrintableTableInfoFromId(monitor.getContext(), pr.getTableId());
problems.addProblemDetail(
new ProblemDetailInformation(tableName, entry.getKey(), pr.getProblemType().name(),
pr.getServer(), pr.getTime(), pr.getResource(), pr.getException()));
}
}
}
return problems;
}
/**
* REST call to clear specific problem details
*
* @param tableID
* Table ID to clear
* @param resource
* Resource to clear
* @param ptype
* Problem type to clear
*/
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Path("details")
public void clearDetailsProblems(
@QueryParam("table") @NotNull @Pattern(regexp = ALPHA_NUM_REGEX_TABLE_ID) String tableID,
@QueryParam("resource") @NotNull @Pattern(regexp = RESOURCE_REGEX) String resource,
@QueryParam("ptype") @NotNull @Pattern(regexp = PROBLEM_TYPE_REGEX) String ptype) {
Logger log = LoggerFactory.getLogger(Monitor.class);
try {
ProblemReports.getInstance(monitor.getContext()).deleteProblemReport(TableId.of(tableID),
ProblemType.valueOf(ptype), resource);
} catch (Exception e) {
log.error("Failed to delete problem reports for table "
+ (tableID.isBlank() ? "" : sanitize(tableID)), e);
}
}
/**
* Prevent potential CRLF injection into logs from read in user data. See
* https://find-sec-bugs.github.io/bugs.htm#CRLF_INJECTION_LOGS
*/
private String sanitize(String msg) {
return msg.replaceAll("[\r\n]", "");
}
@GET
@Path("exception")
public Exception getException() {
return monitor.getProblemException();
}
}