30
30
import hudson .util .VersionNumber ;
31
31
import org .junit .Assume ;
32
32
33
+ import java .io .ByteArrayOutputStream ;
33
34
import java .io .IOException ;
35
+ import java .util .Arrays ;
36
+ import java .util .List ;
37
+ import java .util .Optional ;
34
38
import java .util .concurrent .TimeUnit ;
39
+ import java .util .regex .Matcher ;
40
+ import java .util .regex .Pattern ;
35
41
42
+ import org .hamcrest .Matchers ;
36
43
import org .jenkinsci .plugins .docker .commons .tools .DockerTool ;
37
44
38
45
/**
41
48
public class DockerTestUtil {
42
49
public static String DEFAULT_MINIMUM_VERSION = "1.3" ;
43
50
51
+ // Major Windows kernel versions. See https://hub.docker.com/r/microsoft/windows-nanoserver
52
+ private static List <String > MAJOR_WINDOWS_KERNEL_VERSIONS = Arrays .asList (
53
+ "10.0.17763.6659" , // 1809
54
+ "10.0.18363.1556" , // 1909
55
+ "10.0.19041.1415" , // 2004
56
+ "10.0.19042.1889" , // 20H2
57
+ "10.0.20348.2966" , // 2022
58
+ "10.0.26100.2605" // 2025
59
+ );
60
+
61
+
44
62
public static void assumeDocker () throws Exception {
45
63
assumeDocker (new VersionNumber (DEFAULT_MINIMUM_VERSION ));
46
64
}
@@ -61,10 +79,78 @@ public static void assumeDocker(VersionNumber minimumVersion) throws Exception {
61
79
Assume .assumeFalse ("Docker version not < " + minimumVersion .toString (), dockerClient .version ().isOlderThan (minimumVersion ));
62
80
}
63
81
82
+ /**
83
+ * Used to assume docker Windows is running in a particular os mode
84
+ * @param os The os [windows, linux]
85
+ * @throws Exception
86
+ */
87
+ public static void assumeDockerServerOSMode (String os ) throws Exception {
88
+ Launcher .LocalLauncher localLauncher = new Launcher .LocalLauncher (StreamTaskListener .NULL );
89
+ try {
90
+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
91
+ int status = localLauncher
92
+ .launch ()
93
+ .cmds (DockerTool .getExecutable (null , null , null , null ), "version" , "-f" , "{{.Server.Os}}" )
94
+ .stdout (out )
95
+ .start ()
96
+ .joinWithTimeout (DockerClient .CLIENT_TIMEOUT , TimeUnit .SECONDS , localLauncher .getListener ());
97
+ Assume .assumeTrue ("Docker working" , status == 0 );
98
+ Assume .assumeThat ("Docker running in " + os + " mode" , out .toString ().trim (), Matchers .equalToIgnoringCase (os ));
99
+ } catch (IOException x ) {
100
+ Assume .assumeNoException ("Docker retrieve OS" , x );
101
+ }
102
+ }
103
+
104
+ public static void assumeWindows () throws Exception {
105
+ Assume .assumeTrue (System .getProperty ("os.name" ).toLowerCase ().contains ("windows" ));
106
+ }
107
+
64
108
public static void assumeNotWindows () throws Exception {
65
109
Assume .assumeFalse (System .getProperty ("os.name" ).toLowerCase ().contains ("windows" ));
66
110
}
67
111
112
+ public static String getWindowsKernelVersion () throws Exception {
113
+ Launcher .LocalLauncher localLauncher = new Launcher .LocalLauncher (StreamTaskListener .NULL );
114
+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
115
+ ByteArrayOutputStream err = new ByteArrayOutputStream ();
116
+
117
+ int status = localLauncher
118
+ .launch ()
119
+ .cmds ("cmd" , "/c" , "ver" )
120
+ .stdout (out )
121
+ .stderr (err )
122
+ .start ()
123
+ .joinWithTimeout (DockerClient .CLIENT_TIMEOUT , TimeUnit .SECONDS , localLauncher .getListener ());
124
+
125
+ if (status != 0 ) {
126
+ throw new RuntimeException (String .format ("Failed to obtain Windows kernel version with exit code: %d stdout: %s stderr: %s" , status , out , err ));
127
+ }
128
+
129
+ Matcher matcher = Pattern .compile ("Microsoft Windows \\ [Version ([^\\ ]]+)\\ ]" ).matcher (out .toString ().trim ());
130
+
131
+ if (matcher .matches ()) {
132
+ return matcher .group (1 );
133
+ } else {
134
+ throw new RuntimeException ("Unable to obtain Windows kernel version from output: " + out );
135
+ }
136
+ }
137
+
138
+ /**
139
+ * @return The image tag of an image with a kernel version corresponding to the closest compatible Windows release
140
+ * @throws Exception
141
+ */
142
+ public static String getWindowsImageTag () throws Exception {
143
+ // Kernel must match when running Windows containers on docker on Windows if < Windows 11 with Server 2022
144
+ String kernelVersion = DockerTestUtil .getWindowsKernelVersion ();
145
+
146
+ // Select the highest well known kernel version <= ours since sometimes an image may not exist for our version
147
+ Optional <String > wellKnownKernelVersion = MAJOR_WINDOWS_KERNEL_VERSIONS .stream ()
148
+ .filter (k -> k .compareTo (kernelVersion ) <= 0 ).max (java .util .Comparator .naturalOrder ());
149
+
150
+ // Fall back to trying our kernel version
151
+ return wellKnownKernelVersion .orElse (kernelVersion );
152
+ }
153
+
68
154
public static EnvVars newDockerLaunchEnv () {
69
155
// Create the KeyMaterial for connecting to the docker host/server.
70
156
// E.g. currently need to add something like the following to your env
0 commit comments