diff --git a/pom.xml b/pom.xml index 09c42666a..91dde9aae 100644 --- a/pom.xml +++ b/pom.xml @@ -168,6 +168,26 @@ + + pl.project13.maven + git-commit-id-plugin + 5.0.0 + + + + revision + + + + + true + ${project.build.outputDirectory}/git.properties + + git.commit.id.abbrev + git.commit.id + + + org.apache.maven.plugins maven-javadoc-plugin diff --git a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java index 233325750..02000e85e 100644 --- a/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java +++ b/src/main/java/org/gaul/s3proxy/S3ProxyHandler.java @@ -41,6 +41,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Properties; import java.util.Set; import java.util.SortedMap; import java.util.TimeZone; @@ -58,6 +59,7 @@ import javax.xml.stream.XMLStreamWriter; import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.google.common.base.CharMatcher; import com.google.common.base.Splitter; @@ -293,6 +295,13 @@ public final void doHandle(HttpServletRequest baseRequest, String uri = request.getRequestURI(); String originalUri = request.getRequestURI(); + String healthzUri = servicePath.isEmpty() ? "/healthz" : + servicePath + "/healthz"; + if (healthzUri.equals(uri) && "GET".equalsIgnoreCase(method)) { + handleStatuszRequest(response); + return; + } + if (!this.servicePath.isEmpty()) { if (uri.length() > this.servicePath.length()) { uri = uri.substring(this.servicePath.length()); @@ -2030,6 +2039,55 @@ private void handlePutBlob(HttpServletRequest request, response.addHeader(HttpHeaders.ETAG, maybeQuoteETag(eTag)); } + private void handleStatuszRequest(HttpServletResponse response) + throws IOException { + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("application/json"); + response.setCharacterEncoding(UTF_8); + + var statusBody = ImmutableMap.of("gitHash", StatusMetadata.INSTANCE.gitHash); + String versionInfo = StatusMetadata.JSON_MAPPER.writeValueAsString(statusBody); + + try (PrintWriter writer = response.getWriter()) { + writer.write(versionInfo); + writer.flush(); + } + } + + private static final class StatusMetadata { + private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); + private static final StatusMetadata INSTANCE = StatusMetadata.load(); + private static final String UNKNOWN_VALUE = "unknown"; + private final String gitHash; + + private StatusMetadata(String gitHash) { + this.gitHash = gitHash; + } + + static StatusMetadata load() { + String gitHash = loadGitHash(); + return new StatusMetadata(gitHash); + } + + private static String loadGitHash() { + try (InputStream stream = S3ProxyHandler.class.getClassLoader() + .getResourceAsStream("git.properties")) { + if (stream == null) { + return UNKNOWN_VALUE; + } + Properties properties = new Properties(); + properties.load(stream); + return Optional.ofNullable( + properties.getProperty("git.commit.id.abbrev")) + .orElseGet(() -> properties.getProperty("git.commit.id", + UNKNOWN_VALUE)); + } catch (IOException ioe) { + logger.debug("Unable to load git.properties", ioe); + return UNKNOWN_VALUE; + } + } + } + private void handlePostBlob(HttpServletRequest request, HttpServletResponse response, InputStream is, BlobStore blobStore, String containerName) diff --git a/src/test/java/org/gaul/s3proxy/AwsSdkAnonymousTest.java b/src/test/java/org/gaul/s3proxy/AwsSdkAnonymousTest.java index ad260ca3e..d65f1ced4 100644 --- a/src/test/java/org/gaul/s3proxy/AwsSdkAnonymousTest.java +++ b/src/test/java/org/gaul/s3proxy/AwsSdkAnonymousTest.java @@ -19,7 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.Random; import com.amazonaws.SDKGlobalConfiguration; @@ -50,6 +52,7 @@ public final class AwsSdkAnonymousTest { private static final ByteSource BYTE_SOURCE = ByteSource.wrap(new byte[1]); private URI s3Endpoint; + private URI httpEndpoint; private EndpointConfiguration s3EndpointConfig; private S3Proxy s3Proxy; private BlobStoreContext context; @@ -66,6 +69,7 @@ public void setUp() throws Exception { awsCreds = new AnonymousAWSCredentials(); context = info.getBlobStore().getContext(); s3Proxy = info.getS3Proxy(); + httpEndpoint = info.getEndpoint(); s3Endpoint = info.getSecureEndpoint(); servicePath = info.getServicePath(); s3EndpointConfig = new EndpointConfiguration( @@ -128,6 +132,31 @@ public void testAwsV4SignatureChunkedAnonymous() throws Exception { } } + @Test + public void testHealthzEndpoint() throws Exception { + URI baseUri = httpEndpoint != null ? httpEndpoint : s3Endpoint; + String path = (servicePath == null ? "" : servicePath) + "/healthz"; + URI healthzUri = new URI(baseUri.getScheme(), baseUri.getUserInfo(), + baseUri.getHost(), baseUri.getPort(), path, + baseUri.getQuery(), baseUri.getFragment()); + + HttpURLConnection connection = + (HttpURLConnection) healthzUri.toURL().openConnection(); + connection.setRequestMethod("GET"); + + assertThat(connection.getResponseCode()).isEqualTo(200); + + String body; + try (InputStream stream = connection.getInputStream()) { + body = new String(stream.readAllBytes(), StandardCharsets.UTF_8); + } finally { + connection.disconnect(); + } + + assertThat(body).contains("\"gitHash\":\""); + assertThat(body).startsWith("{").endsWith("}"); + } + private static String createRandomContainerName() { return "s3proxy-" + new Random().nextInt(Integer.MAX_VALUE); }