Skip to content

Commit 3eab8c8

Browse files
authored
Validate that resource keys do not contain variable references (#5169)
## Changes Validate that resource keys do not contain variable references ## Why Fixes #5098 ## Tests Added an acceptance test, failed with panic before the fix ``` runtime/debug.Stack() runtime/debug/stack.go:26 +0x5e github.com/databricks/cli/cmd/root.Execute.func1() github.com/databricks/cli/cmd/root/root.go:117 +0xb4 panic({0x7ff66a649480?, 0x7ff66bad51a0?}) runtime/panic.go:783 +0x132 github.com/databricks/cli/bundle/direct/dresources.(*ResourceSchema).PrepareState(0x0?, 0x0?) github.com/databricks/cli/bundle/direct/dresources/schema.go:22 reflect.Value.call({0xc0001294a0?, 0xc000988ea8?, 0xc0006ae848?}, {0x7ff66a9b6321, 0x4}, {0xc0000d1bf0, 0x2, 0xc0006e4e18?}) reflect/value.go:581 +0xcc6 reflect.Value.Call({0xc0001294a0?, 0xc000988ea8?, 0x4?}, {0xc0000d1bf0?, 0x0?, 0x5?}) reflect/value.go:365 +0xb9 github.com/databricks/cli/libs/calladapt.(*BoundCaller).call(0xc000b93e00, {0xc0006aeab8?, 0x1, 0xc0006e4e0a?}) github.com/databricks/cli/libs/calladapt/calladapt.go:71 +0x765 github.com/databricks/cli/libs/calladapt.(*BoundCaller).Call(0xc000b93e00, {0xc0006aeab8?, 0x7ff66a9c3172?, 0xc?}) github.com/databricks/cli/libs/calladapt/calladapt.go:78 +0x2f github.com/databricks/cli/bundle/direct/dresources.(*Adapter).PrepareState(0xc000421df8?, {0x0?, 0x0?}) github.com/databricks/cli/bundle/direct/dresources/adapter.go:374 +0x37 github.com/databricks/cli/bundle/direct.(*DeploymentBundle).makePlan(0xc000421df8, {0xc00014ea80?, 0x3e?}, 0xc000421858, 0xc000421e08) github.com/databricks/cli/bundle/direct/bundle_plan.go:837 +0x7fd github.com/databricks/cli/bundle/direct.(*DeploymentBundle).CalculatePlan(0xc000421df8, {0x7ff66acfa188, 0xc000b140c0}, 0xc000150908, 0xc000421858, {0xc00014ea80, 0x3e}) github.com/databricks/cli/bundle/direct/bundle_plan.go:124 +0xf0 github.com/databricks/cli/bundle/phases.RunPlan({0x7ff66acfa188, 0xc000b140c0}, 0xc000421808, {0x7ff66a9b8320?, 0x1000000000100?}) github.com/databricks/cli/bundle/phases/deploy.go:218 +0xf4 github.com/databricks/cli/cmd/bundle.newPlanCommand.func1(0xc00056cf08, {0xc000370be0?, 0x4?, 0x7ff66a9b6115?}) github.com/databricks/cli/cmd/bundle/plan.go:65 +0x1e5 github.com/spf13/cobra.(*Command).execute(0xc00056cf08, {0xc000370bc0, 0x2, 0x2}) github.com/spf13/cobra@v1.10.2/command.go:1015 +0xb02 github.com/spf13/cobra.(*Command).ExecuteC(0xc000394608) github.com/spf13/cobra@v1.10.2/command.go:1148 +0x465 github.com/spf13/cobra.(*Command).ExecuteContextC(...) github.com/spf13/cobra@v1.10.2/command.go:1080 github.com/databricks/cli/cmd/root.Execute({0x7ff66acfa150, 0x7ff66bb62640}, 0xc000394608) github.com/databricks/cli/cmd/root/root.go:149 +0x176 main.main() github.com/databricks/cli/main.go:13 +0x3b ```
1 parent 00a9f8a commit 3eab8c8

7 files changed

Lines changed: 99 additions & 2 deletions

File tree

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* JSON output for single objects now uses standard `"key": "value"` spacing (matching list output and `encoding/json` defaults).
99

1010
### Bundles
11+
* Validate that resource keys do not contain variable references ([#5169](https://github.com/databricks/cli/pull/5169))
1112
* engine/direct: Drop the deployment state entry on a recreate before the follow-up `Create`, so a `Create` failure no longer leaves a broken state with `invalid state: empty id` on the next `bundle plan` ([#5173](https://github.com/databricks/cli/pull/5173)).
1213

1314
### Dependency updates
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
bundle:
2+
name: variable-in-resource-key
3+
4+
variables:
5+
env:
6+
description: The target environment
7+
default: dev
8+
9+
resources:
10+
jobs:
11+
${var.env}_job:
12+
name: my-job
13+
14+
targets:
15+
dev:
16+
default: true
17+
resources:
18+
jobs:
19+
${var.env}_job_2:
20+
name: my-job
21+
${var.env}: my-job-description

acceptance/bundle/variables/variable_in_resource_key/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Warning: unknown field: ${var.env}
2+
at targets.dev.resources.jobs.${var.env}_job_2
3+
in databricks.yml:21:11
4+
5+
Error: resource key "${var.env}_job" must not contain variable references
6+
at resources.jobs.${var.env}_job
7+
in databricks.yml:12:7
8+
9+
Error: resource key "${var.env}_job_2" must not contain variable references
10+
at targets.dev.resources.jobs.${var.env}_job_2
11+
in databricks.yml:20:11
12+
13+
14+
Exit code: 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$CLI bundle plan

bundle/config/mutator/mutator.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ func DefaultMutators(ctx context.Context, b *bundle.Bundle) {
2828
InitializeVariables(),
2929
DefineDefaultTarget(),
3030

31-
// Note: This mutator must run before the target overrides are merged.
32-
// See the mutator for more details.
31+
// Note: These mutators must run before the target overrides are merged.
32+
// See the mutators for more details.
33+
validate.NoVariableReferenceInResourceKey(),
3334
validate.UniqueResourceKeys(),
3435
)
3536
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package validate
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/databricks/cli/bundle"
8+
"github.com/databricks/cli/libs/diag"
9+
"github.com/databricks/cli/libs/dyn"
10+
"github.com/databricks/cli/libs/dyn/dynvar"
11+
)
12+
13+
type noVariableReferenceInResourceKey struct{}
14+
15+
// NoVariableReferenceInResourceKey validates that no resource key contains a variable reference.
16+
// Resource keys are used as identifiers throughout the deployment pipeline and must be static strings.
17+
func NoVariableReferenceInResourceKey() bundle.Mutator {
18+
return &noVariableReferenceInResourceKey{}
19+
}
20+
21+
func (m *noVariableReferenceInResourceKey) Name() string {
22+
return "validate:no_variable_reference_in_resource_key"
23+
}
24+
25+
func (m *noVariableReferenceInResourceKey) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics {
26+
var diags diag.Diagnostics
27+
28+
patterns := []dyn.Pattern{
29+
dyn.NewPattern(dyn.Key("resources"), dyn.AnyKey(), dyn.AnyKey()),
30+
dyn.NewPattern(dyn.Key("targets"), dyn.AnyKey(), dyn.Key("resources"), dyn.AnyKey(), dyn.AnyKey()),
31+
}
32+
33+
for _, pattern := range patterns {
34+
_, err := dyn.MapByPattern(
35+
b.Config.Value(),
36+
pattern,
37+
func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
38+
key := p[len(p)-1].Key()
39+
if dynvar.ContainsVariableReference(key) {
40+
diags = append(diags, diag.Diagnostic{
41+
Severity: diag.Error,
42+
Summary: fmt.Sprintf("resource key %q must not contain variable references", key),
43+
Locations: v.Locations(),
44+
Paths: []dyn.Path{p},
45+
})
46+
}
47+
return v, nil
48+
},
49+
)
50+
if err != nil {
51+
diags = append(diags, diag.FromErr(err)...)
52+
}
53+
}
54+
55+
return diags
56+
}

0 commit comments

Comments
 (0)