diff --git a/.changelog/44875.txt b/.changelog/44875.txt new file mode 100644 index 000000000000..a18e014146e1 --- /dev/null +++ b/.changelog/44875.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_fis_target_account_configuration +``` \ No newline at end of file diff --git a/internal/service/fis/exports_test.go b/internal/service/fis/exports_test.go index d22424e77e12..e37a2ba30d29 100644 --- a/internal/service/fis/exports_test.go +++ b/internal/service/fis/exports_test.go @@ -8,4 +8,8 @@ var ( ResourceExperimentTemplate = resourceExperimentTemplate FindExperimentTemplateByID = findExperimentTemplateByID + + ResourceTargetAccountConfiguration = newResourceTargetAccountConfiguration + + FindTargetAccountConfigurationByID = findTargetAccountConfigurationByID ) diff --git a/internal/service/fis/service_package_gen.go b/internal/service/fis/service_package_gen.go index 248151156c33..fd9ca82939a2 100644 --- a/internal/service/fis/service_package_gen.go +++ b/internal/service/fis/service_package_gen.go @@ -29,7 +29,14 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S } func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.ServicePackageFrameworkResource { - return []*inttypes.ServicePackageFrameworkResource{} + return []*inttypes.ServicePackageFrameworkResource{ + { + Factory: newResourceTargetAccountConfiguration, + TypeName: "aws_fis_target_account_configuration", + Name: "Target Account Configuration", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*inttypes.ServicePackageSDKDataSource { diff --git a/internal/service/fis/sweep.go b/internal/service/fis/sweep.go index 3ab41eb1dd00..2ce192ff039a 100644 --- a/internal/service/fis/sweep.go +++ b/internal/service/fis/sweep.go @@ -6,15 +6,19 @@ package fis import ( "context" + "github.com/YakDriver/smarterr" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/fis" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/sweep" "github.com/hashicorp/terraform-provider-aws/internal/sweep/awsv2" + sweepfw "github.com/hashicorp/terraform-provider-aws/internal/sweep/framework" + "github.com/hashicorp/terraform-provider-aws/names" ) func RegisterSweepers() { awsv2.Register("aws_fis_experiment_template", sweepExperimentTemplates) + awsv2.Register("aws_fis_target_account_configuration", sweepTargetAccountConfigurations) } func sweepExperimentTemplates(ctx context.Context, client *conns.AWSClient) ([]sweep.Sweepable, error) { @@ -41,3 +45,43 @@ func sweepExperimentTemplates(ctx context.Context, client *conns.AWSClient) ([]s return sweepResources, nil } + +func sweepTargetAccountConfigurations(ctx context.Context, client *conns.AWSClient) ([]sweep.Sweepable, error) { + conn := client.FISClient(ctx) + var sweepResources []sweep.Sweepable + + experimentsInput := &fis.ListExperimentTemplatesInput{} + experimentPages := fis.NewListExperimentTemplatesPaginator(conn, experimentsInput) + + for experimentPages.HasMorePages() { + experimentPage, err := experimentPages.NextPage(ctx) + if err != nil { + return nil, smarterr.NewError(err) + } + + for _, experiment := range experimentPage.ExperimentTemplates { + input := &fis.ListTargetAccountConfigurationsInput{ + ExperimentTemplateId: experiment.Id, + } + + pages := fis.NewListTargetAccountConfigurationsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + if err != nil { + return nil, smarterr.NewError(err) + } + + for _, v := range page.TargetAccountConfigurations { + sweepResources = append(sweepResources, sweepfw.NewSweepResource( + newResourceTargetAccountConfiguration, + client, + sweepfw.NewAttribute(names.AttrAccountID, aws.ToString(v.AccountId)), + sweepfw.NewAttribute("experiment_template_id", aws.ToString(experiment.Id)), + )) + } + } + } + } + + return sweepResources, nil +} diff --git a/internal/service/fis/target_account_configuration.go b/internal/service/fis/target_account_configuration.go new file mode 100644 index 000000000000..c0088b3dd506 --- /dev/null +++ b/internal/service/fis/target_account_configuration.go @@ -0,0 +1,245 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package fis + +import ( + "context" + "errors" + "fmt" + + "github.com/YakDriver/smarterr" + "github.com/aws/aws-sdk-go-v2/service/fis" + awstypes "github.com/aws/aws-sdk-go-v2/service/fis/types" + "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/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + 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" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_fis_target_account_configuration", name="Target Account Configuration") +func newResourceTargetAccountConfiguration(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceTargetAccountConfiguration{} + return r, nil +} + +const ( + ResNameTargetAccountConfiguration = "Target Account Configuration" +) + +type resourceTargetAccountConfiguration struct { + framework.ResourceWithModel[resourceTargetAccountConfigurationModel] +} + +func (r *resourceTargetAccountConfiguration) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrAccountID: schema.StringAttribute{ + Required: true, + Validators: []validator.String{stringvalidator.LengthBetween(12, 48)}, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrDescription: schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{stringvalidator.LengthAtMost(512)}, + }, + "experiment_template_id": schema.StringAttribute{ + Required: true, + Validators: []validator.String{stringvalidator.LengthBetween(1, 64)}, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrRoleARN: schema.StringAttribute{ + Optional: true, + Computed: true, + Validators: []validator.String{stringvalidator.LengthBetween(20, 2048)}, + }, + }, + } +} + +func (r *resourceTargetAccountConfiguration) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().FISClient(ctx) + + var plan resourceTargetAccountConfigurationModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Plan.Get(ctx, &plan)) + if resp.Diagnostics.HasError() { + return + } + + var input fis.CreateTargetAccountConfigurationInput + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Expand(ctx, plan, &input)) + if resp.Diagnostics.HasError() { + return + } + + out, err := conn.CreateTargetAccountConfiguration(ctx, &input) + if err != nil { + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, plan.ExperimentTemplateId.String()) + return + } + if out == nil || out.TargetAccountConfiguration == nil { + smerr.AddError(ctx, &resp.Diagnostics, errors.New("empty output"), smerr.ID, plan.ExperimentTemplateId.String()) + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &plan)) + if resp.Diagnostics.HasError() { + return + } + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, plan)) +} + +func (r *resourceTargetAccountConfiguration) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().FISClient(ctx) + + var state resourceTargetAccountConfigurationModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.State.Get(ctx, &state)) + if resp.Diagnostics.HasError() { + return + } + + out, err := findTargetAccountConfigurationByID(ctx, conn, state.AccountId.ValueStringPointer(), state.ExperimentTemplateId.ValueStringPointer()) + if tfresource.NotFound(err) { + resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + resp.State.RemoveResource(ctx) + return + } + if err != nil { + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, state.ExperimentTemplateId.String()) + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &state)) + if resp.Diagnostics.HasError() { + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &state)) +} + +func (r *resourceTargetAccountConfiguration) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + conn := r.Meta().FISClient(ctx) + + var plan, state resourceTargetAccountConfigurationModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Plan.Get(ctx, &plan)) + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.State.Get(ctx, &state)) + if resp.Diagnostics.HasError() { + return + } + + diff, d := flex.Diff(ctx, plan, state) + smerr.EnrichAppend(ctx, &resp.Diagnostics, d) + if resp.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { + var input fis.UpdateTargetAccountConfigurationInput + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Expand(ctx, plan, &input)) + if resp.Diagnostics.HasError() { + return + } + + out, err := conn.UpdateTargetAccountConfiguration(ctx, &input) + if err != nil { + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, plan.ExperimentTemplateId.String()) + return + } + if out == nil || out.TargetAccountConfiguration == nil { + smerr.AddError(ctx, &resp.Diagnostics, errors.New("empty output"), smerr.ID, plan.ExperimentTemplateId.String()) + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &plan)) + if resp.Diagnostics.HasError() { + return + } + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &plan)) +} + +func (r *resourceTargetAccountConfiguration) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().FISClient(ctx) + + var state resourceTargetAccountConfigurationModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.State.Get(ctx, &state)) + if resp.Diagnostics.HasError() { + return + } + input := fis.DeleteTargetAccountConfigurationInput{ + AccountId: state.AccountId.ValueStringPointer(), + ExperimentTemplateId: state.ExperimentTemplateId.ValueStringPointer(), + } + _, err := conn.DeleteTargetAccountConfiguration(ctx, &input) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, state.ExperimentTemplateId.String()) + return + } +} + +func (r *resourceTargetAccountConfiguration) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + const idParts = 2 + parts, err := intflex.ExpandResourceId(req.ID, idParts, false) + if err != nil { + resp.Diagnostics.AddError("Resource Import Invalid ID", fmt.Sprintf(`Unexpected format for import ID (%s), use: "account_id,experiment_template_id"`, req.ID)) + return + } + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.SetAttribute(ctx, path.Root(names.AttrAccountID), parts[0])) + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.SetAttribute(ctx, path.Root("experiment_template_id"), parts[1])) +} + +func findTargetAccountConfigurationByID(ctx context.Context, conn *fis.Client, accountId, experimentId *string) (*awstypes.TargetAccountConfiguration, error) { + input := fis.GetTargetAccountConfigurationInput{ + AccountId: accountId, + ExperimentTemplateId: experimentId, + } + + out, err := conn.GetTargetAccountConfiguration(ctx, &input) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, smarterr.NewError(&retry.NotFoundError{ + LastError: err, + LastRequest: &input, + }) + } + + return nil, smarterr.NewError(err) + } + + if out == nil || out.TargetAccountConfiguration == nil { + return nil, smarterr.NewError(tfresource.NewEmptyResultError(&input)) + } + + return out.TargetAccountConfiguration, nil +} + +type resourceTargetAccountConfigurationModel struct { + framework.WithRegionModel + AccountId types.String `tfsdk:"account_id"` + Description types.String `tfsdk:"description"` + ExperimentTemplateId types.String `tfsdk:"experiment_template_id"` + RoleArn types.String `tfsdk:"role_arn"` +} diff --git a/internal/service/fis/target_account_configuration_test.go b/internal/service/fis/target_account_configuration_test.go new file mode 100644 index 000000000000..cc4a670d21d1 --- /dev/null +++ b/internal/service/fis/target_account_configuration_test.go @@ -0,0 +1,365 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package fis_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/fis" + awstypes "github.com/aws/aws-sdk-go-v2/service/fis/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" + tffis "github.com/hashicorp/terraform-provider-aws/internal/service/fis" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccFISTargetAccountConfiguration_basic(t *testing.T) { + ctx := acctest.Context(t) + + var targetaccountconfiguration awstypes.TargetAccountConfiguration + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_fis_target_account_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.FISServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetAccountConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetAccountConfigurationConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetAccountConfigurationExists(ctx, resourceName, &targetaccountconfiguration), + resource.TestCheckResourceAttrSet(resourceName, names.AttrAccountID), + resource.TestCheckResourceAttrSet(resourceName, "experiment_template_id"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrRoleARN), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, fmt.Sprintf("%s target account configuration", rName)), + acctest.MatchResourceAttrGlobalARN(ctx, resourceName, names.AttrRoleARN, "iam", regexache.MustCompile(`role/.+$`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: acctest.AttrsImportStateIdFunc(resourceName, ",", names.AttrAccountID, "experiment_template_id"), + ImportStateVerifyIdentifierAttribute: names.AttrAccountID, + }, + }, + }) +} + +func TestAccFISTargetAccountConfiguration_update(t *testing.T) { + ctx := acctest.Context(t) + + var before, after awstypes.TargetAccountConfiguration + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_fis_target_account_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.FISServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetAccountConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetAccountConfigurationConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetAccountConfigurationExists(ctx, resourceName, &before), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, fmt.Sprintf("%s target account configuration", rName)), + ), + }, + { + Config: testAccTargetAccountConfigurationConfig_update(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetAccountConfigurationExists(ctx, resourceName, &after), + testAccCheckTargetAccountConfigurationNotRecreated(&before, &after), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, fmt.Sprintf("%s target account configuration updated", rName)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: acctest.AttrsImportStateIdFunc(resourceName, ",", names.AttrAccountID, "experiment_template_id"), + ImportStateVerifyIdentifierAttribute: names.AttrAccountID, + }, + }, + }) +} + +func TestAccFISTargetAccountConfiguration_disappears(t *testing.T) { + ctx := acctest.Context(t) + + var targetaccountconfiguration awstypes.TargetAccountConfiguration + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_fis_target_account_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.FISServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTargetAccountConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTargetAccountConfigurationConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTargetAccountConfigurationExists(ctx, resourceName, &targetaccountconfiguration), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tffis.ResourceTargetAccountConfiguration, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckTargetAccountConfigurationDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).FISClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_fis_target_account_configuration" { + continue + } + + accountId := aws.String(rs.Primary.Attributes[names.AttrAccountID]) + experimentId := aws.String(rs.Primary.Attributes["experiment_template_id"]) + _, err := tffis.FindTargetAccountConfigurationByID(ctx, conn, accountId, experimentId) + if tfresource.NotFound(err) { + return nil + } + if err != nil { + return create.Error(names.FIS, create.ErrActionCheckingDestroyed, tffis.ResNameTargetAccountConfiguration, *experimentId, err) + } + + return create.Error(names.FIS, create.ErrActionCheckingDestroyed, tffis.ResNameTargetAccountConfiguration, *experimentId, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckTargetAccountConfigurationExists(ctx context.Context, name string, targetaccountconfiguration *awstypes.TargetAccountConfiguration) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.FIS, create.ErrActionCheckingExistence, tffis.ResNameTargetAccountConfiguration, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.FIS, create.ErrActionCheckingExistence, tffis.ResNameTargetAccountConfiguration, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).FISClient(ctx) + + accountId := aws.String(rs.Primary.Attributes[names.AttrAccountID]) + experimentTemplateId := aws.String(rs.Primary.Attributes["experiment_template_id"]) + + resp, err := tffis.FindTargetAccountConfigurationByID(ctx, conn, accountId, experimentTemplateId) + if err != nil { + return create.Error(names.FIS, create.ErrActionCheckingExistence, tffis.ResNameTargetAccountConfiguration, rs.Primary.ID, err) + } + + *targetaccountconfiguration = *resp + + return nil + } +} + +func testAccPreCheck(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).FISClient(ctx) + + input := &fis.ListExperimentTemplatesInput{} + + _, err := conn.ListExperimentTemplates(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccCheckTargetAccountConfigurationNotRecreated(before, after *awstypes.TargetAccountConfiguration) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.ToString(before.AccountId), aws.ToString(after.AccountId); before != after { + return create.Error(names.FIS, create.ErrActionCheckingNotRecreated, tffis.ResNameTargetAccountConfiguration, before, errors.New("recreated")) + } + + return nil + } +} + +func testAccTargetAccountConfigurationConfig_basic(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = "%[1]s-role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "fis.${data.aws_partition.current.dns_suffix}" + } + }] + }) +} + +resource "aws_iam_role_policy_attachment" "test" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSFaultInjectionSimulatorEC2Access" +} + +resource "aws_fis_experiment_template" "test" { + description = "%[1]s experiment template" + role_arn = aws_iam_role.test.arn + + experiment_options { + account_targeting = "multi-account" + empty_target_resolution_mode = "fail" + } + + action { + name = "stop-instances" + action_id = "aws:ec2:stop-instances" + + parameter { + key = "startInstancesAfterDuration" + value = "PT10M" + } + + target { + key = "Instances" + value = "test-instances" + } + } + + target { + name = "test-instances" + resource_type = "aws:ec2:instance" + selection_mode = "PERCENT(50)" + + resource_tag { + key = "Environment" + value = "test" + } + } + + stop_condition { + source = "none" + } + + tags = { + Name = "%[1]s-experiment-template" + } +} + +resource "aws_fis_target_account_configuration" "test" { + experiment_template_id = aws_fis_experiment_template.test.id + account_id = data.aws_caller_identity.current.account_id + role_arn = aws_iam_role.test.arn + description = "%[1]s target account configuration" +} +`, rName) +} + +func testAccTargetAccountConfigurationConfig_update(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = "%[1]s-role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "fis.${data.aws_partition.current.dns_suffix}" + } + }] + }) +} + +resource "aws_iam_role_policy_attachment" "test" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSFaultInjectionSimulatorEC2Access" +} + +resource "aws_fis_experiment_template" "test" { + description = "%[1]s experiment template" + role_arn = aws_iam_role.test.arn + + experiment_options { + account_targeting = "multi-account" + empty_target_resolution_mode = "fail" + } + + action { + name = "stop-instances" + action_id = "aws:ec2:stop-instances" + + parameter { + key = "startInstancesAfterDuration" + value = "PT10M" + } + + target { + key = "Instances" + value = "test-instances" + } + } + + target { + name = "test-instances" + resource_type = "aws:ec2:instance" + selection_mode = "PERCENT(50)" + + resource_tag { + key = "Environment" + value = "test" + } + } + + stop_condition { + source = "none" + } + + tags = { + Name = "%[1]s-experiment-template" + } +} + +resource "aws_fis_target_account_configuration" "test" { + experiment_template_id = aws_fis_experiment_template.test.id + account_id = data.aws_caller_identity.current.account_id + role_arn = aws_iam_role.test.arn + description = "%[1]s target account configuration updated" +} +`, rName) +} diff --git a/website/docs/r/fis_target_account_configuration.html.markdown b/website/docs/r/fis_target_account_configuration.html.markdown new file mode 100644 index 000000000000..ec77cb1a00c9 --- /dev/null +++ b/website/docs/r/fis_target_account_configuration.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "FIS (Fault Injection Simulator)" +layout: "aws" +page_title: "AWS: aws_fis_target_account_configuration" +description: |- + Manages an AWS FIS (Fault Injection Simulator) Target Account Configuration. +--- + +# Resource: aws_fis_target_account_configuration + +Manages an AWS FIS (Fault Injection Simulator) Target Account Configuration. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_fis_target_account_configuration" "example" { + experiment_template_id = aws_fis_experiment_template.example.id + account_id = data.aws_caller_identity.current.account_id + role_arn = aws_iam_role.fis_role.arn + description = "Example" +} +``` + +## Argument Reference + +The following arguments are required: + +* `account_id` - (Required) Account ID of the target account. +* `experiment_template_id` - (Required) Experiment Template ID. + +The following arguments are optional: + +* `description` - (Optional) Description of the target account. +* `role_arn` - (Optional) ARN of the IAM Role for the target account. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). + +## Attribute Reference + +This resource exports no additional attributes. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import FIS (Fault Injection Simulator) Target Account Configuration using the `account_id,experiment_template_id`. For example: + +```terraform +import { + to = aws_fis_target_account_configuration.example + id = "123456789012,abcd123456789" +} +``` + +Using `terraform import`, import FIS (Fault Injection Simulator) Target Account Configuration using the `account_id,experiment_template_id`. For example: + +```console +% terraform import aws_fis_target_account_configuration.example 123456789012,abcd123456789 +```