提交 1ace6b21 编写于 作者: K kohsuke

added NodeMonitor abstraction which performs node monitoring and diagnostics.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@3923 71c3de6d-444a-0410-be80-ed276b4c234a
上级 cd08deec
package hudson.model;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import hudson.node_monitors.NodeMonitor;
import java.util.List;
/**
* Serves as the top of {@link Computer}s in the URL hierarchy.
* <p>
* Getter methods are prefixed with '_' to avoid collision with computer names.
*
* @author Kohsuke Kawaguchi
*/
public final class ComputerSet implements ModelObject {
public String getDisplayName() {
return "nodes";
}
public List<NodeMonitor> get_monitors() {
return NodeMonitor.LIST;
}
public Computer[] get_all() {
return Hudson.getInstance().getComputers();
}
public Computer getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
return Hudson.getInstance().getComputer(token);
}
}
package hudson.node_monitors;
import hudson.model.Computer;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.triggers.Trigger;
import hudson.util.ClockDifference;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* {@link NodeMonitor} that checks clock of {@link Node} to
* detect out of sync clocks.
*
* @author Kohsuke Kawaguchi
*/
public class ClockMonitor extends NodeMonitor {
public String getColumnCaption() {
return "Clock Diff";
}
/**
* Obtains the difference.
*/
public ClockDifference getDifferenceFor(Computer c) {
if(record==null) {
// if this is the first time, try to check it now
if(inProgress==null) {
synchronized(ClockMonitor.class) {
if(inProgress==null)
new Record().start();
}
}
return null;
}
return record.diff.get(c);
}
/**
* Represents the last record of the update
*/
private static volatile Record record = null;
/**
* Represents the update activity in progress.
*/
private static volatile Record inProgress = null;
/**
* Thread that computes the clock difference, as well as the data structure to record
* the result.
*/
private static final class Record extends Thread {
/**
* Last computed clock difference.
*/
private final Map<Computer,ClockDifference> diff = new HashMap<Computer,ClockDifference>();
/**
* When was {@link #diff} last updated?
*/
private Date lastUpdated;
public Record() {
super("clock monitor update thread started "+new Date());
synchronized(ClockMonitor.class) {
if(inProgress!=null) {
// maybe it got stuck?
LOGGER.warning("Previous clock check still in progress. Interrupting");
inProgress.interrupt();
}
inProgress = this;
}
}
public void run() {
try {
long startTime = System.currentTimeMillis();
for( Computer c : Hudson.getInstance().getComputers() ) {
Node n = c.getNode();
if(n!=null && !c.isOffline())
try {
diff.put(c, n.getClockDifference());
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to check clock", e);
}
}
lastUpdated = new Date();
synchronized(ClockMonitor.class) {
assert inProgress==this;
inProgress = null;
record = this;
}
LOGGER.info("Clock difference check completed in "+(System.currentTimeMillis()-startTime)+"ms");
} catch (InterruptedException e) {
LOGGER.log(Level.WARNING,"Clock difference check aborted",e);
}
}
}
private static final Logger LOGGER = Logger.getLogger(ClockMonitor.class.getName());
static {
long HOUR = 1000*60*60L;
// check every hour
Trigger.timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
// start checking
new Record().start();
}
},HOUR,HOUR);
}
}
package hudson.node_monitors;
import hudson.ExtensionPoint;
import hudson.model.ComputerSet;
import hudson.model.Node;
import java.util.List;
import java.util.ArrayList;
/**
* Extension point for managing and monitoring {@link Node}s.
*
* <h2>Views</h2>
* <dl>
* <dt>column.jelly</dt>
* <dd>
* Invoked from {@link ComputerSet} <tt>index.jelly</tt> to render a column.
* The {@link NodeMonitor} instance is accessible through the "from" variable.
* Also see {@link #getColumnCaption()}.
* </dl>
*
* @author Kohsuke Kawaguchi
* @since 1.123
*/
public abstract class NodeMonitor implements ExtensionPoint {
/**
* Returns the name of the column to be added to {@link ComputerSet} index.jelly.
*
* @return
* null to not render a column. The convention is to use capitalization like "Foo Bar Zot".
*/
public abstract String getColumnCaption();
/**
* All registered {@link NodeMonitor}s.
*/
public static final List<NodeMonitor> LIST = new ArrayList<NodeMonitor>();
static {
LIST.add(new ClockMonitor());
}
}
......@@ -17,7 +17,7 @@ public final class ClockDifference {
* Positive value means the slave is behind the master,
* negative value means the slave is ahead of the master.
*/
public final Long diff;
public final long diff;
public ClockDifference(long value) {
this.diff = value;
......@@ -30,6 +30,13 @@ public final class ClockDifference {
return Math.abs(diff)>5000;
}
/**
* Gets the absolute value of {@link #diff}.
*/
public long abs() {
return Math.abs(diff);
}
/**
* Gets the clock difference in HTML string.
*/
......
<!--
Entrance to the configuration page
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:layout title="Nodes">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<j:set var="monitors" value="${it._monitors}"/>
<table id="projectstatus" class="sortable pane">
<tr>
<th width="32">S</th>
<th initialSortDir="down">Name</th>
<j:forEach var="m" items="${monitors}">
<j:if test="${m.columnCaption!=null}">
<th>${m.columnCaption}</th>
</j:if>
</j:forEach>
</tr>
<j:forEach var="c" items="${it._all}">
<tr>
<td width="32" data="${c.icon}">
<img src="${rootURL}/images/32x32/${c.icon}" width="32" height="32" />
</td>
<td><a href="${rootURL}/${c.url}">${c.displayName}</a></td>
<j:forEach var="m" items="${monitors}">
<j:if test="${m.columnCaption!=null}">
<st:include page="column.jelly" from="${m}" />
</j:if>
</j:forEach>
</tr>
</j:forEach>
</table>
</l:main-panel>
</l:layout>
</j:jelly>
<!--
Side panel
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<l:header />
<l:side-panel>
<l:tasks>
<l:task icon="images/24x24/up.gif" href="${rootURL}/" title="Back to Dashboard" />
</l:tasks>
</l:side-panel>
</j:jelly>
\ No newline at end of file
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:s="/lib/form">
<j:set var="diff" value="${from.getDifferenceFor(c)}"/>
<j:choose>
<j:when test="${diff==null}">
<td data="-1">N/A</td>
</j:when>
<j:otherwise>
<td data="${diff.abs()}">${diff.toHtml()}</td>
</j:otherwise>
</j:choose>
</j:jelly>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册