提交 c32b011d 编写于 作者: S stephenconnolly

Making slave availability a strategy extension point

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@9352 71c3de6d-444a-0410-be80-ed276b4c234a
上级 8114bd1b
......@@ -247,10 +247,6 @@ public class Functions {
return Node.Mode.values();
}
public static Node.Availability[] getNodeAvailabilities() {
return Node.Availability.values();
}
public static String getProjectListString(List<Project> projects) {
return Items.toNameList(projects);
}
......@@ -501,6 +497,10 @@ public class Functions {
return SlaveStartMethod.LIST;
}
public static List<Descriptor<SlaveAvailabilityStrategy>> getSlaveAvailabilityStrategyDescriptors() {
return SlaveAvailabilityStrategy.LIST;
}
/**
* Computes the path to the icon of the given action
* from the context path.
......
......@@ -1486,39 +1486,13 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
Object src = json.get("slaves");
ArrayList<Slave> r = new ArrayList<Slave>();
if (src instanceof JSONObject) {
JSONObject j = (JSONObject) src;
final Slave slave = req.bindJSON(Slave.class, j);
String clazz = j.get("startMethodClass").toString();
for (Descriptor<SlaveStartMethod> d: SlaveStartMethod.LIST) {
if (d.getClass().getName().equals(clazz)) {
slave.setStartMethod(d.newInstance(req, j.getJSONObject("startMethod")));
break;
}
}
r.add(slave);
r.add(newSlave(req, (JSONObject) src));
}
if (src instanceof JSONArray) {
JSONArray a = (JSONArray) src;
for (Object o : a) {
if (o instanceof JSONObject) {
JSONObject j = (JSONObject) o;
String clazz = j.get("startMethodClass").toString();
SlaveStartMethod startMethod = null;
for (Descriptor<SlaveStartMethod> d: SlaveStartMethod.LIST) {
if (d.getClass().getName().equals(clazz)) {
startMethod = d.newInstance(req, j.getJSONObject("startMethod"));
break;
}
}
j.remove("startMethod");
j.remove("startMethodClass");
System.out.println("j = " + j);
final Slave slave = req.bindJSON(Slave.class, j);
slave.setStartMethod(startMethod);
r.add(slave);
r.add(newSlave(req, (JSONObject) o));
}
}
}
......@@ -1546,6 +1520,31 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
}
}
private Slave newSlave(StaplerRequest req, JSONObject j) throws FormException {
final SlaveStartMethod startMethod = newDescribedChild(req, j, "startMethod", SlaveStartMethod.LIST);
final SlaveAvailabilityStrategy availabilityStrategy =
newDescribedChild(req, j, "availabilityStrategy", SlaveAvailabilityStrategy.LIST);
final Slave slave = req.bindJSON(Slave.class, j);
slave.setStartMethod(startMethod);
slave.setAvailabilityStrategy(availabilityStrategy);
return slave;
}
private <T extends Describable<T>> T newDescribedChild(StaplerRequest req, JSONObject j,
String name, List<Descriptor<T>> descriptors)
throws FormException {
final String clazz = j.get(name + "Class").toString();
final JSONObject data = j.getJSONObject(name);
j.remove(name + "Class");
j.remove(name);
for (Descriptor<T> d: descriptors) {
if (d.getClass().getName().equals(clazz)) {
return d.newInstance(req, data);
}
}
return null;
}
/**
* Accepts the new description.
*/
......
......@@ -141,38 +141,7 @@ public interface Node {
static {
Stapler.CONVERT_UTILS.register(new EnumConverter(), Mode.class);
Stapler.CONVERT_UTILS.register(new EnumConverter(), Availability.class);
}
}
public enum Availability {
ALWAYS("Keep this slave on-line as much as possible", "configPageAlways"),
// SCHEDULED("Take this slave on-line and off-line at specific times", "configPageScheduled"),
// DEMAND("Take this slave on-line and off-line as needed", "configPageDemand"),
;
private final String configPage;
private final String description;
public String getDescription() {
return description;
}
public String getName() {
return name();
}
Availability(String description, String configPage) {
this.description = description;
this.configPage = configPage;
}
public void doConfigPage( StaplerRequest req, StaplerResponse rsp ) throws IOException {
rsp.sendRedirect2(configPage);
}
}
}
......@@ -79,31 +79,7 @@ public final class Slave implements Node, Serializable {
/**
* Slave availablility strategy.
*/
private Availability onlineAvailability;
/**
* Number of minutes when the slave is required to be on-line before bringing the slave on-line.
* Only used with {@link #onlineAvailability} == {@link hudson.model.Node.Availability#DEMAND}
*/
private int demandPeriod = 5;
/**
* Number of minutes when the slave is idle before bringing the slave off-line.
* Only used with {@link #onlineAvailability} == {@link hudson.model.Node.Availability#DEMAND}
*/
private int idlePeriod = 10;
/**
* Cron spec for starting up the slave.
* Only used with {@link #onlineAvailability} == {@link hudson.model.Node.Availability#SCHEDULED}
*/
private String startupSpec = "";
/**
* Cron spec for shutting down the slave.
* Only used with {@link #onlineAvailability} == {@link hudson.model.Node.Availability#SCHEDULED}
*/
private String shutdownSpec = "";
private SlaveAvailabilityStrategy availabilityStrategy;
/**
* The starter that will startup this slave.
......@@ -127,18 +103,13 @@ public final class Slave implements Node, Serializable {
* @stapler-constructor
*/
public Slave(String name, String description, String remoteFS, String numExecutors,
Mode mode, String label, Availability onlineAvailability) throws FormException {
Mode mode, String label) throws FormException {
this.name = name;
this.description = description;
this.numExecutors = Util.tryParseNumber(numExecutors, 1).intValue();
this.mode = mode;
this.remoteFS = remoteFS;
this.label = Util.fixNull(label).trim();
this.onlineAvailability = onlineAvailability;
this.demandPeriod = demandPeriod;
this.idlePeriod = idlePeriod;
this.startupSpec = startupSpec;
this.shutdownSpec = shutdownSpec;
getAssignedLabels(); // compute labels now
if (name.equals(""))
......@@ -184,24 +155,12 @@ public final class Slave implements Node, Serializable {
return mode;
}
public Availability getOnlineAvailability() {
return onlineAvailability;
}
public int getDemandPeriod() {
return demandPeriod;
}
public int getIdlePeriod() {
return idlePeriod;
}
public String getStartupSpec() {
return startupSpec;
public SlaveAvailabilityStrategy getAvailabilityStrategy() {
return availabilityStrategy == null ? new SlaveAvailabilityStrategy.Always() : availabilityStrategy;
}
public String getShutdownSpec() {
return shutdownSpec;
public void setAvailabilityStrategy(SlaveAvailabilityStrategy availabilityStrategy) {
this.availabilityStrategy = availabilityStrategy;
}
public String getLabelString() {
......
package hudson.model;
import hudson.util.DescriptorList;
import hudson.ExtensionPoint;
import org.kohsuke.stapler.StaplerRequest;
import net.sf.json.JSONObject;
/**
* Slave availability strategy
*/
public abstract class SlaveAvailabilityStrategy implements Describable<SlaveAvailabilityStrategy>, ExtensionPoint {
/**
* This method will be called periodically to allow this strategy to decide what to do with it's owning slave.
* The default implementation takes the slave on-line every time it's off-line.
*
* @param slave The slave that owns this strategy, i.e. {@code slave.getAvailabilityStrategy() == this}
* @param state Some state information that may be useful in deciding what to do.
* @return The number of minutes after which the strategy would like to be checked again. The strategy may be
* rechecked earlier or later that this!
*/
public long check(Slave slave, State state) {
Slave.ComputerImpl c = slave.getComputer();
if (c != null && c.isOffline() && c.isStartSupported())
c.tryReconnect();
return 5;
}
/**
* All registered {@link SlaveAvailabilityStrategy} implementations.
*/
public static final DescriptorList<SlaveAvailabilityStrategy> LIST = new DescriptorList<SlaveAvailabilityStrategy>(
Always.DESCRIPTOR
);
public static class State {
private final boolean jobWaiting;
private final boolean jobRunning;
public State(boolean jobWaiting, boolean jobRunning) {
this.jobWaiting = jobWaiting;
this.jobRunning = jobRunning;
}
public boolean isJobWaiting() {
return jobWaiting;
}
public boolean isJobRunning() {
return jobRunning;
}
}
public static class Always extends SlaveAvailabilityStrategy {
public Descriptor<SlaveAvailabilityStrategy> getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<SlaveAvailabilityStrategy> DESCRIPTOR =
new DescriptorImpl();
private static class DescriptorImpl extends Descriptor<SlaveAvailabilityStrategy> {
public DescriptorImpl() {
super(Always.class);
}
public String getDisplayName() {
return "Keep this slave on-line as much as possible";
}
public SlaveAvailabilityStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new Always();
}
}
}
}
......@@ -80,25 +80,29 @@
</table>
</div>
</j:if>
<p>${d}, ${d.class.name}, ${d == null}</p>
</s:nested>
</s:dropdownListBlock>
</j:if>
</j:forEach>
</s:dropdownList>
<s:dropdownList name="slave.onlineAvailability" title="${%Availability}"
<s:dropdownList name="slave.availabilityStrategyClass" title="${%Availability}"
help="/help/system-config/master-slave/availability.html">
<j:forEach var="a" items="${h.getNodeAvailabilities()}">
<s:dropdownListBlock value="${a}" name="${a.name}"
selected="${a==s.onlineAvailability}"
title="${a.description}">
<s:nested>
<table width="100%">
<st:include from="${a}" page="${a.name}.jelly"/>
</table>
</s:nested>
</s:dropdownListBlock>
<j:forEach var="d" items="${h.getSlaveAvailabilityStrategyDescriptors()}">
<j:if test="${d != null}">
<s:dropdownListBlock value="${d.class.name}" name="${d.displayName}"
selected="${s.availabilityStrategy.descriptor==d}"
title="${d.displayName}">
<s:nested>
<j:if test='${d.configPage != ""}'>
<j:set var="descriptor" value="${d}"/>
<j:set var="instance"
value="${h.ifThenElse(s.availabilityStrategy.descriptor==d,s.availabilityStrategy,null)}"/>
<st:include from="${d}" page="${d.configPage}" optional="true"/>
</j:if>
</s:nested>
</s:dropdownListBlock>
</j:if>
</j:forEach>
</s:dropdownList>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册