diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 79b9e7e4ed8c5..ba1720aa2abe6 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -53,13 +53,6 @@ func (t *terraform) Provision(stream proto.DRPCProvisioner_ProvisionStream) erro } }() start := request.GetStart() - statefilePath := filepath.Join(start.Directory, "terraform.tfstate") - if len(start.State) > 0 { - err := os.WriteFile(statefilePath, start.State, 0600) - if err != nil { - return xerrors.Errorf("write statefile %q: %w", statefilePath, err) - } - } terraform, err := tfexec.NewTerraform(start.Directory, t.binaryPath) if err != nil { @@ -244,14 +237,18 @@ func (t *terraform) Provision(stream proto.DRPCProvisioner_ProvisionStream) erro errorMessage := err.Error() // Terraform can fail and apply and still need to store it's state. // In this case, we return Complete with an explicit error message. - statefileContent, err := os.ReadFile(statefilePath) + state, err := terraform.Show(stream.Context()) + if err != nil { + return xerrors.Errorf("show state: %w", err) + } + stateData, err := json.Marshal(state) if err != nil { - return xerrors.Errorf("read file %q: %w", statefilePath, err) + return xerrors.Errorf("marshal state: %w", err) } return stream.Send(&proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ - State: statefileContent, + State: stateData, Error: errorMessage, }, }, @@ -264,7 +261,7 @@ func (t *terraform) Provision(stream proto.DRPCProvisioner_ProvisionStream) erro if start.DryRun { resp, err = parseTerraformPlan(stream.Context(), terraform, planfilePath) } else { - resp, err = parseTerraformApply(stream.Context(), terraform, statefilePath) + resp, err = parseTerraformApply(stream.Context(), terraform) } if err != nil { return err @@ -358,14 +355,10 @@ func parseTerraformPlan(ctx context.Context, terraform *tfexec.Terraform, planfi }, nil } -func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform, statefilePath string) (*proto.Provision_Response, error) { - statefileContent, err := os.ReadFile(statefilePath) +func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform) (*proto.Provision_Response, error) { + state, err := terraform.Show(ctx) if err != nil { - return nil, xerrors.Errorf("read file %q: %w", statefilePath, err) - } - state, err := terraform.ShowStateFile(ctx, statefilePath) - if err != nil { - return nil, xerrors.Errorf("show state file %q: %w", statefilePath, err) + return nil, xerrors.Errorf("show state file: %w", err) } resources := make([]*proto.Resource, 0) if state.Values != nil { @@ -498,6 +491,11 @@ func parseTerraformApply(ctx context.Context, terraform *tfexec.Terraform, state } } + statefileContent, err := json.Marshal(state) + if err != nil { + return nil, xerrors.Errorf("marshal state: %w", err) + } + return &proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index 565a4d1fc52cc..f331583c15944 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -91,7 +91,13 @@ provider "coder" { "main.tf": `variable "A" { }`, }, - Error: true, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Error: "exit status 1", + }, + }, + }, }, { Name: "single-resource", Files: map[string]string{ @@ -497,6 +503,8 @@ provider "coder" { resourcesWant, err := json.Marshal(testCase.Response.GetComplete().Resources) require.NoError(t, err) + require.Equal(t, testCase.Response.GetComplete().Error, msg.GetComplete().Error) + require.Equal(t, string(resourcesWant), string(resourcesGot)) break }