Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 163 additions & 11 deletions java/src/org/openqa/selenium/docker/ContainerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class ContainerConfig {
private final boolean autoRemove;
private final long shmSize;
private final Map<String, Object> hostConfig;
private final Map<String, String> labels;
private final String name;

public ContainerConfig(
Image image,
Expand All @@ -61,6 +63,7 @@ public ContainerConfig(
devices,
networkName,
shmSize,
ImmutableMap.of(),
ImmutableMap.of());
}

Expand All @@ -73,6 +76,52 @@ public ContainerConfig(
String networkName,
long shmSize,
Map<String, Object> hostConfig) {
this(
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
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,
Map<String, String> labels) {
this(
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
null);
}

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,
Map<String, String> labels,
String name) {
this.image = image;
this.portBindings = portBindings;
this.envVars = envVars;
Expand All @@ -82,6 +131,12 @@ public ContainerConfig(
this.autoRemove = true;
this.shmSize = shmSize;
this.hostConfig = hostConfig;
this.labels = labels;
this.name = name;
}

public String getName() {
return this.name;
}

public Image getImage() {
Expand Down Expand Up @@ -114,40 +169,94 @@ public ContainerConfig map(Port containerPort, Port hostPort) {
ImmutableMap.of("HostPort", String.valueOf(hostPort.getPort()), "HostIp", ""));

return new ContainerConfig(
image, updatedBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
updatedBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig env(Map<String, String> envVars) {
Require.nonNull("Container env vars", envVars);

return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig bind(Map<String, String> volumeBinds) {
Require.nonNull("Container volume binds", volumeBinds);

return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig network(String networkName) {
Require.nonNull("Container network name", networkName);

return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig shmMemorySize(long shmSize) {
return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig devices(List<Device> devices) {
Require.nonNull("Container device files", devices);

return new ContainerConfig(
image, portBindings, envVars, volumeBinds, devices, networkName, shmSize);
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig applyHostConfig(Map<String, Object> hostConfig, List<String> configKeys) {
Expand All @@ -158,7 +267,46 @@ public ContainerConfig applyHostConfig(Map<String, Object> hostConfig, List<Stri
.collect(Collectors.toMap(key -> key, hostConfig::get));

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

public ContainerConfig labels(Map<String, String> labels) {
Require.nonNull("Container labels", labels);

return new ContainerConfig(
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

public ContainerConfig name(String name) {
return new ContainerConfig(
image,
portBindings,
envVars,
volumeBinds,
devices,
networkName,
shmSize,
hostConfig,
labels,
name);
}

@Override
Expand Down Expand Up @@ -221,9 +369,13 @@ private Map<String, Object> toJson() {
hostConfig = ImmutableMap.copyOf(copyMap);
}

return ImmutableMap.of(
"Image", image.getId(),
"Env", envVars,
"HostConfig", hostConfig);
Map<String, Object> config = new HashMap<>();
config.put("Image", image.getId());
config.put("Env", envVars);
config.put("HostConfig", hostConfig);
if (!labels.isEmpty()) {
config.put("Labels", labels);
}
return config;
}
}
16 changes: 16 additions & 0 deletions java/src/org/openqa/selenium/docker/ContainerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,30 @@ public class ContainerInfo {
private final List<Map<String, Object>> mountedVolumes;
private final String networkName;
private Map<String, Object> hostConfig;
private Map<String, String> labels;

public ContainerInfo(
ContainerId id,
String ip,
List<Map<String, Object>> mountedVolumes,
String networkName,
Map<String, Object> hostConfig) {
this(id, ip, mountedVolumes, networkName, hostConfig, Map.of());
}

public ContainerInfo(
ContainerId id,
String ip,
List<Map<String, Object>> mountedVolumes,
String networkName,
Map<String, Object> hostConfig,
Map<String, String> labels) {
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);
this.labels = Require.nonNull("Labels", labels);
}

public String getIp() {
Expand All @@ -64,6 +76,10 @@ public Map<String, Object> getHostConfig() {
return this.hostConfig;
}

public Map<String, String> getLabels() {
return this.labels;
}

@Override
public String toString() {
return "ContainerInfo{"
Expand Down
17 changes: 16 additions & 1 deletion java/src/org/openqa/selenium/docker/client/CreateContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import static org.openqa.selenium.remote.http.Contents.asJson;
import static org.openqa.selenium.remote.http.HttpMethod.POST;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Logger;
Expand Down Expand Up @@ -62,10 +65,22 @@ public Container apply(ContainerConfig info) {
Map<String, Object> requestJson = JSON.toType(JSON.toJson(info), MAP_TYPE);
Map<String, Object> adaptedRequest = adapter.adaptContainerCreateRequest(requestJson);

// Build the URL with optional name parameter
String url = String.format("/v%s/containers/create", apiVersion);
if (info.getName() != null && !info.getName().trim().isEmpty()) {
String containerName = info.getName().trim();
try {
String encodedName = URLEncoder.encode(containerName, StandardCharsets.UTF_8.toString());
url += "?name=" + encodedName;
} catch (UnsupportedEncodingException e) {
throw new DockerException("Failed to encode container name: " + containerName, e);
}
}

HttpResponse res =
DockerMessages.throwIfNecessary(
client.execute(
new HttpRequest(POST, String.format("/v%s/containers/create", apiVersion))
new HttpRequest(POST, url)
.addHeader("Content-Type", JSON_UTF_8)
.setContent(asJson(adaptedRequest))),
"Unable to create container: ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ public ContainerInfo apply(ContainerId id) {
mounts.stream().map(mount -> (Map<String, Object>) mount).collect(Collectors.toList());
Map<String, Object> hostConfig =
(Map<String, Object>) rawInspectInfo.getOrDefault("HostConfig", Collections.emptyMap());
Map<String, Object> config =
(Map<String, Object>) rawInspectInfo.getOrDefault("Config", Collections.emptyMap());
Map<String, String> labels =
(Map<String, String>) config.getOrDefault("Labels", Collections.emptyMap());

return new ContainerInfo(id, ip, mountedVolumes, networkName, hostConfig);
return new ContainerInfo(id, ip, mountedVolumes, networkName, hostConfig, labels);
}
}
18 changes: 17 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 @@ -38,6 +38,7 @@
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Platform;
import org.openqa.selenium.docker.ContainerId;
Expand Down Expand Up @@ -173,6 +174,7 @@ public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(
DockerAssetsPath assetsPath = getAssetsPath(info);
String networkName = getDockerNetworkName(info);
Map<String, Object> hostConfig = getDockerHostConfig(info);
Map<String, String> composeLabels = getComposeLabels(info);

loadImages(docker, kinds.keySet().toArray(new String[0]));
Image videoImage = getVideoImage(docker);
Expand Down Expand Up @@ -208,7 +210,8 @@ public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(
info.isPresent(),
capabilities -> options.getSlotMatcher().matches(caps, capabilities),
hostConfig,
hostConfigKeys));
hostConfigKeys,
composeLabels));
}
LOG.info(
String.format(
Expand Down Expand Up @@ -257,6 +260,19 @@ private Map<String, Object> getDockerHostConfig(Optional<ContainerInfo> info) {
return info.map(ContainerInfo::getHostConfig).orElse(Collections.emptyMap());
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Map<String, String> getComposeLabels(Optional<ContainerInfo> info) {
if (info.isEmpty()) {
return Collections.emptyMap();
}

Map<String, String> allLabels = info.get().getLabels();
// Filter for Docker Compose labels (com.docker.compose.*)
return allLabels.entrySet().stream()
.filter(entry -> entry.getKey().startsWith("com.docker.compose."))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private DockerAssetsPath getAssetsPath(Optional<ContainerInfo> info) {
if (info.isPresent()) {
Expand Down
Loading
Loading