Skip to content

Commit b9fafa4

Browse files
committed
Fix host directory mounts on Windows
On Windows, it is not possible to mount host directories to a subfolder of a non-C: drive. Due to this restriction, having a workspace on another drive will make the docker run execution fail since the plugin tries to map the workspace into the container. This fixes that by collecting all the non-C: drive volume mappings and handling those explicitly by mapping the entire drive into the container.
1 parent b174d46 commit b9fafa4

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

src/main/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClient.java

+34-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import javax.annotation.Nonnull;
1313
import java.io.*;
1414
import java.nio.charset.Charset;
15+
import java.nio.file.InvalidPathException;
16+
import java.nio.file.Path;
17+
import java.nio.file.Paths;
1518
import java.util.*;
1619
import java.util.concurrent.TimeUnit;
1720
import java.util.logging.Level;
@@ -39,8 +42,38 @@ public String run(@Nonnull EnvVars launchEnv, @Nonnull String image, @CheckForNu
3942
if (workdir != null) {
4043
argb.add("-w", workdir);
4144
}
45+
Set<String> drives = new HashSet<>();
4246
for (Map.Entry<String, String> volume : volumes.entrySet()) {
43-
argb.add("-v", volume.getKey() + ":" + volume.getValue());
47+
String driveName = null;
48+
49+
try {
50+
Path hostPath = Paths.get(volume.getKey());
51+
Path rootPath = hostPath.getRoot();
52+
// If we have a valid root we can check if we need to do our special root handling
53+
if (rootPath != null) {
54+
driveName = rootPath.toString();
55+
if (driveName.endsWith("\\")) {
56+
driveName = driveName.substring(0, driveName.length() - 1);
57+
}
58+
}
59+
} catch (InvalidPathException e) {
60+
// We got a value that is not a valid path. Keeping driveName at null allows us to gracefully handle this
61+
// and skip the special drive path handling for those cases
62+
}
63+
if (driveName == null || driveName.equals("C:")) {
64+
// C: path can be mapped directly
65+
argb.add("-v", volume.getKey() + ":" + volume.getValue());
66+
}
67+
else
68+
{
69+
// Non C: drive paths in the container can not be mapped due to Windows limitations. It is only possible
70+
// to map an entire drive so we collect the used drives and map the entire drive
71+
drives.add(driveName);
72+
}
73+
}
74+
for (String drive : drives) {
75+
// Windows requires that the host part is a directory but the container path must be an entire drive
76+
argb.add("-v", String.format("%s\\:%s", drive, drive));
4477
}
4578
for (String containerId : volumesFromContainers) {
4679
argb.add("--volumes-from", containerId);

src/test/java/org/jenkinsci/plugins/docker/workflow/client/WindowsDockerClientTest.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import java.io.IOException;
1414
import java.util.Collections;
15+
import java.util.HashMap;
16+
import java.util.Map;
1517

1618
public class WindowsDockerClientTest {
1719

@@ -35,7 +37,7 @@ public void test_run() throws IOException, InterruptedException {
3537
"learn/tutorial",
3638
null,
3739
null,
38-
Collections.emptyMap(),
40+
Collections.singletonMap("D:\\Jenkins\\workspace", "D:\\Jenkins\\workspace"),
3941
Collections.emptyList(),
4042
new EnvVars(),
4143
dockerClient.whoAmI(),
@@ -47,7 +49,7 @@ public void test_run() throws IOException, InterruptedException {
4749
Assert.assertTrue(containerRecord.getContainerName().length() > 0);
4850
Assert.assertTrue(containerRecord.getHost().length() > 0);
4951
Assert.assertTrue(containerRecord.getCreated() > 1000000000000L);
50-
Assert.assertEquals(Collections.<String>emptyList(), dockerClient.getVolumes(launchEnv, containerId));
52+
Assert.assertEquals(Collections.singletonList("D:\\Jenkins\\workspace"), dockerClient.getVolumes(launchEnv, containerId));
5153

5254
// Also test that the stop works and cleans up after itself
5355
Assert.assertNotNull(dockerClient.inspect(launchEnv, containerId, ".Name"));

0 commit comments

Comments
 (0)