Skip to content

Add JobTaskClusterSpec validate mutator - #1784

Merged
pietern merged 6 commits into
databricks:mainfrom
kanterov:kanterov/cluster-spec-validation
Sep 25, 2024
Merged

Add JobTaskClusterSpec validate mutator#1784
pietern merged 6 commits into
databricks:mainfrom
kanterov:kanterov/cluster-spec-validation

Conversation

@kanterov

@kanterovkanterov commented Sep 23, 2024

Copy link
Copy Markdown
Collaborator

Changes

Add JobTaskClusterSpec validate mutator. It catches the case when tasks don't which cluster to use.

For example, we can get this error with minor modifications to default-python template:

tasks:
- task_key: python_file_taskspark_python_task:
python_file: ../src/my_project_10/main.py
 % databricks bundle validate
Error: Missing required cluster or environment settings
at resources.jobs.my_project_10_job.tasks[0]
in resources/my_project_10_job.yml:17:11
Task "print_github_stars" requires a cluster or an environment to run.
Specify one of the following fields: job_cluster_key, environment_key, existing_cluster_id, new_cluster.

We implicitly rely on "one of" validation, which does not exist. Many bundle fields can't co-exist, for instance, specifying: JobTask.{existing_cluster_id,job_cluster_key}, Library.{whl,pypi}, JobTask.{notebook_task,python_wheel_task}, etc.

Tests

Unit tests

Comment threadbundle/config/validate/job_task_cluster_spec.go

diags = diags.Extend(validateJobTask(rb, task, taskPath))
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This mixes access to the typed configuration with dyn.Value access.

Any chance we can just use the dyn.Value one?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I can change it. I think it's easier to implement and test validations using typed configuration though. The only problematic part is constructing path to a property.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What I was thinking is you can use dyn.MapByPattern to find all tasks across all jobs (and you get the right base path), and then use convert.ToTyped to get the typed jobs.Task value.

@pieternpietern left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The code LGTM, but not sure about the classic/serverless ambiguity in the errors.

Comment threadbundle/config/validate/job_task_cluster_spec.go
TaskKey: "my_task",
},
errorPath: "resources.jobs.job1.tasks[0]",
errorDetail: "Task \"my_task\" has a task type that requires a cluster, but no cluster is specified",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What I find tricky (and counterintuitive) is that the error detail talks about a cluster, but the user's underlying intent may be to use serverless and an environment_key.

How can we surface this ambiguity in the error/warning? E.g. an and/or?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

The error summary string contains one of possible attributes to set:

Error: One of the following fields must be set: job_cluster_key, environment_key, existing_cluster_id, new_cluster
at resources.jobs.my_project_10_job.tasks[0]
in resources/my_project_10_job.yml:17:11
Task "python_file_task" uses a task type that requires a cluster

I can change the wording to:

Task "my_task" has a task type that requires a cluster or environment, but neither is specified.


diags = diags.Extend(validateJobTask(rb, task, taskPath))
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What I was thinking is you can use dyn.MapByPattern to find all tasks across all jobs (and you get the right base path), and then use convert.ToTyped to get the typed jobs.Task value.

@kanterov

Copy link
Copy Markdown
CollaboratorAuthor

@pietern I've updated error/warning messages and added more comments as you suggested. I assume that the convert.ToTyped comment is optional because, at this point, the module is small and logic is encapsulated. I think it makes a lot of sense to have shared visitors, for instance, extract code that visits all tasks that need cluster/environment.

@pietern

Copy link
Copy Markdown
Contributor

Yes, it's not strictly necessary.

A higher-level comment about the error messages is that the summary is what users will read first, and that's what should contain what is wrong, not the solution. Right now they are swapped. The solution is in the summary and the error is in the detail. Could you swap those around? Then it will say, Error: task "main_task" has a task type that requires a cluster or environment, but neither is specified with the solution following it. WDYT?

@pieternpietern left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

Added one more suggestion.

Comment threadbundle/config/validate/job_task_cluster_spec.go Outdated
kanterovand others added 2 commits September 25, 2024 13:19
Co-authored-by: Pieter Noordhuis <pcnoordhuis@gmail.com>
@kanterov

Copy link
Copy Markdown
CollaboratorAuthor

@pietern Thanks. I've updated the doc. Can you please add it to the merge queue?

@pietern
pietern added this pull request to the merge queueSep 25, 2024
Merged via the queue into databricks:main with commit 3d9decdSep 25, 2024
andrewnester added a commit that referenced this pull request Oct 1, 2024
Bundles:
* Added support for creating all-purpose clusters ([#1698](#1698)).
* Reduce time until the prompt is shown for bundle run ([#1727](#1727)).
* Use Unity Catalog for pipelines in the default-python template ([#1766](#1766)).
* Add verbose flag to the "bundle deploy" command ([#1774](#1774)).
* Fixed full variable override detection ([#1787](#1787)).
* Add sub-extension to resource files in built-in templates ([#1777](#1777)).
* Fix panic in `apply_presets.go` ([#1796](#1796)).
Internal:
* Assert tokens are redacted in origin URL when username is not specified ([#1785](#1785)).
* Refactor jobs path translation ([#1782](#1782)).
* Add JobTaskClusterSpec validate mutator ([#1784](#1784)).
* Pin Go toolchain to 1.22.7 ([#1790](#1790)).
* Modify SetLocation test utility to take full locations as argument ([#1788](#1788)).
* Simplified isFullVariableOverrideDef implementation ([#1791](#1791)).
* Sort tasks by `task_key` before generating the Terraform configuration ([#1776](#1776)).
* Trim trailing whitespace ([#1794](#1794)).
* Move trampoline code into trampoline package ([#1793](#1793)).
* Rename `RootPath` -> `BundleRootPath` ([#1792](#1792)).
API Changes:
* Changed `databricks apps delete` command to return .
* Changed `databricks apps deploy` command with new required argument order.
* Changed `databricks apps start` command to return .
* Changed `databricks apps stop` command to return .
* Added `databricks temporary-table-credentials` command group.
* Added `databricks serving-endpoints put-ai-gateway` command.
* Added `databricks disable-legacy-access` command group.
* Added `databricks account disable-legacy-features` command group.
OpenAPI commit 6f6b1371e640f2dfeba72d365ac566368656f6b6 (2024-09-19)
Dependency updates:
* Upgrade to Go SDK 0.47.0 ([#1799](#1799)).
* Upgrade to TF provider 1.52 ([#1781](#1781)).
* Bump golang.org/x/mod from 0.20.0 to 0.21.0 ([#1758](#1758)).
* Bump github.com/hashicorp/hc-install from 0.7.0 to 0.9.0 ([#1772](#1772)).
github-merge-queueBot pushed a commit that referenced this pull request Oct 1, 2024
Bundles:
* Added support for creating all-purpose clusters
([#1698](#1698)).
* Reduce time until the prompt is shown for bundle run
([#1727](#1727)).
* Use Unity Catalog for pipelines in the default-python template
([#1766](#1766)).
* Add verbose flag to the "bundle deploy" command
([#1774](#1774)).
* Fixed full variable override detection
([#1787](#1787)).
* Add sub-extension to resource files in built-in templates
([#1777](#1777)).
* Fix panic in `apply_presets.go`
([#1796](#1796)).
Internal:
* Assert tokens are redacted in origin URL when username is not
specified ([#1785](#1785)).
* Refactor jobs path translation
([#1782](#1782)).
* Add JobTaskClusterSpec validate mutator
([#1784](#1784)).
* Pin Go toolchain to 1.22.7
([#1790](#1790)).
* Modify SetLocation test utility to take full locations as argument
([#1788](#1788)).
* Simplified isFullVariableOverrideDef implementation
([#1791](#1791)).
* Sort tasks by `task_key` before generating the Terraform configuration
([#1776](#1776)).
* Trim trailing whitespace
([#1794](#1794)).
* Move trampoline code into trampoline package
([#1793](#1793)).
* Rename `RootPath` -> `BundleRootPath`
([#1792](#1792)).
API Changes:
* Changed `databricks apps delete` command to return .
* Changed `databricks apps deploy` command with new required argument
order.
* Changed `databricks apps start` command to return .
* Changed `databricks apps stop` command to return .
* Added `databricks temporary-table-credentials` command group.
* Added `databricks serving-endpoints put-ai-gateway` command.
* Added `databricks disable-legacy-access` command group.
* Added `databricks account disable-legacy-features` command group.
OpenAPI commit 6f6b1371e640f2dfeba72d365ac566368656f6b6 (2024-09-19)
Dependency updates:
* Upgrade to Go SDK 0.47.0
([#1799](#1799)).
* Upgrade to TF provider 1.52
([#1781](#1781)).
* Bump golang.org/x/mod from 0.20.0 to 0.21.0
([#1758](#1758)).
* Bump github.com/hashicorp/hc-install from 0.7.0 to 0.9.0
([#1772](#1772)).
denik pushed a commit that referenced this pull request May 20, 2026
## Changes
Add JobTaskClusterSpec validate mutator. It catches the case when tasks
don't which cluster to use.
For example, we can get this error with minor modifications to
`default-python` template:
```yaml
tasks:
- task_key: python_file_task
spark_python_task:
python_file: ../src/my_project_10/main.py
```
```
% databricks bundle validate
Error: Missing required cluster or environment settings
at resources.jobs.my_project_10_job.tasks[0]
in resources/my_project_10_job.yml:17:11
Task "print_github_stars" requires a cluster or an environment to run.
Specify one of the following fields: job_cluster_key, environment_key, existing_cluster_id, new_cluster.
```
We implicitly rely on "one of" validation, which does not exist. Many
bundle fields can't co-exist, for instance, specifying:
`JobTask.{existing_cluster_id,job_cluster_key}`, `Library.{whl,pypi}`,
`JobTask.{notebook_task,python_wheel_task}`, etc.
## Tests
Unit tests
---------
Co-authored-by: Pieter Noordhuis <pcnoordhuis@gmail.com>
denik pushed a commit that referenced this pull request May 20, 2026
Bundles:
* Added support for creating all-purpose clusters
([#1698](#1698)).
* Reduce time until the prompt is shown for bundle run
([#1727](#1727)).
* Use Unity Catalog for pipelines in the default-python template
([#1766](#1766)).
* Add verbose flag to the "bundle deploy" command
([#1774](#1774)).
* Fixed full variable override detection
([#1787](#1787)).
* Add sub-extension to resource files in built-in templates
([#1777](#1777)).
* Fix panic in `apply_presets.go`
([#1796](#1796)).
Internal:
* Assert tokens are redacted in origin URL when username is not
specified ([#1785](#1785)).
* Refactor jobs path translation
([#1782](#1782)).
* Add JobTaskClusterSpec validate mutator
([#1784](#1784)).
* Pin Go toolchain to 1.22.7
([#1790](#1790)).
* Modify SetLocation test utility to take full locations as argument
([#1788](#1788)).
* Simplified isFullVariableOverrideDef implementation
([#1791](#1791)).
* Sort tasks by `task_key` before generating the Terraform configuration
([#1776](#1776)).
* Trim trailing whitespace
([#1794](#1794)).
* Move trampoline code into trampoline package
([#1793](#1793)).
* Rename `RootPath` -> `BundleRootPath`
([#1792](#1792)).
API Changes:
* Changed `databricks apps delete` command to return .
* Changed `databricks apps deploy` command with new required argument
order.
* Changed `databricks apps start` command to return .
* Changed `databricks apps stop` command to return .
* Added `databricks temporary-table-credentials` command group.
* Added `databricks serving-endpoints put-ai-gateway` command.
* Added `databricks disable-legacy-access` command group.
* Added `databricks account disable-legacy-features` command group.
OpenAPI commit 6f6b1371e640f2dfeba72d365ac566368656f6b6 (2024-09-19)
Dependency updates:
* Upgrade to Go SDK 0.47.0
([#1799](#1799)).
* Upgrade to TF provider 1.52
([#1781](#1781)).
* Bump golang.org/x/mod from 0.20.0 to 0.21.0
([#1758](#1758)).
* Bump github.com/hashicorp/hc-install from 0.7.0 to 0.9.0
([#1772](#1772)).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@kanterov@pietern