Search code examples
jenkinsgroovyjenkins-pipeline

How to run a closure that returns a value in parallel in Jenkins pipeline?


I want to check if I can delete some of our AWS EBS snapshots that meet a certain criteria. However, since we have a LOT of snapshots, I don't want to iterate one-by-one, and instead perform the check if I can delete them in parallel. I get a list of snapshots in JSON form like this

{
    "Snapshots": [
        {
            "Description": "",
            "Encrypted": false,
            "OwnerId": "0123456789",
            "Progress": "100%",
            "SnapshotId": "snap-0123456789",
            "StartTime": "2021-03-23T23:58:42.019000+00:00",
            "State": "completed",
            "VolumeId": "vol-ffffffff",
            "VolumeSize": 8,
            "OwnerAlias": "amazon",
            "StorageTier": "standard"
        },
        // more snapshots
    ]
}

Here's the (simplified) closure to determine if I can delete a snapshot, passing to it a snapshot element from the JSON

// Closure to check if I can delete snapshot
private Closure snapshotCanBeDeleted(final String s) {
  return {
    s.State.equals("completed")
  }
}

Here's the code that uses the above closure.

// Get a list of snapshots via AWS SDK or CLI in JSON
def snapshots = functionToGetAListOfSnapshots() // function not shown

// Create a map of snapshots and closures that can be run in parallel
Map<String, Closure> map = new TreeMap()
snapshots.Snapshots.each {
  map.put(it.SnapshotId, snapshotCanBeDeleted(it))
}
parallel map // This runs the snapshotCanBeDeleted(it) closures in parallel

But how I now print out the values of the closure, which are boolean values? I tried this

map.each {k,v ->
  println "Snapshot $k can be deleted: $v"
}

But I think this is trying to print the closure itself, instead of its value, which should be true for false, because I just get, without the v part of the map being printed out.

snap-0123456789 can be deleted: 
[Pipeline] echo
snap-1234567890 can be deleted: 
[Pipeline] echo
snap-9876543210 can be deleted: 

I want

snap-0123456789 can be deleted: true
[Pipeline] echo
snap-1234567890 can be deleted: false
[Pipeline] echo
snap-9876543210 can be deleted: true

Any clues? Is this not the proper way to run a closure that returns a value? Thanks.


Solution

  • parallel step doesn't modify the map you provide. Think of it as .each{}. So you will have to define a list outside the closure and put all the results there:

    def completedSnapshots = []
    
    private Closure snapshotCanBeDeleted(final String s) {
      return {
        if (s.State.equals("completed")) {
          completedSnapshots.add(s.SnapshotId)
        }
      }
    }