Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix aws_securitylake_subscriber to accept more than one source blocks #36268

Merged
merged 24 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8b10f3c
Fix `aws_securitylake_subscriber` to accept more than one source blocks
lawliet89 Mar 8, 2024
2cf42fb
Add changelog
lawliet89 Mar 8, 2024
9ad8f3f
Allows running tests from delegated admin account
gdavison Apr 25, 2024
cfe01ed
Cleanup
gdavison Apr 26, 2024
cbd8fa6
Uses `aws_region` data source instead of `acctest.Region`
gdavison Apr 26, 2024
6a0169f
Simplifies tag tests
gdavison Apr 26, 2024
67a20bb
Use `ComposeAggregateTestCheckFunc`
gdavison Apr 26, 2024
342ac0f
Uses `aws_region` data source instead of `acctest.Region` for AWS Log…
gdavison Apr 26, 2024
3fefd97
Correctly handles default version
gdavison Apr 26, 2024
04a5b9b
Avoids conflict when creating multiple AWS Log Sources
gdavison Apr 27, 2024
a7b837a
Updates documentation to note need for `depends_on` relationship with…
gdavison Apr 29, 2024
5a818ef
`aws_securitylake_aws_log_source` updates
gdavison Apr 29, 2024
05dd4d2
Tests defaults in `testAccCustomLogSource_basic`
gdavison Apr 30, 2024
4d5946a
Additional tests for Custom Log Sources
gdavison Apr 30, 2024
a91b214
Avoids conflict when creating multiple Custom Log Sources
gdavison Apr 30, 2024
a243050
`terrafmt`
gdavison Apr 30, 2024
5061c60
Tests defaults in `testAccSubscriber_basic` and adds additional tests
gdavison May 1, 2024
2c1c4b8
Prevent panic when API call returns error
gdavison May 2, 2024
8413eb0
Converts `source` from List to Set and adds test for handling multipl…
gdavison May 2, 2024
06fa44a
Updates CHANGELOG
gdavison May 2, 2024
c9ee390
Cleanup
gdavison May 2, 2024
6a2d9ac
Parameterizes roles for Subscriber Notification tests
gdavison May 3, 2024
c613018
Linting fixes
gdavison May 3, 2024
d08b70d
Fixes `nosemgrep` annotations
gdavison May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changelog/36268.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
```release-note:bug
resource/aws_securitylake_subscriber: Allow more than one log source
```

```release-note:bug
resource/aws_securitylake_aws_log_source: Correctly handles unspecified `source_version`
```

```release-note:bug
resource/aws_securitylake_aws_log_source: Prevents errors when creating multiple log sources concurrently
```

```release-note:bug
resource/aws_securitylake_custom_log_source: Validates length of `source_name` parameter
```

```release-note:bug
resource/aws_securitylake_custom_log_source: Prevents errors when creating multiple log sources concurrently
```

```release-note:bug
resource/aws_securitylake_subscriber: Correctly handles unspecified `access_type`
```

```release-note:bug
resource/aws_securitylake_subscriber: Correctly requires `source_name` parameter for `aws_log_source_resource` and `custom_log_source_resource`
```

```release-note:bug
resource/aws_securitylake_subscriber: Correctly handles unspecified `source_version` parameter for `aws_log_source_resource` and `custom_log_source_resource`
```
9 changes: 7 additions & 2 deletions internal/service/securitylake/aws_log_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ func (r *awsLogSourceResource) Create(ctx context.Context, request resource.Crea
return
}

_, err := conn.CreateAwsLogSource(ctx, input)
_, err := retryDataLakeConflictWithMutex(ctx, func() (*securitylake.CreateAwsLogSourceOutput, error) {
return conn.CreateAwsLogSource(ctx, input)
})

if err != nil {
response.Diagnostics.AddError("creating Security Lake AWS Log Source", err.Error())
Expand All @@ -144,6 +146,7 @@ func (r *awsLogSourceResource) Create(ctx context.Context, request resource.Crea

sourceData.Accounts.SetValue = fwflex.FlattenFrameworkStringValueSet(ctx, logSource.Accounts)
sourceData.SourceVersion = fwflex.StringToFramework(ctx, logSource.SourceVersion)
data.Source = fwtypes.NewListNestedObjectValueOfPtrMust(ctx, sourceData)

response.Diagnostics.Append(response.State.Set(ctx, data)...)
}
Expand Down Expand Up @@ -212,7 +215,9 @@ func (r *awsLogSourceResource) Delete(ctx context.Context, request resource.Dele
input.Sources = []awstypes.AwsLogSourceConfiguration{*logSource}
}

_, err := conn.DeleteAwsLogSource(ctx, input)
_, err := retryDataLakeConflictWithMutex(ctx, func() (*securitylake.DeleteAwsLogSourceOutput, error) {
return conn.DeleteAwsLogSource(ctx, input)
})

if errs.IsA[*awstypes.ResourceNotFoundException](err) {
return
Expand Down
190 changes: 172 additions & 18 deletions internal/service/securitylake/aws_log_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/securitylake/types"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
Expand All @@ -28,13 +29,62 @@ func testAccAWSLogSource_basic(t *testing.T) {
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SecurityLake)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.SecurityLakeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckAWSLogSourceDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccAWSLogSourceConfig_basic(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLogSourceExists(ctx, resourceName, &logSource),
resource.TestCheckResourceAttr(resourceName, "source.#", "1"),
resource.TestCheckResourceAttrSet(resourceName, "source.0.accounts.#"),
acctest.CheckResourceAttrAccountID(resourceName, "source.0.accounts.0"),
func(s *terraform.State) error {
return resource.TestCheckTypeSetElemAttr(resourceName, "source.0.accounts.*", acctest.AccountID())(s)
},
resource.TestCheckResourceAttr(resourceName, "source.0.regions.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "source.0.regions.*", acctest.Region()),
resource.TestCheckResourceAttr(resourceName, "source.0.source_name", "ROUTE53"),
resource.TestCheckResourceAttr(resourceName, "source.0.source_version", "2.0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSLogSourceConfig_sourceVersion("2.0"),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
}

func testAccAWSLogSource_sourceVersion(t *testing.T) {
ctx := acctest.Context(t)
resourceName := "aws_securitylake_aws_log_source.test"
var logSource types.AwsLogSourceConfiguration

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SecurityLake)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.SecurityLakeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckAWSLogSourceDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccAWSLogSourceConfig_sourceVersion("1.0"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLogSourceExists(ctx, resourceName, &logSource),
resource.TestCheckResourceAttr(resourceName, "source.#", "1"),
Expand All @@ -50,6 +100,23 @@ func testAccAWSLogSource_basic(t *testing.T) {
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSLogSourceConfig_sourceVersion("2.0"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLogSourceExists(ctx, resourceName, &logSource),
resource.TestCheckResourceAttr(resourceName, "source.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source.0.accounts.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source.0.regions.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "source.0.regions.*", acctest.Region()),
resource.TestCheckResourceAttr(resourceName, "source.0.source_name", "ROUTE53"),
resource.TestCheckResourceAttr(resourceName, "source.0.source_version", "2.0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand All @@ -64,9 +131,11 @@ func testAccAWSLogSource_multiRegion(t *testing.T) {
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SecurityLake)
acctest.PreCheckMultipleRegion(t, 2)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.SecurityLakeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
ProtoV5ProviderFactories: acctest.ProtoV5FactoriesAlternate(ctx, t),
CheckDestroy: testAccCheckAWSLogSourceDestroy(ctx),
Steps: []resource.TestStep{
{
Expand All @@ -78,8 +147,6 @@ func testAccAWSLogSource_multiRegion(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "source.0.regions.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "source.0.regions.*", acctest.Region()),
resource.TestCheckTypeSetElemAttr(resourceName, "source.0.regions.*", acctest.AlternateRegion()),
resource.TestCheckResourceAttr(resourceName, "source.0.source_name", "ROUTE53"),
resource.TestCheckResourceAttr(resourceName, "source.0.source_version", "1.0"),
),
},
{
Expand All @@ -100,7 +167,7 @@ func testAccAWSLogSource_disappears(t *testing.T) {
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SecurityLake)
acctest.PreCheckOrganizationsAccount(ctx, t)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.SecurityLakeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Expand All @@ -118,6 +185,46 @@ func testAccAWSLogSource_disappears(t *testing.T) {
})
}

func testAccAWSLogSource_multiple(t *testing.T) {
ctx := acctest.Context(t)
resourceName := "aws_securitylake_aws_log_source.test"
resourceName2 := "aws_securitylake_aws_log_source.test2"
var logSource, logSource2 types.AwsLogSourceConfiguration

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.SecurityLake)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.SecurityLakeServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckAWSLogSourceDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccAWSLogSourceConfig_multiple(),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLogSourceExists(ctx, resourceName, &logSource),
testAccCheckAWSLogSourceExists(ctx, resourceName2, &logSource2),

resource.TestCheckResourceAttr(resourceName, "source.#", "1"),
resource.TestCheckResourceAttr(resourceName, "source.0.source_name", "ROUTE53"),
resource.TestCheckResourceAttr(resourceName, "source.0.source_version", "2.0"),

resource.TestCheckResourceAttr(resourceName2, "source.#", "1"),
resource.TestCheckResourceAttr(resourceName2, "source.0.source_name", "S3_DATA"),
resource.TestCheckResourceAttr(resourceName2, "source.0.source_version", "2.0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAWSLogSourceDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).SecurityLakeClient(ctx)
Expand Down Expand Up @@ -166,34 +273,81 @@ func testAccCheckAWSLogSourceExists(ctx context.Context, n string, v *types.AwsL
}

func testAccAWSLogSourceConfig_basic() string {
return acctest.ConfigCompose(testAccDataLakeConfig_basic(), fmt.Sprintf(`
data "aws_caller_identity" "test" {}
return acctest.ConfigCompose(
testAccDataLakeConfig_basic(), `
resource "aws_securitylake_aws_log_source" "test" {
source {
accounts = [data.aws_caller_identity.current.account_id]
regions = [data.aws_region.current.name]
source_name = "ROUTE53"
}
depends_on = [aws_securitylake_data_lake.test]
}

data "aws_region" "current" {}
`)
}

func testAccAWSLogSourceConfig_sourceVersion(version string) string {
return acctest.ConfigCompose(
testAccDataLakeConfig_basic(), fmt.Sprintf(`
resource "aws_securitylake_aws_log_source" "test" {
source {
accounts = [data.aws_caller_identity.test.account_id]
regions = [%[1]q]
accounts = [data.aws_caller_identity.current.account_id]
regions = [data.aws_region.current.name]
source_name = "ROUTE53"
source_version = "1.0"
source_version = %[1]q
}
depends_on = [aws_securitylake_data_lake.test]
}
`, acctest.Region()))

data "aws_region" "current" {}
`, version))
}

func testAccAWSLogSourceConfig_multiRegion(rName string) string {
return acctest.ConfigCompose(testAccDataLakeConfig_replication(rName), fmt.Sprintf(`
data "aws_caller_identity" "test" {}

return acctest.ConfigCompose(
acctest.ConfigMultipleRegionProvider(2),
testAccDataLakeConfig_replication(rName), `
resource "aws_securitylake_aws_log_source" "test" {
source {
accounts = [data.aws_caller_identity.test.account_id]
regions = [%[1]q, %[2]q]
source_name = "ROUTE53"
source_version = "1.0"
accounts = [data.aws_caller_identity.current.account_id]
regions = [data.aws_region.current.name, data.aws_region.alternate.name]
source_name = "ROUTE53"
}

depends_on = [aws_securitylake_data_lake.test, aws_securitylake_data_lake.region_2]
}
`, acctest.Region(), acctest.AlternateRegion()))

data "aws_region" "current" {}

data "aws_region" "alternate" {
provider = awsalternate
}
`)
}

func testAccAWSLogSourceConfig_multiple() string {
return acctest.ConfigCompose(
testAccDataLakeConfig_basic(), `
resource "aws_securitylake_aws_log_source" "test" {
source {
accounts = [data.aws_caller_identity.current.account_id]
regions = [data.aws_region.current.name]
source_name = "ROUTE53"
}
depends_on = [aws_securitylake_data_lake.test]
}

resource "aws_securitylake_aws_log_source" "test2" {
source {
accounts = [data.aws_caller_identity.current.account_id]
regions = [data.aws_region.current.name]
source_name = "S3_DATA"
}
depends_on = [aws_securitylake_data_lake.test]
}

data "aws_region" "current" {}
`)
}
12 changes: 10 additions & 2 deletions internal/service/securitylake/custom_log_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/securitylake"
awstypes "github.com/aws/aws-sdk-go-v2/service/securitylake/types"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand Down Expand Up @@ -88,6 +89,9 @@ func (r *customLogSourceResource) Schema(ctx context.Context, request resource.S
},
"source_name": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.LengthAtMost(20),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
Expand Down Expand Up @@ -184,7 +188,9 @@ func (r *customLogSourceResource) Create(ctx context.Context, request resource.C
return
}

output, err := conn.CreateCustomLogSource(ctx, input)
output, err := retryDataLakeConflictWithMutex(ctx, func() (*securitylake.CreateCustomLogSourceOutput, error) {
return conn.CreateCustomLogSource(ctx, input)
})

if err != nil {
response.Diagnostics.AddError("creating Security Lake Custom Log Source", err.Error())
Expand Down Expand Up @@ -266,7 +272,9 @@ func (r *customLogSourceResource) Delete(ctx context.Context, request resource.D
return
}

_, err := conn.DeleteCustomLogSource(ctx, input)
_, err := retryDataLakeConflictWithMutex(ctx, func() (*securitylake.DeleteCustomLogSourceOutput, error) {
return conn.DeleteCustomLogSource(ctx, input)
})

if errs.IsA[*awstypes.ResourceNotFoundException](err) {
return
Expand Down
Loading
Loading