Kanister Execution Hooks

Kanister Blueprints can be used to execute arbitrary functionality before or after K10 Actions.

To use a Blueprint to define an execution hook, create the Blueprint in the K10 namespace and add a reference to one of the Blueprint's actions in a Policy or Action.

  1. For snapshot/export actions, these execution hooks operate on namespaces and can be set independently. The namespace is the source namespace where the application being snapshotted/exported is deployed. A hook blueprint can use this namespace via template parameters like {{ .Namespace.Name }}

  2. For restore actions, the execution hooks can operate on other Kubernetes resources as well. The resource on which the hook would operate can be selected on the dashboard as shown in the image below. For example, if a StatefulSet is selected as the target resource, a hook blueprint can access it via template parameters like {{ .StatefulSet.Name }}. Only the resources created in the target namespace can be selected as a subject. If no target resource is selected, namespace would be the target resource.

    ../_images/target_resource.png

Policies that apply to multiple namespaces will invoke hooks on each namespace.

Execution hooks do not require location profiles and hook Blueprint actions cannot use template parameters and helpers such as {{ .Profile.Location.Bucket }} or kando location.

For example, the following Blueprint defines a hook which updates a label on the namespace that was snapshotted.

apiVersion: cr.kanister.io/v1alpha1
kind: Blueprint
metadata:
  name: hook-blueprint
  namespace: kasten-io
actions:
  post-export:
    kind: Namespace
    phases:
    - func: KubeTask
      name: hookPhase
      args:
        podOverride:
          serviceAccountName: "k10-k10"
        image: bitnami/kubectl
        command:
        - /bin/sh
        - -c
        - |
          kubectl patch namespace "{{ .Namespace.Name }}" --type json -p='[{"op": "remove", "path": "/metadata/labels/migrate"}]'

The following Blueprint defines a hook which checks if a particular pod is ready after restore.

apiVersion: cr.kanister.io/v1alpha1
kind: Blueprint
metadata:
  name: hook-blueprint
  namespace: kasten-io
actions:
  post-restore:
    phases:
    - func: Wait
      name: WaitForPod
      args:
        timeout: 120s
        conditions:
         anyOf:
         - condition: '{{ if { $.status.containerStatuses[].ready } }}true{{ else }}false{{ end }}'
           objectReference:
            apiVersion: v1
            resource: pods
            name: '{{ .StatefulSet.Name }}'
            namespace: '{{ .StatefulSet.Namespace }}'

A hook reference may include preHook, onSuccess, or onFailure:

  • A preHook action is executed before the K10 Action (after any K10 setup steps have succeeded).

  • An onSuccess action is executed after the K10 Action has succeeded.

  • An onFailure action is executed when there is a failure in an earlier step and K10 has reached its retry limit.

Once successful, hook actions are not retried. If a preHook or onSuccess action fails, it may be retried by K10. If an onFailure action fails, K10 will not retry. Execution hooks may or may not be invoked when a K10 Action is cancelled asynchronously.

Kanister artifacts returned as outputArtifacts by the hook Blueprint action for preHook are passed as inputArtifacts to any hook Blueprint action for onSuccess or onFailure.

For example, the following hook reference specifies an execution hook for before a Restore Action and the error and non-error cases:

...
hooks:
  preHook:
    blueprint: hook-blueprint
    actionName: pre-restore
  onSuccess:
    blueprint: hook-blueprint
    actionName: post-restore
    subject:
       name: mysql-statefulset
       namespace: mysql
       type: statefulset
  onFailure:
    blueprint: hook-blueprint
    actionName: post-restore-failed
...

Look here to see how to embed hook references in API objects.

Note, using VBR as a profile for blueprint based backups is currently unsupported.

Configuring Security Context for Kanister Execution Hooks

By default, Pods provisioned as part of a Kanister Execution Hook action run with root privileges. If certain conditions are met, it is possible to change this behavior (e.g., to configure Kanister Hooks in a rootless manner).

Note

The Kanister Pod Override ConfigMap holds the highest priority. If the pod's security context is defined in this ConfigMap, it will override any other configuration.

Setting the forceRootInKanisterHooks flag to false provides more flexibility for configuring the security context for the Kanister Execution Hooks but should be done cautiously.

Once the flag is set to false, K10 will use the security context specified in the Kanister Blueprint's phase. If no security context is set for the phase, K10 will default to using an empty security context.

Note

The security context can be set in the args.podOverride section of any phase in the Kanister Blueprint for all functions that deploy temporary Pods. See the Kanister documentation for a complete list of functions that support args.podOverride.

For example, the following section should be added to the phase's args section to make it run as the user 1000:

...
podOverride:
  serviceAccountName: "k10-k10"
  # Add the securityContext section here to use it in Kanister Hook.
  securityContext:
    runAsUser: 1000
    runAsNonRoot: true
...