New to Kestra?
Use blueprints to kickstart your first workflows.
Audit Bigtable rows for missing required column families on a schedule and alert Slack with the exact row keys affected.
Bigtable has no schema to enforce, a column family exists the moment any cell is written to it, and nothing stops a buggy write path, a half-finished migration, or a dropped field in an application update from silently producing rows that are missing a family every downstream reader assumes is there. The table itself will never tell you, a read for a missing family just comes back empty, no error. This blueprint turns a row sample into a Day 2 compliance gate: it reads a batch of real rows, checks each one against the column families it is supposed to have, and alerts Slack with the exact row keys and families missing, never a guess.
route_connection_mode (io.kestra.plugin.core.flow.If) picks the connection based on
use_emulator. probe_rows_emulator connects to a local Bigtable emulator via
emulatorHost with no credentials, probe_rows_live connects to real Bigtable with a
GCP service account. Both run io.kestra.plugin.gcp.bigtable.ReadRows with
rowKeyPrefix, limit: sample_size, and fetchType: FETCH, and both have
allowFailure: true so an unreachable instance or missing table does not stop the flow
before it can be classified as PROBE_FAILED below.audit_column_families (io.kestra.plugin.core.output.OutputValues) reads whichever
branch's rows list exists (guarded with is defined/is not defined, since exactly
one of the two probe tasks ran), computes the distinct cells[].family values present
on each row, and flags every row missing a required family per
column_family_check_mode.classify_compliance_status (io.kestra.plugin.core.debug.Return) returns
PROBE_FAILED when neither probe produced output, CRITICAL or WARNING depending on
whether the violation count meets violation_count_critical_threshold, or COMPLIANT
when there are none.route_by_compliance_status (io.kestra.plugin.core.flow.Switch) branches on that
status: COMPLIANT logs it, WARNING, CRITICAL, and PROBE_FAILED each alert Slack
with the exact row keys and missing families from the audit, never an invented count.log_audit_summary always runs last and logs the final classification.errors block posts to Slack if the flow itself fails outside the gate logic above.io.kestra.plugin.gcp.bigtable.ReadRows against both the local emulator and real
Bigtable, using the same task with different connection properties.Bigtable itself enforces nothing about which families a row contains, there is no constraint, no alert, no concept of "this row looks wrong". Kestra adds the recurring sample, the column family completeness check, and a Slack alert built from the rows' own data, all as one declarative YAML file you can version and review like code, runnable against a local emulator before it ever touches a real table.
For local testing, the official Bigtable emulator, no GCP account needed:
docker run -p 127.0.0.1:8086:8086 --rm -ti google/cloud-sdk gcloud beta emulators bigtable start --host-port=0.0.0.0:8086
Port 8086 does not collide with Kestra's own default UI port. The emulator supports table creation and read/write against any project and instance name, it does not support the full instance/cluster administrative API, which this blueprint does not use.
For real Bigtable, a GCP project with a Bigtable instance and table, and a service
account with bigtable.rows.readColumnFamilies-equivalent read permission
(roles/bigtable.reader is enough, this blueprint only reads).
A Slack incoming webhook for alerts.
This plugin calls the Bigtable Data API directly from the Kestra worker process, there
is no sub-container taskRunner. If Kestra itself runs in a container and
use_emulator is true, point emulator_host at host.docker.internal:8086 or connect
Kestra's container to the emulator's Docker network and use its container name instead.
GCP_PROJECT_ID, GCP_SERVICE_ACCOUNT: used by probe_rows_live only, not needed when
use_emulator is true.
SLACK_WEBHOOK_URL: Slack incoming webhook URL used by the alert tasks and the errors
block.
In Kestra OSS, set all three as base64-encoded environment variables:
SECRET_GCP_PROJECT_ID, SECRET_GCP_SERVICE_ACCOUNT, SECRET_SLACK_WEBHOOK_URL.
| Input | Type | Default | Allowed values |
|---|---|---|---|
instance_id |
STRING | demo-instance |
any Bigtable instance ID |
table_id |
STRING | sensor-readings |
any Bigtable table ID |
row_key_prefix |
STRING | `` (empty) | any row key prefix, empty scans the whole table |
required_column_families |
JSON | ["readings", "metadata"] |
JSON array of column family names |
column_family_check_mode |
SELECT | any_required_missing |
any_required_missing, all_required_missing |
sample_size |
INT | 100 |
any positive integer |
violation_count_critical_threshold |
INT | 10 |
any non-negative integer |
use_emulator |
BOOL | true |
true, false |
emulator_host |
STRING | localhost:8086 |
any host:port |
cbt CLI or
the Bigtable client of your choice, some with every required family, some without.SLACK_WEBHOOK secret.log_audit_summary for the result.use_emulator: false and add the GCP_PROJECT_ID and GCP_SERVICE_ACCOUNT secrets
to point this at a real table.hourly trigger.row_key_prefix to the namespace of a single tenant or device and run one
instance of this flow per tenant with different required_column_families, if
different tenants are expected to have different schemas.metadata:schema_version to exist.CRITICAL that writes the exact violating row keys to a
file in internal storage for a data engineer to inspect, instead of only Slack.sample_size is a sample, not a full table scan. A rare violation pattern can be missed
entirely if it falls outside the sampled rows, raise sample_size or scope
row_key_prefix tighter for a more complete audit.column_family_check_mode settings, that is
expected, not a false positive.emulatorHost uses plaintext transport with no credentials, only ever point it at a
local emulator, never at a real endpoint.