Skip to content
Merged
1 change: 1 addition & 0 deletions acceptance/bundle/deploy/empty-bundle/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion acceptance/bundle/deploy/empty-bundle/test.toml
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
Cloud=true
Cloud = true

[EnvMatrix]
DATABRICKS_BUNDLE_ENABLE_EXPERIMENTAL_YAML_SYNC = ["", "true"]
57 changes: 34 additions & 23 deletions bundle/statemgmt/upload_state_for_yaml_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,23 @@ func (m *uploadStateForYamlSync) Apply(ctx context.Context, b *bundle.Bundle) di

_, snapshotPath := b.StateFilenameConfigSnapshot(ctx)

diags := m.convertState(ctx, b, snapshotPath)
if diags.HasError() {
return diags
created, err := m.convertState(ctx, b, snapshotPath)
if err != nil {
log.Warnf(ctx, "Failed to create config snapshot: %v", err)
return nil
}
if !created {
return nil
}

err := uploadState(ctx, b)
err = uploadState(ctx, b)
if err != nil {
return diags.Extend(diag.Warningf("Failed to upload config snapshot to workspace: %v", err))
log.Warnf(ctx, "Failed to upload config snapshot: %v", err)
return nil
}

log.Infof(ctx, "Config snapshot created at %s", snapshotPath)
return diags
return nil
}

func uploadState(ctx context.Context, b *bundle.Bundle) error {
Expand All @@ -94,10 +99,22 @@ func uploadState(ctx context.Context, b *bundle.Bundle) error {
return nil
}

func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bundle, snapshotPath string) (diags diag.Diagnostics) {
func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bundle, snapshotPath string) (bool, error) {
terraformResources, err := terraform.ParseResourcesState(ctx, b)
if err != nil {
return diag.FromErr(err)
return false, fmt.Errorf("failed to parse terraform state: %w", err)
}

// ParseResourcesState returns nil when the terraform state file doesn't exist
// (e.g. first deploy with no resources).
if terraformResources == nil {
return false, nil
}

_, localTerraformPath := b.StateFilenameTerraform(ctx)
data, err := os.ReadFile(localTerraformPath)
if err != nil {
return false, fmt.Errorf("failed to read terraform state: %w", err)
}

state := make(map[string]dstate.ResourceEntry)
Expand All @@ -113,18 +130,12 @@ func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bun
}
}

_, localTerraformPath := b.StateFilenameTerraform(ctx)
data, err := os.ReadFile(localTerraformPath)
if err != nil {
return diag.FromErr(err)
}

var tfState struct {
Lineage string `json:"lineage"`
Serial int `json:"serial"`
}
if err := json.Unmarshal(data, &tfState); err != nil {
return diag.FromErr(err)
return false, err
}

migratedDB := dstate.NewDatabase(tfState.Lineage, tfState.Serial+1)
Expand All @@ -142,29 +153,29 @@ func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bun
// the migrated state and config agree on .permissions entries.
bundle.ApplyContext(ctx, b, resourcemutator.SecretScopeFixups(engine.EngineDirect))
if logdiag.HasError(ctx) {
return diag.Errorf("failed to apply secret scope fixups")
return false, errors.New("failed to apply secret scope fixups")
}

// Get the dynamic value from b.Config and reverse the interpolation
// Get the dynamic value from b.Config and reverse the interpolation.
// b.Config has been modified by terraform.Interpolate which converts bundle-style
// references (${resources.pipelines.x.id}) to terraform-style (${databricks_pipeline.x.id})
// references (${resources.pipelines.x.id}) to terraform-style (${databricks_pipeline.x.id}).
interpolatedRoot := b.Config.Value()
uninterpolatedRoot, err := reverseInterpolate(interpolatedRoot)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to reverse interpolation: %w", err))
return false, fmt.Errorf("failed to reverse interpolation: %w", err)
}

var uninterpolatedConfig config.Root
err = uninterpolatedConfig.Mutate(func(_ dyn.Value) (dyn.Value, error) {
return uninterpolatedRoot, nil
})
if err != nil {
return diag.FromErr(fmt.Errorf("failed to create uninterpolated config: %w", err))
return false, fmt.Errorf("failed to create uninterpolated config: %w", err)
}

plan, err := deploymentBundle.CalculatePlan(ctx, b.WorkspaceClient(), &uninterpolatedConfig, snapshotPath)
if err != nil {
return diag.FromErr(err)
return false, err
}

for _, entry := range plan.Plan {
Expand All @@ -182,13 +193,13 @@ func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bun
}
err := structaccess.Set(sv.Value, structpath.NewStringKey(nil, "etag"), etag)
if err != nil {
diags = diags.Extend(diag.Warningf("Failed to set etag on %q: %v", key, err))
log.Warnf(ctx, "Failed to set etag on %q: %v", key, err)
}
}

deploymentBundle.Apply(ctx, b.WorkspaceClient(), plan, direct.MigrateMode(true))

return diags
return true, nil
}

// reverseInterpolate reverses the terraform.Interpolate transformation.
Expand Down
Loading