jenkinsjenkins-pipelinejenkins-groovy

Jenkins Pipeline: Shared Libraries failure to access instance classes


I am implementing significantly more complex rules for working with nodes which the built in node handling... well, can't handle. I need to use this in a function which dynamically generates stages which will be parallelized. I can NOT put this code into the pipeline block.

I want to create a shared library which deals with node objects. I have the shared library plugin installed and configured properly. It is finding and checking out my library and I can see changes to this library being propagated.

The base data this library will operate on is "all Nodes" determined at runtime. It can filter on labels It can look at how busy a node is It can look at online vs offline and if offline, stand it back up. (this is the critical requirement) I am working on being able to ask more detailed questions such as disk space and or operating system version

I have tried passing the current context into the library from the context of a function , but that comes across as class WorkFlowScript

def generateBuildStage(job) {
    def myNode = myNodes.freeNode(this, "${BUILDLABEL}")
    return {
        node myNode.nodeName
        stage ('Update Workspace') {
        ...

I need class jenkins.instance so I can generate the list of all nodes and iterate on it. I have tried importing the jenkins.model.* and hudson.model.* in the library and that does not work. I get method not defined errors. (I think because those objects are not defined in that context?)

If I try to address jenkins.instance in the pipeline script proper to try and generate the list there to pass to the library, the pipeline itself just stops working. I have no idea why. There are no errors.

I have tested this code in this raw pipeline script (outside the "pipeline" definition) and it works, but in a shared library context it does NOT work NOR will the pipeline scripting work if this code is inline. Some functions and the actual pipeline code omitted.

I am convinced this is related to scope, but I don't know how...

import hudson.model.*
import hudson.AbortException

Jenkins jenkins = Jenkins.instance
def targetNode = null
def candidates = []

for (Node node in jenkins.nodes) {
    for (label in node.getAssignedLabels()) {
        println("Testing label ${label}")
        if (buildGroup.equals(label.toString().trim())) {
            println("Found a match ${label}")
            candidates.add(node)
        }
    }
}

if (candidates.size < 1) {
    throw new AbortException("TestChrisK aborted: No such build label ${buildGroup}.")
}
for (node in candidates) {    
    if ( node.getComputer().isOnline() && (node.getComputer().countBusy() < 1)  ) {
        targetNode = node
    }
}
// If we did not find a completely free node, look for one doing only 1 thing
if (! targetNode) {
    for (node in candidates) {
        if ( node.getComputer().isOnline() && (node.getComputer().countBusy() < 2)  ) {
            targetNode = node
        }
    }
}
// Otherwise quit
if (! targetNode) {
     throw new AbortException("TestChrisK aborted: No available nodes in ${buildGroup}.")
}
else {
    println("target node = " + targetNode.nodeName )
}

Solution

  • Not related to scope, Jenkins class has a static method that returns its instance, singleton pattern

    def nodes = Jenkins.get().nodes