Skip to content

Commit 261218d

Browse files
authored
Merge pull request #44867 from hashicorp/b-lakeformation-non-iam-principals
resource/aws_lakeformation_permissions: Allow use with IAM Identity Center Groups
2 parents 06e1581 + 6693c1c commit 261218d

39 files changed

+1480
-189
lines changed

.changelog/44867.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
```release-note:new-resource
2+
aws_lakeformation_identity_center_configuration
3+
```
4+
5+
```release-note:bug
6+
resource/aws_lakeformation_permissions: Allows IAM Identity Center Groups as `principal`.
7+
```
8+
9+
```release-note:bug
10+
data-source/aws_lakeformation_permissions: Allows IAM Identity Center Groups as `principal`.
11+
```
12+
13+
```release-note:enhancement
14+
resource/aws_identitystore_group: Adds `arn` attribute.
15+
```
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package knownvalue
5+
6+
import (
7+
"fmt"
8+
9+
"github.com/aws/aws-sdk-go-v2/aws/arn"
10+
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
11+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
12+
)
13+
14+
var _ knownvalue.Check = globalARNNoAccountIDExact{}
15+
16+
type globalARNNoAccountIDExact struct {
17+
service string
18+
resource string
19+
}
20+
21+
// CheckValue determines whether the passed value is of type string, and
22+
// contains a matching sequence of bytes.
23+
func (v globalARNNoAccountIDExact) CheckValue(other any) error {
24+
otherVal, ok := other.(string)
25+
26+
if !ok {
27+
return fmt.Errorf("expected string value for GlobalARNNoAccountIDExact check, got: %T", other)
28+
}
29+
30+
if otherVal != v.buildARNString() {
31+
return fmt.Errorf("expected value %s for GlobalARNNoAccountIDExact check, got: %s", v.buildARNString(), otherVal)
32+
}
33+
34+
return nil
35+
}
36+
37+
// String returns the string representation of the value.
38+
func (v globalARNNoAccountIDExact) String() string {
39+
return v.buildARNString()
40+
}
41+
42+
func (v globalARNNoAccountIDExact) buildARNString() string {
43+
return arn.ARN{
44+
AccountID: "",
45+
Partition: acctest.Partition(),
46+
Region: "",
47+
Service: v.service,
48+
Resource: v.resource,
49+
}.String()
50+
}
51+
52+
func GlobalARNNoAccountIDExact(service, resource string) knownvalue.Check {
53+
return globalARNNoAccountIDExact{
54+
service: service,
55+
resource: resource,
56+
}
57+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package statecheck
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/hashicorp/terraform-plugin-testing/statecheck"
11+
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
12+
tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue"
13+
)
14+
15+
var _ statecheck.StateCheck = expectGlobalARNNoAccountIDFormatCheck{}
16+
17+
type expectGlobalARNNoAccountIDFormatCheck struct {
18+
base Base
19+
attributePath tfjsonpath.Path
20+
arnService string
21+
arnFormat string
22+
}
23+
24+
func (e expectGlobalARNNoAccountIDFormatCheck) CheckState(ctx context.Context, request statecheck.CheckStateRequest, response *statecheck.CheckStateResponse) {
25+
resource, ok := e.base.ResourceFromState(request, response)
26+
if !ok {
27+
return
28+
}
29+
30+
value, err := tfjsonpath.Traverse(resource.AttributeValues, e.attributePath)
31+
if err != nil {
32+
response.Error = err
33+
return
34+
}
35+
36+
arnString, err := populateFromResourceState(e.arnFormat, resource)
37+
if err != nil {
38+
response.Error = err
39+
return
40+
}
41+
42+
knownCheck := tfknownvalue.GlobalARNNoAccountIDExact(e.arnService, arnString)
43+
if err = knownCheck.CheckValue(value); err != nil { //nolint:contextcheck // knownCheck implements an interface
44+
response.Error = fmt.Errorf("checking value for attribute at path: %s.%s, err: %w", e.base.ResourceAddress(), e.attributePath, err)
45+
return
46+
}
47+
}
48+
49+
func ExpectGlobalARNNoAccountIDFormat(resourceAddress string, attributePath tfjsonpath.Path, arnService, arnFormat string) statecheck.StateCheck {
50+
return expectGlobalARNNoAccountIDFormatCheck{
51+
base: NewBase(resourceAddress),
52+
attributePath: attributePath,
53+
arnService: arnService,
54+
arnFormat: arnFormat,
55+
}
56+
}

internal/generate/identitytests/resource_test.go.gtpl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ CheckDestroy: acctest.CheckDestroyNoop,
6969
{{ if gt (len .ImportStateIDFunc) 0 -}}
7070
ImportStateIdFunc: acctest.CrossRegionImportStateIdFuncAdapter(resourceName, {{ .ImportStateIDFunc }}),
7171
{{ else if .HasImportStateIDAttribute -}}
72-
// TODO
72+
ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, {{ .ImportStateIDAttribute }}),
7373
{{ else -}}
7474
ImportStateIdFunc: acctest.CrossRegionImportStateIdFunc(resourceName),
7575
{{ end -}}
@@ -99,7 +99,7 @@ CheckDestroy: acctest.CheckDestroyNoop,
9999
{{ if gt (len .ImportStateIDFunc) 0 -}}
100100
ImportStateIdFunc: acctest.CrossRegionImportStateIdFuncAdapter(resourceName, {{ .ImportStateIDFunc }}),
101101
{{ else if .HasImportStateIDAttribute -}}
102-
// TODO
102+
ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, {{ .ImportStateIDAttribute }}),
103103
{{ else -}}
104104
ImportStateIdFunc: acctest.CrossRegionImportStateIdFunc(resourceName),
105105
{{ end -}}
@@ -238,9 +238,11 @@ func {{ template "testname" . }}_IdentitySerial(t *testing.T) {
238238
{{- end }}
239239

240240
testCases := map[string]func(t *testing.T){
241-
acctest.CtBasic: {{ template "testname" . }}_Identity_Basic,
242-
"ExistingResource": {{ template "testname" . }}_Identity_ExistingResource,
243-
"ExistingResourceNoRefresh": {{ template "testname" . }}_Identity_ExistingResource_NoRefresh_NoChange,
241+
acctest.CtBasic: {{ template "testname" . }}_Identity_Basic,
242+
{{ if .PreIdentityVersion -}}
243+
"ExistingResource": {{ template "testname" . }}_Identity_ExistingResource,
244+
"ExistingResourceNoRefresh": {{ template "testname" . }}_Identity_ExistingResource_NoRefresh_NoChange,
245+
{{ end -}}
244246
{{ if .GenerateRegionOverrideTest -}}
245247
"RegionOverride": {{ template "testname" . }}_Identity_RegionOverride,
246248
{{ end -}}

internal/service/identitystore/group.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ func resourceGroup() *schema.Resource {
3737
},
3838

3939
Schema: map[string]*schema.Schema{
40+
names.AttrARN: {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
},
4044
names.AttrDescription: {
4145
Type: schema.TypeString,
4246
Optional: true,
@@ -123,6 +127,8 @@ func resourceGroupRead(ctx context.Context, d *schema.ResourceData, meta any) di
123127
return sdkdiag.AppendErrorf(diags, "reading IdentityStore Group (%s): %s", d.Id(), err)
124128
}
125129

130+
groupARN := meta.(*conns.AWSClient).GlobalARNNoAccount(ctx, "identitystore", "group/"+groupID)
131+
d.Set(names.AttrARN, groupARN)
126132
d.Set(names.AttrDescription, out.Description)
127133
d.Set(names.AttrDisplayName, out.DisplayName)
128134
if err := d.Set("external_ids", flattenExternalIDs(out.ExternalIds)); err != nil {

internal/service/identitystore/group_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010

1111
"github.com/aws/aws-sdk-go-v2/service/identitystore"
12+
"github.com/hashicorp/terraform-plugin-testing/compare"
1213
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
1314
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1415
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
@@ -17,6 +18,7 @@ import (
1718
"github.com/hashicorp/terraform-plugin-testing/terraform"
1819
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
1920
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
21+
tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck"
2022
"github.com/hashicorp/terraform-provider-aws/internal/conns"
2123
tfidentitystore "github.com/hashicorp/terraform-provider-aws/internal/service/identitystore"
2224
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
@@ -42,9 +44,11 @@ func TestAccIdentityStoreGroup_basic(t *testing.T) {
4244
{
4345
Config: testAccGroupConfig_basic(displayName),
4446
ConfigStateChecks: []statecheck.StateCheck{
47+
tfstatecheck.ExpectGlobalARNNoAccountIDFormat(resourceName, tfjsonpath.New(names.AttrARN), "identitystore", "group/{group_id}"),
48+
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrDescription), knownvalue.StringExact("")),
4549
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrDisplayName), knownvalue.StringExact(displayName)),
4650
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("group_id"), knownvalue.NotNull()),
47-
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("identity_store_id"), knownvalue.NotNull()),
51+
statecheck.CompareValuePairs(resourceName, tfjsonpath.New("identity_store_id"), "data.aws_ssoadmin_instances.test", tfjsonpath.New("identity_store_ids").AtSliceIndex(0), compare.ValuesSame()),
4852
},
4953
Check: resource.ComposeTestCheckFunc(
5054
testAccCheckGroupExists(ctx, resourceName, &group),
@@ -234,33 +238,35 @@ func testAccCheckGroupExists(ctx context.Context, n string, v *identitystore.Des
234238

235239
func testAccGroupConfig_basic(displayName string) string {
236240
return fmt.Sprintf(`
237-
data "aws_ssoadmin_instances" "test" {}
238241
resource "aws_identitystore_group" "test" {
239-
identity_store_id = tolist(data.aws_ssoadmin_instances.test.identity_store_ids)[0]
242+
identity_store_id = data.aws_ssoadmin_instances.test.identity_store_ids[0]
240243
display_name = %[1]q
241-
description = "Example description"
242244
}
245+
246+
data "aws_ssoadmin_instances" "test" {}
243247
`, displayName)
244248
}
245249

246250
func testAccGroupConfig_description(description string) string {
247251
return fmt.Sprintf(`
248-
data "aws_ssoadmin_instances" "test" {}
249252
resource "aws_identitystore_group" "test" {
250253
identity_store_id = tolist(data.aws_ssoadmin_instances.test.identity_store_ids)[0]
251254
display_name = "Test display name"
252255
description = %[1]q
253256
}
257+
258+
data "aws_ssoadmin_instances" "test" {}
254259
`, description)
255260
}
256261

257262
func testAccGroupConfig_displayName(displayName string) string {
258263
return fmt.Sprintf(`
259-
data "aws_ssoadmin_instances" "test" {}
260264
resource "aws_identitystore_group" "test" {
261265
identity_store_id = tolist(data.aws_ssoadmin_instances.test.identity_store_ids)[0]
262266
display_name = %[1]q
263267
description = "Test description"
264268
}
269+
270+
data "aws_ssoadmin_instances" "test" {}
265271
`, displayName)
266272
}

internal/service/lakeformation/consts.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ import (
77
"time"
88
)
99

10+
type TableType string
11+
12+
const (
13+
TableTypeTable TableType = "Table"
14+
TableTypeTableWithColumns TableType = "TableWithColumns"
15+
)
16+
1017
const (
11-
TableNameAllTables = "ALL_TABLES"
12-
TableTypeTable = "Table"
13-
TableTypeTableWithColumns = "TableWithColumns"
14-
IAMAllowedPrincipals = "IAM_ALLOWED_PRINCIPALS"
18+
TableNameAllTables = "ALL_TABLES"
19+
IAMAllowedPrincipals = "IAM_ALLOWED_PRINCIPALS"
1520
)
1621

1722
const (

internal/service/lakeformation/data_cells_filter_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func testAccDataCellsFilter_basic(t *testing.T) {
3232
resource.Test(t, resource.TestCase{
3333
PreCheck: func() {
3434
acctest.PreCheck(ctx, t)
35-
acctest.PreCheckPartitionHasService(t, names.LakeFormation)
35+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
3636
testAccDataCellsFilterPreCheck(ctx, t)
3737
},
3838
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
@@ -69,7 +69,7 @@ func testAccDataCellsFilter_columnWildcard(t *testing.T) {
6969
resource.Test(t, resource.TestCase{
7070
PreCheck: func() {
7171
acctest.PreCheck(ctx, t)
72-
acctest.PreCheckPartitionHasService(t, names.LakeFormation)
72+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
7373
testAccDataCellsFilterPreCheck(ctx, t)
7474
},
7575
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
@@ -102,7 +102,7 @@ func testAccDataCellsFilter_disappears(t *testing.T) {
102102
resource.Test(t, resource.TestCase{
103103
PreCheck: func() {
104104
acctest.PreCheck(ctx, t)
105-
acctest.PreCheckPartitionHasService(t, names.LakeFormation)
105+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
106106
testAccDataCellsFilterPreCheck(ctx, t)
107107
},
108108
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
@@ -137,7 +137,7 @@ func testAccDataCellsFilter_rowFilter(t *testing.T) {
137137
resource.Test(t, resource.TestCase{
138138
PreCheck: func() {
139139
acctest.PreCheck(ctx, t)
140-
acctest.PreCheckPartitionHasService(t, names.LakeFormation)
140+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
141141
testAccDataCellsFilterPreCheck(ctx, t)
142142
},
143143
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),

internal/service/lakeformation/data_lake_settings_data_source_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ func testAccDataLakeSettingsDataSource_basic(t *testing.T) {
1616
resourceName := "data.aws_lakeformation_data_lake_settings.test"
1717

1818
resource.Test(t, resource.TestCase{
19-
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.LakeFormation) },
19+
PreCheck: func() {
20+
acctest.PreCheck(ctx, t)
21+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
22+
},
2023
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
2124
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
2225
CheckDestroy: testAccCheckDataLakeSettingsDestroy(ctx),
@@ -42,7 +45,10 @@ func testAccDataLakeSettingsDataSource_readOnlyAdmins(t *testing.T) {
4245
resourceName := "data.aws_lakeformation_data_lake_settings.test"
4346

4447
resource.Test(t, resource.TestCase{
45-
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.LakeFormation) },
48+
PreCheck: func() {
49+
acctest.PreCheck(ctx, t)
50+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
51+
},
4652
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
4753
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
4854
CheckDestroy: testAccCheckDataLakeSettingsDestroy(ctx),

internal/service/lakeformation/data_lake_settings_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ func testAccDataLakeSettings_basic(t *testing.T) {
2525
resourceName := "aws_lakeformation_data_lake_settings.test"
2626

2727
resource.Test(t, resource.TestCase{
28-
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.LakeFormation) },
28+
PreCheck: func() {
29+
acctest.PreCheck(ctx, t)
30+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
31+
},
2932
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
3033
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
3134
CheckDestroy: testAccCheckDataLakeSettingsDestroy(ctx),
@@ -62,7 +65,10 @@ func testAccDataLakeSettings_disappears(t *testing.T) {
6265
resourceName := "aws_lakeformation_data_lake_settings.test"
6366

6467
resource.Test(t, resource.TestCase{
65-
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.LakeFormation) },
68+
PreCheck: func() {
69+
acctest.PreCheck(ctx, t)
70+
acctest.PreCheckPartitionHasService(t, names.LakeFormationEndpointID)
71+
},
6672
ErrorCheck: acctest.ErrorCheck(t, names.LakeFormationServiceID),
6773
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
6874
CheckDestroy: testAccCheckDataLakeSettingsDestroy(ctx),

0 commit comments

Comments
 (0)