Skip to content

Commit

Permalink
[grid] Clean up configuration.
Browse files Browse the repository at this point in the history
* Nodes must use `--detect-drivers` to autodetect drivers
* Standalone can prevent the default behaviour by setting
  the flag to `false`
* Docker output is a little less chatty now.
  • Loading branch information
shs96c committed Mar 19, 2019
1 parent 75a7b00 commit ce9100d
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 109 deletions.
18 changes: 11 additions & 7 deletions java/server/src/org/openqa/selenium/docker/Docker.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Logger;
Expand Down Expand Up @@ -83,6 +84,8 @@ public Image pull(String name, String tag) {
Objects.requireNonNull(name);
Objects.requireNonNull(tag);

findImage(new ImageNamePredicate(name, tag));

LOG.info(String.format("Pulling %s:%s", name, tag));

HttpRequest request = new HttpRequest(POST, "/images/create");
Expand All @@ -91,13 +94,15 @@ public Image pull(String name, String tag) {

client.apply(request);

LOG.info("Pull complete");
LOG.info(String.format("Pull of %s:%s complete", name, tag));

return findImage(new ImageNamePredicate(name, tag));
return findImage(new ImageNamePredicate(name, tag))
.orElseThrow(() -> new DockerException(
String.format("Cannot find image matching: %s:%s", name, tag)));
}

public List<Image> listImages() {
LOG.info("Listing images");
LOG.fine("Listing images");
HttpResponse response = client.apply(new HttpRequest(GET, "/images/json"));

List<ImageSummary> images =
Expand All @@ -108,15 +113,14 @@ public List<Image> listImages() {
.collect(toImmutableList());
}

public Image findImage(Predicate<Image> filter) {
public Optional<Image> findImage(Predicate<Image> filter) {
Objects.requireNonNull(filter);

LOG.info("Finding image: " + filter);
LOG.fine("Finding image: " + filter);

return listImages().stream()
.filter(filter)
.findFirst()
.orElseThrow(() -> new DockerException("Cannot find image matching: " + filter));
.findFirst();
}

public Container create(ContainerInfo info) {
Expand Down
3 changes: 2 additions & 1 deletion java/server/src/org/openqa/selenium/grid/commands/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ java_library(
"//java/server/src/org/openqa/selenium/grid/config:config",
"//java/server/src/org/openqa/selenium/grid/distributor:distributor",
"//java/server/src/org/openqa/selenium/grid/distributor/local:local",
"//java/server/src/org/openqa/selenium/grid/docker:docker",
"//java/server/src/org/openqa/selenium/grid/node:node",
"//java/server/src/org/openqa/selenium/grid/node/local:local",
"//java/server/src/org/openqa/selenium/grid/node/config:config",
"//java/server/src/org/openqa/selenium/grid/router:router",
"//java/server/src/org/openqa/selenium/grid/sessionmap:sessionmap",
"//java/server/src/org/openqa/selenium/grid/sessionmap/local:local",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class DefaultStandaloneConfig extends MapConfig {
"events", ImmutableMap.of(
"publish", "inproc://standalone-pub",
"subscribe", "inproc://standalone-sub",
"bind", true),
"node", ImmutableMap.of(
"detect-drivers", true)));
"bind", true)));
// "node", ImmutableMap.of(
// "detect-drivers", true)));
}

}
4 changes: 0 additions & 4 deletions java/server/src/org/openqa/selenium/grid/commands/Hub.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.openqa.selenium.grid.distributor.Distributor;
import org.openqa.selenium.grid.distributor.local.LocalDistributor;
import org.openqa.selenium.grid.log.LoggingOptions;
import org.openqa.selenium.grid.node.local.NodeFlags;
import org.openqa.selenium.grid.router.Router;
import org.openqa.selenium.grid.server.BaseServer;
import org.openqa.selenium.grid.server.BaseServerFlags;
Expand Down Expand Up @@ -69,14 +68,12 @@ public Executable configure(String... args) {
HelpFlags help = new HelpFlags();
BaseServerFlags baseFlags = new BaseServerFlags(4444);
EventBusFlags eventBusFlags = new EventBusFlags();
NodeFlags nodeFlags = new NodeFlags();

JCommander commander = JCommander.newBuilder()
.programName("standalone")
.addObject(baseFlags)
.addObject(eventBusFlags)
.addObject(help)
.addObject(nodeFlags)
.build();

return () -> {
Expand All @@ -97,7 +94,6 @@ public Executable configure(String... args) {
new ConcatenatingConfig("selenium", '.', System.getProperties()),
new AnnotatedConfig(help),
new AnnotatedConfig(eventBusFlags),
new AnnotatedConfig(nodeFlags),
new AnnotatedConfig(baseFlags),
new DefaultHubConfig());

Expand Down
19 changes: 13 additions & 6 deletions java/server/src/org/openqa/selenium/grid/commands/Standalone.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@
import org.openqa.selenium.grid.config.EnvConfig;
import org.openqa.selenium.grid.distributor.Distributor;
import org.openqa.selenium.grid.distributor.local.LocalDistributor;
import org.openqa.selenium.grid.docker.DockerFlags;
import org.openqa.selenium.grid.docker.DockerOptions;
import org.openqa.selenium.grid.log.LoggingOptions;
import org.openqa.selenium.grid.node.Node;
import org.openqa.selenium.grid.node.config.NodeOptions;
import org.openqa.selenium.grid.node.local.LocalNode;
import org.openqa.selenium.grid.node.local.NodeFlags;
import org.openqa.selenium.grid.router.Router;
import org.openqa.selenium.grid.web.RoutableHttpClientFactory;
import org.openqa.selenium.grid.server.BaseServer;
import org.openqa.selenium.grid.server.BaseServerFlags;
import org.openqa.selenium.grid.server.BaseServerOptions;
Expand All @@ -49,6 +50,7 @@
import org.openqa.selenium.grid.sessionmap.SessionMap;
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.Routes;
import org.openqa.selenium.net.NetworkUtils;
import org.openqa.selenium.remote.http.HttpClient;
Expand Down Expand Up @@ -77,14 +79,16 @@ public Executable configure(String... args) {
HelpFlags help = new HelpFlags();
BaseServerFlags baseFlags = new BaseServerFlags(4444);
EventBusFlags eventFlags = new EventBusFlags();
NodeFlags nodeFlags = new NodeFlags();
DockerFlags dockerFlags = new DockerFlags();
StandaloneFlags standaloneFlags = new StandaloneFlags();

JCommander commander = JCommander.newBuilder()
.programName("standalone")
.addObject(baseFlags)
.addObject(help)
.addObject(eventFlags)
.addObject(nodeFlags)
.addObject(dockerFlags)
.addObject(standaloneFlags)
.build();

return () -> {
Expand All @@ -105,7 +109,8 @@ public Executable configure(String... args) {
new ConcatenatingConfig("selenium", '.', System.getProperties()),
new AnnotatedConfig(help),
new AnnotatedConfig(baseFlags),
new AnnotatedConfig(nodeFlags),
new AnnotatedConfig(dockerFlags),
new AnnotatedConfig(standaloneFlags),
new AnnotatedConfig(eventFlags),
new DefaultStandaloneConfig());

Expand Down Expand Up @@ -154,7 +159,9 @@ public Executable configure(String... args) {
clientFactory,
localhost)
.maximumConcurrentSessions(Runtime.getRuntime().availableProcessors() * 3);
nodeFlags.configure(config, clientFactory, nodeBuilder);

new NodeOptions(config).configure(clientFactory, nodeBuilder);
new DockerOptions(config).configure(clientFactory, nodeBuilder);

Node node = nodeBuilder.build();
combinedHandler.addHandler(node);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.openqa.selenium.grid.commands;

import com.beust.jcommander.Parameter;

import org.openqa.selenium.grid.config.ConfigValue;

public class StandaloneFlags {

@Parameter(
names = {"--detect-drivers"},
description = "Autodetect which drivers are available on the current system, and add them to the node.",
arity = 1)
@ConfigValue(section = "node", name = "detect-drivers")
public boolean autoconfigure = true;

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.openqa.selenium.grid.config;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

public class MapConfig implements Config {
Expand All @@ -30,6 +31,9 @@ public MapConfig(Map<String, Object> raw) {

@Override
public Optional<String> get(String section, String option) {
Objects.requireNonNull(section, "Section name not set");
Objects.requireNonNull(option, "Option name not set");

Object rawSection = raw.get(section);
if (!(rawSection instanceof Map)) {
return Optional.empty();
Expand Down
2 changes: 2 additions & 0 deletions java/server/src/org/openqa/selenium/grid/docker/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ java_library(
"//java/server/src/org/openqa/selenium/grid/node/local:local",
"//java/server/src/org/openqa/selenium/grid/web:web",
"//third_party/java/beust:jcommander",
"//third_party/java/guava:guava",
],
visibility = [
"//java/server/src/org/openqa/selenium/grid/commands/...",
"//java/server/src/org/openqa/selenium/grid/node/...",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ public class DockerFlags {

@Parameter(
names = {"--docker"},
description = "Whether docker integration is enabled",
arity = 1)
description = "Whether docker integration is enabled")
@ConfigValue(section = "docker", name = "enabled")
private boolean isEnabled = true;
private boolean isEnabled;

public DockerFlags() {
try {
Expand Down
87 changes: 52 additions & 35 deletions java/server/src/org/openqa/selenium/grid/docker/DockerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@
import static java.util.logging.Level.WARNING;
import static org.openqa.selenium.remote.http.HttpMethod.GET;

import com.google.common.collect.ImmutableMap;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.docker.Docker;
import org.openqa.selenium.docker.DockerException;
import org.openqa.selenium.docker.Image;
import org.openqa.selenium.docker.ImageNamePredicate;
import org.openqa.selenium.grid.config.Config;
Expand All @@ -36,11 +40,10 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import java.util.stream.Collectors;

public class DockerOptions {

Expand Down Expand Up @@ -79,53 +82,67 @@ public boolean isEnabled(HttpClient.Factory clientFactory) {

return true;
} catch (IOException e) {
LOG.log(WARNING, "Unable to ping docker daemon: " + e.getMessage(), e);
LOG.log(WARNING, "Unable to ping docker daemon. Docker disabled: " + e.getMessage());
return false;
}
}

public void configure(HttpClient.Factory clientFactory, LocalNode.Builder node)
throws IOException {
if (!isEnabled(clientFactory)) {
return;
}

HttpClient client = clientFactory.createClient(new URL("http://localhost:2375"));
Docker docker = new Docker(client);

loadImages(
docker,
"selenium/standalone-firefox:3.141.59",
"selenium/standalone-chrome:3.141.59");
ImmutableMap<String, Capabilities> kinds = ImmutableMap.of(
"selenium/standalone-firefox:3.141.59", new ImmutableCapabilities("browserName", "firefox"),
"selenium/standalone-chrome:3.141.59", new ImmutableCapabilities("browserName", "chrome"));

Image firefox = docker.findImage(new ImageNamePredicate("selenium/standalone-firefox:3.141.59"));
for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
node.add(new ImmutableCapabilities("browserName", "firefox"),
new DockerSessionFactory(clientFactory, docker, firefox));
}
loadImages(docker, kinds.keySet().toArray(new String[0]));

Image chrome = docker.findImage(new ImageNamePredicate("selenium/standalone-chrome:3.141.59"));
for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
node.add(new ImmutableCapabilities("browserName", "chrome"),
new DockerSessionFactory(clientFactory, docker, chrome));
}
int maxContainerCount = Runtime.getRuntime().availableProcessors();
kinds.forEach((name, caps) -> {
Image image = docker.findImage(new ImageNamePredicate(name))
.orElseThrow(() -> new DockerException(
String.format("Cannot find image matching: %s", name)));
for (int i = 0; i < maxContainerCount; i++) {
node.add(caps, new DockerSessionFactory(clientFactory, docker, image));
}
LOG.info(String.format(
"Mapping %s to docker image %s %d times",
caps,
name,
maxContainerCount));
});
}

private void loadImages(Docker docker, String... imageNames) {
List<CompletableFuture<Image>> allFutures = Arrays.stream(imageNames)
.map(entry -> {
int index = entry.lastIndexOf(':');
if (index == -1) {
throw new RuntimeException("Unable to determine tag from " + entry);
}
String name = entry.substring(0, index);
String version = entry.substring(index + 1);

return CompletableFuture.supplyAsync(() -> docker.pull(name, version));
})
.collect(Collectors.toList());

CompletableFuture<Void>
cd =
CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0]));
cd.whenComplete((ignored, throwable) -> {
CompletableFuture<Void> cd = CompletableFuture.allOf(
Arrays.stream(imageNames)
.map(entry -> {
int index = entry.lastIndexOf(':');
if (index == -1) {
throw new RuntimeException("Unable to determine tag from " + entry);
}
String name = entry.substring(0, index);
String version = entry.substring(index + 1);

return CompletableFuture.supplyAsync(() -> docker.pull(name, version));
}).toArray(CompletableFuture[]::new));

});
try {
cd.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
} catch (ExecutionException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
throw new RuntimeException(cause);
}
}
}
17 changes: 17 additions & 0 deletions java/server/src/org/openqa/selenium/grid/node/config/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
java_library(
name = "config",
srcs = glob(["*.java"]),
exported_deps = [
"//java/client/src/org/openqa/selenium/remote:remote",
"//java/server/src/org/openqa/selenium/grid/node/local:local"
],
deps = [
"//java/server/src/org/openqa/selenium/grid/config:config",
"//java/server/src/org/openqa/selenium/grid/data:data",
"//java/server/src/org/openqa/selenium/grid/web:web",
"//third_party/java/beust:jcommander",
],
visibility = [
"//java/server/src/org/openqa/selenium/grid/...",
],
)

0 comments on commit ce9100d

Please sign in to comment.