Skip to content

air: add convert-to-dabs (run YAML -> Databricks Asset Bundle) - #6111

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

air: add convert-to-dabs (run YAML -> Databricks Asset Bundle)#6111
vinchenzo-db wants to merge 9 commits into
mainfrom
air-convert-to-dabs-main

Conversation

@vinchenzo-db

Copy link
Copy Markdown
Contributor

Adds air convert-to-dabs, which translates an AIR CLI run YAML into a deployable Databricks Asset Bundle so a workload authored for air run can be managed and deployed with the standard DABs workflow (validate/deploy/run).

The emitted bundle is schema-valid: the ai_runtime_task maps to the SDK jobs.AiRuntimeTask (experiment + deployments[].{command_path,compute} + code_source_path), with framework fields (retries, timeout, budget policy) on the surrounding task and the runtime environment in environments[].

Snapshotting is owned by the deploy-time aicode mutator, not by convert: code_source_path points at a local directory staged inside the bundle, and bundle deploy (aicode.PackageAndUpload) packages it into a content-addressed tarball and uploads it. convert only lays down the source bytes — copying the working tree (honoring .gitignore) or materializing a pinned git commit into the directory. requirements.yaml is likewise not emitted: aicode.SynthesizeRequirements regenerates it from the environments[] spec, so convert folds the whole dependency set (inline or requirements-file) into that spec instead.

env_variables / secrets / parameters have no native ai_runtime_task field, so they ride as env_vars.json / secret_env_vars.json / hyperparameters.yaml sidecars (same as air run), and a "Notes:" section tells a migrating user what was transformed or staged out-of-band.

This is the top of a 2-PR stack: it builds on the aicode deploy-time packaging mutator so the two compose end-to-end.

Co-authored-by: Isaac

Changes

Why

Tests

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 2cf4f20

Run: 30963132099

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 306 1091 4:39
💚​ aws windows 4 4 308 1089 8:51
💚​ azure linux 4 4 305 1091 4:37
💚​ azure windows 4 4 307 1089 7:39
💚​ gcp linux 1 5 306 1091 4:51
💚​ gcp windows 1 5 308 1089 6:45
8 interesting tests: 4 RECOVERED, 4 SKIP
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R
Top 6 slowest tests (at least 2 minutes):
duration env testname
8:15 aws windows TestAccept
7:05 azure windows TestAccept
6:10 gcp windows TestAccept
2:56 azure linux TestAccept
2:53 gcp linux TestAccept
2:52 aws linux TestAccept

@vinchenzo-db
vinchenzo-db force-pushed the air-convert-to-dabs-main branch 10 times, most recently from e74034f to 29248d4 Compare August 3, 2026 22:03
Base automatically changed from air-code-source-dir-rebase to main August 4, 2026 22:12
Adds `air convert-to-dabs`, which translates an AIR CLI run YAML into a
deployable Databricks Asset Bundle so a workload authored for `air run` can be
managed and deployed with the standard DABs workflow (validate/deploy/run).

The emitted bundle is schema-valid: the ai_runtime_task maps to the SDK
jobs.AiRuntimeTask (experiment + deployments[].{command_path,compute} +
code_source_path), with framework fields (retries, timeout, budget policy) on
the surrounding task and the runtime environment in environments[].

Snapshotting is owned by the deploy-time aicode mutator, not by convert:
code_source_path points at a local *directory* staged inside the bundle, and
`bundle deploy` (aicode.PackageAndUpload) packages it into a content-addressed
tarball and uploads it. convert only lays down the source bytes — copying the
working tree (honoring .gitignore) or materializing a pinned git commit into the
directory. requirements.yaml is likewise not emitted: aicode.SynthesizeRequirements
regenerates it from the environments[] spec, so convert folds the whole dependency
set (inline or requirements-file) into that spec instead.

env_variables / secrets / parameters have no native ai_runtime_task field, so they
ride as env_vars.json / secret_env_vars.json / hyperparameters.yaml sidecars (same
as `air run`), and a "Notes:" section tells a migrating user what was transformed
or staged out-of-band.

This is the top of a 2-PR stack: it builds on the aicode deploy-time packaging
mutator so the two compose end-to-end.

Co-authored-by: Isaac
The Windows CI job failed the convert-to-dabs acceptance test with
"tar (child): Cannot connect to C: resolve failed": the system tar reads the
`C:` in an absolute archive path as a remote host:path.

Two fixes:
- createPlainTarball now passes the archive as a bare basename with cmd.Dir set
  to the output directory (and an absolute parent), so no `C:\...` path reaches
  tar's -f argument. Mirrors how git archive is invoked; safe on GNU tar and
  bsdtar. (This helper is shared with the `air run` snapshot path.)
- extractTarball is rewritten in pure Go (archive/tar + compress/gzip) instead of
  shelling out to `tar -xzf`, eliminating the same drive-letter hazard on the
  extract side and dropping the external-tar dependency for extraction. It rejects
  entries that would escape the destination (path traversal, absolute/escaping
  symlinks) and bounds each file copy to its header size.

Adds unit tests for extractTarball (happy path incl. nested dirs + in-tree
symlink; traversal + escaping-symlink rejection).

Co-authored-by: Isaac
convert-to-dabs is now a purely local, syntactic translation. It no longer copies,
snapshots, or git-archives the code source — the deploy-time aicode mutator (from
the base PR) packages the source in place at `bundle deploy`.

- code_source_path is emitted as the source directory relative to the bundle
  (bundle root defaults to the input YAML's directory, which contains it), rather
  than a copied ./code_source dir.
- Removed the materialize/extract-tarball machinery and the git-pinned-commit
  path. code_source.snapshot.git is now rejected (deploy packages the working
  tree); a code_source outside the bundle directory is rejected with guidance.
- writeBundle now only writes databricks.yml + command.sh + the env/secret/param
  sidecars. Dependencies stay folded into the environments[] spec.

Tests updated: assert code_source_path points at ./src with no copy, reject
git-pin and out-of-bundle sources; the acceptance test converts in place.

Co-authored-by: Isaac
git and remote_volume stay unsupported, but the errors now explain why and what
to do: for git, check out the revision before converting (deploy packages the
working tree as-is); for remote_volume, set workspace.artifact_path (the bundle
artifact location is bundle-wide, not per-code-source).

Co-authored-by: Isaac
Re-running a conversion previously failed with no way to overwrite, and the
suggested remedy (--output-dir) is a dead end in place: code_source must live
inside the bundle dir. Add --force, and point the error at it.

The next-steps message said "databricks bundle ...". A CLI without
ai_runtime_task support only warns on the unknown field and then deploys a job
with no AI task, so print the invoked binary instead and call out the risk.

Co-authored-by: Isaac
The bundle is written next to the input YAML, so `cd .` was a no-op step; it is
now printed only when the bundle lands elsewhere. Drop the notes block and the
stale-CLI warning, and point at `bundle summary` for what was deployed.

Co-authored-by: Isaac
@vinchenzo-db
vinchenzo-db force-pushed the air-convert-to-dabs-main branch from 7a2b086 to c7698c9 Compare August 4, 2026 22:44
Comment thread experimental/air/cmd/convert_to_dabs.go
Comment thread experimental/air/cmd/convert_to_dabs.go Outdated
include_paths narrows the archive to a subset of root_path, which a bundle can't
express per code source — deploy packages the whole directory. Converting was
silently dropping it and uploading files the user meant to exclude, so reject it
and point at sync.exclude / .gitignore.

Emit a job resource key that YAML would type as a non-string scalar ("12345" ->
!!int) as a quoted key instead of prefixing it with "job_". yamlsaver already had
this logic for scalar *values* (isScalarValueInString); apply it to map keys too,
so the resource key keeps the experiment name.

Co-authored-by: Isaac

@ben-hansen-db ben-hansen-db left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates!

@vinchenzo-db
vinchenzo-db enabled auto-merge August 5, 2026 16:54
vinchenzo-db and others added 2 commits August 5, 2026 12:20
Keep the change inside experimental/air/ instead of teaching the shared
yamlsaver to quote map keys. quoteJobKey rewrites the emitted job resource key
when the experiment name would otherwise load as a non-string scalar ("12345" ->
!!int), which the bundle loader rejects.

NewSaverWithStyle can't do this: its style map applies to a key's whole subtree,
so quoting the job key also quotes every nested key and turns
accelerator_count: 1 into a string.

Co-authored-by: Isaac
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.

3 participants