diff --git a/.changelog/35603.txt b/.changelog/35603.txt new file mode 100644 index 00000000000..4f85b5ed660 --- /dev/null +++ b/.changelog/35603.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_datazone_environment_profile +``` \ No newline at end of file diff --git a/internal/service/datazone/environment_profile.go b/internal/service/datazone/environment_profile.go new file mode 100644 index 00000000000..d318ea20543 --- /dev/null +++ b/internal/service/datazone/environment_profile.go @@ -0,0 +1,330 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package datazone + +import ( + "context" + "errors" + "fmt" + + "github.com/YakDriver/regexache" + "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-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "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/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "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/errs" + intflex "github.com/hashicorp/terraform-provider-aws/internal/flex" + "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_profile", name="Environment Profile") +func newResourceEnvironmentProfile(_ context.Context) (resource.ResourceWithConfigure, error) { + return &resourceEnvironmentProfile{}, nil +} + +const ( + ResNameEnvironmentProfile = "Environment Profile" + + environmentProfileIDParts = 2 +) + +type resourceEnvironmentProfile struct { + framework.ResourceWithConfigure +} + +func (r *resourceEnvironmentProfile) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "aws_datazone_environment_profile" +} + +func (r *resourceEnvironmentProfile) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrAWSAccountID: schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile("^\\d{12}$"), "must match ^\\d{12}$"), + }, + }, + "aws_account_region": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile("^[a-z]{2}-[a-z]{4,10}-\\d$"), "must match ^[a-z]{2}-[a-z]{4,10}-\\d$"), + }, + }, + names.AttrCreatedAt: schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + }, + "created_by": schema.StringAttribute{ + Computed: true, + }, + names.AttrDescription: schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(0, 2048), + }, + }, + "domain_identifier": schema.StringAttribute{ + Required: true, + }, + "environment_blueprint_identifier": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9_-]{1,36}$"), "must match ^[a-zA-Z0-9_-]{1,36}$"), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrID: schema.StringAttribute{ + Computed: true, + }, + names.AttrName: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile("^[\\w -]+$"), "must match ^[\\w -]+$"), + stringvalidator.LengthBetween(1, 64), + }, + }, + "project_identifier": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9_-]{1,36}$"), "must match ^[a-zA-Z0-9_-]{1,36}$"), + }, + }, + "updated_at": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "user_parameters": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[userParametersData](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrName: schema.StringAttribute{ + Optional: true, + }, + names.AttrValue: schema.StringAttribute{ + Optional: true, + }, + }, + }, + }, + }, + } +} + +func (r *resourceEnvironmentProfile) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var plan environmentProfileData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + in := &datazone.CreateEnvironmentProfileInput{} + resp.Diagnostics.Append(flex.Expand(ctx, &plan, in)...) + if resp.Diagnostics.HasError() { + return + } + in.EnvironmentBlueprintIdentifier = plan.EnvironmentBlueprintId.ValueStringPointer() + + out, err := conn.CreateEnvironmentProfile(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironmentProfile, plan.Name.String(), err), + err.Error(), + ) + return + } + if out == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironmentProfile, plan.Name.String(), nil), + errors.New("empty output").Error(), + ) + return + } + + option := flex.WithIgnoredFieldNamesAppend("UserParameters") + resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan, option)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *resourceEnvironmentProfile) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var state environmentProfileData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := findEnvironmentProfileByID(ctx, conn, state.Id.ValueString(), state.DomainIdentifier.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionReading, ResNameEnvironmentProfile, state.Id.String(), err), + err.Error(), + ) + return + } + + option := flex.WithIgnoredFieldNamesAppend("UserParameters") + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, option)...) + if resp.Diagnostics.HasError() { + return + } + state.EnvironmentBlueprintId = flex.StringToFramework(ctx, out.EnvironmentBlueprintId) + state.ProjectIdentifier = flex.StringToFramework(ctx, out.ProjectId) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceEnvironmentProfile) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var plan, state environmentProfileData + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + if !plan.Description.Equal(state.Description) || + !plan.Name.Equal(state.Name) || + !plan.UserParameters.Equal(state.UserParameters) || + !plan.AwsAccountId.Equal(state.AwsAccountId) || + !plan.AwsAccountRegion.Equal(state.AwsAccountRegion) { + in := &datazone.UpdateEnvironmentProfileInput{} + + resp.Diagnostics.Append(flex.Expand(ctx, plan, in)...) + if resp.Diagnostics.HasError() { + return + } + in.Identifier = state.Id.ValueStringPointer() + + out, err := conn.UpdateEnvironmentProfile(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionUpdating, ResNameEnvironmentProfile, state.Id.ValueString(), err), + err.Error(), + ) + return + } + + option := flex.WithIgnoredFieldNamesAppend("UserParameters") + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, option)...) + if resp.Diagnostics.HasError() { + return + } + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceEnvironmentProfile) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().DataZoneClient(ctx) + + var state environmentProfileData + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := conn.DeleteEnvironmentProfile(ctx, &datazone.DeleteEnvironmentProfileInput{ + Identifier: state.Id.ValueStringPointer(), + DomainIdentifier: state.DomainIdentifier.ValueStringPointer(), + }) + + if err != nil && !errs.IsA[*awstypes.ResourceNotFoundException](err) { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.DataZone, create.ErrActionDeleting, ResNameEnvironmentProfile, state.Id.ValueString(), err), + err.Error(), + ) + return + } +} + +func (r *resourceEnvironmentProfile) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + parts, err := intflex.ExpandResourceId(req.ID, environmentProfileIDParts, false) + if err != nil { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: id,domain_identifier. Got: %q", req.ID), + ) + return + } + + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrID), parts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), parts[1])...) +} + +func findEnvironmentProfileByID(ctx context.Context, conn *datazone.Client, id string, domainID string) (*datazone.GetEnvironmentProfileOutput, error) { + in := &datazone.GetEnvironmentProfileInput{ + Identifier: aws.String(id), + DomainIdentifier: aws.String(domainID), + } + + out, err := conn.GetEnvironmentProfile(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 environmentProfileData struct { + AwsAccountId types.String `tfsdk:"aws_account_id"` + AwsAccountRegion types.String `tfsdk:"aws_account_region"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + CreatedBy types.String `tfsdk:"created_by"` + Description types.String `tfsdk:"description"` + DomainIdentifier types.String `tfsdk:"domain_identifier"` + EnvironmentBlueprintId types.String `tfsdk:"environment_blueprint_identifier"` + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + ProjectIdentifier types.String `tfsdk:"project_identifier"` + UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at"` + UserParameters fwtypes.ListNestedObjectValueOf[userParametersData] `tfsdk:"user_parameters"` +} + +type userParametersData struct { + Name types.String `tfsdk:"name"` + Value types.String `tfsdk:"value"` +} diff --git a/internal/service/datazone/environment_profile_test.go b/internal/service/datazone/environment_profile_test.go new file mode 100644 index 00000000000..0a72d752197 --- /dev/null +++ b/internal/service/datazone/environment_profile_test.go @@ -0,0 +1,306 @@ +// 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/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/names" +) + +func TestAccDataZoneEnvironmentProfile_basic(t *testing.T) { + ctx := acctest.Context(t) + + var environmentprofile datazone.GetEnvironmentProfileOutput + epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resourceName := "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) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentProfileDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentProfileConfig_basic(epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentProfileExists(ctx, resourceName, &environmentprofile), + resource.TestCheckResourceAttrPair(resourceName, names.AttrAWSAccountID, callName, names.AttrAccountID), + resource.TestCheckResourceAttrPair(resourceName, "aws_account_region", regionName, names.AttrName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttr(resourceName, names.AttrName, epName), + resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, names.AttrID), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAuthorizerEnvProfImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"user_parameters"}, + }, + }, + }) +} + +func TestAccDataZoneEnvironmentProfile_disappears(t *testing.T) { + ctx := acctest.Context(t) + + var environmentprofile datazone.GetEnvironmentProfileOutput + epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resourceName := "aws_datazone_environment_profile.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.DataZoneEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentProfileDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentProfileConfig_basic(epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentProfileExists(ctx, resourceName, &environmentprofile), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfdatazone.ResourceEnvironmentProfile, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccDataZoneEnvironmentProfile_update(t *testing.T) { + ctx := acctest.Context(t) + + var environmentprofile datazone.GetEnvironmentProfileOutput + epName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resourceName := "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) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DataZoneServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEnvironmentProfileDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEnvironmentProfileConfig_basic(epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentProfileExists(ctx, resourceName, &environmentprofile), + resource.TestCheckResourceAttrPair(resourceName, names.AttrAWSAccountID, callName, names.AttrAccountID), + resource.TestCheckResourceAttrPair(resourceName, "aws_account_region", regionName, names.AttrName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "desc"), + resource.TestCheckResourceAttr(resourceName, "user_parameters.0.name", "consumerGlueDbName"), + resource.TestCheckResourceAttr(resourceName, "user_parameters.0.value", names.AttrValue), + resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttr(resourceName, names.AttrName, epName), + resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, names.AttrID), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAuthorizerEnvProfImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"user_parameters"}, + }, + { + Config: testAccEnvironmentProfileConfig_update(epName, dName, pName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEnvironmentProfileExists(ctx, resourceName, &environmentprofile), + testAccCheckEnvironmentProfileExists(ctx, resourceName, &environmentprofile), + resource.TestCheckResourceAttrPair(resourceName, names.AttrAWSAccountID, callName, names.AttrAccountID), + resource.TestCheckResourceAttrPair(resourceName, "aws_account_region", regionName, names.AttrName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(resourceName, "created_by"), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, names.AttrDescription), + resource.TestCheckResourceAttr(resourceName, "user_parameters.0.name", "consumerGlueDbName"), + resource.TestCheckResourceAttr(resourceName, "user_parameters.0.value", names.AttrValue), + resource.TestCheckResourceAttrPair(resourceName, "domain_identifier", domainName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "environment_blueprint_identifier", blueName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttr(resourceName, names.AttrName, epName), + resource.TestCheckResourceAttrPair(resourceName, "project_identifier", projectName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, "updated_at"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAuthorizerEnvProfImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"user_parameters"}, + }, + }, + }) +} + +func testAccCheckEnvironmentProfileDestroy(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_profile" { + continue + } + + _, err := tfdatazone.FindEnvironmentProfileByID(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["domain_identifier"]) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) || errs.IsA[*awstypes.AccessDeniedException](err) { + return nil + } + if err != nil { + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironmentProfile, rs.Primary.ID, err) + } + + return create.Error(names.DataZone, create.ErrActionCheckingDestroyed, tfdatazone.ResNameEnvironmentProfile, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckEnvironmentProfileExists(ctx context.Context, name string, environmentprofile *datazone.GetEnvironmentProfileOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironmentProfile, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironmentProfile, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).DataZoneClient(ctx) + resp, err := tfdatazone.FindEnvironmentProfileByID(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["domain_identifier"]) + + if err != nil { + return create.Error(names.DataZone, create.ErrActionCheckingExistence, tfdatazone.ResNameEnvironmentProfile, rs.Primary.ID, err) + } + + *environmentprofile = *resp + + return nil + } +} + +func testAccAuthorizerEnvProfImportStateIdFunc(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 fmt.Sprintf("%s,%s", rs.Primary.ID, rs.Primary.Attributes["domain_identifier"]), nil + } +} + +func testAccEnvironmentProfileConfig_base(domainName, projectName string) string { + return acctest.ConfigCompose( + testAccProjectConfig_basic(projectName, domainName), + ` +data "aws_caller_identity" "test" {} +data "aws_region" "test" {} + +data "aws_datazone_environment_blueprint" "test" { + domain_id = aws_datazone_domain.test.id + name = "DefaultDataLake" + managed = 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.domain_execution_role.arn + enabled_regions = [data.aws_region.test.name] +} +`) +} + +func testAccEnvironmentProfileConfig_basic(rName, domainName, projectName string) string { + return acctest.ConfigCompose( + testAccEnvironmentProfileConfig_base(domainName, projectName), + fmt.Sprintf(` +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 = "desc" + 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 testAccEnvironmentProfileConfig_update(rName, domainName, projectName string) string { + return acctest.ConfigCompose( + testAccEnvironmentProfileConfig_base(domainName, projectName), + fmt.Sprintf(` +resource "aws_datazone_environment_profile" "test" { + aws_account_id = data.aws_caller_identity.test.account_id + aws_account_region = data.aws_region.test.name + description = "description" + environment_blueprint_identifier = data.aws_datazone_environment_blueprint.test.id + name = %[1]q + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + user_parameters { + name = "consumerGlueDbName" + value = "value" + } +} +`, rName)) +} diff --git a/internal/service/datazone/exports_test.go b/internal/service/datazone/exports_test.go index f971f2cd71a..23b34b62e00 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 + ResourceEnvironmentProfile = newResourceEnvironmentProfile + FindEnvironmentProfileByID = findEnvironmentProfileByID ResourceGlossary = newResourceGlossary FindGlossaryByID = findGlossaryByID ) diff --git a/internal/service/datazone/service_package_gen.go b/internal/service/datazone/service_package_gen.go index 27d808e33a1..b7f374cebe3 100644 --- a/internal/service/datazone/service_package_gen.go +++ b/internal/service/datazone/service_package_gen.go @@ -36,6 +36,10 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic Factory: newResourceEnvironmentBlueprintConfiguration, Name: "Environment Blueprint Configuration", }, + { + Factory: newResourceEnvironmentProfile, + Name: "Environment Profile", + }, { Factory: newResourceGlossary, Name: "Glossary", diff --git a/website/docs/r/datazone_environment_profile.html.markdown b/website/docs/r/datazone_environment_profile.html.markdown new file mode 100644 index 00000000000..e3e77a9a0ab --- /dev/null +++ b/website/docs/r/datazone_environment_profile.html.markdown @@ -0,0 +1,150 @@ +--- +subcategory: "DataZone" +layout: "aws" +page_title: "AWS: aws_datazone_environment_profile" +description: |- + Terraform resource for managing an AWS DataZone Environment Profile. +--- + +# Resource: aws_datazone_environment_profile + +Terraform resource for managing an AWS DataZone Environment Profile. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_iam_role" "domain_execution_role" { + name = "example-name" + 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" + } + }, + ] + }) + + inline_policy { + name = "example-name" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "datazone:*", + "ram:*", + "sso:*", + "kms:*", + ] + Effect = "Allow" + Resource = "*" + }, + ] + }) + } +} + +resource "aws_datazone_domain" "test" { + name = "example-name" + domain_execution_role = aws_iam_role.domain_execution_role.arn +} + +resource "aws_security_group" "test" { + name = "example-name" +} + +resource "aws_datazone_project" "test" { + domain_identifier = aws_datazone_domain.test.id + glossary_terms = ["2N8w6XJCwZf"] + name = "example-name" + description = "desc" + skip_deletion_check = true +} + +data "aws_caller_identity" "test" {} +data "aws_region" "test" {} + +data "aws_datazone_environment_blueprint" "test" { + domain_id = aws_datazone_domain.test.id + name = "DefaultDataLake" + managed = 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.domain_execution_role.arn + enabled_regions = [data.aws_region.test.name] +} + +resource "aws_datazone_environment_profile" "test" { + aws_account_id = data.aws_caller_identity.test.account_id + aws_account_region = data.aws_region.test.name + description = "description" + environment_blueprint_identifier = data.aws_datazone_environment_blueprint.test.id + name = "example-name" + project_identifier = aws_datazone_project.test.id + domain_identifier = aws_datazone_domain.test.id + user_parameters { + name = "consumerGlueDbName" + value = "value" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `aws_account_id` - (Required) - Id of the AWS account being used. +* `aws_account_region` - (Required) - Desired region for environment profile. +* `domain_identifier` - (Required) - Domain Identifier for environment profile. +* `name` - (Required) - Name of the environment profile. +* `environment_blueprint_identifier` - (Required) - ID of the blueprint which the environment will be created with. +* `project_identifier` - (Required) - Project identifier for environment profile. + +The following arguments are optional: + +* `description` - (Optional) Description of environment profile. +* `user_parameters` - (Optional) - Array of user parameters of the environment profile with the following attributes: + * `name` - (Required) - Name of the environment profile parameter. + * `value` - (Required) - Value of the environment profile parameter. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `created_at` - Creation time of environment profile. +* `created_by` - Creator of environment profile. +* `id` - ID of environment profile. +* `updated_at` - Time of last update to environment profile. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DataZone Environment Profile using a comma-delimited string combining `id` and `domain_identifier`. For example: + +```terraform +import { + to = aws_datazone_environment_profile.example + id = "environment_profile-id-12345678,domain-id-12345678" +} +``` + +Using `terraform import`, import DataZone Environment Profile using a comma-delimited string combining `id` and `domain_identifier`. For example: + +```console +% terraform import aws_datazone_environment_profile.example environment_profile-id-12345678,domain-id-12345678 +```