private HttpResponse getFromMesos(String uri, boolean useShortTimeout) { HttpClient currentHttpClient = useShortTimeout ? shortTimeoutHttpClient : httpClient; HttpResponse response = null; final long start = System.currentTimeMillis(); LOG.debug("Fetching {} from mesos", uri); try { response = currentHttpClient.execute(HttpRequest.newBuilder().setUrl(uri).build(), new Options()); 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 SingularityClientException fail(String type, HttpResponse response) { String body = ""; try { body = response.getAsString(); } catch (Exception e) { LOG.warn("Unable to read body", e); } String uri = ""; try { uri = response.getRequest().getUrl().toString(); } catch (Exception e) { LOG.warn("Unable to read uri", e); } throw new SingularityClientException(String.format("Failed '%s' action on Singularity (%s) - code: %s, %s", type, uri, response.getStatusCode(), body), response.getStatusCode()); }
private void checkResponse(String type, HttpResponse response) { if (response.isError()) { throw fail(type, response); } }
@Override protected void configure() { ObjectMapper objectMapper = JavaUtils.newObjectMapper(); Builder httpConfigBuilder = HttpConfig.newBuilder().setObjectMapper(objectMapper); bind(ObjectMapper.class).annotatedWith(Names.named(MESOS_CLIENT_OBJECT_MAPPER)).toInstance(objectMapper); bind(HttpClient.class).annotatedWith(Names.named(SingularityMesosClient.DEFAULT_HTTP_CLIENT_NAME)) .toInstance(new NingHttpClient(httpConfigBuilder.build())); bind(HttpClient.class).annotatedWith(Names.named(SingularityMesosClient.SHORT_TIMEOUT_HTTP_CLIENT_NAME)) .toInstance(new NingHttpClient(httpConfigBuilder.setRequestTimeoutSeconds(MESOS_CLIENT_HTTP_SHORT_TIMEOUT_SECONDS).build())); bind(MesosClient.class).to(SingularityMesosClient.class).in(Scopes.SINGLETON); }
@Test public void itRetriesRequestsThatErrorDueToDeadHost() { when(httpClient.execute(any())) .thenReturn(response); when(response.getStatusCode()) .thenReturn(503) .thenReturn(200); when(response.isServerError()) .thenReturn(true) .thenReturn(false); singularityClient.pauseSingularityRequest("requestId", Optional.absent()); verify(httpClient, times(2)) .execute(requestCaptor.capture()); HttpRequest sentRequest = requestCaptor.getValue(); assertThat(sentRequest.getUrl().toString()) .matches("http://host(1|2)/singularity/v2/api/requests/request/requestId/pause"); }
private <T> Optional<T> getSingleWithParams(Function<String, String> hostToUrl, String type, String id, Optional<Map<String, Object>> queryParams, Class<T> clazz) { final long start = System.currentTimeMillis(); HttpResponse response = executeGetSingleWithParams(hostToUrl, type, id, queryParams); if (response.getStatusCode() == 404) { return Optional.absent(); } checkResponse(type, response); LOG.info("Got {} {} in {}ms", type, id, System.currentTimeMillis() - start); return Optional.fromNullable(response.getAs(clazz)); }
@Test public void itThrowsAnExceptionOnServerErrors() { when(httpClient.execute(any())) .thenReturn(response); when(response.getStatusCode()) .thenReturn(500); when(response.isError()) .thenReturn(true); assertThatExceptionOfType(SingularityClientException.class) .isThrownBy(() -> singularityClient.pauseSingularityRequest("requestId", Optional.absent())); }
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); singularityClient = buildClient(); when(response.getRequest()) .thenReturn(request); when(request.getUrl()) .thenReturn(new URI("test-url")); }
private <T> Optional<T> post(Function<String, String> hostToUri, String type, Optional<?> body, Optional<Class<T>> clazz) { try { HttpResponse response = executeRequest(hostToUri, type, body, Method.POST, Optional.absent()); if (clazz.isPresent()) { return Optional.of(response.getAs(clazz.get())); } } catch (Exception e) { LOG.warn("Http post failed", e); } return Optional.absent(); }
private void addQueryParams(HttpRequest.Builder requestBuilder, Map<String, ?> queryParams) { for (Entry<String, ?> queryParamEntry : queryParams.entrySet()) { if (queryParamEntry.getValue() instanceof String) { requestBuilder.setQueryParam(queryParamEntry.getKey()).to((String) queryParamEntry.getValue()); } else if (queryParamEntry.getValue() instanceof Integer) { requestBuilder.setQueryParam(queryParamEntry.getKey()).to((Integer) queryParamEntry.getValue()); } else if (queryParamEntry.getValue() instanceof Long) { requestBuilder.setQueryParam(queryParamEntry.getKey()).to((Long) queryParamEntry.getValue()); } else if (queryParamEntry.getValue() instanceof Boolean) { requestBuilder.setQueryParam(queryParamEntry.getKey()).to((Boolean) queryParamEntry.getValue()); } else { throw new RuntimeException(String.format("The type '%s' of query param %s is not supported. Only String, long, int and boolean values are supported", queryParamEntry.getValue().getClass().getName(), queryParamEntry.getKey())); } } }
private void addCredentials(HttpRequest.Builder requestBuilder) { if (credentials.isPresent()) { requestBuilder.addHeader(credentials.get().getHeaderName(), credentials.get().getToken()); } }
public boolean checkAuthForRequestGroupsUpdate(String requestId, SingularityUpdateGroupsRequest updateGroupsRequest) { final Function<String, String> requestUri = (host) -> String.format(REQUEST_GROUPS_UPDATE_AUTH_CHECK_FORMAT, getApiBase(host), requestId); final HttpResponse response = post(requestUri, String.format("check auth for update authorized groups of request %s", requestId), Optional.of(updateGroupsRequest)); return response.isSuccess(); }
@Override protected void configure() { ObjectMapper objectMapper = JavaUtils.newObjectMapper(); objectMapper.registerModule(new GuavaModule()); objectMapper.registerModule(new Jdk8Module()); HttpClient httpClient = new NingHttpClient(httpConfig.or(HttpConfig.newBuilder().setObjectMapper(objectMapper).build())); bind(HttpClient.class).annotatedWith(Names.named(HTTP_CLIENT_NAME)).toInstance(httpClient); bind(SingularityClient.class).toProvider(SingularityClientProvider.class).in(Scopes.SINGLETON); if (hosts != null) { bindHosts(binder()).toInstance(hosts); } }
private <T> Optional<T> getSingleWithParams(Function<String, String> hostToUrl, String type, String id, Optional<Map<String, Object>> queryParams, TypeReference<T> typeReference) { final long start = System.currentTimeMillis(); HttpResponse response = executeGetSingleWithParams(hostToUrl, type, id, queryParams); if (response.getStatusCode() == 404) { return Optional.absent(); } checkResponse(type, response); LOG.info("Got {} {} in {}ms", type, id, System.currentTimeMillis() - start); return Optional.fromNullable(response.getAs(typeReference)); }
/** * * @param requestId * @param runNowRequest * @param minimalReturn - if `true` will return a SingularityPendingRequestParent that is _not_ hydrated with extra task + deploy information * @return */ public SingularityPendingRequestParent runSingularityRequest(String requestId, Optional<SingularityRunNowRequest> runNowRequest, boolean minimalReturn) { final Function<String, String> requestUri = (host) -> String.format(REQUEST_RUN_FORMAT, getApiBase(host), requestId); final HttpResponse response = post(requestUri, String.format("run of request %s", requestId), runNowRequest, ImmutableMap.of("minimal", String.valueOf(minimalReturn))); return response.getAs(SingularityPendingRequestParent.class); }
public Optional<SingularityTaskReconciliationStatistics> getTaskReconciliationStatistics() { final Function<String, String> uri = (host) -> String.format(TASK_RECONCILIATION_FORMAT, getApiBase(host)); LOG.info("Fetch task reconciliation statistics from {}", uri); final long start = System.currentTimeMillis(); HttpResponse response = executeRequest(uri, Method.GET, Optional.absent(), Collections.emptyMap()); if (response.getStatusCode() == 404) { return Optional.absent(); } checkResponse("task reconciliation statistics", response); LOG.info("Got task reconciliation statistics in {}ms", System.currentTimeMillis() - start); return Optional.of(response.getAs(SingularityTaskReconciliationStatistics.class)); }
public SingularityPendingRequestParent updateAuthorizedGroups(String requestId, SingularityUpdateGroupsRequest updateGroupsRequest) { final Function<String, String> requestUri = (host) -> String.format(REQUEST_GROUPS_UPDATE_FORMAT, getApiBase(host), requestId); final HttpResponse response = post(requestUri, String.format("update authorized groups of request %s", requestId), Optional.of(updateGroupsRequest)); return response.getAs(SingularityPendingRequestParent.class); }
@Override public List<MesosTaskMonitorObject> getSlaveResourceUsage(String hostname, boolean useShortTimeout) { final String uri = String.format(MESOS_SLAVE_STATISTICS_URL, hostname); HttpResponse response = getFromMesos(uri, useShortTimeout); 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); } }
private <T> T getFromMesos(String uri, Class<T> clazz, boolean useShortTimeout) { HttpResponse response = getFromMesos(uri, useShortTimeout); try { return response.getAs(clazz); } catch (Exception e) { throw new MesosClientException(String.format("Couldn't deserialize %s from %s", clazz.getSimpleName(), uri), e); } }
public SingularityRequestParent updateIncrementalDeployInstanceCount(SingularityUpdatePendingDeployRequest updateRequest) { final Function<String, String> requestUri = (host) -> String.format(UPDATE_DEPLOY_FORMAT, getApiBase(host)); HttpResponse response = post(requestUri, String.format("update deploy %s", new SingularityDeployKey(updateRequest.getRequestId(), updateRequest.getDeployId())), Optional.of(updateRequest)); return getAndLogRequestAndDeployStatus(response.getAs(SingularityRequestParent.class)); }