diff --git a/.github/OWNERS b/.github/OWNERS index a0b9aa88c8a..6b4e8e0f180 100644 --- a/.github/OWNERS +++ b/.github/OWNERS @@ -73,11 +73,13 @@ /cmd/aitools/ team:eng-apps-devex team:ide @lennartkats-db /libs/aitools/ team:eng-apps-devex team:ide @lennartkats-db +# AI Runtime +/cmd/air/ team:ai-training +/acceptance/air/ team:ai-training + # CLI compatibility manifest /internal/build/cli-compat.json team:eng-apps-devex team:platform /libs/clicompat/ team:eng-apps-devex team:platform # Experimental -/experimental/air/ team:ai-training -/acceptance/experimental/air/ team:ai-training /experimental/aitools/ team:eng-apps-devex @lennartkats-db diff --git a/.nextchanges/cli/air-graduation.md b/.nextchanges/cli/air-graduation.md new file mode 100644 index 00000000000..40d26da8558 --- /dev/null +++ b/.nextchanges/cli/air-graduation.md @@ -0,0 +1 @@ +* The AI Runtime commands are now available under `databricks air`. The deprecated `databricks experimental air` alias remains available temporarily. ([#6722](https://github.com/databricks/cli/pull/6722)) diff --git a/acceptance/experimental/air/.gitkeep b/acceptance/air/.gitkeep similarity index 100% rename from acceptance/experimental/air/.gitkeep rename to acceptance/air/.gitkeep diff --git a/acceptance/experimental/air/cancel/out.test.toml b/acceptance/air/cancel/out.test.toml similarity index 100% rename from acceptance/experimental/air/cancel/out.test.toml rename to acceptance/air/cancel/out.test.toml diff --git a/acceptance/experimental/air/cancel/output.txt b/acceptance/air/cancel/output.txt similarity index 77% rename from acceptance/experimental/air/cancel/output.txt rename to acceptance/air/cancel/output.txt index 9fd8a055f13..b30dee255aa 100644 --- a/acceptance/experimental/air/cancel/output.txt +++ b/acceptance/air/cancel/output.txt @@ -1,10 +1,10 @@ === cancel by id (text) ->>> [CLI] experimental air cancel 123 +>>> [CLI] air cancel 123 Successfully requested cancellation for run 123 === cancel by id (json) ->>> [CLI] experimental air cancel 123 -o json +>>> [CLI] air cancel 123 -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -16,13 +16,13 @@ Successfully requested cancellation for run 123 } === cancel multiple ids ->>> [CLI] experimental air cancel 123 456 +>>> [CLI] air cancel 123 456 Successfully requested cancellation for run 123 Successfully requested cancellation for run 456 Successfully requested cancellation for 2 run(s). === cancel --all ->>> [CLI] experimental air cancel --all -y +>>> [CLI] air cancel --all -y Searching active runs for [USERNAME] in [DATABRICKS_URL]... Successfully requested cancellation for run [NUMID] Successfully requested cancellation for run [NUMID] diff --git a/acceptance/air/cancel/script b/acceptance/air/cancel/script new file mode 100644 index 00000000000..d121b4d8e3b --- /dev/null +++ b/acceptance/air/cancel/script @@ -0,0 +1,11 @@ +title "cancel by id (text)" +trace $CLI air cancel 123 + +title "cancel by id (json)" +trace $CLI air cancel 123 -o json + +title "cancel multiple ids" +trace $CLI air cancel 123 456 + +title "cancel --all" +trace $CLI air cancel --all -y diff --git a/acceptance/experimental/air/cancel/test.toml b/acceptance/air/cancel/test.toml similarity index 100% rename from acceptance/experimental/air/cancel/test.toml rename to acceptance/air/cancel/test.toml diff --git a/acceptance/experimental/air/config-help/out.test.toml b/acceptance/air/config-help/out.test.toml similarity index 100% rename from acceptance/experimental/air/config-help/out.test.toml rename to acceptance/air/config-help/out.test.toml diff --git a/acceptance/experimental/air/config-help/output.txt b/acceptance/air/config-help/output.txt similarity index 83% rename from acceptance/experimental/air/config-help/output.txt rename to acceptance/air/config-help/output.txt index dc313f32eed..9c95366bf11 100644 --- a/acceptance/experimental/air/config-help/output.txt +++ b/acceptance/air/config-help/output.txt @@ -1,21 +1,21 @@ === command help ->>> [CLI] experimental air run --help +>>> [CLI] air run --help Submit a training workload to Databricks serverless GPU compute. The workload is described by a YAML config file (see --file). To look up a config field, pass its path to -h: - databricks experimental air run -h config - databricks experimental air run -h config.compute - databricks experimental air run -h config.compute.accelerator_type + databricks air run -h config + databricks air run -h config.compute + databricks air run -h config.compute.accelerator_type The path must be a separate argument: cobra reserves -h as a boolean, so -h=config.compute and -hconfig.compute are not accepted. Usage: - databricks experimental air run [flags] + databricks air run [flags] Flags: --dry-run Validate the config without submitting @@ -32,7 +32,7 @@ Global Flags: -t, --target string bundle target to use (if applicable) === schema overview ->>> [CLI] experimental air run -h config +>>> [CLI] air run -h config config The run YAML schema. Pass a field path for details, e.g. config.compute.accelerator_type. @@ -58,7 +58,7 @@ config Use "-h config." for details on a field. === nested object lists its fields ->>> [CLI] experimental air run -h config.compute +>>> [CLI] air run -h config.compute config.compute Which accelerators to run on and how many. @@ -71,35 +71,35 @@ config.compute Use "-h config.compute." for details on a field. === new submission fields are documented ->>> [CLI] experimental air run -h config.mlflow_artifact_location +>>> [CLI] air run -h config.mlflow_artifact_location config.mlflow_artifact_location DBFS location where MLflow artifacts are written. A /Volumes path is normalized to dbfs:/Volumes/... . Type: string Required: no ->>> [CLI] experimental air run -h config.compute.pool_id +>>> [CLI] air run -h config.compute.pool_id config.compute.pool_id GPU pool to run on, by id. A GPU pool is a pre-provisioned accelerator reservation; contact your Databricks account team to provision one. Must be 1-255 characters. List available pools with 'air list pools'. Type: string Required: no ->>> [CLI] experimental air run -h config.compute.priority_class +>>> [CLI] air run -h config.compute.priority_class config.compute.priority_class Scheduling priority within the pool: BEST_EFFORT (lowest, preemptable), NORMAL, or CRITICAL (highest). Requires pool_id. Type: string Required: no ->>> [CLI] experimental air run -h config.environment.dependencies +>>> [CLI] air run -h config.environment.dependencies config.environment.dependencies Inline list of packages to install. Not allowed alongside unity_catalog_image. Type: list of strings Required: no ->>> [CLI] experimental air run -h config.environment.version +>>> [CLI] air run -h config.environment.version config.environment.version Client image version to pin. @@ -107,7 +107,7 @@ config.environment.version Required: no === leaf field ->>> [CLI] experimental air run -h config.compute.accelerator_type +>>> [CLI] air run -h config.compute.accelerator_type config.compute.accelerator_type Which accelerator to run on, e.g. GPU_1xA10. See https://docs.databricks.com/aws/en/machine-learning/ai-runtime/cli/yaml-config#reference for the current list of supported GPU types. Matched case-sensitively. @@ -115,7 +115,7 @@ config.compute.accelerator_type Required: no === conditionally required leaf ->>> [CLI] experimental air run -h config.code_source.type +>>> [CLI] air run -h config.code_source.type config.code_source.type Kind of code source. Must be "snapshot", the only supported type. @@ -123,7 +123,7 @@ config.code_source.type Required: when code_source is set === union field reports both accepted shapes ->>> [CLI] experimental air run -h config.code_source.snapshot.git.remote +>>> [CLI] air run -h config.code_source.snapshot.git.remote config.code_source.snapshot.git.remote No longer supported: the snapshot archives your local copy. Only false is accepted; use commit to pin a revision. @@ -131,7 +131,7 @@ config.code_source.snapshot.git.remote Required: no === git-pinned subdirectory snapshots document root_path scoping ->>> [CLI] experimental air run -h config.code_source.snapshot.root_path +>>> [CLI] air run -h config.code_source.snapshot.root_path config.code_source.snapshot.root_path Root of the code source to archive. A git-pinned subdirectory packages only that subtree. @@ -139,7 +139,7 @@ config.code_source.snapshot.root_path Required: when code_source.snapshot is set === the config. prefix is optional ->>> [CLI] experimental air run -h compute.num_accelerators +>>> [CLI] air run -h compute.num_accelerators config.compute.num_accelerators Total number of GPUs to allocate. Must be a positive multiple of the accelerator type's per-node GPU count. See https://docs.databricks.com/aws/en/machine-learning/ai-runtime/cli/yaml-config#reference for supported GPU types. @@ -147,11 +147,11 @@ config.compute.num_accelerators Required: no === unknown field suggests the near match ->>> [CLI] experimental air run -h config.compute.acclerator_type +>>> [CLI] air run -h config.compute.acclerator_type Error: unknown config field "config.compute.acclerator_type"; did you mean "accelerator_type"? fields under "config.compute" are: accelerator_type, num_accelerators, pool_id, priority_class === free-form map keys are not schema fields ->>> [CLI] experimental air run -h config.parameters.learning_rate +>>> [CLI] air run -h config.parameters.learning_rate Error: "config.parameters" holds user-defined keys, so "learning_rate" is not part of the schema; see "config.parameters" instead diff --git a/acceptance/air/config-help/script b/acceptance/air/config-help/script new file mode 100644 index 00000000000..e38fb1dd5e9 --- /dev/null +++ b/acceptance/air/config-help/script @@ -0,0 +1,41 @@ +# Pin the rendered config field help. Any change to a `help:` struct tag on the +# run YAML schema shows up as a diff here. + +# Plain -h must keep documenting the command itself, and advertise the config +# path syntax so the feature is discoverable. +title "command help" +trace $CLI air run --help + +title "schema overview" +trace $CLI air run -h config + +title "nested object lists its fields" +trace $CLI air run -h config.compute + +title "new submission fields are documented" +trace $CLI air run -h config.mlflow_artifact_location +trace $CLI air run -h config.compute.pool_id +trace $CLI air run -h config.compute.priority_class +trace $CLI air run -h config.environment.dependencies +trace $CLI air run -h config.environment.version + +title "leaf field" +trace $CLI air run -h config.compute.accelerator_type + +title "conditionally required leaf" +trace $CLI air run -h config.code_source.type + +title "union field reports both accepted shapes" +trace $CLI air run -h config.code_source.snapshot.git.remote + +title "git-pinned subdirectory snapshots document root_path scoping" +trace $CLI air run -h config.code_source.snapshot.root_path + +title "the config. prefix is optional" +trace $CLI air run -h compute.num_accelerators + +title "unknown field suggests the near match" +trace $CLI air run -h config.compute.acclerator_type + +title "free-form map keys are not schema fields" +trace $CLI air run -h config.parameters.learning_rate diff --git a/acceptance/experimental/air/convert-to-dabs/out.test.toml b/acceptance/air/convert-to-dabs/out.test.toml similarity index 100% rename from acceptance/experimental/air/convert-to-dabs/out.test.toml rename to acceptance/air/convert-to-dabs/out.test.toml diff --git a/acceptance/experimental/air/convert-to-dabs/output.txt b/acceptance/air/convert-to-dabs/output.txt similarity index 94% rename from acceptance/experimental/air/convert-to-dabs/output.txt rename to acceptance/air/convert-to-dabs/output.txt index 0922646a0d0..07323e00079 100644 --- a/acceptance/experimental/air/convert-to-dabs/output.txt +++ b/acceptance/air/convert-to-dabs/output.txt @@ -1,6 +1,6 @@ === convert an AIR run YAML into a DABs bundle (in place, next to the source) ->>> [CLI] experimental air convert-to-dabs train.yaml +>>> [CLI] air convert-to-dabs train.yaml Wrote a Databricks Asset Bundle to .: databricks.yml generated_artifacts/training_config.yaml @@ -77,13 +77,13 @@ Workspace: Validation OK! === re-converting refuses to clobber the generated bundle ->>> [CLI] experimental air convert-to-dabs train.yaml +>>> [CLI] air convert-to-dabs train.yaml Error: databricks.yml already exists in .; pass --force to overwrite or remove it Exit code: 1 === --force overwrites it ->>> [CLI] experimental air convert-to-dabs train.yaml --force +>>> [CLI] air convert-to-dabs train.yaml --force Wrote a Databricks Asset Bundle to .: databricks.yml generated_artifacts/training_config.yaml diff --git a/acceptance/experimental/air/convert-to-dabs/script b/acceptance/air/convert-to-dabs/script similarity index 71% rename from acceptance/experimental/air/convert-to-dabs/script rename to acceptance/air/convert-to-dabs/script index fd39053c927..ff0e124d339 100644 --- a/acceptance/experimental/air/convert-to-dabs/script +++ b/acceptance/air/convert-to-dabs/script @@ -1,5 +1,5 @@ title "convert an AIR run YAML into a DABs bundle (in place, next to the source)" -trace $CLI experimental air convert-to-dabs train.yaml +trace $CLI air convert-to-dabs train.yaml title "emitted databricks.yml (code_source packaged as a tgz artifact; no code is copied)" trace cat databricks.yml @@ -11,7 +11,7 @@ title "the emitted bundle validates" trace $CLI bundle validate title "re-converting refuses to clobber the generated bundle" -errcode trace $CLI experimental air convert-to-dabs train.yaml +errcode trace $CLI air convert-to-dabs train.yaml title "--force overwrites it" -trace $CLI experimental air convert-to-dabs train.yaml --force +trace $CLI air convert-to-dabs train.yaml --force diff --git a/acceptance/experimental/air/convert-to-dabs/src/train.py b/acceptance/air/convert-to-dabs/src/train.py similarity index 100% rename from acceptance/experimental/air/convert-to-dabs/src/train.py rename to acceptance/air/convert-to-dabs/src/train.py diff --git a/acceptance/experimental/air/convert-to-dabs/test.toml b/acceptance/air/convert-to-dabs/test.toml similarity index 100% rename from acceptance/experimental/air/convert-to-dabs/test.toml rename to acceptance/air/convert-to-dabs/test.toml diff --git a/acceptance/experimental/air/convert-to-dabs/train.yaml b/acceptance/air/convert-to-dabs/train.yaml similarity index 100% rename from acceptance/experimental/air/convert-to-dabs/train.yaml rename to acceptance/air/convert-to-dabs/train.yaml diff --git a/acceptance/experimental/air/get-ai-runtime/out.test.toml b/acceptance/air/get-ai-runtime/out.test.toml similarity index 100% rename from acceptance/experimental/air/get-ai-runtime/out.test.toml rename to acceptance/air/get-ai-runtime/out.test.toml diff --git a/acceptance/experimental/air/get-ai-runtime/output.txt b/acceptance/air/get-ai-runtime/output.txt similarity index 97% rename from acceptance/experimental/air/get-ai-runtime/output.txt rename to acceptance/air/get-ai-runtime/output.txt index 9267ea4b8d9..900871ab6ef 100644 --- a/acceptance/experimental/air/get-ai-runtime/output.txt +++ b/acceptance/air/get-ai-runtime/output.txt @@ -1,6 +1,6 @@ === get (text) ->>> [CLI] experimental air get 123 +>>> [CLI] air get 123 ╭─ Configuration ────────────────────────────────────────────────╮ │ │ @@ -35,7 +35,7 @@ Run URL: [DATABRICKS_URL]/jobs/runs/123?o=[NUMID] MLflow URL: [DATABRICKS_URL]/ml/experiments/exp1/runs/run1 === get (json) ->>> [CLI] experimental air get 123 -o json +>>> [CLI] air get 123 -o json { "v": 1, "ts": "[TIMESTAMP]", diff --git a/acceptance/experimental/air/get-ai-runtime/script b/acceptance/air/get-ai-runtime/script similarity index 86% rename from acceptance/experimental/air/get-ai-runtime/script rename to acceptance/air/get-ai-runtime/script index 3f41b089cdd..7a98ebac655 100644 --- a/acceptance/experimental/air/get-ai-runtime/script +++ b/acceptance/air/get-ai-runtime/script @@ -5,7 +5,7 @@ $CLI workspace mkdirs "/Workspace/Users/user@example.com/.air/cli_launch/my-exp/ $CLI workspace import "/Workspace/Users/user@example.com/.air/cli_launch/my-exp/my-exp_abc/training_config.yaml" --file training_config.yaml --format AUTO &> LOG.import title "get (text)" -trace $CLI experimental air get 123 +trace $CLI air get 123 title "get (json)" -trace $CLI experimental air get 123 -o json +trace $CLI air get 123 -o json diff --git a/acceptance/experimental/air/get-ai-runtime/test.toml b/acceptance/air/get-ai-runtime/test.toml similarity index 100% rename from acceptance/experimental/air/get-ai-runtime/test.toml rename to acceptance/air/get-ai-runtime/test.toml diff --git a/acceptance/experimental/air/get-ai-runtime/training_config.yaml b/acceptance/air/get-ai-runtime/training_config.yaml similarity index 100% rename from acceptance/experimental/air/get-ai-runtime/training_config.yaml rename to acceptance/air/get-ai-runtime/training_config.yaml diff --git a/acceptance/experimental/air/get/out.test.toml b/acceptance/air/get/out.test.toml similarity index 100% rename from acceptance/experimental/air/get/out.test.toml rename to acceptance/air/get/out.test.toml diff --git a/acceptance/experimental/air/get/output.txt b/acceptance/air/get/output.txt similarity index 95% rename from acceptance/experimental/air/get/output.txt rename to acceptance/air/get/output.txt index a448d7a057c..7d5625108b8 100644 --- a/acceptance/experimental/air/get/output.txt +++ b/acceptance/air/get/output.txt @@ -1,6 +1,6 @@ === get (text) ->>> [CLI] experimental air get 123 +>>> [CLI] air get 123 ╭─ Configuration ────────────────────────────────────────────────╮ │ │ @@ -35,7 +35,7 @@ Run URL: [DATABRICKS_URL]/jobs/runs/123?o=[NUMID] MLflow URL: [DATABRICKS_URL]/ml/experiments/exp1/runs/run1 === get (json) ->>> [CLI] experimental air get 123 -o json +>>> [CLI] air get 123 -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -54,13 +54,13 @@ MLflow URL: [DATABRICKS_URL]/ml/experiments/exp1/runs/run1 } === invalid run id ->>> [CLI] experimental air get notanumber +>>> [CLI] air get notanumber Error: invalid JOB_RUN_ID "notanumber": must be a positive integer Exit code: 1 === invalid run id (json) ->>> [CLI] experimental air get notanumber -o json +>>> [CLI] air get notanumber -o json { "v": 1, "ts": "[TIMESTAMP]", diff --git a/acceptance/air/get/script b/acceptance/air/get/script new file mode 100644 index 00000000000..40910baa7fa --- /dev/null +++ b/acceptance/air/get/script @@ -0,0 +1,11 @@ +title "get (text)" +trace $CLI air get 123 + +title "get (json)" +trace $CLI air get 123 -o json + +title "invalid run id" +errcode trace $CLI air get notanumber + +title "invalid run id (json)" +errcode trace $CLI air get notanumber -o json diff --git a/acceptance/experimental/air/get/test.toml b/acceptance/air/get/test.toml similarity index 100% rename from acceptance/experimental/air/get/test.toml rename to acceptance/air/get/test.toml diff --git a/acceptance/experimental/air/help/out.test.toml b/acceptance/air/help/out.test.toml similarity index 100% rename from acceptance/experimental/air/help/out.test.toml rename to acceptance/air/help/out.test.toml diff --git a/acceptance/experimental/air/help/output.txt b/acceptance/air/help/output.txt similarity index 77% rename from acceptance/experimental/air/help/output.txt rename to acceptance/air/help/output.txt index 46c08458fb6..d459128b009 100644 --- a/acceptance/experimental/air/help/output.txt +++ b/acceptance/air/help/output.txt @@ -1,13 +1,10 @@ === help ->>> [CLI] experimental air --help -Run and manage AI runtime training workloads on Databricks serverless GPU compute. - -This command set is the Go port of the standalone Python "air" CLI. It is -experimental and may change in future versions. +>>> [CLI] air --help +Run and manage AI Runtime training workloads on Databricks serverless GPU compute. Usage: - databricks experimental air [command] + databricks air [command] Available Commands: cancel Cancel one or more runs @@ -26,15 +23,15 @@ Global Flags: -p, --profile string ~/.databrickscfg profile -t, --target string bundle target to use (if applicable) -Use "databricks experimental air [command] --help" for more information about a command. +Use "databricks air [command] --help" for more information about a command. === list help ->>> [CLI] experimental air list --help +>>> [CLI] air list --help List your active runs for the current profile (use --all-status for finished runs) Usage: - databricks experimental air list [flags] - databricks experimental air list [command] + databricks air list [flags] + databricks air list [command] Available Commands: pools List the GPU pools available to the current workspace @@ -52,14 +49,14 @@ Global Flags: -p, --profile string ~/.databrickscfg profile -t, --target string bundle target to use (if applicable) -Use "databricks experimental air list [command] --help" for more information about a command. +Use "databricks air list [command] --help" for more information about a command. === logs help ->>> [CLI] experimental air logs --help +>>> [CLI] air logs --help Stream logs from an active run, or fetch logs from a completed run. Usage: - databricks experimental air logs JOB_RUN_ID [flags] + databricks air logs JOB_RUN_ID [flags] Flags: --download-to string Download all logs to this directory instead of printing diff --git a/acceptance/experimental/air/help/script b/acceptance/air/help/script similarity index 57% rename from acceptance/experimental/air/help/script rename to acceptance/air/help/script index 91dc12567a6..2e528d65e80 100644 --- a/acceptance/experimental/air/help/script +++ b/acceptance/air/help/script @@ -2,10 +2,10 @@ # shows up as a diff here. title "help" -trace $CLI experimental air --help +trace $CLI air --help title "list help" -trace $CLI experimental air list --help +trace $CLI air list --help title "logs help" -trace $CLI experimental air logs --help +trace $CLI air logs --help diff --git a/acceptance/experimental/air/list/out.test.toml b/acceptance/air/list/out.test.toml similarity index 100% rename from acceptance/experimental/air/list/out.test.toml rename to acceptance/air/list/out.test.toml diff --git a/acceptance/experimental/air/list/output.txt b/acceptance/air/list/output.txt similarity index 87% rename from acceptance/experimental/air/list/output.txt rename to acceptance/air/list/output.txt index c71cae27ef4..10889d0b2d6 100644 --- a/acceptance/experimental/air/list/output.txt +++ b/acceptance/air/list/output.txt @@ -1,11 +1,11 @@ === list (text) ->>> [CLI] experimental air list +>>> [CLI] air list Run ID Experiment Status Started Duration Progress MLflow User Accelerators [NUMID] qwen-train ● SUCCESS [TIMESTAMP] 12s - qwen-train-001 [USERNAME] 8x H100 === list (json) ->>> [CLI] experimental air list -o json +>>> [CLI] air list -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -24,12 +24,12 @@ } === list --all-status (text, via AiTrainingService index) ->>> [CLI] experimental air list --all-status +>>> [CLI] air list --all-status Run ID Experiment Status Started Duration Progress MLflow User Accelerators [NUMID] qwen-train ● SUCCESS [TIMESTAMP] 12s - qwen-train-001 [USERNAME] 8x H100 === list --all-status (json) ->>> [CLI] experimental air list --all-status -o json +>>> [CLI] air list --all-status -o json { "v": 1, "ts": "[TIMESTAMP]", diff --git a/acceptance/air/list/script b/acceptance/air/list/script new file mode 100644 index 00000000000..449b2a936e0 --- /dev/null +++ b/acceptance/air/list/script @@ -0,0 +1,11 @@ +title "list (text)" +trace $CLI air list + +title "list (json)" +trace $CLI air list -o json + +title "list --all-status (text, via AiTrainingService index)" +trace $CLI air list --all-status + +title "list --all-status (json)" +trace $CLI air list --all-status -o json diff --git a/acceptance/experimental/air/list/test.toml b/acceptance/air/list/test.toml similarity index 100% rename from acceptance/experimental/air/list/test.toml rename to acceptance/air/list/test.toml diff --git a/acceptance/experimental/air/logs-download/out.test.toml b/acceptance/air/logs-download/out.test.toml similarity index 100% rename from acceptance/experimental/air/logs-download/out.test.toml rename to acceptance/air/logs-download/out.test.toml diff --git a/acceptance/experimental/air/logs-download/output.txt b/acceptance/air/logs-download/output.txt similarity index 67% rename from acceptance/experimental/air/logs-download/output.txt rename to acceptance/air/logs-download/output.txt index 202f1094fd5..4dedd822aa2 100644 --- a/acceptance/experimental/air/logs-download/output.txt +++ b/acceptance/air/logs-download/output.txt @@ -1,16 +1,16 @@ === download-to reports no logs when none are available ->>> [CLI] experimental air logs 123 --download-to dl-logs +>>> [CLI] air logs 123 --download-to dl-logs No logs available for run 123. Run terminated in state SUCCESS === download-to with an out-of-range node is rejected ->>> [CLI] experimental air logs 123 --download-to dl-logs --node 5 +>>> [CLI] air logs 123 --download-to dl-logs --node 5 Error: invalid --node 5: run has 2 node(s), indexed 0 to 1 Exit code: 1 === download-to cannot be combined with --tail ->>> [CLI] experimental air logs 123 --download-to dl-logs --tail 50 +>>> [CLI] air logs 123 --download-to dl-logs --tail 50 Error: --download-to writes complete logs, so it cannot be combined with --tail or --minutes Exit code: 1 diff --git a/acceptance/experimental/air/logs-download/script b/acceptance/air/logs-download/script similarity index 64% rename from acceptance/experimental/air/logs-download/script rename to acceptance/air/logs-download/script index b90fbbdb850..324c35f2a85 100644 --- a/acceptance/experimental/air/logs-download/script +++ b/acceptance/air/logs-download/script @@ -3,10 +3,10 @@ # download is covered by unit tests, since the pre-signed URL host is dynamic). title "download-to reports no logs when none are available" -errcode trace $CLI experimental air logs 123 --download-to dl-logs +errcode trace $CLI air logs 123 --download-to dl-logs title "download-to with an out-of-range node is rejected" -errcode trace $CLI experimental air logs 123 --download-to dl-logs --node 5 +errcode trace $CLI air logs 123 --download-to dl-logs --node 5 title "download-to cannot be combined with --tail" -errcode trace $CLI experimental air logs 123 --download-to dl-logs --tail 50 +errcode trace $CLI air logs 123 --download-to dl-logs --tail 50 diff --git a/acceptance/experimental/air/logs-download/test.toml b/acceptance/air/logs-download/test.toml similarity index 100% rename from acceptance/experimental/air/logs-download/test.toml rename to acceptance/air/logs-download/test.toml diff --git a/acceptance/experimental/air/logs-mlflow-fallback/out.test.toml b/acceptance/air/logs-mlflow-fallback/out.test.toml similarity index 100% rename from acceptance/experimental/air/logs-mlflow-fallback/out.test.toml rename to acceptance/air/logs-mlflow-fallback/out.test.toml diff --git a/acceptance/experimental/air/logs-mlflow-fallback/output.txt b/acceptance/air/logs-mlflow-fallback/output.txt similarity index 76% rename from acceptance/experimental/air/logs-mlflow-fallback/output.txt rename to acceptance/air/logs-mlflow-fallback/output.txt index 874ad273314..e783e9a1ba7 100644 --- a/acceptance/experimental/air/logs-mlflow-fallback/output.txt +++ b/acceptance/air/logs-mlflow-fallback/output.txt @@ -1,8 +1,8 @@ === logs falls back to mlflow (no logs) ->>> [CLI] experimental air logs 123 +>>> [CLI] air logs 123 No logs available for run 123. Run terminated in state SUCCESS === logs falls back to mlflow (json) ->>> [CLI] experimental air logs 123 -o json +>>> [CLI] air logs 123 -o json {"type":"ERROR","ts":"[TIMESTAMP]","node":0,"line":"No logs available for run 123. Run terminated in state SUCCESS"} diff --git a/acceptance/experimental/air/logs-mlflow-fallback/script b/acceptance/air/logs-mlflow-fallback/script similarity index 76% rename from acceptance/experimental/air/logs-mlflow-fallback/script rename to acceptance/air/logs-mlflow-fallback/script index ad8856a036a..d8c52588bd2 100644 --- a/acceptance/experimental/air/logs-mlflow-fallback/script +++ b/acceptance/air/logs-mlflow-fallback/script @@ -3,7 +3,7 @@ # logs and exits non-zero — proving the try/catch routes to MLflow. title "logs falls back to mlflow (no logs)" -errcode trace $CLI experimental air logs 123 +errcode trace $CLI air logs 123 title "logs falls back to mlflow (json)" -errcode trace $CLI experimental air logs 123 -o json +errcode trace $CLI air logs 123 -o json diff --git a/acceptance/experimental/air/logs-mlflow-fallback/test.toml b/acceptance/air/logs-mlflow-fallback/test.toml similarity index 100% rename from acceptance/experimental/air/logs-mlflow-fallback/test.toml rename to acceptance/air/logs-mlflow-fallback/test.toml diff --git a/acceptance/experimental/air/logs/out.test.toml b/acceptance/air/logs/out.test.toml similarity index 100% rename from acceptance/experimental/air/logs/out.test.toml rename to acceptance/air/logs/out.test.toml diff --git a/acceptance/experimental/air/logs/output.txt b/acceptance/air/logs/output.txt similarity index 72% rename from acceptance/experimental/air/logs/output.txt rename to acceptance/air/logs/output.txt index a070a834a4d..da16c857ad6 100644 --- a/acceptance/experimental/air/logs/output.txt +++ b/acceptance/air/logs/output.txt @@ -1,47 +1,47 @@ === logs (text, completed run) ->>> [CLI] experimental air logs 123 +>>> [CLI] air logs 123 step 1 step 2 CUDA out of memory === logs (json) ->>> [CLI] experimental air logs 123 -o json +>>> [CLI] air logs 123 -o json {"type":"LOG","ts":"[TIMESTAMP]","node":0,"line":"step 1"} {"type":"LOG","ts":"[TIMESTAMP]","node":0,"line":"step 2"} {"type":"ALERT","ts":"[TIMESTAMP]","node":0,"line":"CUDA out of memory"} {"type":"LOG","ts":"[TIMESTAMP]","node":0,"line":"CUDA out of memory"} === logs with --minutes ->>> [CLI] experimental air logs 123 --minutes 30 +>>> [CLI] air logs 123 --minutes 30 step 1 step 2 CUDA out of memory === logs with --tail ->>> [CLI] experimental air logs 123 --tail 1 +>>> [CLI] air logs 123 --tail 1 CUDA out of memory === logs with --tail 0 is rejected ->>> [CLI] experimental air logs 123 --tail 0 +>>> [CLI] air logs 123 --tail 0 Error: invalid --tail 0: must be positive Exit code: 1 === logs from a specific retry ->>> [CLI] experimental air logs 123 --retry 0 +>>> [CLI] air logs 123 --retry 0 step 1 step 2 CUDA out of memory === logs --tail and --minutes are mutually exclusive ->>> [CLI] experimental air logs 123 --tail 100 --minutes 30 +>>> [CLI] air logs 123 --tail 100 --minutes 30 Error: cannot combine --tail with --minutes: --tail selects by line count, --minutes by time window Exit code: 1 === logs --tail and --minutes are mutually exclusive (json) ->>> [CLI] experimental air logs 123 --tail 100 --minutes 30 -o json +>>> [CLI] air logs 123 --tail 100 --minutes 30 -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -56,13 +56,13 @@ Exit code: 1 Exit code: 1 === invalid run id ->>> [CLI] experimental air logs notanumber +>>> [CLI] air logs notanumber Error: invalid JOB_RUN_ID "notanumber": must be a positive integer Exit code: 1 === negative node ->>> [CLI] experimental air logs 123 --node -1 +>>> [CLI] air logs 123 --node -1 Error: invalid --node -1: must not be negative Exit code: 1 diff --git a/acceptance/air/logs/script b/acceptance/air/logs/script new file mode 100644 index 00000000000..9060c674a74 --- /dev/null +++ b/acceptance/air/logs/script @@ -0,0 +1,29 @@ +title "logs (text, completed run)" +trace $CLI air logs 123 + +title "logs (json)" +trace $CLI air logs 123 -o json + +title "logs with --minutes" +trace $CLI air logs 123 --minutes 30 + +title "logs with --tail" +trace $CLI air logs 123 --tail 1 + +title "logs with --tail 0 is rejected" +errcode trace $CLI air logs 123 --tail 0 + +title "logs from a specific retry" +trace $CLI air logs 123 --retry 0 + +title "logs --tail and --minutes are mutually exclusive" +errcode trace $CLI air logs 123 --tail 100 --minutes 30 + +title "logs --tail and --minutes are mutually exclusive (json)" +errcode trace $CLI air logs 123 --tail 100 --minutes 30 -o json + +title "invalid run id" +errcode trace $CLI air logs notanumber + +title "negative node" +errcode trace $CLI air logs 123 --node -1 diff --git a/acceptance/experimental/air/logs/test.toml b/acceptance/air/logs/test.toml similarity index 100% rename from acceptance/experimental/air/logs/test.toml rename to acceptance/air/logs/test.toml diff --git a/acceptance/experimental/air/pools/out.test.toml b/acceptance/air/pools/out.test.toml similarity index 100% rename from acceptance/experimental/air/pools/out.test.toml rename to acceptance/air/pools/out.test.toml diff --git a/acceptance/experimental/air/pools/output.txt b/acceptance/air/pools/output.txt similarity index 83% rename from acceptance/experimental/air/pools/output.txt rename to acceptance/air/pools/output.txt index 4df5949628c..d4f289bf0d9 100644 --- a/acceptance/experimental/air/pools/output.txt +++ b/acceptance/air/pools/output.txt @@ -1,12 +1,12 @@ === list pools (text) ->>> [CLI] experimental air list pools +>>> [CLI] air list pools ID ACCELERATOR RESERVED pool-8xh100-alpha GPU_8xH100 64 pool-1xh100-beta GPU_1xH100 8 === list pools (json) ->>> [CLI] experimental air list pools -o json +>>> [CLI] air list pools -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -27,7 +27,7 @@ pool-1xh100-beta GPU_1xH100 8 } === get pool (text) ->>> [CLI] experimental air get pool pool-8xh100-alpha +>>> [CLI] air get pool pool-8xh100-alpha Pool ID: pool-8xh100-alpha Accelerator Type: GPU_8xH100 Reserved Accelerators: 64 @@ -35,7 +35,7 @@ Used Accelerators: 40 Idle Accelerators: 24 === get pool (json) ->>> [CLI] experimental air get pool pool-8xh100-alpha -o json +>>> [CLI] air get pool pool-8xh100-alpha -o json { "v": 1, "ts": "[TIMESTAMP]", diff --git a/acceptance/air/pools/script b/acceptance/air/pools/script new file mode 100644 index 00000000000..be1d9c306dc --- /dev/null +++ b/acceptance/air/pools/script @@ -0,0 +1,11 @@ +title "list pools (text)" +trace $CLI air list pools + +title "list pools (json)" +trace $CLI air list pools -o json + +title "get pool (text)" +trace $CLI air get pool pool-8xh100-alpha + +title "get pool (json)" +trace $CLI air get pool pool-8xh100-alpha -o json diff --git a/acceptance/experimental/air/pools/test.toml b/acceptance/air/pools/test.toml similarity index 100% rename from acceptance/experimental/air/pools/test.toml rename to acceptance/air/pools/test.toml diff --git a/acceptance/experimental/air/run-submit-databricks-ai/out.test.toml b/acceptance/air/run-submit-databricks-ai/out.test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-databricks-ai/out.test.toml rename to acceptance/air/run-submit-databricks-ai/out.test.toml diff --git a/acceptance/experimental/air/run-submit-databricks-ai/output.txt b/acceptance/air/run-submit-databricks-ai/output.txt similarity index 94% rename from acceptance/experimental/air/run-submit-databricks-ai/output.txt rename to acceptance/air/run-submit-databricks-ai/output.txt index 7f7bfff1783..dbc134d186b 100644 --- a/acceptance/experimental/air/run-submit-databricks-ai/output.txt +++ b/acceptance/air/run-submit-databricks-ai/output.txt @@ -1,13 +1,13 @@ === submit with a Databricks AI environment and no dependencies ->>> [CLI] experimental air run -f run.yaml +>>> [CLI] air run -f run.yaml Submitting experiment: databricks-ai-v5-smoke Submitted workload with Job Run ID: 555 View job run at: [DATABRICKS_URL]/jobs/runs/555 Tip: use --watch when submitting a run to stream logs to your terminal. Stream logs after submission using: - databricks experimental air logs 555 + databricks air logs 555 === submit includes the Databricks AI environment version and omits dependencies >>> print_requests.py //api/2.2/jobs/runs/submit diff --git a/acceptance/experimental/air/run-submit-databricks-ai/run.yaml b/acceptance/air/run-submit-databricks-ai/run.yaml similarity index 100% rename from acceptance/experimental/air/run-submit-databricks-ai/run.yaml rename to acceptance/air/run-submit-databricks-ai/run.yaml diff --git a/acceptance/experimental/air/run-submit-databricks-ai/script b/acceptance/air/run-submit-databricks-ai/script similarity index 82% rename from acceptance/experimental/air/run-submit-databricks-ai/script rename to acceptance/air/run-submit-databricks-ai/script index da4301870d2..94f2ef5250f 100644 --- a/acceptance/experimental/air/run-submit-databricks-ai/script +++ b/acceptance/air/run-submit-databricks-ai/script @@ -1,5 +1,5 @@ title "submit with a Databricks AI environment and no dependencies" -trace $CLI experimental air run -f run.yaml +trace $CLI air run -f run.yaml title "submit includes the Databricks AI environment version and omits dependencies" trace print_requests.py //api/2.2/jobs/runs/submit diff --git a/acceptance/experimental/air/run-submit-databricks-ai/test.toml b/acceptance/air/run-submit-databricks-ai/test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-databricks-ai/test.toml rename to acceptance/air/run-submit-databricks-ai/test.toml diff --git a/acceptance/experimental/air/run-submit-deps/.gitattributes b/acceptance/air/run-submit-deps/.gitattributes similarity index 100% rename from acceptance/experimental/air/run-submit-deps/.gitattributes rename to acceptance/air/run-submit-deps/.gitattributes diff --git a/acceptance/experimental/air/run-submit-deps/databricks.yml b/acceptance/air/run-submit-deps/databricks.yml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/databricks.yml rename to acceptance/air/run-submit-deps/databricks.yml diff --git a/acceptance/experimental/air/run-submit-deps/out.test.toml b/acceptance/air/run-submit-deps/out.test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/out.test.toml rename to acceptance/air/run-submit-deps/out.test.toml diff --git a/acceptance/experimental/air/run-submit-deps/output.txt b/acceptance/air/run-submit-deps/output.txt similarity index 94% rename from acceptance/experimental/air/run-submit-deps/output.txt rename to acceptance/air/run-submit-deps/output.txt index 618148f4a6f..3346fcd06d7 100644 --- a/acceptance/experimental/air/run-submit-deps/output.txt +++ b/acceptance/air/run-submit-deps/output.txt @@ -1,13 +1,13 @@ === submit with inline dependencies ->>> [CLI] experimental air run -f run.yaml +>>> [CLI] air run -f run.yaml Submitting experiment: deps-smoke Submitted workload with Job Run ID: 555 View job run at: [DATABRICKS_URL]/jobs/runs/555 Tip: use --watch when submitting a run to stream logs to your terminal. Stream logs after submission using: - databricks experimental air logs 555 + databricks air logs 555 === only config + command are uploaded; no requirements.yaml >>> print_requests.py //api/2.0/workspace-files/import-file --oneline --sort --unique --keep @@ -61,8 +61,8 @@ Stream logs after submission using: } === a requirements.yaml file path is rejected; deps must be inline ->>> [CLI] experimental air run -f run-file.yaml +>>> [CLI] air run -f run-file.yaml Error: invalid config run-file.yaml: environment.dependencies must be a list of packages or reference a requirements.txt (see https://docs.databricks.com/aws/en/machine-learning/ai-runtime/cli/yaml-config#reference). A direct file reference is not supported Tip: use the --debug flag to see more details and a trace of this error: - databricks --debug experimental air run … + databricks --debug air run … diff --git a/acceptance/experimental/air/run-submit-deps/reqs.yaml b/acceptance/air/run-submit-deps/reqs.yaml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/reqs.yaml rename to acceptance/air/run-submit-deps/reqs.yaml diff --git a/acceptance/experimental/air/run-submit-deps/run-file.yaml b/acceptance/air/run-submit-deps/run-file.yaml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/run-file.yaml rename to acceptance/air/run-submit-deps/run-file.yaml diff --git a/acceptance/experimental/air/run-submit-deps/run.yaml b/acceptance/air/run-submit-deps/run.yaml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/run.yaml rename to acceptance/air/run-submit-deps/run.yaml diff --git a/acceptance/experimental/air/run-submit-deps/script b/acceptance/air/run-submit-deps/script similarity index 80% rename from acceptance/experimental/air/run-submit-deps/script rename to acceptance/air/run-submit-deps/script index 35eb8e5c810..422980c99b3 100644 --- a/acceptance/experimental/air/run-submit-deps/script +++ b/acceptance/air/run-submit-deps/script @@ -1,5 +1,5 @@ title "submit with inline dependencies" -trace $CLI experimental air run -f run.yaml +trace $CLI air run -f run.yaml title "only config + command are uploaded; no requirements.yaml" trace print_requests.py //api/2.0/workspace-files/import-file --oneline --sort --unique --keep @@ -8,4 +8,4 @@ title "inline deps, artifact location, and capacity id reach the submit payload" trace print_requests.py //api/2.2/jobs/runs/submit title "a requirements.yaml file path is rejected; deps must be inline" -musterr trace $CLI experimental air run -f run-file.yaml +musterr trace $CLI air run -f run-file.yaml diff --git a/acceptance/experimental/air/run-submit-deps/test.toml b/acceptance/air/run-submit-deps/test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-deps/test.toml rename to acceptance/air/run-submit-deps/test.toml diff --git a/acceptance/experimental/air/run-submit-overrides/.gitattributes b/acceptance/air/run-submit-overrides/.gitattributes similarity index 100% rename from acceptance/experimental/air/run-submit-overrides/.gitattributes rename to acceptance/air/run-submit-overrides/.gitattributes diff --git a/acceptance/experimental/air/run-submit-overrides/databricks.yml b/acceptance/air/run-submit-overrides/databricks.yml similarity index 100% rename from acceptance/experimental/air/run-submit-overrides/databricks.yml rename to acceptance/air/run-submit-overrides/databricks.yml diff --git a/acceptance/experimental/air/run-submit-overrides/out.test.toml b/acceptance/air/run-submit-overrides/out.test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-overrides/out.test.toml rename to acceptance/air/run-submit-overrides/out.test.toml diff --git a/acceptance/experimental/air/run-submit-overrides/output.txt b/acceptance/air/run-submit-overrides/output.txt similarity index 88% rename from acceptance/experimental/air/run-submit-overrides/output.txt rename to acceptance/air/run-submit-overrides/output.txt index c8240021986..0be49262d1b 100644 --- a/acceptance/experimental/air/run-submit-overrides/output.txt +++ b/acceptance/air/run-submit-overrides/output.txt @@ -1,6 +1,6 @@ === submit with nested overrides ->>> [CLI] experimental air run -f run.yaml --override compute.num_accelerators=2 --override parameters.model.hidden_size=2048 --override parameters.optimizer.learning_rate=0.001 +>>> [CLI] air run -f run.yaml --override compute.num_accelerators=2 --override parameters.model.hidden_size=2048 --override parameters.optimizer.learning_rate=0.001 Override: changing compute.num_accelerators from 1 to 2 Override: changing parameters.model.hidden_size from 1024 to 2048 Override: setting parameters.optimizer.learning_rate to 0.001 @@ -10,7 +10,7 @@ View job run at: [DATABRICKS_URL]/jobs/runs/555 Tip: use --watch when submitting a run to stream logs to your terminal. Stream logs after submission using: - databricks experimental air logs 555 + databricks air logs 555 === the uploaded config preserves source order and contains overrides >>> print_requests.py //api/2.0/workspace-files/import-file --oneline --sort --unique diff --git a/acceptance/experimental/air/run-submit-overrides/run.yaml b/acceptance/air/run-submit-overrides/run.yaml similarity index 100% rename from acceptance/experimental/air/run-submit-overrides/run.yaml rename to acceptance/air/run-submit-overrides/run.yaml diff --git a/acceptance/experimental/air/run-submit-overrides/script b/acceptance/air/run-submit-overrides/script similarity index 88% rename from acceptance/experimental/air/run-submit-overrides/script rename to acceptance/air/run-submit-overrides/script index 59d2138c860..263c1920e6c 100644 --- a/acceptance/experimental/air/run-submit-overrides/script +++ b/acceptance/air/run-submit-overrides/script @@ -1,5 +1,5 @@ title "submit with nested overrides" -trace $CLI experimental air run -f run.yaml \ +trace $CLI air run -f run.yaml \ --override compute.num_accelerators=2 \ --override parameters.model.hidden_size=2048 \ --override parameters.optimizer.learning_rate=0.001 diff --git a/acceptance/experimental/air/run-submit-overrides/test.toml b/acceptance/air/run-submit-overrides/test.toml similarity index 100% rename from acceptance/experimental/air/run-submit-overrides/test.toml rename to acceptance/air/run-submit-overrides/test.toml diff --git a/acceptance/experimental/air/run-submit/databricks.yml b/acceptance/air/run-submit/databricks.yml similarity index 100% rename from acceptance/experimental/air/run-submit/databricks.yml rename to acceptance/air/run-submit/databricks.yml diff --git a/acceptance/experimental/air/run-submit/out.test.toml b/acceptance/air/run-submit/out.test.toml similarity index 100% rename from acceptance/experimental/air/run-submit/out.test.toml rename to acceptance/air/run-submit/out.test.toml diff --git a/acceptance/experimental/air/run-submit/output.txt b/acceptance/air/run-submit/output.txt similarity index 96% rename from acceptance/experimental/air/run-submit/output.txt rename to acceptance/air/run-submit/output.txt index c20c8467f1e..d73877599d6 100644 --- a/acceptance/experimental/air/run-submit/output.txt +++ b/acceptance/air/run-submit/output.txt @@ -1,6 +1,6 @@ === submit with a git code_source ->>> [CLI] experimental air run -f run.yaml +>>> [CLI] air run -f run.yaml Submitting experiment: submit-smoke Uploading [SNAPSHOT_TARBALL]... Submitted workload with Job Run ID: 555 @@ -8,7 +8,7 @@ View job run at: [DATABRICKS_URL]/jobs/runs/555 Tip: use --watch when submitting a run to stream logs to your terminal. Stream logs after submission using: - databricks experimental air logs 555 + databricks air logs 555 === the ai_runtime_task and additive job permission grants >>> print_requests.py --get //api/2.2/jobs/runs/submit //api/2.2/jobs/runs/get //api/2.0/permissions //api/2.0/mlflow --sort --unique diff --git a/acceptance/experimental/air/run-submit/run.yaml.tmpl b/acceptance/air/run-submit/run.yaml.tmpl similarity index 100% rename from acceptance/experimental/air/run-submit/run.yaml.tmpl rename to acceptance/air/run-submit/run.yaml.tmpl diff --git a/acceptance/experimental/air/run-submit/script b/acceptance/air/run-submit/script similarity index 95% rename from acceptance/experimental/air/run-submit/script rename to acceptance/air/run-submit/script index 26161d63ad4..a8f40bb22a2 100644 --- a/acceptance/experimental/air/run-submit/script +++ b/acceptance/air/run-submit/script @@ -10,7 +10,7 @@ git-repo-init sed "s/COMMIT_SHA/$(git rev-parse HEAD)/" run.yaml.tmpl > run.yaml title "submit with a git code_source" -trace $CLI experimental air run -f run.yaml +trace $CLI air run -f run.yaml title "the ai_runtime_task and additive job permission grants" # Include MLflow paths so an accidental experiment request appears in the golden output. diff --git a/acceptance/experimental/air/run-submit/test.toml b/acceptance/air/run-submit/test.toml similarity index 100% rename from acceptance/experimental/air/run-submit/test.toml rename to acceptance/air/run-submit/test.toml diff --git a/acceptance/experimental/air/run/git-remote.yaml b/acceptance/air/run/git-remote.yaml similarity index 100% rename from acceptance/experimental/air/run/git-remote.yaml rename to acceptance/air/run/git-remote.yaml diff --git a/acceptance/experimental/air/run/invalid.yaml b/acceptance/air/run/invalid.yaml similarity index 100% rename from acceptance/experimental/air/run/invalid.yaml rename to acceptance/air/run/invalid.yaml diff --git a/acceptance/experimental/air/run/out.test.toml b/acceptance/air/run/out.test.toml similarity index 100% rename from acceptance/experimental/air/run/out.test.toml rename to acceptance/air/run/out.test.toml diff --git a/acceptance/experimental/air/run/output.txt b/acceptance/air/run/output.txt similarity index 68% rename from acceptance/experimental/air/run/output.txt rename to acceptance/air/run/output.txt index de25a42433d..5231733b66d 100644 --- a/acceptance/experimental/air/run/output.txt +++ b/acceptance/air/run/output.txt @@ -1,10 +1,10 @@ === dry-run (text) ->>> [CLI] experimental air run -f valid.yaml --dry-run +>>> [CLI] air run -f valid.yaml --dry-run Dry run: configuration for "smoke-test" is valid; not submitting. === dry-run (json) ->>> [CLI] experimental air run -f valid.yaml --dry-run -o json +>>> [CLI] air run -f valid.yaml --dry-run -o json { "v": 1, "ts": "[TIMESTAMP]", @@ -15,58 +15,63 @@ Dry run: configuration for "smoke-test" is valid; not submitting. } === override applies and logs the change ->>> [CLI] experimental air run -f valid.yaml --dry-run --override compute.num_accelerators=2 --override timeout_minutes=45 +>>> [CLI] air run -f valid.yaml --dry-run --override compute.num_accelerators=2 --override timeout_minutes=45 Override: changing compute.num_accelerators from 1 to 2 Override: setting timeout_minutes to 45 Dry run: configuration for "smoke-test" is valid; not submitting. === override of an unknown field is rejected ->>> [CLI] experimental air run -f valid.yaml --dry-run --override bogus=1 +>>> [CLI] air run -f valid.yaml --dry-run --override bogus=1 Error: invalid --override "bogus": "bogus" is not a known field; available fields are: code_source, command, compute, env_variables, environment, experiment_name, idempotency_token, max_retries, mlflow_artifact_location, mlflow_experiment_directory, mlflow_run_name, parameters, permissions, secrets, timeout_minutes, usage_policy_id, usage_policy_name Tip: use the --debug flag to see more details and a trace of this error: - databricks --debug experimental air run … + databricks --debug air run … Exit code: 1 === override still runs schema validation ->>> [CLI] experimental air run -f valid.yaml --dry-run --override compute.num_accelerators=0 +>>> [CLI] air run -f valid.yaml --dry-run --override compute.num_accelerators=0 Override: changing compute.num_accelerators from 1 to 0 Error: compute.num_accelerators must be positive, got 0 Tip: use the --debug flag to see more details and a trace of this error: - databricks --debug experimental air run … + databricks --debug air run … Exit code: 1 === watch is ignored with dry-run (nothing is submitted) ->>> [CLI] experimental air run -f valid.yaml --dry-run --watch +>>> [CLI] air run -f valid.yaml --dry-run --watch Dry run: configuration for "smoke-test" is valid; not submitting. === code_source config passes validation ->>> [CLI] experimental air run -f with-code-source.yaml --dry-run +>>> [CLI] air run -f with-code-source.yaml --dry-run Dry run: configuration for "smoke-test" is valid; not submitting. === git.remote is rejected ->>> [CLI] experimental air run -f git-remote.yaml --dry-run +>>> [CLI] air run -f git-remote.yaml --dry-run Error: git.remote is no longer supported: the snapshot archives your local copy, so a branch resolves to its local HEAD. To deploy a specific committed revision, use git.commit Tip: use the --debug flag to see more details and a trace of this error: - databricks --debug experimental air run … + databricks --debug air run … Exit code: 1 === invalid config is rejected ->>> [CLI] experimental air run -f invalid.yaml --dry-run +>>> [CLI] air run -f invalid.yaml --dry-run Error: invalid experiment_name "bad.name": only alphanumeric characters, hyphens (-), and underscores (_) are allowed Tip: use the --debug flag to see more details and a trace of this error: - databricks --debug experimental air run … + databricks --debug air run … Exit code: 1 === missing --file ->>> [CLI] experimental air run --dry-run +>>> [CLI] air run --dry-run Error: required flag(s) "file" not set Exit code: 1 + +=== deprecated experimental alias still runs +>>> [CLI] experimental air run -f valid.yaml --dry-run +Command "run" is deprecated, use "databricks air run" instead; this experimental alias will be removed in a future release +Dry run: configuration for "smoke-test" is valid; not submitting. diff --git a/acceptance/air/run/script b/acceptance/air/run/script new file mode 100644 index 00000000000..88cf037ae44 --- /dev/null +++ b/acceptance/air/run/script @@ -0,0 +1,32 @@ +title "dry-run (text)" +trace $CLI air run -f valid.yaml --dry-run + +title "dry-run (json)" +trace $CLI air run -f valid.yaml --dry-run -o json + +title "override applies and logs the change" +trace $CLI air run -f valid.yaml --dry-run --override compute.num_accelerators=2 --override timeout_minutes=45 + +title "override of an unknown field is rejected" +errcode trace $CLI air run -f valid.yaml --dry-run --override bogus=1 + +title "override still runs schema validation" +errcode trace $CLI air run -f valid.yaml --dry-run --override compute.num_accelerators=0 + +title "watch is ignored with dry-run (nothing is submitted)" +trace $CLI air run -f valid.yaml --dry-run --watch + +title "code_source config passes validation" +trace $CLI air run -f with-code-source.yaml --dry-run + +title "git.remote is rejected" +errcode trace $CLI air run -f git-remote.yaml --dry-run + +title "invalid config is rejected" +errcode trace $CLI air run -f invalid.yaml --dry-run + +title "missing --file" +errcode trace $CLI air run --dry-run + +title "deprecated experimental alias still runs" +trace $CLI experimental air run -f valid.yaml --dry-run diff --git a/acceptance/experimental/air/run/valid.yaml b/acceptance/air/run/valid.yaml similarity index 100% rename from acceptance/experimental/air/run/valid.yaml rename to acceptance/air/run/valid.yaml diff --git a/acceptance/experimental/air/run/with-code-source.yaml b/acceptance/air/run/with-code-source.yaml similarity index 100% rename from acceptance/experimental/air/run/with-code-source.yaml rename to acceptance/air/run/with-code-source.yaml diff --git a/acceptance/experimental/air/test.toml b/acceptance/air/test.toml similarity index 100% rename from acceptance/experimental/air/test.toml rename to acceptance/air/test.toml diff --git a/acceptance/experimental/air/cancel/script b/acceptance/experimental/air/cancel/script deleted file mode 100644 index ce04a8977fd..00000000000 --- a/acceptance/experimental/air/cancel/script +++ /dev/null @@ -1,11 +0,0 @@ -title "cancel by id (text)" -trace $CLI experimental air cancel 123 - -title "cancel by id (json)" -trace $CLI experimental air cancel 123 -o json - -title "cancel multiple ids" -trace $CLI experimental air cancel 123 456 - -title "cancel --all" -trace $CLI experimental air cancel --all -y diff --git a/acceptance/experimental/air/config-help/script b/acceptance/experimental/air/config-help/script deleted file mode 100644 index dd171f9218f..00000000000 --- a/acceptance/experimental/air/config-help/script +++ /dev/null @@ -1,41 +0,0 @@ -# Pin the rendered config field help. Any change to a `help:` struct tag on the -# run YAML schema shows up as a diff here. - -# Plain -h must keep documenting the command itself, and advertise the config -# path syntax so the feature is discoverable. -title "command help" -trace $CLI experimental air run --help - -title "schema overview" -trace $CLI experimental air run -h config - -title "nested object lists its fields" -trace $CLI experimental air run -h config.compute - -title "new submission fields are documented" -trace $CLI experimental air run -h config.mlflow_artifact_location -trace $CLI experimental air run -h config.compute.pool_id -trace $CLI experimental air run -h config.compute.priority_class -trace $CLI experimental air run -h config.environment.dependencies -trace $CLI experimental air run -h config.environment.version - -title "leaf field" -trace $CLI experimental air run -h config.compute.accelerator_type - -title "conditionally required leaf" -trace $CLI experimental air run -h config.code_source.type - -title "union field reports both accepted shapes" -trace $CLI experimental air run -h config.code_source.snapshot.git.remote - -title "git-pinned subdirectory snapshots document root_path scoping" -trace $CLI experimental air run -h config.code_source.snapshot.root_path - -title "the config. prefix is optional" -trace $CLI experimental air run -h compute.num_accelerators - -title "unknown field suggests the near match" -trace $CLI experimental air run -h config.compute.acclerator_type - -title "free-form map keys are not schema fields" -trace $CLI experimental air run -h config.parameters.learning_rate diff --git a/acceptance/experimental/air/get/script b/acceptance/experimental/air/get/script deleted file mode 100644 index ee66b4aff04..00000000000 --- a/acceptance/experimental/air/get/script +++ /dev/null @@ -1,11 +0,0 @@ -title "get (text)" -trace $CLI experimental air get 123 - -title "get (json)" -trace $CLI experimental air get 123 -o json - -title "invalid run id" -errcode trace $CLI experimental air get notanumber - -title "invalid run id (json)" -errcode trace $CLI experimental air get notanumber -o json diff --git a/acceptance/experimental/air/list/script b/acceptance/experimental/air/list/script deleted file mode 100644 index df547794c6f..00000000000 --- a/acceptance/experimental/air/list/script +++ /dev/null @@ -1,11 +0,0 @@ -title "list (text)" -trace $CLI experimental air list - -title "list (json)" -trace $CLI experimental air list -o json - -title "list --all-status (text, via AiTrainingService index)" -trace $CLI experimental air list --all-status - -title "list --all-status (json)" -trace $CLI experimental air list --all-status -o json diff --git a/acceptance/experimental/air/logs/script b/acceptance/experimental/air/logs/script deleted file mode 100644 index 3aceb1892d3..00000000000 --- a/acceptance/experimental/air/logs/script +++ /dev/null @@ -1,29 +0,0 @@ -title "logs (text, completed run)" -trace $CLI experimental air logs 123 - -title "logs (json)" -trace $CLI experimental air logs 123 -o json - -title "logs with --minutes" -trace $CLI experimental air logs 123 --minutes 30 - -title "logs with --tail" -trace $CLI experimental air logs 123 --tail 1 - -title "logs with --tail 0 is rejected" -errcode trace $CLI experimental air logs 123 --tail 0 - -title "logs from a specific retry" -trace $CLI experimental air logs 123 --retry 0 - -title "logs --tail and --minutes are mutually exclusive" -errcode trace $CLI experimental air logs 123 --tail 100 --minutes 30 - -title "logs --tail and --minutes are mutually exclusive (json)" -errcode trace $CLI experimental air logs 123 --tail 100 --minutes 30 -o json - -title "invalid run id" -errcode trace $CLI experimental air logs notanumber - -title "negative node" -errcode trace $CLI experimental air logs 123 --node -1 diff --git a/acceptance/experimental/air/pools/script b/acceptance/experimental/air/pools/script deleted file mode 100644 index f7424db52ae..00000000000 --- a/acceptance/experimental/air/pools/script +++ /dev/null @@ -1,11 +0,0 @@ -title "list pools (text)" -trace $CLI experimental air list pools - -title "list pools (json)" -trace $CLI experimental air list pools -o json - -title "get pool (text)" -trace $CLI experimental air get pool pool-8xh100-alpha - -title "get pool (json)" -trace $CLI experimental air get pool pool-8xh100-alpha -o json diff --git a/acceptance/experimental/air/run/script b/acceptance/experimental/air/run/script deleted file mode 100644 index 2a5263bceb2..00000000000 --- a/acceptance/experimental/air/run/script +++ /dev/null @@ -1,29 +0,0 @@ -title "dry-run (text)" -trace $CLI experimental air run -f valid.yaml --dry-run - -title "dry-run (json)" -trace $CLI experimental air run -f valid.yaml --dry-run -o json - -title "override applies and logs the change" -trace $CLI experimental air run -f valid.yaml --dry-run --override compute.num_accelerators=2 --override timeout_minutes=45 - -title "override of an unknown field is rejected" -errcode trace $CLI experimental air run -f valid.yaml --dry-run --override bogus=1 - -title "override still runs schema validation" -errcode trace $CLI experimental air run -f valid.yaml --dry-run --override compute.num_accelerators=0 - -title "watch is ignored with dry-run (nothing is submitted)" -trace $CLI experimental air run -f valid.yaml --dry-run --watch - -title "code_source config passes validation" -trace $CLI experimental air run -f with-code-source.yaml --dry-run - -title "git.remote is rejected" -errcode trace $CLI experimental air run -f git-remote.yaml --dry-run - -title "invalid config is rejected" -errcode trace $CLI experimental air run -f invalid.yaml --dry-run - -title "missing --file" -errcode trace $CLI experimental air run --dry-run diff --git a/acceptance/help/output.txt b/acceptance/help/output.txt index bcc21702547..d572b4c32a3 100644 --- a/acceptance/help/output.txt +++ b/acceptance/help/output.txt @@ -183,6 +183,7 @@ Developer Tools Additional Commands: account Databricks Account Commands + air Run and manage AI Runtime training workloads aitools Databricks skills and plugins for coding agents api Perform Databricks API call auth Authentication related commands diff --git a/experimental/air/.gitkeep b/cmd/air/.gitkeep similarity index 100% rename from experimental/air/.gitkeep rename to cmd/air/.gitkeep diff --git a/experimental/air/cmd/air.go b/cmd/air/air.go similarity index 76% rename from experimental/air/cmd/air.go rename to cmd/air/air.go index de42677a6a4..7149b108f26 100644 --- a/experimental/air/cmd/air.go +++ b/cmd/air/air.go @@ -7,15 +7,12 @@ import ( "github.com/spf13/cobra" ) -// New returns the root command for the experimental AI runtime CLI. +// New returns the root command for the AI Runtime CLI. func New() *cobra.Command { cmd := &cobra.Command{ Use: "air", - Short: "Run and manage AI runtime training workloads", - Long: `Run and manage AI runtime training workloads on Databricks serverless GPU compute. - -This command set is the Go port of the standalone Python "air" CLI. It is -experimental and may change in future versions.`, + Short: "Run and manage AI Runtime training workloads", + Long: "Run and manage AI Runtime training workloads on Databricks serverless GPU compute.", } runCommand := newRunCommand() diff --git a/experimental/air/cmd/air_test.go b/cmd/air/air_test.go similarity index 89% rename from experimental/air/cmd/air_test.go rename to cmd/air/air_test.go index fe602693b7d..016dc0af079 100644 --- a/experimental/air/cmd/air_test.go +++ b/cmd/air/air_test.go @@ -34,17 +34,15 @@ func TestRunErrorIncludesDebugTip(t *testing.T) { airCommand := &cobra.Command{Use: "air"} airCommand.AddCommand(runCommand) wrapRunErrorWithDebugTip(runCommand) - experimentalCommand := &cobra.Command{Use: "experimental"} - experimentalCommand.AddCommand(airCommand) rootCommand := &cobra.Command{Use: "databricks"} rootCommand.PersistentFlags().Bool("debug", false, "") - rootCommand.AddCommand(experimentalCommand) + rootCommand.AddCommand(airCommand) err := runCommand.RunE(runCommand, []string{"secret-value"}) assert.ErrorIs(t, err, originalErr) assert.Contains(t, err.Error(), "use the --debug flag") - assert.Contains(t, err.Error(), "databricks --debug experimental air run …") + assert.Contains(t, err.Error(), "databricks --debug air run …") assert.NotContains(t, err.Error(), "secret-value") } diff --git a/experimental/air/cmd/aitraining.go b/cmd/air/aitraining.go similarity index 100% rename from experimental/air/cmd/aitraining.go rename to cmd/air/aitraining.go diff --git a/experimental/air/cmd/aitraining_test.go b/cmd/air/aitraining_test.go similarity index 100% rename from experimental/air/cmd/aitraining_test.go rename to cmd/air/aitraining_test.go diff --git a/experimental/air/cmd/cancel.go b/cmd/air/cancel.go similarity index 100% rename from experimental/air/cmd/cancel.go rename to cmd/air/cancel.go diff --git a/experimental/air/cmd/cancel_test.go b/cmd/air/cancel_test.go similarity index 100% rename from experimental/air/cmd/cancel_test.go rename to cmd/air/cancel_test.go diff --git a/experimental/air/cmd/compute.go b/cmd/air/compute.go similarity index 100% rename from experimental/air/cmd/compute.go rename to cmd/air/compute.go diff --git a/experimental/air/cmd/compute_test.go b/cmd/air/compute_test.go similarity index 100% rename from experimental/air/cmd/compute_test.go rename to cmd/air/compute_test.go diff --git a/experimental/air/cmd/convert_to_dabs.go b/cmd/air/convert_to_dabs.go similarity index 100% rename from experimental/air/cmd/convert_to_dabs.go rename to cmd/air/convert_to_dabs.go diff --git a/experimental/air/cmd/convert_to_dabs_test.go b/cmd/air/convert_to_dabs_test.go similarity index 100% rename from experimental/air/cmd/convert_to_dabs_test.go rename to cmd/air/convert_to_dabs_test.go diff --git a/experimental/air/cmd/eta.go b/cmd/air/eta.go similarity index 100% rename from experimental/air/cmd/eta.go rename to cmd/air/eta.go diff --git a/experimental/air/cmd/eta_test.go b/cmd/air/eta_test.go similarity index 100% rename from experimental/air/cmd/eta_test.go rename to cmd/air/eta_test.go diff --git a/experimental/air/cmd/format.go b/cmd/air/format.go similarity index 100% rename from experimental/air/cmd/format.go rename to cmd/air/format.go diff --git a/experimental/air/cmd/format_test.go b/cmd/air/format_test.go similarity index 100% rename from experimental/air/cmd/format_test.go rename to cmd/air/format_test.go diff --git a/experimental/air/cmd/get.go b/cmd/air/get.go similarity index 100% rename from experimental/air/cmd/get.go rename to cmd/air/get.go diff --git a/experimental/air/cmd/get_test.go b/cmd/air/get_test.go similarity index 100% rename from experimental/air/cmd/get_test.go rename to cmd/air/get_test.go diff --git a/experimental/air/cmd/joblist.go b/cmd/air/joblist.go similarity index 100% rename from experimental/air/cmd/joblist.go rename to cmd/air/joblist.go diff --git a/experimental/air/cmd/joblist_test.go b/cmd/air/joblist_test.go similarity index 100% rename from experimental/air/cmd/joblist_test.go rename to cmd/air/joblist_test.go diff --git a/experimental/air/cmd/list.go b/cmd/air/list.go similarity index 100% rename from experimental/air/cmd/list.go rename to cmd/air/list.go diff --git a/experimental/air/cmd/list_cache.go b/cmd/air/list_cache.go similarity index 100% rename from experimental/air/cmd/list_cache.go rename to cmd/air/list_cache.go diff --git a/experimental/air/cmd/list_cache_test.go b/cmd/air/list_cache_test.go similarity index 100% rename from experimental/air/cmd/list_cache_test.go rename to cmd/air/list_cache_test.go diff --git a/experimental/air/cmd/list_detail.go b/cmd/air/list_detail.go similarity index 100% rename from experimental/air/cmd/list_detail.go rename to cmd/air/list_detail.go diff --git a/experimental/air/cmd/list_filter.go b/cmd/air/list_filter.go similarity index 100% rename from experimental/air/cmd/list_filter.go rename to cmd/air/list_filter.go diff --git a/experimental/air/cmd/list_filter_test.go b/cmd/air/list_filter_test.go similarity index 100% rename from experimental/air/cmd/list_filter_test.go rename to cmd/air/list_filter_test.go diff --git a/experimental/air/cmd/list_format.go b/cmd/air/list_format.go similarity index 100% rename from experimental/air/cmd/list_format.go rename to cmd/air/list_format.go diff --git a/experimental/air/cmd/list_index.go b/cmd/air/list_index.go similarity index 100% rename from experimental/air/cmd/list_index.go rename to cmd/air/list_index.go diff --git a/experimental/air/cmd/list_index_test.go b/cmd/air/list_index_test.go similarity index 100% rename from experimental/air/cmd/list_index_test.go rename to cmd/air/list_index_test.go diff --git a/experimental/air/cmd/list_test.go b/cmd/air/list_test.go similarity index 100% rename from experimental/air/cmd/list_test.go rename to cmd/air/list_test.go diff --git a/experimental/air/cmd/list_tui.go b/cmd/air/list_tui.go similarity index 100% rename from experimental/air/cmd/list_tui.go rename to cmd/air/list_tui.go diff --git a/experimental/air/cmd/list_tui_render.go b/cmd/air/list_tui_render.go similarity index 100% rename from experimental/air/cmd/list_tui_render.go rename to cmd/air/list_tui_render.go diff --git a/experimental/air/cmd/list_tui_test.go b/cmd/air/list_tui_test.go similarity index 100% rename from experimental/air/cmd/list_tui_test.go rename to cmd/air/list_tui_test.go diff --git a/experimental/air/cmd/logbricklens.go b/cmd/air/logbricklens.go similarity index 100% rename from experimental/air/cmd/logbricklens.go rename to cmd/air/logbricklens.go diff --git a/experimental/air/cmd/logbricklens_test.go b/cmd/air/logbricklens_test.go similarity index 100% rename from experimental/air/cmd/logbricklens_test.go rename to cmd/air/logbricklens_test.go diff --git a/experimental/air/cmd/logdetect.go b/cmd/air/logdetect.go similarity index 100% rename from experimental/air/cmd/logdetect.go rename to cmd/air/logdetect.go diff --git a/experimental/air/cmd/logdownload.go b/cmd/air/logdownload.go similarity index 100% rename from experimental/air/cmd/logdownload.go rename to cmd/air/logdownload.go diff --git a/experimental/air/cmd/logdownload_test.go b/cmd/air/logdownload_test.go similarity index 100% rename from experimental/air/cmd/logdownload_test.go rename to cmd/air/logdownload_test.go diff --git a/experimental/air/cmd/logmlflow.go b/cmd/air/logmlflow.go similarity index 100% rename from experimental/air/cmd/logmlflow.go rename to cmd/air/logmlflow.go diff --git a/experimental/air/cmd/logmlflow_test.go b/cmd/air/logmlflow_test.go similarity index 100% rename from experimental/air/cmd/logmlflow_test.go rename to cmd/air/logmlflow_test.go diff --git a/experimental/air/cmd/logs.go b/cmd/air/logs.go similarity index 100% rename from experimental/air/cmd/logs.go rename to cmd/air/logs.go diff --git a/experimental/air/cmd/logs_test.go b/cmd/air/logs_test.go similarity index 99% rename from experimental/air/cmd/logs_test.go rename to cmd/air/logs_test.go index 73d7645299b..abc289cacd7 100644 --- a/experimental/air/cmd/logs_test.go +++ b/cmd/air/logs_test.go @@ -231,8 +231,8 @@ func TestLogsCommandPrintsGuidanceWhenStreamingIsInterrupted(t *testing.T) { err := cmd.RunE(cmd, []string{"5"}) require.ErrorIs(t, err, root.ErrAlreadyPrinted) assert.Contains(t, buf.String(), "Streaming logs interrupted.") - assert.Contains(t, buf.String(), "To check status:\ndatabricks experimental air get 5 -p 'team profile'") - assert.Contains(t, buf.String(), "To resume streaming logs:\ndatabricks experimental air logs 5 -p 'team profile'") + assert.Contains(t, buf.String(), "To check status:\ndatabricks air get 5 -p 'team profile'") + assert.Contains(t, buf.String(), "To resume streaming logs:\ndatabricks air logs 5 -p 'team profile'") } // activeRunPastRetryServer serves a still-RUNNING run with two attempts and a diff --git a/experimental/air/cmd/logstream.go b/cmd/air/logstream.go similarity index 100% rename from experimental/air/cmd/logstream.go rename to cmd/air/logstream.go diff --git a/experimental/air/cmd/logstream_support.go b/cmd/air/logstream_support.go similarity index 100% rename from experimental/air/cmd/logstream_support.go rename to cmd/air/logstream_support.go diff --git a/experimental/air/cmd/logstream_test.go b/cmd/air/logstream_test.go similarity index 100% rename from experimental/air/cmd/logstream_test.go rename to cmd/air/logstream_test.go diff --git a/experimental/air/cmd/mlflow.go b/cmd/air/mlflow.go similarity index 100% rename from experimental/air/cmd/mlflow.go rename to cmd/air/mlflow.go diff --git a/experimental/air/cmd/mlflow_test.go b/cmd/air/mlflow_test.go similarity index 100% rename from experimental/air/cmd/mlflow_test.go rename to cmd/air/mlflow_test.go diff --git a/experimental/air/cmd/output.go b/cmd/air/output.go similarity index 100% rename from experimental/air/cmd/output.go rename to cmd/air/output.go diff --git a/experimental/air/cmd/output_test.go b/cmd/air/output_test.go similarity index 100% rename from experimental/air/cmd/output_test.go rename to cmd/air/output_test.go diff --git a/experimental/air/cmd/pools.go b/cmd/air/pools.go similarity index 100% rename from experimental/air/cmd/pools.go rename to cmd/air/pools.go diff --git a/experimental/air/cmd/pools_test.go b/cmd/air/pools_test.go similarity index 100% rename from experimental/air/cmd/pools_test.go rename to cmd/air/pools_test.go diff --git a/experimental/air/cmd/profile.go b/cmd/air/profile.go similarity index 100% rename from experimental/air/cmd/profile.go rename to cmd/air/profile.go diff --git a/experimental/air/cmd/profile_test.go b/cmd/air/profile_test.go similarity index 100% rename from experimental/air/cmd/profile_test.go rename to cmd/air/profile_test.go diff --git a/experimental/air/cmd/render.go b/cmd/air/render.go similarity index 100% rename from experimental/air/cmd/render.go rename to cmd/air/render.go diff --git a/experimental/air/cmd/render_test.go b/cmd/air/render_test.go similarity index 100% rename from experimental/air/cmd/render_test.go rename to cmd/air/render_test.go diff --git a/experimental/air/cmd/run.go b/cmd/air/run.go similarity index 96% rename from experimental/air/cmd/run.go rename to cmd/air/run.go index 45202a09b87..35a6e5f5556 100644 --- a/experimental/air/cmd/run.go +++ b/cmd/air/run.go @@ -47,9 +47,9 @@ The workload is described by a YAML config file (see --file). To look up a config field, pass its path to -h: - databricks experimental air run -h config - databricks experimental air run -h config.compute - databricks experimental air run -h config.compute.accelerator_type + databricks air run -h config + databricks air run -h config.compute + databricks air run -h config.compute.accelerator_type The path must be a separate argument: cobra reserves -h as a boolean, so -h=config.compute and -hconfig.compute are not accepted.`, @@ -187,7 +187,7 @@ The path must be a separate argument: cobra reserves -h as a boolean, so } func airLogsCommand(profile, runID string) string { - args := []string{"databricks", "experimental", "air", "logs", shellquote.BashArg(runID)} + args := []string{"databricks", "air", "logs", shellquote.BashArg(runID)} if profile != "" { args = append(args, "-p", shellquote.BashArg(profile)) } @@ -195,7 +195,7 @@ func airLogsCommand(profile, runID string) string { } func airGetCommand(profile, runID string) string { - args := []string{"databricks", "experimental", "air", "get", shellquote.BashArg(runID)} + args := []string{"databricks", "air", "get", shellquote.BashArg(runID)} if profile != "" { args = append(args, "-p", shellquote.BashArg(profile)) } diff --git a/experimental/air/cmd/run_signal_test.go b/cmd/air/run_signal_test.go similarity index 100% rename from experimental/air/cmd/run_signal_test.go rename to cmd/air/run_signal_test.go diff --git a/experimental/air/cmd/run_test.go b/cmd/air/run_test.go similarity index 82% rename from experimental/air/cmd/run_test.go rename to cmd/air/run_test.go index bb72c54f6e0..e573b684a84 100644 --- a/experimental/air/cmd/run_test.go +++ b/cmd/air/run_test.go @@ -77,7 +77,7 @@ func TestRunSubmitTextOutput(t *testing.T) { assert.Contains(t, out, "/jobs/runs/555") assert.Contains(t, out, "Tip: use --watch when submitting a run to stream logs to your terminal.") assert.Contains(t, out, "Stream logs after submission using:") - assert.Contains(t, out, "databricks experimental air logs 555") + assert.Contains(t, out, "databricks air logs 555") assert.NotContains(t, out, "View MLflow run at:") assert.Zero(t, counts.runGet.Load(), "bare submission must not poll runs/get") assert.Zero(t, counts.runGetOutput.Load(), "bare submission must not poll runs/get-output") @@ -89,19 +89,19 @@ func TestRunSubmitTextOutputIncludesProfileInLogsCommand(t *testing.T) { err := runSubmitCmdWithProfile(t, flags.OutputText, &buf, srv.URL, "team profile") require.NoError(t, err) - assert.Contains(t, buf.String(), "databricks experimental air logs 555 -p 'team profile'") + assert.Contains(t, buf.String(), "databricks air logs 555 -p 'team profile'") } func TestAirLogsCommand(t *testing.T) { - assert.Equal(t, "databricks experimental air logs 123", airLogsCommand("", "123")) - assert.Equal(t, "databricks experimental air logs 123 -p profile-name", airLogsCommand("profile-name", "123")) - assert.Equal(t, "databricks experimental air logs 123 -p 'team profile'", airLogsCommand("team profile", "123")) + assert.Equal(t, "databricks air logs 123", airLogsCommand("", "123")) + assert.Equal(t, "databricks air logs 123 -p profile-name", airLogsCommand("profile-name", "123")) + assert.Equal(t, "databricks air logs 123 -p 'team profile'", airLogsCommand("team profile", "123")) } func TestAirGetCommand(t *testing.T) { - assert.Equal(t, "databricks experimental air get 123", airGetCommand("", "123")) - assert.Equal(t, "databricks experimental air get 123 -p profile-name", airGetCommand("profile-name", "123")) - assert.Equal(t, "databricks experimental air get 123 -p 'team profile'", airGetCommand("team profile", "123")) + assert.Equal(t, "databricks air get 123", airGetCommand("", "123")) + assert.Equal(t, "databricks air get 123 -p profile-name", airGetCommand("profile-name", "123")) + assert.Equal(t, "databricks air get 123 -p 'team profile'", airGetCommand("team profile", "123")) } func TestRunSubmitJSONStatusPending(t *testing.T) { diff --git a/experimental/air/cmd/run_watch_test.go b/cmd/air/run_watch_test.go similarity index 98% rename from experimental/air/cmd/run_watch_test.go rename to cmd/air/run_watch_test.go index 3cf30055617..bf0d2c0d10c 100644 --- a/experimental/air/cmd/run_watch_test.go +++ b/cmd/air/run_watch_test.go @@ -191,8 +191,8 @@ func TestHandleWatchResultPrintsProfileAwareResumeCommand(t *testing.T) { out := buf.String() assert.Contains(t, out, "Streaming logs interrupted.") - assert.Contains(t, out, "To check status:\ndatabricks experimental air get 777 -p 'team profile'") - assert.Contains(t, out, "To resume streaming logs:\ndatabricks experimental air logs 777 -p 'team profile'") + assert.Contains(t, out, "To check status:\ndatabricks air get 777 -p 'team profile'") + assert.Contains(t, out, "To resume streaming logs:\ndatabricks air logs 777 -p 'team profile'") assert.NotContains(t, out, "The workload was not canceled") } diff --git a/experimental/air/cmd/runconfig.go b/cmd/air/runconfig.go similarity index 100% rename from experimental/air/cmd/runconfig.go rename to cmd/air/runconfig.go diff --git a/experimental/air/cmd/runconfig_launch.go b/cmd/air/runconfig_launch.go similarity index 100% rename from experimental/air/cmd/runconfig_launch.go rename to cmd/air/runconfig_launch.go diff --git a/experimental/air/cmd/runconfig_launch_test.go b/cmd/air/runconfig_launch_test.go similarity index 100% rename from experimental/air/cmd/runconfig_launch_test.go rename to cmd/air/runconfig_launch_test.go diff --git a/experimental/air/cmd/runconfig_load.go b/cmd/air/runconfig_load.go similarity index 100% rename from experimental/air/cmd/runconfig_load.go rename to cmd/air/runconfig_load.go diff --git a/experimental/air/cmd/runconfig_override.go b/cmd/air/runconfig_override.go similarity index 100% rename from experimental/air/cmd/runconfig_override.go rename to cmd/air/runconfig_override.go diff --git a/experimental/air/cmd/runconfig_override_test.go b/cmd/air/runconfig_override_test.go similarity index 100% rename from experimental/air/cmd/runconfig_override_test.go rename to cmd/air/runconfig_override_test.go diff --git a/experimental/air/cmd/runconfig_test.go b/cmd/air/runconfig_test.go similarity index 100% rename from experimental/air/cmd/runconfig_test.go rename to cmd/air/runconfig_test.go diff --git a/experimental/air/cmd/runlaunch.go b/cmd/air/runlaunch.go similarity index 100% rename from experimental/air/cmd/runlaunch.go rename to cmd/air/runlaunch.go diff --git a/experimental/air/cmd/runlaunch_test.go b/cmd/air/runlaunch_test.go similarity index 100% rename from experimental/air/cmd/runlaunch_test.go rename to cmd/air/runlaunch_test.go diff --git a/experimental/air/cmd/runpermissions.go b/cmd/air/runpermissions.go similarity index 100% rename from experimental/air/cmd/runpermissions.go rename to cmd/air/runpermissions.go diff --git a/experimental/air/cmd/runpermissions_test.go b/cmd/air/runpermissions_test.go similarity index 100% rename from experimental/air/cmd/runpermissions_test.go rename to cmd/air/runpermissions_test.go diff --git a/experimental/air/cmd/runsubmit.go b/cmd/air/runsubmit.go similarity index 100% rename from experimental/air/cmd/runsubmit.go rename to cmd/air/runsubmit.go diff --git a/experimental/air/cmd/runsubmit_test.go b/cmd/air/runsubmit_test.go similarity index 99% rename from experimental/air/cmd/runsubmit_test.go rename to cmd/air/runsubmit_test.go index ba10c1b61dd..c4e9690ed60 100644 --- a/experimental/air/cmd/runsubmit_test.go +++ b/cmd/air/runsubmit_test.go @@ -357,7 +357,9 @@ func TestSubmitWorkload(t *testing.T) { d := at.Deployments[0] assert.True(t, strings.HasSuffix(d.CommandPath, "/"+commandScriptName), d.CommandPath) assert.Contains(t, d.CommandPath, "/.air/cli_launch/") - assert.Equal(t, jobs.ComputeSpec{AcceleratorType: jobs.ComputeSpecAcceleratorTypeGpu1xH100, AcceleratorCount: 1}, d.Compute) + assert.Equal(t, jobs.ComputeSpecAcceleratorTypeGpu1xH100, d.Compute.AcceleratorType) + assert.Equal(t, 1, d.Compute.AcceleratorCount) + assert.Empty(t, d.Compute.ProvisionedCapacityId) } func TestSubmitWorkloadStagingErrorPreventsSubmit(t *testing.T) { diff --git a/experimental/air/cmd/runupload.go b/cmd/air/runupload.go similarity index 100% rename from experimental/air/cmd/runupload.go rename to cmd/air/runupload.go diff --git a/experimental/air/cmd/runupload_test.go b/cmd/air/runupload_test.go similarity index 100% rename from experimental/air/cmd/runupload_test.go rename to cmd/air/runupload_test.go diff --git a/experimental/air/cmd/snapshot.go b/cmd/air/snapshot.go similarity index 100% rename from experimental/air/cmd/snapshot.go rename to cmd/air/snapshot.go diff --git a/experimental/air/cmd/snapshot_cachekey.go b/cmd/air/snapshot_cachekey.go similarity index 100% rename from experimental/air/cmd/snapshot_cachekey.go rename to cmd/air/snapshot_cachekey.go diff --git a/experimental/air/cmd/snapshot_cachekey_test.go b/cmd/air/snapshot_cachekey_test.go similarity index 100% rename from experimental/air/cmd/snapshot_cachekey_test.go rename to cmd/air/snapshot_cachekey_test.go diff --git a/experimental/air/cmd/snapshot_dabs.go b/cmd/air/snapshot_dabs.go similarity index 100% rename from experimental/air/cmd/snapshot_dabs.go rename to cmd/air/snapshot_dabs.go diff --git a/experimental/air/cmd/snapshot_git.go b/cmd/air/snapshot_git.go similarity index 100% rename from experimental/air/cmd/snapshot_git.go rename to cmd/air/snapshot_git.go diff --git a/experimental/air/cmd/snapshot_git_test.go b/cmd/air/snapshot_git_test.go similarity index 98% rename from experimental/air/cmd/snapshot_git_test.go rename to cmd/air/snapshot_git_test.go index 7096e5ad0b0..a208b4ef83f 100644 --- a/experimental/air/cmd/snapshot_git_test.go +++ b/cmd/air/snapshot_git_test.go @@ -82,7 +82,11 @@ func TestGitRepo_RepositoryLayout(t *testing.T) { root, err := g.repositoryRoot(ctx) require.NoError(t, err) - assert.Equal(t, repo, root) + expected, err := os.Stat(repo) + require.NoError(t, err) + actual, err := os.Stat(root) + require.NoError(t, err) + assert.True(t, os.SameFile(expected, actual)) writeRepoFile(t, repo, " leading-space/train.py", "print()") prefix, err = newGitRepo(filepath.Join(repo, " leading-space")).repoRelativePrefix(ctx) diff --git a/experimental/air/cmd/snapshot_package.go b/cmd/air/snapshot_package.go similarity index 100% rename from experimental/air/cmd/snapshot_package.go rename to cmd/air/snapshot_package.go diff --git a/experimental/air/cmd/snapshot_package_test.go b/cmd/air/snapshot_package_test.go similarity index 100% rename from experimental/air/cmd/snapshot_package_test.go rename to cmd/air/snapshot_package_test.go diff --git a/experimental/air/cmd/snapshot_resolve.go b/cmd/air/snapshot_resolve.go similarity index 100% rename from experimental/air/cmd/snapshot_resolve.go rename to cmd/air/snapshot_resolve.go diff --git a/experimental/air/cmd/snapshot_resolve_test.go b/cmd/air/snapshot_resolve_test.go similarity index 100% rename from experimental/air/cmd/snapshot_resolve_test.go rename to cmd/air/snapshot_resolve_test.go diff --git a/experimental/air/cmd/sweep.go b/cmd/air/sweep.go similarity index 100% rename from experimental/air/cmd/sweep.go rename to cmd/air/sweep.go diff --git a/experimental/air/cmd/sweep_test.go b/cmd/air/sweep_test.go similarity index 100% rename from experimental/air/cmd/sweep_test.go rename to cmd/air/sweep_test.go diff --git a/experimental/air/cmd/testdata/cache_keys.json b/cmd/air/testdata/cache_keys.json similarity index 100% rename from experimental/air/cmd/testdata/cache_keys.json rename to cmd/air/testdata/cache_keys.json diff --git a/experimental/air/cmd/usagepolicy.go b/cmd/air/usagepolicy.go similarity index 100% rename from experimental/air/cmd/usagepolicy.go rename to cmd/air/usagepolicy.go diff --git a/experimental/air/cmd/usagepolicy_test.go b/cmd/air/usagepolicy_test.go similarity index 100% rename from experimental/air/cmd/usagepolicy_test.go rename to cmd/air/usagepolicy_test.go diff --git a/experimental/air/cmd/validateconfig.go b/cmd/air/validateconfig.go similarity index 100% rename from experimental/air/cmd/validateconfig.go rename to cmd/air/validateconfig.go diff --git a/experimental/air/cmd/validateconfig_test.go b/cmd/air/validateconfig_test.go similarity index 100% rename from experimental/air/cmd/validateconfig_test.go rename to cmd/air/validateconfig_test.go diff --git a/cmd/cmd.go b/cmd/cmd.go index a2c3280b940..7888af65068 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -4,6 +4,7 @@ import ( "context" "strings" + aircmd "github.com/databricks/cli/cmd/air" aitoolscmd "github.com/databricks/cli/cmd/aitools" "github.com/databricks/cli/cmd/psql" ssh "github.com/databricks/cli/experimental/ssh/cmd" @@ -105,6 +106,7 @@ func New(ctx context.Context) *cobra.Command { } // Add other subcommands. + cli.AddCommand(aircmd.New()) cli.AddCommand(aitoolscmd.NewAitoolsCmd()) cli.AddCommand(api.New()) cli.AddCommand(auth.New()) diff --git a/cmd/experimental/air.go b/cmd/experimental/air.go new file mode 100644 index 00000000000..a4731f03fdb --- /dev/null +++ b/cmd/experimental/air.go @@ -0,0 +1,21 @@ +package experimental + +import ( + "fmt" + + aircmd "github.com/databricks/cli/cmd/air" + "github.com/spf13/cobra" +) + +func newAirCmd() *cobra.Command { + cmd := aircmd.New() + deprecateAirCommand(cmd, "databricks air") + return cmd +} + +func deprecateAirCommand(cmd *cobra.Command, replacement string) { + cmd.Deprecated = fmt.Sprintf(`use %q instead; this experimental alias will be removed in a future release`, replacement) + for _, child := range cmd.Commands() { + deprecateAirCommand(child, replacement+" "+child.Name()) + } +} diff --git a/cmd/experimental/air_test.go b/cmd/experimental/air_test.go new file mode 100644 index 00000000000..6bc0489142c --- /dev/null +++ b/cmd/experimental/air_test.go @@ -0,0 +1,27 @@ +package experimental + +import ( + "testing" + + aircmd "github.com/databricks/cli/cmd/air" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDeprecatedAirCommandMatchesStableCommand(t *testing.T) { + assertDeprecatedAirTree(t, aircmd.New(), newAirCmd()) +} + +func assertDeprecatedAirTree(t *testing.T, stable, deprecated *cobra.Command) { + t.Helper() + require.Equal(t, stable.Name(), deprecated.Name()) + assert.Contains(t, deprecated.Deprecated, `use "databricks `+stable.CommandPath()+`" instead`) + + stableChildren := stable.Commands() + deprecatedChildren := deprecated.Commands() + require.Len(t, deprecatedChildren, len(stableChildren)) + for i := range stableChildren { + assertDeprecatedAirTree(t, stableChildren[i], deprecatedChildren[i]) + } +} diff --git a/cmd/experimental/experimental.go b/cmd/experimental/experimental.go index 7dec16256de..a36ba0d718f 100644 --- a/cmd/experimental/experimental.go +++ b/cmd/experimental/experimental.go @@ -1,7 +1,6 @@ package experimental import ( - aircmd "github.com/databricks/cli/experimental/air/cmd" aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd" postgrescmd "github.com/databricks/cli/experimental/postgres/cmd" "github.com/spf13/cobra" @@ -22,7 +21,7 @@ These commands provide early access to new features that are still under development. They may change or be removed in future versions without notice.`, } - cmd.AddCommand(aircmd.New()) + cmd.AddCommand(newAirCmd()) cmd.AddCommand(aitoolscmd.NewAitoolsCmd()) cmd.AddCommand(newGenieCmd()) cmd.AddCommand(postgrescmd.New())