Fix: Route existing nodes through updateNode to prevent configuration…#26933
Fix: Route existing nodes through updateNode to prevent configuration…#26933mehtahet619 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adjusts Nodes#addNode to treat adding a node with an already-existing name as an update rather than an add, aiming to route through the “update” flow for existing nodes.
Changes:
- Added an early check for existing node names in
addNode. - Routed existing-name additions to
updateNode(node)and returned early.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // THE FIX: Route to the proper update flow if it already exists | ||
| if (nodes.containsKey(node.getNodeName())) { | ||
| updateNode(node); | ||
| return; | ||
| } |
| if (nodes.containsKey(node.getNodeName())) { | ||
| updateNode(node); | ||
| return; | ||
| } |
| Jenkins.checkGoodName(node.getNodeName()); | ||
| } | ||
|
|
||
| // THE FIX: Route to the proper update flow if it already exists |
| updateNode(node); | ||
| return; | ||
| } | ||
|
|
da18a46 to
96f7a20
Compare
| return; | ||
| } | ||
| // If a node with this name exists, treat this as an update to preserve update semantics | ||
| updateNode(node); |
There was a problem hiding this comment.
Not sure but is calling updateNode really fixing the issue?
Shouldn't that call replaceNode(old, node)
There was a problem hiding this comment.
Taking a closer look, I think that this will also not fix the issue.
There was a problem hiding this comment.
Best to add a unit test that shows that the problem is fixed
96f7a20 to
76b9c81
Compare
| Node old = nodes.putIfAbsent(node.getNodeName(), node); | ||
|
|
||
| if (old != null) { | ||
| if (node == old) { | ||
| return; | ||
| } | ||
| // Use replaceNode as suggested by maintainers to ensure deep configuration sync | ||
| replaceNode(old, node); | ||
| } else { | ||
| handleAddedNode(node, null); |
| Node old = nodes.putIfAbsent(node.getNodeName(), node); | ||
|
|
||
| if (old != null) { | ||
| if (node == old) { | ||
| return; | ||
| } | ||
| // Use replaceNode as suggested by maintainers to ensure deep configuration sync | ||
| replaceNode(old, node); |
| if (node == old) { | ||
| return; | ||
| } | ||
| // Use replaceNode as suggested by maintainers to ensure deep configuration sync |
|
After the comment #26692 (comment) it is clear that we run into the case |
76b9c81 to
d0bf091
Compare
|
You will not be able to solve the problem by calling |
d0bf091 to
8cb3236
Compare
| Node old = nodes.put(node.getNodeName(), node); | ||
| if (node != old) { | ||
| handleAddedNode(node, old); | ||
| } else { | ||
| // Fixes #26692: Explicitly update the active Computer so it picks up | ||
| // the mutated configuration when the exact same instance is re-added. | ||
| Jenkins j = Jenkins.get(); | ||
| j.updateComputers(node); |
| if (node != old) { | ||
| handleAddedNode(node, old); | ||
| } else { | ||
| // Fixes #26692: Explicitly update the active Computer so it picks up |
8cb3236 to
9c4d32f
Compare
| // Array used to safely capture the existing node from inside the lambda | ||
| final Node[] previousNode = new Node[1]; | ||
|
|
||
| // Atomic swap: The map is locked ONLY for this tiny operation | ||
| nodes.compute(node.getNodeName(), (name, existingNode) -> { | ||
| previousNode[0] = existingNode; | ||
| return node; | ||
| }); | ||
|
|
||
| Node old = previousNode[0]; |
| // Atomic swap: The map is locked ONLY for this tiny operation | ||
| nodes.compute(node.getNodeName(), (name, existingNode) -> { |
Fixes #26692
Testing done
Manually verified the logic path. Previously, calling
addNode()with an existing node name would silently overwrite theNodeconfiguration in the internalConcurrentMapwithout notifying the activeComputerobject. This resulted in the running agent caching old configurations (such asSSHLauncherparameters) until a manual restart.By delegating existing nodes to the dedicated
updateNode()method, theComputerobject properly evaluates the new configuration and reconnects if necessary to sync the live runtime state with the updated properties.Screenshots (UI changes only)
Before
N/A (Core logic change)
After
N/A
Proposed changelog entries
addNodetriggers the proper runtime update lifecycle.Proposed changelog category
/label bug
Proposed upgrade guidelines
N/A
Submitter checklist
@Restrictedor have@since TODOJavadocs, as appropriate.@Deprecated(since = "TODO")or@Deprecated(forRemoval = true, since = "TODO"), if applicable.Desired reviewers
@jenkinsci/core-pr-reviewers