提交 d8b1111c 编写于 作者: O Oliver Gondža

[FIXED JENKINS-26751] Do not run /script on offline slave

上级 f2c2f0fa
......@@ -34,15 +34,18 @@ import hudson.remoting.Future;
import hudson.remoting.VirtualChannel;
import hudson.security.AccessControlled;
import jenkins.security.MasterToSlaveCallable;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.WebMethod;
import javax.annotation.Nonnull;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
......@@ -104,7 +107,7 @@ public final class RemotingDiagnostics {
/**
* Executes Groovy script remotely.
*/
public static String executeGroovy(String script, VirtualChannel channel) throws IOException, InterruptedException {
public static String executeGroovy(String script, @Nonnull VirtualChannel channel) throws IOException, InterruptedException {
return channel.call(new Script(script));
}
......
......@@ -3527,6 +3527,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
if (!"POST".equals(req.getMethod())) {
throw HttpResponses.error(HttpURLConnection.HTTP_BAD_METHOD, "requires POST");
}
if (channel == null) {
throw HttpResponses.error(HttpURLConnection.HTTP_NOT_FOUND, "Node is offline");
}
try {
req.setAttribute("output",
RemotingDiagnostics.executeGroovy(text, channel));
......
......@@ -36,7 +36,9 @@ THE SOFTWARE.
<l:task href="${rootURL}/${it.url}configure" icon="icon-setting icon-md" permission="${it.CONFIGURE}" title="${%Configure}"/>
<l:task href="${rootURL}/${it.url}builds" icon="icon-notepad icon-md" title="${%Build History}"/>
<l:task href="${rootURL}/${it.url}load-statistics" icon="icon-monitor icon-md" title="${%Load Statistics}"/>
<l:task href="${rootURL}/${it.url}script" icon="icon-terminal icon-md" permission="${app.RUN_SCRIPTS}" title="${%Script Console}"/>
<j:if test="${it.channel!=null}">
<l:task href="${rootURL}/${it.url}script" icon="icon-terminal icon-md" permission="${app.RUN_SCRIPTS}" title="${%Script Console}"/>
</j:if>
<st:include page="sidepanel2.jelly" optional="true" /><!-- hook for derived class to add more items -->
<t:actions />
</l:tasks>
......@@ -45,4 +47,4 @@ THE SOFTWARE.
</j:forEach>
<t:executors computers="${h.singletonList(it)}" />
</l:side-panel>
</j:jelly>
\ No newline at end of file
</j:jelly>
......@@ -31,29 +31,36 @@ THE SOFTWARE.
<st:include page="sidepanel.jelly" />
<l:main-panel>
<h1>${%Script Console}</h1>
<p>
${%description}
</p>
<!-- this is where the example goes -->
<d:invokeBody />
<p>
${%description2}
</p>
<form action="script" method="post">
<textarea id="script" name="script" class="script">${request.getParameter('script')}</textarea>
<div align="right">
<f:submit value="${%Run}"/>
</div>
</form>
<st:adjunct includes="org.kohsuke.stapler.codemirror.mode.groovy.groovy"/>
<st:adjunct includes="org.kohsuke.stapler.codemirror.theme.default"/>
<j:if test="${output!=null}">
<h2>${%Result}</h2>
<pre><st:out value="${output}"/></pre>
</j:if>
<h1><img src="${imagesURL}/48x48/${it.icon}" width="48" height="48" alt=""/> ${%Script Console}</h1>
<j:choose>
<j:when test="${it.channel != null}">
<p>
${%description}
</p>
<!-- this is where the example goes -->
<d:invokeBody />
<p>
${%description2}
</p>
<form action="script" method="post">
<textarea id="script" name="script" class="script">${request.getParameter('script')}</textarea>
<div align="right">
<f:submit value="${%Run}"/>
</div>
</form>
<st:adjunct includes="org.kohsuke.stapler.codemirror.mode.groovy.groovy"/>
<st:adjunct includes="org.kohsuke.stapler.codemirror.theme.default"/>
<j:if test="${output!=null}">
<h2>${%Result}</h2>
<pre><st:out value="${output}"/></pre>
</j:if>
</j:when>
<j:otherwise>
${%It is not possible to run scripts when slave is offline.}
</j:otherwise>
</j:choose>
</l:main-panel>
</l:layout>
</j:jelly>
\ No newline at end of file
</j:jelly>
......@@ -23,6 +23,9 @@
*/
package jenkins.model;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
......@@ -31,7 +34,9 @@ import static org.junit.Assert.fail;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebRequestSettings;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
......@@ -50,6 +55,7 @@ import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.security.LegacySecurityRealm;
import hudson.security.Permission;
import hudson.slaves.ComputerListener;
import hudson.slaves.DumbSlave;
import hudson.slaves.OfflineCause;
import hudson.util.FormValidation;
......@@ -427,4 +433,20 @@ public class JenkinsTest {
@TestExtension(value = "testComputerListenerNotifiedOnRestart")
public static final ComputerListener listenerMock = Mockito.mock(ComputerListener.class);
@Test
public void runScriptOnOfflineComputer() throws Exception {
DumbSlave slave = j.createSlave();
URL url = new URL(j.getURL(), "computer/" + slave.getNodeName() + "/scriptText?script=println(42)");
WebClient wc = j.createWebClient();
wc.setThrowExceptionOnFailingStatusCode(false);
WebRequestSettings req = new WebRequestSettings(url, HttpMethod.POST);
Page page = wc.getPage(wc.addCrumb(req));
WebResponse rsp = page.getWebResponse();
assertThat(rsp.getContentAsString(), containsString("Node is offline"));
assertThat(rsp.getStatusCode(), equalTo(404));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册