KeptnTaskDefinition

Define tasks that can be run pre- or post-deployment

A KeptnTaskDefinition defines tasks that are run by the Keptn Lifecycle Toolkit as part of the pre- and post-deployment phases of a KeptnApp or KeptnWorkload.

A Keptn task executes as a runner in an application container, which runs as part of a Kubernetes job.

Each KeptnTaskDefinition can use exactly one container with one runner. which is one of the following, differentiated by the spec section:

Yaml Synopsis for all runners

The KeptnTaskDefinition Yaml files for all runners include the same lines at the top. These are described here.

apiVersion: lifecycle.keptn.sh/v?alpha?
kind: KeptnTaskDefinition
metadata:
  name: <task-name>
spec:
  deno | python | container
  ...
  retries: <integer>
  timeout: <duration-in-seconds>

The API ref points to Kubernetes doc where I don’t find a direct hit but timeouts seem to be measured in seconds.

Fields used for all containers

  • apiVersion – API version being used. `

  • kind – Resource type. Must be set to KeptnTaskDefinition

  • metadata

    • name – Unique name of this task or container. This is the name used to insert this task or container into the preDeployment or postDeployment list. Names must comply with the Kubernetes Object Names and IDs specification.
  • spec

    • deno | python | container – Define the container type to use for this task. Each task can use one type of runner, identified by this field:
    • retries (optional) - specifies the number of times, a job executing the KeptnTaskDefinition should be restarted if an attempt is unsuccessful.
    • timeout (optional)* – specifies the maximum time, in seconds, to wait for the task to be completed successfully. If the task does not complete successfully within this time frame, it is considered to be failed.

Yaml Synopsis for deno-runtime container

When using the deno-runtime runner to define a task, the task is coded in Deno-script (which is mostly the same as JavaScript and TypeScript) and executed in the Deno runner, which is a lightweight runtime environment that executes in your namespace. Note that Deno has tighter restrictions for permissions and importing data so a script that works properly elsewhere may not function out of the box when run in the deno-runtime runner.

apiVersion: lifecycle.keptn.sh/v?alpha?
kind: KeptnTaskDefinition
metadata:
  name: <task-name>
spec:
  deno:
    inline | httpRef | functionRef | ConfigMapRef
    parameters:
      map:
        textMessage: "This is my configuration"
    secureParameters:
      secret: slack-token

Spec fields for deno-runtime definitions

  • spec
    • deno – Specify that the task uses the deno-runtime and is expressed as a Deno script. Refer to function runtime for more information about this runner.

      The task can be defined as one of the following:

      • inline - Include the actual executable code to execute. This can be written as a full-fledged Deno script that is included in this file. For example:

        deno:
          inline:
            code: |
                    console.log("Deployment Task has been executed");
        
      • httpRef - Specify a Deno script to be executed at runtime from the remote webserver that is specified. For example:

        name: hello-keptn-http
          spec:
              deno:
                httpRef:
                  url: "https://www.example.com/yourscript.js"
        
      • functionRef – Execute one or more KeptnTaskDefinition resources that have been defined to use the deno-runtime runner. Populate this field with the value(s) of the name field for the KeptnTaskDefinition(s) to be called. This is commonly used to call a general function that is used in multiple places, possibly with different parameters. An example is:

        spec:
          deno:
            functionRef:
              name: slack-notification
        

        This can also be used to group a set of tasks into a single KeptnTaskDefinition, such as defining a KeptnTaskDefinition for testing. In this case, it calls other, existing KeptnTaskDefinitions for each type of test to be run, specifying each by the value of the name field.

      • ConfigMapRef - Specify the name of a ConfigMap resource that contains the function to be executed.

    • parameters - An optional field to supply input parameters to a function. The Lifecycle Toolkit passes the values defined inside the map field as a JSON object. For example:

        spec:
          parameters:
            map:
              textMessage: "This is my configuration"
      

      See Parameterized functions for more information.

    • secureParameters – An optional field used to pass a Kubernetes secret. The secret value is the Kubernetes secret name that is mounted into the runtime and made available to functions using the SECURE_DATA environment variable. For example:

      secureParameters:
        secret: slack-token
      

      Note that, currently, only one secret can be passed.

      See Create secret text for details.

Yaml Synopsis for container-runtime

apiVersion: lifecycle.keptn.sh/v?alpha?
kind: KeptnTaskDefinition
metadata:
  name: <task-name>
spec:
  container:
    name: <container-name>
    image: <image-name>
    <other fields>

Spec used only for container-runtime

The container-runtime can be used to specify your own container image and define almost task you want to do. If you are migrating from Keptn v1, you can use a container-runtime to execute almost anything that you implemented with JES for Keptn v1.

  • spec
    • container – Container definition.
      • name – Name of the container that will run, which is not the same as the metadata.name field that is used in the KeptnApp resource.
      • image – name of the image you defined according to image reference and image concepts and pushed to a registry
      • other fields – The full list of valid fields is available at ContainerSpec, with additional information in the Kubernetes Container spec documentation.

Yaml Synopsis for Python-runtime runner

The python-runtime runner provides a way to easily define a task using Python 3. You do not need to specify the image, volumes, and so forth. Instead, just provide a Python script and KLT sets up the container and runs the script as part of the task.

apiVersion: lifecycle.keptn.sh/v?alpha?
kind: KeptnTaskDefinition
metadata:
  name: <task-name>
spec:
    python:
      inline | httpRef | functionRef | ConfigMapRef
      parameters:
        map:
          textMessage: "This is my configuration"
      secureParameters:
        secret: slack-token

Spec used only for the python-runtime runner

The python-runtime runner is used to define tasks using Python 3 code.

  • spec
    • python – Identifies this as a Python runner.

      • inline – Include the actual Python 3.1 code to execute. For example, the following example prints data stored in the parameters map:

        python:
          inline:
            code: |
              data = os.getenv('DATA')
              print(data)      
        
      • httpRef - Specify a Deno script to be executed at runtime from the remote webserver that is specified. For example:

        name: hello-keptn-http
          spec:
              python:
                httpRef:
                  url: "https://www.example.com/yourscript.py"
        
      • functionRef – Execute one or more KeptnTaskDefinition resources that have been defined to use the python-runtime runner. Populate this field with the value(s) of the metadata.name field for each KeptnDefinitionTask to be called. This is commonly used to call a general function that is used in multiple places, possibly with different parameters. An example is:

         spec:
           python:
             functionRef:
               name: slack-notification
        

        This can also be used to group a set of tasks into a single KeptnTaskDefinition, such as defining a KeptnTaskDefinition for testing. In this case, it calls other, existing KeptnTaskDefinitions for each type of test to be run, specifying each by the value of the name field.

      • ConfigMapRef – Specify the name of a ConfigMap resource that contains the function to be executed.

    • parameters - An optional field to supply input parameters to a function. The Lifecycle Toolkit passes the values defined inside the map field as a JSON object. For example:

        spec:
          parameters:
            map:
              textMessage: "This is my configuration"
      

      See Parameterized functions for more information.

    • secureParameters – An optional field used to pass a Kubernetes secret. The secret value is the Kubernetes secret name that is mounted into the runtime and made available to functions using the SECURE_DATA environment variable. For example:

      secureParameters:
        secret: slack-token
      

      Note that, currently, only one secret can be passed.

      See Create secret text for details.

Usage

A Task executes the TaskDefinition of a KeptnApp or a KeptnWorkload. The execution is done by spawning a Kubernetes Job to handle a single Task. In its state, it tracks the current status of this Kubernetes Job.

When using a container runtime that includes a volume, an EmptyDir volume is created with the same name as is specified the container volumeMount. Note that, if more volumeMounts are specified, only one volume is created with the name of the first volumeMount. By default, the size of this volume is 1GB. If the memory limit for the container is set, the size of the volume is 50% of the memory allocated for the node.

A task can be executed either pre-deployment or post-deployment as specified in the pod template specs of your Workloads (Deployments, StatefulSets, DaemonSets, and ReplicaSets. See Pre- and post-deployment tasks for details. Note that the annotation identifies the task by name. This means that you can modify the function code in the resource definition and the revised code is picked up without additional changes.

Examples for deno-runtime runner

Example 1: inline script for a Deno script

This example defines a full-fledged Deno script within the KeptnTaskDefinition YAML file:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: hello-keptn-inline
spec:
  deno:
    inline:
      code: |
        let text = Deno.env.get("DATA");
        let data;
        let name;
        data = JSON.parse(text);

        name = data.name
        console.log("Hello, " + name + " new");        

Example 2: httpRef script for a Deno script

This example fetches the Deno script from a remote webserver at runtime:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: hello-keptn-http
spec:
  deno:
    httpRef:
      url: "https://www.example.com/yourscript.js"

For another example, see the sample-app.

See the sample-app/version-1 PodtatoHead example for a more complete example.

Example 3: functionRef for a Deno script

This example calls another defined task, illustrating how one KeptnTaskDefinition can build on top of other KeptnTaskDefinitions. In this case, it calls slack-notification-dev, passing parameters and secureParameters to that other task:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: slack-notification-dev
spec:
  deno:
    functionRef:
      name: slack-notification
    parameters:
      map:
        textMessage: "This is my configuration"
    secureParameters:
      secret: slack-token

Example 4: ConfigMapRef for a Deno script

This example references a ConfigMap by the name of dev-configmap that contains the code for the function to be executed.

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: keptntaskdefinition-sample
spec:
  deno:
    configMapRef:
      name: dev-configmap

Example 5: ConfigMap for a Deno script

This example illustrates the use of both a ConfigMapRef and a ConfigMap:

apiVersion: lifecycle.keptn.sh/v1alpha2
kind: KeptnTaskDefinition
metadata:
  name: scheduled-deployment
spec:
  function:
    configMapRef:
      name: scheduled-deployment-cm-1
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: scheduled-deployment-1
data:
  code: |
    let text = Deno.env.get("DATA");
    let data;
    if (text != "") {
        data = JSON.parse(text);
    }
    let targetDate = new Date(data.targetDate)
    let dateTime = new Date();
    if(targetDate < dateTime) {
        console.log("Date has passed - ok");
        Deno.exit(0);
    } else {
        console.log("It's too early - failing");
        Deno.exit(1);
    }
    console.log(targetDate);    

Examples for a custom-runtime container

For an example of a KeptnTaskDefinition that defines a custom container. see [container-task.yaml](https://github.com/keptn/lifecycle-toolkit/blob/main/examples/sample-app/base/container-task.yaml. The spec includes:

spec:
  container:
    name: testy-test
    image: busybox:1.36.0
    command:
      - 'sh'
      - '-c'
      - 'sleep 30'

This task is then referenced in

app.yaml.

This is a a trivial example that just runs busybox, then spawns a shell and runs the sleep 30 command.

Examples for a python-runtime runner

Example 1: inline code for a python-runtime runner

You can embed python code directly in the task definition. This example prints data stored in the parameters map:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: scheduled-deployment-inline
spec:
  python:
    parameters:
      map:
        mydata: "my-user-defined"
    inline:
      code: |
        # Get environment variables
        data = os.getenv('DATA')
        print(data)        

Example 2: httpRef for a python-runtime runner

You can refer to code stored online. For example, we have a few examples available in the python-runtime samples tree.

Consider the following:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: scheduled-deployment
spec:
  python:
    configMapRef:
      name: python-test-cm
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: python-test-cm
data:
  code: |
        print("Hello, World!")

Example 3: functionRef for a python-runtime runner

You can refer to an existing KeptnTaskDefinition. This example calls the inline example but overrides the data printed with what is specified in the task:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: scheduled-deployment-2
spec:
  python:
    parameters:
      map:
        mydata: "my-other-data"
    functionRef:
      name: scheduled-deployment-inline

Example 4: ConfigMapRef for a python-runtime runner

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: scheduled-deployment
spec:
  python:
    configMapRef:
      name: python-test-cm
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: python-test-cm
data:
  code: |
        print("Hello, World!")

Allowed libraries for the python-runtime runner

The following example shows how to use some of the allowed packages, namely: requests, json, git, and yaml:

apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: python-inline
spec:
  python:
    inlineRef:
      code: |
        import sys
        import json
        import yaml
        print("Hello, World!")
        dct = yaml.safe_load('''
        name: John
        age: 30
        automobiles:
          - brand: Honda
            type: Odyssey
            year: 2018
          - brand: Toyota
            type: Sienna
            year: 2015
        ''')
        assert dct['name'] == 'John'
        assert dct['age'] == 30
        assert len(dct["automobiles"]) == 2
        assert dct["automobiles"][0]["brand"] == "Honda"
        assert dct["automobiles"][1]["year"] == 2015
        # some JSON:
        x =  '{ "name":"John", "age":30, "city":"New York"}'
        # parse x:
        y = json.loads(x)
        # the result is a Python dictionary:
        print(y["age"])        

Passing secrets, environment variables and modifying the python command

The following examples show how to pass data inside the parameter map, how to load a secret in your code, and how to modify the python command. In this case the container runs with the -h option, which prints the help message for the python3 interpreter:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  SECURE_DATA: dG9rZW46IG15dG9rZW4=
---
apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
  name: pre-deployment-hello
  annotations:
    python: test
spec:
  python:
    parameters:
      map:
        user: "myuser"
    secureParameters:
      secret: mysecret
    cmdParameters: "-h"
    inline:
      code: |
        import os
        import yaml
        data = os.getenv('DATA')
        dct = yaml.safe_load(data)
        USER= dct['user']
        PASSWORD = os.environ.get('SECURE_DATA')
        print(USER,PASSWORD)        

More examples

See the operator/config/samples directory for more example KeptnTaskDefinition YAML files.

Files

API Reference:

Differences between versions

The KeptnTaskDefinition support for the container-runtime and python-runtime is introduced in v0.8.0. This modifies the synopsis in the following ways:

  • Add the spec.container field.
  • Add the python descriptor for the python-runtime runner.
  • Add the container descriptor for the container-runtime runner.
  • Add the deno descriptor to replace function for the deno-runtime runner. The function identifier for the deno-runtime runner is deprecated; it still works for v 0.8.0 but will be dropped from future releases.
  • The spec.function field is changed to be a pointer receiver. This aligns it with the spec.container field, which must be a pointer, and enables KeptnTask to omit it when it is empty, which it must be when spec.container is populated.

Limitations

Only one runtime is allowed per KeptnTaskDefinition.

See also