Skip to content

Run AIR CLI via DABs#5937

Open
vinchenzo-db wants to merge 6 commits into
mainfrom
air-dabs-main
Open

Run AIR CLI via DABs#5937
vinchenzo-db wants to merge 6 commits into
mainfrom
air-dabs-main

Conversation

@vinchenzo-db

Copy link
Copy Markdown

Changes

Why

Tests

…-> run) with env vars

Wires the experimental `air` CLI to submit and list workloads via Databricks
Asset Bundles (persistent Jobs resources) alongside the ephemeral runs/submit
path. Gated behind --via-dabs / AIR_VIA_DABS=1; the ephemeral path stays the
default and is untouched (additive).

- run: `air run --via-dabs` converts train.yaml -> databricks.yml (reusing the
  exportbundle.go converter), then deploys the bundle and runs it. env vars/secrets
  ride the common Jobs env-var API (API-293) as a job-level environment_variables
  profile the ai_runtime_task references by key; secrets emit as
  {{secrets/scope/key}} refs. Verified against staging that this shape persists on
  runs/get, so the converter's env-var/secret rejection is lifted.
- list: `air list --via-dabs` drops the SUBMIT_RUN server-side restriction so
  DABs-submitted AIR runs (RunType JOB_RUN) are included; isAirRun still selects by
  task shape. The AiTrainingService index path already returns the caller's runs
  regardless of submit verb, so only the jobs-scan fallback needed widening.
- cancel / get: work unchanged for DABs runs (both key on a run_id that a
  bundle run still produces); documented inline.

Prototype scope: deploy/run shell out to `databricks bundle` (production would call
cmd/bundle/utils.ProcessBundle in-process); run_id parsing and code_source staging
into the bundle folder are TODO(prototype). Persistent-job GC is accepted for now.

Co-authored-by: Isaac
Rewrites `air run` to submit exclusively via a Databricks Asset Bundle
(convert train.yaml -> databricks.yml -> deploy -> run), removing the
ephemeral runs/submit path and the experimental --via-dabs flag. This
honors the AIR-CLI/DABs agreement: DECO requires AIR to integrate with
DABs and submit through the public Jobs API, not an internal proxy.

Deploy and run are driven IN-PROCESS via the bundle libraries
(cmd/bundle/utils.ProcessBundle + Jobs.RunNow), the same entry points the
`databricks bundle` commands use and the pattern the pipelines CLI
established (cmd/pipelines). There is no child `databricks` process, so
the deploy always uses this build's ai_runtime_task-aware bundle schema.

- rundabs.go: submitWorkload converts the config to a bundle in a temp
  root, deploys it with ProcessBundle (rooted via DATABRICKS_BUNDLE_ROOT
  on the context, direct engine), then RunNow on the resolved job to
  return the run_id (fire-and-return, no wait). A synthetic carrier
  command supplies the flags ProcessBundle reads and forwards air's
  resolved auth profile.
- run.go: DABs is the only path; --via-dabs removed. --dry-run always
  renders the generated bundle for transparency.
- list.go: the jobs scan no longer restricts to SUBMIT_RUN, since AIR
  runs are now runs of a persistent DABs job (JOB_RUN); --via-dabs gate
  removed. isAirRun still selects by task shape.
- runsubmit.go: ephemeral submit path retired, leaving only the runtime-
  image defaults the converter shares.

Verified end-to-end on staging (e2-dogfood): run -> get -> list ->
cancel all work against a real in-process deploy+run. go build + go test
./experimental/air/... pass.

Co-authored-by: Isaac
@github-actions

Copy link
Copy Markdown
Contributor

Waiting for approval

Based on git history, these people are best suited to review:

  • @riddhibhagwat-db -- recent work in experimental/air/cmd/

Eligible reviewers: @apeforest, @ben-hansen-db, @bfontain, @lu-wang-dl, @maggiewang-db, @panchalhp-db, @pardis-beikzadeh-db

Suggestions based on git history. See OWNERS for ownership rules.

Wires code_source snapshots through the DABs content-addressed snapshot
path (experimental.immutable_folder) so `air run` uploads the user's code
tree the same zip-and-fingerprint way AIR does today — giving an
apples-to-apples benchmark against the mechanism the uploads-vs-DABs
scoping doc compares (DECO-27087), not the per-file bundle sync.

- exportbundle.go: emit experimental.immutable_folder=true; emit
  command_path as a bundle-root-relative path so translate_paths rewrites
  it to the deployed snapshot location (emitting ${workspace.file_path}
  directly is validated as a local file and fails). The convertibility
  gate now allows working-tree code_source snapshots but still rejects
  git-pinned (working-tree upload can't pin a commit) and remote_volume
  (immutable_folder is Workspace-Files-only) snapshots.
- rundabs.go: writeBundleProject copies the code_source working tree into
  the bundle root (honoring include_paths) so deploy uploads it in the
  immutable snapshot.
- Trim AI-narration comments across the air files (provenance dumps,
  verification history, migration storytelling) down to what/why.

Verified on staging: `air run` with a code_source snapshot deploys via
"Uploading immutable bundle snapshot..." and submits a run. (The AI
Runtime execution then fails on a backend PrincipalContext/entity-owner
error, independent of code delivery and of the CLI path.)

Co-authored-by: Isaac
Covers the parts of rundabs.go that don't need a live workspace:
- writeBundleProject: databricks.yml + command.sh land, immutable_folder
  is set, code_source tree is staged, a user command.sh doesn't shadow
  the generated one, and the convertibility gate fails before any temp
  dir is created.
- newBundleCarrierCommand: forwards air's profile, declares the flags
  ProcessBundle reads, and seeds bundle-root + direct engine on the
  context.
- bundleTargetsBlock and isRunnableJob.

deployBundle / runDeployedJob still need a live deploy+RunNow and stay
covered by staging validation.

Co-authored-by: Isaac
Match the Python CLI (#2237609): env vars and secrets ride the job-level
environment_variables profile the converter emits, not the legacy
env_vars.json / secret_env_vars.json workspace side-channel. Drop that
sidecar staging from buildArtifacts and delete the now-dead entry
encoders and filename constants.

The other launch artifacts buildArtifacts stages (command.sh,
training_config.yaml, requirements.yaml, hyperparameters.yaml) are
unchanged — those fixed the "requirements.yaml not found" harness error
and are unrelated to env vars.

Known gap (verified on staging): the vendored databricks-sdk-go
jobs.JobSettings/Task has no environment_variables field, so the DABs
bundle schema strips it client-side ("unknown field") before the wire.
Env vars therefore aren't delivered on the DABs path until the SDK
carries the common Jobs env-var API. The Jobs server already accepts the
field (gated by allowEnvironmentVariables); this is purely a
DABs/SDK-schema lag.

Co-authored-by: Isaac
Mirror the Python CLI's rollout dual-write (#2237609): env vars / secrets
ride BOTH the common Jobs env-var API (the converter's
environment_variables profile) and the env_vars.json / secret_env_vars.json
sidecars the scheduler falls back to. The prior commit removed the
sidecars; restore them.

The sidecar fallback matters on two fronts: (1) the allowEnvironmentVariables
SAFE flag is off in prod, so Jobs drops the profile field, and (2) on the
DABs path the bundle SDK schema strips the profile field client-side
regardless of the flag (vendored jobs.JobSettings has no
environment_variables). Until the flag ramps AND the SDK carries the field,
the sidecar is the only working env-var delivery on the DABs path.

Verified on staging: a code-free run with env_variables + secrets deploys
env_vars.json / secret_env_vars.json into the immutable snapshot with the
correct shapes, next to command.sh.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: e8780b8

Run: 29455962164

Env 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 227 1103 5:05
💚​ aws windows 4 4 229 1101 6:52
🔄​ aws-ucws linux 3 3 4 314 1019 5:53
💚​ aws-ucws windows 4 4 318 1017 7:34
💚​ azure linux 4 4 227 1102 4:50
💚​ azure windows 4 4 229 1100 6:45
💚​ azure-ucws linux 4 4 318 1016 6:15
💚​ azure-ucws windows 4 4 320 1014 8:15
🔄​ gcp linux 1 3 4 226 1104 6:26
💚​ gcp windows 4 4 228 1102 8:51
10 interesting tests: 4 flaky, 4 SKIP, 2 RECOVERED
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🔄​ TestAccept 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🔄​ TestAccept/bundle/deploy/mlops-stacks 🙈​s 🙈​s 🔄​f ✅​p 🙈​s 🙈​s ✅​p ✅​p 🙈​s 🙈​s
🔄​ TestAccept/bundle/deploy/mlops-stacks/DATABRICKS_BUNDLE_ENGINE=direct 🔄​f ✅​p ✅​p ✅​p
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 9 slowest tests (at least 2 minutes):
duration env testname
8:26 gcp windows TestAccept
6:51 azure-ucws windows TestAccept
6:25 aws windows TestAccept
6:24 aws-ucws windows TestAccept
6:17 azure windows TestAccept
3:03 aws linux TestAccept
2:59 gcp linux TestAccept
2:56 azure linux TestAccept
2:45 azure-ucws linux TestAccept

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants