Skip to content

Commit

Permalink
[grid][java] browser containers provisioned in dynamic grid can get h…
Browse files Browse the repository at this point in the history
…ostconfig from node-docker (SeleniumHQ#13804)

* [grid][java] browser containers provisioned in dynamic grid uses node-docker hostConfig

Signed-off-by: Viet Nguyen Duc <[email protected]>

* update code as suggestions

Signed-off-by: Viet Nguyen Duc <[email protected]>

---------

Signed-off-by: Viet Nguyen Duc <[email protected]>
  • Loading branch information
VietND96 authored Apr 12, 2024
1 parent 61f507f commit 6d7e7da
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 5 deletions.
42 changes: 42 additions & 0 deletions java/src/org/openqa/selenium/docker/ContainerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -42,6 +43,7 @@ public class ContainerConfig {
private final String networkName;
private final boolean autoRemove;
private final long shmSize;
private final Map<String, Object> hostConfig;

public ContainerConfig(
Image image,
Expand All @@ -51,6 +53,26 @@ public ContainerConfig(
List<Device> devices,
String networkName,
long shmSize) {
this(
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
ImmutableMap.of());
}

public ContainerConfig(
Image image,
Multimap<String, Map<String, Object>> portBindings,
Map<String, String> envVars,
Map<String, String> volumeBinds,
List<Device> devices,
String networkName,
long shmSize,
Map<String, Object> hostConfig) {
this.image = image;
this.portBindings = portBindings;
this.envVars = envVars;
Expand All @@ -59,6 +81,7 @@ public ContainerConfig(
this.networkName = networkName;
this.autoRemove = true;
this.shmSize = shmSize;
this.hostConfig = hostConfig;
}

public static ContainerConfig image(Image image) {
Expand Down Expand Up @@ -123,6 +146,17 @@ public ContainerConfig devices(List<Device> devices) {
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
}

public ContainerConfig applyHostConfig(Map<String, Object> hostConfig, List<String> configKeys) {
Map<String, Object> setHostConfig =
configKeys.stream()
.filter(hostConfig::containsKey)
.filter(key -> hostConfig.get(key) != null)
.collect(Collectors.toMap(key -> key, hostConfig::get));

return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize, setHostConfig);
}

@Override
public String toString() {
return "ContainerConfig{"
Expand All @@ -142,6 +176,8 @@ public String toString() {
+ autoRemove
+ ", shmSize="
+ shmSize
+ ", hostConfig="
+ hostConfig
+ '}';
}

Expand Down Expand Up @@ -175,6 +211,12 @@ private Map<String, Object> toJson() {
"Binds", volumeBinds,
"Devices", devicesMapping);

if (!this.hostConfig.isEmpty()) {
Map<String, Object> copyMap = new HashMap<>(hostConfig);
copyMap.putAll(this.hostConfig);
hostConfig = ImmutableMap.copyOf(copyMap);
}

return ImmutableMap.of(
"Image", image.getId(),
"Env", envVars,
Expand Down
12 changes: 11 additions & 1 deletion java/src/org/openqa/selenium/docker/ContainerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ public class ContainerInfo {
private final ContainerId id;
private final List<Map<String, Object>> mountedVolumes;
private final String networkName;
private Map<String, Object> hostConfig;

public ContainerInfo(
ContainerId id, String ip, List<Map<String, Object>> mountedVolumes, String networkName) {
ContainerId id,
String ip,
List<Map<String, Object>> mountedVolumes,
String networkName,
Map<String, Object> hostConfig) {
this.ip = Require.nonNull("Container ip address", ip);
this.id = Require.nonNull("Container id", id);
this.mountedVolumes = Require.nonNull("Mounted volumes", mountedVolumes);
this.networkName = Require.nonNull("Network name", networkName);
this.hostConfig = Require.nonNull("Host config", hostConfig);
}

public String getIp() {
Expand All @@ -54,6 +60,10 @@ public String getNetworkName() {
return networkName;
}

public Map<String, Object> getHostConfig() {
return this.hostConfig;
}

@Override
public String toString() {
return "ContainerInfo{"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.openqa.selenium.remote.http.HttpMethod.GET;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
Expand Down Expand Up @@ -67,7 +68,9 @@ public ContainerInfo apply(ContainerId id) {
ArrayList<Object> mounts = (ArrayList<Object>) rawInspectInfo.get("Mounts");
List<Map<String, Object>> mountedVolumes =
mounts.stream().map(mount -> (Map<String, Object>) mount).collect(Collectors.toList());
Map<String, Object> hostConfig =
(Map<String, Object>) rawInspectInfo.getOrDefault("HostConfig", Collections.emptyMap());

return new ContainerInfo(id, ip, mountedVolumes, networkName);
return new ContainerInfo(id, ip, mountedVolumes, networkName, hostConfig);
}
}
12 changes: 12 additions & 0 deletions java/src/org/openqa/selenium/grid/node/docker/DockerFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ public class DockerFlags implements HasRoles {
"[\"selenium/standalone-firefox:latest\", \"{\\\"browserName\\\": \\\"firefox\\\"}\"]")
private List<String> images2Capabilities;

@Parameter(
names = {"--docker-host-config-keys"},
description =
"Specify which docker host configuration keys should be passed to browser containers."
+ " Keys name can be found in the Docker API documentation, or by running `docker"
+ " inspect` the node-docker container.")
@ConfigValue(
section = DockerOptions.DOCKER_SECTION,
name = "host-config-keys",
example = "[\"Dns\", \"DnsOptions\", \"DnsSearch\", \"ExtraHosts\", \"Binds\"]")
private List<String> hostConfigKeys;

@Parameter(
names = {"--docker-devices"},
description =
Expand Down
13 changes: 12 additions & 1 deletion java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(
.getAll(DOCKER_SECTION, "configs")
.orElseThrow(() -> new DockerException("Unable to find docker configs"));

List<String> hostConfigKeys =
config.getAll(DOCKER_SECTION, "host-config-keys").orElseGet(Collections::emptyList);

Multimap<String, Capabilities> kinds = HashMultimap.create();
for (int i = 0; i < allConfigs.size(); i++) {
String imageName = allConfigs.get(i);
Expand All @@ -152,6 +155,7 @@ public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(

DockerAssetsPath assetsPath = getAssetsPath(info);
String networkName = getDockerNetworkName(info);
Map<String, Object> hostConfig = getDockerHostConfig(info);

loadImages(docker, kinds.keySet().toArray(new String[0]));
Image videoImage = getVideoImage(docker);
Expand Down Expand Up @@ -182,7 +186,9 @@ public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(
assetsPath,
networkName,
info.isPresent(),
capabilities -> options.getSlotMatcher().matches(caps, capabilities)));
capabilities -> options.getSlotMatcher().matches(caps, capabilities),
hostConfig,
hostConfigKeys));
}
LOG.info(
String.format(
Expand Down Expand Up @@ -229,6 +235,11 @@ private String getDockerNetworkName(Optional<ContainerInfo> info) {
return DEFAULT_DOCKER_NETWORK;
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Map<String, Object> getDockerHostConfig(Optional<ContainerInfo> info) {
return info.map(ContainerInfo::getHostConfig).orElse(Collections.emptyMap());
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private DockerAssetsPath getAssetsPath(Optional<ContainerInfo> info) {
if (info.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public class DockerSessionFactory implements SessionFactory {
private final String networkName;
private final boolean runningInDocker;
private final Predicate<Capabilities> predicate;
private final Map<String, Object> hostConfig;
private final List<String> hostConfigKeys;

public DockerSessionFactory(
Tracer tracer,
Expand All @@ -115,7 +117,9 @@ public DockerSessionFactory(
DockerAssetsPath assetsPath,
String networkName,
boolean runningInDocker,
Predicate<Capabilities> predicate) {
Predicate<Capabilities> predicate,
Map<String, Object> hostConfig,
List<String> hostConfigKeys) {
this.tracer = Require.nonNull("Tracer", tracer);
this.clientFactory = Require.nonNull("HTTP client", clientFactory);
this.sessionTimeout = Require.nonNull("Session timeout", sessionTimeout);
Expand All @@ -129,6 +133,8 @@ public DockerSessionFactory(
this.assetsPath = assetsPath;
this.runningInDocker = runningInDocker;
this.predicate = Require.nonNull("Accepted capabilities predicate", predicate);
this.hostConfig = Require.nonNull("Container host config", hostConfig);
this.hostConfigKeys = Require.nonNull("Browser container host config keys", hostConfigKeys);
}

@Override
Expand Down Expand Up @@ -285,10 +291,12 @@ private Container createBrowserContainer(int port, Capabilities sessionCapabilit
.env(browserContainerEnvVars)
.shmMemorySize(browserContainerShmMemorySize)
.network(networkName)
.devices(devices);
.devices(devices)
.applyHostConfig(hostConfig, hostConfigKeys);
if (!runningInDocker) {
containerConfig = containerConfig.map(Port.tcp(4444), Port.tcp(port));
}
LOG.fine("Container config: " + containerConfig);
return docker.create(containerConfig);
}

Expand Down

0 comments on commit 6d7e7da

Please sign in to comment.