Webhook icon
Schedule icon
WorkingDirectory icon
Commands icon
Docker icon
Script icon
Loop icon
If icon
SlackIncomingWebhook icon
Fail icon
Log icon

Audit Databricks Clusters Left Running Outside Work Hours

Audit Databricks clusters for disabled auto termination and idle time past policy, alert Slack per offender, and estimate wasted compute hours.

Categories
Cloud

How it works

  1. on_cluster_inventory (io.kestra.plugin.core.trigger.Webhook, keyed with the DATABRICKS_AUDIT_WEBHOOK_KEY secret) receives the cluster inventory from a governance or usage export job after each collection window. nightly_idle_audit (io.kestra.plugin.core.trigger.Schedule, cron 0 22 * * *) is the safety net and ships disabled: true until an operator turns it on.
  2. inventory_workspace (io.kestra.plugin.core.flow.WorkingDirectory) opens one shared directory so the staged inventory and the auditor read the same file.
  3. stage_cluster_inventory (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image alpine:3.20) writes cluster_inventory.json with a heredoc holding five clusters. Two run with auto termination disabled, one sits idle 200 minutes past the 120 minute policy, one is a healthy interactive cluster, and one is terminated and must not count.
  4. audit_clusters (io.kestra.plugin.scripts.python.Script on python:3.12-slim) prefers the posted webhook body and falls back to the staged inventory, keeps only clusters in the RUNNING state, and flags a cluster when auto_termination_minutes is missing or zero or when idle_minutes exceeds idle_policy_minutes. Each offender carries its reason code and an estimated wasted compute hour figure, and the verdict, the counts and the estimate are printed as a single ::{"outputs": ...}:: line.
  5. remediate_offenders (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) walks the flagged rows one at a time. route_offender (io.kestra.plugin.core.flow.If) branches on the reason code, so a disabled timeout reaches alert_disabled_termination while an idle overrun reaches alert_idle_overrun, both io.kestra.plugin.slack.notifications.SlackIncomingWebhook tasks with the exact counters.
  6. audit_verdict (io.kestra.plugin.core.flow.If) branches on audit_ok and offender_count > 0. Violations reach alert_audit_summary with the offender share and the wasted hours, then enforce_audit (io.kestra.plugin.core.flow.If) applies the fail_on_violations policy with fail_audit (io.kestra.plugin.core.execution.Fail) or the report only log_audit_softened. A clean workspace lands on log_audit_clean.
  7. The flow level errors handler (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) reports any failure with the execution id, because an audit that dies silently looks exactly like a compliant workspace.

What you get

  • Per cluster violations split into two reason codes, disabled auto termination and idle time past policy, each with its own remediation alert.
  • A wasted compute hour estimate summed across offenders, the number finops can put next to a bill.
  • Terminated and compliant clusters scored but never alerted, so the signal stays about actual waste.
  • idle_clusters, offender_count, wasted_hours, cluster_count and audit_ok as typed outputs for dashboards and chargeback reports.
  • A disabled nightly sweep as a second net once the webhook path is trusted.

Who it's for

  • Finops and platform engineers accountable for Databricks compute spend who suspect interactive clusters idle overnight.
  • Data engineers running shared workspaces who want offenders named with evidence instead of inferred from an invoice.
  • Governance owners who need a dated record that auto termination policy was checked every night.

Why orchestrate this with Kestra

Databricks reports auto termination settings per cluster in a UI nobody audits at scale, and a missing timeout looks harmless until the monthly bill lands. Kestra gives the inventory a webhook to land on, a shared workspace for the fixture and the auditor, a Loop that remediates each offender with its own context, a branch that separates escalation from the all clear, and outputs a chargeback report can consume. The policy threshold, the fail versus report choice and the execution history that proves the audit ran all live in one version controlled file.

Prerequisites

  • A worker with Docker access, the fixture runs in alpine:3.20 and the auditor in python:3.12-slim.
  • A governance job that can POST the cluster inventory as JSON from the Databricks APIs, or rely on the bundled fixture for trial runs.
  • A Slack incoming webhook for the per offender alerts, the summary alert and failure alerts.

Secrets

  • DATABRICKS_AUDIT_WEBHOOK_KEY: key segment guarding the audit webhook URL, anyone holding it can trigger an audit run.
  • SLACK_WEBHOOK_URL: Slack incoming webhook for the offender alerts, the summary alert and failure alerts.

Quick start

  1. Add the two secrets to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm offender_count reads 3, wasted_hours reads 7.33, cluster_count reads 5, idle_clusters lists etl-dbx-prod, ml-feature-dev and bi-cache-refresh, and the three per offender alerts plus the summary arrived.
  3. Raise idle_policy_minutes to 300 and re-run to watch bi-cache-refresh clear as the only remaining violations become the clusters with termination disabled.
  4. Re-run with fail_on_violations set to false and watch log_audit_softened keep the execution green while the alerts still fire.
  5. Point your governance job at /api/v1/{tenant}/executions/webhook/{namespace}/databricks-job-cluster-auto-termination-audit/{DATABRICKS_AUDIT_WEBHOOK_KEY} and enable nightly_idle_audit once the path is trusted.

How to extend

  • Add node type pricing to audit_clusters so wasted_hours becomes a dollar figure per offender for chargeback.
  • Terminate offenders directly with an io.kestra.plugin.core.http.Request against the Databricks API behind an approval gate, keeping alerts as the fallback path.
  • Persist every nightly audit with io.kestra.plugin.jdbc.postgresql.Queries to chart waste trends across the quarter.
  • Fan out per workspace with io.kestra.plugin.core.flow.ForEachItem over a subflow that audits one workspace each.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.