提交 690acbc3 编写于 作者: K kohsuke

[FIXED HUDSON-6598] applied a patch from Mike Dillon, plus the separate...

[FIXED HUDSON-6598] applied a patch from Mike Dillon, plus the separate independent extension point. In 1.360.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@31304 71c3de6d-444a-0410-be80-ed276b4c234a
上级 0263abd5
...@@ -27,6 +27,8 @@ import hudson.ExtensionPoint; ...@@ -27,6 +27,8 @@ import hudson.ExtensionPoint;
import hudson.FilePath; import hudson.FilePath;
import hudson.FileSystemProvisioner; import hudson.FileSystemProvisioner;
import hudson.Launcher; import hudson.Launcher;
import hudson.model.Queue.Task;
import hudson.model.queue.CauseOfBlockage;
import hudson.node_monitors.NodeMonitor; import hudson.node_monitors.NodeMonitor;
import hudson.remoting.VirtualChannel; import hudson.remoting.VirtualChannel;
import hudson.security.ACL; import hudson.security.ACL;
...@@ -221,6 +223,35 @@ public abstract class Node extends AbstractModelObject implements Describable<No ...@@ -221,6 +223,35 @@ public abstract class Node extends AbstractModelObject implements Describable<No
return Label.get(getNodeName()); return Label.get(getNodeName());
} }
/**
* Called by the {@link Queue} to determine whether or not this node can
* take the given task. The default checks include whether or not this node
* is part of the task's assigned label, whether this node is in
* {@link Mode#EXCLUSIVE} mode if it is not in the task's assigned label,
* and whether or not any of this node's {@link NodeProperty}s say that the
* task cannot be run.
*
* @since 1.360
*/
public CauseOfBlockage canTake(Task task) {
Label l = task.getAssignedLabel();
if(l!=null && !l.contains(this))
return CauseOfBlockage.fromMessage(Messages._Node_LabelMissing(getNodeName(),l)); // the task needs to be executed on label that this node doesn't have.
if(l==null && getMode()== Mode.EXCLUSIVE)
return CauseOfBlockage.fromMessage(Messages._Node_BecauseNodeIsReserved(getNodeName())); // this node is reserved for tasks that are tied to it
// Check each NodeProperty to see whether they object to this node
// taking the task
for (NodeProperty prop: getNodeProperties()) {
CauseOfBlockage c = prop.canTake(task);
if (c!=null) return c;
}
// Looks like we can take the task
return null;
}
/** /**
* Returns a "workspace" directory for the given {@link TopLevelItem}. * Returns a "workspace" directory for the given {@link TopLevelItem}.
* *
......
...@@ -35,6 +35,7 @@ import static hudson.util.Iterators.reverse; ...@@ -35,6 +35,7 @@ import static hudson.util.Iterators.reverse;
import hudson.cli.declarative.CLIMethod; import hudson.cli.declarative.CLIMethod;
import hudson.cli.declarative.CLIResolver; import hudson.cli.declarative.CLIResolver;
import hudson.model.queue.QueueSorter; import hudson.model.queue.QueueSorter;
import hudson.model.queue.QueueTaskDispatcher;
import hudson.remoting.AsyncFutureImpl; import hudson.remoting.AsyncFutureImpl;
import hudson.model.Node.Mode; import hudson.model.Node.Mode;
import hudson.model.listeners.SaveableListener; import hudson.model.listeners.SaveableListener;
...@@ -179,12 +180,12 @@ public class Queue extends ResourceController implements Saveable { ...@@ -179,12 +180,12 @@ public class Queue extends ResourceController implements Saveable {
Node node = getNode(); Node node = getNode();
if (node==null) return false; // this executor is about to die if (node==null) return false; // this executor is about to die
Label l = task.getAssignedLabel(); if(node.canTake(task)!=null)
if(l!=null && !l.contains(node)) return false; // this node is not able to take the task
return false; // the task needs to be executed on label that this node doesn't have.
if(l==null && node.getMode()== Mode.EXCLUSIVE) for (QueueTaskDispatcher d : QueueTaskDispatcher.all())
return false; // this node is reserved for tasks that are tied to it if (d.canTake(node,task)!=null)
return false;
return isAvailable(); return isAvailable();
} }
......
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, 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 hudson.model.queue;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.model.Queue;
import hudson.model.Queue.Task;
/**
* Vetos the execution of a task on a node
*
* <p>
* To register your dispatcher implementations, put @{@link Extension} on your subtypes.
*
* @author Kohsuke Kawaguchi
* @since 1.360
*/
public abstract class QueueTaskDispatcher implements ExtensionPoint {
/**
* Called whenever {@link Queue} is considering to execute the given task on a given node.
*
* <p>
* Implementations can return null to indicate that the assignment is fine, or it can return
* a non-null instance to block the execution of the task on the given node.
*
* <p>
* Queue doesn't remember/cache the response from dispatchers, and instead it'll keep asking.
* The upside of this is that it's very easy to block execution for a limited time period (
* as you just need to return null when it's ready to execute.) The downside of this is that
* the decision needs to be made quickly.
*
* <p>
* Vetos are additive. When multiple {@link QueueTaskDispatcher}s are in the system,
* the task won't run on the given node if any one of them returns a non-null value.
* (This relationship is also the same with built-in check logic.)
*/
public abstract CauseOfBlockage canTake(Node node, Task task);
/**
* All registered {@link QueueTaskDispatcher}s.
*/
public static ExtensionList<QueueTaskDispatcher> all() {
return Hudson.getInstance().getExtensionList(QueueTaskDispatcher.class);
}
}
\ No newline at end of file
...@@ -26,6 +26,7 @@ package hudson.slaves; ...@@ -26,6 +26,7 @@ package hudson.slaves;
import hudson.ExtensionPoint; import hudson.ExtensionPoint;
import hudson.Launcher; import hudson.Launcher;
import hudson.DescriptorExtensionList; import hudson.DescriptorExtensionList;
import hudson.model.queue.CauseOfBlockage;
import hudson.scm.SCM; import hudson.scm.SCM;
import hudson.model.AbstractBuild; import hudson.model.AbstractBuild;
import hudson.model.BuildListener; import hudson.model.BuildListener;
...@@ -33,6 +34,7 @@ import hudson.model.Describable; ...@@ -33,6 +34,7 @@ import hudson.model.Describable;
import hudson.model.Environment; import hudson.model.Environment;
import hudson.model.Hudson; import hudson.model.Hudson;
import hudson.model.Node; import hudson.model.Node;
import hudson.model.Queue.Task;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
...@@ -69,6 +71,18 @@ public abstract class NodeProperty<N extends Node> implements Describable<NodePr ...@@ -69,6 +71,18 @@ public abstract class NodeProperty<N extends Node> implements Describable<NodePr
return (NodePropertyDescriptor)Hudson.getInstance().getDescriptorOrDie(getClass()); return (NodePropertyDescriptor)Hudson.getInstance().getDescriptorOrDie(getClass());
} }
/**
* Called by the {@link Node} to help determine whether or not it should
* take the given task. Individual properties can return a non-null value
* here if there is some reason the given task should not be run on its
* associated node. By default, this method returns <code>null</code>.
*
* @since 1.360
*/
public CauseOfBlockage canTake(Task task) {
return null;
}
/** /**
* Runs before the {@link SCM#checkout(AbstractBuild, Launcher, FilePath, BuildListener, File)} runs, and performs a set up. * Runs before the {@link SCM#checkout(AbstractBuild, Launcher, FilePath, BuildListener, File)} runs, and performs a set up.
* Can contribute additional properties to the environment. * Can contribute additional properties to the environment.
......
...@@ -141,6 +141,8 @@ Label.GroupOf=group of {0} ...@@ -141,6 +141,8 @@ Label.GroupOf=group of {0}
Label.InvalidLabel=invalid label Label.InvalidLabel=invalid label
Label.ProvisionedFrom=Provisioned from {0} Label.ProvisionedFrom=Provisioned from {0}
MultiStageTimeSeries.EMPTY_STRING= MultiStageTimeSeries.EMPTY_STRING=
Node.BecauseNodeIsReserved={0} is reserved for jobs tied to it
Node.LabelMissing={0} doesn''t have label {1}
Queue.AllNodesOffline=All nodes of label ''{0}'' are offline Queue.AllNodesOffline=All nodes of label ''{0}'' are offline
Queue.BlockedBy=Blocked by {0} Queue.BlockedBy=Blocked by {0}
Queue.HudsonIsAboutToShutDown=Hudson is about to shut down Queue.HudsonIsAboutToShutDown=Hudson is about to shut down
......
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, 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 hudson.slaves;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Messages;
import hudson.model.Node;
import hudson.model.Node.Mode;
import hudson.model.Project;
import hudson.model.Result;
import hudson.model.Queue.BuildableItem;
import hudson.model.Queue.Task;
import hudson.model.Slave;
import hudson.model.queue.CauseOfBlockage;
import junit.framework.Assert;
import org.jvnet.hudson.test.HudsonTestCase;
public class NodeCanTakeTaskTest extends HudsonTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
// Set master executor count to zero to force all jobs to slaves
hudson.setNumExecutors(0);
}
public void testTakeBlockedByProperty() throws Exception {
Slave slave = createSlave();
FreeStyleProject project = createFreeStyleProject();
// First, attempt to run our project before adding the property
Future<FreeStyleBuild> build = project.scheduleBuild2(0);
assertBuildStatus(Result.SUCCESS, build.get(10, TimeUnit.SECONDS));
// Add the build-blocker property and try again
slave.getNodeProperties().add(new RejectAllTasksProperty());
build = project.scheduleBuild2(0);
try {
build.get(10, TimeUnit.SECONDS);
fail("Expected timeout exception");
} catch (TimeoutException e) {
List<BuildableItem> buildables = hudson.getQueue().getBuildableItems();
Assert.assertNotNull(buildables);
Assert.assertEquals(1, buildables.size());
BuildableItem item = buildables.get(0);
Assert.assertEquals(project, item.task);
Assert.assertNotNull(item.getCauseOfBlockage());
Assert.assertEquals(Messages.Queue_WaitingForNextAvailableExecutor(), item.getCauseOfBlockage().getShortDescription());
}
}
private static class RejectAllTasksProperty extends NodeProperty<Node> {
@Override
public CauseOfBlockage canTake(Task task) {
return CauseOfBlockage.fromMessage(null);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册