Skip to content

Commit

Permalink
[grid] Add k8s compatible /readyz readiness check to all servers
Browse files Browse the repository at this point in the history
This returns a status code appropriate for use in a k8s deployment.
  • Loading branch information
shs96c committed Jun 1, 2020
1 parent 82b6b12 commit 7f4b8c8
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 26 deletions.
6 changes: 5 additions & 1 deletion java/server/src/org/openqa/selenium/grid/commands/Hub.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.openqa.selenium.grid.sessionmap.local.LocalSessionMap;
import org.openqa.selenium.grid.web.CombinedHandler;
import org.openqa.selenium.grid.web.RoutableHttpClientFactory;
import org.openqa.selenium.grid.web.StatusBasedReadinessCheck;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpHandler;
Expand All @@ -52,6 +53,7 @@
import java.util.logging.Logger;

import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.remote.http.HttpMethod.GET;
import static org.openqa.selenium.remote.http.Route.combine;

@AutoService(CliCommand.class)
Expand Down Expand Up @@ -127,11 +129,13 @@ protected void execute(Config config) {

Router router = new Router(tracer, clientFactory, sessions, distributor);
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri().toString());
StatusBasedReadinessCheck readinessCheck = new StatusBasedReadinessCheck(router, GET, "/status");

HttpHandler httpHandler = combine(
router,
Route.prefix("/wd/hub").to(combine(router)),
Route.post("/graphql").to(() -> graphqlHandler));
Route.post("/graphql").to(() -> graphqlHandler),
Route.get("/readyz").to(() -> readinessCheck));

Server<?> server = new NettyServer(serverOptions, httpHandler, new ProxyCdpIntoGrid(clientFactory, sessions));
server.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.EVENT_BUS_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.json.Json.JSON_UTF_8;
Expand Down Expand Up @@ -101,24 +102,26 @@ protected void execute(Config config) {

Server<?> server = new NettyServer(
serverOptions,
Route.get("/status").to(() -> req -> {
CountDownLatch latch = new CountDownLatch(1);

Type healthCheck = new Type("healthcheck");
bus.addListener(healthCheck, event -> latch.countDown());
bus.fire(new Event(healthCheck, "ping"));

try {
if (latch.await(5, TimeUnit.SECONDS)) {
return httpResponse(true, "Event bus running");
} else {
return httpResponse(false, "Event bus could not deliver a test message in 5 seconds");
Route.combine(
Route.get("/status").to(() -> req -> {
CountDownLatch latch = new CountDownLatch(1);

Type healthCheck = new Type("healthcheck");
bus.addListener(healthCheck, event -> latch.countDown());
bus.fire(new Event(healthCheck, "ping"));

try {
if (latch.await(5, TimeUnit.SECONDS)) {
return httpResponse(true, "Event bus running");
} else {
return httpResponse(false, "Event bus could not deliver a test message in 5 seconds");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return httpResponse(false, "Status checking was interrupted");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return httpResponse(false, "Status checking was interrupted");
}
})
}),
Route.get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT)))
);
server.start();

Expand All @@ -134,7 +137,8 @@ private HttpResponse httpResponse(boolean ready, String message) {
return new HttpResponse()
.addHeader("Content-Type", JSON_UTF_8)
.setContent(asJson(ImmutableMap.of(
"value", ImmutableMap.of(
"ready", ready,
"message", message)));
"message", message))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
import org.openqa.selenium.grid.sessionmap.local.LocalSessionMap;
import org.openqa.selenium.grid.web.CombinedHandler;
import org.openqa.selenium.grid.web.RoutableHttpClientFactory;
import org.openqa.selenium.grid.web.StatusBasedReadinessCheck;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.net.NetworkUtils;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.HttpClient;
Expand All @@ -61,12 +63,14 @@

import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.NODE_ROLE;
import static org.openqa.selenium.remote.http.HttpMethod.GET;
import static org.openqa.selenium.remote.http.Route.combine;

@AutoService(CliCommand.class)
public class Standalone extends TemplateGridCommand {

private static final Logger LOG = Logger.getLogger("selenium");
private static final Json JSON = new Json();

@Override
public String getName() {
Expand Down Expand Up @@ -136,13 +140,15 @@ protected void execute(Config config) {
Distributor distributor = new LocalDistributor(tracer, bus, clientFactory, sessions, null);
combinedHandler.addHandler(distributor);
Router router = new Router(tracer, clientFactory, sessions, distributor);
StatusBasedReadinessCheck readinessCheck = new StatusBasedReadinessCheck(router, GET, "/status");

BaseServerOptions serverOptions = new BaseServerOptions(config);
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri().toString());
HttpHandler httpHandler = combine(
router,
Route.prefix("/wd/hub").to(combine(router)),
Route.post("/graphql").to(() -> graphqlHandler));
Route.post("/graphql").to(() -> graphqlHandler),
Route.get("/readyz").to(() -> readinessCheck));

LocalNode.Builder nodeBuilder = LocalNode.builder(
tracer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ java_library(
"//java/server/src/org/openqa/selenium/events",
"//java/server/src/org/openqa/selenium/grid:base-command",
"//java/server/src/org/openqa/selenium/grid/config",
"//java/server/src/org/openqa/selenium/grid/data",
"//java/server/src/org/openqa/selenium/grid/distributor",
"//java/server/src/org/openqa/selenium/grid/distributor/local",
"//java/server/src/org/openqa/selenium/grid/log",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.MediaType;
import org.openqa.selenium.BuildInfo;
import org.openqa.selenium.cli.CliCommand;
import org.openqa.selenium.events.EventBus;
import org.openqa.selenium.grid.TemplateGridCommand;
import org.openqa.selenium.grid.config.Config;
import org.openqa.selenium.grid.config.Role;
import org.openqa.selenium.grid.data.DistributorStatus;
import org.openqa.selenium.grid.distributor.Distributor;
import org.openqa.selenium.grid.distributor.local.LocalDistributor;
import org.openqa.selenium.grid.log.LoggingOptions;
Expand All @@ -38,6 +40,7 @@
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.Contents;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpHandler;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
import org.openqa.selenium.remote.tracing.Tracer;
Expand All @@ -46,10 +49,13 @@
import java.util.Set;
import java.util.logging.Logger;

import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.EVENT_BUS_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.SESSION_MAP_ROLE;
import static org.openqa.selenium.remote.http.HttpMethod.GET;
import static org.openqa.selenium.remote.http.Route.get;

@AutoService(CliCommand.class)
public class DistributorServer extends TemplateGridCommand {
Expand Down Expand Up @@ -107,6 +113,16 @@ protected void execute(Config config) {
clientFactory,
sessions,
serverOptions.getRegistrationSecret());
HttpHandler readinessCheck = req -> {
DistributorStatus status = distributor.getStatus();
if (status.hasCapacity()) {
return new HttpResponse().setStatus(HTTP_NO_CONTENT);
}
return new HttpResponse()
.setStatus(HTTP_INTERNAL_ERROR)
.setHeader("Content-Type", MediaType.PLAIN_TEXT_UTF_8.toString())
.setContent(Contents.utf8String("No capacity available"));
};

Route handler = Route.combine(
distributor,
Expand All @@ -115,7 +131,8 @@ protected void execute(Config config) {
.setContent(Contents.asJson(
ImmutableMap.of("value", ImmutableMap.of(
"ready", true,
"message", "Distributor is ready"))))));
"message", "Distributor is ready"))))),
get("/readyz").to(() -> readinessCheck));

Server<?> server = new NettyServer(serverOptions, handler);
server.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.MediaType;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;
import org.openqa.selenium.BuildInfo;
Expand All @@ -39,7 +40,11 @@
import org.openqa.selenium.grid.server.NetworkOptions;
import org.openqa.selenium.grid.server.Server;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.Contents;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpHandler;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
import org.openqa.selenium.remote.tracing.Tracer;

import java.time.Duration;
Expand All @@ -50,10 +55,13 @@
import java.util.concurrent.Executors;
import java.util.logging.Logger;

import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.EVENT_BUS_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.NODE_ROLE;
import static org.openqa.selenium.grid.data.NodeAddedEvent.NODE_ADDED;
import static org.openqa.selenium.remote.http.Route.get;

@AutoService(CliCommand.class)
public class NodeServer extends TemplateGridCommand {
Expand Down Expand Up @@ -119,14 +127,28 @@ protected void execute(Config config) {

LocalNode node = builder.build();

HttpHandler readinessCheck = req -> {
if (node.getStatus().hasCapacity()) {
return new HttpResponse().setStatus(HTTP_NO_CONTENT);
}

return new HttpResponse()
.setStatus(HTTP_INTERNAL_ERROR)
.setHeader("Content-Type", MediaType.PLAIN_TEXT_UTF_8.toString())
.setContent(Contents.utf8String("No capacity available"));
};

bus.addListener(NODE_ADDED, event -> {
UUID nodeId = event.getData(UUID.class);
if (node.getId().equals(nodeId)) {
LOG.info("Node has been added");
}
});
Route httpHandler = Route.combine(
node,
get("/readyz").to(() -> readinessCheck));

Server<?> server = new NettyServer(serverOptions, node, new ProxyNodeCdp(clientFactory, node));
Server<?> server = new NettyServer(serverOptions, httpHandler, new ProxyNodeCdp(clientFactory, node));
server.start();

BuildInfo info = new BuildInfo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,19 @@
import org.openqa.selenium.grid.sessionmap.config.SessionMapOptions;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
import org.openqa.selenium.remote.tracing.Tracer;

import java.util.Collections;
import java.util.Set;
import java.util.logging.Logger;

import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.DISTRIBUTOR_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.SESSION_MAP_ROLE;
import static org.openqa.selenium.remote.http.Route.get;

@AutoService(CliCommand.class)
public class RouterServer extends TemplateGridCommand {
Expand Down Expand Up @@ -105,7 +108,8 @@ protected void execute(Config config) {

Route handler = Route.combine(
new Router(tracer, clientFactory, sessions, distributor),
Route.post("/graphql").to(() -> graphqlHandler));
Route.post("/graphql").to(() -> graphqlHandler),
get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT)));

Server<?> server = new NettyServer(serverOptions, handler, new ProxyCdpIntoGrid(clientFactory, sessions));
server.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.Set;
import java.util.logging.Logger;

import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.EVENT_BUS_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.json.Json.JSON_UTF_8;
Expand Down Expand Up @@ -91,9 +92,10 @@ protected void execute(Config config) {
new HttpResponse()
.addHeader("Content-Type", JSON_UTF_8)
.setContent(asJson(
ImmutableMap.of("value", ImmutableMap.of(
"ready", true,
"message", "Session map is ready.")))))));
ImmutableMap.of("value", ImmutableMap.of(
"ready", true,
"message", "Session map is ready."))))),
get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT))));
server.start();

BuildInfo info = new BuildInfo();
Expand Down
Loading

0 comments on commit 7f4b8c8

Please sign in to comment.