Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FIXED JENKINS-26751] Do not run /script on offline slave
  • Loading branch information
olivergondza committed Apr 4, 2015
1 parent f2c2f0f commit d8b1111
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 27 deletions.
5 changes: 4 additions & 1 deletion core/src/main/java/hudson/util/RemotingDiagnostics.java
Expand Up @@ -34,15 +34,18 @@
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;
Expand Down Expand Up @@ -104,7 +107,7 @@ public Map<String,String> call() {
/**
* 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));
}

Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/jenkins/model/Jenkins.java
Expand Up @@ -3527,6 +3527,11 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis
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));
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/resources/hudson/model/Computer/sidepanel.jelly
Expand Up @@ -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>
Expand All @@ -45,4 +47,4 @@ THE SOFTWARE.
</j:forEach>
<t:executors computers="${h.singletonList(it)}" />
</l:side-panel>
</j:jelly>
</j:jelly>
55 changes: 31 additions & 24 deletions core/src/main/resources/lib/hudson/scriptConsole.jelly
Expand Up @@ -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>
</j:jelly>
22 changes: 22 additions & 0 deletions test/src/test/java/jenkins/model/JenkinsTest.java
Expand Up @@ -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;
Expand All @@ -31,7 +34,9 @@

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;

Expand All @@ -50,6 +55,7 @@
import hudson.security.LegacySecurityRealm;
import hudson.security.Permission;
import hudson.slaves.ComputerListener;
import hudson.slaves.DumbSlave;
import hudson.slaves.OfflineCause;
import hudson.util.FormValidation;

Expand Down Expand Up @@ -427,4 +433,20 @@ public void testComputerListenerNotifiedOnRestart() {

@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));
}
}

0 comments on commit d8b1111

Please sign in to comment.