Skip to content

Commit a9ba5c0

Browse files
authored
Check plan before migration (#4088)
## Why Since we ask to do the deploy before the migration, running plan ensures people don't forget to do that.
1 parent 009f9e4 commit a9ba5c0

File tree

11 files changed

+126
-12
lines changed

11 files changed

+126
-12
lines changed

NEXT_CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
### CLI
88

99
### Bundles
10+
* `bundle deployment migrate` will now run a plan before migration to check if deployment was done ([#4088](https://github.com/databricks/cli/pull/4088))
1011

1112
### Dependency updates
1213

acceptance/bundle/help/bundle-deployment-migrate/output.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Usage:
1414
databricks bundle deployment migrate [flags]
1515

1616
Flags:
17-
-h, --help help for migrate
17+
-h, --help help for migrate
18+
--noplancheck Skip running bundle plan before migration.
1819

1920
Global Flags:
2021
--debug enable debug logging

acceptance/bundle/migrate/basic/output.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ Updating deployment state...
1111
Deployment complete!
1212

1313
>>> [CLI] bundle deployment migrate
14+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
15+
Plan: 0 to add, 0 to change, 0 to delete, 3 unchanged
1416
Migrated 3 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/dev/resources.json
1517

16-
Validate the migration by running "bundle plan", there should be no actions planned.
18+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
1719

1820
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
1921

acceptance/bundle/migrate/dashboards/output.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ Updating deployment state...
66
Deployment complete!
77

88
>>> [CLI] bundle deployment migrate
9+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
10+
Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
911
Migrated 1 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/default/resources.json
1012

11-
Validate the migration by running "bundle plan", there should be no actions planned.
13+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
1214

1315
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
1416

acceptance/bundle/migrate/default-python/output.txt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,20 @@ Deployment complete!
2222

2323
>>> print_state.py
2424

25-
>>> [CLI] bundle deployment migrate
25+
>>> musterr [CLI] bundle deployment migrate
26+
Building python_artifact...
27+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
28+
Building python_artifact...
29+
update jobs.sample_job
30+
31+
Plan: 0 to add, 1 to change, 0 to delete, 1 unchanged
32+
Error: 'databricks bundle plan' shows actions planned, aborting migration. Please run 'databricks bundle deploy' first to ensure your bundle is up to date, If actions persist after deploy, skip plan check with --noplancheck option
33+
34+
>>> [CLI] bundle deployment migrate --noplancheck
2635
Building python_artifact...
2736
Migrated 2 resources to direct engine state file: [TEST_TMP_DIR]/my_default_python/.databricks/bundle/dev/resources.json
2837

29-
Validate the migration by running "bundle plan", there should be no actions planned.
38+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
3039

3140
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
3241

acceptance/bundle/migrate/default-python/script

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ cd my_default_python
33

44
trace DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle deploy
55
trace print_state.py > ../out.state_original.json
6-
trace $CLI bundle deployment migrate
6+
7+
trace musterr $CLI bundle deployment migrate
8+
trace $CLI bundle deployment migrate --noplancheck
9+
710
trace print_state.py > ../out.state_after_migration.json
811
trace jq '.. | .libraries? | select(.)' ../out.state_after_migration.json
912

acceptance/bundle/migrate/grants/output.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ Updating deployment state...
66
Deployment complete!
77

88
>>> [CLI] bundle deployment migrate
9+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
10+
Plan: 0 to add, 0 to change, 0 to delete, 6 unchanged
911
Migrated 6 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/default/resources.json
1012

11-
Validate the migration by running "bundle plan", there should be no actions planned.
13+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
1214

1315
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
1416

acceptance/bundle/migrate/permissions/output.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ Updating deployment state...
66
Deployment complete!
77

88
>>> [CLI] bundle deployment migrate
9+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
10+
Plan: 0 to add, 0 to change, 0 to delete, 4 unchanged
911
Migrated 4 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/default/resources.json
1012

11-
Validate the migration by running "bundle plan", there should be no actions planned.
13+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
1214

1315
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
1416

acceptance/bundle/migrate/runas/output.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,23 @@ Consider using a adding a top-level permissions section such as the following:
8181
See https://docs.databricks.com/dev-tools/bundles/permissions.html to learn more about permission configuration.
8282
in databricks.yml:5:3
8383

84+
Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:
85+
Recommendation: permissions section should explicitly include the current deployment identity '[USERNAME]' or one of its groups
86+
If it is not included, CAN_MANAGE permissions are only applied if the present identity is used to deploy.
87+
88+
Consider using a adding a top-level permissions section such as the following:
89+
90+
permissions:
91+
- user_name: [USERNAME]
92+
level: CAN_MANAGE
93+
94+
See https://docs.databricks.com/dev-tools/bundles/permissions.html to learn more about permission configuration.
95+
in databricks.yml:5:3
96+
97+
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged
8498
Migrated 2 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/production/resources.json
8599

86-
Validate the migration by running "bundle plan", there should be no actions planned.
100+
Validate the migration by running "databricks bundle plan", there should be no actions planned.
87101

88102
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
89103

cmd/bundle/deployment/migrate.go

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package deployment
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"os"
8+
"os/exec"
9+
"strings"
710

811
"github.com/databricks/cli/bundle/deploy/terraform"
912
"github.com/databricks/cli/bundle/direct"
@@ -19,6 +22,59 @@ import (
1922

2023
const backupSuffix = ".backup"
2124

25+
// runPlanCheck runs bundle plan and checks if there are any actions planned.
26+
// Returns error if plan fails or if there are actions planned.
27+
func runPlanCheck(cmd *cobra.Command, target string) error {
28+
ctx := cmd.Context()
29+
30+
executable, err := os.Executable()
31+
if err != nil {
32+
return fmt.Errorf("failed to get executable path: %w", err)
33+
}
34+
35+
args := []string{"bundle", "plan"}
36+
targetArgs := ""
37+
if target != "" {
38+
targetArgs = " -t " + target
39+
args = append(args, "-t", target)
40+
}
41+
42+
planCmd := exec.CommandContext(ctx, executable, args...)
43+
var stdout bytes.Buffer
44+
planCmd.Stdout = &stdout
45+
planCmd.Stderr = cmd.ErrOrStderr()
46+
47+
// Use the engine encoded in the state
48+
planCmd.Env = append(os.Environ(), "DATABRICKS_BUNDLE_ENGINE=terraform")
49+
50+
err = planCmd.Run()
51+
52+
// Output the plan stdout as is
53+
output := stdout.String()
54+
fmt.Fprint(cmd.OutOrStdout(), output)
55+
56+
if err != nil {
57+
var exitErr *exec.ExitError
58+
msg := ""
59+
if errors.As(err, &exitErr) {
60+
msg = fmt.Sprintf("exit code %d", exitErr.ExitCode())
61+
} else {
62+
msg = err.Error()
63+
}
64+
return fmt.Errorf("bundle plan failed with %s, aborting migration. To proceed with migration anyway, re-run the command with --noplancheck option", msg)
65+
}
66+
67+
if !strings.Contains(output, "Plan:") {
68+
return fmt.Errorf("cannot parse 'databricks bundle plan%s' output, aborting migration. Skip plan check with --noplancheck option", targetArgs)
69+
}
70+
71+
if !strings.Contains(output, "Plan: 0 to add, 0 to change, 0 to delete") {
72+
return fmt.Errorf("'databricks bundle plan%s' shows actions planned, aborting migration. Please run 'databricks bundle deploy%s' first to ensure your bundle is up to date, If actions persist after deploy, skip plan check with --noplancheck option", targetArgs, targetArgs)
73+
}
74+
75+
return nil
76+
}
77+
2278
func newMigrateCommand() *cobra.Command {
2379
cmd := &cobra.Command{
2480
Use: "migrate",
@@ -36,7 +92,20 @@ WARNING: Both direct deployment engine and this command are experimental and not
3692
Args: root.NoArgs,
3793
}
3894

95+
var noPlanCheck bool
96+
cmd.Flags().BoolVar(&noPlanCheck, "noplancheck", false, "Skip running bundle plan before migration.")
97+
3998
cmd.RunE = func(cmd *cobra.Command, args []string) error {
99+
// Get the target if it was explicitly passed
100+
target := ""
101+
if flag := cmd.Flag("target"); flag != nil && flag.Changed {
102+
target = flag.Value.String()
103+
}
104+
targetArgs := ""
105+
if target != "" {
106+
targetArgs += " -t " + target
107+
}
108+
40109
opts := utils.ProcessOptions{
41110
SkipEngineEnvVar: true,
42111
AlwaysPull: true,
@@ -82,6 +151,14 @@ To start using direct engine, deploy with DATABRICKS_BUNDLE_ENGINE=direct env va
82151
return fmt.Errorf("state file %s already exists", localPath)
83152
}
84153

154+
// Run plan check unless --noplancheck is set
155+
if !noPlanCheck {
156+
fmt.Fprintf(cmd.OutOrStdout(), "Note: Migration should be done after a full deploy. Running plan now to verify that deployment was done:\n")
157+
if err = runPlanCheck(cmd, target); err != nil {
158+
return err
159+
}
160+
}
161+
85162
etags := map[string]string{}
86163

87164
state := make(map[string]dstate.ResourceEntry)
@@ -155,12 +232,12 @@ To start using direct engine, deploy with DATABRICKS_BUNDLE_ENGINE=direct env va
155232

156233
cmdio.LogString(ctx, fmt.Sprintf(`Migrated %d resources to direct engine state file: %s
157234
158-
Validate the migration by running "bundle plan", there should be no actions planned.
235+
Validate the migration by running "databricks bundle plan%s", there should be no actions planned.
159236
160-
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy".
237+
The state file is not synchronized to the workspace yet. To do that and finalize the migration, run "bundle deploy%s".
161238
162239
To undo the migration, remove %s and rename %s to %s
163-
`, len(deploymentBundle.StateDB.Data.State), localPath, localPath, localTerraformBackupPath, localTerraformPath))
240+
`, len(deploymentBundle.StateDB.Data.State), localPath, targetArgs, targetArgs, localPath, localTerraformBackupPath, localTerraformPath))
164241
return nil
165242
}
166243

0 commit comments

Comments
 (0)