
Helm ReleaseTrigger
CertifiedTrigger a flow when a Helm release changes state
Helm ReleaseTrigger
Trigger a flow when a Helm release changes state
Polls the Helm release records on a cluster and starts a flow when a release reaches a new revision or a new status, whoever made the change: a Kestra task, a CI pipeline, or someone running helm by hand.
Reads Helm's release Secrets (owner=helm) through the Kubernetes API, so no Helm container runs on each poll. Only the latest revision of each release is considered, so a revision that failed long ago and has since been superseded does not fire again.
The first evaluation treats every release already on the cluster as new; set on: UPDATE to react only to changes made after the trigger starts.
Requires list and get permissions on secrets in the watched namespaces, or cluster-wide with allNamespaces. Kubernetes RBAC cannot narrow that permission to Helm's Secrets, so prefer a namespace-scoped Role. Without get, releases still fire but without chart details. Only releases stored with Helm's default secret storage driver are seen.
type: io.kestra.plugin.helm.ReleaseTriggerExamples
Alert on any release that fails in a namespace
id: helm_failed_release_alert
namespace: company.team
tasks:
- id: each_release
type: io.kestra.plugin.core.flow.ForEach
values: "{{ trigger.releases }}"
tasks:
- id: slack
type: io.kestra.plugin.slack.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK') }}"
payload: |
{
"text": "Helm release {{ fromJson(taskrun.value).releaseName }} failed at revision {{ fromJson(taskrun.value).revision }}: {{ fromJson(taskrun.value).description }}"
}
triggers:
- id: failed_release
type: io.kestra.plugin.helm.ReleaseTrigger
namespace: web
statuses:
- FAILED
cluster: prod-eu
kubeconfig: "{{ secret('PROD_EU_KUBECONFIG') }}"
Roll back a release stuck in pending-upgrade for 15 minutes
id: helm_unstick_release
namespace: company.team
tasks:
- id: rollback
type: io.kestra.plugin.helm.Rollback
releaseName: "{{ trigger.releases[0].releaseName }}"
namespace: "{{ trigger.releases[0].namespace }}"
kubeconfig: "{{ secret('PROD_EU_KUBECONFIG') }}"
triggers:
- id: stuck
type: io.kestra.plugin.helm.ReleaseTrigger
namespace: web
releaseName: nginx
statuses:
- PENDING_UPGRADE
stuckFor: PT15M
kubeconfig: "{{ secret('PROD_EU_KUBECONFIG') }}"
Smoke-test every new revision that reaches deployed
id: helm_post_deploy_smoke_test
namespace: company.team
tasks:
- id: each_release
type: io.kestra.plugin.core.flow.ForEach
values: "{{ trigger.releases }}"
tasks:
- id: healthz
type: io.kestra.plugin.core.http.Request
uri: "https://{{ fromJson(taskrun.value).releaseName }}.example.com/healthz"
triggers:
- id: deployed
type: io.kestra.plugin.helm.ReleaseTrigger
allNamespaces: true
releaseNamePattern: "^api-.*"
statuses:
- DEPLOYED
on: UPDATE
connection:
masterUrl: https://prod-eu.k8s.example.com
caCertData: "{{ secret('PROD_EU_CA') }}"
oauthToken: "{{ secret('PROD_EU_TOKEN') }}"
Properties
allNamespaces booleanstring
falseWatch every namespace
Watches releases in all namespaces. Needs a ClusterRole that can list and get Secrets cluster-wide.
allowConcurrent boolean
falseSpecifies whether a trigger is allowed to start a new execution even if a previous run is still in progress.
cluster string
Cluster name
Reported as cluster on each release in the trigger output, resolved the same way as on the tasks so the two can be joined. Defaults to the host of the Kubernetes API server when connection is used, and is null otherwise. Set it explicitly to match the name your team uses, e.g. prod-eu.
connection
Kubernetes connection
Cluster credentials, using the same model as the Kubernetes plugin. Mutually exclusive with kubeconfig. If neither is set, the trigger uses the kubeconfig or service account available to the Kestra worker.
inheritClusterConfig booleanstring
falseInherit ambient cluster configuration
When true, connection is layered on top of the ambient auto-configuration (system properties, environment, kubeconfig, in-cluster service account) instead of starting from blank.
interval string
PT1MdurationPolling interval
ISO-8601 duration between two reads of the cluster.
kubeContext string
Kubeconfig context
Context to select from kubeconfig, or from the worker's ambient kubeconfig when neither kubeconfig nor connection is set.
kubeconfig string
Raw kubeconfig content
A complete kubeconfig. Mutually exclusive with connection. Supply through {{ secret('...') }} rather than inline.
Unlike the tasks, which hand the kubeconfig to helm inside a container, the trigger loads it on the Kestra worker, so it must carry its credentials inline: exec, auth-provider, tokenFile, client-certificate, client-key, and certificate-authority are rejected. Use the *-data fields and a token, or connection with an oauthTokenProvider for short-lived cloud credentials such as EKS or GKE.
namespace string
defaultKubernetes namespace
Namespace whose releases are watched. Ignored when allNamespaces is true.
on string
CREATE_OR_UPDATECREATEUPDATECREATE_OR_UPDATETrigger event type
CREATE: fires for releases the trigger has not seen before.UPDATE: fires when a release it has already seen moves to a new revision or status.CREATE_OR_UPDATE: fires on either.
releaseName string
Release name
Watches only the release with this exact name, which must be a valid Helm release name. Mutually exclusive with releaseNamePattern.
releaseNamePattern string
Release name pattern
Watches only releases whose name matches this regular expression in full. Mutually exclusive with releaseName. At most 256 characters, and a repeated group must not itself contain a quantifier or an alternation, such as (a+)+ or (a|aa)+. This is a best-effort guard against patterns that backtrack catastrophically on every poll, not a guarantee, so keep patterns simple.
stateKey string
State key
KV key under which the last seen revision and status of each release is stored. Defaults to <namespace>_<flowId>_<triggerId>.
stateTtl string
State TTL
How long a release is remembered without being listed by a poll, e.g. P30D. Releases that are no longer on the cluster are forgotten on the next poll regardless, so this only matters when the trigger stops polling for longer than the TTL: every release then fires again as new.
statuses array
UNKNOWNDEPLOYEDUNINSTALLEDSUPERSEDEDFAILEDUNINSTALLINGPENDING_INSTALLPENDING_UPGRADEPENDING_ROLLBACKStatuses to fire on
Fires only when the latest revision of a release is in one of these statuses. Every status fires when unset.
stopAfter array
CREATEDSUBMITTEDRUNNINGPAUSEDRESTARTEDKILLINGSUCCESSWARNINGFAILEDKILLEDCANCELLEDQUEUEDRETRYINGRETRIEDSKIPPEDBREAKPOINTRESUBMITTEDList of execution states after which a trigger should be stopped (a.k.a. disabled).
stuckFor string
Minimum time in a pending status
When set, a release in PENDING_INSTALL, PENDING_UPGRADE, or PENDING_ROLLBACK fires only once it has been pending for longer than this, which tells a stuck operation apart from one still running. Other statuses are unaffected.
when string
trueA condition that determines whether the trigger should run.
A Pebble expression evaluated at trigger time. The trigger fires only when the expression evaluates to a truthy value (true, a non-empty string, a non-zero number). Use this to gate trigger execution on dynamic runtime values such as execution labels, flow variables, or environment conditions.
Outputs
count integer
Number of releases that changed state
releases array
Releases that changed state
io.kestra.plugin.helm.ReleaseTrigger-ReleaseChange
Application version
Chart name
Chart version
Cluster name
The cluster property, or the host of the Kubernetes API server when connection is used. Null otherwise.
Revision description
Helm's summary of the last operation, e.g. Upgrade complete, or the error that failed it.
date-timeFirst deployment time
date-timeLast deployment time
Namespace holding the release
Previous status
Status the trigger last recorded for this release. Null the first time the release is seen.
Release name
Revision of the release now current
Release status
Helm status of the current revision, such as deployed, failed, or pending-upgrade.