Skip to content

Commit

Permalink
Merge pull request #41 from oleg-nenashev/feature/JENKINS-25326_Execu…
Browse files Browse the repository at this point in the history
…torPermission

[JENKINS-25326] - Elevate user to system during build throttling
  • Loading branch information
oleg-nenashev committed Apr 10, 2016
2 parents e1aeb17 + dfb3d2f commit c823d8d
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 2 deletions.
13 changes: 13 additions & 0 deletions pom.xml
Expand Up @@ -135,6 +135,19 @@ THE SOFTWARE.
<version>1.4.1</version>
</dependency>

<!-- Dependencies for test -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloudbees-folder</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>1.9.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Expand Up @@ -16,6 +16,8 @@
import hudson.model.labels.LabelAtom;
import hudson.model.queue.CauseOfBlockage;
import hudson.model.queue.QueueTaskDispatcher;
import hudson.security.ACL;
import hudson.security.NotSerilizableSecurityContext;
import hudson.model.Action;
import hudson.model.ParametersAction;

Expand All @@ -28,11 +30,34 @@
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;

import jenkins.model.Jenkins;

@Extension
public class ThrottleQueueTaskDispatcher extends QueueTaskDispatcher {

@Override
public CauseOfBlockage canTake(Node node, Task task) {
if (Jenkins.getAuthentication() == ACL.SYSTEM) {
return canTakeImpl(node, task);
}

// Throttle-concurrent-builds requires READ permissions for all projects.
SecurityContext orig = SecurityContextHolder.getContext();
NotSerilizableSecurityContext auth = new NotSerilizableSecurityContext();
auth.setAuthentication(ACL.SYSTEM);
SecurityContextHolder.setContext(auth);

try {
return canTakeImpl(node, task);
} finally {
SecurityContextHolder.setContext(orig);
}
}

private CauseOfBlockage canTakeImpl(Node node, Task task) {

ThrottleJobProperty tjp = getThrottleJobProperty(task);

Expand All @@ -42,7 +67,7 @@ public CauseOfBlockage canTake(Node node, Task task) {
}

if (tjp!=null && tjp.getThrottleEnabled()) {
CauseOfBlockage cause = canRun(task, tjp);
CauseOfBlockage cause = canRunImpl(task, tjp);
if (cause != null) {
return cause;
}
Expand Down Expand Up @@ -144,6 +169,24 @@ private boolean shouldBeThrottled(@Nonnull Task task, @CheckForNull ThrottleJobP
}

public CauseOfBlockage canRun(Task task, ThrottleJobProperty tjp) {
if (Jenkins.getAuthentication() == ACL.SYSTEM) {
return canRunImpl(task, tjp);
}

// Throttle-concurrent-builds requires READ permissions for all projects.
SecurityContext orig = SecurityContextHolder.getContext();
NotSerilizableSecurityContext auth = new NotSerilizableSecurityContext();
auth.setAuthentication(ACL.SYSTEM);
SecurityContextHolder.setContext(auth);

try {
return canRunImpl(task, tjp);
} finally {
SecurityContextHolder.setContext(orig);
}
}

private CauseOfBlockage canRunImpl(Task task, ThrottleJobProperty tjp) {
if (!shouldBeThrottled(task, tjp)) {
return null;
}
Expand Down
Expand Up @@ -24,11 +24,13 @@

package hudson.plugins.throttleconcurrents;

import com.cloudbees.hudson.plugins.folder.Folder;
import hudson.EnvVars;
import hudson.model.FreeStyleProject;
import hudson.model.Node.Mode;
import hudson.plugins.throttleconcurrents.ThrottleJobProperty.NodeLabeledPair;
import hudson.plugins.throttleconcurrents.testutils.ExecutorWaterMarkRetentionStrategy;
import hudson.security.GlobalMatrixAuthorizationStrategy;
import hudson.slaves.DumbSlave;
import hudson.slaves.NodeProperty;
import hudson.slaves.RetentionStrategy;
Expand All @@ -37,9 +39,14 @@
import java.util.Arrays;
import java.util.Collections;

import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.SleepBuilder;

/*
import com.cloudbees.hudson.plugins.folder.Folder;
*/

/**
* Tests that {@link ThrottleJobProperty} actually works for builds.
*/
Expand Down Expand Up @@ -80,8 +87,19 @@ private void setupSlave() throws Exception {
slave.setRetentionStrategy(waterMark);
}

/**
* setup security so that no one except SYSTEM has any permissions.
* should be called after {@link #setupSlave()}
*/
private void setupSecurity() {
jenkins.setSecurityRealm(createDummySecurityRealm());
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
jenkins.setAuthorizationStrategy(auth);
}

public void testNoThrottling() throws Exception {
setupSlave();
setupSecurity();

FreeStyleProject p1 = createFreeStyleProject();
p1.setAssignedNode(slave);
Expand All @@ -102,6 +120,7 @@ public void testNoThrottling() throws Exception {

public void testThrottlingWithCategory() throws Exception {
setupSlave();
setupSecurity();
final String category = "category";

ThrottleJobProperty.DescriptorImpl descriptor
Expand Down Expand Up @@ -151,4 +170,60 @@ public void testThrottlingWithCategory() throws Exception {
// throttled, and only one build runs at the same time.
assertEquals(1, waterMark.getExecutorWaterMark());
}

@Bug(25326)
public void testThrottlingWithCategoryInFolder() throws Exception {
setupSlave();
setupSecurity();
final String category = "category";

ThrottleJobProperty.DescriptorImpl descriptor
= (ThrottleJobProperty.DescriptorImpl)jenkins.getDescriptor(ThrottleJobProperty.class);
descriptor.setCategories(Arrays.asList(
new ThrottleJobProperty.ThrottleCategory(
category,
1, // maxConcurrentPerNode
null, // maxConcurrentTotal
Collections.<NodeLabeledPair>emptyList()
)
));

Folder f1 = jenkins.createProject(Folder.class, "folder1");
FreeStyleProject p1 = f1.createProject(FreeStyleProject.class, "p");
p1.setAssignedNode(slave);
p1.addProperty(new ThrottleJobProperty(
null, // maxConcurrentPerNode
null, // maxConcurrentTotal
Arrays.asList(category), // categories
true, // throttleEnabled
"category", // throttleOption
false, // limitOneJobWithMatchingParams
null, // paramsToUse for the previous flag
ThrottleMatrixProjectOptions.DEFAULT
));
p1.getBuildersList().add(new SleepBuilder(SLEEP_TIME));

Folder f2 = jenkins.createProject(Folder.class, "folder2");
FreeStyleProject p2 = f2.createProject(FreeStyleProject.class, "p");
p2.setAssignedNode(slave);
p2.addProperty(new ThrottleJobProperty(
null, // maxConcurrentPerNode
null, // maxConcurrentTotal
Arrays.asList(category), // categories
true, // throttleEnabled
"category", // throttleOption
false, // limitOneJobWithMatchingParams
null, // paramsToUse for the previous flag
ThrottleMatrixProjectOptions.DEFAULT
));
p2.getBuildersList().add(new SleepBuilder(SLEEP_TIME));

p1.scheduleBuild2(0);
p2.scheduleBuild2(0);

waitUntilNoActivity();

// throttled, and only one build runs at the same time.
assertEquals(1, waterMark.getExecutorWaterMark());
}
}
Expand Up @@ -16,6 +16,7 @@
*/
package hudson.plugins.throttleconcurrents;

import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
Expand Down Expand Up @@ -358,7 +359,13 @@ private String configureLogger()
input.setValueAttribute(logger);
}
HtmlSelect select = form.getSelectByName("level");
HtmlOption option = select.getOptionByValue("ALL");
HtmlOption option;
try {
option = select.getOptionByValue("fine");
} catch (ElementNotFoundException e) {
// gets upper case since Jenkins 1.519
option = select.getOptionByValue("FINE");
}
select.setSelectedAttribute(option, true);
break;
}
Expand Down

0 comments on commit c823d8d

Please sign in to comment.