Skip to content

Commit 1ad6faa

Browse files
committed
[grid] Allowing a path on the host & container to be configurable [skip ci]
When we run inside a container, we need to know where to save the assets inside it, which is not the same path we have on the host. The user will mount the host path to the container path, so for the user the assets will end up on the same path on their host machine.
1 parent 59285ab commit 1ad6faa

File tree

4 files changed

+104
-20
lines changed

4 files changed

+104
-20
lines changed

java/server/src/org/openqa/selenium/grid/docker/DockerFlags.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,24 @@ public class DockerFlags implements HasRoles {
6868

6969
@Parameter(
7070
names = {"--docker-assets-path"},
71-
description = "Absolute path where videos will be stored"
71+
description = "Absolute path where assets will be stored"
7272
)
7373
@ConfigValue(section = "docker", name = "assets-path", example = "\"/absolute/path/to/assets/path\"")
7474
private String assetsPath;
7575

76+
@Parameter(
77+
names = {"--docker-container-assets-path"},
78+
description = "Absolute path where assets inside the container will be stored. Use it when " +
79+
"running inside a Docker container.",
80+
hidden = true
81+
)
82+
@ConfigValue(
83+
section = "docker",
84+
name = "container-assets-path",
85+
example = "\"/absolute/path/to/container/assets/path\""
86+
)
87+
private String containerAssetsPath;
88+
7689
@Override
7790
public Set<Role> getRoles() {
7891
return Collections.singleton(NODE_ROLE);

java/server/src/org/openqa/selenium/grid/docker/DockerOptions.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,18 @@ private Image getVideoImage(Docker docker) {
180180
return videoImage.map(docker::getImage).orElse(null);
181181
}
182182

183-
private String getAssetsPath() {
184-
return config.get(DOCKER_SECTION, "assets-path").orElse("");
183+
private DockerSessionAssetsPath getAssetsPath() {
184+
Optional<String> hostAssetsPath = config.get(DOCKER_SECTION, "assets-path");
185+
Optional<String> containerAssetsPath = config.get(DOCKER_SECTION, "container-assets-path");
186+
if (hostAssetsPath.isPresent() && containerAssetsPath.isPresent()) {
187+
return new DockerSessionAssetsPath(hostAssetsPath.get(), containerAssetsPath.get());
188+
} else if (hostAssetsPath.isPresent()) {
189+
// If only the host assets path is present, we assume this is not running inside a container.
190+
return new DockerSessionAssetsPath(hostAssetsPath.get(), hostAssetsPath.get());
191+
}
192+
// We should not reach this point because the invocation to this method is
193+
// guarded by `isVideoRecordingAvailable()`
194+
return null;
185195
}
186196

187197
private void loadImages(Docker docker, String... imageNames) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.docker;
19+
20+
import org.openqa.selenium.remote.SessionId;
21+
22+
import java.io.IOException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.util.Optional;
27+
import java.util.logging.Level;
28+
import java.util.logging.Logger;
29+
30+
public class DockerSessionAssetsPath {
31+
32+
private static final Logger LOG = Logger.getLogger(DockerSessionAssetsPath.class.getName());
33+
34+
private final String hostAssetsPath;
35+
private final String containerAssetsPath;
36+
37+
public DockerSessionAssetsPath(String hostAssetsPath, String containerAssetsPath) {
38+
this.hostAssetsPath = hostAssetsPath;
39+
this.containerAssetsPath = containerAssetsPath;
40+
}
41+
42+
public Optional<Path> createHostSessionAssetsPath(SessionId id) {
43+
return createSessionAssetsPath(this.hostAssetsPath, id);
44+
}
45+
46+
public Optional<Path> createContainerSessionAssetsPath(SessionId id) {
47+
return createSessionAssetsPath(this.containerAssetsPath, id);
48+
}
49+
50+
private Optional<Path> createSessionAssetsPath(String assetsPath, SessionId id) {
51+
if (assetsPath == null || assetsPath.isEmpty()) {
52+
return Optional.empty();
53+
}
54+
try {
55+
return Optional.of(Files.createDirectories(Paths.get(assetsPath, id.toString())));
56+
} catch (IOException e) {
57+
LOG.log(Level.WARNING,
58+
"Failed to create path to store session assets, no assets will be stored: " +
59+
assetsPath, e);
60+
}
61+
return Optional.empty();
62+
}
63+
}

java/server/src/org/openqa/selenium/grid/docker/DockerSessionFactory.java

+15-17
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public class DockerSessionFactory implements SessionFactory {
9191
private final Capabilities stereotype;
9292
private boolean isVideoRecordingAvailable;
9393
private Image videoImage;
94-
private String assetsPath;
94+
private DockerSessionAssetsPath assetsPath;
9595

9696
public DockerSessionFactory(
9797
Tracer tracer,
@@ -110,8 +110,15 @@ public DockerSessionFactory(
110110
this.isVideoRecordingAvailable = false;
111111
}
112112

113-
public DockerSessionFactory(Tracer tracer, HttpClient.Factory clientFactory, Docker docker, URI dockerUri,
114-
Image browserImage, Capabilities stereotype, Image videoImage, String assetsPath) {
113+
public DockerSessionFactory(
114+
Tracer tracer,
115+
HttpClient.Factory clientFactory,
116+
Docker docker,
117+
URI dockerUri,
118+
Image browserImage,
119+
Capabilities stereotype,
120+
Image videoImage,
121+
DockerSessionAssetsPath assetsPath) {
115122
this(tracer, clientFactory, docker, dockerUri, browserImage, stereotype);
116123
this.isVideoRecordingAvailable = true;
117124
this.videoImage = videoImage;
@@ -201,16 +208,17 @@ public Optional<ActiveSession> apply(CreateSessionRequest sessionRequest) {
201208

202209
SessionId id = new SessionId(response.getSessionId());
203210
Capabilities capabilities = new ImmutableCapabilities((Map<?, ?>) response.getValue());
204-
Optional<Path> sessionAssetsPath = createSessionAssetsPath(assetsPath, id);
205-
sessionAssetsPath.ifPresent(path -> saveSessionCapabilities(capabilities, path));
211+
Optional<Path> containerAssetsPath = assetsPath.createContainerSessionAssetsPath(id);
212+
containerAssetsPath.ifPresent(path -> saveSessionCapabilities(capabilities, path));
206213
Container videoContainer = null;
207214
if (isVideoRecordingAvailable && recordVideoForSession(capabilities)) {
208215
Map<String, String> envVars = getVideoContainerEnvVars(
209216
capabilities,
210217
containerInfo.getIp());
211-
if (sessionAssetsPath.isPresent()) {
218+
Optional<Path> hostAssetsPath = assetsPath.createHostSessionAssetsPath(id);
219+
if (hostAssetsPath.isPresent()) {
212220
Map<String, String> volumeBinds =
213-
Collections.singletonMap(sessionAssetsPath.get().toString(), "/videos");
221+
Collections.singletonMap(hostAssetsPath.get().toString(), "/videos");
214222
videoContainer = docker.create(image(videoImage).env(envVars).bind(volumeBinds));
215223
videoContainer.start();
216224
LOG.info(String.format("Video container started (id: %s)", videoContainer.getId()));
@@ -320,16 +328,6 @@ private Object getCapability(Capabilities sessionRequestCapabilities, String cap
320328
return null;
321329
}
322330

323-
private Optional<Path> createSessionAssetsPath(String assetsPath, SessionId id) {
324-
try {
325-
return Optional.of(Files.createDirectories(Paths.get(assetsPath, id.toString())));
326-
} catch (IOException e) {
327-
LOG.log(Level.WARNING,
328-
"Failed to create path to store session assets, no assets will be stored", e);
329-
}
330-
return Optional.empty();
331-
}
332-
333331
private void saveSessionCapabilities(Capabilities sessionRequestCapabilities, Path assetsPath) {
334332
String capsToJson = new Json().toJson(sessionRequestCapabilities);
335333
try {

0 commit comments

Comments
 (0)