From 375cca85ed8397d10728e52f040e67de94e21722 Mon Sep 17 00:00:00 2001 From: kohsuke Date: Sun, 18 May 2008 21:42:57 +0000 Subject: [PATCH] Creating a package to host slave related code. git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@9393 71c3de6d-444a-0410-be80-ed276b4c234a --- core/src/main/java/hudson/Functions.java | 3 +- core/src/main/java/hudson/model/Computer.java | 3 +- core/src/main/java/hudson/model/Hudson.java | 2 + core/src/main/java/hudson/model/Slave.java | 2 + .../slaves/SlaveAvailabilityStrategy.java | 82 +++++++++++++++++++ .../hudson/slaves/SlaveReconnectionWork.java | 40 +++++++++ .../java/hudson/slaves/SlaveStartMethod.java | 47 +++++++++++ core/src/main/java/hudson/slaves/package.html | 5 ++ .../main/java/hudson/triggers/Trigger.java | 2 +- .../Demand/config.jelly | 0 .../Scheduled/config.jelly | 0 .../SlaveAvailabilityStrategy/config.jelly | 0 12 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/hudson/slaves/SlaveAvailabilityStrategy.java create mode 100644 core/src/main/java/hudson/slaves/SlaveReconnectionWork.java create mode 100644 core/src/main/java/hudson/slaves/SlaveStartMethod.java create mode 100644 core/src/main/java/hudson/slaves/package.html rename core/src/main/resources/hudson/{model => slaves}/SlaveAvailabilityStrategy/Demand/config.jelly (100%) rename core/src/main/resources/hudson/{model => slaves}/SlaveAvailabilityStrategy/Scheduled/config.jelly (100%) rename core/src/main/resources/hudson/{model => slaves}/SlaveAvailabilityStrategy/config.jelly (100%) diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index d97f64e451..a89857c06d 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -13,6 +13,8 @@ import hudson.security.SecurityRealm; import hudson.security.AuthorizationStrategy; import hudson.security.Permission; import hudson.util.Area; +import hudson.slaves.SlaveStartMethod; +import hudson.slaves.SlaveAvailabilityStrategy; import org.apache.commons.jexl.parser.ASTSizeFunction; import org.apache.commons.jexl.util.Introspector; import org.apache.commons.jelly.JellyContext; @@ -48,7 +50,6 @@ import java.util.TreeMap; import java.util.logging.LogRecord; import java.util.logging.SimpleFormatter; import java.util.regex.Pattern; -import java.util.regex.Matcher; /** * Utility functions used in views. diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index ab5fe008c5..0c2dbe4d6a 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1,6 +1,7 @@ package hudson.model; import hudson.EnvVars; +import hudson.slaves.SlaveStartMethod; import hudson.node_monitors.NodeMonitor; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; @@ -125,7 +126,7 @@ public abstract class Computer extends AbstractModelObject { /** * Returns true if this computer is supposed to be launched via JNLP. - * @deprecated see {@linkplain #isLaunchSupported()} and {@linkplain hudson.model.SlaveStartMethod} + * @deprecated see {@linkplain #isLaunchSupported()} and {@linkplain SlaveStartMethod} */ @Exported @Deprecated diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 3dbc281bcc..34d4e98f5a 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -14,6 +14,8 @@ import hudson.TcpSlaveAgentListener; import hudson.Util; import static hudson.Util.fixEmpty; import hudson.XmlFile; +import hudson.slaves.SlaveStartMethod; +import hudson.slaves.SlaveAvailabilityStrategy; import hudson.model.Descriptor.FormException; import hudson.model.listeners.ItemListener; import hudson.model.listeners.JobListener; diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 87caa18be0..c8366ec3f6 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -5,6 +5,8 @@ import hudson.FilePath; import hudson.Launcher; import hudson.Launcher.RemoteLauncher; import hudson.Util; +import hudson.slaves.SlaveStartMethod; +import hudson.slaves.SlaveAvailabilityStrategy; import hudson.maven.agent.Main; import hudson.maven.agent.PluginManagerInterceptor; import hudson.model.Descriptor.FormException; diff --git a/core/src/main/java/hudson/slaves/SlaveAvailabilityStrategy.java b/core/src/main/java/hudson/slaves/SlaveAvailabilityStrategy.java new file mode 100644 index 0000000000..304266a280 --- /dev/null +++ b/core/src/main/java/hudson/slaves/SlaveAvailabilityStrategy.java @@ -0,0 +1,82 @@ +package hudson.slaves; + +import hudson.util.DescriptorList; +import hudson.ExtensionPoint; +import hudson.model.Describable; +import hudson.model.Slave; +import hudson.model.Descriptor; +import org.kohsuke.stapler.StaplerRequest; +import net.sf.json.JSONObject; + +/** + * Slave availability strategy + */ +public abstract class SlaveAvailabilityStrategy implements Describable, 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.isLaunchSupported()) + c.tryReconnect(); + return 5; + } + + /** + * All registered {@link SlaveAvailabilityStrategy} implementations. + */ + public static final DescriptorList LIST = new DescriptorList( + 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 getDescriptor() { + return DESCRIPTOR; + } + + public static final Descriptor DESCRIPTOR = + new DescriptorImpl(); + + private static class DescriptorImpl extends Descriptor { + 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(); + } + + + } + } +} diff --git a/core/src/main/java/hudson/slaves/SlaveReconnectionWork.java b/core/src/main/java/hudson/slaves/SlaveReconnectionWork.java new file mode 100644 index 0000000000..8ace451274 --- /dev/null +++ b/core/src/main/java/hudson/slaves/SlaveReconnectionWork.java @@ -0,0 +1,40 @@ +package hudson.slaves; + +import hudson.model.Slave; +import hudson.model.Hudson; +import hudson.model.Queue; +import hudson.model.Executor; +import hudson.triggers.SafeTimerTask; + +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Periodically checks the slaves and try to reconnect dead slaves. + * + * @author Kohsuke Kawaguchi + */ +public class SlaveReconnectionWork extends SafeTimerTask { + protected void doRun() { + // use a weak hashmap + Map nextCheck = new WeakHashMap(); + for (Slave s : Hudson.getInstance().getSlaves()) { + if (!nextCheck.containsKey(s) || System.currentTimeMillis() > nextCheck.get(s)) { + final Queue queue = Hudson.getInstance().getQueue(); + boolean hasJob = false; + for (Executor exec: s.getComputer().getExecutors()) { + if (!exec.isIdle()) { + hasJob = true; + break; + } + } + // 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, s.getAvailabilityStrategy().check(s, state))); + nextCheck.put(s, System.currentTimeMillis() + 60 * 1000 * waitInMins); + } + } + } +} diff --git a/core/src/main/java/hudson/slaves/SlaveStartMethod.java b/core/src/main/java/hudson/slaves/SlaveStartMethod.java new file mode 100644 index 0000000000..5051174ab1 --- /dev/null +++ b/core/src/main/java/hudson/slaves/SlaveStartMethod.java @@ -0,0 +1,47 @@ +package hudson.slaves; + +import hudson.ExtensionPoint; +import hudson.model.Slave.ComputerImpl; +import hudson.model.Describable; +import hudson.model.Computer; +import hudson.remoting.Channel.Listener; +import hudson.util.DescriptorList; +import hudson.util.StreamTaskListener; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Extension point to allow control over how Slaves are started. + * + * @author Stephen Connolly + * @since 24-Apr-2008 22:12:35 + */ +public abstract class SlaveStartMethod implements Describable, ExtensionPoint { + /** + * Returns true if this {@link SlaveStartMethod} supports + * programatic launch of the slave agent in the target {@link Computer}. + */ + public boolean isLaunchSupported() { + return true; + } + + /** + * Launches the slave agent for the given {@link Computer}. + * + *

+ * If the slave agent is launched successfully, {@link ComputerImpl#setChannel(InputStream, OutputStream, OutputStream, Listener)} + * should be invoked in the end to notify Hudson of the established connection. + * The operation could also fail, in which case there's no need to make any callback notification, + * (except to notify the user of the failure through {@link StreamTaskListener}.) + * + * @param listener + * The progress of the launch, as well as any error, should be sent to this listener. + */ + public abstract void launch(ComputerImpl computer, StreamTaskListener listener); + + /** + * All registered {@link SlaveStartMethod} implementations. + */ + public static final DescriptorList LIST = new DescriptorList(); +} diff --git a/core/src/main/java/hudson/slaves/package.html b/core/src/main/java/hudson/slaves/package.html new file mode 100644 index 0000000000..97698b1840 --- /dev/null +++ b/core/src/main/java/hudson/slaves/package.html @@ -0,0 +1,5 @@ + + +Code related to slaves. + + \ No newline at end of file diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index 897c98bd8c..a6d8e00ad0 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -4,6 +4,7 @@ import antlr.ANTLRException; import hudson.DependencyRunner; import hudson.DependencyRunner.ProjectRunnable; import hudson.ExtensionPoint; +import hudson.slaves.SlaveReconnectionWork; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.Build; @@ -13,7 +14,6 @@ import hudson.model.FingerprintCleanupThread; import hudson.model.Hudson; import hudson.model.Item; import hudson.model.Project; -import hudson.model.SlaveReconnectionWork; import hudson.model.WorkspaceCleanupThread; import hudson.scheduler.CronTab; import hudson.scheduler.CronTabList; diff --git a/core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/Demand/config.jelly b/core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/Demand/config.jelly similarity index 100% rename from core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/Demand/config.jelly rename to core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/Demand/config.jelly diff --git a/core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/Scheduled/config.jelly b/core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/Scheduled/config.jelly similarity index 100% rename from core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/Scheduled/config.jelly rename to core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/Scheduled/config.jelly diff --git a/core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/config.jelly b/core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/config.jelly similarity index 100% rename from core/src/main/resources/hudson/model/SlaveAvailabilityStrategy/config.jelly rename to core/src/main/resources/hudson/slaves/SlaveAvailabilityStrategy/config.jelly -- GitLab