How to find the agent that a FlowNode is executing on?

372 views
Skip to first unread message

Gregory Paciga

unread,
Jul 8, 2021, 12:48:30 PM7/8/21
to Jenkins Developers

I'm working on a Jenkins plugin that implements org.jenkinsci.plugins.workflow.flow.GraphListener to monitor how a pipeline is progressing. It receives org.jenkinsci.plugins.workflow.graph.FlowNode objects. I would like to be able to report on which agent a particular FlowNode is running on.

How can I go from an instance of a FlowNode to its hudson.model.Computer, hudson.model.Node, or anything else that will tell me the agent's name? I am ok with assuming that the FlowNode is currently executing, or is contained inside a node{} block if it helps, but would prefer to keep it general.

I've so far tried browsing through the related FlowExecution, FlowExecutionOwner, Queue.Executable, and Subtask classes, but if it's in there I haven't found it.

The closest I've come so far is to use node.iterateEnclosingBlocks(). I can find FlowNodes where an agent was allocated with .getDisplayFunctionName().equals('node'), but not which agent was allocated. I thought the WorkspaceAction action may help since it has a getNode() method that should return the agent name as a string, but it returns nothing:

for (FlowNode enclosing : node.iterateEnclosingBlocks()) {
    WorkspaceAction ws = enclosing.getAction(WorkspaceAction.class);
    if (ws != null) {
        System.out.println(ws.getNode()); // outputs empty string 
    }
}

Can anyone direct me to the right methods/classes to get this information?


Jesse Glick

unread,
Jul 8, 2021, 5:57:42 PM7/8/21
to Jenkins Dev
On Thu, Jul 8, 2021 at 12:48 PM Gregory Paciga <gregory...@cbc.ca> wrote:

I'm working on a Jenkins plugin that implements org.jenkinsci.plugins.workflow.flow.GraphListener to monitor how a pipeline is progressing. It receives org.jenkinsci.plugins.workflow.graph.FlowNode objects. I would like to be able to report on which agent a particular FlowNode is running on.

Gregory Paciga

unread,
Jul 9, 2021, 12:53:04 PM7/9/21
to Jenkins Developers
Thanks for that suggestion, that did let me make some progress by getting access to the StepContext (from which I can get the Computer), but unfortunately that creates other problems. In particular, information which is available in a FlowNode doesn't seem available from the Step.

I can do context.get(FlowNode.class), but some information is still missing, e.g. for a "stage" Step, the FlowNode (a StepStartNode) doesn't yet have a LabelAction associated with it. If I get the same StepStartNode from my GraphListener (or at least what I think is the same - a StepStartNode associated with the beginning of a new stage), I can use the LabelAction to get the stage name.

I also have the problem that I need to use both StepStartNode and the StepEndNode, so I can get information like the step duration, which GraphListener does provide. That doesn't seem to be possible with a StepListener, which only sees the start of each step. While I would prefer to be able to get the Computer at both the start and end (to make it easier to do things like correlate a specific Computer with error messages at the end of the stage), I could compromise by using StepListener to get the start of a step and GraphListener to get the end of it, but only if the stage name can be found.

Given the FlowNode from GraphListener, is there a way to get to the StepContext?

Jesse Glick

unread,
Jul 9, 2021, 3:03:47 PM7/9/21
to Jenkins Dev
On Fri, Jul 9, 2021 at 12:53 PM Gregory Paciga <gregory...@cbc.ca> wrote:
for a "stage" Step, the FlowNode (a StepStartNode) doesn't yet have a LabelAction associated with it.

Yes, you need to wait for the next step to run, or at least some time. Same as for `GraphListener.Synchronous`, and (depending on luck) regular `GraphListener`.

I could compromise by using StepListener to get the start of a step and GraphListener to get the end of it, but only if the stage name can be found.

What do you need a stage name for? Just track the `FlowNode.id`.

Given the FlowNode from GraphListener, is there a way to get to the StepContext?

No. 

Gregory Paciga

unread,
Jul 9, 2021, 4:51:17 PM7/9/21
to Jenkins Developers
> What do you need a stage name for? Just track the `FlowNode.id`.

The output is intended for humans, to whom FlowNode.id will be meaningless, and it is also prone to change, meaning it can't reliably be used to track performance of a stage over time.

Jesse Glick

unread,
Jul 9, 2021, 6:05:46 PM7/9/21
to Jenkins Dev
On Fri, Jul 9, 2021 at 4:51 PM Gregory Paciga <gregory...@cbc.ca> wrote:
The output is intended for humans, to whom FlowNode.id will be meaningless

Right, I mean simply to correlate an event from a `GraphListener` with an event from a `StepListener`. 

Gregory Paciga

unread,
Jul 12, 2021, 11:49:51 AM7/12/21
to Jenkins Developers

Do you mean to correlate them offline, or is there a way of doing it live? If both listeners have access to the same node, I feel there must be some way of getting the same information.

Jenkins at some level must know what agent a flownode is on... if there's not a way of getting at that information from the flownode itself (and I'd still really like to know *why* that is the case), there must be another angle to find it.

Jesse Glick

unread,
Jul 12, 2021, 12:59:02 PM7/12/21
to Jenkins Dev
On Mon, Jul 12, 2021 at 11:50 AM Gregory Paciga <gregory...@cbc.ca> wrote:
If both listeners have access to the same node, I feel there must be some way of getting the same information.

`GraphListener` has the `FlowNode` as it is being added (but no runtime details about the program) whereas `StepListener` has the information about the step that the program is about to run (but before it has added to the graph). So they are complementary. In your case it looks like you just need to implement both and pass information from one to the other, keyed by node id. It would be helpful to have some richer listener interface that offers both kinds of information at once, but currently there is no such API.

if there's not a way of getting at that information from the flownode itself (and I'd still really like to know *why* that is the case)

The `FlowNode` survives past the end of the build (currently as a set of XML files) and is just a record of what the structure of the build was, including any persisted `Action`s. The live objects that were originally passed around in the program, saved to `program.dat` and including anything present in `StepContext` for the dynamic scope of a block, are not retained.

Anyway, back to your original question, https://javadoc.jenkins.io/plugin/workflow-api/org/jenkinsci/plugins/workflow/actions/WorkspaceAction.html#getNode-- ought to tell you the name of the agent running a `node` block, or the empty string in the case of a controller executor (typically ill-advised). While the `node` block is running, you can look up the actual `Node` based on that name. (After the block exits, this is no longer valid; for example, when using the `kubernetes` plugin, the agent will have been immediately discarded.)

Gregory Paciga

unread,
Jul 12, 2021, 1:57:39 PM7/12/21
to Jenkins Developers
https://javadoc.jenkins.io/plugin/workflow-api/org/jenkinsci/plugins/workflow/actions/WorkspaceAction.html#getNode-- ought to tell you the name of the agent running a `node` block, or the empty string in the case of a controller executor (typically ill-advised).

That's exactly where I started, and you know, I think that's my mistake. I'm working in a plugin with mvn hpi:run, which only has the single controller node. I thought I was getting an empty string because the information wasn't there at all, when in fact the empty string was probably indicated exactly what I should have expected - that my node{} block was running on the controller.


 

Jesse Glick

unread,
Jul 12, 2021, 2:28:00 PM7/12/21
to Jenkins Dev
On Mon, Jul 12, 2021 at 1:58 PM Gregory Paciga <gregory...@cbc.ca> wrote:
I'm working in a plugin with mvn hpi:run, which only has the single controller node.

Reply all
Reply to author
Forward
0 new messages