Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 0 additions & 72 deletions acceptance/bin/list_code_snapshot.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

>>> [CLI] bundle deploy
Error: code_source_path "./src" has no files to package (all excluded by .gitignore or sync.exclude, or the directory is empty)
Building air_code_source_src...
Error: artifact tgz: no files to pack under "[TEST_TMP_DIR]" (empty, gitignored, or no `include` match)

Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
bundle:
name: ai-runtime-test

sync:
# *.log excluded; data/*.bin force-included despite .gitignore.
exclude:
- "**/*.log"
include:
- src/data/*.bin

resources:
jobs:
train:
name: "[${bundle.target}] AI Runtime training"
tasks:
# Two AI Runtime tasks with distinct local code dirs: each is packaged into
# its own content-addressed tarball, both under the repo root's .air_snapshots.
# Two AI Runtime tasks with distinct local code dirs: each is turned into its
# own tgz artifact and uploaded through the standard artifact path.
- task_key: train
environment_key: default
ai_runtime_task:
Expand Down
130 changes: 15 additions & 115 deletions acceptance/bundle/ai_runtime_task/local_code_source/output.txt
Original file line number Diff line number Diff line change
@@ -1,129 +1,29 @@

=== deploy packages and uploads the local code sources
=== deploy packages the local code sources as tgz artifacts and uploads them

>>> [CLI] bundle deploy
Building air_code_source_src...
Building air_code_source_src2...
Uploading .databricks/air_code_source/air_code_source_src.tar.gz...
Uploading .databricks/air_code_source/air_code_source_src2.tar.gz...
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files...
Created jobs.train
Files: 13 uploaded, 0 deleted
Files: 9 uploaded, 0 deleted
Resources: 1 created, 0 changed, 0 deleted, 0 unchanged

=== each task's tarball holds only synced files (both under the repo root .air_snapshots)
=== both code_source_paths rewritten to the uploaded artifact remote paths

>>> list_code_snapshot.py
# .air_snapshots/[SNAPSHOT].tar.gz
src2/command.sh
src2/train.py
# .air_snapshots/[SNAPSHOT].tar.gz
src/.gitignore
src/command.sh
src/data/model.bin
src/train.py
>>> jq -s .[] | select(.path=="/api/2.2/jobs/create") | .body.tasks[].ai_runtime_task.code_source_path out.requests.txt
"/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/artifacts/.internal/air_code_source_src.tar.gz"
"/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/artifacts/.internal/air_code_source_src2.tar.gz"

=== both code_source_paths point into the bundle .air_snapshots, command_paths rewritten, deps on environments spec
=== both code tarballs uploaded

>>> print_requests.py --nostamp --sort --del-field raw_body //.air_snapshots/ //jobs/create
{
"method": "POST",
"path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/.air_snapshots/[SNAPSHOT].tar.gz",
"q": {
"overwrite": "true"
}
}
{
"method": "POST",
"path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/.air_snapshots/[SNAPSHOT].tar.gz",
"q": {
"overwrite": "true"
}
}
{
"method": "POST",
"path": "/api/2.2/jobs/create",
"body": {
"deployment": {
"kind": "BUNDLE",
"metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/state/metadata.json"
},
"edit_mode": "UI_LOCKED",
"environments": [
{
"environment_key": "default",
"spec": {
"dependencies": [
"torch>=2.0.0"
],
"environment_version": "5"
}
}
],
"format": "MULTI_TASK",
"max_concurrent_runs": 1,
"name": "[default] AI Runtime training",
"queue": {
"enabled": true
},
"tasks": [
{
"ai_runtime_task": {
"code_source_path": "/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/.air_snapshots/[SNAPSHOT].tar.gz",
"deployments": [
{
"command_path": "/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/src/command.sh",
"compute": {
"accelerator_count": 8,
"accelerator_type": "GPU_8xH100"
}
}
],
"experiment": "my-training"
},
"environment_key": "default",
"task_key": "train"
},
{
"ai_runtime_task": {
"code_source_path": "/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/.air_snapshots/[SNAPSHOT].tar.gz",
"deployments": [
{
"command_path": "/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/src2/command.sh",
"compute": {
"accelerator_count": 8,
"accelerator_type": "GPU_8xH100"
}
}
],
"experiment": "my-training-2"
},
"environment_key": "default",
"task_key": "train2"
}
]
}
}
>>> jq -r .path
/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/artifacts/.internal/air_code_source_src.tar.gz
/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/artifacts/.internal/air_code_source_src2.tar.gz

=== re-planning unchanged code is a no-op (no changes)

>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged

=== editing a file changes the snapshot hash (content-addressed name changes)

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files...
Updated jobs.train
Files: 4 uploaded, 1 deleted
Resources: 0 created, 1 changed, 0 deleted, 0 unchanged

>>> print_requests.py --nostamp --sort --del-field raw_body //.air_snapshots/
{
"method": "POST",
"path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.bundle/ai-runtime-test/default/files/.air_snapshots/[SNAPSHOT].tar.gz",
"q": {
"overwrite": "true"
}
}

=== destroy removes the deployed bundle (including the synced snapshots)
=== destroy removes the deployed bundle

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
Expand Down
33 changes: 11 additions & 22 deletions acceptance/bundle/ai_runtime_task/local_code_source/script
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
# Two AI Runtime tasks each with a local directory code_source_path. Each is
# packaged into a content-addressed tarball written into the bundle
# (.air_snapshots/, at the repo root) and uploaded by normal bundle file sync;
# code_source_path/command_path are rewritten. Pip deps ride on the job's
# environments[].spec.dependencies (no requirements.yaml is synthesized).
# Two AI Runtime tasks with distinct local directory code sources. Each directory is
# turned into a tgz artifact (see bundle/config/mutator/aicode), built and uploaded
# through the standard artifact path, and its code_source_path is rewritten to the
# uploaded remote path. Pip deps ride on the job's environments[].spec.dependencies.

title "deploy packages and uploads the local code sources\n"
title "deploy packages the local code sources as tgz artifacts and uploads them\n"
trace $CLI bundle deploy

title "each task's tarball holds only synced files (both under the repo root .air_snapshots)\n"
trace list_code_snapshot.py
title "both code_source_paths rewritten to the uploaded artifact remote paths\n"
# Filters use a leading // so Git Bash on Windows does not path-convert them.
trace jq -s '.[] | select(.path=="/api/2.2/jobs/create") | .body.tasks[].ai_runtime_task.code_source_path' out.requests.txt

title "both code_source_paths point into the bundle .air_snapshots, command_paths rewritten, deps on environments spec\n"
# --del-field raw_body drops the binary tarball upload payload (kept readable). Filters
# use a leading // so Git Bash on Windows does not path-convert them. --keep is not
# passed, so print_requests.py --nostamp consumes out.requests.txt.
trace print_requests.py --nostamp --sort --del-field raw_body '//.air_snapshots/' '//jobs/create'
title "both code tarballs uploaded\n"
trace jq -r .path < out.requests.txt | grep import | grep '.tar.gz' | sort

title "re-planning unchanged code is a no-op (no changes)\n"
trace $CLI bundle plan

title "editing a file changes the snapshot hash (content-addressed name changes)\n"
update_file.py src/train.py 'print("training")' 'print("training v2")'
trace $CLI bundle deploy
trace print_requests.py --nostamp --sort --del-field raw_body '//.air_snapshots/'

title "destroy removes the deployed bundle (including the synced snapshots)\n"
title "destroy removes the deployed bundle\n"
trace $CLI bundle destroy --auto-approve
rm out.requests.txt

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

7 changes: 0 additions & 7 deletions acceptance/bundle/ai_runtime_task/local_code_source/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,3 @@ RecordRequests = true
Ignore = [
'.databricks',
]

# The archive is content-addressed: <dir>_<sha256[:16]>.tar.gz. The hash is stable
# given the committed inputs, but collapse it to a token so the test does not pin a
# specific digest. Matches both src_ and src2_ archives.
[[Repls]]
Old = '(src2?)_[0-9a-f]{16}\.tar\.gz'
New = '$1_[SNAPSHOT].tar.gz'
18 changes: 0 additions & 18 deletions bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ func (b *Bundle) SuppressProgress() bool {
return b.Quiet >= QuietAll
}

// AiCodeSnapshotDir is the sync-relative dir the aicode mutator writes AI Runtime
// code snapshots into. Force-included in sync (see GetSyncIncludePatterns) so user
// ignore rules can't filter the deployed job's code_source_path archives out.
const AiCodeSnapshotDir = ".air_snapshots"

// Filename where resources are stored for DATABRICKS_BUNDLE_ENGINE=direct
const resourcesFilename = "resources.json"

Expand Down Expand Up @@ -224,12 +219,6 @@ type Bundle struct {
// comparison with remote state, but local file validation would incorrectly fail.
SkipLocalFileValidation bool

// HasAiRuntimeCodeSnapshot is set by the aicode.PackageCodeSource build-phase
// mutator when it packages a local AI Runtime code_source into the bundle's
// snapshot dir. GetSyncIncludePatterns reads it to force-sync that dir only for
// bundles that actually use the feature, rather than for every bundle.
HasAiRuntimeCodeSnapshot bool

// Tagging is used to normalize tag keys and values.
// The implementation depends on the cloud being targeted.
Tagging tags.Cloud
Expand Down Expand Up @@ -419,13 +408,6 @@ func (b *Bundle) GetSyncIncludePatterns(ctx context.Context) ([]string, error) {
return nil, err
}
includes := append(b.Config.Sync.Include, filepath.ToSlash(filepath.Join(internalDirRel, "*.*")))
// Force-sync generated AI Runtime code snapshots so a user ignore rule (e.g.
// "*.tar.gz" in .gitignore) can't filter them out — the deployed job's
// code_source_path points at these archives (see bundle/config/mutator/aicode).
// Scoped to bundles that actually package one, so it's not a global include.
if b.HasAiRuntimeCodeSnapshot {
includes = append(includes, AiCodeSnapshotDir+"/*")
}
return includes, nil
}

Expand Down
23 changes: 0 additions & 23 deletions bundle/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,6 @@ func TestBundleLocalStateDir(t *testing.T) {
assert.Equal(t, filepath.Join(projectDir, ".databricks", "bundle", "default"), cacheDir)
}

func TestGetSyncIncludePatternsScopesSnapshotDir(t *testing.T) {
ctx := t.Context()
projectDir := t.TempDir()
f, err := os.Create(filepath.Join(projectDir, "databricks.yml"))
require.NoError(t, err)
f.Close()

b, err := Load(ctx, projectDir)
require.NoError(t, err)
b.Config.Bundle.Target = "default"

// Without an AI Runtime code snapshot, the dir is not force-included.
includes, err := b.GetSyncIncludePatterns(ctx)
require.NoError(t, err)
assert.NotContains(t, includes, AiCodeSnapshotDir+"/*")

// Once the aicode mutator sets the flag, it is.
b.HasAiRuntimeCodeSnapshot = true
includes, err = b.GetSyncIncludePatterns(ctx)
require.NoError(t, err)
assert.Contains(t, includes, AiCodeSnapshotDir+"/*")
}

func TestBundleLocalStateDirOverride(t *testing.T) {
ctx := t.Context()
projectDir := t.TempDir()
Expand Down
Loading
Loading