diff --git a/acceptance/bundle/invariant/continue_293/script b/acceptance/bundle/invariant/continue_293/script index cd0e57ba9b8..2a0e94d9719 100644 --- a/acceptance/bundle/invariant/continue_293/script +++ b/acceptance/bundle/invariant/continue_293/script @@ -1,41 +1,17 @@ # Invariant to test: current CLI can deploy on top of state produced by v0.293.0 -cp -r "$TESTDIR/../data/." . &> LOG.cp - -INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" -if [ -f "$INIT_SCRIPT" ]; then - source "$INIT_SCRIPT" &> LOG.init -fi - -envsubst < "$TESTDIR/../configs/$INPUT_CONFIG" > databricks.yml - -cleanup() { - $CLI bundle destroy --auto-approve &> LOG.destroy - cat LOG.destroy | contains.py '!panic:' '!internal error' > /dev/null - - CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" - if [ -f "$CLEANUP_SCRIPT" ]; then - source "$CLEANUP_SCRIPT" &> LOG.cleanup - fi -} - -trap cleanup EXIT +invariant_setup # Deploy with old CLI to produce v0.293.0 state trace $CLI_293 --version -$CLI_293 bundle deploy &> LOG.deploy.293 -cat LOG.deploy.293 | contains.py '!panic:' '!internal error' > /dev/null - -echo INPUT_CONFIG_OK +invariant_deploy LOG.deploy.293 $CLI_293 bundle deploy # Deploy with current CLI on top of old state $CLI bundle deploy &> LOG.deploy cat LOG.deploy | contains.py '!panic:' '!internal error' > /dev/null # Verify no drift after current CLI deploy -$CLI bundle plan -o json > LOG.planjson 2>LOG.planjson.err -cat LOG.planjson.err | contains.py '!panic:' '!internal error' > /dev/null -verify_no_drift.py LOG.planjson +invariant_verify_no_drift $CLI bundle plan 2>LOG.plan.err | contains.py '!panic:' '!internal error' 'Plan: 0 to add, 0 to change, 0 to delete' > LOG.plan cat LOG.plan.err | contains.py '!panic:' '!internal error' > /dev/null diff --git a/acceptance/bundle/invariant/delete_idempotent/script b/acceptance/bundle/invariant/delete_idempotent/script index e21c2887f07..aba945dbb2e 100644 --- a/acceptance/bundle/invariant/delete_idempotent/script +++ b/acceptance/bundle/invariant/delete_idempotent/script @@ -2,36 +2,13 @@ # After a delete succeeds, restoring the pre-delete state and running deploy again # must succeed even though the resources are already gone on the server. -# Copy data files to test directory -cp -r "$TESTDIR/../data/." . &> LOG.cp - -# Run init script if present -INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" -if [ -f "$INIT_SCRIPT" ]; then - source "$INIT_SCRIPT" &> LOG.init -fi - -envsubst < $TESTDIR/../configs/$INPUT_CONFIG > databricks.yml - -cp databricks.yml LOG.config +invariant_setup # All configs use `test-bundle-$UNIQUE_NAME`; workspace root/state paths follow # the default `~/.bundle//` template with target=default. bundle_name=test-bundle-$UNIQUE_NAME STATE_PATH=/Workspace/Users/$CURRENT_USER_NAME/.bundle/$bundle_name/default/state -cleanup() { - trace $CLI bundle destroy --auto-approve &> LOG.destroy - cat LOG.destroy | contains.py '!panic:' '!internal error' > /dev/null - - CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" - if [ -f "$CLEANUP_SCRIPT" ]; then - source "$CLEANUP_SCRIPT" &> LOG.cleanup - fi -} - -trap cleanup EXIT - # Initial deploy of the resources. Only pre-plan when READPLAN=1 exercises the # saved-plan deploy path; otherwise `bundle deploy` plans on its own. if [[ -n "$READPLAN" ]]; then @@ -39,12 +16,7 @@ if [[ -n "$READPLAN" ]]; then cat LOG.plan_initial.err | contains.py '!panic:' '!internal error' > /dev/null fi -trace $CLI bundle deploy $(readplanarg plan_initial.json) &> LOG.deploy_initial -cat LOG.deploy_initial | contains.py '!panic:' '!internal error' > /dev/null - -# Special message to fuzzer that generated config was fine. -# Any failures after this point will be considered as "bug detected" by fuzzer. -echo INPUT_CONFIG_OK +invariant_deploy LOG.deploy_initial $CLI bundle deploy $(readplanarg plan_initial.json) # Snapshot the deploy state before we delete anything. cp -r .databricks .databricks.backup diff --git a/acceptance/bundle/invariant/destroy_idempotent/script b/acceptance/bundle/invariant/destroy_idempotent/script index d9e76cbaf1b..0467b23330e 100644 --- a/acceptance/bundle/invariant/destroy_idempotent/script +++ b/acceptance/bundle/invariant/destroy_idempotent/script @@ -2,36 +2,13 @@ # After destroy succeeds, restoring the pre-destroy state and running destroy again # must succeed even though the resources are already gone on the server. -# Copy data files to test directory -cp -r "$TESTDIR/../data/." . &> LOG.cp - -# Run init script if present -INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" -if [ -f "$INIT_SCRIPT" ]; then - source "$INIT_SCRIPT" &> LOG.init -fi - -envsubst < $TESTDIR/../configs/$INPUT_CONFIG > databricks.yml - -cp databricks.yml LOG.config +invariant_setup # All configs use `test-bundle-$UNIQUE_NAME`; workspace root path follows the # default `~/.bundle//` template with target=default. bundle_name=test-bundle-$UNIQUE_NAME ROOT_PATH=/Workspace/Users/$CURRENT_USER_NAME/.bundle/$bundle_name/default -final_cleanup() { - trace $CLI bundle destroy --auto-approve &> LOG.destroy_final - cat LOG.destroy_final | contains.py '!panic:' '!internal error' > /dev/null - - CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" - if [ -f "$CLEANUP_SCRIPT" ]; then - source "$CLEANUP_SCRIPT" &> LOG.cleanup - fi -} - -trap final_cleanup EXIT - # Initial deploy of the resources. Only pre-plan when READPLAN=1 exercises the # saved-plan deploy path; otherwise `bundle deploy` plans on its own. if [[ -n "$READPLAN" ]]; then @@ -39,12 +16,7 @@ if [[ -n "$READPLAN" ]]; then cat LOG.plan_initial.err | contains.py '!panic:' '!internal error' > /dev/null fi -trace $CLI bundle deploy $(readplanarg plan_initial.json) &> LOG.deploy_initial -cat LOG.deploy_initial | contains.py '!panic:' '!internal error' > /dev/null - -# Special message to fuzzer that generated config was fine. -# Any failures after this point will be considered as "bug detected" by fuzzer. -echo INPUT_CONFIG_OK +invariant_deploy LOG.deploy_initial $CLI bundle deploy $(readplanarg plan_initial.json) # Snapshot the deploy state before we destroy anything. cp -r .databricks .databricks.backup diff --git a/acceptance/bundle/invariant/migrate/script b/acceptance/bundle/invariant/migrate/script index 78f45faa7da..4cd19571951 100644 --- a/acceptance/bundle/invariant/migrate/script +++ b/acceptance/bundle/invariant/migrate/script @@ -3,36 +3,9 @@ unset DATABRICKS_BUNDLE_ENGINE -# Copy data files to test directory -cp -r "$TESTDIR/../data/." . &> LOG.cp +invariant_setup -# Run init script if present -INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" -if [ -f "$INIT_SCRIPT" ]; then - source "$INIT_SCRIPT" &> LOG.init -fi - -envsubst < $TESTDIR/../configs/$INPUT_CONFIG > databricks.yml - -cp databricks.yml LOG.config - -cleanup() { - trace $CLI bundle destroy --auto-approve &> LOG.destroy - cat LOG.destroy | contains.py '!panic:' '!internal error' > /dev/null - - # Run cleanup script if present - CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" - if [ -f "$CLEANUP_SCRIPT" ]; then - source "$CLEANUP_SCRIPT" &> LOG.cleanup - fi -} - -trap cleanup EXIT - -trace DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle deploy &> LOG.deploy -cat LOG.deploy | contains.py '!panic:' '!internal error' > /dev/null - -echo INPUT_CONFIG_OK +invariant_deploy LOG.deploy DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle deploy MIGRATE_ARGS="" # The terraform provider sorts depends_on entries alphabetically by task_key on Read @@ -48,6 +21,4 @@ trace $CLI bundle deployment migrate $MIGRATE_ARGS &> LOG.migrate cat LOG.migrate | contains.py '!panic:' '!internal error' > /dev/null -$CLI bundle plan -o json > plan.json 2>plan.json.err -cat plan.json.err | contains.py '!panic:' '!internal error' > /dev/null -verify_no_drift.py plan.json +invariant_verify_no_drift diff --git a/acceptance/bundle/invariant/no_drift/script b/acceptance/bundle/invariant/no_drift/script index ca80ab85440..9f031c0f613 100644 --- a/acceptance/bundle/invariant/no_drift/script +++ b/acceptance/bundle/invariant/no_drift/script @@ -1,31 +1,7 @@ # Invariant to test: no drift after deploy # Additional checks: no internal errors / panics in validate/plan/deploy -# Copy data files to test directory -cp -r "$TESTDIR/../data/." . &> LOG.cp - -# Run init script if present -INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" -if [ -f "$INIT_SCRIPT" ]; then - source "$INIT_SCRIPT" &> LOG.init -fi - -envsubst < $TESTDIR/../configs/$INPUT_CONFIG > databricks.yml - -cp databricks.yml LOG.config - -cleanup() { - trace $CLI bundle destroy --auto-approve &> LOG.destroy - cat LOG.destroy | contains.py '!panic:' '!internal error' > /dev/null - - # Run cleanup script if present - CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" - if [ -f "$CLEANUP_SCRIPT" ]; then - source "$CLEANUP_SCRIPT" &> LOG.cleanup - fi -} - -trap cleanup EXIT +invariant_setup # Only compute a plan up front when the READPLAN variant actually consumes it via --plan. # Without READPLAN, deploy computes its own plan internally, so a separate `bundle plan` @@ -35,15 +11,6 @@ if [[ -n "$READPLAN" ]]; then cat LOG.plan_initial.err | contains.py '!panic:' '!internal error' > /dev/null fi -trace $CLI bundle deploy $(readplanarg plan.json) &> LOG.deploy -cat LOG.deploy | contains.py '!panic:' '!internal error' > /dev/null - -# Special message to fuzzer that generated config was fine. -# Any failures after this point will be considered as "bug detected" by fuzzer. -echo INPUT_CONFIG_OK +invariant_deploy LOG.deploy $CLI bundle deploy $(readplanarg plan.json) -# JSON plan asserts every action is "skip" -- a strict superset of the text -# renderer's "Plan: 0 to add, 0 to change, 0 to delete" summary. -$CLI bundle plan -o json > LOG.planjson 2>LOG.planjson.err -cat LOG.planjson.err | contains.py '!panic:' '!internal error' > /dev/null -verify_no_drift.py LOG.planjson +invariant_verify_no_drift diff --git a/acceptance/bundle/invariant/script.prepare b/acceptance/bundle/invariant/script.prepare new file mode 100644 index 00000000000..54f2a3dbf25 --- /dev/null +++ b/acceptance/bundle/invariant/script.prepare @@ -0,0 +1,54 @@ +# Shared setup for the invariant targets; each script keeps only the invariant it asserts. + +invariant_cleanup() { + trace $CLI bundle destroy --auto-approve &> LOG.destroy + cat LOG.destroy | contains.py '!panic:' '!internal error' > /dev/null + + CLEANUP_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-cleanup.sh" + if [ -f "$CLEANUP_SCRIPT" ]; then + source "$CLEANUP_SCRIPT" &> LOG.cleanup + fi +} + +# Separate from invariant_setup so a caller that generates its own config can override the +# render alone; child script.prepare files are concatenated after this one. +invariant_render() { + cp -r "$TESTDIR/../data/." . &> LOG.cp + + INIT_SCRIPT="$TESTDIR/../configs/$INPUT_CONFIG-init.sh" + if [ -f "$INIT_SCRIPT" ]; then + source "$INIT_SCRIPT" &> LOG.init + fi + + envsubst < "$TESTDIR/../configs/$INPUT_CONFIG" > databricks.yml + + cp databricks.yml LOG.config +} + +# Call from the target, not at prepare time: prepare runs outside the subshell wrapping the +# script, so the trap would belong to the outer shell. +invariant_setup() { + invariant_render + + trap invariant_cleanup EXIT +} + +# Goes through trace, so callers can prefix the command with VAR=val. +invariant_deploy() { + local logfile="$1" + shift + trace "$@" &> "$logfile" + cat "$logfile" | contains.py '!panic:' '!internal error' > /dev/null + + # Tells the fuzzer the generated config was valid; failures after this count as bugs. + echo INPUT_CONFIG_OK +} + +# JSON plan asserts every action is "skip" -- a strict superset of the text +# renderer's "Plan: 0 to add, 0 to change, 0 to delete" summary. +# Overridable for a caller whose config the server does not round-trip exactly. +invariant_verify_no_drift() { + $CLI bundle plan -o json > LOG.planjson 2>LOG.planjson.err + cat LOG.planjson.err | contains.py '!panic:' '!internal error' > /dev/null + verify_no_drift.py LOG.planjson +}