diff options
author | Martin Polden <mpolden@mpolden.no> | 2022-02-10 13:02:56 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2022-02-10 13:09:30 +0100 |
commit | 42fe732584876b156fc936f718dabf87af018220 (patch) | |
tree | 0bb74302d7f8b90beeaccf53b9e1173ea5195b38 /routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java | |
parent | 0b284f194c0b2dc9b1f8b36b489911f32961d840 (diff) |
Import routing-generator
Diffstat (limited to 'routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java')
-rw-r--r-- | routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java b/routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java new file mode 100644 index 00000000000..fdfd0f71e96 --- /dev/null +++ b/routing-generator/src/main/java/com/yahoo/vespa/hosted/routing/nginx/NginxHealthClient.java @@ -0,0 +1,104 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.routing.nginx; + +import com.yahoo.component.AbstractComponent; +import com.yahoo.component.annotation.Inject; +import com.yahoo.lang.CachedSupplier; +import com.yahoo.slime.ArrayTraverser; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Slime; +import com.yahoo.slime.SlimeUtils; +import com.yahoo.vespa.hosted.routing.status.HealthStatus; +import com.yahoo.vespa.hosted.routing.status.ServerGroup; +import com.yahoo.yolean.Exceptions; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Client for the Nginx upstream health status page served at /health-status. + * + * @author oyving + * @author mpolden + */ +public class NginxHealthClient extends AbstractComponent implements HealthStatus { + + private static final URI healthStatusUrl = URI.create("http://localhost:4080/health-status/?format=json"); + private static final Duration requestTimeout = Duration.ofSeconds(5); + private static final Duration cacheTtl = Duration.ofSeconds(5); + + private final CloseableHttpClient httpClient; + private final CachedSupplier<ServerGroup> cache = new CachedSupplier<>(this::getStatus, cacheTtl); + + @Inject + public NginxHealthClient() { + this( + HttpClientBuilder.create() + .setDefaultRequestConfig(RequestConfig.custom() + .setConnectTimeout((int) requestTimeout.toMillis()) + .setConnectionRequestTimeout((int) requestTimeout.toMillis()) + .setSocketTimeout((int) requestTimeout.toMillis()) + .build()) + .build() + ); + } + + NginxHealthClient(CloseableHttpClient client) { + this.httpClient = Objects.requireNonNull(client); + } + + @Override + public ServerGroup servers() { + return cache.get(); + } + + private ServerGroup getStatus() { + HttpGet httpGet = new HttpGet(healthStatusUrl); + try (CloseableHttpResponse response = httpClient.execute(httpGet)) { + String entity = Exceptions.uncheck(() -> EntityUtils.toString(response.getEntity())); + if (response.getStatusLine().getStatusCode() / 100 != 2) { + throw new IllegalArgumentException("Got status code " + response.getStatusLine().getStatusCode() + + " for URL " + healthStatusUrl + ", with response: " + entity); + } + return parseStatus(entity); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static ServerGroup parseStatus(String json) { + Slime slime = SlimeUtils.jsonToSlime(json); + Cursor root = slime.get(); + List<ServerGroup.Server> servers = new ArrayList<>(); + Cursor serversObject = root.field("servers"); + + Cursor streamArray = serversObject.field("stream"); + Cursor serverArray = serversObject.field("server"); // TODO(mpolden): Remove after 2022-03-01 + Cursor array = streamArray.valid() ? streamArray : serverArray; + + array.traverse((ArrayTraverser) (idx, inspector) -> { + String upstreamName = inspector.field("upstream").asString(); + String hostPort = inspector.field("name").asString(); + boolean up = "up".equals(inspector.field("status").asString()); + servers.add(new ServerGroup.Server(upstreamName, hostPort, up)); + }); + return new ServerGroup(servers); + } + + @Override + public void deconstruct() { + Exceptions.uncheck(httpClient::close); + } + +} |