提交 efdd52e9 编写于 作者: O Oleg Nenashev 提交者: GitHub

[JENKINS-45841] - Disable JNLP/JNLP2/CLI protocols on new installations (#2950)

* [JENKINS-45841] - Disable JNLP/JNLP2/CLI protocols in the Setup Wizard

* [JENKINS-45841] - Implement deprecation data model for Agent protocols.

WiP

* [JENKINS-45841] - DeprecationCause is YAGNI, extend UI and document deprecated protocols

* [JENKINS-45841] - Fix the layouts

* [JENKINS-45841] - Add administrative monitor for deprecated protocols

* [JENKINS-45841] - Added Initializer check, polished the warning message

* [JENKINS-45841] - Add tests

* [JENKINS-45841] - Replace JNLP protocol links by jenkins.io redirects

* [JENKINS-45841] - Address comments from @jglick

* [JENKINS-45841] - Initializer checks status when Jenkins instance is not ready
上级 d8ef4be5
......@@ -47,12 +47,17 @@ public class CliProtocol extends AgentProtocol {
return jenkins.CLI.get().isEnabled() ? "CLI-connect" : null;
}
@Override
public boolean isDeprecated() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String getDisplayName() {
return "Jenkins CLI Protocol/1";
return "Jenkins CLI Protocol/1 (deprecated, unencrypted)";
}
@Override
......
......@@ -38,12 +38,18 @@ public class CliProtocol2 extends CliProtocol {
return false;
}
@Override
public boolean isDeprecated() {
// We do not recommend it though it may be required for Remoting CLI
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String getDisplayName() {
return "Jenkins CLI Protocol/2";
return "Jenkins CLI Protocol/2 (deprecated)";
}
@Override
......
......@@ -8,6 +8,8 @@ import hudson.TcpSlaveAgentListener;
import java.io.IOException;
import java.net.Socket;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
/**
......@@ -18,6 +20,15 @@ import jenkins.model.Jenkins;
* Implementations of this extension point is singleton, and its {@link #handle(Socket)} method
* gets invoked concurrently whenever a new connection comes in.
*
* <h2>Extending UI</h2>
* <dl>
* <dt>description.jelly</dt>
* <dd>Optional protocol description</dd>
* <dt>deprecationCause.jelly</dt>
* <dd>Optional. If the protocol is marked as {@link #isDeprecated()},
* clarifies the deprecation reason and provides extra documentation links</dd>
* </dl>
*
* @author Kohsuke Kawaguchi
* @since 1.467
* @see TcpSlaveAgentListener
......@@ -53,6 +64,16 @@ public abstract class AgentProtocol implements ExtensionPoint {
public boolean isRequired() {
return false;
}
/**
* Checks if the protocol is deprecated.
*
* @since TODO
*/
public boolean isDeprecated() {
return false;
}
/**
* Protocol name.
*
......@@ -86,6 +107,7 @@ public abstract class AgentProtocol implements ExtensionPoint {
return ExtensionList.lookup(AgentProtocol.class);
}
@CheckForNull
public static AgentProtocol of(String protocolName) {
for (AgentProtocol p : all()) {
String n = p.getName();
......
......@@ -52,6 +52,8 @@ import java.net.HttpRetryException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import jenkins.CLI;
......@@ -62,6 +64,7 @@ import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jenkinsci.remoting.engine.JnlpProtocol4Handler;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.interceptor.RequirePOST;
......@@ -127,6 +130,13 @@ public class SetupWizard extends PageDecorator {
// Disable CLI over Remoting
CLI.get().setEnabled(false);
// Disable old Non-Encrypted protocols ()
HashSet<String> newProtocols = new HashSet<>(jenkins.getAgentProtocols());
newProtocols.removeAll(Arrays.asList(
"JNLP2-connect", "JNLP-connect", "CLI-connect"
));
jenkins.setAgentProtocols(newProtocols);
// require a crumb issuer
jenkins.setCrumbIssuer(new DefaultCrumbIssuer(false));
......
/*
* The MIT License
*
* Copyright (c) 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.slaves;
import hudson.Extension;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.AdministrativeMonitor;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import jenkins.AgentProtocol;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Monitors enabled protocols and warns if an {@link AgentProtocol} is deprecated.
*
* @author Oleg Nenashev
* @since TODO
* @see AgentProtocol
*/
@Extension
@Symbol("deprecatedAgentProtocol")
@Restricted(NoExternalUse.class)
public class DeprecatedAgentProtocolMonitor extends AdministrativeMonitor {
private static final Logger LOGGER = Logger.getLogger(DeprecatedAgentProtocolMonitor.class.getName());
public DeprecatedAgentProtocolMonitor() {
super();
}
@Override
public String getDisplayName() {
return Messages.DeprecatedAgentProtocolMonitor_displayName();
}
@Override
public boolean isActivated() {
final Set<String> agentProtocols = Jenkins.getInstance().getAgentProtocols();
for (String name : agentProtocols) {
AgentProtocol pr = AgentProtocol.of(name);
if (pr != null && pr.isDeprecated()) {
return true;
}
}
return false;
}
@Restricted(NoExternalUse.class)
public String getDeprecatedProtocols() {
String res = getDeprecatedProtocolsString();
return res != null ? res : "N/A";
}
@CheckForNull
public static String getDeprecatedProtocolsString() {
final List<String> deprecatedProtocols = new ArrayList<>();
final Set<String> agentProtocols = Jenkins.getInstance().getAgentProtocols();
for (String name : agentProtocols) {
AgentProtocol pr = AgentProtocol.of(name);
if (pr != null && pr.isDeprecated()) {
deprecatedProtocols.add(name);
}
}
if (deprecatedProtocols.isEmpty()) {
return null;
}
return StringUtils.join(deprecatedProtocols, ',');
}
@Initializer(after = InitMilestone.JOB_LOADED)
@Restricted(NoExternalUse.class)
public static void initializerCheck() {
String protocols = getDeprecatedProtocolsString();
if(protocols != null) {
LOGGER.log(Level.WARNING, "This Jenkins instance uses deprecated Remoting protocols: {0}"
+ "It may impact stability of the instance. "
+ "If newer protocol versions are supported by all system components "
+ "(agents, CLI and other clients), "
+ "it is highly recommended to disable the deprecated protocols.", protocols);
}
}
}
......@@ -79,6 +79,11 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol {
return OPT_IN;
}
@Override
public boolean isDeprecated() {
return true;
}
@Override
public String getName() {
return handler.isEnabled() ? handler.getName() : null;
......
......@@ -53,6 +53,11 @@ public class JnlpSlaveAgentProtocol2 extends AgentProtocol {
return false;
}
@Override
public boolean isDeprecated() {
return true;
}
/**
* {@inheritDoc}
*/
......
......@@ -67,6 +67,11 @@ public class JnlpSlaveAgentProtocol3 extends AgentProtocol {
return Messages.JnlpSlaveAgentProtocol3_displayName();
}
@Override
public boolean isDeprecated() {
return true;
}
@Override
public void handle(Socket socket) throws IOException, InterruptedException {
handler.handle(socket,
......
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
${%message}
</j:jelly>
message=This protocol is an obsolete protocol, which has been replaced by CLI2-connect. \
It is also not encrypted.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
${%message}
</j:jelly>
message=Remoting-based CLI is deprecated and not recommended due to the security reasons. \
It is recommended to disable this protocol on the instance. \
if you need Remoting CLI on your instance, this protocol has to be enabled.
......@@ -72,6 +72,11 @@ l.layout(norefresh:true, permission:app.ADMINISTER, title:my.displayName, csscla
td(colspan:"2");
td(class:"setting-description"){
st.include(from:p, page: "description", optional:true);
if (p.deprecated) {
br()
text(b(_("Deprecated. ")))
st.include(from:p, page: "deprecationCause", optional:true);
}
}
td();
}
......
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
<div class="warning">
${%blurb(it.deprecatedProtocols)}
<a href="${rootURL}/configureSecurity">${%Protocol Configuration}</a>
</div>
</j:jelly>
blurb=This Jenkins instance uses deprecated protocols: {0}. \
It may impact stability of the instance. \
If newer protocol versions are supported by all system components (agents, CLI and other clients), \
it is highly recommended to disable the deprecated protocols.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
${%message}
</j:jelly>
message=This protocol is an obsolete protocol, which has been replaced by JNLP2-connect. \
It is also not encrypted.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
${%message}
<a href="https://jenkins.io/redirect/project/remoting/protocols/jnlp2-errata">${%JNLP2 Protocol Errata}</a>
</j:jelly>
message=This protocol has known stability issues, and it is replaced by JNLP4. \
It is also not encrypted. \
See more information in the protocol Errata.
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core">
${%This protocol is unstable. See the protocol documentation for more info.}
<a href="https://jenkins.io/redirect/project/remoting/protocols/jnlp3-errata">${%JNLP3 Protocol Errata}</a>
</j:jelly>
summary=Extends the version 2 protocol by adding basic encryption but requires a thread per client. \
This protocol falls back to Java Web Start Agent Protocol/2 (unencrypted) when it can't create a secure connection. \
This protocol is not recommended. \
Use Java Web Start Agent Protocol/4 instead.
summary=Extends the version 2 protocol by adding basic encryption but requires a thread per client.
......@@ -20,6 +20,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
summary=Erweitert das Protokoll Version 2 um einfache Verschl\u00FCsselung, aber erfordert einen Thread pro Client. \
Dieses Protokoll f\u00E4llt auf Protokoll-Version 2 (unverschl\u00FCsselt) zur\u00FCck, wenn keine sichere Verbindung hergestellt werden kann. \
Dieses Protokoll sollte nicht verwendet werden, stattdessen sollte Protokoll-Version 4 verwendet werden.
summary=Erweitert das Protokoll Version 2 um einfache Verschl\u00fcsselung, aber erfordert einen Thread pro Client.
......@@ -20,7 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
JnlpSlaveAgentProtocol.displayName=Java Web Start Agent Protocol/1 (unencrypted)
JnlpSlaveAgentProtocol2.displayName=Java Web Start Agent Protocol/2 (unencrypted)
JnlpSlaveAgentProtocol3.displayName=Java Web Start Agent Protocol/3 (basic encryption)
JnlpSlaveAgentProtocol.displayName=Java Web Start Agent Protocol/1 (deprecated, unencrypted)
JnlpSlaveAgentProtocol2.displayName=Java Web Start Agent Protocol/2 (deprecated, unencrypted)
JnlpSlaveAgentProtocol3.displayName=Java Web Start Agent Protocol/3 (deprecated, basic encryption)
JnlpSlaveAgentProtocol4.displayName=Java Web Start Agent Protocol/4 (TLS encryption)
DeprecatedAgentProtocolMonitor.displayName=Deprecated Agent Protocol Monitor
/*
* The MIT License
*
* Copyright (c) 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
import jenkins.install.SetupWizardTest;
import jenkins.model.Jenkins;
import jenkins.slaves.DeprecatedAgentProtocolMonitor;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang.StringUtils;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import org.hamcrest.core.StringContains;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.recipes.LocalData;
/**
* Tests for {@link AgentProtocol}.
*
* @author Oleg Nenashev
*/
public class AgentProtocolTest {
@Rule
public JenkinsRule j = new JenkinsRule();
/**
* Checks that Jenkins does not disable agent protocols by default after the upgrade.
*
* @throws Exception Test failure
* @see SetupWizardTest#shouldDisableUnencryptedProtocolsByDefault()
*/
@Test
@LocalData
@Issue("JENKINS-45841")
public void testShouldNotDisableProtocolsForMigratedInstances() throws Exception {
assertProtocols(true, "Legacy Non-encrypted JNLP/CLI protocols should be enabled",
"JNLP-connect", "JNLP2-connect", "JNLP4-connect", "CLI-connect");
assertProtocols(true, "Default encrypted protocols should be enabled", "JNLP4-connect", "CLI2-connect");
assertProtocols(true, "Protocol should be enabled due to CLI settings", "CLI2-connect");
assertProtocols(false, "JNLP3-connect protocol should be disabled by default", "JNLP3-connect");
assertMonitorTriggered("JNLP-connect", "JNLP2-connect", "CLI-connect");
}
@Test
@LocalData
@Issue("JENKINS-45841")
public void testShouldNotOverrideUserConfiguration() throws Exception {
assertEnabled("CLI-connect", "JNLP-connect", "JNLP3-connect");
assertDisabled("CLI2-connect", "JNLP2-connect", "JNLP4-connect");
assertProtocols(true, "System protocols should be always enabled", "Ping");
assertMonitorTriggered("JNLP-connect", "JNLP3-connect", "CLI-connect");
}
@Test
@LocalData
public void testShouldDisableCLIProtocolsWhenCLIisDisabled() throws Exception {
assertProtocols(false, "CLI is forcefully disabled, protocols should be blocked",
"CLI-connect", "CLI2-connect");
assertEnabled("JNLP3-connect");
assertMonitorTriggered("JNLP3-connect");
}
private void assertEnabled(String ... protocolNames) throws AssertionError {
assertProtocols(true, null, protocolNames);
}
private void assertDisabled(String ... protocolNames) throws AssertionError {
assertProtocols(false, null, protocolNames);
}
private void assertProtocols(boolean shouldBeEnabled, @CheckForNull String why, String ... protocolNames) {
assertProtocols(j.jenkins, shouldBeEnabled, why, protocolNames);
}
public static void assertProtocols(Jenkins jenkins, boolean shouldBeEnabled, @CheckForNull String why, String ... protocolNames)
throws AssertionError {
Set<String> agentProtocols = jenkins.getAgentProtocols();
List<String> failedChecks = new ArrayList<>();
for (String protocol : protocolNames) {
if (shouldBeEnabled && !(agentProtocols.contains(protocol))) {
failedChecks.add(protocol);
}
if (!shouldBeEnabled && agentProtocols.contains(protocol)) {
failedChecks.add(protocol);
}
}
if (!failedChecks.isEmpty()) {
String message = String.format("Protocol(s) are not %s: %s. %sEnabled protocols: %s",
shouldBeEnabled ? "enabled" : "disabled",
StringUtils.join(failedChecks, ','),
why != null ? "Reason: " + why + ". " : "",
StringUtils.join(agentProtocols, ','));
fail(message);
}
}
public static void assertMonitorNotActive() {
DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor();
assertFalse("Deprecated Agent Protocol Monitor should not be activated", monitor.isActivated());
}
public static void assertMonitorTriggered(String ... expectedProtocols) {
DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor();
assertTrue("Deprecated Agent Protocol Monitor should be activated", monitor.isActivated());
String protocolList = monitor.getDeprecatedProtocols();
assertThat("List of the protocols should not be null", protocolList, not(nullValue()));
List<String> failedChecks = new ArrayList<>();
for(String protocol : expectedProtocols) {
if (!protocolList.contains(protocol)) {
failedChecks.add(protocol);
}
}
if (!failedChecks.isEmpty()) {
String message = String.format(
"Protocol(s) should in the deprecated protocol list: %s. Current list: %s",
StringUtils.join(expectedProtocols, ','), protocolList);
fail(message);
}
}
}
......@@ -32,6 +32,9 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Set;
import jenkins.AgentProtocolTest;
import jenkins.slaves.DeprecatedAgentProtocolMonitor;
import org.apache.commons.io.FileUtils;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
......@@ -39,6 +42,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertFalse;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue;
......@@ -111,6 +115,17 @@ public class SetupWizardTest {
wc.assertFails("setupWizard/completeInstall", 403);
}
@Test
@Issue("JENKINS-45841")
public void shouldDisableUnencryptedProtocolsByDefault() throws Exception {
AgentProtocolTest.assertProtocols(j.jenkins, true,
"Encrypted JNLP4-protocols protocol should be enabled", "JNLP4-connect");
AgentProtocolTest.assertProtocols(j.jenkins, false,
"Non-encrypted JNLP protocols should be disabled by default",
"JNLP-connect", "JNLP2-connect", "CLI-connect");
AgentProtocolTest.assertMonitorNotActive();
}
private String jsonRequest(JenkinsRule.WebClient wc, String path) throws Exception {
// Try to call the actions method to retrieve the data
final Page res;
......
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>1.0</version>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.SecurityRealm$None"/>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${ITEM_ROOTDIR}/workspace</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds/>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>all</primaryView>
<slaveAgentPort>0</slaveAgentPort>
<enabledAgentProtocols>
<string>CLI-connect</string>
<string>CLI2-connect</string>
<string>JNLP3-connect</string>
</enabledAgentProtocols>
<disabledAgentProtocols>
<string>JNLP4-connect</string>
</disabledAgentProtocols>
<label></label>
<nodeProperties/>
<globalNodeProperties/>
</hudson>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8'?>
<jenkins.CLI>
<enabled>false</enabled>
</jenkins.CLI>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>1.0</version>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.SecurityRealm$None"/>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${ITEM_ROOTDIR}/workspace</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds/>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>all</primaryView>
<slaveAgentPort>0</slaveAgentPort>
<!-- Disabled to emulate defaults
<enabledAgentProtocols>
<string>JNLP4-connect</string>
</enabledAgentProtocols>
-->
<label></label>
<nodeProperties/>
<globalNodeProperties/>
</hudson>
\ No newline at end of file
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>1.0</version>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.SecurityRealm$None"/>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${ITEM_ROOTDIR}/workspace</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds/>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>all</primaryView>
<slaveAgentPort>0</slaveAgentPort>
<!-- YOLO: unstable configuration -->
<enabledAgentProtocols>
<string>CLI-connect</string>
<string>JNLP-connect</string>
<string>JNLP3-connect</string>
</enabledAgentProtocols>
<disabledAgentProtocols>
<string>JNLP4-connect</string>
<string>JNLP2-connect</string>
<string>CLI2-connect</string>
</disabledAgentProtocols>
<label></label>
<nodeProperties/>
<globalNodeProperties/>
</hudson>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册