From 405fa8fbbf5e290631a982912524ac8cb876a9a9 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Thu, 16 May 2024 10:51:12 +0200 Subject: [PATCH 1/5] Usage of https://github.com/jenkinsci/docker-agent/pull/809 Add system properties based switches to use the new mechanism To enable usage of REMOTING_OPTS -Dorg.csanchez.jenkins.plugins.kubernetes.PodTemplateBuilder.useRemotingOpts=true Enabling it requires all pod templates to use a version of agent with https://github.com/jenkinsci/docker-agent/pull/809 in. Add extra REMOTING options -Dorg.csanchez.jenkins.plugins.kubernetes.PodTemplateBuilder.extraRemotingOpts="-noReconnectAfter 10m" Used this approach because there are migration challenges: * The remoting version must be recent enough to support REMOTING_OPTS * When overriding the JNLP container, the configuration form is generic, and part of REMOTING_OPTS is generated based on options defined in the cloud, so can't expose either an "extra remoting options" field, not use the `REMOTING_OPTS` environment variable. --- .../kubernetes/PodTemplateBuilder.java | 111 +++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java index c27b30359f..cf422e5120 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java @@ -61,6 +61,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -73,6 +74,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import jenkins.model.Jenkins; +import jenkins.util.SystemProperties; import org.apache.commons.lang.StringUtils; import org.csanchez.jenkins.plugins.kubernetes.model.TemplateEnvVar; import org.csanchez.jenkins.plugins.kubernetes.pipeline.PodTemplateStepExecution; @@ -136,6 +138,11 @@ public class PodTemplateBuilder { static final String DEFAULT_JNLP_CONTAINER_CPU_LIMIT = System.getProperty(PodTemplateStepExecution.class.getName() + ".defaultContainer.defaultCpuLimit"); + private static final boolean USE_REMOTING_OPTS = + SystemProperties.getBoolean(PodTemplateBuilder.class.getName() + ".useRemotingOpts"); + private static final String EXTRA_REMOTING_OPTS = + SystemProperties.getString(PodTemplateBuilder.class.getName() + ".extraRemotingOpts"); + private static final String JNLPMAC_REF = "\\$\\{computer.jnlpmac\\}"; private static final String NAME_REF = "\\$\\{computer.name\\}"; @@ -405,7 +412,7 @@ private Map defaultEnvVars(Collection globalEnvV return envVarsMap; } - private Map jnlpEnvVars(String workingDir) { + private Map jnlpEnvVars(@CheckForNull String workingDir) { if (workingDir == null) { workingDir = ContainerTemplate.DEFAULT_WORKING_DIR; } @@ -413,38 +420,44 @@ private Map jnlpEnvVars(String workingDir) { HashMap env = new HashMap<>(); if (agent != null) { - SlaveComputer computer = agent.getComputer(); - if (computer != null) { - // Add some default env vars for Jenkins - env.put("JENKINS_SECRET", computer.getJnlpMac()); - // JENKINS_AGENT_NAME is default in jnlp-slave - // JENKINS_NAME only here for backwords compatability - env.put("JENKINS_NAME", computer.getName()); - env.put("JENKINS_AGENT_NAME", computer.getName()); + if (USE_REMOTING_OPTS) { + contributeRemotingOptions(workingDir, env); } else { - LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); - } + // TODO: legacy, remove when we require a minimum version of inbound agent containing + // https://github.com/jenkinsci/docker-agent/pull/809 + SlaveComputer computer = agent.getComputer(); + if (computer != null) { + // Add some default env vars for Jenkins + env.put("JENKINS_SECRET", computer.getJnlpMac()); + // JENKINS_AGENT_NAME is default in jnlp-slave + // JENKINS_NAME only here for backwords compatability + env.put("JENKINS_NAME", computer.getName()); + env.put("JENKINS_AGENT_NAME", computer.getName()); + } else { + LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); + } - env.put("JENKINS_AGENT_WORKDIR", workingDir); + env.put("JENKINS_AGENT_WORKDIR", workingDir); - KubernetesCloud cloud = agent.getKubernetesCloud(); + KubernetesCloud cloud = agent.getKubernetesCloud(); - if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { - env.put("JENKINS_TUNNEL", cloud.getJenkinsTunnel()); - } + if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { + env.put("JENKINS_TUNNEL", cloud.getJenkinsTunnel()); + } - if (!cloud.isDirectConnection()) { - env.put("JENKINS_URL", cloud.getJenkinsUrlOrDie()); - if (cloud.isWebSocket()) { - env.put("JENKINS_WEB_SOCKET", "true"); + if (!cloud.isDirectConnection()) { + env.put("JENKINS_URL", cloud.getJenkinsUrlOrDie()); + if (cloud.isWebSocket()) { + env.put("JENKINS_WEB_SOCKET", "true"); + } + } else { + TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); + String host = tcpSlaveAgentListener.getAdvertisedHost(); + int port = tcpSlaveAgentListener.getAdvertisedPort(); + env.put("JENKINS_DIRECT_CONNECTION", host + ":" + port); + env.put("JENKINS_PROTOCOLS", "JNLP4-connect"); + env.put("JENKINS_INSTANCE_IDENTITY", tcpSlaveAgentListener.getIdentityPublicKey()); } - } else { - TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); - String host = tcpSlaveAgentListener.getAdvertisedHost(); - int port = tcpSlaveAgentListener.getAdvertisedPort(); - env.put("JENKINS_DIRECT_CONNECTION", host + ":" + port); - env.put("JENKINS_PROTOCOLS", "JNLP4-connect"); - env.put("JENKINS_INSTANCE_IDENTITY", tcpSlaveAgentListener.getIdentityPublicKey()); } } Map envVarsMap = new HashMap<>(); @@ -453,6 +466,50 @@ private Map jnlpEnvVars(String workingDir) { return envVarsMap; } + private void contributeRemotingOptions(@NonNull String workingDir, @NonNull Map env) { + SlaveComputer computer = agent.getComputer(); + var remotingOptions = new ArrayList(); + if (computer != null) { + remotingOptions.add("-secret"); + remotingOptions.add(computer.getJnlpMac()); + remotingOptions.add("-name"); + remotingOptions.add(computer.getName()); + } else { + LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); + } + + remotingOptions.add("-workDir"); + remotingOptions.add(workingDir); + + KubernetesCloud cloud = agent.getKubernetesCloud(); + + if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { + remotingOptions.add("-tunnel"); + remotingOptions.add(cloud.getJenkinsTunnel()); + } + + if (!cloud.isDirectConnection()) { + remotingOptions.add("-url"); + remotingOptions.add(cloud.getJenkinsUrlOrDie()); + if (cloud.isWebSocket()) { + remotingOptions.add("-webSocket"); + } + } else { + TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); + remotingOptions.add("-direct"); + remotingOptions.add( + tcpSlaveAgentListener.getAdvertisedHost() + ":" + tcpSlaveAgentListener.getAdvertisedPort()); + remotingOptions.add("-protocols"); + remotingOptions.add("JNLP4-connect"); + remotingOptions.add("-instanceIdentity"); + remotingOptions.add(tcpSlaveAgentListener.getIdentityPublicKey()); + } + if (EXTRA_REMOTING_OPTS != null) { + remotingOptions.addAll(Arrays.asList(EXTRA_REMOTING_OPTS.split(" "))); + } + env.put("REMOTING_OPTS", String.join(" ", remotingOptions)); + } + private Container createContainer( ContainerTemplate containerTemplate, Collection globalEnvVars, From 74502ab076eea4d8edcff0794910737aa90036e3 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Fri, 17 May 2024 14:07:40 +0200 Subject: [PATCH 2/5] Add default value for -noReconnectAfter of 1 day Can be tuned via org.csanchez.jenkins.plugins.kubernetes.PodTemplateBuilder.noReconnectAfter using the same syntax as what remoting.jar -noReconnectAfter takes. If the remoting version is too old, this parameter is ignored --- .../jenkins/plugins/kubernetes/PodTemplateBuilder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java index cf422e5120..f3d42097df 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java @@ -102,6 +102,8 @@ public class PodTemplateBuilder { public static final Pattern FROM_DIRECTIVE = Pattern.compile("^FROM (.*)$"); public static final String LABEL_KUBERNETES_CONTROLLER = "kubernetes.jenkins.io/controller"; + private static final String NO_RECONNECT_AFTER_TIMEOUT = + SystemProperties.getString(PodTemplateBuilder.class.getName() + ".noReconnectAfter", "1d"); @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "tests") @Restricted(NoExternalUse.class) @@ -458,6 +460,7 @@ private Map jnlpEnvVars(@CheckForNull String workingDir) { env.put("JENKINS_PROTOCOLS", "JNLP4-connect"); env.put("JENKINS_INSTANCE_IDENTITY", tcpSlaveAgentListener.getIdentityPublicKey()); } + env.put("REMOTING_OPTS", "-noReconnectAfter " + NO_RECONNECT_AFTER_TIMEOUT); } } Map envVarsMap = new HashMap<>(); @@ -504,6 +507,8 @@ private void contributeRemotingOptions(@NonNull String workingDir, @NonNull Map< remotingOptions.add("-instanceIdentity"); remotingOptions.add(tcpSlaveAgentListener.getIdentityPublicKey()); } + remotingOptions.add("-noReconnectAfter"); + remotingOptions.add(NO_RECONNECT_AFTER_TIMEOUT); if (EXTRA_REMOTING_OPTS != null) { remotingOptions.addAll(Arrays.asList(EXTRA_REMOTING_OPTS.split(" "))); } From 1daed42fe8b1203075b88af176e8ffa9d3fd8542 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Tue, 21 May 2024 10:00:25 +0200 Subject: [PATCH 3/5] Simplify patch * Bump built-in remoting to the version coming with REMOTING_OPTS --- .../kubernetes/PodTemplateBuilder.java | 114 +++++------------- .../jenkins/plugins/kubernetes/Dockerfile | 2 +- 2 files changed, 29 insertions(+), 87 deletions(-) diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java index f3d42097df..4a2307bc3a 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java @@ -61,7 +61,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -140,11 +139,6 @@ public class PodTemplateBuilder { static final String DEFAULT_JNLP_CONTAINER_CPU_LIMIT = System.getProperty(PodTemplateStepExecution.class.getName() + ".defaultContainer.defaultCpuLimit"); - private static final boolean USE_REMOTING_OPTS = - SystemProperties.getBoolean(PodTemplateBuilder.class.getName() + ".useRemotingOpts"); - private static final String EXTRA_REMOTING_OPTS = - SystemProperties.getString(PodTemplateBuilder.class.getName() + ".extraRemotingOpts"); - private static final String JNLPMAC_REF = "\\$\\{computer.jnlpmac\\}"; private static final String NAME_REF = "\\$\\{computer.name\\}"; @@ -414,7 +408,7 @@ private Map defaultEnvVars(Collection globalEnvV return envVarsMap; } - private Map jnlpEnvVars(@CheckForNull String workingDir) { + private Map jnlpEnvVars(String workingDir) { if (workingDir == null) { workingDir = ContainerTemplate.DEFAULT_WORKING_DIR; } @@ -422,46 +416,40 @@ private Map jnlpEnvVars(@CheckForNull String workingDir) { HashMap env = new HashMap<>(); if (agent != null) { - if (USE_REMOTING_OPTS) { - contributeRemotingOptions(workingDir, env); + SlaveComputer computer = agent.getComputer(); + if (computer != null) { + // Add some default env vars for Jenkins + env.put("JENKINS_SECRET", computer.getJnlpMac()); + // JENKINS_AGENT_NAME is default in jnlp-slave + // JENKINS_NAME only here for backwords compatability + env.put("JENKINS_NAME", computer.getName()); + env.put("JENKINS_AGENT_NAME", computer.getName()); } else { - // TODO: legacy, remove when we require a minimum version of inbound agent containing - // https://github.com/jenkinsci/docker-agent/pull/809 - SlaveComputer computer = agent.getComputer(); - if (computer != null) { - // Add some default env vars for Jenkins - env.put("JENKINS_SECRET", computer.getJnlpMac()); - // JENKINS_AGENT_NAME is default in jnlp-slave - // JENKINS_NAME only here for backwords compatability - env.put("JENKINS_NAME", computer.getName()); - env.put("JENKINS_AGENT_NAME", computer.getName()); - } else { - LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); - } + LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); + } - env.put("JENKINS_AGENT_WORKDIR", workingDir); + env.put("JENKINS_AGENT_WORKDIR", workingDir); - KubernetesCloud cloud = agent.getKubernetesCloud(); + KubernetesCloud cloud = agent.getKubernetesCloud(); - if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { - env.put("JENKINS_TUNNEL", cloud.getJenkinsTunnel()); - } + if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { + env.put("JENKINS_TUNNEL", cloud.getJenkinsTunnel()); + } - if (!cloud.isDirectConnection()) { - env.put("JENKINS_URL", cloud.getJenkinsUrlOrDie()); - if (cloud.isWebSocket()) { - env.put("JENKINS_WEB_SOCKET", "true"); - } - } else { - TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); - String host = tcpSlaveAgentListener.getAdvertisedHost(); - int port = tcpSlaveAgentListener.getAdvertisedPort(); - env.put("JENKINS_DIRECT_CONNECTION", host + ":" + port); - env.put("JENKINS_PROTOCOLS", "JNLP4-connect"); - env.put("JENKINS_INSTANCE_IDENTITY", tcpSlaveAgentListener.getIdentityPublicKey()); + if (!cloud.isDirectConnection()) { + env.put("JENKINS_URL", cloud.getJenkinsUrlOrDie()); + if (cloud.isWebSocket()) { + env.put("JENKINS_WEB_SOCKET", "true"); } - env.put("REMOTING_OPTS", "-noReconnectAfter " + NO_RECONNECT_AFTER_TIMEOUT); + } else { + TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); + String host = tcpSlaveAgentListener.getAdvertisedHost(); + int port = tcpSlaveAgentListener.getAdvertisedPort(); + env.put("JENKINS_DIRECT_CONNECTION", host + ":" + port); + env.put("JENKINS_PROTOCOLS", "JNLP4-connect"); + env.put("JENKINS_INSTANCE_IDENTITY", tcpSlaveAgentListener.getIdentityPublicKey()); } + env.put("REMOTING_OPTS", "-noReconnectAfter " + NO_RECONNECT_AFTER_TIMEOUT); } Map envVarsMap = new HashMap<>(); @@ -469,52 +457,6 @@ private Map jnlpEnvVars(@CheckForNull String workingDir) { return envVarsMap; } - private void contributeRemotingOptions(@NonNull String workingDir, @NonNull Map env) { - SlaveComputer computer = agent.getComputer(); - var remotingOptions = new ArrayList(); - if (computer != null) { - remotingOptions.add("-secret"); - remotingOptions.add(computer.getJnlpMac()); - remotingOptions.add("-name"); - remotingOptions.add(computer.getName()); - } else { - LOGGER.log(Level.INFO, "Computer is null for agent: {0}", agent.getNodeName()); - } - - remotingOptions.add("-workDir"); - remotingOptions.add(workingDir); - - KubernetesCloud cloud = agent.getKubernetesCloud(); - - if (!StringUtils.isBlank(cloud.getJenkinsTunnel())) { - remotingOptions.add("-tunnel"); - remotingOptions.add(cloud.getJenkinsTunnel()); - } - - if (!cloud.isDirectConnection()) { - remotingOptions.add("-url"); - remotingOptions.add(cloud.getJenkinsUrlOrDie()); - if (cloud.isWebSocket()) { - remotingOptions.add("-webSocket"); - } - } else { - TcpSlaveAgentListener tcpSlaveAgentListener = Jenkins.get().getTcpSlaveAgentListener(); - remotingOptions.add("-direct"); - remotingOptions.add( - tcpSlaveAgentListener.getAdvertisedHost() + ":" + tcpSlaveAgentListener.getAdvertisedPort()); - remotingOptions.add("-protocols"); - remotingOptions.add("JNLP4-connect"); - remotingOptions.add("-instanceIdentity"); - remotingOptions.add(tcpSlaveAgentListener.getIdentityPublicKey()); - } - remotingOptions.add("-noReconnectAfter"); - remotingOptions.add(NO_RECONNECT_AFTER_TIMEOUT); - if (EXTRA_REMOTING_OPTS != null) { - remotingOptions.addAll(Arrays.asList(EXTRA_REMOTING_OPTS.split(" "))); - } - env.put("REMOTING_OPTS", String.join(" ", remotingOptions)); - } - private Container createContainer( ContainerTemplate containerTemplate, Collection globalEnvVars, diff --git a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Dockerfile b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Dockerfile index a7b9ab4c16..ecfe80ce45 100644 --- a/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Dockerfile +++ b/src/main/resources/org/csanchez/jenkins/plugins/kubernetes/Dockerfile @@ -1 +1 @@ -FROM jenkins/inbound-agent:3206.vb_15dcf73f6a_9-2 +FROM jenkins/inbound-agent:3248.v65ecb_254c298-2 From 6411ccc84e2d5ed1147378883b1d3f607c4d708e Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Tue, 21 May 2024 15:24:30 +0200 Subject: [PATCH 4/5] Fix test --- .../jenkins/plugins/kubernetes/PodTemplateBuilder.java | 2 +- .../jenkins/plugins/kubernetes/PodTemplateBuilderTest.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java index 4a2307bc3a..7af040b886 100644 --- a/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java +++ b/src/main/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilder.java @@ -101,7 +101,7 @@ public class PodTemplateBuilder { public static final Pattern FROM_DIRECTIVE = Pattern.compile("^FROM (.*)$"); public static final String LABEL_KUBERNETES_CONTROLLER = "kubernetes.jenkins.io/controller"; - private static final String NO_RECONNECT_AFTER_TIMEOUT = + static final String NO_RECONNECT_AFTER_TIMEOUT = SystemProperties.getString(PodTemplateBuilder.class.getName() + ".noReconnectAfter", "1d"); @SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "tests") diff --git a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java index 13be3b83ee..789021c4d4 100644 --- a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java +++ b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java @@ -451,8 +451,8 @@ private void validateContainers(Pod pod, KubernetesSlave slave, boolean directCo if ("jnlp".equals(c.getName())) { validateJnlpContainer(c, slave, directConnection); } else { - List env = c.getEnv(); - assertThat(env.stream().map(EnvVar::getName).collect(toList()), everyItem(not(isIn(exclusions)))); + assertThat( + c.getEnv().stream().map(EnvVar::getName).collect(toList()), everyItem(not(is(in(exclusions))))); } } } @@ -480,6 +480,7 @@ private void validateJnlpContainer(Container jnlp, KubernetesSlave slave, boolea envVars.add(new EnvVar("JENKINS_NAME", AGENT_NAME, null)); envVars.add(new EnvVar("JENKINS_AGENT_NAME", AGENT_NAME, null)); envVars.add(new EnvVar("JENKINS_AGENT_WORKDIR", ContainerTemplate.DEFAULT_WORKING_DIR, null)); + envVars.add(new EnvVar("REMOTING_OPTS", "-noReconnectAfter " + NO_RECONNECT_AFTER_TIMEOUT, null)); } else { assertThat(jnlp.getArgs(), empty()); } From 9961ad16d471d144481f9a60463a3168929d211c Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Wed, 22 May 2024 08:30:14 +0200 Subject: [PATCH 5/5] Revert unrelated hunk --- .../jenkins/plugins/kubernetes/PodTemplateBuilderTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java index 789021c4d4..9ab3e0db79 100644 --- a/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java +++ b/src/test/java/org/csanchez/jenkins/plugins/kubernetes/PodTemplateBuilderTest.java @@ -451,8 +451,8 @@ private void validateContainers(Pod pod, KubernetesSlave slave, boolean directCo if ("jnlp".equals(c.getName())) { validateJnlpContainer(c, slave, directConnection); } else { - assertThat( - c.getEnv().stream().map(EnvVar::getName).collect(toList()), everyItem(not(is(in(exclusions))))); + List env = c.getEnv(); + assertThat(env.stream().map(EnvVar::getName).collect(toList()), everyItem(not(isIn(exclusions)))); } } }