diff --git a/acceptance/bundle/deploy/empty-bundle/out.test.toml b/acceptance/bundle/deploy/empty-bundle/out.test.toml index 01ed6822af..0940cf4b56 100644 --- a/acceptance/bundle/deploy/empty-bundle/out.test.toml +++ b/acceptance/bundle/deploy/empty-bundle/out.test.toml @@ -2,4 +2,5 @@ Local = true Cloud = true [EnvMatrix] + DATABRICKS_BUNDLE_ENABLE_EXPERIMENTAL_YAML_SYNC = ["", "true"] DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/bundle/deploy/empty-bundle/test.toml b/acceptance/bundle/deploy/empty-bundle/test.toml index 5265ac0b23..f64800a163 100644 --- a/acceptance/bundle/deploy/empty-bundle/test.toml +++ b/acceptance/bundle/deploy/empty-bundle/test.toml @@ -1 +1,4 @@ -Cloud=true +Cloud = true + +[EnvMatrix] +DATABRICKS_BUNDLE_ENABLE_EXPERIMENTAL_YAML_SYNC = ["", "true"] diff --git a/bundle/statemgmt/upload_state_for_yaml_sync.go b/bundle/statemgmt/upload_state_for_yaml_sync.go index 7d7c766743..c3da05727c 100644 --- a/bundle/statemgmt/upload_state_for_yaml_sync.go +++ b/bundle/statemgmt/upload_state_for_yaml_sync.go @@ -54,18 +54,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 { @@ -92,10 +97,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) @@ -111,18 +128,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) @@ -135,13 +146,13 @@ func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bun }, } - // 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 @@ -149,12 +160,12 @@ func (m *uploadStateForYamlSync) convertState(ctx context.Context, b *bundle.Bun 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 { @@ -172,13 +183,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.