package hudson.model; import hudson.EnvVars; import hudson.Util; import hudson.slaves.ComputerLauncher; import hudson.slaves.RetentionStrategy; import hudson.node_monitors.NodeMonitor; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.tasks.BuildWrapper; import hudson.tasks.Publisher; import hudson.util.DaemonThreadFactory; import hudson.util.RemotingDiagnostics; import hudson.util.RunList; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.LogRecord; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; /** * Represents the running state of a remote computer that holds {@link Executor}s. * *
* {@link Executor}s on one {@link Computer} are transparently interchangeable * (that is the definition of {@link Computer}.) * *
* This object is related to {@link Node} but they have some significant difference. * {@link Computer} primarily works as a holder of {@link Executor}s, so * if a {@link Node} is configured (probably temporarily) with 0 executors, * you won't have a {@link Computer} object for it. * * Also, even if you remove a {@link Node}, it takes time for the corresponding * {@link Computer} to be removed, if some builds are already in progress on that * node. * *
* This object also serves UI (since {@link Node} is an interface and can't have
* related side pages.)
*
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public abstract class Computer extends AbstractModelObject {
private final CopyOnWriteArrayList
* When this value is decreased, it is temporarily possible
* for {@link #executors} to have a larger number than this.
*/
// ugly name to let EL access this
public int getNumExecutors() {
return numExecutors;
}
/**
* Returns the {@link Node} that this computer represents.
*/
public Node getNode() {
if(nodeName==null)
return Hudson.getInstance();
return Hudson.getInstance().getSlave(nodeName);
}
@Exported
public boolean isOffline() {
return temporarilyOffline || getChannel()==null;
}
/**
* Returns true if this computer is supposed to be launched via JNLP.
* @deprecated see {@linkplain #isLaunchSupported()} and {@linkplain ComputerLauncher}
*/
@Exported
@Deprecated
public boolean isJnlpAgent() {
return false;
}
/**
* Returns true if this computer can be launched by Hudson.
*/
@Exported
public boolean isLaunchSupported() {
return true;
}
/**
* Returns true if this node is marked temporarily offline by the user.
*
*
* In contrast, {@link #isOffline()} represents the actual online/offline
* state. For example, this method may return false while {@link #isOffline()}
* returns true if the slave agent failed to launch.
*
* @deprecated
* You should almost always want {@link #isOffline()}.
* This method is marked as deprecated to warn people when they
* accidentally call this method.
*/
@Exported
public boolean isTemporarilyOffline() {
return temporarilyOffline;
}
public void setTemporarilyOffline(boolean temporarilyOffline) {
this.temporarilyOffline = temporarilyOffline;
Hudson.getInstance().getQueue().scheduleMaintenance();
}
@Exported
public String getIcon() {
if(isOffline())
return "computer-x.gif";
else
return "computer.gif";
}
@Exported
public String getDisplayName() {
return nodeName;
}
public String getCaption() {
return Messages.Computer_Caption(nodeName);
}
public String getUrl() {
return "computer/"+getDisplayName()+"/";
}
/**
* Returns projects that are tied on this node.
*/
public List
* If this computer is already idle, the return value will point to the
* time in the past since when this computer has been idle.
*
*
* If this computer is busy, the return value will point to the
* time in the future where this computer will be expected to become free.
*/
public final long getIdleStartMilliseconds() {
long firstIdle = Long.MIN_VALUE;
for (Executor e : executors) {
firstIdle = Math.max(firstIdle, e.getIdleStartMilliseconds());
}
return firstIdle;
}
/**
* Returns the time when this computer first became in demand.
*/
public final long getDemandStartMilliseconds() {
long firstDemand = Long.MAX_VALUE;
for (Queue.BuildableItem item : Hudson.getInstance().getQueue().getBuildableItems(this)) {
firstDemand = Math.min(item.buildableStartMilliseconds, firstDemand);
}
return firstDemand;
}
/**
* Called by {@link Executor} to kill excessive executors from this computer.
*/
/*package*/ synchronized void removeExecutor(Executor e) {
executors.remove(e);
if(executors.isEmpty())
Hudson.getInstance().removeComputer(this);
}
/**
* Interrupt all {@link Executor}s.
*/
public void interrupt() {
for (Executor e : executors) {
e.interrupt();
}
}
public String getSearchUrl() {
return "computer/"+nodeName;
}
/**
* {@link RetentionStrategy} associated with this computer.
*
* @return
* never null. This method return {@code RetentionStrategy super T>} where
* {@code T=this.getClass()}.
*/
public abstract RetentionStrategy getRetentionStrategy();
/**
* Expose monitoring data for the remote API.
*/
@Exported(inline=true)
public Map