From 308a927da5df85f28d102dc1cd34789edb7ba0b5 Mon Sep 17 00:00:00 2001 From: ThomasZalewski Date: Fri, 9 Aug 2024 16:53:14 -0400 Subject: [PATCH 01/13] Added support for datazone environment resource --- internal/service/datazone/environment.go | 541 ++++++++++++++++++ internal/service/datazone/environment_test.go | 213 +++++++ internal/service/datazone/exports_test.go | 2 + .../service/datazone/service_package_gen.go | 4 + .../docs/r/datazone_environment.html.markdown | 69 +++ 5 files changed, 829 insertions(+) create mode 100644 internal/service/datazone/environment.go create mode 100644 internal/service/datazone/environment_test.go create mode 100644 website/docs/r/datazone_environment.html.markdown diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go new file mode 100644 index 000000000000..7346b7aabe1c --- /dev/null +++ b/internal/service/datazone/environment.go @@ -0,0 +1,541 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package datazone + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/datazone" + awstypes "github.com/aws/aws-sdk-go-v2/service/datazone/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_datazone_environment", name="Environment") +func newResourceEnvironment(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceEnvironment{} + + r.SetDefaultCreateTimeout(30 * time.Minute) + r.SetDefaultUpdateTimeout(30 * time.Minute) + r.SetDefaultDeleteTimeout(30 * time.Minute) + + return r, nil +} + +const ( + ResNameEnvironment = "Environment" +) + +type resourceEnvironment struct { + framework.ResourceWithConfigure + framework.WithTimeouts +} + +func (r *resourceEnvironment) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "aws_datazone_environment" +} + +func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "description": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "environment_account_identifier": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "environment_account_region": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrCreatedAt: schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + }, + "created_by": schema.StringAttribute{ + Computed: true, + }, + "custom_parameters": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceCustomParameterData](ctx), + Computed: true, + }, + "deployment_parameters": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceDeploymentPropertiesData](ctx), // double cehck this + Computed: true, + }, + "domain_identifier": schema.StringAttribute{ + Required: true, + }, + "environment_actions": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceEnvironmentActionData](ctx), + Computed: true, + }, + "environment_blueprint_identifier": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "environment_profile_identifier": schema.StringAttribute{ + Required: true, + }, + "glossary_terms": schema.ListAttribute{ + CustomType: fwtypes.ListOfStringType, + Optional: true, + }, + "id": schema.StringAttribute{ // fix this i forgot + Computed: true, + }, + "last_deployment": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceLastDeployment](ctx), + Computed: true, + }, + "name": schema.StringAttribute{ + Required: true, + }, + "project_identifier": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "provider_environment": schema.StringAttribute{ + Computed: true, + }, + "provisioned_resources": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionedResourcesData](ctx), + Computed: true, + }, + "provisioning_properties": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionPropertiesData](ctx), + Computed: true, + }, + "status": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.EnvironmentStatus](), + Computed: true, + }, + "updated_at": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "user_parameters": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceUserParametersData](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrName: schema.StringAttribute{ + Optional: true, + }, + names.AttrValue: schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + "timeouts": timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().DataZoneClient(ctx) + var plan resourceEnvironmentData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + fmt.Printf("plan: %v\n", plan) + fmt.Printf("plan.DomainIdentifier: %v\n", plan.DomainIdentifier) + fmt.Printf("plan.ProjectIdentifier: %v\n", plan.ProjectIdentifier) + fmt.Printf("plan.EnvironmentProfileIdentifier: %v\n", plan.EnvironmentProfileIdentifier) + fmt.Printf("plan.EnvironmentBlueprintId: %v\n", plan.EnvironmentBlueprintId) + fmt.Printf("plan.AwsAccountId: %v\n", plan.AwsAccountId) + fmt.Printf("plan.AwsAccountRegion: %v\n", plan.AwsAccountRegion) + fmt.Printf("plan.Name: %v\n", plan.Name) + + option := flex.WithIgnoredFieldNames([]string{"UserParameters", "CustomParameters"}) + in := &datazone.CreateEnvironmentInput{} + resp.Diagnostics.Append(flex.Expand(ctx, &plan, in)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := conn.CreateEnvironment(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironment, plan.Name.String(), err), + err.Error(), + ) + return + } + if out == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironment, plan.Name.String(), nil), + errors.New("empty output").Error(), + ) + return + } + + resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan, option)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(flex.Flatten(ctx, out.UserParameters, &plan.CustomParameters)...) + if resp.Diagnostics.HasError() { + return + } + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) + _, err = waitEnvironmentCreated(ctx, conn, plan.DomainIdentifier.ValueString(), plan.Id.ValueString(), createTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForCreation, ResNameEnvironment, plan.Name.String(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} +func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var state resourceEnvironmentData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := findEnvironmentByID(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionSetting, ResNameEnvironment, state.Id.String(), err), + err.Error(), + ) + return + } + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} +func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + conn := r.Meta().DataZoneClient(ctx) + + // TIP: -- 2. Fetch the plan + var plan, state resourceEnvironmentData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + if !plan.Name.Equal(state.Name) || + !plan.Description.Equal(state.Description) || + !plan.GlossaryTerms.Equal(state.GlossaryTerms) { + + in := &datazone.UpdateEnvironmentInput{} + resp.Diagnostics.Append(flex.Expand(ctx, plan, in)...) + if resp.Diagnostics.HasError() { + return + } + out, err := conn.UpdateEnvironment(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionUpdating, ResNameEnvironment, plan.Id.String(), err), + err.Error(), + ) + return + } + if out == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionUpdating, ResNameEnvironment, plan.Id.String(), nil), + errors.New("empty output").Error(), + ) + return + } + + } + + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + _, err := waitEnvironmentUpdated(ctx, conn, plan.DomainIdentifier.ValueString(), plan.Id.ValueString(), updateTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForUpdate, ResNameEnvironment, plan.Id.String(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var state resourceEnvironmentData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + in := &datazone.DeleteEnvironmentInput{ + DomainIdentifier: state.DomainIdentifier.ValueStringPointer(), + Identifier: state.Id.ValueStringPointer(), + } + + _, err := conn.DeleteEnvironment(ctx, in) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionDeleting, ResNameEnvironment, state.Id.String(), err), + err.Error(), + ) + return + } + + // TIP: -- 5. Use a waiter to wait for delete to complete + deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) + _, err = waitEnvironmentDeleted(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString(), deleteTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForDeletion, ResNameEnvironment, state.Id.String(), err), + err.Error(), + ) + return + } +} + +func (r *resourceEnvironment) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + parts := strings.Split(req.ID, ":") + + if len(parts) != 2 { + resp.Diagnostics.AddError("Resource Import Invalid ID", fmt.Sprintf(`Unexpected format for import ID (%s), use: "DomainIdentifier,Id"`, req.ID)) + } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), parts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrIdentifier), parts[1])...) +} + +func waitEnvironmentCreated(ctx context.Context, conn *datazone.Client, domainId string, id string, timeout time.Duration) (*datazone.GetEnvironmentOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusCreating), + Target: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusActive), + Refresh: statusEnvironment(ctx, conn, domainId, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + return out, err + } + + return nil, err +} + +func waitEnvironmentUpdated(ctx context.Context, conn *datazone.Client, domainId string, id string, timeout time.Duration) (*datazone.GetEnvironmentOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusUpdating), + Target: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusActive), + Refresh: statusEnvironment(ctx, conn, domainId, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + return out, err + } + + return nil, err +} + +func waitEnvironmentDeleted(ctx context.Context, conn *datazone.Client, domainId string, id string, timeout time.Duration) (*datazone.GetEnvironmentOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusDeleting, awstypes.EnvironmentStatusActive), + Target: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusDeleted), + Refresh: statusEnvironment(ctx, conn, domainId, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + return out, err + } + + return nil, err +} + +func statusEnvironment(ctx context.Context, conn *datazone.Client, domainId string, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := findEnvironmentByID(ctx, conn, domainId, id) + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return out, aws.ToString((*string)(&out.Status)), nil + } +} + +func findEnvironmentByID(ctx context.Context, conn *datazone.Client, domainId string, id string) (*datazone.GetEnvironmentOutput, error) { + in := &datazone.GetEnvironmentInput{ + DomainIdentifier: aws.String(domainId), + Identifier: aws.String(id), + } + + out, err := conn.GetEnvironment(ctx, in) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out, nil +} + +type resourceEnvironmentData struct { + AwsAccountId types.String `tfsdk:"environment_account_identifier"` + AwsAccountRegion types.String `tfsdk:"environment_account_region"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + CustomParameters fwtypes.ListNestedObjectValueOf[resourceCustomParameterData] `tfsdk:"custom_parameters"` + DeploymentParameters fwtypes.ListNestedObjectValueOf[resourceDeploymentPropertiesData] `tfsdk:"deployment_parameters"` + Description types.String `tfsdk:"description"` + DomainIdentifier types.String `tfsdk:"domain_identifier"` + EnvironmentActions fwtypes.ListNestedObjectValueOf[resourceEnvironmentActionData] `tfsdk:"environment_actions"` + EnvironmentBlueprintId types.String `tfsdk:"environment_blueprint_identifier"` + EnvironmentProfileIdentifier types.String `tfsdk:"environment_profile_identifier"` + GlossaryTerms fwtypes.ListValueOf[types.String] `tfsdk:"glossary_terms"` + Id types.String `tfsdk:"id"` + LastDeployment fwtypes.ListNestedObjectValueOf[resourceLastDeployment] `tfsdk:"last_deployment"` + Name types.String `tfsdk:"name"` + ProjectIdentifier types.String `tfsdk:"project_identifier"` + Provider types.String `tfsdk:"provider_environment"` + ProvisionedResources fwtypes.ListNestedObjectValueOf[resourceProvisionedResourcesData] `tfsdk:"provisioned_resources"` + ProvisioningProperties fwtypes.ListNestedObjectValueOf[resourceProvisionPropertiesData] `tfsdk:"provisioning_properties"` + Status fwtypes.StringEnum[awstypes.EnvironmentStatus] `tfsdk:"status"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at"` + UserParameters fwtypes.ListNestedObjectValueOf[resourceUserParametersData] `tfsdk:"user_parameters"` +} + +type resourceCustomParameterData struct { + DefaultValue types.String `tfsdk:"default_value"` + Description types.String `tfsdk:"description"` + FieldType types.String `tfsdk:"field_type"` + IsEditable types.Bool `tfsdk:"is_editable"` + IsOptional types.Bool `tfsdk:"is_optional"` + KeyName types.String `tfsdk:"key_name"` +} + +type resourceDeploymentPropertiesData struct { + EndTimeoutMinutes types.Int64 `tfsdk:"is_optional"` + StartTimeoutMinutes types.Int64 `tfsdk:"key_name"` +} + +type resourceEnvironmentActionData struct { + Auth types.String `tfsdk:"auth"` + Parameters fwtypes.ListNestedObjectValueOf[resourceParametersData] `tfsdk:"parameters"` + Type types.String `tfsdk:"type"` + // awstypes.ConfigurableActionTypeAuthorization??? +} + +type resourceParametersData struct { + Key types.String `tfsdk:"key"` + Value types.String `tfsdk:"value"` +} + +type resourceLastDeployment struct { + DeploymentId types.String `tfsdk:"deployment_id"` + DeploymentStatus types.String `tfsdk:"deployment_status"` + DeploymentType fwtypes.StringEnum[awstypes.DeploymentType] `tfsdk:"deployment_type"` + FailureReasons fwtypes.ListNestedObjectValueOf[resourceFailureReasonsData] `tfsdk:"failure_reasons"` + IsDeploymentComplete types.Bool `tfsdk:"is_deployment_complete"` + Messages fwtypes.ListValueOf[types.String] `tfsdk:"messages"` +} + +type resourceFailureReasonsData struct { + Code types.String `tfsdk:"code"` + Message types.String `tfsdk:"message"` +} + +type resourceProvisionedResourcesData struct { + Name types.String `tfsdk:"name"` + Provider types.String `tfsdk:"provider"` + Type types.String `tfsdk:"type"` + Value types.String `tfsdk:"value"` +} + +type resourceProvisionPropertiesData struct { + CloudFormation types.String `tfsdk:"cloud_formation"` +} + +type resourceCloudFormationData struct { + template_url types.String `tfsdk:"template_url"` +} + +type resourceUserParametersData struct { + Name types.String `tfsdk:"name"` + Value types.String `tfsdk:"value"` +} diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go new file mode 100644 index 000000000000..b01863070c5d --- /dev/null +++ b/internal/service/datazone/environment_test.go @@ -0,0 +1,213 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package datazone_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/datazone" + "github.com/aws/aws-sdk-go-v2/service/datazone/types" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/names" + + tfdatazone "github.com/hashicorp/terraform-provider-aws/internal/service/datazone" +) + +func TestAccDataZoneEnvironment_basic(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var environment datazone.GetEnvironmentOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resourceName := "aws_datazone_environment.test" + envProfileName := "aws_datazone_environment_profile.test" + domainName := "aws_datazone_domain.test" + callName := "data.aws_caller_identity.test" + projectName := "aws_datazone_project.test" + regionName := "data.aws_region.test" + blueName := "data.aws_datazone_environment_blueprint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentConfig_basic(rName, epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentExists(ctx, resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, "description", "desc"), + resource.TestCheckResourceAttrPair(resourceName, "enviroment_account_identifier", callName, "account_id"), // fix + resource.TestCheckResourceAttrPair(resourceName, "environment_account_region", regionName, "help"), // fix + resource.TestCheckResourceAttrSet(resourceName, "created_at"), // fix + resource.TestCheckResourceAttrSet(regionName, "created_by"), + //custom parameters + //deployment parameters + resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, "id"), // check this + resource.TestCheckResourceAttrPair(resourceName, "environment_profile_identifier", envProfileName, "id"), // check this + resource.TestCheckResourceAttr(resourceName, "glossary_terms.0", "glossary_term"), + resource.TestCheckResourceAttrSet(resourceName, "id"), + // last deployment + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, "id"), + resource.TestCheckResourceAttrSet(resourceName, "provider_environment"), + // provisioned resources + resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + ), + }, + {ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"user"}, + }, + }, + }) +} + +func TestAccDataZoneEnvironment_disappears(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var environment datazone.GetEnvironmentOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_datazone_environment.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentConfig_basic(rName, epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentExists(ctx, resourceName, &environment), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfdatazone.ResourceEnvironment, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_datazone_environment" { + continue + } + + _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes["id"]) + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil + } + if err != nil { + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) + } + + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckEnvironmentExists(ctx context.Context, name string, environment *datazone.GetEnvironmentOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironment, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironment, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) + resp, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes["id"]) + + if err != nil { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) + } + + *environment = *resp + + return nil + } +} + +func testAccEnviromentPreCheck(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) + + input := &datazone.ListEnvironmentsInput{} + _, err := conn.ListEnvironments(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccCheckEnvironmentNotRecreated(before, after *datazone.GetEnvironmentOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if bf, after := aws.ToString(before.Id), aws.ToString(after.Id); bf != after { + return create.Error(names.DataZone, create.ErrActionCheckingNotRecreated, tfdatazone.ResNameEnvironment, aws.ToString(before.Id), errors.New("recreated")) + } + + return nil + } +} + +func testAccEnvironmentConfig_basic(rName, epName, dName, pName string) string { + return acctest.ConfigCompose(testAccEnvironmentProfileConfig_basic_base(epName, dName, pName), fmt.Sprintf(` + + +resource "aws_datazone_environment" "test" { + description = "desc" + environment_account_identifier = data.aws_caller_identity.test.account_id + environment_account_region = data.aws_region.test.name + environment_blueprint_identifier = data.aws_datazone_environment_blueprint.test.id + environment_profile_identifier = aws_datazone_environment_profile.test.id + glossary_terms = ["glossary_term"] + name = %[1]q + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id +} +`, rName)) +} diff --git a/internal/service/datazone/exports_test.go b/internal/service/datazone/exports_test.go index f971f2cd71a5..e428e9c22b17 100644 --- a/internal/service/datazone/exports_test.go +++ b/internal/service/datazone/exports_test.go @@ -9,6 +9,8 @@ var ( ResourceEnvironmentBlueprintConfiguration = newResourceEnvironmentBlueprintConfiguration IsResourceMissing = isResourceMissing ResourceProject = newResourceProject + ResourceEnvironment = newResourceEnvironment + FindEnvironmentByID = findEnvironmentByID ResourceGlossary = newResourceGlossary FindGlossaryByID = findGlossaryByID ) diff --git a/internal/service/datazone/service_package_gen.go b/internal/service/datazone/service_package_gen.go index 27d808e33a1a..7fed514d7889 100644 --- a/internal/service/datazone/service_package_gen.go +++ b/internal/service/datazone/service_package_gen.go @@ -32,6 +32,10 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic IdentifierAttribute: names.AttrARN, }, }, + { + Factory: newResourceEnvironment, + Name: "Environment", + }, { Factory: newResourceEnvironmentBlueprintConfiguration, Name: "Environment Blueprint Configuration", diff --git a/website/docs/r/datazone_environment.html.markdown b/website/docs/r/datazone_environment.html.markdown new file mode 100644 index 000000000000..bea083a484e6 --- /dev/null +++ b/website/docs/r/datazone_environment.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "DataZone" +layout: "aws" +page_title: "AWS: aws_datazone_environment" +description: |- + Terraform resource for managing an AWS DataZone Environment. +--- +` +# Resource: aws_datazone_environment + +Terraform resource for managing an AWS DataZone Environment. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_datazone_environment" "example" { +} +``` + +## Argument Reference + +The following arguments are required: + +* `example_arg` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +The following arguments are optional: + +* `optional_arg` - (Optional) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `arn` - ARN of the Environment. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `example_attribute` - Concise description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `60m`) +* `update` - (Default `180m`) +* `delete` - (Default `90m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment using the `example_id_arg`. For example: + +```terraform +import { + to = aws_datazone_environment.example + id = "environment-id-12345678" +} +``` + +Using `terraform import`, import DataZone Environment using the `example_id_arg`. For example: + +```console +% terraform import aws_datazone_environment.example environment-id-12345678 +``` From 9582d4ed1ca286180863a9ca643b2162b5a5950a Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 29 Aug 2024 11:50:10 -0500 Subject: [PATCH 02/13] aws_datazone_environment: reorganize schema and fmt handlers --- internal/service/datazone/environment.go | 183 +++++++++++++--------- internal/service/datazone/exports_test.go | 2 +- 2 files changed, 111 insertions(+), 74 deletions(-) diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index 7346b7aabe1c..3e115ee0d840 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -26,8 +26,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -60,15 +61,49 @@ func (r *resourceEnvironment) Metadata(_ context.Context, req resource.MetadataR func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ + names.AttrCreatedAt: schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "created_by": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "custom_parameters": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceCustomParameterData](ctx), + Computed: true, + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, + }, + "deployment_parameters": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[resourceDeploymentPropertiesData](ctx), + Computed: true, + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, + }, "description": schema.StringAttribute{ Optional: true, Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain_identifier": schema.StringAttribute{ + Required: true, }, "environment_account_identifier": schema.StringAttribute{ Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, "environment_account_region": schema.StringAttribute{ @@ -76,29 +111,15 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, - names.AttrCreatedAt: schema.StringAttribute{ - CustomType: timetypes.RFC3339Type{}, - Computed: true, - }, - "created_by": schema.StringAttribute{ - Computed: true, - }, - "custom_parameters": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceCustomParameterData](ctx), - Computed: true, - }, - "deployment_parameters": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceDeploymentPropertiesData](ctx), // double cehck this - Computed: true, - }, - "domain_identifier": schema.StringAttribute{ - Required: true, - }, "environment_actions": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[resourceEnvironmentActionData](ctx), Computed: true, + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, }, "environment_blueprint_identifier": schema.StringAttribute{ Optional: true, @@ -114,12 +135,13 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq CustomType: fwtypes.ListOfStringType, Optional: true, }, - "id": schema.StringAttribute{ // fix this i forgot - Computed: true, - }, + "id": framework.IDAttribute(), "last_deployment": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[resourceLastDeployment](ctx), Computed: true, + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, }, "name": schema.StringAttribute{ Required: true, @@ -132,6 +154,9 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq }, "provider_environment": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "provisioned_resources": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionedResourcesData](ctx), @@ -141,14 +166,6 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionPropertiesData](ctx), Computed: true, }, - "status": schema.StringAttribute{ - CustomType: fwtypes.StringEnumType[awstypes.EnvironmentStatus](), - Computed: true, - }, - "updated_at": schema.StringAttribute{ - CustomType: timetypes.RFC3339Type{}, - Computed: true, - }, }, Blocks: map[string]schema.Block{ "user_parameters": schema.ListNestedBlock{ @@ -178,28 +195,22 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { conn := r.Meta().DataZoneClient(ctx) + var plan resourceEnvironmentData resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { return } - fmt.Printf("plan: %v\n", plan) - fmt.Printf("plan.DomainIdentifier: %v\n", plan.DomainIdentifier) - fmt.Printf("plan.ProjectIdentifier: %v\n", plan.ProjectIdentifier) - fmt.Printf("plan.EnvironmentProfileIdentifier: %v\n", plan.EnvironmentProfileIdentifier) - fmt.Printf("plan.EnvironmentBlueprintId: %v\n", plan.EnvironmentBlueprintId) - fmt.Printf("plan.AwsAccountId: %v\n", plan.AwsAccountId) - fmt.Printf("plan.AwsAccountRegion: %v\n", plan.AwsAccountRegion) - fmt.Printf("plan.Name: %v\n", plan.Name) - - option := flex.WithIgnoredFieldNames([]string{"UserParameters", "CustomParameters"}) + in := &datazone.CreateEnvironmentInput{} - resp.Diagnostics.Append(flex.Expand(ctx, &plan, in)...) + resp.Diagnostics.Append(fwflex.Expand(ctx, &plan, in)...) if resp.Diagnostics.HasError() { return } out, err := conn.CreateEnvironment(ctx, in) + if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironment, plan.Name.String(), err), @@ -207,6 +218,7 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq ) return } + if out == nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironment, plan.Name.String(), nil), @@ -215,16 +227,22 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq return } - resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan, option)...) - if resp.Diagnostics.HasError() { - return - } - resp.Diagnostics.Append(flex.Flatten(ctx, out.UserParameters, &plan.CustomParameters)...) - if resp.Diagnostics.HasError() { - return - } + state := plan + state.Id = fwflex.StringToFramework(ctx, out.Id) + + //resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan, flex.WithIgnoredFieldNames([]string{"UserParameters", "CustomParameters"}))...) + //if resp.Diagnostics.HasError() { + // return + //} + // + //resp.Diagnostics.Append(flex.Flatten(ctx, out.UserParameters, &plan.CustomParameters)...) + //if resp.Diagnostics.HasError() { + // return + //} + // createTimeout := r.CreateTimeout(ctx, plan.Timeouts) - _, err = waitEnvironmentCreated(ctx, conn, plan.DomainIdentifier.ValueString(), plan.Id.ValueString(), createTimeout) + output, err := waitEnvironmentCreated(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString(), createTimeout) + if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForCreation, ResNameEnvironment, plan.Name.String(), err), @@ -233,22 +251,32 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq return } - resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + resp.Diagnostics.Append(fwflex.Flatten(ctx, output, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } + func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { conn := r.Meta().DataZoneClient(ctx) var state resourceEnvironmentData resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { return } out, err := findEnvironmentByID(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString()) if tfresource.NotFound(err) { + resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) return } + if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionSetting, ResNameEnvironment, state.Id.String(), err), @@ -256,7 +284,9 @@ func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest ) return } - resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) + + resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state)...) + if resp.Diagnostics.HasError() { return } @@ -279,10 +309,12 @@ func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateReq !plan.GlossaryTerms.Equal(state.GlossaryTerms) { in := &datazone.UpdateEnvironmentInput{} - resp.Diagnostics.Append(flex.Expand(ctx, plan, in)...) + resp.Diagnostics.Append(fwflex.Expand(ctx, plan, in)...) + if resp.Diagnostics.HasError() { return } + out, err := conn.UpdateEnvironment(ctx, in) if err != nil { resp.Diagnostics.AddError( @@ -291,6 +323,7 @@ func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateReq ) return } + if out == nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionUpdating, ResNameEnvironment, plan.Id.String(), nil), @@ -299,16 +332,16 @@ func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateReq return } - } + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + _, err = waitEnvironmentUpdated(ctx, conn, plan.DomainIdentifier.ValueString(), plan.Id.ValueString(), updateTimeout) - updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) - _, err := waitEnvironmentUpdated(ctx, conn, plan.DomainIdentifier.ValueString(), plan.Id.ValueString(), updateTimeout) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForUpdate, ResNameEnvironment, plan.Id.String(), err), - err.Error(), - ) - return + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForUpdate, ResNameEnvironment, plan.Id.String(), err), + err.Error(), + ) + return + } } resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) @@ -319,6 +352,7 @@ func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteReq var state resourceEnvironmentData resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { return } @@ -329,10 +363,12 @@ func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteReq } _, err := conn.DeleteEnvironment(ctx, in) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + if err != nil { - if errs.IsA[*awstypes.ResourceNotFoundException](err) { - return - } resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionDeleting, ResNameEnvironment, state.Id.String(), err), err.Error(), @@ -340,9 +376,9 @@ func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteReq return } - // TIP: -- 5. Use a waiter to wait for delete to complete deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) _, err = waitEnvironmentDeleted(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString(), deleteTimeout) + if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForDeletion, ResNameEnvironment, state.Id.String(), err), @@ -429,21 +465,22 @@ func statusEnvironment(ctx context.Context, conn *datazone.Client, domainId stri } } -func findEnvironmentByID(ctx context.Context, conn *datazone.Client, domainId string, id string) (*datazone.GetEnvironmentOutput, error) { +func findEnvironmentByID(ctx context.Context, conn *datazone.Client, domainId, id string) (*datazone.GetEnvironmentOutput, error) { in := &datazone.GetEnvironmentInput{ DomainIdentifier: aws.String(domainId), Identifier: aws.String(id), } out, err := conn.GetEnvironment(ctx, in) - if err != nil { - if errs.IsA[*awstypes.ResourceNotFoundException](err) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, } + } + if err != nil { return nil, err } diff --git a/internal/service/datazone/exports_test.go b/internal/service/datazone/exports_test.go index cb31a5c34c36..167ae0f6bcae 100644 --- a/internal/service/datazone/exports_test.go +++ b/internal/service/datazone/exports_test.go @@ -8,13 +8,13 @@ var ( ResourceDomain = newResourceDomain ResourceEnvironmentBlueprintConfiguration = newResourceEnvironmentBlueprintConfiguration ResourceEnvironment = newResourceEnvironment - FindEnvironmentByID = findEnvironmentByID ResourceEnvironmentProfile = newResourceEnvironmentProfile ResourceFormType = newResourceFormType ResourceGlossary = newResourceGlossary ResourceGlossaryTerm = newResourceGlossaryTerm ResourceProject = newResourceProject + FindEnvironmentByID = findEnvironmentByID FindEnvironmentProfileByID = findEnvironmentProfileByID FindFormTypeByID = findFormTypeByID FindGlossaryByID = findGlossaryByID From dfee634d45df7cc08a37920aa425cb2578a8568b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 29 Aug 2024 11:53:34 -0500 Subject: [PATCH 03/13] chore: PKG=datazone semgrep-fix --- internal/service/datazone/environment.go | 8 +++---- internal/service/datazone/environment_test.go | 24 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index 3e115ee0d840..b7a42993f073 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -88,7 +88,7 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq listplanmodifier.UseStateForUnknown(), }, }, - "description": schema.StringAttribute{ + names.AttrDescription: schema.StringAttribute{ Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ @@ -135,7 +135,7 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq CustomType: fwtypes.ListOfStringType, Optional: true, }, - "id": framework.IDAttribute(), + names.AttrID: framework.IDAttribute(), "last_deployment": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[resourceLastDeployment](ctx), Computed: true, @@ -143,7 +143,7 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq listplanmodifier.UseStateForUnknown(), }, }, - "name": schema.StringAttribute{ + names.AttrName: schema.StringAttribute{ Required: true, }, "project_identifier": schema.StringAttribute{ @@ -184,7 +184,7 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq }, }, }, - "timeouts": timeouts.Block(ctx, timeouts.Opts{ + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ Create: true, Update: true, Delete: true, diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index b01863070c5d..ef7e022928af 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -58,24 +58,24 @@ func TestAccDataZoneEnvironment_basic(t *testing.T) { Config: testAccEnvironmentConfig_basic(rName, epName, dName, pName), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), - resource.TestCheckResourceAttr(resourceName, "description", "desc"), - resource.TestCheckResourceAttrPair(resourceName, "enviroment_account_identifier", callName, "account_id"), // fix + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "desc"), + resource.TestCheckResourceAttrPair(resourceName, "enviroment_account_identifier", callName, names.AttrAccountID), // fix resource.TestCheckResourceAttrPair(resourceName, "environment_account_region", regionName, "help"), // fix - resource.TestCheckResourceAttrSet(resourceName, "created_at"), // fix + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), // fix resource.TestCheckResourceAttrSet(regionName, "created_by"), //custom parameters //deployment parameters - resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, "id"), - resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, "id"), // check this - resource.TestCheckResourceAttrPair(resourceName, "environment_profile_identifier", envProfileName, "id"), // check this + resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, names.AttrID), // check this + resource.TestCheckResourceAttrPair(resourceName, "environment_profile_identifier", envProfileName, names.AttrID), // check this resource.TestCheckResourceAttr(resourceName, "glossary_terms.0", "glossary_term"), - resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), // last deployment - resource.TestCheckResourceAttr(resourceName, "name", rName), - resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, "id"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, names.AttrID), resource.TestCheckResourceAttrSet(resourceName, "provider_environment"), // provisioned resources - resource.TestCheckResourceAttr(resourceName, "status", "ACTIVE"), + resource.TestCheckResourceAttr(resourceName, names.AttrStatus, "ACTIVE"), ), }, {ResourceName: resourceName, @@ -131,7 +131,7 @@ func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc continue } - _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes["id"]) + _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes[names.AttrID]) if errs.IsA[*types.ResourceNotFoundException](err) { return nil } @@ -158,7 +158,7 @@ func testAccCheckEnvironmentExists(ctx context.Context, name string, environment } conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) - resp, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes["id"]) + resp, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes[names.AttrID]) if err != nil { return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) From 910e96507fb62f234fd3ff10264fd82a00ea2f80 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 29 Aug 2024 16:06:04 -0500 Subject: [PATCH 04/13] aws_datazone_environment: tidy parameters --- internal/service/datazone/environment.go | 189 +++++---------- internal/service/datazone/environment_test.go | 225 +++++++++++++----- 2 files changed, 227 insertions(+), 187 deletions(-) diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index b7a42993f073..47905ff696d4 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -38,9 +38,9 @@ import ( func newResourceEnvironment(_ context.Context) (resource.ResourceWithConfigure, error) { r := &resourceEnvironment{} - r.SetDefaultCreateTimeout(30 * time.Minute) - r.SetDefaultUpdateTimeout(30 * time.Minute) - r.SetDefaultDeleteTimeout(30 * time.Minute) + r.SetDefaultCreateTimeout(10 * time.Minute) + r.SetDefaultUpdateTimeout(10 * time.Minute) + r.SetDefaultDeleteTimeout(10 * time.Minute) return r, nil } @@ -61,44 +61,15 @@ func (r *resourceEnvironment) Metadata(_ context.Context, req resource.MetadataR func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - names.AttrCreatedAt: schema.StringAttribute{ - CustomType: timetypes.RFC3339Type{}, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "created_by": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "custom_parameters": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceCustomParameterData](ctx), - Computed: true, - PlanModifiers: []planmodifier.List{ - listplanmodifier.UseStateForUnknown(), - }, - }, - "deployment_parameters": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceDeploymentPropertiesData](ctx), - Computed: true, - PlanModifiers: []planmodifier.List{ - listplanmodifier.UseStateForUnknown(), - }, - }, - names.AttrDescription: schema.StringAttribute{ + "account_identifier": schema.StringAttribute{ Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), stringplanmodifier.UseStateForUnknown(), }, }, - "domain_identifier": schema.StringAttribute{ - Required: true, - }, - "environment_account_identifier": schema.StringAttribute{ + "account_region": schema.StringAttribute{ Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ @@ -106,29 +77,33 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq stringplanmodifier.UseStateForUnknown(), }, }, - "environment_account_region": schema.StringAttribute{ + "blueprint_identifier": schema.StringAttribute{ Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), - stringplanmodifier.UseStateForUnknown(), }, }, - "environment_actions": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceEnvironmentActionData](ctx), + names.AttrCreatedAt: schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, Computed: true, - PlanModifiers: []planmodifier.List{ - listplanmodifier.UseStateForUnknown(), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - "environment_blueprint_identifier": schema.StringAttribute{ - Optional: true, + "created_by": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, }, - "environment_profile_identifier": schema.StringAttribute{ + names.AttrDescription: schema.StringAttribute{ + Optional: true, + }, + "domain_identifier": schema.StringAttribute{ + Required: true, + }, + "profile_identifier": schema.StringAttribute{ Required: true, }, "glossary_terms": schema.ListAttribute{ @@ -161,10 +136,9 @@ func (r *resourceEnvironment) Schema(ctx context.Context, req resource.SchemaReq "provisioned_resources": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionedResourcesData](ctx), Computed: true, - }, - "provisioning_properties": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[resourceProvisionPropertiesData](ctx), - Computed: true, + PlanModifiers: []planmodifier.List{ + listplanmodifier.UseStateForUnknown(), + }, }, }, Blocks: map[string]schema.Block{ @@ -204,7 +178,7 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq } in := &datazone.CreateEnvironmentInput{} - resp.Diagnostics.Append(fwflex.Expand(ctx, &plan, in)...) + resp.Diagnostics.Append(fwflex.Expand(ctx, &plan, in, fwflex.WithFieldNamePrefix("Environment"))...) if resp.Diagnostics.HasError() { return } @@ -230,16 +204,14 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq state := plan state.Id = fwflex.StringToFramework(ctx, out.Id) - //resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan, flex.WithIgnoredFieldNames([]string{"UserParameters", "CustomParameters"}))...) - //if resp.Diagnostics.HasError() { - // return - //} - // - //resp.Diagnostics.Append(flex.Flatten(ctx, out.UserParameters, &plan.CustomParameters)...) - //if resp.Diagnostics.HasError() { - // return - //} - // + // set partial state + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrID), out.Id)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), out.DomainId)...) + + if resp.Diagnostics.HasError() { + return + } + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) output, err := waitEnvironmentCreated(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString(), createTimeout) @@ -251,8 +223,7 @@ func (r *resourceEnvironment) Create(ctx context.Context, req resource.CreateReq return } - resp.Diagnostics.Append(fwflex.Flatten(ctx, output, &state)...) - + resp.Diagnostics.Append(fwflex.Flatten(ctx, output, &state, fwflex.WithIgnoredFieldNames([]string{"UserParameters"}))...) if resp.Diagnostics.HasError() { return } @@ -285,7 +256,7 @@ func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest return } - resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state)...) + resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state, fwflex.WithIgnoredFieldNamesAppend("UserParameters"))...) if resp.Diagnostics.HasError() { return @@ -296,7 +267,6 @@ func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { conn := r.Meta().DataZoneClient(ctx) - // TIP: -- 2. Fetch the plan var plan, state resourceEnvironmentData resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -314,6 +284,7 @@ func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateReq if resp.Diagnostics.HasError() { return } + in.Identifier = state.Id.ValueStringPointer() out, err := conn.UpdateEnvironment(ctx, in) if err != nil { @@ -378,7 +349,7 @@ func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteReq deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) _, err = waitEnvironmentDeleted(ctx, conn, state.DomainIdentifier.ValueString(), state.Id.ValueString(), deleteTimeout) - + if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.DataZone, create.ErrActionWaitingForDeletion, ResNameEnvironment, state.Id.String(), err), @@ -389,11 +360,13 @@ func (r *resourceEnvironment) Delete(ctx context.Context, req resource.DeleteReq } func (r *resourceEnvironment) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - parts := strings.Split(req.ID, ":") + parts := strings.Split(req.ID, ",") if len(parts) != 2 { - resp.Diagnostics.AddError("Resource Import Invalid ID", fmt.Sprintf(`Unexpected format for import ID (%s), use: "DomainIdentifier,Id"`, req.ID)) + resp.Diagnostics.AddError("resource import invalid ID", fmt.Sprintf(`Unexpected format for import ID (%s), use: "DomainIdentifier,Id"`, req.ID)) + return } + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), parts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrIdentifier), parts[1])...) } @@ -436,8 +409,8 @@ func waitEnvironmentUpdated(ctx context.Context, conn *datazone.Client, domainId func waitEnvironmentDeleted(ctx context.Context, conn *datazone.Client, domainId string, id string, timeout time.Duration) (*datazone.GetEnvironmentOutput, error) { stateConf := &retry.StateChangeConf{ - Pending: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusDeleting, awstypes.EnvironmentStatusActive), - Target: enum.Slice[awstypes.EnvironmentStatus](awstypes.EnvironmentStatusDeleted), + Pending: enum.Slice(awstypes.EnvironmentStatusDeleting, awstypes.EnvironmentStatusActive), + Target: []string{}, Refresh: statusEnvironment(ctx, conn, domainId, id), Timeout: timeout, } @@ -450,7 +423,7 @@ func waitEnvironmentDeleted(ctx context.Context, conn *datazone.Client, domainId return nil, err } -func statusEnvironment(ctx context.Context, conn *datazone.Client, domainId string, id string) retry.StateRefreshFunc { +func statusEnvironment(ctx context.Context, conn *datazone.Client, domainId, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { out, err := findEnvironmentByID(ctx, conn, domainId, id) if tfresource.NotFound(err) { @@ -461,7 +434,7 @@ func statusEnvironment(ctx context.Context, conn *datazone.Client, domainId stri return nil, "", err } - return out, aws.ToString((*string)(&out.Status)), nil + return out, string(out.Status), nil } } @@ -492,55 +465,23 @@ func findEnvironmentByID(ctx context.Context, conn *datazone.Client, domainId, i } type resourceEnvironmentData struct { - AwsAccountId types.String `tfsdk:"environment_account_identifier"` - AwsAccountRegion types.String `tfsdk:"environment_account_region"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` - CreatedBy types.String `tfsdk:"created_by"` - CustomParameters fwtypes.ListNestedObjectValueOf[resourceCustomParameterData] `tfsdk:"custom_parameters"` - DeploymentParameters fwtypes.ListNestedObjectValueOf[resourceDeploymentPropertiesData] `tfsdk:"deployment_parameters"` - Description types.String `tfsdk:"description"` - DomainIdentifier types.String `tfsdk:"domain_identifier"` - EnvironmentActions fwtypes.ListNestedObjectValueOf[resourceEnvironmentActionData] `tfsdk:"environment_actions"` - EnvironmentBlueprintId types.String `tfsdk:"environment_blueprint_identifier"` - EnvironmentProfileIdentifier types.String `tfsdk:"environment_profile_identifier"` - GlossaryTerms fwtypes.ListValueOf[types.String] `tfsdk:"glossary_terms"` - Id types.String `tfsdk:"id"` - LastDeployment fwtypes.ListNestedObjectValueOf[resourceLastDeployment] `tfsdk:"last_deployment"` - Name types.String `tfsdk:"name"` - ProjectIdentifier types.String `tfsdk:"project_identifier"` - Provider types.String `tfsdk:"provider_environment"` - ProvisionedResources fwtypes.ListNestedObjectValueOf[resourceProvisionedResourcesData] `tfsdk:"provisioned_resources"` - ProvisioningProperties fwtypes.ListNestedObjectValueOf[resourceProvisionPropertiesData] `tfsdk:"provisioning_properties"` - Status fwtypes.StringEnum[awstypes.EnvironmentStatus] `tfsdk:"status"` - Timeouts timeouts.Value `tfsdk:"timeouts"` - UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at"` - UserParameters fwtypes.ListNestedObjectValueOf[resourceUserParametersData] `tfsdk:"user_parameters"` -} - -type resourceCustomParameterData struct { - DefaultValue types.String `tfsdk:"default_value"` - Description types.String `tfsdk:"description"` - FieldType types.String `tfsdk:"field_type"` - IsEditable types.Bool `tfsdk:"is_editable"` - IsOptional types.Bool `tfsdk:"is_optional"` - KeyName types.String `tfsdk:"key_name"` -} - -type resourceDeploymentPropertiesData struct { - EndTimeoutMinutes types.Int64 `tfsdk:"is_optional"` - StartTimeoutMinutes types.Int64 `tfsdk:"key_name"` -} - -type resourceEnvironmentActionData struct { - Auth types.String `tfsdk:"auth"` - Parameters fwtypes.ListNestedObjectValueOf[resourceParametersData] `tfsdk:"parameters"` - Type types.String `tfsdk:"type"` - // awstypes.ConfigurableActionTypeAuthorization??? -} - -type resourceParametersData struct { - Key types.String `tfsdk:"key"` - Value types.String `tfsdk:"value"` + AccountIdentifier types.String `tfsdk:"account_identifier"` + AccountRegion types.String `tfsdk:"account_region"` + BlueprintId types.String `tfsdk:"blueprint_identifier"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + Description types.String `tfsdk:"description"` + DomainIdentifier types.String `tfsdk:"domain_identifier"` + ProfileIdentifier types.String `tfsdk:"profile_identifier"` + GlossaryTerms fwtypes.ListValueOf[types.String] `tfsdk:"glossary_terms"` + Id types.String `tfsdk:"id"` + LastDeployment fwtypes.ListNestedObjectValueOf[resourceLastDeployment] `tfsdk:"last_deployment"` + Name types.String `tfsdk:"name"` + ProjectIdentifier types.String `tfsdk:"project_identifier"` + Provider types.String `tfsdk:"provider_environment"` + ProvisionedResources fwtypes.ListNestedObjectValueOf[resourceProvisionedResourcesData] `tfsdk:"provisioned_resources"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + UserParameters fwtypes.ListNestedObjectValueOf[resourceUserParametersData] `tfsdk:"user_parameters"` } type resourceLastDeployment struct { @@ -564,14 +505,6 @@ type resourceProvisionedResourcesData struct { Value types.String `tfsdk:"value"` } -type resourceProvisionPropertiesData struct { - CloudFormation types.String `tfsdk:"cloud_formation"` -} - -type resourceCloudFormationData struct { - template_url types.String `tfsdk:"template_url"` -} - type resourceUserParametersData struct { Name types.String `tfsdk:"name"` Value types.String `tfsdk:"value"` diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index ef7e022928af..a7acc1bb9ff7 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -9,32 +9,23 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/datazone" - "github.com/aws/aws-sdk-go-v2/service/datazone/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" - "github.com/hashicorp/terraform-provider-aws/internal/errs" - "github.com/hashicorp/terraform-provider-aws/names" - tfdatazone "github.com/hashicorp/terraform-provider-aws/internal/service/datazone" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) func TestAccDataZoneEnvironment_basic(t *testing.T) { ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } var environment datazone.GetEnvironmentOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_datazone_environment.test" envProfileName := "aws_datazone_environment_profile.test" @@ -48,26 +39,25 @@ func TestAccDataZoneEnvironment_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) - testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckEnvironmentDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccEnvironmentConfig_basic(rName, epName, dName, pName), + Config: testAccEnvironmentConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "desc"), - resource.TestCheckResourceAttrPair(resourceName, "enviroment_account_identifier", callName, names.AttrAccountID), // fix - resource.TestCheckResourceAttrPair(resourceName, "environment_account_region", regionName, "help"), // fix - resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), // fix + resource.TestCheckResourceAttrPair(resourceName, "account_identifier", callName, names.AttrAccountID), // fix + resource.TestCheckResourceAttrPair(resourceName, "account_region", regionName, "help"), // fix + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), // fix resource.TestCheckResourceAttrSet(regionName, "created_by"), //custom parameters //deployment parameters resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), - resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, names.AttrID), // check this - resource.TestCheckResourceAttrPair(resourceName, "environment_profile_identifier", envProfileName, names.AttrID), // check this + resource.TestCheckResourceAttrPair(resourceName, "blueprint_identifier", blueName, names.AttrID), // check this + resource.TestCheckResourceAttrPair(resourceName, "profile_identifier", envProfileName, names.AttrID), // check this resource.TestCheckResourceAttr(resourceName, "glossary_terms.0", "glossary_term"), resource.TestCheckResourceAttrSet(resourceName, names.AttrID), // last deployment @@ -78,10 +68,11 @@ func TestAccDataZoneEnvironment_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, names.AttrStatus, "ACTIVE"), ), }, - {ResourceName: resourceName, + { + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"user"}, + ImportStateVerifyIgnore: []string{"user_parameters"}, }, }, }) @@ -89,29 +80,23 @@ func TestAccDataZoneEnvironment_basic(t *testing.T) { func TestAccDataZoneEnvironment_disappears(t *testing.T) { ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } var environment datazone.GetEnvironmentOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_datazone_environment.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) - testAccPreCheck(ctx, t) + // testAccEnvironmentPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckEnvironmentDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccEnvironmentConfig_basic(rName, epName, dName, pName), + Config: testAccEnvironmentConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfdatazone.ResourceEnvironment, resourceName), @@ -131,10 +116,12 @@ func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc continue } - _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes[names.AttrID]) - if errs.IsA[*types.ResourceNotFoundException](err) { - return nil + _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identifier"], rs.Primary.Attributes[names.AttrID]) + + if tfresource.NotFound(err) { + continue } + if err != nil { return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) } @@ -170,44 +157,164 @@ func testAccCheckEnvironmentExists(ctx context.Context, name string, environment } } -func testAccEnviromentPreCheck(ctx context.Context, t *testing.T) { - conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) +func testAccEnvironmentConfig_base(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = ["sts:AssumeRole", "sts:TagSession"] + Effect = "Allow" + Principal = { + Service = "datazone.amazonaws.com" + } + }, + { + Action = ["sts:AssumeRole", "sts:TagSession"] + Effect = "Allow" + Principal = { + Service = "cloudformation.amazonaws.com" + } + }, + ] + }) - input := &datazone.ListEnvironmentsInput{} - _, err := conn.ListEnvironments(ctx, input) + inline_policy { + name = local.name + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "datazone:*", + "ram:*", + "sso:*", + "kms:*", + "glue:*", + "lakeformation:*", + "s3:*", + "cloudformation:*", + "athena:*", + "iam:*", + "logs:*", + ] + Effect = "Allow" + Resource = "*" + }, + ] + }) + } +} - if acctest.PreCheckSkipError(err) { - t.Skipf("skipping acceptance testing: %s", err) - } - if err != nil { - t.Fatalf("unexpected PreCheck error: %s", err) - } +data "aws_caller_identity" "test" {} +data "aws_region" "test" {} + +data "aws_iam_session_context" "current" { + arn = data.aws_caller_identity.test.arn } -func testAccCheckEnvironmentNotRecreated(before, after *datazone.GetEnvironmentOutput) resource.TestCheckFunc { - return func(s *terraform.State) error { - if bf, after := aws.ToString(before.Id), aws.ToString(after.Id); bf != after { - return create.Error(names.DataZone, create.ErrActionCheckingNotRecreated, tfdatazone.ResNameEnvironment, aws.ToString(before.Id), errors.New("recreated")) - } +resource "aws_lakeformation_data_lake_settings" "test" { + admins = [ + data.aws_iam_session_context.current.issuer_arn, + aws_iam_role.test.arn, + ] +} - return nil - } +resource "aws_datazone_domain" "test" { + name = %[1]q + domain_execution_role = aws_iam_role.test.arn + + depends_on = [ + aws_lakeformation_data_lake_settings.test, + ] } -func testAccEnvironmentConfig_basic(rName, epName, dName, pName string) string { - return acctest.ConfigCompose(testAccEnvironmentProfileConfig_basic_base(epName, dName, pName), fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q +} +resource "aws_datazone_project" "test" { + domain_identifier = aws_datazone_domain.test.id + glossary_terms = ["2N8w6XJCwZf"] + name = %[1]q + description = %[1]q + skip_deletion_check = true +} + +data "aws_datazone_environment_blueprint" "test" { + domain_id = aws_datazone_domain.test.id + name = "DefaultDataLake" + managed = true +} +resource "aws_s3_bucket" "test" { + bucket = %[1]q + force_destroy = true +} + +resource "aws_datazone_environment_blueprint_configuration" "test" { + domain_id = aws_datazone_domain.test.id + environment_blueprint_id = data.aws_datazone_environment_blueprint.test.id + provisioning_role_arn = aws_iam_role.test.arn + manage_access_role_arn = aws_iam_role.test.arn + enabled_regions = [data.aws_region.test.name] + + regional_parameters = { + (data.aws_region.test.name) = { + "S3Location" = "s3://${aws_s3_bucket.test.bucket}" + } + } +} + +resource "aws_datazone_environment_profile" "test" { + aws_account_id = data.aws_caller_identity.test.account_id + aws_account_region = data.aws_region.test.name + environment_blueprint_identifier = data.aws_datazone_environment_blueprint.test.id + description = %[1]q + name = %[1]q + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + user_parameters { + name = "consumerGlueDbName" + value = "value" + } +} +`, rName) +} + +func testAccEnvironmentConfig_basic(rName string) string { + return acctest.ConfigCompose(testAccEnvironmentConfig_base(rName), fmt.Sprintf(` resource "aws_datazone_environment" "test" { - description = "desc" - environment_account_identifier = data.aws_caller_identity.test.account_id - environment_account_region = data.aws_region.test.name - environment_blueprint_identifier = data.aws_datazone_environment_blueprint.test.id - environment_profile_identifier = aws_datazone_environment_profile.test.id - glossary_terms = ["glossary_term"] - name = %[1]q - project_identifier = aws_datazone_project.test.id - domain_identifier = aws_datazone_domain.test.id + name = %[1]q + description = "desc" + account_identifier = data.aws_caller_identity.test.account_id + account_region = data.aws_region.test.name + blueprint_identifier = aws_datazone_environment_blueprint_configuration.test.environment_blueprint_id + profile_identifier = aws_datazone_environment_profile.test.id + glossary_terms = ["glossary_term"] + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + + user_parameters { + name = "consumerGlueDbName" + value = "%[1]s-consumer" + } + + user_parameters { + name = "producerGlueDbName" + value = "%[1]s-producer" + } + + user_parameters { + name = "workgroupName" + value = "%[1]s-workgroup" + } + + depends_on = [ + aws_lakeformation_data_lake_settings.test, + ] } `, rName)) } From aef4877b8c8a324d4719222cc184a6c21c4a257e Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 29 Aug 2024 16:08:30 -0500 Subject: [PATCH 05/13] chore: fmt tests --- internal/service/datazone/environment_test.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index a7acc1bb9ff7..21d4e093d8be 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -219,7 +219,7 @@ resource "aws_lakeformation_data_lake_settings" "test" { admins = [ data.aws_iam_session_context.current.issuer_arn, aws_iam_role.test.arn, - ] + ] } resource "aws_datazone_domain" "test" { @@ -250,7 +250,7 @@ data "aws_datazone_environment_blueprint" "test" { } resource "aws_s3_bucket" "test" { - bucket = %[1]q + bucket = %[1]q force_destroy = true } @@ -287,15 +287,15 @@ resource "aws_datazone_environment_profile" "test" { func testAccEnvironmentConfig_basic(rName string) string { return acctest.ConfigCompose(testAccEnvironmentConfig_base(rName), fmt.Sprintf(` resource "aws_datazone_environment" "test" { - name = %[1]q - description = "desc" + name = %[1]q + description = "desc" account_identifier = data.aws_caller_identity.test.account_id account_region = data.aws_region.test.name blueprint_identifier = aws_datazone_environment_blueprint_configuration.test.environment_blueprint_id profile_identifier = aws_datazone_environment_profile.test.id - glossary_terms = ["glossary_term"] - project_identifier = aws_datazone_project.test.id - domain_identifier = aws_datazone_domain.test.id + glossary_terms = ["glossary_term"] + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id user_parameters { name = "consumerGlueDbName" @@ -312,9 +312,9 @@ resource "aws_datazone_environment" "test" { value = "%[1]s-workgroup" } - depends_on = [ - aws_lakeformation_data_lake_settings.test, - ] + depends_on = [ + aws_lakeformation_data_lake_settings.test, + ] } `, rName)) } From ee4c17769f9e8bf84c48c4a2a2c4b117141382bf Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 29 Aug 2024 16:14:38 -0500 Subject: [PATCH 06/13] aws_datazone_environment: tidy documentation --- .../docs/r/datazone_environment.html.markdown | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/website/docs/r/datazone_environment.html.markdown b/website/docs/r/datazone_environment.html.markdown index bea083a484e6..aa30907de8a9 100644 --- a/website/docs/r/datazone_environment.html.markdown +++ b/website/docs/r/datazone_environment.html.markdown @@ -5,14 +5,7 @@ page_title: "AWS: aws_datazone_environment" description: |- Terraform resource for managing an AWS DataZone Environment. --- -` + # Resource: aws_datazone_environment Terraform resource for managing an AWS DataZone Environment. @@ -23,6 +16,28 @@ Terraform resource for managing an AWS DataZone Environment. ```terraform resource "aws_datazone_environment" "example" { + name = "example" + account_identifier = data.aws_caller_identity.test.account_id + account_region = data.aws_region.test.name + blueprint_identifier = aws_datazone_environment_blueprint_configuration.test.environment_blueprint_id + profile_identifier = aws_datazone_environment_profile.test.id + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + + user_parameters { + name = "consumerGlueDbName" + value = "consumer" + } + + user_parameters { + name = "producerGlueDbName" + value = "producer" + } + + user_parameters { + name = "workgroupName" + value = "workgroup" + } } ``` @@ -47,9 +62,9 @@ This resource exports the following attributes in addition to the arguments abov [Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): -* `create` - (Default `60m`) -* `update` - (Default `180m`) -* `delete` - (Default `90m`) +* `create` - (Default `10m`) +* `update` - (Default `10m`) +* `delete` - (Default `10m`) ## Import From 8052ed2060874160b8b4c7ebf710b680bb78c8ec Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 11:59:31 -0500 Subject: [PATCH 07/13] aws_datazone_environment: tidy tests --- internal/service/datazone/datazone_test.go | 20 +++ internal/service/datazone/environment.go | 11 +- internal/service/datazone/environment_test.go | 119 +++++++++--------- .../docs/r/datazone_environment.html.markdown | 2 +- 4 files changed, 90 insertions(+), 62 deletions(-) create mode 100644 internal/service/datazone/datazone_test.go diff --git a/internal/service/datazone/datazone_test.go b/internal/service/datazone/datazone_test.go new file mode 100644 index 000000000000..41f5a5ae95bf --- /dev/null +++ b/internal/service/datazone/datazone_test.go @@ -0,0 +1,20 @@ +package datazone_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccDataZone_serial(t *testing.T) { + t.Parallel() + + testCases := map[string]map[string]func(t *testing.T){ + "Environment": { + acctest.CtBasic: testAccEnvironment_basic, + acctest.CtDisappears: testAccEnvironment_disappears, + }, + } + + acctest.RunSerialTests2Levels(t, testCases, 0) +} diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index 47905ff696d4..94e401ec2717 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -256,12 +256,19 @@ func (r *resourceEnvironment) Read(ctx context.Context, req resource.ReadRequest return } - resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state, fwflex.WithIgnoredFieldNamesAppend("UserParameters"))...) + resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state, fwflex.WithIgnoredFieldNamesAppend("UserParameters"), + fwflex.WithFieldNamePrefix("Environment"), + )...) if resp.Diagnostics.HasError() { return } + state.AccountIdentifier = fwflex.StringToFramework(ctx, out.AwsAccountId) + state.AccountRegion = fwflex.StringToFramework(ctx, out.AwsAccountRegion) + state.ProjectIdentifier = fwflex.StringToFramework(ctx, out.ProjectId) + state.ProfileIdentifier = fwflex.StringToFramework(ctx, out.EnvironmentProfileId) + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { @@ -368,7 +375,7 @@ func (r *resourceEnvironment) ImportState(ctx context.Context, req resource.Impo } resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), parts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrIdentifier), parts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrID), parts[1])...) } func waitEnvironmentCreated(ctx context.Context, conn *datazone.Client, domainId string, id string, timeout time.Duration) (*datazone.GetEnvironmentOutput, error) { diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index 21d4e093d8be..c83f15f21c91 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -7,35 +7,31 @@ import ( "context" "errors" "fmt" + "strings" "testing" "github.com/aws/aws-sdk-go-v2/service/datazone" + awstypes "github.com/aws/aws-sdk-go-v2/service/datazone/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tfdatazone "github.com/hashicorp/terraform-provider-aws/internal/service/datazone" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccDataZoneEnvironment_basic(t *testing.T) { +func testAccEnvironment_basic(t *testing.T) { ctx := acctest.Context(t) var environment datazone.GetEnvironmentOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_datazone_environment.test" - envProfileName := "aws_datazone_environment_profile.test" - domainName := "aws_datazone_domain.test" - callName := "data.aws_caller_identity.test" - projectName := "aws_datazone_project.test" - regionName := "data.aws_region.test" - blueName := "data.aws_datazone_environment_blueprint.test" - - resource.ParallelTest(t, resource.TestCase{ + + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) @@ -48,48 +44,43 @@ func TestAccDataZoneEnvironment_basic(t *testing.T) { Config: testAccEnvironmentConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "desc"), - resource.TestCheckResourceAttrPair(resourceName, "account_identifier", callName, names.AttrAccountID), // fix - resource.TestCheckResourceAttrPair(resourceName, "account_region", regionName, "help"), // fix - resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), // fix - resource.TestCheckResourceAttrSet(regionName, "created_by"), - //custom parameters - //deployment parameters - resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), - resource.TestCheckResourceAttrPair(resourceName, "blueprint_identifier", blueName, names.AttrID), // check this - resource.TestCheckResourceAttrPair(resourceName, "profile_identifier", envProfileName, names.AttrID), // check this - resource.TestCheckResourceAttr(resourceName, "glossary_terms.0", "glossary_term"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrID), - // last deployment resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, names.AttrID), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), + resource.TestCheckResourceAttrSet(resourceName, "account_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "account_region"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrSet(resourceName, "domain_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "blueprint_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "profile_identifier"), + resource.TestCheckResourceAttr(resourceName, "user_parameters.#", acctest.Ct3), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, "project_identifier"), resource.TestCheckResourceAttrSet(resourceName, "provider_environment"), - // provisioned resources - resource.TestCheckResourceAttr(resourceName, names.AttrStatus, "ACTIVE"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateIdFunc: testAccEnvironmentImportStateFunc(resourceName), ImportStateVerifyIgnore: []string{"user_parameters"}, }, }, }) } -func TestAccDataZoneEnvironment_disappears(t *testing.T) { +func testAccEnvironment_disappears(t *testing.T) { ctx := acctest.Context(t) var environment datazone.GetEnvironmentOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_datazone_environment.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) - // testAccEnvironmentPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, @@ -107,29 +98,13 @@ func TestAccDataZoneEnvironment_disappears(t *testing.T) { }) } -func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_datazone_environment" { - continue - } - - _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identifier"], rs.Primary.Attributes[names.AttrID]) - - if tfresource.NotFound(err) { - continue - } - - if err != nil { - return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) - } - - return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, errors.New("not destroyed")) +func testAccEnvironmentImportStateFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) } - - return nil + return strings.Join([]string{rs.Primary.Attributes["domain_identifier"], rs.Primary.ID}, ","), nil } } @@ -145,7 +120,7 @@ func testAccCheckEnvironmentExists(ctx context.Context, name string, environment } conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) - resp, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identfier"], rs.Primary.Attributes[names.AttrID]) + resp, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identifier"], rs.Primary.ID) if err != nil { return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) @@ -157,6 +132,37 @@ func testAccCheckEnvironmentExists(ctx context.Context, name string, environment } } +func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_datazone_environment" { + continue + } + + _, err := tfdatazone.FindEnvironmentByID(ctx, conn, rs.Primary.Attributes["domain_identifier"], rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + // returns access denied if domain is already destroyed + if errs.IsA[*awstypes.AccessDeniedException](err) { + continue + } + + if err != nil { + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) + } + + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + func testAccEnvironmentConfig_base(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { @@ -182,7 +188,7 @@ resource "aws_iam_role" "test" { }) inline_policy { - name = local.name + name = %[1]q policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -225,10 +231,6 @@ resource "aws_lakeformation_data_lake_settings" "test" { resource "aws_datazone_domain" "test" { name = %[1]q domain_execution_role = aws_iam_role.test.arn - - depends_on = [ - aws_lakeformation_data_lake_settings.test, - ] } resource "aws_security_group" "test" { @@ -288,12 +290,11 @@ func testAccEnvironmentConfig_basic(rName string) string { return acctest.ConfigCompose(testAccEnvironmentConfig_base(rName), fmt.Sprintf(` resource "aws_datazone_environment" "test" { name = %[1]q - description = "desc" + description = %[1]q account_identifier = data.aws_caller_identity.test.account_id account_region = data.aws_region.test.name blueprint_identifier = aws_datazone_environment_blueprint_configuration.test.environment_blueprint_id profile_identifier = aws_datazone_environment_profile.test.id - glossary_terms = ["glossary_term"] project_identifier = aws_datazone_project.test.id domain_identifier = aws_datazone_domain.test.id diff --git a/website/docs/r/datazone_environment.html.markdown b/website/docs/r/datazone_environment.html.markdown index aa30907de8a9..dd56c8e250ce 100644 --- a/website/docs/r/datazone_environment.html.markdown +++ b/website/docs/r/datazone_environment.html.markdown @@ -68,7 +68,7 @@ This resource exports the following attributes in addition to the arguments abov ## Import -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment using the `example_id_arg`. For example: +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment using the `domain_identifier`,`id`. For example: ```terraform import { From 84cf462680b8387a345f74499c0697419e0436d3 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 12:43:16 -0500 Subject: [PATCH 08/13] add better error messaging to waiters --- internal/service/datazone/datazone_test.go | 4 ++ internal/service/datazone/environment.go | 11 +++- internal/service/datazone/environment_test.go | 55 ++++++++++++++++--- .../docs/r/datazone_environment.html.markdown | 9 ++- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/internal/service/datazone/datazone_test.go b/internal/service/datazone/datazone_test.go index 41f5a5ae95bf..1d0f50f9cd1d 100644 --- a/internal/service/datazone/datazone_test.go +++ b/internal/service/datazone/datazone_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package datazone_test import ( @@ -13,6 +16,7 @@ func TestAccDataZone_serial(t *testing.T) { "Environment": { acctest.CtBasic: testAccEnvironment_basic, acctest.CtDisappears: testAccEnvironment_disappears, + "update": testAccEnvironment_update, }, } diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index 94e401ec2717..96e2a092b49e 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -390,6 +390,9 @@ func waitEnvironmentCreated(ctx context.Context, conn *datazone.Client, domainId outputRaw, err := stateConf.WaitForStateContext(ctx) if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + if status, deployment := out.Status, out.LastDeployment; status == awstypes.EnvironmentStatusCreateFailed && deployment != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", status, aws.ToString(deployment.FailureReason.Message))) + } return out, err } @@ -408,6 +411,9 @@ func waitEnvironmentUpdated(ctx context.Context, conn *datazone.Client, domainId outputRaw, err := stateConf.WaitForStateContext(ctx) if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + if status, deployment := out.Status, out.LastDeployment; status == awstypes.EnvironmentStatusUpdateFailed && deployment != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", status, aws.ToString(deployment.FailureReason.Message))) + } return out, err } @@ -424,6 +430,9 @@ func waitEnvironmentDeleted(ctx context.Context, conn *datazone.Client, domainId outputRaw, err := stateConf.WaitForStateContext(ctx) if out, ok := outputRaw.(*datazone.GetEnvironmentOutput); ok { + if status, deployment := out.Status, out.LastDeployment; status == awstypes.EnvironmentStatusDeleteFailed && deployment != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", status, aws.ToString(deployment.FailureReason.Message))) + } return out, err } @@ -453,7 +462,7 @@ func findEnvironmentByID(ctx context.Context, conn *datazone.Client, domainId, i out, err := conn.GetEnvironment(ctx, in) - if errs.IsA[*awstypes.ResourceNotFoundException](err) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) || errs.IsA[*awstypes.AccessDeniedException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: in, diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index c83f15f21c91..795a183596af 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -11,14 +11,12 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/datazone" - awstypes "github.com/aws/aws-sdk-go-v2/service/datazone/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" - "github.com/hashicorp/terraform-provider-aws/internal/errs" tfdatazone "github.com/hashicorp/terraform-provider-aws/internal/service/datazone" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -98,6 +96,54 @@ func testAccEnvironment_disappears(t *testing.T) { }) } +func testAccEnvironment_update(t *testing.T) { + ctx := acctest.Context(t) + + var environment datazone.GetEnvironmentOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdate := fmt.Sprintf("%s-update", rName) + resourceName := "aws_datazone_environment.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentExists(ctx, resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), + resource.TestCheckResourceAttrSet(resourceName, "account_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "account_region"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrSet(resourceName, "domain_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "blueprint_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "profile_identifier"), + resource.TestCheckResourceAttr(resourceName, "user_parameters.#", acctest.Ct3), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, "project_identifier"), + resource.TestCheckResourceAttrSet(resourceName, "provider_environment"), + ), + }, + { + Config: testAccEnvironmentConfig_basic(rNameUpdate), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentExists(ctx, resourceName, &environment), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdate), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rNameUpdate), + ), + }, + }, + }) +} + func testAccEnvironmentImportStateFunc(resourceName string) resource.ImportStateIdFunc { return func(s *terraform.State) (string, error) { rs, ok := s.RootModule().Resources[resourceName] @@ -147,11 +193,6 @@ func testAccCheckEnvironmentDestroy(ctx context.Context) resource.TestCheckFunc continue } - // returns access denied if domain is already destroyed - if errs.IsA[*awstypes.AccessDeniedException](err) { - continue - } - if err != nil { return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironment, rs.Primary.ID, err) } diff --git a/website/docs/r/datazone_environment.html.markdown b/website/docs/r/datazone_environment.html.markdown index dd56c8e250ce..2d9490b64b91 100644 --- a/website/docs/r/datazone_environment.html.markdown +++ b/website/docs/r/datazone_environment.html.markdown @@ -45,16 +45,21 @@ resource "aws_datazone_environment" "example" { The following arguments are required: -* `example_arg` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `account_identifier` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. The following arguments are optional: -* `optional_arg` - (Optional) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `account_identifier` - (Optional) The ID of the Amazon Web Services account where the environment exists +* `account_region` - (Optional) The Amazon Web Services region where the environment exists. +* `blueprint_identifier` - (Optional) The blueprint with which the environment is created. +* `descrioption` - (Optional) The description of the environment. ## Attribute Reference This resource exports the following attributes in addition to the arguments above: +* `created_at` - The time the environment was created. +* `created_by` - The user who created the environment. * `arn` - ARN of the Environment. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. * `example_attribute` - Concise description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. From 8ccc19a7bd28304656c0b140bc19a5c71e0932e8 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 12:48:44 -0500 Subject: [PATCH 09/13] aws_datazone_domain: add skip_deletion_check attribute --- internal/service/datazone/domain.go | 12 ++++++++++++ internal/service/datazone/domain_test.go | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/internal/service/datazone/domain.go b/internal/service/datazone/domain.go index 6b6b258733a8..c0dafa136772 100644 --- a/internal/service/datazone/domain.go +++ b/internal/service/datazone/domain.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" @@ -90,6 +91,12 @@ func (r *resourceDomain) Schema(ctx context.Context, req resource.SchemaRequest, stringplanmodifier.UseStateForUnknown(), }, }, + "skip_deletion_check": schema.BoolAttribute{ + Optional: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), }, @@ -326,6 +333,10 @@ func (r *resourceDomain) Delete(ctx context.Context, req resource.DeleteRequest, Identifier: aws.String(state.ID.ValueString()), } + if !state.SkipDeletionCheck.IsNull() { + in.SkipDeletionCheck = state.SkipDeletionCheck.ValueBoolPointer() + } + _, err := conn.DeleteDomain(ctx, in) if err != nil { if isResourceMissing(err) { @@ -477,6 +488,7 @@ type domainResourceModel struct { KmsKeyIdentifier fwtypes.ARN `tfsdk:"kms_key_identifier"` Name types.String `tfsdk:"name"` PortalUrl types.String `tfsdk:"portal_url"` + SkipDeletionCheck types.Bool `tfsdk:"skip_deletion_check"` SingleSignOn types.List `tfsdk:"single_sign_on"` Tags types.Map `tfsdk:"tags"` TagsAll types.Map `tfsdk:"tags_all"` diff --git a/internal/service/datazone/domain_test.go b/internal/service/datazone/domain_test.go index ea70756d0821..c23682a5beaf 100644 --- a/internal/service/datazone/domain_test.go +++ b/internal/service/datazone/domain_test.go @@ -51,7 +51,7 @@ func TestAccDataZoneDomain_basic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user"}, + ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user", "skip_deletion_check"}, }, }, }) @@ -113,7 +113,7 @@ func TestAccDataZoneDomain_kms_key_identifier(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user"}, + ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user", "skip_deletion_check"}, }, }, }) @@ -148,7 +148,7 @@ func TestAccDataZoneDomain_description(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user"}, + ImportStateVerifyIgnore: []string{names.AttrApplyImmediately, "user", "skip_deletion_check"}, }, }, }) @@ -182,7 +182,7 @@ func TestAccDataZoneDomain_single_sign_on(t *testing.T) { ImportState: true, ImportStateVerify: true, // we do not set single_sign_on if it's the default value - ImportStateVerifyIgnore: []string{"single_sign_on"}, + ImportStateVerifyIgnore: []string{"single_sign_on", "skip_deletion_check"}, }, }, }) From bc0cb8304cb0bcb04f21d84e992e03bc1b03902f Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 12:59:54 -0500 Subject: [PATCH 10/13] aws_datazone_environment: tidy tests --- internal/service/datazone/environment_test.go | 40 ++++++++++++++++++- website/docs/r/datazone_domain.html.markdown | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/internal/service/datazone/environment_test.go b/internal/service/datazone/environment_test.go index 795a183596af..b91621953679 100644 --- a/internal/service/datazone/environment_test.go +++ b/internal/service/datazone/environment_test.go @@ -114,7 +114,7 @@ func testAccEnvironment_update(t *testing.T) { CheckDestroy: testAccCheckEnvironmentDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccEnvironmentConfig_basic(rName), + Config: testAccEnvironmentConfig_update(rName, rName), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -133,7 +133,7 @@ func testAccEnvironment_update(t *testing.T) { ), }, { - Config: testAccEnvironmentConfig_basic(rNameUpdate), + Config: testAccEnvironmentConfig_update(rName, rNameUpdate), Check: resource.ComposeTestCheckFunc( testAccCheckEnvironmentExists(ctx, resourceName, &environment), resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdate), @@ -272,6 +272,8 @@ resource "aws_lakeformation_data_lake_settings" "test" { resource "aws_datazone_domain" "test" { name = %[1]q domain_execution_role = aws_iam_role.test.arn + + skip_deletion_check = true } resource "aws_security_group" "test" { @@ -360,3 +362,37 @@ resource "aws_datazone_environment" "test" { } `, rName)) } + +func testAccEnvironmentConfig_update(rName, rNameUpdated string) string { + return acctest.ConfigCompose(testAccEnvironmentConfig_base(rName), fmt.Sprintf(` +resource "aws_datazone_environment" "test" { + name = %[2]q + description = %[2]q + account_identifier = data.aws_caller_identity.test.account_id + account_region = data.aws_region.test.name + blueprint_identifier = aws_datazone_environment_blueprint_configuration.test.environment_blueprint_id + profile_identifier = aws_datazone_environment_profile.test.id + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + + user_parameters { + name = "consumerGlueDbName" + value = "%[1]s-consumer" + } + + user_parameters { + name = "producerGlueDbName" + value = "%[1]s-producer" + } + + user_parameters { + name = "workgroupName" + value = "%[1]s-workgroup" + } + + depends_on = [ + aws_lakeformation_data_lake_settings.test, + ] +} +`, rName, rNameUpdated)) +} diff --git a/website/docs/r/datazone_domain.html.markdown b/website/docs/r/datazone_domain.html.markdown index 8a386a6a73d0..12c4255b37b8 100644 --- a/website/docs/r/datazone_domain.html.markdown +++ b/website/docs/r/datazone_domain.html.markdown @@ -76,6 +76,7 @@ The following arguments are optional: * `description` - (Optional) Description of the Domain. * `kms_key_identifier` - (Optional) ARN of the KMS key used to encrypt the Amazon DataZone domain, metadata and reporting data. * `single_sign_on` - (Optional) Single sign on options, used to [enable AWS IAM Identity Center](https://docs.aws.amazon.com/datazone/latest/userguide/enable-IAM-identity-center-for-datazone.html) for DataZone. +* `skip_deletion_check` - (Optional) Whether to skip the deletion check for the Domain. ## Attribute Reference From 1a07ee594dd87b66ddada23cef17af32eb8c7e64 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 13:27:18 -0500 Subject: [PATCH 11/13] aws_datazone_environment: update documentation --- .../docs/r/datazone_environment.html.markdown | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/website/docs/r/datazone_environment.html.markdown b/website/docs/r/datazone_environment.html.markdown index 2d9490b64b91..2d02882502fd 100644 --- a/website/docs/r/datazone_environment.html.markdown +++ b/website/docs/r/datazone_environment.html.markdown @@ -46,6 +46,10 @@ resource "aws_datazone_environment" "example" { The following arguments are required: * `account_identifier` - (Required) Concise argument description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `domain_identifier` - (Required) The ID of the domain where the environment exists. +* `name` - (Required) The name of the environment. +* `profile_identifier` - (Required) The ID of the profile with which the environment is created. +* `project_identifier` - (Required) The ID of the project where the environment exists. The following arguments are optional: @@ -53,6 +57,13 @@ The following arguments are optional: * `account_region` - (Optional) The Amazon Web Services region where the environment exists. * `blueprint_identifier` - (Optional) The blueprint with which the environment is created. * `descrioption` - (Optional) The description of the environment. +* `glossary_terms` - (Optional) The business glossary terms that can be used in this environment. +* `user_parameters` - (Optional) The user parameters that are used in the environment. See [User Parameters](#user-parameters) for more information. + +### User Parameters + +* `name` - (Required) The name of an environment profile parameter. +* `value` - (Required) The value of an environment profile parameter. ## Attribute Reference @@ -60,8 +71,10 @@ This resource exports the following attributes in addition to the arguments abov * `created_at` - The time the environment was created. * `created_by` - The user who created the environment. -* `arn` - ARN of the Environment. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. -* `example_attribute` - Concise description. Do not begin the description with "An", "The", "Defines", "Indicates", or "Specifies," as these are verbose. In other words, "Indicates the amount of storage," can be rewritten as "Amount of storage," without losing any information. +* `id` - The ID of the environment. +* `last_deployment` - The details of the last deployment of the environment. +* `provider_environment` - The provider of the environment. +* `provisioned_resource` - The provisioned resources of this environment ## Timeouts @@ -73,17 +86,17 @@ This resource exports the following attributes in addition to the arguments abov ## Import -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment using the `domain_identifier`,`id`. For example: +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment using the `domain_identifier,id`. For example: ```terraform import { to = aws_datazone_environment.example - id = "environment-id-12345678" + id = "dzd_d2i7tzk3tnjjf4,5vpywijpwryec0" } ``` -Using `terraform import`, import DataZone Environment using the `example_id_arg`. For example: +Using `terraform import`, import DataZone Environment using the `domain_idntifier,id`. For example: ```console -% terraform import aws_datazone_environment.example environment-id-12345678 +% terraform import aws_datazone_environment.example dzd_d2i7tzk3tnjjf4,5vpywijpwryec0 ``` From c6e061ae2bc2087b02be7b7f122614622feec512 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 13:29:42 -0500 Subject: [PATCH 12/13] add CHANGELOG entry --- .changelog/38811.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/38811.txt diff --git a/.changelog/38811.txt b/.changelog/38811.txt new file mode 100644 index 000000000000..008a0ced551f --- /dev/null +++ b/.changelog/38811.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_datazone_domain: Add `skip_deletion_protection` attribute +``` + +```release-note:new-resource +aws_datazone_environment +``` \ No newline at end of file From 5a0cf7f3508e64091ec588de7d6379cadfc56ce1 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 30 Aug 2024 13:43:48 -0500 Subject: [PATCH 13/13] chore: golangci-lint --- internal/service/datazone/environment.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/datazone/environment.go b/internal/service/datazone/environment.go index 96e2a092b49e..b9ce1c4282fb 100644 --- a/internal/service/datazone/environment.go +++ b/internal/service/datazone/environment.go @@ -284,7 +284,6 @@ func (r *resourceEnvironment) Update(ctx context.Context, req resource.UpdateReq if !plan.Name.Equal(state.Name) || !plan.Description.Equal(state.Description) || !plan.GlossaryTerms.Equal(state.GlossaryTerms) { - in := &datazone.UpdateEnvironmentInput{} resp.Diagnostics.Append(fwflex.Expand(ctx, plan, in)...)