Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.github.bonigarcia.wdm.docker.DockerService Maven / Gradle / Ivy
/*
* (C) Copyright 2021 Boni Garcia (https://bonigarcia.github.io/)
*
* Licensed 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 io.github.bonigarcia.wdm.docker;
import static io.github.bonigarcia.wdm.WebDriverManager.isDockerAvailable;
import static io.github.bonigarcia.wdm.config.Config.isNullOrEmpty;
import static io.github.bonigarcia.wdm.docker.DockerHost.defaultAddress;
import static io.github.bonigarcia.wdm.versions.Shell.runAndWait;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.lang.invoke.MethodHandles.lookup;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Locale.ROOT;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.SystemUtils.IS_OS_LINUX;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback.Adapter;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Capability;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Mount;
import com.github.dockerjava.api.model.PortBinding;
import com.github.dockerjava.api.model.Ports;
import com.github.dockerjava.api.model.Ports.Binding;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.api.model.TmpfsOptions;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient.Builder;
import io.github.bonigarcia.wdm.cache.ResolutionCache;
import io.github.bonigarcia.wdm.config.Config;
import io.github.bonigarcia.wdm.config.DriverManagerType;
import io.github.bonigarcia.wdm.config.WebDriverManagerException;
import io.github.bonigarcia.wdm.docker.DockerContainer.DockerBuilder;
import io.github.bonigarcia.wdm.docker.DockerHubTags.DockerHubTag;
import io.github.bonigarcia.wdm.online.HttpClient;
import io.github.bonigarcia.wdm.versions.VersionComparator;
/**
* Docker Service.
*
* @author Boni Garcia
* @since 5.0.0
*/
public class DockerService {
final Logger log = getLogger(lookup().lookupClass());
public static final String NETWORK_HOST = "host";
private static final String DEFAULT_GATEWAY = "172.17.0.1";
private static final String BETA = "beta";
private static final String DEV = "dev";
private static final String LATEST_MINUS = "latest-";
private static final String RECORDING_EXT = ".mp4";
private static final String SEPARATOR = "_";
private static final String DATE_FORMAT = "yyyy.MM.dd_HH.mm.ss.SSS";
private static final int POLL_TIME_MSEC = 500;
private Config config;
private HttpClient httpClient;
private DockerClient dockerClient;
private ResolutionCache resolutionCache;
private URI dockerHostUri;
public DockerService(Config config, HttpClient httpClient,
ResolutionCache resolutionCache) {
this.config = config;
this.httpClient = httpClient;
this.resolutionCache = resolutionCache;
if (config.isDockerLocalFallback() && !isRunningInsideDocker()
&& !isDockerAvailable()) {
log.warn(
"Docker is not available in your machine... local browsers are used instead");
} else {
this.dockerClient = createDockerClient();
}
}
private DockerClient createDockerClient() {
String dockerDaemonUrl = config.getDockerDaemonUrl();
String dockerHost = isNullOrEmpty(dockerDaemonUrl)
? DockerHost.fromEnv().endpoint()
: dockerDaemonUrl;
return getDockerClient(dockerHost);
}
private DockerClient getDockerClient(String dockerHost) {
DefaultDockerClientConfig.Builder dockerClientConfigBuilder = DefaultDockerClientConfig
.createDefaultConfigBuilder();
if (!isNullOrEmpty(dockerHost)) {
dockerClientConfigBuilder.withDockerHost(dockerHost);
}
DockerClientConfig dockerClientConfig = dockerClientConfigBuilder
.build();
dockerHostUri = dockerClientConfig.getDockerHost();
ApacheDockerHttpClient dockerHttpClient = new Builder()
.dockerHost(dockerHostUri).build();
return DockerClientBuilder.getInstance(dockerClientConfig)
.withDockerHttpClient(dockerHttpClient).build();
}
public String getHost(String containerId, String network) {
String host = getDefaultHost();
if (IS_OS_LINUX && isRunningInsideDocker()) {
host = getGateway(containerId, network);
log.debug(
"WebDriverManager running inside a Docker container. Using gateway address: {}",
host);
}
return host;
}
public boolean isRunningInsideDocker() {
String[] commandArray = new String[] { "bash", "-c",
"cat /proc/self/cgroup | grep docker" };
String commandOutput = runAndWait(false, commandArray);
return !isNullOrEmpty(commandOutput);
}
public String getDefaultHost() {
return Optional.ofNullable(dockerHostUri.getHost())
.orElse(defaultAddress());
}
public String getGateway(String containerId, String network) {
String gateway = dockerClient.inspectContainerCmd(containerId).exec()
.getNetworkSettings().getNetworks().get(network).getGateway();
if (isNullOrEmpty(gateway)) {
return DEFAULT_GATEWAY;
}
return gateway;
}
public String getAddress(String containerId, String network) {
return dockerClient.inspectContainerCmd(containerId).exec()
.getNetworkSettings().getNetworks().get(network).getIpAddress();
}
public synchronized String startContainer(DockerContainer dockerContainer)
throws DockerException {
String imageId = dockerContainer.getImageId();
log.info("Starting Docker container {}", imageId);
HostConfig hostConfigBuilder = new HostConfig();
String containerId;
try (CreateContainerCmd containerConfigBuilder = dockerClient
.createContainerCmd(imageId)) {
boolean privileged = dockerContainer.isPrivileged();
if (privileged) {
log.trace("Using privileged mode");
hostConfigBuilder.withPrivileged(true);
}
if (dockerContainer.isSysadmin()) {
log.trace("Adding sysadmin capability");
hostConfigBuilder.withCapAdd(Capability.SYS_ADMIN);
}
Optional shmSize = dockerContainer.getShmSize();
if (shmSize.isPresent()) {
log.trace("Using shm size: {}", shmSize.get());
hostConfigBuilder.withShmSize(shmSize.get());
}
Optional network = dockerContainer.getNetwork();
if (network.isPresent()) {
log.trace("Using network: {}", network.get());
hostConfigBuilder.withNetworkMode(network.get());
}
List exposedPorts = dockerContainer.getExposedPorts();
if (!exposedPorts.isEmpty()) {
log.trace("Using exposed ports: {}", exposedPorts);
containerConfigBuilder.withExposedPorts(exposedPorts.stream()
.map(ExposedPort::parse).collect(Collectors.toList()));
hostConfigBuilder.withPortBindings(exposedPorts.stream()
.map(PortBinding::parse).collect(Collectors.toList()));
hostConfigBuilder.withPublishAllPorts(true);
}
Optional> binds = dockerContainer.getBinds();
if (binds.isPresent()) {
log.trace("Using binds: {}", binds.get());
hostConfigBuilder.withBinds(binds.get());
}
Optional> mounts = dockerContainer.getMounts();
if (mounts.isPresent()) {
log.trace("Using mounts: {}", mounts.get());
hostConfigBuilder.withMounts(mounts.get());
}
Optional> envs = dockerContainer.getEnvs();
if (envs.isPresent()) {
log.trace("Using envs: {}", envs.get());
containerConfigBuilder
.withEnv(envs.get().toArray(new String[] {}));
}
Optional> cmd = dockerContainer.getCmd();
if (cmd.isPresent()) {
log.trace("Using cmd: {}", cmd.get());
containerConfigBuilder
.withCmd(cmd.get().toArray(new String[] {}));
}
Optional> entryPoint = dockerContainer.getEntryPoint();
if (entryPoint.isPresent()) {
log.trace("Using entryPoint: {}", entryPoint.get());
containerConfigBuilder.withEntrypoint(
entryPoint.get().toArray(new String[] {}));
}
hostConfigBuilder.withExtraHosts(dockerContainer.getExtraHosts());
containerId = containerConfigBuilder
.withHostConfig(hostConfigBuilder).exec().getId();
dockerClient.startContainerCmd(containerId).exec();
}
return containerId;
}
public String execCommandInContainer(String containerId,
String... command) {
String commandStr = Arrays.toString(command);
log.trace("Running command {} in container {}", commandStr,
containerId);
String execId = dockerClient.execCreateCmd(containerId).withCmd(command)
.withAttachStdout(true).withAttachStderr(true).exec().getId();
final StringBuilder output = new StringBuilder();
try {
dockerClient.execStartCmd(execId).exec(new Adapter () {
@Override
public void onNext(Frame object) {
output.append(new String(object.getPayload(), UTF_8));
super.onNext(object);
}
}).awaitCompletion();
} catch (InterruptedException e) {
log.error("Exception execution command {} on container {}",
commandStr, containerId, e);
Thread.currentThread().interrupt();
}
log.trace("Result of command {} in container {}: {}", commandStr,
containerId, output);
return output.toString();
}
public String getBindPort(String containerId, String exposed)
throws DockerException {
String bindPort = null;
int waitTimeoutSec = config.getTimeout();
long timeoutMs = System.currentTimeMillis()
+ Duration.ofSeconds(waitTimeoutSec).toMillis();
do {
Ports ports = dockerClient.inspectContainerCmd(containerId).exec()
.getNetworkSettings().getPorts();
Binding[] exposedPort = ports.getBindings()
.get(ExposedPort.parse(exposed));
log.trace("Port list {} -- Exposed port {} = {}", ports, exposed,
exposedPort);
if (ports.getBindings() == null || exposedPort == null
|| ports.getBindings().isEmpty()
|| exposedPort.length == 0) {
String dockerImage = dockerClient
.inspectContainerCmd(containerId).exec().getConfig()
.getImage();
if (currentTimeMillis() > timeoutMs) {
throw new WebDriverManagerException("Timeout of "
+ waitTimeoutSec
+ " getting bind port in container " + dockerImage);
} else {
try {
log.trace("Port {} is not bindable in container {}",
exposed, dockerImage);
Thread.sleep(POLL_TIME_MSEC);
} catch (InterruptedException e) {
log.warn("Interrupted exception getting bind port", e);
Thread.currentThread().interrupt();
}
}
} else {
bindPort = exposedPort[0].getHostPortSpec();
}
} while (bindPort == null);
return bindPort;
}
public void pullImageIfNecessary(String cacheKey, String imageId,
String imageVersion) throws DockerException {
if (!config.getDockerAvoidPulling()
&& !resolutionCache.checkKeyInResolutionCache(cacheKey)) {
try {
log.info(
"Pulling Docker image {} (this might take some time, but only the first time)",
imageId);
dockerClient.pullImageCmd(imageId)
.exec(new Adapter() {
}).awaitCompletion();
log.trace("Docker image {} pulled", imageId);
if (!config.isAvoidResolutionCache()) {
resolutionCache.putValueInResolutionCacheIfEmpty(cacheKey,
imageVersion, config.getTtlForBrowsers());
}
} catch (Exception e) {
log.warn("Exception pulling image {}: {}", imageId,
e.getMessage());
}
}
}
public synchronized void stopAndRemoveContainer(
DockerContainer dockerContainer) {
String containerId = dockerContainer.getContainerId();
String imageId = dockerContainer.getImageId();
log.info("Stopping Docker container {}", imageId);
try {
stopContainer(containerId);
removeContainer(containerId);
} catch (Exception e) {
log.warn("Exception stopping container {}", imageId, e);
}
}
public synchronized void stopContainer(String containerId)
throws DockerException {
int stopTimeoutSec = config.getDockerStopTimeoutSec();
if (stopTimeoutSec == 0) {
log.trace("Killing container {}", containerId);
dockerClient.killContainerCmd(containerId).exec();
} else {
log.trace("Stopping container {} (timeout {} seconds)", containerId,
stopTimeoutSec);
dockerClient.stopContainerCmd(containerId)
.withTimeout(stopTimeoutSec).exec();
}
}
public synchronized void removeContainer(String containerId)
throws DockerException {
log.trace("Removing container {}", containerId);
int stopTimeoutSec = config.getDockerStopTimeoutSec();
if (stopTimeoutSec == 0) {
dockerClient.removeContainerCmd(containerId).withForce(true).exec();
} else {
dockerClient.removeContainerCmd(containerId).exec();
}
}
public void close() throws IOException {
dockerClient.close();
}
public void updateDockerClient(String dockerHost) {
log.debug("Updating Docker client using {}", dockerHost);
dockerClient = getDockerClient(dockerHost);
}
public String getImageVersionFromDockerHub(
DriverManagerType driverManagerType, String cacheKey,
String browserName, String browserVersion, boolean androidEnabled) {
String latestVersion = null;
if (!resolutionCache.checkKeyInResolutionCache(cacheKey, false)) {
VersionComparator versionComparator = new VersionComparator();
List browserList = null;
DockerHubService dockerHubService = new DockerHubService(config,
httpClient);
List dockerHubTags;
String tagPreffix = browserName + SEPARATOR;
int minusIndex = getMinusIndex(browserVersion);
String dockerBrowserImageFormat = config
.getDockerBrowserSelenoidImageFormat();
switch (driverManagerType) {
case CHROME:
case FIREFOX:
if (androidEnabled) {
dockerBrowserImageFormat = String.format(
config.getDockerBrowserMobileImageFormat(),
browserName, "");
}
dockerHubTags = dockerHubService
.listTags(dockerBrowserImageFormat);
if (androidEnabled) {
browserList = dockerHubTags.stream()
.map(DockerHubTag::getName)
.sorted(versionComparator::compare)
.collect(toList());
} else {
browserList = dockerHubTags.stream()
.filter(p -> p.getName().startsWith(tagPreffix))
.map(p -> p.getName().replace(tagPreffix, ""))
.sorted(versionComparator::compare)
.collect(toList());
}
latestVersion = browserList
.get(browserList.size() - 1 - minusIndex);
break;
case OPERA:
dockerHubTags = dockerHubService
.listTags(dockerBrowserImageFormat);
browserList = dockerHubTags.stream()
.filter(p -> p.getName().startsWith(tagPreffix))
.map(p -> p.getName().replace(tagPreffix, ""))
.sorted(versionComparator::compare).skip(1)
.collect(toList());
latestVersion = browserList
.get(browserList.size() - 1 - minusIndex);
break;
case EDGE:
case SAFARI:
String dockerBrowserAerokubeImageFormat = String.format(
config.getDockerBrowserAerokubeImageFormat(),
browserName, "");
dockerHubTags = dockerHubService
.listTags(dockerBrowserAerokubeImageFormat);
browserList = dockerHubTags.stream().map(DockerHubTag::getName)
.sorted(versionComparator::compare).collect(toList());
latestVersion = browserList
.get(browserList.size() - 1 - minusIndex);
break;
default:
throw new WebDriverManagerException(
driverManagerType.getBrowserName()
+ " is not available as Docker container");
}
if (minusIndex == 0) {
log.debug("The latest version of {} in Docker Hub is {}",
driverManagerType.getBrowserName(), latestVersion);
} else {
log.debug("The version-{} of {} in Docker Hub is {}",
minusIndex, driverManagerType.getBrowserName(),
latestVersion);
}
} else {
latestVersion = resolutionCache
.getValueFromResolutionCache(cacheKey);
}
return latestVersion;
}
public int getMinusIndex(String browserVersion) {
int minusIndex = 0;
if (isBrowserVersionLatestMinus(browserVersion)) {
minusIndex = Integer.parseInt(browserVersion
.substring(browserVersion.indexOf(LATEST_MINUS)
+ LATEST_MINUS.length()));
}
return minusIndex;
}
public String getDockerImage(String browserName, String browserVersion,
boolean androidEnabled) {
String dockerImageFormat;
String dockerImage;
switch (browserName) {
case "edge":
case "safari":
dockerImageFormat = config.getDockerBrowserAerokubeImageFormat();
dockerImage = String.format(dockerImageFormat, browserName,
browserVersion);
break;
default:
dockerImageFormat = getDockerImageFormat(browserVersion,
androidEnabled);
dockerImage = String.format(dockerImageFormat, browserName,
browserVersion);
break;
}
log.trace("Docker image: {}", dockerImage);
return dockerImage;
}
public String getDockerImageFormat(String browserVersion,
boolean androidEnabled) {
String dockerImageFormat;
if (isBrowserVersionBetaOrDev(browserVersion)) {
dockerImageFormat = config.getDockerBrowserTwilioImageFormat();
} else if (androidEnabled) {
dockerImageFormat = config.getDockerBrowserMobileImageFormat();
} else {
dockerImageFormat = config.getDockerBrowserSelenoidImageFormat();
}
return dockerImageFormat;
}
public boolean isBrowserVersionWildCard(String browserVersion) {
return isBrowserVersionBetaOrDev(browserVersion)
|| isBrowserVersionLatestMinus(browserVersion);
}
public boolean isBrowserVersionBetaOrDev(String browserVersion) {
return browserVersion.equalsIgnoreCase(BETA)
|| browserVersion.equalsIgnoreCase(DEV);
}
public boolean isBrowserVersionLatestMinus(String browserVersion) {
return browserVersion.toLowerCase(ROOT).contains(LATEST_MINUS);
}
private String getPrefixedDockerImage(String dockerImage) {
String newDockerImage = dockerImage;
String prefix = config.getDockerPrivateEndpoint();
if (StringUtils.isNotBlank(prefix)) {
newDockerImage = String.format("%s/%s", prefix, dockerImage);
}
return newDockerImage;
}
public DockerContainer startNoVncContainer(String dockerImage,
String cacheKey, String browserVersion,
DockerContainer browserContainer) {
dockerImage = getPrefixedDockerImage(dockerImage);
// pull image
pullImageIfNecessary(cacheKey, dockerImage, browserVersion);
// exposed ports
List exposedPorts = new ArrayList<>();
String dockerNoVncPort = String.valueOf(config.getDockerNoVncPort());
exposedPorts.add(dockerNoVncPort);
// envs
List envs = new ArrayList<>();
envs.add("AUTOCONNECT=true");
envs.add("VIEW_ONLY=" + config.isDockerViewOnly());
envs.add("VNC_PASSWORD=" + config.getDockerVncPassword());
String vncAddress = browserContainer.getAddress();
String vncPort = String.valueOf(config.getDockerVncPort());
envs.add("VNC_SERVER=" + vncAddress + ":" + vncPort);
// network
String network = config.getDockerNetwork();
// extra hosts
List extraHosts = config.getDockerExtraHosts();
// builder
DockerContainer noVncContainer = DockerContainer
.dockerBuilder(dockerImage).exposedPorts(exposedPorts)
.network(network).extraHosts(extraHosts).envs(envs).build();
String containerId = startContainer(noVncContainer);
noVncContainer.setContainerId(containerId);
String noVncHost = getDefaultHost();
String noVncPort = isHost(network) ? dockerNoVncPort
: getBindPort(containerId, dockerNoVncPort + "/tcp");
String noVncUrlFormat = "http://%s:%s/";
String noVncUrl = format(noVncUrlFormat, noVncHost, noVncPort);
noVncContainer.setContainerUrl(noVncUrl);
return noVncContainer;
}
public DockerContainer startBrowserContainer(String dockerImage,
String cacheKey, String browserVersion, boolean androidEnabled) {
dockerImage = getPrefixedDockerImage(dockerImage);
// pull image
pullImageIfNecessary(cacheKey, dockerImage, browserVersion);
// exposed ports
List exposedPorts = new ArrayList<>();
String dockerBrowserPort = String
.valueOf(config.getDockerBrowserPort());
exposedPorts.add(dockerBrowserPort);
// shmSize
long shmSize = config.getDockerMemSizeBytes(config.getDockerShmSize());
// mounts
List mounts = new ArrayList<>();
Mount tmpfsMount = new Mount()
.withTmpfsOptions(new TmpfsOptions().withSizeBytes(config
.getDockerMemSizeBytes(config.getDockerTmpfsSize())))
.withTarget(config.getDockerTmpfsMount());
mounts.add(tmpfsMount);
// binds
List binds = new ArrayList<>();
String dockerVolumes = config.getDockerVolumes();
if (!isNullOrEmpty(dockerVolumes)) {
List volumeList = Arrays.asList(dockerVolumes.split(","));
log.trace("Using custom volumes: {}", volumeList);
binds.addAll(volumeList);
}
// envs
List envs = new ArrayList<>();
envs.add("TZ=" + config.getDockerTimezone());
envs.add("LANGUAGE=" + config.getDockerLang());
envs.add("SCREEN_RESOLUTION=" + config.getDockerScreenResolution());
envs.addAll(config.getDockerEnvVariables());
String dockerVncPort = String.valueOf(config.getDockerVncPort());
if (config.isDockerEnabledVnc()) {
envs.add("ENABLE_VNC=true");
exposedPorts.add(dockerVncPort);
}
if (androidEnabled) {
envs.add("QTWEBENGINE_DISABLE_SANDBOX=1");
}
if (isChromeAllowedOrigins(dockerImage, browserVersion)) {
envs.add("DRIVER_ARGS=--whitelisted-ips= --allowed-origins=*");
}
// network
String network = config.getDockerNetwork();
// extra hosts
List extraHosts = config.getDockerExtraHosts();
// builder
DockerBuilder dockerBuilder = DockerContainer.dockerBuilder(dockerImage)
.exposedPorts(exposedPorts).network(network).mounts(mounts)
.binds(binds).shmSize(shmSize).envs(envs).extraHosts(extraHosts)
.sysadmin();
if (androidEnabled) {
dockerBuilder = dockerBuilder.privileged();
}
DockerContainer browserContainer = dockerBuilder.build();
String containerId = startContainer(browserContainer);
browserContainer.setContainerId(containerId);
String gateway = getGateway(containerId, network);
browserContainer.setGateway(gateway);
String browserHost = getHost(containerId, network);
String browserPort = isHost(network) ? dockerBrowserPort
: getBindPort(containerId, dockerBrowserPort + "/tcp");
String browserUrlFormat = "http://%s:%s/";
if (dockerImage.contains("firefox") || androidEnabled) {
browserUrlFormat += "wd/hub";
}
String browserUrl = format(browserUrlFormat, browserHost, browserPort);
browserContainer.setContainerUrl(browserUrl);
String address = getAddress(containerId, network);
browserContainer.setAddress(address);
log.trace("Browser remote URL {}", browserUrl);
if (config.isDockerEnabledVnc()) {
String vncPort = isHost(network) ? dockerVncPort
: getBindPort(containerId, dockerVncPort + "/tcp");
browserContainer.setVncPort(vncPort);
String vncAddress = format("vnc://%s:%s/", getDefaultHost(),
vncPort);
log.debug("VNC server URL: {}", vncAddress);
browserContainer.setVncAddress(vncAddress);
}
return browserContainer;
}
private boolean isHost(String dockerNetwork) {
return dockerNetwork.equalsIgnoreCase(NETWORK_HOST);
}
private boolean isChromeAllowedOrigins(String dockerImage,
String browserVersion) {
if (dockerImage.contains("chrome")) {
browserVersion = browserVersion
.replaceAll(config.getBrowserVersionDetectionRegex(), "");
return new VersionComparator().compare(browserVersion, "95") >= 0;
}
return false;
}
public DockerContainer startRecorderContainer(String dockerImage,
String cacheKey, String recorderVersion,
DockerContainer browserContainer) {
dockerImage = getPrefixedDockerImage(dockerImage);
// pull image
pullImageIfNecessary(cacheKey, dockerImage, recorderVersion);
// network
String network = config.getDockerNetwork();
// envs
List envs = new ArrayList<>();
String browserAddress = isHost(network) ? browserContainer.getGateway()
: browserContainer.getAddress();
envs.add("BROWSER_CONTAINER_NAME=" + browserAddress);
Path recordingPath = getRecordingPath(browserContainer);
envs.add("FILE_NAME=" + recordingPath.getFileName().toString());
envs.add("VIDEO_SIZE=" + config.getDockerVideoSize());
envs.add("FRAME_RATE=" + config.getDockerRecordingFrameRate());
// extra hosts
List extraHosts = config.getDockerExtraHosts();
// binds
List binds = new ArrayList<>();
binds.add(recordingPath.toAbsolutePath().getParent().toString()
+ ":/data");
String dockerVolumes = config.getDockerVolumes();
if (!isNullOrEmpty(dockerVolumes)) {
List volumeList = Arrays.asList(dockerVolumes.split(","));
log.trace("Using custom volumes: {}", volumeList);
binds.addAll(volumeList);
}
// builder
DockerContainer recorderContainer = DockerContainer
.dockerBuilder(dockerImage).network(network).envs(envs)
.binds(binds).extraHosts(extraHosts).sysadmin().build();
String containerId = startContainer(recorderContainer);
recorderContainer.setContainerId(containerId);
recorderContainer.setRecordingPath(recordingPath);
return recorderContainer;
}
public Path getRecordingPath(DockerContainer browserContainer) {
Path recordingPath;
Path dockerRecordingPath = config.getDockerRecordingOutput();
if (dockerRecordingPath.toString().toLowerCase(ROOT)
.endsWith(RECORDING_EXT)) {
recordingPath = dockerRecordingPath;
} else {
String sessionId = browserContainer.getSessionId();
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
String recordingFileName = browserContainer.getBrowserName()
+ SEPARATOR + dateFormat.format(now) + SEPARATOR + sessionId
+ RECORDING_EXT;
String prefix = config.getDockerRecordingPrefix();
if (!isNullOrEmpty(prefix)) {
recordingFileName = prefix + recordingFileName;
}
recordingPath = Paths.get(dockerRecordingPath.toString(),
recordingFileName);
}
return recordingPath;
}
public String getVersionFromImage(String dockerImage) {
return dockerImage.substring(dockerImage.indexOf(":") + 1);
}
public DockerClient getDockerClient() {
return dockerClient;
}
}