feat(cf): increase logging for cf to better detect fails
MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryApiException.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryApiException.java
@@ -25,18 +25,24 @@ import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.Getter;
+import retrofit.RetrofitError;
@Getter
public class CloudFoundryApiException extends RuntimeException {
- private static final String UNKNOWN_ERROR = "Unknown Error";
@Nullable private ErrorDescription.Code errorCode;
- public CloudFoundryApiException(ErrorDescription errorCause) {
+ public CloudFoundryApiException(ErrorDescription errorCause, RetrofitError retrofitError) {
super(
Optional.ofNullable(errorCause)
.map(e -> getMessage(e.getErrors().toArray(new String[0])))
- .orElse(UNKNOWN_ERROR));
+ .orElse(
+ "status: "
+ + retrofitError.getResponse().getStatus()
+ + ". url: "
+ + retrofitError.getResponse().getUrl()
+ + ". raw response body: "
+ + retrofitError.getResponse().getBody()));
if (errorCause != null) {
this.errorCode = errorCause.getCode();
}

MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryClientUtils.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryClientUtils.java
@@ -33,7 +33,7 @@ final class CloudFoundryClientUtils {
} catch (RetrofitError retrofitError) {
if (retrofitError.getResponse() == null || retrofitError.getResponse().getStatus() != 404) {
throw new CloudFoundryApiException(
- (ErrorDescription) retrofitError.getBodyAs(ErrorDescription.class));
+ (ErrorDescription) retrofitError.getBodyAs(ErrorDescription.class), retrofitError);
}
}
}
@@ -52,7 +52,7 @@ final class CloudFoundryClientUtils {
if (errorDescription == null) {
throw new CloudFoundryApiException(retrofitError.getCause());
}
- throw new CloudFoundryApiException(errorDescription);
+ throw new CloudFoundryApiException(errorDescription, retrofitError);
}
}
}

MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/HttpCloudFoundryClient.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/HttpCloudFoundryClient.java
@@ -21,17 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ApplicationService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.AuthenticationService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ConfigService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.DomainService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.DopplerService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.OrganizationService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.RouteService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ServiceInstanceService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ServiceKeyService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.SpaceService;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.TaskService;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.*;
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.Token;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
@@ -63,6 +53,8 @@ import okio.Buffer;
import okio.BufferedSource;
import org.apache.commons.fileupload.MultipartStream;
import org.cloudfoundry.dropsonde.events.EventFactory.Envelope;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;
import retrofit.client.OkClient;
@@ -99,6 +91,8 @@ public class HttpCloudFoundryClient implements CloudFoundryClient {
private Tasks tasks;
private Logs logs;
+ Logger logger = LoggerFactory.getLogger(HttpCloudFoundryClient.class);
+
private final RequestInterceptor oauthInterceptor =
new RequestInterceptor() {
@Override
@@ -127,7 +121,7 @@ public class HttpCloudFoundryClient implements CloudFoundryClient {
.intervalFunction(IntervalFunction.ofExponentialBackoff(Duration.ofSeconds(10), 3))
.retryExceptions(RetryableApiException.class)
.build());
-
+ logger.debug("cf request: " + chain.request().urlString());
AtomicReference<Response> lastResponse = new AtomicReference<>();
try {
return retry.executeCallable(

MODIFY
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryApiExceptionTest.java
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/CloudFoundryApiExceptionTest.java
package com.netflix.spinnaker.clouddriver.cloudfoundry.client;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.ErrorDescription;
import java.util.Arrays;
+import java.util.Collections;
import org.junit.jupiter.api.Test;
+import retrofit.RetrofitError;
+import retrofit.client.Response;
class CloudFoundryApiExceptionTest {
@Test
void constructorWithErrorDescription() {
+ Response response = new Response("url", 500, "reason", Collections.emptyList(), null);
+ RetrofitError retrofitError = mock(RetrofitError.class);
+ when(retrofitError.getResponse()).thenReturn(response);
CloudFoundryApiException e =
new CloudFoundryApiException(
new ErrorDescription()
.setErrors(
Arrays.asList(
new ErrorDescription.Detail().setDetail("Main Error"),
- new ErrorDescription.Detail().setDetail("Foo"))));
+ new ErrorDescription.Detail().setDetail("Foo"))),
+ retrofitError);
assertThat(e.getMessage()).contains("Main Error and Foo");
}
@Test
void constructorHandlesNullErrorDescription() {
- CloudFoundryApiException e = new CloudFoundryApiException((ErrorDescription) null);
+ Response response = new Response("url", 500, "reason", Collections.emptyList(), null);
+ RetrofitError retrofitError = mock(RetrofitError.class);
+ when(retrofitError.getResponse()).thenReturn(response);
+ CloudFoundryApiException e =
+ new CloudFoundryApiException((ErrorDescription) null, retrofitError);
- assertThat(e.getMessage()).contains("Unknown Error");
+ assertThat(e.getMessage()).contains("status: 500. url: url. raw response body: null");
}
}

feat(cf): increase logging for cf to better detect fails (#4156)