Delivery Extensions

Delivery extensions are custom workflows that can be added to the convergence of any service. Delivery extensions can be defined globally, where they may be reused by many services across many applications, or inlined in service configs.

Configuring Delivery Extensions

Configuring Inlined Delivery Extensions

Delivery extensions can be defined inline in service configs.

service:
  name: my-service
  application: my-application
  deliveryExtensions:
  - inlined:
      kubernetesConfig:
        type: KUBERNETES
        local:
          path: path-to-job-yaml
    lifecycle: POST_APPROVAL
  ... # the rest of service configuration here, such as kubernetes/program configs
apiVersion: batch/v1
kind: Job
metadata:
  generateName: my-prefix-
spec:
  ttlSecondsAfterFinished: 600
  template:
    spec:
      containers:
        - name: my-container
          image: my-image
          command: ["command", ...]
      restartPolicy: Never
  backoffLimit: 0

In the example above, in each release channel, before deploying a service but after any requested approval have been submitted, Prodvana will run a Kubernetes job using the image my-image, with the command command ..., in the same runtime and namespace of the release channel. For services using Runtime Extensions, the release channel must be configured with both a custom runtime and a Kubernetes runtime, and Prodvana will run the delivery extension inside the Kubernetes runtime.

Apply the config with pvnctl configs apply:

pvnctl configs apply my-service.pvn.yaml

For more information about configuring services, see Configuring Services.

(Coming Soon) Configuring Global Delivery Extensions

Valid Lifecycles

Delivery extensions run in a lifecycle of the service being deployed in a release channel. When they fail, they prevent the service in that release channel from proceeding to the next lifecycle and will continuously retry. The following lifecycles are supported for delivery extensions:

  • PRE_APPROVAL - run after releaseChannelStable preconditions are satisfied
  • POST_APPROVAL - run after approvals and PRE_APPROVAL extensions
    • If there are no approvals configured on the release channel, POST_APPROVAL extensions will run immediately after PRE_APPROVAL extensions are satisfied.
  • POST_DEPLOYMENT - run after deployment is done before marking the service as converged in the release channel.

Injected Environment Variables

The following variables are injected into delivery extension jobs and can be used in the logic of the extension.

VariableWhat
PVN_DESIRED_STATE_IDThe desired state ID of the convergence, useful to determine, for example, what the starting and desired states for the convergence is.
PVN_APISERVER_ADDRThe address to connect to Prodvana API.
PVN_TOKENTemporary token which can be used to interact with Prodvana API.

See our API documentation and examples for how to query Prodvana and achieve complex logic. The Python library will automatically connect to your instance of Prodvana with a temporary API token generated specifically for the delivery extension run.

Common Examples

Using Prodvana Backend-Agnostic Configurations

To avoid writing a Kubernetes config, you can use our configuration instead which takes docker image as an interface.

service:
  name: my-service
  application: my-application
  deliveryExtensions:
  - inlined:
      taskConfig:
        program:
          name: my-program-name
          imageTag: my-tag
          imageRegistryInfo:
            containerRegistry: my-registry-name
            imageRepository: my-repository
          cmd: ['run-command-pre-deployment']
    lifecycle: POST_APPROVAL
  ... # the rest of service configuration here, such as kubernetes/program configs

Using the Same Image As the Service Itself

A common workflow is to run a setup command from the same commit/source as the code being deployed, before updating the service. For example, this workflow can be used to run migrations.

To use the same image for a delivery extension that is being used for the service itself, use parameters. Parameter applications happen at the same time and just like any other part of the service configuration.

service:
  name: my-service
  application: my-application
  deliveryExtensions:
  - inlined:
      kubernetesConfig:
        type: KUBERNETES
        local:
          path: path-to-job-yaml
    lifecycle: POST_APPROVAL
  parameters:
    - name: image
      dockerImage:
        defaultTag: my-tag
        imageRegistryInfo:
          containerRegistry: my-registry-name
          imageRepository: my-repository
  ... # the rest of service configuration here, such as kubernetes/program configs
apiVersion: batch/v1
kind: Job
metadata:
  generateName: my-prefix-
spec:
  ttlSecondsAfterFinished: 600
  template:
    spec:
      containers:
        - name: my-container
          image: '{{.Params.image}}'
          command: ["command", ...]
      restartPolicy: Never
  backoffLimit: 0

service:
  name: my-service
  application: my-application
  deliveryExtensions:
  - inlined:
      taskConfig:
        program:
          name: my-program-name
          image: '{{.Params.image}}'
          cmd: ['run-command-pre-deployment']
    lifecycle: POST_APPROVAL
  parameters:
    - name: image
      dockerImage:
        defaultTag: my-tag
        imageRegistryInfo:
          containerRegistry: my-registry-name
          imageRepository: my-repository
  ... # the rest of service configuration here, such as kubernetes/program configs

Defining Delivery Extensions Per Release Channel

It is possible to define extensions per release channel. The final extensions list is the union of the service-level list and the per-release-channel list.

service:
  name: my-service
  application: my-application
  deliveryExtensions:
  - inlined:
      ... # config here
    lifecycle: POST_APPROVAL
  perReleaseChannel:
  - releaseChannel: staging
    deliveryExtensions:
    - inlined:
      ... # config here
      lifecycle: POST_APPROVAL
  ... # the rest of service configuration here, such as kubernetes/program configs

(Coming Soon) Sharing a Delivery Extension across Many Release Channels

(Coming Soon) Configuring Retry Policy

By default, delivery extensions will retry forever until they succeed. To customize this behavior, configure their retry policy.