Skip to content

Commit

Permalink
CR updates
Browse files Browse the repository at this point in the history
  • Loading branch information
anGie44 committed Aug 18, 2021
1 parent 1db0212 commit c4a413c
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 122 deletions.
3 changes: 3 additions & 0 deletions .changelog/18585.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_iam_roles
```
110 changes: 43 additions & 67 deletions aws/data_source_aws_iam_roles.go
Original file line number Diff line number Diff line change
@@ -1,118 +1,94 @@
package aws

import ( // nosemgrep: aws-sdk-go-multiple-service-imports
import (
"fmt"
"log"
"path/filepath" // filepath for glob matching
"regexp"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func dataSourceAwsIAMRoles() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsIAMRolesRead,

Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"path_prefix": {
Type: schema.TypeString,
Optional: true,
},
"arns": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"name_regex": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringIsValidRegExp,
},
"names": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"path_prefix": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

func dataSourceAwsIAMRolesRead(d *schema.ResourceData, meta interface{}) error {
iamconn := meta.(*AWSClient).iamconn
req := &iam.ListRolesInput{}
conn := meta.(*AWSClient).iamconn

if pathPrefix, hasPathPrefix := d.GetOk("path_prefix"); hasPathPrefix {
req.PathPrefix = aws.String(pathPrefix.(string))
input := &iam.ListRolesInput{}

if v, ok := d.GetOk("path_prefix"); ok {
input.PathPrefix = aws.String(v.(string))
}

filters, hasFilters := d.GetOk("filter")
filtersSet := []*ec2.Filter{}
var results []*iam.Role

if hasFilters {
filtersSet = buildAwsDataSourceFilters(filters.(*schema.Set))
log.Printf("[DEBUG] Has filters : %s", filtersSet)
// Only filters using the name "role-name" are currently supported
for _, f := range filtersSet {
if "role-name" != aws.StringValue(f.Name) {
return fmt.Errorf("Provided filters does not match supported names. See the documentation of this data source for supported filters.")
}
err := conn.ListRolesPages(input, func(page *iam.ListRolesOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}
} else {
log.Printf("[DEBUG] No filter")
}

roles := []*iam.Role{}

err := iamconn.ListRolesPages(
req,
func(page *iam.ListRolesOutput, lastPage bool) bool {
for _, role := range page.Roles {
if hasFilters {
log.Printf("[DEBUG] Found Role '%s' to be checked against filters", *role.RoleName)
matchAllFilters := true
for _, f := range filtersSet {
for _, filterValue := range f.Values {
// must match all values
if matched, _ := filepath.Match(*filterValue, *role.RoleName); !matched {
log.Printf("[DEBUG] RoleName '%s' does not match filter '%s'", *role.RoleName, *filterValue)
matchAllFilters = false
}
}
}
if matchAllFilters {
roles = append(roles, role)
}
} else {
log.Printf("[DEBUG] Found Role '%s'", *role.RoleName)
roles = append(roles, role)
}
for _, role := range page.Roles {
if role == nil {
continue
}
return !lastPage
},
)

if v, ok := d.GetOk("name_regex"); ok && !regexp.MustCompile(v.(string)).MatchString(aws.StringValue(role.RoleName)) {
continue
}

results = append(results, role)
}

return !lastPage
})

if err != nil {
return fmt.Errorf("error reading IAM roles : %w", err)
return fmt.Errorf("error reading IAM roles: %w", err)
}

if len(roles) == 0 {
log.Printf("[WARN] couldn't find any IAM role matching the provided parameters")
}
d.SetId(meta.(*AWSClient).region)

var arns, names []string

arns := []string{}
names := []string{}
for _, v := range roles {
arns = append(arns, aws.StringValue(v.Arn))
names = append(names, aws.StringValue(v.RoleName))
for _, r := range results {
arns = append(arns, aws.StringValue(r.Arn))
names = append(names, aws.StringValue(r.RoleName))
}

if err := d.Set("arns", arns); err != nil {
return fmt.Errorf("error setting arns: %w", err)
}

if err := d.Set("names", names); err != nil {
return fmt.Errorf("error setting names: %w", err)
}

d.SetId(meta.(*AWSClient).region)

return nil
}
81 changes: 52 additions & 29 deletions aws/data_source_aws_iam_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,36 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccAWSDataSourceIAMRoles_basic(t *testing.T) {
func TestAccAWSIAMRolesDataSource_basic(t *testing.T) {
dataSourceName := "data.aws_iam_roles.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, iam.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceIAMRolesConfig_basic(),
Config: testAccAWSIAMRolesConfigDataSource_basic,
Check: resource.ComposeTestCheckFunc(
// testCheckResourceAttrIsNot(dataSourceName, "names.#", "0"),
resource.TestMatchResourceAttr(dataSourceName, "names.#", regexp.MustCompile("[^0].*$")),
),
},
},
})
}

func TestAccAWSDataSourceIAMRoles_filterRoleName(t *testing.T) {
func TestAccAWSIAMRolesDataSource_nameRegex(t *testing.T) {
rCount := strconv.Itoa(acctest.RandIntRange(1, 4))
rName := acctest.RandomWithPrefix("tf-acc-test")
dataSourceName := "data.aws_iam_roles.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, iam.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceIAMRolesConfig_filterByName(rCount, rName),
Config: testAccAWSIAMRolesConfigDataSource_nameRegex(rCount, rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "names.#", rCount),
resource.TestCheckResourceAttr(dataSourceName, "arns.#", rCount),
Expand All @@ -49,18 +50,19 @@ func TestAccAWSDataSourceIAMRoles_filterRoleName(t *testing.T) {
})
}

func TestAccAWSDataSourceIAMRoles_pathPrefix(t *testing.T) {
func TestAccAWSIAMRolesDataSource_pathPrefix(t *testing.T) {
rCount := strconv.Itoa(acctest.RandIntRange(1, 4))
rName := acctest.RandomWithPrefix("tf-acc-test")
rPathPrefix := acctest.RandomWithPrefix("tf-acc-path")
dataSourceName := "data.aws_iam_roles.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, iam.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceIAMRolesConfig_pathPrefix(rCount, rName, rPathPrefix),
Config: testAccAWSIAMRolesConfigDataSource_pathPrefix(rCount, rName, rPathPrefix),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "names.#", rCount),
resource.TestCheckResourceAttr(dataSourceName, "arns.#", rCount),
Expand All @@ -70,35 +72,54 @@ func TestAccAWSDataSourceIAMRoles_pathPrefix(t *testing.T) {
})
}

func TestAccAWSDataSourceIAMRoles_pathPrefixAndFilterRoleName(t *testing.T) {
func TestAccAWSIAMRolesDataSource_nonExistentPathPrefix(t *testing.T) {
dataSourceName := "data.aws_iam_roles.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, iam.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSIAMRolesConfigDataSource_nonExistentPathPrefix,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "arns.#", "0"),
resource.TestCheckResourceAttr(dataSourceName, "names.#", "0"),
),
},
},
})
}

func TestAccAWSIAMRolesDataSource_nameRegexAndPathPrefix(t *testing.T) {
rCount := strconv.Itoa(acctest.RandIntRange(1, 4))
rName := acctest.RandomWithPrefix("tf-acc-test")
rPathPrefix := acctest.RandomWithPrefix("tf-acc-path")
dataSourceName := "data.aws_iam_roles.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, iam.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceIAMRolesConfig_pathPrefixAndFilterRoleName(rCount, rName, rPathPrefix),
Config: testAccAWSIAMRolesConfigDataSource_nameRegexAndPathPrefix(rCount, rName, rPathPrefix, "0"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "names.#", rCount),
resource.TestCheckResourceAttr(dataSourceName, "arns.#", rCount),
resource.TestCheckResourceAttr(dataSourceName, "names.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "arns.#", "1"),
),
},
},
})
}

func testAccAWSDataSourceIAMRolesConfig_basic() string {
return `
const testAccAWSIAMRolesConfigDataSource_basic = `
data "aws_iam_roles" "test" {}
`
}

func testAccAWSDataSourceIAMRolesConfig_filterByName(rCount string, rName string) string {
func testAccAWSIAMRolesConfigDataSource_nameRegex(rCount, rName string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}
resource "aws_iam_role" "test" {
count = %[1]s
Expand All @@ -111,7 +132,7 @@ resource "aws_iam_role" "test" {
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
"Service": "ec2.${data.aws_partition.current.dns_suffix}"
},
"Effect": "Allow",
"Sid": ""
Expand All @@ -125,16 +146,14 @@ EOF
}
data "aws_iam_roles" "test" {
filter {
name = "role-name"
values = ["${aws_iam_role.test[0].tags["Seed"]}-*-role"]
}
name_regex = "${aws_iam_role.test[0].tags["Seed"]}-.*-role"
}
`, rCount, rName)
}

func testAccAWSDataSourceIAMRolesConfig_pathPrefix(rCount string, rName string, rPathPrefix string) string {
func testAccAWSIAMRolesConfigDataSource_pathPrefix(rCount, rName, rPathPrefix string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}
resource "aws_iam_role" "test" {
count = %[1]s
Expand All @@ -147,7 +166,7 @@ resource "aws_iam_role" "test" {
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
"Service": "ec2.${data.aws_partition.current.dns_suffix}"
},
"Effect": "Allow",
"Sid": ""
Expand All @@ -165,8 +184,15 @@ data "aws_iam_roles" "test" {
`, rCount, rName, rPathPrefix)
}

func testAccAWSDataSourceIAMRolesConfig_pathPrefixAndFilterRoleName(rCount string, rName string, rPathPrefix string) string {
const testAccAWSIAMRolesConfigDataSource_nonExistentPathPrefix = `
data "aws_iam_roles" "test" {
path_prefix = "/dne/path"
}
`

func testAccAWSIAMRolesConfigDataSource_nameRegexAndPathPrefix(rCount, rName, rPathPrefix, rIndex string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}
resource "aws_iam_role" "test" {
count = %[1]s
Expand All @@ -179,7 +205,7 @@ resource "aws_iam_role" "test" {
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
"Service": "ec2.${data.aws_partition.current.dns_suffix}"
},
"Effect": "Allow",
"Sid": ""
Expand All @@ -195,11 +221,8 @@ EOF
}
data "aws_iam_roles" "test" {
filter {
name = "role-name"
values = ["${aws_iam_role.test[0].tags["Seed"]}-*-role", "*-role"]
}
name_regex = "${aws_iam_role.test[0].tags["Seed"]}-%[4]s-role"
path_prefix = aws_iam_role.test[0].path
}
`, rCount, rName, rPathPrefix)
`, rCount, rName, rPathPrefix, rIndex)
}
Loading

0 comments on commit c4a413c

Please sign in to comment.