diff --git a/.changelog/43503.txt b/.changelog/43503.txt new file mode 100644 index 000000000000..78a2eebad517 --- /dev/null +++ b/.changelog/43503.txt @@ -0,0 +1,12 @@ +```release-note:enhancement +resource/aws_iam_openid_connect_provider: Add resource identity support +``` +```release-note:enhancement +resource/aws_iam_policy: Add resource identity support +``` +```release-note:enhancement +resource/aws_iam_saml_provider: Add resource identity support +``` +```release-note:enhancement +resource/aws_iam_service_linked_role: Add resource identity support +``` diff --git a/.ci/.tflint.hcl b/.ci/.tflint.hcl index c745a469afd4..bdffe7525511 100644 --- a/.ci/.tflint.hcl +++ b/.ci/.tflint.hcl @@ -29,3 +29,8 @@ rule "aws_acm_certificate_lifecycle" { rule "aws_accessanalyzer_analyzer_invalid_type" { enabled = false } + +# Avoids errant findings related to directory paths in generated configuration files +rule "aws_iam_saml_provider_invalid_saml_metadata_document" { + enabled = false +} diff --git a/internal/service/iam/openid_connect_provider.go b/internal/service/iam/openid_connect_provider.go index a8078a9d30fc..382a20acebc2 100644 --- a/internal/service/iam/openid_connect_provider.go +++ b/internal/service/iam/openid_connect_provider.go @@ -26,6 +26,8 @@ import ( // @SDKResource("aws_iam_openid_connect_provider", name="OIDC Provider") // @Tags(identifierAttribute="arn", resourceType="OIDCProvider") // @Testing(name="OpenIDConnectProvider") +// @ArnIdentity +// @Testing(preIdentityVersion="v6.4.0") func resourceOpenIDConnectProvider() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceOpenIDConnectProviderCreate, @@ -33,10 +35,6 @@ func resourceOpenIDConnectProvider() *schema.Resource { UpdateWithoutTimeout: resourceOpenIDConnectProviderUpdate, DeleteWithoutTimeout: resourceOpenIDConnectProviderDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ names.AttrARN: { Type: schema.TypeString, diff --git a/internal/service/iam/openid_connect_provider_identity_gen_test.go b/internal/service/iam/openid_connect_provider_identity_gen_test.go new file mode 100644 index 000000000000..410dd03ae8b1 --- /dev/null +++ b/internal/service/iam/openid_connect_provider_identity_gen_test.go @@ -0,0 +1,155 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package iam_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/compare" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccIAMOpenIDConnectProvider_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_openid_connect_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckOpenIDConnectProviderDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckOpenIDConnectProviderExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.4.0 +func TestAccIAMOpenIDConnectProvider_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_openid_connect_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckOpenIDConnectProviderDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic_v6.4.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckOpenIDConnectProviderExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/OpenIDConnectProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} diff --git a/internal/service/iam/policy.go b/internal/service/iam/policy.go index 7843d5d6f43a..80fce89dab07 100644 --- a/internal/service/iam/policy.go +++ b/internal/service/iam/policy.go @@ -37,6 +37,8 @@ const ( // @SDKResource("aws_iam_policy", name="Policy") // @Tags(identifierAttribute="arn", resourceType="Policy") // @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/iam/types;types.Policy") +// @ArnIdentity +// @Testing(preIdentityVersion="v6.4.0") func resourcePolicy() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourcePolicyCreate, @@ -44,10 +46,6 @@ func resourcePolicy() *schema.Resource { UpdateWithoutTimeout: resourcePolicyUpdate, DeleteWithoutTimeout: resourcePolicyDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ names.AttrARN: { Type: schema.TypeString, diff --git a/internal/service/iam/policy_identity_gen_test.go b/internal/service/iam/policy_identity_gen_test.go new file mode 100644 index 000000000000..60a9b0ae79fe --- /dev/null +++ b/internal/service/iam/policy_identity_gen_test.go @@ -0,0 +1,160 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package iam_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/iam/types" + "github.com/hashicorp/terraform-plugin-testing/compare" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccIAMPolicy_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + + var v types.Policy + resourceName := "aws_iam_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckPolicyDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckPolicyExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.4.0 +func TestAccIAMPolicy_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + + var v types.Policy + resourceName := "aws_iam_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckPolicyDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic_v6.4.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckPolicyExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Policy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} diff --git a/internal/service/iam/saml_provider.go b/internal/service/iam/saml_provider.go index 921ce35cf7d7..8179579409f9 100644 --- a/internal/service/iam/saml_provider.go +++ b/internal/service/iam/saml_provider.go @@ -29,6 +29,8 @@ import ( // @SDKResource("aws_iam_saml_provider", name="SAML Provider") // @Tags(identifierAttribute="arn", resourceType="SAMLProvider") // @Testing(tagsTest=false) +// @ArnIdentity +// @Testing(preIdentityVersion="v6.4.0") func resourceSAMLProvider() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceSAMLProviderCreate, @@ -36,10 +38,6 @@ func resourceSAMLProvider() *schema.Resource { UpdateWithoutTimeout: resourceSAMLProviderUpdate, DeleteWithoutTimeout: resourceSAMLProviderDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ names.AttrARN: { Type: schema.TypeString, diff --git a/internal/service/iam/saml_provider_identity_gen_test.go b/internal/service/iam/saml_provider_identity_gen_test.go new file mode 100644 index 000000000000..e597d0f0cdea --- /dev/null +++ b/internal/service/iam/saml_provider_identity_gen_test.go @@ -0,0 +1,155 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package iam_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/compare" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccIAMSAMLProvider_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_saml_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckSAMLProviderDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSAMLProviderExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.4.0 +func TestAccIAMSAMLProvider_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_saml_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckSAMLProviderDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic_v6.4.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSAMLProviderExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SAMLProvider/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} diff --git a/internal/service/iam/service_linked_role.go b/internal/service/iam/service_linked_role.go index 162732845e7b..bd9a26a1020e 100644 --- a/internal/service/iam/service_linked_role.go +++ b/internal/service/iam/service_linked_role.go @@ -31,6 +31,8 @@ import ( // @SDKResource("aws_iam_service_linked_role", name="Service Linked Role") // @Tags(identifierAttribute="id", resourceType="ServiceLinkedRole") +// @ArnIdentity(arnAttribute="id") +// @Testing(preIdentityVersion="v6.4.0") func resourceServiceLinkedRole() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceServiceLinkedRoleCreate, @@ -38,10 +40,6 @@ func resourceServiceLinkedRole() *schema.Resource { UpdateWithoutTimeout: resourceServiceLinkedRoleUpdate, DeleteWithoutTimeout: resourceServiceLinkedRoleDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ names.AttrARN: { Type: schema.TypeString, diff --git a/internal/service/iam/service_linked_role_identity_gen_test.go b/internal/service/iam/service_linked_role_identity_gen_test.go new file mode 100644 index 000000000000..e301af165bbf --- /dev/null +++ b/internal/service/iam/service_linked_role_identity_gen_test.go @@ -0,0 +1,155 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package iam_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/compare" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccIAMServiceLinkedRole_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_service_linked_role.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckServiceLinkedRoleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckServiceLinkedRoleExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.4.0 +func TestAccIAMServiceLinkedRole_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_iam_service_linked_role.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID), + CheckDestroy: testAccCheckServiceLinkedRoleDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic_v6.4.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckServiceLinkedRoleExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ServiceLinkedRole/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} diff --git a/internal/service/iam/service_package_gen.go b/internal/service/iam/service_package_gen.go index 50160ba1a514..fb8e7bb76263 100644 --- a/internal/service/iam/service_package_gen.go +++ b/internal/service/iam/service_package_gen.go @@ -244,6 +244,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa ResourceType: "OIDCProvider", }), Region: unique.Make(inttypes.ResourceRegionDisabled()), + Identity: inttypes.GlobalARNIdentity( + inttypes.WithIdentityDuplicateAttrs(names.AttrID), + ), + Import: inttypes.SDKv2Import{ + WrappedImport: true, + }, }, { Factory: resourcePolicy, @@ -254,6 +260,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa ResourceType: "Policy", }), Region: unique.Make(inttypes.ResourceRegionDisabled()), + Identity: inttypes.GlobalARNIdentity( + inttypes.WithIdentityDuplicateAttrs(names.AttrID), + ), + Import: inttypes.SDKv2Import{ + WrappedImport: true, + }, }, { Factory: resourcePolicyAttachment, @@ -311,6 +323,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa ResourceType: "SAMLProvider", }), Region: unique.Make(inttypes.ResourceRegionDisabled()), + Identity: inttypes.GlobalARNIdentity( + inttypes.WithIdentityDuplicateAttrs(names.AttrID), + ), + Import: inttypes.SDKv2Import{ + WrappedImport: true, + }, }, { Factory: resourceSecurityTokenServicePreferences, @@ -337,6 +355,12 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa ResourceType: "ServiceLinkedRole", }), Region: unique.Make(inttypes.ResourceRegionDisabled()), + Identity: inttypes.GlobalARNIdentity( + inttypes.WithIdentityDuplicateAttrs(names.AttrID), + ), + Import: inttypes.SDKv2Import{ + WrappedImport: true, + }, }, { Factory: resourceServiceSpecificCredential, diff --git a/internal/service/iam/testdata/OpenIDConnectProvider/basic/main_gen.tf b/internal/service/iam/testdata/OpenIDConnectProvider/basic/main_gen.tf new file mode 100644 index 000000000000..93f26868d425 --- /dev/null +++ b/internal/service/iam/testdata/OpenIDConnectProvider/basic/main_gen.tf @@ -0,0 +1,18 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_iam_openid_connect_provider" "test" { + url = "https://accounts.testle.com/${var.rName}" + + client_id_list = [ + "266362248691-re108qaeld573ia0l6clj2i5ac7r7291.apps.testleusercontent.com", + ] + + thumbprint_list = ["cf23df2207d99a74fbe169e3eba035e633b65d94"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} diff --git a/internal/service/iam/testdata/OpenIDConnectProvider/basic_v6.4.0/main_gen.tf b/internal/service/iam/testdata/OpenIDConnectProvider/basic_v6.4.0/main_gen.tf new file mode 100644 index 000000000000..490e7d3980e3 --- /dev/null +++ b/internal/service/iam/testdata/OpenIDConnectProvider/basic_v6.4.0/main_gen.tf @@ -0,0 +1,28 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_iam_openid_connect_provider" "test" { + url = "https://accounts.testle.com/${var.rName}" + + client_id_list = [ + "266362248691-re108qaeld573ia0l6clj2i5ac7r7291.apps.testleusercontent.com", + ] + + thumbprint_list = ["cf23df2207d99a74fbe169e3eba035e633b65d94"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.4.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/iam/testdata/Policy/basic/main_gen.tf b/internal/service/iam/testdata/Policy/basic/main_gen.tf new file mode 100644 index 000000000000..28b5c575f926 --- /dev/null +++ b/internal/service/iam/testdata/Policy/basic/main_gen.tf @@ -0,0 +1,31 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_iam_policy" "test" { + name = var.rName + + policy = <