Skip to content

Commit ccaf541

Browse files
authored
Fix Jenkins#updateNode to call NodeListener#onUpdated (#10397)
2 parents 1c8a9ad + b1848e3 commit ccaf541

File tree

5 files changed

+51
-12
lines changed

5 files changed

+51
-12
lines changed

core/src/main/java/hudson/model/Node.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public boolean isHoldOffLaunchUntilSave() {
138138
}
139139

140140
/**
141+
* In most cases, you should not call this method directly, but {@link Jenkins#updateNode(Node)} instead.
141142
* @since 1.635.
142143
*/
143144
@Override
@@ -281,7 +282,7 @@ void setTemporaryOfflineCause(OfflineCause cause) {
281282
try {
282283
if (temporaryOfflineCause != cause) {
283284
temporaryOfflineCause = cause;
284-
save();
285+
Jenkins.get().updateNode(this);
285286
}
286287
if (temporaryOfflineCause != null) {
287288
Listeners.notify(ComputerListener.class, false, l -> l.onTemporarilyOffline(toComputer(), temporaryOfflineCause));

core/src/main/java/hudson/model/Slave.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,15 @@ public ComputerLauncher getLauncher() {
248248
return launcher == null ? new JNLPLauncher() : launcher;
249249
}
250250

251+
/**
252+
* @deprecated In most cases, you should not call this method directly, but {@link Jenkins#updateNode(Node)} instead.
253+
*/
254+
@Override
255+
@Deprecated
256+
public void save() throws IOException {
257+
super.save();
258+
}
259+
251260
public void setLauncher(ComputerLauncher launcher) {
252261
this.launcher = launcher;
253262
}

core/src/main/java/jenkins/model/Nodes.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import java.util.List;
4848
import java.util.Map;
4949
import java.util.TreeMap;
50-
import java.util.concurrent.Callable;
5150
import java.util.concurrent.ConcurrentMap;
5251
import java.util.concurrent.ConcurrentSkipListMap;
5352
import java.util.concurrent.atomic.AtomicBoolean;
@@ -203,17 +202,18 @@ public XmlFile getConfigFile(String nodeName) {
203202
* @since 1.634
204203
*/
205204
public boolean updateNode(final @NonNull Node node) throws IOException {
205+
return updateNode(node, true);
206+
}
207+
208+
private boolean updateNode(final @NonNull Node node, boolean fireListener) throws IOException {
206209
boolean exists;
207210
try {
208-
exists = Queue.withLock(new Callable<>() {
209-
@Override
210-
public Boolean call() throws Exception {
211-
if (node == nodes.get(node.getNodeName())) {
212-
jenkins.trimLabels(node);
213-
return true;
214-
}
215-
return false;
211+
exists = Queue.withLock(() -> {
212+
if (node == nodes.get(node.getNodeName())) {
213+
jenkins.trimLabels(node);
214+
return true;
216215
}
216+
return false;
217217
});
218218
} catch (RuntimeException e) {
219219
// should never happen, but if it does let's do the right thing
@@ -225,7 +225,9 @@ public Boolean call() throws Exception {
225225
if (exists) {
226226
// TODO there is a theoretical race whereby the node instance is updated/removed after lock release
227227
node.save();
228-
// TODO should this fireOnUpdated?
228+
if (fireListener) {
229+
NodeListener.fireOnUpdated(node, node);
230+
}
229231
return true;
230232
}
231233
return false;
@@ -252,7 +254,7 @@ public void run() {
252254
newOne.onLoad(Nodes.this, newOne.getNodeName());
253255
}
254256
});
255-
updateNode(newOne);
257+
updateNode(newOne, false);
256258
if (!newOne.getNodeName().equals(oldOne.getNodeName())) {
257259
LOGGER.fine(() -> "deleting " + new File(getRootDir(), oldOne.getNodeName()));
258260
Util.deleteRecursive(new File(getRootDir(), oldOne.getNodeName()));

test/src/test/java/hudson/model/NodeTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import edu.umd.cs.findbugs.annotations.NonNull;
4141
import hudson.EnvVars;
42+
import hudson.ExtensionList;
4243
import hudson.FilePath;
4344
import hudson.model.Node.Mode;
4445
import hudson.model.Queue.WaitingItem;
@@ -61,6 +62,7 @@
6162
import java.util.GregorianCalendar;
6263
import java.util.List;
6364
import jenkins.model.Jenkins;
65+
import jenkins.model.NodeListener;
6466
import jenkins.security.QueueItemAuthenticatorConfiguration;
6567
import org.htmlunit.HttpMethod;
6668
import org.htmlunit.Page;
@@ -91,23 +93,40 @@ public void before() {
9193
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
9294
}
9395

96+
@TestExtension("testSetTemporaryOfflineCause")
97+
public static class NodeListenerImpl extends NodeListener {
98+
private int count;
99+
100+
public static int getCount() {
101+
return ExtensionList.lookupSingleton(NodeListenerImpl.class).count;
102+
}
103+
104+
@Override
105+
protected void onUpdated(@NonNull Node oldOne, @NonNull Node newOne) {
106+
count++;
107+
}
108+
}
109+
94110
@Test
95111
public void testSetTemporaryOfflineCause() throws Exception {
96112
Node node = j.createOnlineSlave();
97113
FreeStyleProject project = j.createFreeStyleProject();
98114
project.setAssignedLabel(j.jenkins.getLabel(node.getDisplayName()));
99115
OfflineCause cause = new OfflineCause.ByCLI("message");
100116
node.setTemporaryOfflineCause(cause);
117+
assertThat(NodeListenerImpl.getCount(), is(1));
101118
for (ComputerListener l : ComputerListener.all()) {
102119
l.onOnline(node.toComputer(), TaskListener.NULL);
103120
}
104121
assertEquals("Node should have offline cause which was set.", cause, node.toComputer().getOfflineCause());
105122
OfflineCause cause2 = new OfflineCause.ByCLI("another message");
106123
node.setTemporaryOfflineCause(cause2);
124+
assertThat(NodeListenerImpl.getCount(), is(2));
107125
assertEquals("Node should have the new offline cause.", cause2, node.toComputer().getOfflineCause());
108126
// Exists in some plugins
109127
node.toComputer().setTemporarilyOffline(false, new OfflineCause.ByCLI("A third message"));
110128
assertThat(node.getTemporaryOfflineCause(), nullValue());
129+
assertThat(NodeListenerImpl.getCount(), is(3));
111130
}
112131

113132
@Test

test/src/test/java/jenkins/model/NodeListenerTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ public void crud() throws Exception {
4949
verifyNoMoreInteractions(mock);
5050
}
5151

52+
@Test
53+
public void updateNode() throws Exception {
54+
Node agent = j.createSlave();
55+
agent.setLabelString("some label");
56+
Jenkins.get().updateNode(agent);
57+
verify(mock, times(1)).onUpdated(any(Node.class), any(Node.class));
58+
}
59+
5260
private CLICommandInvoker cli(CLICommand cmd) {
5361
return new CLICommandInvoker(j, cmd);
5462
}

0 commit comments

Comments
 (0)