datus-airflow-plugin
A Datus plugin that drives remote Apache Airflow 2.x or
3.x deployments from datus airflow ..., backed entirely by the stable REST
API (/api/v1 for Airflow 2, /api/v2 for Airflow 3)
— no Airflow installation needed on the client. Command groups mirror the
Airflow CLI, plus a dags deploy command that ships DAG files to S3 or a
local/mounted dags folder and verifies the scheduler picked them up.
pip install datus-airflow-plugin # requests + PyYAML + boto3 (S3 deploy included)
Requires datus-agent >= 0.3.8 — the system-prompt template uses the
config_mutablerender-context variable (older versions skip the whole prompt section).
Configuration
Profiles live under agent.plugins.airflow.<profile> in Datus' agent.yml
(./conf/agent.yml or ~/.datus/conf/agent.yml):
agent:
plugins:
airflow:
prod:
default: true
api_base_url: https://airflow.example.com/api/v1
api_version: auto # URL suffix selects v1; no suffix defaults to v2
username: admin
password: ${AIRFLOW_PASSWORD} # or a static JWT: token: ${AIRFLOW_API_TOKEN}
dags_folder: s3://my-bucket/dags/ # default `dags deploy` target
s3: # optional S3 overrides
region: us-east-1
# profile: my-aws-profile / endpoint_url: http://minio:9000
# access_key_id: ${AWS_ACCESS_KEY_ID} / secret_access_key: ${AWS_SECRET_ACCESS_KEY}
staging:
api_base_url: http://localhost:8080
username: admin
password: ${AIRFLOW_STAGING_PASSWORD}
dags_folder: /opt/airflow/dags
team_a: # scoped to one team's DAGs
api_base_url: https://airflow.example.com
token: ${AIRFLOW_TEAM_A_TOKEN}
dag_id_prefix: team_a_ # only team_a_* DAGs
allow_commands: dags,tasks,version,health # only these command groups
Select an environment with datus airflow --profile staging ...; the
default: true profile is used otherwise.
Scoping a profile
Two optional fields narrow what the agent can do in an environment:
| Field | Effect |
|---|---|
dag_id_prefix |
Every command taking a dag_id rejects ids outside the prefix before any request (exit 2); dags list / dags list-runs / assets events filter their output to it. Comma-separate several prefixes. |
allow_commands |
Comma-separated allowlist of top-level groups. Groups left out do not exist in the parser at all, and --help only shows what remains. Group level only — dags list is rejected as a config error, write dags. |
With dag_id_prefix set, assets materialize and backfill pause|unpause|cancel
are refused: they take no dag_id, so the prefix cannot be checked before the
action happens. Variables, connections and pools are instance-wide in Airflow
and are never prefix-filtered — exclude them via allow_commands if a profile
should not reach them.
These are agent guardrails, not a security boundary. Anyone who can edit
agent.ymlor call the Airflow REST API directly bypasses them. Real tenant isolation has to come from the server: DAG-level RBAC via FabAuthManager, or Airflow 3.2+[core] multi_team. The guardrails are complementary to the manifest'spermissionstree — that one classifies commands as auto-run vs. confirm for every profile, these two limit which commands and DAGs a single profile sees.
For Airflow 2 API v1, username/password use HTTP Basic Auth. Authentication
for Airflow 3 follows its JWT model: username/password are exchanged
for a JWT at POST /auth/token (SimpleAuthManager and FabAuthManager both
expose it; override the URL with auth_token_url if needed). Tokens are
cached under ~/.cache/datus-airflow-plugin/ (0600) and refreshed on expiry;
set cache_token: false to disable. Self-signed TLS: set verify_ssl to a CA
bundle path (or false).
Commands
Everything accepts -o table|json|yaml|plain where output is structured
(json/yaml emit the full API objects). Destructive commands prompt — pass
-y/--yes in scripts.
| Group | Subcommands |
|---|---|
dags |
list, details, list-runs, list-import-errors, show (ASCII task tree), source, pause, unpause, trigger [--wait], state, clear-run, delete, next-execution, deploy, undeploy |
tasks |
list, state, states-for-dag-run, clear, failed-deps, logs |
variables |
list, get, set, delete, import, export |
connections |
list, get, add, delete, test, import, export (json/yaml/env) |
pools |
list, get, set, delete, import, export |
assets |
list, details, materialize, events |
backfill |
create [--dry-run], list, pause, unpause, cancel |
| misc | version, health, providers list, plugins, config list, config get-value, jobs check |
datus airflow dags list -p 'sales_%'
datus airflow dags trigger sales_daily -c '{"backfill": false}' --wait
datus airflow tasks logs sales_daily manual__2026-07-05T00:00:00+00:00 load_orders
datus airflow variables set ENV prod
datus airflow connections add pg --conn-uri 'postgres://user:pass@db:5432/warehouse'
Deploying DAGs
# single file to the profile's dags_folder, then wait until the scheduler parsed it
datus airflow dags deploy ./dags/sales_daily.py --verify sales_daily
# a whole directory to S3, removing remote files that no longer exist locally
datus airflow dags deploy ./dags --dest s3://my-bucket/dags/ --prune -y
# see what would happen first
datus airflow dags deploy ./dags --dry-run
# delete individual files from the target (then drop metadata with `dags delete`)
datus airflow dags undeploy old_dag.py -y
- Directories are scanned recursively for
*.pyand*.zip(--all-filesto include everything);__pycache__, hidden files and*.pycare skipped. --verify <dag_id>polls the API until that DAG has been re-parsed after the upload, and fails fast with the stack trace if the file causes an import error. Detection is based onlast_parsed_timechanging, so it is immune to client/server clock skew.--prunecompares the target against the deployed set and deletes stale files — always try--dry-runfirst.- S3 credentials resolve through the standard boto3 chain (env, shared
config, instance profile / IRSA) unless overridden in the profile's
s3:block; MinIO and other S3-compatible stores work viaendpoint_url. - IAM roles: either point
s3.profileat an assume-role profile in~/.aws/config, or sets3.role_arn(plus optionalrole_session_name/external_id) and the plugin performs the STS AssumeRole itself, using the chain/profile/keys credentials only to bootstrap it.
Exit codes
0 success · 1 runtime/API error (also: run failed under --wait,
connection test failed, unhealthy health) · 2 usage error · 3 config
error · 8 missing dependency (boto3, if the environment stripped it).
Development
pip install -e '.[dev]'
pytest
The package never imports datus. The whole plugin contract is declared in
datus_airflow_plugin/datus-plugin.yml (CLI entry function, bundled skills,
system-prompt template, bash-permission rules, profile config schema); the
entry point airflow in the datus.plugins group maps the plugin name to the
package. Bundled skills: airflow (usage reference for the agent) and
airflow-setup (guided configuration).
Agent bash permissions
The manifest's permissions key declares how the Datus agent may run this
CLI through its bash tool (humans in a terminal are never affected):
- allow everywhere — read-only commands (
list/get/details/show/source/state/logs,connections getmasked by default,connections test,jobs check,version,health, ...). - ask under
normal, allow underauto— reversible routine operations:dags pause/unpause/clear-run,tasks clear,backfill pause/unpause/cancel,variables set,pools set,variables/pools export. - ask under both profiles — anything that starts runs (
dags trigger,assets materialize,backfill create), ships or removes code (dags deploy,dags undeploy), deletes (... delete), bulk-overwrites (... import), or handles connection secrets (connections add/export).
User rules in agent.yml always win (deny > ask > allow).
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file datus_airflow_plugin-0.3.0.tar.gz.
File metadata
- Download URL: datus_airflow_plugin-0.3.0.tar.gz
- Upload date:
- Size: 62.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6daaa4c2ab6b7cd43e75e73739cc462fcc89184a87df909b522a5097cff7eee9
|
|
| MD5 |
37e7054d14992d166d94a9a3f40368df
|
|
| BLAKE2b-256 |
d994e8e24c92709ff5f60793cf607ea67c994218ce0df696abc01a456627815b
|
File details
Details for the file datus_airflow_plugin-0.3.0-py3-none-any.whl.
File metadata
- Download URL: datus_airflow_plugin-0.3.0-py3-none-any.whl
- Upload date:
- Size: 57.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30fd20c717adb6973f5818761f9a8a3c7e9ac8b3527c7c1b9f5ff078eed2b783
|
|
| MD5 |
af754e538e1032b5386c27194060c396
|
|
| BLAKE2b-256 |
5737955730efdbe7cfa38f28464bf59d8dbf083f671d666e83feb9748f34d871
|