Pass variables into a podTemplate loaded from shared library?

In a shared library I have this generic pipeline:

sharedlib/vars/agentLauncher.groovy

def launch(Closure body) {
  String podLabel = "jenkins-agent-${UUID.randomUUID().toString()}"
  String agentImage = 'my-jenkins-agent:latest'
  env.agentImage = agentImage
  podTemplate(label: podLabel, yaml: libraryResource('agentPodTemplate.yaml')) {    
    timestamps {
        node(podLabel) {
            container('my-jenkins-agent') {
              //env.agentImage = agentImage
              body.call()
            }
        }
      }
  }
}

where I am trying to pass the agentImage as a parameter to the podTemplate (located in the same sharedLib) :

sharedlib/resources/agentPodTemplate.yaml

apiVersion: v1
kind: Pod
spec:
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:4.11-1
  - name: my-jenkins-agent
    image: "${env.agentImage}"
    #image: ${agentImage}    
    #image: ${agentImage}          
    #image: my-jenkins-agent:latest
    command: ['cat']
    resources:
      limits:
        cpu : 1
        memory : 4Gi
      requests:
        cpu: 200m
        memory: 1Gi
    tty: true

But when I run that from my pipeline in another repo:

Jenkinsfile

@Library(value="sharedlib", changelog=false) _
agentLauncher.launch() {
    stage('Checkout') {
        checkout scm
    }
    stage('build') {
      container('my-jenkins-agent') {
        sh 'whoami'  
      }
    }    
}

I get the error:

[Warning][jenkins/jenkins-agent-e9b3e42c-6920-44f4-9a38-caab96a520f8-148zq-rwg3b][Failed] Error: InvalidImageName
[Warning][jenkins/jenkins-agent-e9b3e42c-6920-44f4-9a38-caab96a520f8-148zq-rwg3b][InspectFailed] Failed to apply default image tag "${agentImage}": couldn't parse image reference "${agentImage}": invalid reference format: repository name must be lowercase

so the variable is clearly not expanded/resolved at all.

I have looked at:

Any suggestions on how to make this work?

I have done something similar, I hope this is helpful. In this case I use it to pass the environment variable CONTAINER_REGISTRY to the template:

Here is my yaml template, the $env.CONTAINER_REGISTRY is regular groovy templating.

# resources/com/company/distribution/pod-templates/upload-agent.yaml
---
apiVersion: v1
kind: Pod
spec:
  imagePullSecrets:
    - name: artifact-registry
  containers:
    - name: upload-cli
      image: $env.CONTAINER_REGISTRY/uploadcli:v1.0.0
      command:
        - cat
      tty: true

I have a custom step to load the template in the library

// vars/kubernetesPodTemplate.groovy
def call(Map config=[:]) {

    def template = libraryResource("com/company/distribution/pod-templates/${config.name}.yaml")

    if (config.binding) {
        def engine = new groovy.text.GStringTemplateEngine()
        template = engine.createTemplate(template).make(config.binding).toString()
    }

    return template
}

And here is the step in use, I just passed in the env into the template, but you could pass what ever you need :slight_smile:

agent {
    kubernetes {
        yaml kubernetesPodTemplate(name: "upload-agent", binding: ['env': env])
        defaultContainer 'upload-cli'
        showRawYaml false
    }
}
1 Like

Thanks for the input! I don’t actually need to read the values as ENVs so now I am just doing:

def launch(Closure body) {

  String agentImage = 'my-jenkins-agent:latest'
  String podLabel = "jenkins-agent-${UUID.randomUUID().toString()}"

  def config = [agentImage: agentImage]

  def template = libraryResource("agentPodTemplate.yaml")

  @NonCPS
  def engine = new groovy.text.GStringTemplateEngine()
  template = engine.createTemplate(template).make(config).toString()

  println template 
  // Output looks correct!

  podTemplate(label: podLabel, yaml: template) {
    timestamps {
        node(podLabel) {
            container('my-jenkins-agent') {
              body.call()
            }
        }
      }
  }
}

When I run the above println template I can see the variables are substituted as expected. But I get this error afterwards:

[Pipeline] End of Pipeline
an exception which occurred:
	in field com.cloudbees.groovy.cps.impl.BlockScopeEnv.locals
	in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@61565295
	in field com.cloudbees.groovy.cps.impl.CpsClosureDef.capture
	in object com.cloudbees.groovy.cps.impl.CpsClosureDef@485faf50
	in field com.cloudbees.groovy.cps.impl.CpsClosure.def
	in object org.jenkinsci.plugins.workflow.cps.CpsClosure2@7f0be3af
	in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures
	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@1bb5c3c3
	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@1bb5c3c3
Caused: java.io.NotSerializableException: groovy.text.GStringTemplateEngine
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:274)
	at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)

I don’t need to be able to resume this pipeline after a reboot or similar so if its possible to disable that feature all together it would nice (I assume that is what is causing this error).