package com.hubspot.mesos.client; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.type.TypeReference; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.name.Named; import com.hubspot.horizon.HttpClient; import com.hubspot.horizon.HttpRequest; import com.hubspot.horizon.HttpResponse; import com.hubspot.mesos.JavaUtils; import com.hubspot.mesos.json.MesosMasterMetricsSnapshotObject; import com.hubspot.mesos.json.MesosMasterStateObject; import com.hubspot.mesos.json.MesosSlaveStateObject; import com.hubspot.mesos.json.MesosTaskMonitorObject; @Singleton public class SingularityMesosClient implements MesosClient { public static final String HTTP_CLIENT_NAME = "mesos.http.client"; private static final Logger LOG = LoggerFactory.getLogger(SingularityMesosClient.class); private static final String MASTER_STATE_FORMAT = "http://%s/master/state"; private static final String MESOS_SLAVE_JSON_URL = "http://%s:5051/slave(1)/state"; private static final String MESOS_SLAVE_STATISTICS_URL = "http://%s:5051/monitor/statistics"; private static final String MESOS_METRICS_SNAPSHOT_URL = "http://%s/metrics/snapshot"; private static final TypeReference<List<MesosTaskMonitorObject>> TASK_MONITOR_TYPE_REFERENCE = new TypeReference<List<MesosTaskMonitorObject>>() {}; private final HttpClient httpClient; @Inject public SingularityMesosClient(@Named(HTTP_CLIENT_NAME) HttpClient httpClient) { this.httpClient = httpClient; } @Override public String getMasterUri(String hostnameAndPort) { return String.format(MASTER_STATE_FORMAT, hostnameAndPort); } @Override public String getMetricsSnapshotUri(String hostnameAndPort) { return String.format(MESOS_METRICS_SNAPSHOT_URL, hostnameAndPort); } private HttpResponse getFromMesos(String uri) { HttpResponse response = null; final long start = System.currentTimeMillis(); LOG.debug("Fetching {} from mesos", uri); try { response = httpClient.execute(HttpRequest.newBuilder().setUrl(uri).build()); LOG.debug("Response {} - {} after {}", response.getStatusCode(), uri, JavaUtils.duration(start)); } catch (Exception e) { throw new MesosClientException(String.format("Exception fetching %s after %s", uri, JavaUtils.duration(start)), e); } if (!response.isSuccess()) { throw new MesosClientException(String.format("Invalid response code from %s : %s", uri, response.getStatusCode())); } return response; } private <T> T getFromMesos(String uri, Class<T> clazz) { HttpResponse response = getFromMesos(uri); try { return response.getAs(clazz); } catch (Exception e) { throw new MesosClientException(String.format("Couldn't deserialize %s from %s", clazz.getSimpleName(), uri), e); } } @Override public MesosMasterStateObject getMasterState(String uri) { return getFromMesos(uri, MesosMasterStateObject.class); } @Override public MesosMasterMetricsSnapshotObject getMasterMetricsSnapshot(String uri) { return getFromMesos(uri, MesosMasterMetricsSnapshotObject.class); } @Override public String getSlaveUri(String hostname) { return String.format(MESOS_SLAVE_JSON_URL, hostname); } @Override public MesosSlaveStateObject getSlaveState(String uri) { return getFromMesos(uri, MesosSlaveStateObject.class); } @Override public List<MesosTaskMonitorObject> getSlaveResourceUsage(String hostname) { final String uri = String.format(MESOS_SLAVE_STATISTICS_URL, hostname); HttpResponse response = getFromMesos(uri); try { return response.getAs(TASK_MONITOR_TYPE_REFERENCE); } catch (Exception e) { throw new MesosClientException(String.format("Unable to deserialize task monitor object from %s", uri), e); } } }