controllers.HostController Maven / Gradle / Ivy
/**
* Copyright 2014 Groupon.com
*
* Licensed 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 controllers;
import com.arpnetworking.metrics.portal.hosts.HostRepository;
import com.arpnetworking.steno.Logger;
import com.arpnetworking.steno.LoggerFactory;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Maps;
import com.google.common.net.HttpHeaders;
import com.google.inject.Inject;
import models.internal.Host;
import models.internal.HostQuery;
import models.internal.MetricsSoftwareState;
import models.internal.QueryResult;
import models.view.PagedContainer;
import models.view.Pagination;
import play.Configuration;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Singleton;
/**
* Metrics portal host controller. Exposes APIs to query and manipulate hosts.
*
* @author Ville Koskela (vkoskela at groupon dot com)
*/
@Singleton
public class HostController extends Controller {
/**
* Public constructor.
*
* @param configuration Instance of Play's Configuration
.
* @param hostRepository Instance of HostRepository
.
*/
@Inject
public HostController(final Configuration configuration, final HostRepository hostRepository) {
this(configuration.getInt("hosts.limit", MAX_LIMIT), hostRepository);
}
/**
* Query for hosts.
*
* @param name The complete or partial name of the host. Optional.
* @param state The state of the metrics software on the host. Optional.
* @param cluster The name of the cluster for the host. Optional.
* @param limit The maximum number of results to return. Optional.
* @param offset The number of results to skip. Optional.
* @param sort_by The field to sort results by. Optional.
* @return Result
paginated matching hosts.
*/
// CHECKSTYLE.OFF: ParameterNameCheck - Names must match query parameters.
public Result query(
final String name,
final String state,
final String cluster,
final Integer limit,
final Integer offset,
final String sort_by) {
// CHECKSTYLE.ON: ParameterNameCheck
// Convert and validate parameters
final MetricsSoftwareState stateValue;
try {
stateValue = state == null ? null : MetricsSoftwareState.valueOf(state);
} catch (final IllegalArgumentException iae) {
return badRequest("Invalid state argument");
}
final HostQuery.Field sortByValue;
try {
sortByValue = sort_by == null ? null : HostQuery.Field.valueOf(sort_by);
} catch (final IllegalArgumentException iae) {
return badRequest("Invalid sort_by argument");
}
final Optional argName = Optional.ofNullable(name);
final Optional argState = Optional.ofNullable(stateValue);
final Optional argCluster = Optional.ofNullable(cluster);
final Optional argOffset = Optional.ofNullable(offset);
final Optional argSortBy = Optional.ofNullable(sortByValue);
final int argLimit = Math.min(_maxLimit, Optional.of(MoreObjects.firstNonNull(limit, _maxLimit)).get());
if (argLimit < 0) {
return badRequest("Invalid limit; must be greater than or equal to 0");
}
if (argOffset.isPresent() && argOffset.get() < 0) {
return badRequest("Invalid offset; must be greater than or equal to 0");
}
// Build conditions map
final Map conditions = Maps.newHashMap();
if (argName.isPresent()) {
conditions.put("name", argName.get());
}
if (argState.isPresent()) {
conditions.put("state", argState.get().toString());
}
if (argCluster.isPresent()) {
conditions.put("cluster", argCluster.get());
}
if (argSortBy.isPresent()) {
conditions.put("sort_by", argSortBy.get().toString());
}
// Build a host repository query
final HostQuery query = _hostRepository.createQuery()
.partialHostname(argName)
.metricsSoftwareState(argState)
.cluster(argCluster)
.limit(argLimit)
.offset(argOffset)
.sortBy(argSortBy);
// Execute the query
return executeQuery(argOffset, argLimit, conditions, query);
}
private Result executeQuery(
final Optional argOffset,
final int argLimit,
final Map conditions,
final HostQuery query) {
final QueryResult result;
try {
result = query.execute();
// CHECKSTYLE.OFF: IllegalCatch - Convert any exception to 500
} catch (final Exception e) {
// CHECKSTYLE.ON: IllegalCatch
LOGGER.error()
.setMessage("Host query failed")
.setThrowable(e)
.log();
return internalServerError();
}
// Wrap the query results and return as JSON
if (result.etag().isPresent()) {
response().setHeader(HttpHeaders.ETAG, result.etag().get());
}
return ok(Json.toJson(new PagedContainer<>(
result.values()
.stream()
.map(this::internalModelToViewModel)
.collect(Collectors.toList()),
new Pagination(
request().path(),
result.total(),
result.values().size(),
argLimit,
argOffset,
conditions))));
}
private models.view.Host internalModelToViewModel(final Host host) {
final models.view.Host viewHost = new models.view.Host();
viewHost.setCluster(host.getCluster().orNull());
viewHost.setHostname(host.getHostname());
viewHost.setMetricsSoftwareState(host.getMetricsSoftwareState().toString());
return viewHost;
}
private HostController(final int maxLimit, final HostRepository hostRepository) {
_maxLimit = maxLimit;
_hostRepository = hostRepository;
}
private final int _maxLimit;
private final HostRepository _hostRepository;
private static final int MAX_LIMIT = 1000;
private static final Logger LOGGER = LoggerFactory.getLogger(HostController.class);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy