3030import hudson .util .VersionNumber ;
3131import org .junit .Assume ;
3232
33+ import java .io .ByteArrayOutputStream ;
3334import java .io .IOException ;
35+ import java .util .Arrays ;
36+ import java .util .List ;
37+ import java .util .Optional ;
3438import java .util .concurrent .TimeUnit ;
39+ import java .util .regex .Matcher ;
40+ import java .util .regex .Pattern ;
3541
42+ import org .hamcrest .Matchers ;
3643import org .jenkinsci .plugins .docker .commons .tools .DockerTool ;
3744
3845/**
4148public class DockerTestUtil {
4249 public static String DEFAULT_MINIMUM_VERSION = "1.3" ;
4350
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+
4462 public static void assumeDocker () throws Exception {
4563 assumeDocker (new VersionNumber (DEFAULT_MINIMUM_VERSION ));
4664 }
@@ -61,10 +79,78 @@ public static void assumeDocker(VersionNumber minimumVersion) throws Exception {
6179 Assume .assumeFalse ("Docker version not < " + minimumVersion .toString (), dockerClient .version ().isOlderThan (minimumVersion ));
6280 }
6381
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+
64108 public static void assumeNotWindows () throws Exception {
65109 Assume .assumeFalse (System .getProperty ("os.name" ).toLowerCase ().contains ("windows" ));
66110 }
67111
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+
68154 public static EnvVars newDockerLaunchEnv () {
69155 // Create the KeyMaterial for connecting to the docker host/server.
70156 // E.g. currently need to add something like the following to your env
0 commit comments