提交 d86ffdeb 编写于 作者: K kohsuke

extension points shouldn't depend on implementation detail class, so promoted...

extension points shouldn't depend on implementation detail class, so promoted ComputerImpl to SlaveComputer.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@9403 71c3de6d-444a-0410-be80-ed276b4c234a
上级 7723cd7e
......@@ -14,7 +14,7 @@ import hudson.security.AuthorizationStrategy;
import hudson.security.Permission;
import hudson.util.Area;
import hudson.slaves.SlaveStartMethod;
import hudson.slaves.SlaveAvailabilityStrategy;
import hudson.slaves.RetentionStrategy;
import org.apache.commons.jexl.parser.ASTSizeFunction;
import org.apache.commons.jexl.util.Introspector;
import org.apache.commons.jelly.JellyContext;
......@@ -498,8 +498,8 @@ public class Functions {
return SlaveStartMethod.LIST;
}
public static List<Descriptor<SlaveAvailabilityStrategy>> getSlaveAvailabilityStrategyDescriptors() {
return SlaveAvailabilityStrategy.LIST;
public static List<Descriptor<RetentionStrategy<?>>> getSlaveAvailabilityStrategyDescriptors() {
return RetentionStrategy.LIST;
}
/**
......
......@@ -2,6 +2,7 @@ package hudson.model;
import hudson.EnvVars;
import hudson.slaves.SlaveStartMethod;
import hudson.slaves.RetentionStrategy;
import hudson.node_monitors.NodeMonitor;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
......@@ -253,7 +254,7 @@ public abstract class Computer extends AbstractModelObject {
/**
* Returns true if all the executors of this computer is idle.
*/
public boolean isIdle() {
public final boolean isIdle() {
for (Executor e : executors)
if(!e.isIdle())
return false;
......@@ -282,6 +283,14 @@ public abstract class Computer extends AbstractModelObject {
return "computer/"+nodeName;
}
/**
* {@link RetentionStrategy} associated with this computer.
*
* @return
* never null.
*/
public abstract RetentionStrategy getRetentionStrategy();
/**
* Expose monitoring data for the remote API.
*/
......
......@@ -15,7 +15,7 @@ import hudson.Util;
import static hudson.Util.fixEmpty;
import hudson.XmlFile;
import hudson.slaves.SlaveStartMethod;
import hudson.slaves.SlaveAvailabilityStrategy;
import hudson.slaves.RetentionStrategy;
import hudson.model.Descriptor.FormException;
import hudson.model.listeners.ItemListener;
import hudson.model.listeners.JobListener;
......@@ -1524,8 +1524,8 @@ 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 RetentionStrategy availabilityStrategy =
newDescribedChild(req, j, "availabilityStrategy", RetentionStrategy.LIST);
final Slave slave = req.bindJSON(Slave.class, j);
slave.setStartMethod(startMethod);
slave.setAvailabilityStrategy(availabilityStrategy);
......@@ -2356,6 +2356,10 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
return "computer/(master)/";
}
public RetentionStrategy getRetentionStrategy() {
return RetentionStrategy.Always.INSTANCE;
}
@Override
public VirtualChannel getChannel() {
return localChannel;
......
......@@ -5,7 +5,7 @@ import hudson.Launcher;
import hudson.Launcher.RemoteLauncher;
import hudson.Util;
import hudson.slaves.SlaveStartMethod;
import hudson.slaves.SlaveAvailabilityStrategy;
import hudson.slaves.RetentionStrategy;
import hudson.slaves.CommandStartMethod;
import hudson.slaves.JNLPStartMethod;
import hudson.slaves.SlaveComputer;
......@@ -15,7 +15,6 @@ import hudson.remoting.VirtualChannel;
import hudson.tasks.DynamicLabeler;
import hudson.tasks.LabelFinder;
import hudson.util.ClockDifference;
import hudson.util.RingBufferLogHandler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -27,7 +26,6 @@ import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.logging.Logger;
/**
* Information about a Hudson slave node.
......@@ -68,7 +66,7 @@ public final class Slave implements Node, Serializable {
/**
* Slave availablility strategy.
*/
private SlaveAvailabilityStrategy availabilityStrategy;
private RetentionStrategy availabilityStrategy;
/**
* The starter that will startup this slave.
......@@ -144,11 +142,11 @@ public final class Slave implements Node, Serializable {
return mode;
}
public SlaveAvailabilityStrategy getAvailabilityStrategy() {
return availabilityStrategy == null ? new SlaveAvailabilityStrategy.Always() : availabilityStrategy;
public RetentionStrategy getAvailabilityStrategy() {
return availabilityStrategy == null ? RetentionStrategy.Always.INSTANCE : availabilityStrategy;
}
public void setAvailabilityStrategy(SlaveAvailabilityStrategy availabilityStrategy) {
public void setAvailabilityStrategy(RetentionStrategy availabilityStrategy) {
this.availabilityStrategy = availabilityStrategy;
}
......@@ -306,7 +304,7 @@ public final class Slave implements Node, Serializable {
public Launcher createLauncher(TaskListener listener) {
SlaveComputer c = getComputer();
return new RemoteLauncher(listener, c.getChannel(), c.isUnix);
return new RemoteLauncher(listener, c.getChannel(), c.isUnix());
}
/**
......
package hudson.slaves;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Computer;
import hudson.util.DescriptorList;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Controls when to take {@link Computer} offline, bring it back online, or even to destroy it.
*
* <p>
* <b>EXPERIMENTAL: SIGNATURE MAY CHANGE IN FUTURE RELEASES</b>
*/
public abstract class RetentionStrategy<T extends Computer> implements Describable<RetentionStrategy<?>>, ExtensionPoint {
/**
* This method will be called periodically to allow this strategy to decide what to do with it's owning slave.
*
* @param c
* {@link Computer} for which this strategy is assigned. This object also exposes a bunch of properties
* that the callee can use to decide what action to take.
*
* @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 abstract long check(T c);
/**
* All registered {@link RetentionStrategy} implementations.
*/
public static final DescriptorList<RetentionStrategy<?>> LIST = new DescriptorList<RetentionStrategy<?>>(
Always.DESCRIPTOR
);
/**
* {@link RetentionStrategy} that tries to keep the node online all the time.
*/
public static class Always extends RetentionStrategy<SlaveComputer> {
@DataBoundConstructor
public Always() {
}
public long check(SlaveComputer c) {
if (c.isOffline() && c.isLaunchSupported())
c.tryReconnect();
return 1;
}
/**
* Convenient singleton instance, sine this {@link RetentionStrategy} is stateless.
*/
public static final Always INSTANCE = new Always();
public DescriptorImpl getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
private static class DescriptorImpl extends Descriptor<RetentionStrategy<?>> {
public DescriptorImpl() {
super(Always.class);
}
public String getDisplayName() {
return "Keep this slave on-line as much as possible";
}
}
}
}
......@@ -45,7 +45,7 @@ import javax.servlet.http.HttpServletResponse;
*/
public final class SlaveComputer extends Computer {
private volatile Channel channel;
private boolean isUnix;
private Boolean isUnix;
/**
* Number of failed attempts to reconnect to this node
......@@ -67,8 +67,11 @@ public final class SlaveComputer extends Computer {
/**
* True if this computer is a Unix machine (as opposed to Windows machine).
*
* @return
* null if the computer is disconnected and therefore we don't know whether it is Unix or not.
*/
public boolean isUnix() {
public Boolean isUnix() {
return isUnix;
}
......@@ -232,6 +235,10 @@ public final class SlaveComputer extends Computer {
closeChannel();
}
public RetentionStrategy getRetentionStrategy() {
return getNode().getAvailabilityStrategy();
}
/**
* If still connected, disconnect.
*/
......
......@@ -2,7 +2,6 @@ package hudson.slaves;
import hudson.model.Computer;
import hudson.model.Hudson;
import hudson.model.Queue;
import hudson.triggers.SafeTimerTask;
import java.util.Map;
......@@ -20,17 +19,11 @@ public class SlaveReconnectionWork extends SafeTimerTask {
private final Map<Computer,Long> nextCheck = new WeakHashMap<Computer,Long>();
protected void doRun() {
final Queue queue = Hudson.getInstance().getQueue();
for (Computer c : Hudson.getInstance().getComputers()) {
if (!nextCheck.containsKey(c) || System.currentTimeMillis() > nextCheck.get(c)) {
boolean hasJob = !c.isIdle();
// TODO get only the items from the queue that can apply to this slave
SlaveAvailabilityStrategy.State state = new SlaveAvailabilityStrategy.State(queue.getItems().length > 0, hasJob);
// at the moment I don't trust strategies to wait more than 60 minutes
// strategies need to wait at least one minute
final long waitInMins = Math.min(1, Math.max(60, c.getAvailabilityStrategy().check(c, state)));
final long waitInMins = Math.min(1, Math.max(60, c.getRetentionStrategy().check(c)));
nextCheck.put(c, System.currentTimeMillis() + 60 * 1000 * waitInMins);
}
}
......
<!-- Disconnect confirmation -->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${it.displayName} log">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<form method="get" action="doDisconnect">
Are you sure about disconnecting?
<f:submit value="Yes" />
</form>
</l:main-panel>
</l:layout>
</j:jelly>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="${it.displayName} log" secured="true">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<l:isAdmin>
<pre id="out"></pre>
<div id="spinner">
<img src="${imagesURL}/spinner.gif" />
</div>
<t:progressiveText href="progressiveLog" idref="out" spinner="spinner" />
</l:isAdmin>
</l:main-panel>
</l:layout>
</j:jelly>
<!--
Side panel for a slave.
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:header title="${it.displayName}" />
<l:side-panel>
<l:tasks>
<l:task icon="images/24x24/up.gif" href=".." title="${%Back to List}" />
<l:task icon="images/24x24/search.gif" href="${rootURL}/computer/${it.displayName}/" title="${%Status}" />
<l:task icon="images/24x24/notepad.gif" href="${rootURL}/${it.url}/builds" title="${%Build History}" />
<l:isAdmin>
<l:task icon="images/24x24/clipboard.gif" href="log" title="${%Log}" />
<l:task icon="images/24x24/computer.gif" href="systemInfo" title="${%System Information}" />
<j:if test="${it.channel!=null}">
<l:task icon="images/24x24/edit-delete.gif" href="disconnect" title="${%Disconnect}" />
</j:if>
</l:isAdmin>
</l:tasks>
</l:side-panel>
</j:jelly>
\ No newline at end of file
Back\ to\ List=Retour à la liste
Status=Statut
Build\ History=Historique des builds
Log=
System\ Information=Information système
Disconnect=Déconnection
Back\ to\ List=\u30ea\u30b9\u30c8\u3078\u623b\u308b
Status=\u72b6\u614b
Build\ History=\u30d3\u30eb\u30c9\u5c65\u6b74
Log=\u30ed\u30b0
System\ Information=\u30b7\u30b9\u30c6\u30e0\u60c5\u5831
Disconnect=\u5207\u65ad
Back\ to\ List=Terug naar de lijst
Status=Status
Build\ History=Overzicht bouwpogingen
Log=Log
System\ Information=Systeeminformatie
Disconnect=Loskoppelen
Back\ to\ List=Voltar para a Lista
Status=Estado
Build\ History=Hist\u00F3rico de Constru\u00E7\u00F5es
Log=
System\ Information=Informa\u00E7\u00F5es do Sistema
Disconnect=Desconectar
Back\ to\ List=\u0412\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u0441\u043f\u0438\u0441\u043a\u0443
Status=\u0421\u0442\u0430\u0442\u0443\u0441
Build\ History=\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0441\u0431\u043e\u0440\u043e\u043a
Log=\u0416\u0443\u0440\u043d\u0430\u043b
System\ Information=\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0435
Disconnect=\u041e\u0442\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c
Back\ to\ List=Listeye D\u00f6n
Status=Durum
Build\ History=Yap\u0131land\u0131rma Ge\u00e7mi\u015fi
Log=Log
System\ Information=Sistem Bilgisi
Disconnect=Ba\u011flant\u0131y\u0131 Kes
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson">
<st:contentType value="application/x-java-jnlp-file" />
<j:new var="h" className="hudson.Functions" />
<j:set var="rootURL"
value="${request.scheme}://${request.serverName}:${request.serverPort}${request.contextPath}" />
<!--
See http://www.dallaway.com/acad/webstart/ for obtaining the certificate.
-->
<l:isAdminOrTest test="true">
<!-- See http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/syntax.html for the syntax -->
<jnlp spec="1.0+"
codebase="${rootURL}/computer/${h.encode(it.node.nodeName)}/">
<information>
<title>Slave Agent for ${it.displayName}</title>
<vendor>Hudson project</vendor>
<homepage href="https://hudson.dev.java.net/"/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j:set var="port" value="${request.getParameter('debugPort')}"/>
<j:choose>
<j:when test="${port!=null}">
<j2se version="1.5+" java-vm-args="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=${port}" />
</j:when>
<j:otherwise>
<j2se version="1.5+" />
</j:otherwise>
</j:choose>
<jar href="jnlpJars/jnlp-agent.jar"/>
<jar href="jnlpJars/remoting.jar"/>
</resources>
<application-desc main-class="hudson.jnlp.Main">
<argument>${request.serverName}</argument>
<argument>${rootURL}/tcpSlaveAgentListener/</argument>
<argument>${app.secretKey}</argument>
<argument>${it.node.nodeName}</argument>
</application-desc>
</jnlp>
</l:isAdminOrTest>
</j:jelly>
<!--
Various system information for diagnostics.
TODO: merge this with Hudson/systemInfo.jelly
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<l:layout title="${it.displayName} System Information">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<l:isAdmin>
<h1>System Properties</h1>
<t:propertyTable items="${it.systemProperties}" />
<h1>Environment Variables</h1>
<t:propertyTable items="${it.envVars}" />
<h1>Thread Dump</h1>
<j:forEach var="t" items="${it.getThreadDump().entrySet()}">
<h2>${t.key}</h2>
<pre>${t.value}</pre>
</j:forEach>
</l:isAdmin>
</l:main-panel>
</l:layout>
</j:jelly>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册