提交 e376780c 编写于 作者: J Jesse Glick

[JENKINS-47393] Preparation for split of CommandLauncher to a plugin.

上级 860d9c54
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.34</version>
<relativePath />
</parent>
<artifactId>command-launcher</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>hpi</packaging>
<properties>
<jenkins.version>2.85-SNAPSHOT</jenkins.version> <!-- TODO pending split -->
<java.level>8</java.level>
</properties>
<name>Command Launcher Plugin</name>
<description>Allows agents to be launched using a specified command.</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/Command+Launcher+Plugin</url>
<licenses>
<license>
<name>MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<!-- TODO after split
<scm>
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
<developerConnection>scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
<url>https://github.com/jenkinsci/${project.artifactId}-plugin</url>
</scm>
-->
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>script-security</artifactId>
<version>1.18.1</version>
</dependency>
</dependencies>
</project>
......@@ -28,11 +28,13 @@ import hudson.Extension;
import hudson.Util;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
import java.io.IOException;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.command_launcher.CommandLanguage;
import org.jenkinsci.plugins.command_launcher.Messages;
import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext;
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.IOException;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.QueryParameter;
/**
......@@ -46,17 +48,19 @@ public class CommandConnector extends ComputerConnector {
@DataBoundConstructor
public CommandConnector(String command) {
this.command = command;
Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS);
// TODO add withKey if we can determine the Cloud.name being configured
ScriptApproval.get().configuring(command, CommandLanguage.get(), ApprovalContext.create().withCurrentUser());
}
private Object readResolve() {
Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS);
ScriptApproval.get().configuring(command, CommandLanguage.get(), ApprovalContext.create());
return this;
}
@Override
public CommandLauncher launch(String host, TaskListener listener) throws IOException, InterruptedException {
return new CommandLauncher(command,new EnvVars("SLAVE",host));
// no need to call ScriptApproval.using here; CommandLauncher.launch will do that
return new CommandLauncher(new EnvVars("SLAVE", host), command);
}
@Extension @Symbol("command")
......@@ -67,13 +71,10 @@ public class CommandConnector extends ComputerConnector {
}
public FormValidation doCheckCommand(@QueryParameter String value) {
if (!Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
return FormValidation.warning(Messages.CommandLauncher_cannot_be_configured_by_non_administrato());
}
if (Util.fixEmptyAndTrim(value) == null) {
return FormValidation.error(Messages.CommandLauncher_NoLaunchCommand());
} else {
return FormValidation.ok();
return ScriptApproval.get().checking(value, CommandLanguage.get());
}
}
......
......@@ -33,7 +33,6 @@ import hudson.model.Slave;
import jenkins.model.Jenkins;
import hudson.model.TaskListener;
import hudson.remoting.Channel;
import hudson.security.ACL;
import hudson.util.StreamCopyThread;
import hudson.util.FormValidation;
import hudson.util.ProcessTree;
......@@ -45,6 +44,10 @@ import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.command_launcher.CommandLanguage;
import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext;
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import org.jenkinsci.plugins.scriptsecurity.scripts.UnapprovedUsageException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
......@@ -67,19 +70,30 @@ public class CommandLauncher extends ComputerLauncher {
*/
private final EnvVars env;
/** Constructor for use from UI. Conditionally approves the script. */
@DataBoundConstructor
public CommandLauncher(String command) {
this(command, null);
agentCommand = command;
env = null;
// TODO add withKey if we can determine the Slave.nodeName being configured
ScriptApproval.get().configuring(command, CommandLanguage.get(), ApprovalContext.create().withCurrentUser());
}
/** Constructor for programmatic use. Always approves the script. */
public CommandLauncher(String command, EnvVars env) {
this.agentCommand = command;
this.env = env;
Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS);
ScriptApproval.get().preapprove(command, CommandLanguage.get());
}
/** Constructor for use from {@link CommandConnector}. Never approves the script. */
CommandLauncher(EnvVars env, String command) {
this.agentCommand = command;
this.env = env;
}
private Object readResolve() {
Jenkins.getInstance().checkPermission(Jenkins.RUN_SCRIPTS);
ScriptApproval.get().configuring(agentCommand, CommandLanguage.get(), ApprovalContext.create());
return this;
}
......@@ -104,14 +118,15 @@ public class CommandLauncher extends ComputerLauncher {
throw new AbortException("Cannot launch commands on deleted nodes");
}
listener.getLogger().println(hudson.model.Messages.Slave_Launching(getTimestamp()));
if(getCommand().trim().length()==0) {
listener.getLogger().println(Messages.CommandLauncher_NoLaunchCommand());
listener.getLogger().println(org.jenkinsci.plugins.command_launcher.Messages.Slave_Launching(getTimestamp()));
String command = ScriptApproval.get().using(getCommand(), CommandLanguage.get());
if (command.trim().length() == 0) {
listener.getLogger().println(org.jenkinsci.plugins.command_launcher.Messages.CommandLauncher_NoLaunchCommand());
return;
}
listener.getLogger().println("$ " + getCommand());
listener.getLogger().println("$ " + command);
ProcessBuilder pb = new ProcessBuilder(Util.tokenize(getCommand()));
ProcessBuilder pb = new ProcessBuilder(Util.tokenize(command));
final EnvVars cookie = _cookie = EnvVars.createCookie();
pb.environment().putAll(cookie);
pb.environment().put("WORKSPACE", StringUtils.defaultString(computer.getAbsoluteRemoteFs(), node.getRemoteFS())); //path for local slave log
......@@ -153,6 +168,8 @@ public class CommandLauncher extends ComputerLauncher {
LOGGER.info("agent launched for " + computer.getDisplayName());
} catch (InterruptedException e) {
Functions.printStackTrace(e, listener.error(Messages.ComputerLauncher_abortedLaunch()));
} catch (UnapprovedUsageException e) {
listener.error(e.getMessage());
} catch (RuntimeException e) {
Functions.printStackTrace(e, listener.error(Messages.ComputerLauncher_unexpectedError()));
} catch (Error e) {
......@@ -167,7 +184,7 @@ public class CommandLauncher extends ComputerLauncher {
msg = " : " + msg;
// FIXME TODO i18n what is this!?
}
msg = hudson.model.Messages.Slave_UnableToLaunch(computer.getDisplayName(), msg);
msg = org.jenkinsci.plugins.command_launcher.Messages.Slave_UnableToLaunch(computer.getDisplayName(), msg);
LOGGER.log(Level.SEVERE, msg, e);
Functions.printStackTrace(e, listener.error(msg));
......@@ -196,17 +213,14 @@ public class CommandLauncher extends ComputerLauncher {
@Extension @Symbol("command")
public static class DescriptorImpl extends Descriptor<ComputerLauncher> {
public String getDisplayName() {
return Messages.CommandLauncher_displayName();
return org.jenkinsci.plugins.command_launcher.Messages.CommandLauncher_displayName();
}
public FormValidation doCheckCommand(@QueryParameter String value) {
if (!Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
return FormValidation.warning(Messages.CommandLauncher_cannot_be_configured_by_non_administrato());
}
if(Util.fixEmptyAndTrim(value)==null)
return FormValidation.error(Messages.CommandLauncher_NoLaunchCommand());
return FormValidation.error(org.jenkinsci.plugins.command_launcher.Messages.CommandLauncher_NoLaunchCommand());
else
return FormValidation.ok();
return ScriptApproval.get().checking(value, CommandLanguage.get());
}
}
}
/*
* The MIT License
*
* Copyright 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 org.jenkinsci.plugins.command_launcher;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.Util;
import org.jenkinsci.plugins.scriptsecurity.scripts.Language;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Language for launched processes, as per {@link Util#tokenize(String)} and {@link ProcessBuilder}.
*/
@Restricted(NoExternalUse.class) // TODO move to script-security
@Extension
public class CommandLanguage extends Language {
public static Language get() {
return ExtensionList.lookup(Language.class).get(CommandLanguage.class);
}
@Override
public String getName() {
return "command";
}
@Override
public String getDisplayName() {
return "External Commands";
}
}
<?jelly escape-by-default='true'?>
<div>
Allows agents to be launched using a specified command.
</div>
# The MIT License
#
# Copyright 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.
Slave.Launching={0} Launching agent
CommandLauncher.NoLaunchCommand=No launch command specified
CommandLauncher.displayName=Launch agent via execution of command on the master
Slave.UnableToLaunch=Unable to launch the agent for {0}{1}
CommandLauncher.NoLaunchCommand=\
\u041d\u0435 \u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435.
CommandLauncher.displayName=\
\u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0433\u0435\u043d\u0442 \u0447\u0440\u0435\u0437 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440
Slave.UnableToLaunch=\
\u0410\u0433\u0435\u043d\u0442\u044a\u0442 \u0437\u0430 {0}{1} \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430
Slave.Launching=Starte Agenten
CommandLauncher.NoLaunchCommand=Kein Startkommando angegeben.
CommandLauncher.displayName=Agent durch Ausf\u00FChrung eines Befehls auf dem Master-Knoten starten
Slave.UnableToLaunch=Kann Agent \u201E{0}\u201C nicht starten{1}
Slave.Launching={0} Arrancando el agente
CommandLauncher.NoLaunchCommand=No se ha especificado ningún comando
Slave.UnableToLaunch=Imposible ejecutar el agente en {0}{1}
CommandLauncher.NoLaunchCommand=Aucune commande de lancement sp\u00e9cifi\u00e9e
CommandLauncher.NoLaunchCommand=\u8d77\u52d5\u30b3\u30de\u30f3\u30c9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
Slave.Launching={0} Paleid\u017eiamas agentas
Slave.UnableToLaunch=Nepavyksta paleisti agento skirto {0}{1}
CommandLauncher.NoLaunchCommand=Sem nenhum comando de lan\u00e7amento especificado
Slave.Launching={0} \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0442\u043E\u043C
CommandLauncher.NoLaunchCommand=\u041D\u0438\u0458\u0435 \u043D\u0430\u0432\u0435\u0434\u0435\u043D\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0430 \u0437\u0430 \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435.
CommandLauncher.displayName=\u041F\u043E\u043A\u0440\u0435\u043D\u0438 \u0430\u0433\u0435\u043D\u0442\u0430 \u0438\u0437\u0432\u0440\u0448\u0430\u0432\u0430\u045A\u0443 \u043A\u043E\u043C\u0430\u043D\u0434\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u043E\u0458 \u043C\u0430\u0448\u0438\u043D\u0438
Slave.UnableToLaunch=\u0410\u0433\u0435\u043D\u0430\u0442 \u0437\u0430 {0}{1} \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u043E\u043A\u0440\u0435\u043D\u0435
CommandLauncher.NoLaunchCommand=\u6c92\u6709\u6307\u5b9a\u555f\u52d5\u6307\u4ee4
......@@ -28,7 +28,7 @@ import org.jvnet.hudson.test.HudsonTestCase;
/**
* @author Kohsuke Kawaguchi
*/
public class ComputerConnectorTest extends HudsonTestCase {
public class CommandConnectorTest extends HudsonTestCase {
public void testConfigRoundtrip() throws Exception {
CommandConnector cc = new CommandConnector("abc def");
assertEqualDataBoundBeans(cc,configRoundtrip(cc));
......
......@@ -24,7 +24,6 @@
package hudson.slaves;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
......@@ -37,19 +36,23 @@ import hudson.model.Computer;
import hudson.model.User;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Collections;
import java.util.Set;
import javax.annotation.CheckForNull;
import jenkins.model.Jenkins;
import org.apache.tools.ant.filters.StringInputStream;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
import org.jenkinsci.plugins.command_launcher.CommandLanguage;
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.recipes.LocalData;
public class CommandLauncher2Test {
......@@ -58,14 +61,15 @@ public class CommandLauncher2Test {
@Issue("SECURITY-478")
@Test
public void requireRunScripts() throws Exception {
rr.addStep(new Statement() {
public void requireApproval() throws Exception {
rr.addStep(new Statement() { // TODO .then, when using sufficiently new jenkins-test-harness
@Override
public void evaluate() throws Throwable {
rr.j.jenkins.setSecurityRealm(rr.j.createDummySecurityRealm());
rr.j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.ADMINISTER).everywhere().to("admin").
grant(Jenkins.READ, Computer.CONFIGURE).everywhere().to("dev"));
ScriptApproval.get().preapprove("echo unconfigured", CommandLanguage.get());
DumbSlave s = new DumbSlave("s", "/", new CommandLauncher("echo unconfigured"));
rr.j.jenkins.addNode(s);
// First, reconfigure using GUI.
......@@ -95,48 +99,58 @@ public class CommandLauncher2Test {
assertThat(new CLICommandInvoker(rr.j, cmd).withStdin(new StringInputStream(xml.replace("echo configured by GUI", "echo configured by CLI"))).invokeWithArgs("s"), CLICommandInvoker.Matcher.succeededSilently());
s = (DumbSlave) rr.j.jenkins.getNode("s");
assertEquals("echo configured by CLI", ((CommandLauncher) s.getLauncher()).getCommand());
assertEquals(Collections.emptySet(), ScriptApproval.get().getPendingScripts());
assertSerialForm(s, "echo configured by CLI");
// Now verify that all modes failed as dev. First as GUI.
ScriptApproval.get().preapprove("echo configured by admin", CommandLanguage.get());
s.setLauncher(new CommandLauncher("echo configured by admin"));
s.save();
wc = rr.j.createWebClient().login("dev");
form = wc.getPage(s, "configure").getFormByName("config");
input = form.getInputByName("_.command");
assertEquals("echo configured by admin", input.getText());
input.setText("echo ATTACK");
try {
rr.j.submit(form);
fail();
} catch (FailingHttpStatusCodeException x) {
assertEquals("403 would be more natural but Descriptor.newInstance wraps AccessDeniedException2 in Error", 500, x.getStatusCode());
}
input.setText("echo GUI ATTACK");
rr.j.submit(form);
s = (DumbSlave) rr.j.jenkins.getNode("s");
assertEquals("echo configured by admin", ((CommandLauncher) s.getLauncher()).getCommand());
assertSerialForm(s, "echo configured by admin");
assertEquals("echo GUI ATTACK", ((CommandLauncher) s.getLauncher()).getCommand());
Set<ScriptApproval.PendingScript> pendingScripts = ScriptApproval.get().getPendingScripts();
assertEquals(1, pendingScripts.size());
ScriptApproval.PendingScript pendingScript = pendingScripts.iterator().next();
assertEquals(CommandLanguage.get(), pendingScript.getLanguage());
assertEquals("echo GUI ATTACK", pendingScript.script);
assertEquals("dev", pendingScript.getContext().getUser());
ScriptApproval.get().denyScript(pendingScript.getHash());
assertSerialForm(s, "echo GUI ATTACK");
// Then by REST.
req = new WebRequest(wc.createCrumbedUrl(configDotXml), HttpMethod.POST);
req.setEncodingType(null);
req.setRequestBody(xml.replace("echo configured by GUI", "echo ATTACK"));
try {
wc.getPage(req);
} catch (FailingHttpStatusCodeException x) {
assertEquals(HttpURLConnection.HTTP_FORBIDDEN, x.getStatusCode());
}
req.setRequestBody(xml.replace("echo configured by GUI", "echo REST ATTACK"));
wc.getPage(req);
s = (DumbSlave) rr.j.jenkins.getNode("s");
assertNotEquals(CommandLauncher.class, s.getLauncher().getClass()); // currently seems to reset it to JNLPLauncher, whatever
assertSerialForm(s, null);
s.setLauncher(new CommandLauncher("echo configured by admin"));
assertEquals("echo REST ATTACK", ((CommandLauncher) s.getLauncher()).getCommand());
pendingScripts = ScriptApproval.get().getPendingScripts();
assertEquals(1, pendingScripts.size());
pendingScript = pendingScripts.iterator().next();
assertEquals(CommandLanguage.get(), pendingScript.getLanguage());
assertEquals("echo REST ATTACK", pendingScript.script);
assertEquals(/* deserialization, not recording user */ null, pendingScript.getContext().getUser());
ScriptApproval.get().denyScript(pendingScript.getHash());
assertSerialForm(s, "echo REST ATTACK");
// Then by CLI.
cmd = new UpdateNodeCommand();
cmd.setTransportAuth(User.get("dev").impersonate());
assertThat(new CLICommandInvoker(rr.j, cmd).withStdin(new StringInputStream(xml.replace("echo configured by GUI", "echo ATTACK"))).invokeWithArgs("s"),
CLICommandInvoker.Matcher./* gets swallowed by RobustReflectionConverter, hmm*/succeededSilently());
assertThat(new CLICommandInvoker(rr.j, cmd).withStdin(new StringInputStream(xml.replace("echo configured by GUI", "echo CLI ATTACK"))).invokeWithArgs("s"), CLICommandInvoker.Matcher.succeededSilently());
s = (DumbSlave) rr.j.jenkins.getNode("s");
assertNotEquals(CommandLauncher.class, s.getLauncher().getClass());
assertSerialForm(s, null);
assertEquals("echo CLI ATTACK", ((CommandLauncher) s.getLauncher()).getCommand());
pendingScripts = ScriptApproval.get().getPendingScripts();
assertEquals(1, pendingScripts.size());
pendingScript = pendingScripts.iterator().next();
assertEquals(CommandLanguage.get(), pendingScript.getLanguage());
assertEquals("echo CLI ATTACK", pendingScript.script);
assertEquals(/* ditto */null, pendingScript.getContext().getUser());
ScriptApproval.get().denyScript(pendingScript.getHash());
assertSerialForm(s, "echo CLI ATTACK");
// Now also check that SYSTEM deserialization works after a restart.
s.setLauncher(new CommandLauncher("echo configured by admin"));
s.save();
}
private void assertSerialForm(DumbSlave s, @CheckForNull String expectedCommand) throws IOException {
// cf. private methods in Nodes
......@@ -149,7 +163,26 @@ public class CommandLauncher2Test {
@Override
public void evaluate() throws Throwable {
DumbSlave s = (DumbSlave) rr.j.jenkins.getNode("s");
assertEquals("echo configured by admin", ((CommandLauncher) s.getLauncher()).getCommand());
assertEquals("echo CLI ATTACK", ((CommandLauncher) s.getLauncher()).getCommand());
Set<ScriptApproval.PendingScript> pendingScripts = ScriptApproval.get().getPendingScripts();
assertEquals(1, pendingScripts.size());
ScriptApproval.PendingScript pendingScript = pendingScripts.iterator().next();
assertEquals(CommandLanguage.get(), pendingScript.getLanguage());
assertEquals("echo CLI ATTACK", pendingScript.script);
assertEquals(/* ditto */null, pendingScript.getContext().getUser());
}
});
}
@LocalData // saved by Hudson 1.215
@Test
public void ancientSerialForm() {
rr.addStep(new Statement() {
@Override
public void evaluate() throws Throwable {
ComputerLauncher launcher = ((DumbSlave) rr.j.jenkins.getNode("test")).getLauncher();
assertThat(launcher, instanceOf(CommandLauncher.class));
assertEquals("echo from CLI", ((CommandLauncher) launcher).getCommand());
}
});
}
......
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<numExecutors>2</numExecutors>
<authorizationStrategy class="hudson.security.AuthorizationStrategy$Unsecured"/>
<securityRealm class="hudson.security.SecurityRealm$None"/>
<jdks/>
<slaves>
<slave>
<name>test</name>
<description></description>
<remoteFS>/tmp</remoteFS>
<numExecutors>1</numExecutors>
<mode>NORMAL</mode>
<agentCommand>echo from CLI</agentCommand>
<label></label>
</slave>
</slaves>
<quietPeriod>5</quietPeriod>
<slaveAgentPort>0</slaveAgentPort>
<secretKey>ede47f10a483fb5bcc4ffe063a7890b847c31baffcecb124305738bc0d969b3d</secretKey>
</hudson>
\ No newline at end of file
......@@ -425,7 +425,8 @@ public class ClassicPluginStrategy implements PluginStrategy {
new DetachedPlugin("antisamy-markup-formatter", "1.553.*", "1.0"),
new DetachedPlugin("matrix-project", "1.561.*", "1.0"),
new DetachedPlugin("junit", "1.577.*", "1.0"),
new DetachedPlugin("bouncycastle-api", "2.16.*", "2.16.0")
new DetachedPlugin("bouncycastle-api", "2.16.*", "2.16.0"),
new DetachedPlugin("command-launcher", "2.85.*", "1.0-SNAPSHOT") // TODO update after split
));
/** Implicit dependencies that are known to be unnecessary and which must be cut out to prevent a dependency cycle among bundled plugins. */
......@@ -434,6 +435,8 @@ public class ClassicPluginStrategy implements PluginStrategy {
"script-security/windows-slaves",
"script-security/antisamy-markup-formatter",
"script-security/matrix-project",
"script-security/bouncycastle-api",
"script-security/command-launcher",
"credentials/matrix-auth",
"credentials/windows-slaves"
));
......
......@@ -26,6 +26,7 @@ package hudson.model;
import com.google.common.collect.ImmutableSet;
import hudson.DescriptorExtensionList;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Launcher.RemoteLauncher;
......@@ -34,7 +35,6 @@ import hudson.model.Descriptor.FormException;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.Which;
import hudson.slaves.CommandLauncher;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.DumbSlave;
import hudson.slaves.JNLPLauncher;
......@@ -225,6 +225,15 @@ public abstract class Slave extends Node implements Serializable {
}
public ComputerLauncher getLauncher() {
if (launcher == null && !StringUtils.isEmpty(agentCommand)) {
try {
launcher = (ComputerLauncher) Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.slaves.CommandLauncher").getConstructor(String.class, EnvVars.class).newInstance(agentCommand, null);
agentCommand = null;
save();
} catch (Exception x) {
LOGGER.log(Level.WARNING, "could not update historical agentCommand setting to CommandLauncher", x);
}
}
// Default launcher does not use Work Directory
return launcher == null ? new JNLPLauncher(false) : launcher;
}
......@@ -502,12 +511,6 @@ public abstract class Slave extends Node implements Serializable {
* Invoked by XStream when this object is read into memory.
*/
protected Object readResolve() {
// convert the old format to the new one
if (launcher == null) {
launcher = (agentCommand == null || agentCommand.trim().length() == 0)
? new JNLPLauncher(false)
: new CommandLauncher(agentCommand);
}
if(nodeProperties==null)
nodeProperties = new DescribableList<NodeProperty<?>,NodePropertyDescriptor>(Jenkins.getInstance().getNodesObject());
return this;
......
......@@ -239,14 +239,12 @@ Run.Summary.Unknown=?
Slave.InvalidConfig.Executors=Invalid agent configuration for {0}. Invalid # of executors.
Slave.InvalidConfig.NoName=Invalid agent configuration. Name is empty
Slave.Launching={0} Launching agent
Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the master.
Slave.Remote.Director.Mandatory=Remote directory is mandatory
Slave.Terminated={0} agent was terminated
Slave.Remote.Relative.Path.Warning=Are you sure you want to use a relative path for the FS root? Note that relative \
paths require that you can assure that the selected launcher provides a consistent current working directory. Using \
an absolute path is highly recommended.
Slave.UnableToLaunch=Unable to launch the agent for {0}{1}
Slave.UnixSlave=This is a Unix agent
Slave.WindowsSlave=This is a Windows agent
......
......@@ -626,9 +626,6 @@ Computer.BadChannel=\
Computer.DisconnectPermission.Description=\
\u0422\u043e\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0434\u0430\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u0434\u0430 \u043f\u0440\u0435\u043a\u044a\u0441\u0432\u0430\u0442\u0435 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u043a\u044a\u043c \u0430\u0433\u0435\u043d\u0442\u0438 \u0438\u043b\u0438 \u0434\u0430 \u0433\u0438\
\u043e\u0431\u044f\u0432\u044f\u0432\u0430\u0442\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0438\u0437\u0432\u044a\u043d \u043b\u0438\u043d\u0438\u044f.
# Unable to launch the agent for {0}{1}
Slave.UnableToLaunch=\
\u0410\u0433\u0435\u043d\u0442\u044a\u0442 \u0437\u0430 {0}{1} \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430
# This permission allows users to run jobs as them on agents.
Computer.BuildPermission.Description=\
\u0422\u043e\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0434\u0430\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430 \u0430\u0433\u0435\u043d\u0442\u0438\u0442\u0435\
......@@ -691,9 +688,6 @@ Computer.DeletePermission.Description=\
# Agent
Computer.Permissions.Title=\
\u0410\u0433\u0435\u043d\u0442
# {0} Launching agent
Slave.Launching=\
TODO
# This is a Unix agent
Slave.UnixSlave=\
\u0422\u043e\u0432\u0430 \u0435 \u0430\u0433\u0435\u043d\u0442 \u0437\u0430 Unix
......
......@@ -262,13 +262,11 @@ Run.Summary.Unknown=Ergebnis unbekannt
Slave.InvalidConfig.Executors=Ung\u00FCltige Agenten-Konfiguration f\u00FCr \u201E{0}\u201C: Ung\u00FCltige Zahl von Build-Prozessoren
Slave.InvalidConfig.NoName=Ung\u00FCltige Agenten-Konfiguration f\u00FCr \u201E{0}\u201C: Name ist leer
Slave.Launching=Starte Agenten
Slave.Network.Mounted.File.System.Warning=\
Sind Sie sicher, dass Sie ein Netzlaufwerk als Stammverzeichnis verwenden m\u00F6chten? \
Hinweis: Dieses Verzeichnis muss nicht vom Master-Knoten aus sichtbar sein.
Slave.Remote.Director.Mandatory=Ein Stammverzeichnis muss angegeben werden.
Slave.Remote.Relative.Path.Warning=M\u00F6chten Sie wirklich einen relativen Pfad als Stammverzeichnis verwenden? Hierbei ist wichtig, dass die Startmethode des Agenten ein konsistentes Arbeitsverzeichnis bereit stellt. Es wird daher empfohlen, einen absoluten Pfad anzugeben.
Slave.UnableToLaunch=Kann Agent \u201E{0}\u201C nicht starten{1}
Slave.UnixSlave=Dies ist ein Unix- oder Linux-Agent
Slave.WindowsSlave=Dies ist ein Windows-Agent
......
......@@ -154,9 +154,7 @@ Run.Summary.Unknown=?
Slave.InvalidConfig.Executors=Configuraci\u00f3n de nodo incorrecta en {0}. El n\u00famero de ejecutores es inv\u00e1lido.
Slave.InvalidConfig.NoName=Configuraci\u00f3n de nodo incorrecta. El nombre est\u00e1 vac\u00edo
Slave.Launching={0} Arrancando el agente
Slave.Terminated={0} el agente no est\u00e1 en ejecuci\u00f3n
Slave.UnableToLaunch=Imposible ejecutar el agente en {0}{1}
Slave.UnixSlave=Este es un nodo Unix
Slave.WindowsSlave=Este es un nodo Windows
......
......@@ -207,14 +207,12 @@ Run.Summary.Unknown=?
Slave.InvalidConfig.Executors=Netinkama agento {0} konfig\u016bracija. Netinkamas vykdytoj\u0173 skai\u010dius.
Slave.InvalidConfig.NoName=Netinkama agento konfig\u016bracija. Tu\u0161\u010dias pavadinimas
Slave.Launching={0} Paleid\u017eiamas agentas
Slave.Network.Mounted.File.System.Warning=Ar tikrai norite naudoti per tinkl\u0105 prijungt\u0105 fail\u0173 sistem\u0105 kaip FS \u0161ank\u012f? Pasteb\u0117tina, kad \u0161is aplankas neb\u016btinai turi b\u016bti matomas pagrindiniam mazgui.
Slave.Remote.Director.Mandatory=Nutol\u0119s aplankas yra privalomas
Slave.Terminated={0} agentas buvo nutrauktas
Slave.Remote.Relative.Path.Warning=Ar tikrai norite naudoti santykin\u012f keli\u0105, kaip FS \u0161akn\u012f? Pasteb\u0117tina, kad santykiniams \
keliams reikia, kad j\u016bs u\u017etikrintum\u0117te, kad parinktas paleid\u0117jas u\u017etikrina pastov\u0173 einam\u0105j\u012f darbin\u012f aplank\u0105. Primygtinai \
rekomenduojame naudoti absoliut\u0173 keli\u0105.
Slave.UnableToLaunch=Nepavyksta paleisti agento skirto {0}{1}
Slave.UnixSlave=Tai Unix agentas
Slave.WindowsSlave=Tai Windows agentas
......
......@@ -181,12 +181,10 @@ Run.Summary.BrokenSince=\u0441\u043B\u043E\u043C\u0459\u0435\u043D\u043E \u043E\
Run.Summary.Unknown=\u041D/\u0414
Slave.InvalidConfig.Executors=\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u043D\u043E \u043F\u043E\u0434\u0435\u0448\u0430\u0432\u0430\u045A\u0435 \u043D\u0430 \u0430\u0433\u0435\u043D\u0442\u0443 \u0437\u0430 {0}. \u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043D \u0431\u0440\u043E\u0458 \u0438\u0437\u0432\u0440\u0448\u0438\u0442\u0435\u0459\u0430.
Slave.InvalidConfig.NoName=\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u043D\u043E \u043F\u043E\u0434\u0435\u0448\u0430\u0432\u0430\u045A\u0435 \u043D\u0430 \u0430\u0433\u0435\u043D\u0442\u0443 \u2014 \u0438\u043C\u0435 \u0458\u0435 \u043F\u0440\u0430\u0437\u043D\u043E.
Slave.Launching={0} \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0442\u043E\u043C
Slave.Network.Mounted.File.System.Warning=\u0414\u0430 \u043B\u0438 \u0441\u0442\u0435 \u0441\u0438\u0433\u0443\u0440\u043D\u0438 \u0434\u0430 \u0436\u0435\u043B\u0438\u0442\u0435 \u0434\u0430 \u043A\u043E\u0440\u0438\u0441\u0442\u0438\u0442\u0435 \u043C\u0440\u0435\u0436\u043D\u0438 \u0441\u0438\u0441\u0442\u0435\u043C \u0434\u0430\u0442\u043E\u0442\u0435\u043A\u0430 \u0437\u0430 \u043A\u043E\u0440\u0435\u043D \u0442\u043E\u0433 \u0441\u0438\u0441\u0442\u0435\u043C\u0430. \u0414\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0458\u0443\u043C \u043D\u0435\u043C\u043E\u0440\u0430 \u0431\u0438\u0442\u0438 \u0432\u0438\u0434\u0459\u0438\u0432 \u043A\u043E\u0440\u0438\u0441\u043D\u0438\u043A\u0443.
Slave.Remote.Director.Mandatory=\u041E\u0431\u0430\u0432\u0435\u0437\u043D\u043E \u0458\u0435 \u0438\u043C\u0430\u0442\u0438 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0458\u0443\u043C \u043D\u0430 \u0434\u0430\u0459\u0438\u043D\u0438
Slave.Terminated=\u0410\u0433\u0435\u043D\u0442 {0} \u0458\u0435 \u0443\u043A\u043B\u043E\u045A\u0435\u043D
Slave.Remote.Relative.Path.Warning=\u0414\u0430 \u043B\u0438 \u0441\u0442\u0435 \u0441\u0438\u0433\u0443\u0440\u043D\u0438 \u0434\u0430 \u0436\u0435\u043B\u0438\u0442\u0435 \u0434\u0430 \u043A\u043E\u0440\u0438\u0441\u0442\u0438\u0442\u0435 \u0440\u0435\u043B\u0430\u0442\u0438\u0432\u043D\u0430 \u043F\u0443\u0442\u0435\u0432\u0430 \u0437\u0430 \u043A\u043E\u0440\u0435\u043D \u0441\u0438\u0441\u0442\u0435\u043C\u0430 \u0434\u0430\u0442\u043E\u0442\u0435\u043A\u0430. \u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u0435 \u0434\u0430 \u0438\u0437\u0430\u0431\u0440\u0430\u043D\u0438 \u043F\u0440\u043E\u0446\u0435\u0441 \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0430 \u043E\u0431\u0435\u0437\u0431\u0435\u0452\u0443\u0458\u0435 \u043A\u043E\u043D\u0441\u0438\u0441\u0442\u0435\u043D\u0442\u043D\u043E\u0433 \u0440\u0430\u0434\u043D\u043E\u0433 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0458\u0443\u043C\u0430. \u041F\u0440\u0435\u043F\u043E\u0440\u0443\u0447\u0443\u0458\u0435 \u0441\u0435 \u0434\u0430 \u043A\u043E\u0440\u0438\u0441\u0442\u0438\u0442\u0435 \u0430\u043F\u0441\u043E\u043B\u0443\u0442\u043D\u0430 \u043F\u0443\u0442\u0435\u0432\u0430.
Slave.UnableToLaunch=\u0410\u0433\u0435\u043D\u0430\u0442 \u0437\u0430 {0}{1} \u043D\u0435 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043F\u043E\u043A\u0440\u0435\u043D\u0435
Slave.UnixSlave=\u041E\u0432\u043E \u0458\u0435 \u0430\u0433\u0435\u043D\u0442 \u0437\u0430 Unix
TopLevelItemDescriptor.NotApplicableIn={0} \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0430 \u043D\u0435 \u043C\u043E\u0433\u0443 \u0441\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u0438 \u0443 {1}
Slave.WindowsSlave=\u041E\u0432\u043E \u0458\u0435 \u0430\u0433\u0435\u043D\u0442 \u0437\u0430 Windows
......
......@@ -23,12 +23,9 @@
RetentionStrategy.Always.displayName=Keep this agent online as much as possible
RetentionStrategy.Demand.displayName=Take this agent online when in demand, and offline when idle
RetentionStrategy.Demand.OfflineIdle=Offline because computer was idle; it will be relaunched when needed.
CommandLauncher.displayName=Launch agent via execution of command on the master
JNLPLauncher.displayName=Launch agent via Java Web Start
ComputerLauncher.unexpectedError=Unexpected error in launching an agent. This is probably a bug in Jenkins
ComputerLauncher.abortedLaunch=Launching agent process aborted.
CommandLauncher.cannot_be_configured_by_non_administrato=cannot be configured by non-administrators
CommandLauncher.NoLaunchCommand=No launch command specified
ConnectionActivityMonitor.OfflineCause=Repeated ping attempts failed
DumbSlave.displayName=Permanent Agent
NodeProvisioner.EmptyString=
......
......@@ -22,8 +22,6 @@
RetentionStrategy.Demand.OfflineIdle=\
\u041d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f, \u0437\u0430\u0449\u043e\u0442\u043e \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440\u044a\u0442 \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0430. \u0429\u0435 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442.
CommandLauncher.NoLaunchCommand=\
\u041d\u0435 \u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435.
ConnectionActivityMonitor.OfflineCause=\
\u041c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u0438\u0442\u0435 \u043e\u043f\u0438\u0442\u0438 \u0437\u0430 \u0432\u0440\u044a\u0437\u043a\u0430 \u0447\u0440\u0435\u0437 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201eping\u201c \u0441\u0430 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438
NodeProvisioner.EmptyString=\
......@@ -60,9 +58,6 @@ JNLPLauncher.displayName=\
# Keep this agent online as much as possible
RetentionStrategy.Always.displayName=\
\u0410\u0433\u0435\u043d\u0442\u044a\u0442 \u0434\u0430 \u0435 \u043e\u043d\u043b\u0430\u0439\u043d \u043a\u043e\u043b\u043a\u043e\u0442\u043e \u043c\u043e\u0436\u0435 \u043f\u043e-\u0434\u044a\u043b\u0433\u043e
# Launch agent via execution of command on the master
CommandLauncher.displayName=\
\u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0433\u0435\u043d\u0442 \u0447\u0440\u0435\u0437 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440
# This agent is offline because Jenkins failed to launch the agent process on it.
OfflineCause.LaunchFailed=\
\u0410\u0433\u0435\u043d\u0442\u044a\u0442 \u043d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f, \u0437\u0430\u0449\u043e\u0442\u043e Jenkins \u043d\u0435 \u0443\u0441\u043f\u044f \u0434\u0430 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0430 \u043c\u0443.
......
......@@ -23,7 +23,6 @@
RetentionStrategy.Demand.OfflineIdle=Offline da computeren var i tomgang; vil blive genstartet n\u00e5r n\u00f8dvendigt.
SimpleScheduledRetentionStrategy.FinishedUpTime=Computeren har afsluttet sin planlagte oppetid
EnvironmentVariablesNodeProperty.displayName=Milj\u00f8variable
CommandLauncher.NoLaunchCommand=Ingen opstartskommando givet
ConnectionActivityMonitor.OfflineCause=Gentagne pingfors\u00f8g fejlede
SlaveComputer.DisconnectedBy=Frakoblet af {0}{1}
NodeProvisioner.EmptyString=
......@@ -21,8 +21,6 @@
# THE SOFTWARE.
Cloud.ProvisionPermission.Description=Neue Agenten provisionieren
CommandLauncher.displayName=Agent durch Ausf\u00FChrung eines Befehls auf dem Master-Knoten starten
CommandLauncher.NoLaunchCommand=Kein Startkommando angegeben.
ComputerLauncher.abortedLaunch=Start des Agenten-Prozesses abgebrochen
ComputerLauncher.JavaVersionResult={0} -version ergab {1}.
ComputerLauncher.NoJavaFound=Java-Version {0} gefunden, aber 1.7 oder neuer ist n\u00F6tig.
......
......@@ -21,7 +21,6 @@
# THE SOFTWARE.
RetentionStrategy.Demand.OfflineIdle=Fuera de línea porque no es necesario, el servicio se volverá a iniciar cuando haya demanda
CommandLauncher.NoLaunchCommand=No se ha especificado ningún comando
ConnectionActivityMonitor.OfflineCause=No hubo respuesta a ''ping'' despues de varios intentos
SimpleScheduledRetentionStrategy.FinishedUpTime=El nodo ha finalizado el tiempo programado de estar on-line
EnvironmentVariablesNodeProperty.displayName=Variables de entorno
......
......@@ -20,5 +20,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
CommandLauncher.NoLaunchCommand=Aucune commande de lancement sp\u00e9cifi\u00e9e
EnvironmentVariablesNodeProperty.displayName=Variables d''environnement
......@@ -21,7 +21,6 @@
# THE SOFTWARE.
RetentionStrategy.Demand.OfflineIdle=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u304c\u5f85\u6a5f\u4e2d\u306a\u306e\u3067\u30aa\u30d5\u30e9\u30a4\u30f3\u3067\u3059\u3002\u5fc5\u8981\u306b\u306a\u3063\u305f\u3089\u518d\u3073\u8d77\u52d5\u3057\u307e\u3059\u3002
CommandLauncher.NoLaunchCommand=\u8d77\u52d5\u30b3\u30de\u30f3\u30c9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
ConnectionActivityMonitor.OfflineCause=\u4f55\u5ea6\u3082ping\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002
NodeProvisioner.EmptyString=
SimpleScheduledRetentionStrategy.FinishedUpTime=\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u306e\u52d5\u4f5c\u53ef\u80fd\u6642\u9593\u304c\u7d42\u4e86\u3057\u307e\u3057\u305f\u3002
......
......@@ -21,7 +21,6 @@
# THE SOFTWARE.
# No launch command specified
CommandLauncher.NoLaunchCommand=Sem nenhum comando de lan\u00e7amento especificado
# Offline because computer was idle; it will be relaunched when needed.
RetentionStrategy.Demand.OfflineIdle=Offline porque o computador estava ocioso; ser\u00e1 relan\u00e7ado quando necess\u00e1rio.
# Repeated ping attempts failed
......
......@@ -3,12 +3,10 @@
RetentionStrategy.Always.displayName=\u0414\u0440\u0436\u0438 \u043E\u0432\u043E\u0433 \u0430\u0433\u0435\u043D\u0442\u0430 \u043F\u043E\u0432\u0435\u0437\u0430\u043D\u043E\u0433 \u043A\u043E\u043B\u0438\u043A\u043E \u0433\u043E\u0434 \u043C\u043E\u0433\u0443\u045B\u0435
RetentionStrategy.Demand.displayName=\u041F\u043E\u0432\u0435\u0436\u0438 \u043E\u0432\u043E\u0433 \u0430\u0433\u0435\u043D\u0442\u0430 \u043A\u0430\u0434\u0430 \u0431\u0443\u0434\u0435 \u0431\u0438\u043B\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u043D\u043E, \u0430 \u043F\u0440\u0435\u043A\u0438\u043D\u0438 \u0432\u0435\u0437\u0443 \u043A\u0430\u0434\u0430 \u0437\u0430\u0441\u0442\u043E\u0458\u0438.
RetentionStrategy.Demand.OfflineIdle=\u041D\u0438\u0458\u0435 \u043F\u043E\u0432\u0435\u0437\u0430\u043D\u043E, \u0458\u0435\u0440 \u0458\u0435 \u043C\u0430\u0448\u0438\u043D\u0430 \u0437\u0430\u0441\u0442\u043E\u0458\u0430\u043D\u0430. \u0411\u0438\u045B\u0435 \u043F\u043E\u043A\u0440\u0435\u043D\u0443\u0442 \u043A\u0430\u0434\u0430 \u0431\u0443\u0434\u0435 \u0431\u0438\u043B\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u043D\u043E.
CommandLauncher.displayName=\u041F\u043E\u043A\u0440\u0435\u043D\u0438 \u0430\u0433\u0435\u043D\u0442\u0430 \u0438\u0437\u0432\u0440\u0448\u0430\u0432\u0430\u045A\u0443 \u043A\u043E\u043C\u0430\u043D\u0434\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u043E\u0458 \u043C\u0430\u0448\u0438\u043D\u0438
JNLPLauncher.displayName=\u041F\u043E\u043A\u0440\u0435\u043D\u0438 \u0430\u0433\u0435\u043D\u0442\u0430 \u0441\u0430 Java Web Start
ComputerLauncher.unexpectedError=\u041D\u0435\u043E\u0447\u0435\u043A\u0438\u0432\u0430\u043D\u0430 \u0433\u0440\u0435\u0448\u043A\u0430 \u043F\u0440\u0438\u043B\u0438\u043A\u043E\u043C \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0442\u0430. \u041E\u0432\u043E \u0458\u0435 \u0432\u0435\u0440\u043E\u0432\u0430\u0442\u043D\u043E \u0433\u0440\u0435\u0448\u043A\u0430 \u0443 Jenkins.
ComputerLauncher.abortedLaunch=\u041F\u0440\u043E\u0446\u0435\u0441 \u0437\u0430 \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0442\u0430 \u0458\u0435 \u043F\u0440\u0435\u043A\u0438\u043D\u0443\u0442.
ConnectionActivityMonitor.OfflineCause=\u041F\u043E\u043D\u043E\u0432\u0459\u0435\u043D\u0438 \u043F\u043E\u043A\u0443\u0448\u0430\u0458\u0438 \u0434\u0430 \u0441\u0435 \u0441\u0442\u0443\u043F\u0438 \u043A\u043E\u043D\u0442\u0430\u043A\u0442 \u043F\u0440\u0435\u043A\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0435 "ping" \u0441\u0443 \u043D\u0435\u0443\u0441\u043F\u0435\u0448\u043D\u0438.
CommandLauncher.NoLaunchCommand=\u041D\u0438\u0458\u0435 \u043D\u0430\u0432\u0435\u0434\u0435\u043D\u043E \u043A\u043E\u043C\u0430\u043D\u0434\u0430 \u0437\u0430 \u043F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435.
DumbSlave.displayName=\u0421\u0442\u0430\u043B\u043D\u0438 \u0430\u0433\u0435\u043D\u0442
NodeProvisioner.EmptyString=
OfflineCause.LaunchFailed=\u0410\u0433\u0435\u043D\u0442 \u043D\u0438\u0458\u0435 \u043F\u0440\u0438\u043A\u0459\u0443\u0447\u0435\u043D \u0458\u0435\u0440 Jenkins \u043D\u0438\u0458\u0435 \u0443\u0441\u043F\u0435\u043E \u0434\u0430 \u043F\u043E\u043A\u0440\u0435\u043D\u0435 \u043F\u0440\u043E\u0446\u0435\u0441 \u043D\u0430 \u045A\u0435\u0433\u0430.
......@@ -21,4 +19,4 @@ NodeDescripter.CheckName.Mandatory=\u0418\u043C\u0435 \u0458\u0435 \u043E\u0431\
ComputerLauncher.NoJavaFound=\u041F\u0440\u043E\u043D\u0430\u0452\u0435\u043D\u043E \u0458\u0435 Java \u0432\u0435\u0440\u0437\u0438\u0458\u0430 {0}, \u043C\u0435\u0452\u0443\u0442\u0438\u043C \u043F\u043E\u0442\u0440\u0435\u0431\u043D\u043E \u0458\u0435 \u0432\u0435\u0440\u0437\u0438\u0458\u0430 1.6.
ComputerLauncher.JavaVersionResult=\u041A\u043E\u043C\u0430\u043D\u0434\u0430 {0} -version \u0458\u0435 \u0432\u0440\u0430\u0442\u0438\u043B\u043E {1}.
ComputerLauncher.UknownJavaVersion=\u041D\u0438\u0458\u0435 \u043C\u043E\u0433\u0443\u045B\u0435 \u043E\u0434\u0440\u0435\u0434\u0438\u0438\u0442\u0438 Java \u0432\u0435\u0440\u0437\u0438\u0458\u0443 {0}
Cloud.ProvisionPermission.Description=\u041E\u0434\u0440\u0435\u0434\u0438 \u043D\u043E\u0432\u0435 \u043C\u0430\u0448\u0438\u043D\u0435
\ No newline at end of file
Cloud.ProvisionPermission.Description=\u041E\u0434\u0440\u0435\u0434\u0438 \u043D\u043E\u0432\u0435 \u043C\u0430\u0448\u0438\u043D\u0435
......@@ -20,7 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
CommandLauncher.NoLaunchCommand=\u6c92\u6709\u6307\u5b9a\u555f\u52d5\u6307\u4ee4
ComputerLauncher.JavaVersionResult={0} -version \u56de\u50b3 {1}\u3002
ComputerLauncher.NoJavaFound=\u627e\u5230 Java {0} \u7248\uff0c\u4e0d\u904e\u6211\u5011\u8981\u7684\u662f 1.5 \u6216\u66f4\u65b0\u7684\u7248\u672c\u3002
......
......@@ -49,6 +49,7 @@ THE SOFTWARE.
<modules>
<module>core</module>
<module>command-launcher-plugin</module>
<module>war</module>
<module>test</module>
<module>cli</module>
......
......@@ -110,6 +110,12 @@ THE SOFTWARE.
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
<version>${matrix-project.version}</version>
<exclusions>
<exclusion> <!-- TODO pick up from command-launcher, so long as that is a dep -->
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>script-security</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
......@@ -123,6 +129,12 @@ THE SOFTWARE.
<version>1.2</version>
<scope>test</scope>
</dependency>
<dependency> <!-- TODO at least pending a signature change in JenkinsRule.createComputerLauncher -->
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>command-launcher</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jvnet.mock-javamail</groupId>
<artifactId>mock-javamail</artifactId>
......
......@@ -41,7 +41,7 @@ import hudson.model.JDK;
import hudson.model.Run;
import hudson.model.Slave;
import hudson.model.TaskListener;
import hudson.slaves.CommandLauncher;
import hudson.slaves.ComputerLauncher;
import hudson.slaves.NodeProperty;
import hudson.slaves.RetentionStrategy;
import hudson.slaves.SlaveComputer;
......@@ -126,7 +126,7 @@ public class SimpleBuildWrapperTest {
}
}
private static class SpecialEnvSlave extends Slave {
SpecialEnvSlave(File remoteFS, CommandLauncher launcher) throws Descriptor.FormException, IOException {
SpecialEnvSlave(File remoteFS, ComputerLauncher launcher) throws Descriptor.FormException, IOException {
super("special", "SpecialEnvSlave", remoteFS.getAbsolutePath(), 1, Mode.NORMAL, "", launcher, RetentionStrategy.NOOP, Collections.<NodeProperty<?>>emptyList());
}
@Override public Computer createComputer() {
......
......@@ -404,6 +404,14 @@ THE SOFTWARE.
<version>2.16.0</version>
<type>hpi</type>
</artifactItem>
<!-- TODO after split:
<artifactItem>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>command-launcher</artifactId>
<version>1.0</version>
<type>hpi</type>
</artifactItem>
-->
</artifactItems>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/detached-plugins</outputDirectory>
<stripVersion>true</stripVersion>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册