Skip to content

Commit

Permalink
Merge pull request #31430 from silvaalbert/f-add-resourcegroups-resou…
Browse files Browse the repository at this point in the history
…rces

add resourcegroups resource
  • Loading branch information
ewbankkit authored May 30, 2023
2 parents 87e1b0f + ea05077 commit 5ab1842
Show file tree
Hide file tree
Showing 5 changed files with 393 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/31430.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_resourcegroups_resource
```
157 changes: 157 additions & 0 deletions internal/service/resourcegroups/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package resourcegroups

import (
"context"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/resourcegroups"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKResource("aws_resourcegroups_resource", name="Resource")
func ResourceResource() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceResourceCreate,
ReadWithoutTimeout: resourceResourceRead,
DeleteWithoutTimeout: resourceResourceDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"group_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"resource_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"resource_type": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

const (
ResNameResource = "Resource"
)

func resourceResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).ResourceGroupsConn()

group := d.Get("group_arn").(string)
resourceArn := d.Get("resource_arn").(string)

in := &resourcegroups.GroupResourcesInput{
Group: aws.String(group),
ResourceArns: []*string{&resourceArn},
}

_, err := conn.GroupResourcesWithContext(ctx, in)

if err != nil {
return create.DiagError(names.ResourceGroups, create.ErrActionCreating, ResNameResource, d.Get("name").(string), err)
}

vars := []string{
strings.Split(strings.ToLower(d.Get("group_arn").(string)), "/")[1],
strings.Split(d.Get("resource_arn").(string), "/")[1],
}

d.SetId(strings.Join(vars, "_"))

return resourceResourceRead(ctx, d, meta)
}

func resourceResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).ResourceGroupsConn()

out, err := FindResourceByARN(ctx, conn, d.Get("group_arn").(string), d.Get("resource_arn").(string))

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] ResourceGroups Resource (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return create.DiagError(names.ResourceGroups, create.ErrActionReading, ResNameResource, d.Id(), err)
}

d.Set("resource_arn", out.Identifier.ResourceArn)
d.Set("resource_type", out.Identifier.ResourceType)

return nil
}

func resourceResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).ResourceGroupsConn()

log.Printf("[INFO] Deleting ResourceGroups Resource %s", d.Id())

group := d.Get("group_arn").(string)
resourceArn := d.Get("resource_arn").(string)

_, err := conn.UngroupResourcesWithContext(ctx, &resourcegroups.UngroupResourcesInput{
Group: aws.String(group),
ResourceArns: []*string{&resourceArn},
})

if err != nil {
return create.DiagError(names.ResourceGroups, create.ErrActionDeleting, ResNameResource, d.Id(), err)
}

_, err = tfresource.RetryUntilNotFound(ctx, d.Timeout(schema.TimeoutDelete), func() (interface{}, error) {
return FindResourceByARN(ctx, conn, d.Get("group_arn").(string), d.Get("resource_arn").(string))
})

if err != nil {
return create.DiagError(names.ResourceGroups, create.ErrActionDeleting, ResNameResource, d.Id(), err)
}

return nil
}

func FindResourceByARN(ctx context.Context, conn *resourcegroups.ResourceGroups, groupArn, resourceArn string) (*resourcegroups.ListGroupResourcesItem, error) {
input := &resourcegroups.ListGroupResourcesInput{
Group: aws.String(groupArn),
}

output, err := conn.ListGroupResourcesWithContext(ctx, input)

if tfawserr.ErrCodeEquals(err, resourcegroups.ErrCodeNotFoundException) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

for _, resourceItem := range output.Resources {
if aws.StringValue(resourceItem.Identifier.ResourceArn) == resourceArn {
return resourceItem, nil
}
}

return nil, tfresource.NewEmptyResultError(input)
}
171 changes: 171 additions & 0 deletions internal/service/resourcegroups/resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package resourcegroups_test

import (
"context"
"errors"
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/resourcegroups"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
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"
tfresourcegroups "github.com/hashicorp/terraform-provider-aws/internal/service/resourcegroups"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccResourceGroupsResource_basic(t *testing.T) {
ctx := context.Background()
var r resourcegroups.ListGroupResourcesItem
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_resourcegroups_resource.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, resourcegroups.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckResourceDestroy,
Steps: []resource.TestStep{
{
Config: testAccResourceConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckResourceExists(ctx, resourceName, &r),
resource.TestCheckResourceAttr(resourceName, "resource_type", "AWS::EC2::Host"),
resource.TestCheckResourceAttrSet(resourceName, "group_arn"),
resource.TestCheckResourceAttrSet(resourceName, "resource_arn"),
),
},
},
})
}

func testAccCheckResourceDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).ResourceGroupsConn()
ctx := context.Background()

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_resourcegroups_resource" {
continue
}

_, err := tfresourcegroups.FindResourceByARN(ctx, conn, rs.Primary.Attributes["group_arn"], rs.Primary.Attributes["resource_arn"])

if err != nil {
if tfawserr.ErrCodeEquals(err, resourcegroups.ErrCodeNotFoundException) {
return nil
}
return err
}

return create.Error(names.ResourceGroups, create.ErrActionCheckingDestroyed, tfresourcegroups.ResNameResource, rs.Primary.ID, errors.New("not destroyed"))
}

return nil
}

func testAccCheckResourceExists(ctx context.Context, name string, resource *resourcegroups.ListGroupResourcesItem) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return create.Error(names.ResourceGroups, create.ErrActionCheckingExistence, tfresourcegroups.ResNameResource, name, errors.New("not found"))
}

if rs.Primary.ID == "" {
return create.Error(names.ResourceGroups, create.ErrActionCheckingExistence, tfresourcegroups.ResNameResource, name, errors.New("not set"))
}

conn := acctest.Provider.Meta().(*conns.AWSClient).ResourceGroupsConn()

resp, err := tfresourcegroups.FindResourceByARN(ctx, conn, rs.Primary.Attributes["group_arn"], rs.Primary.Attributes["resource_arn"])

if err != nil {
return create.Error(names.ResourceGroups, create.ErrActionCheckingExistence, tfresourcegroups.ResNameResource, rs.Primary.ID, err)
}

*resource = *resp

return nil
}
}

func testAccResourceConfig_base(rName string) string {
return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(`
resource "aws_ec2_host" "test" {
auto_placement = "on"
availability_zone = data.aws_availability_zones.available.names[0]
host_recovery = "off"
instance_family = "c5"
tags = {
Name = %[1]q
}
}
resource "aws_resourcegroups_group" "test" {
name = %[1]q
configuration {
type = "AWS::EC2::HostManagement"
parameters {
name = "any-host-based-license-configuration"
values = [
"true"
]
}
parameters {
name = "auto-allocate-host"
values = [
"false"
]
}
parameters {
name = "auto-host-recovery"
values = [
"false"
]
}
parameters {
name = "auto-release-host"
values = [
"false"
]
}
}
configuration {
type = "AWS::ResourceGroups::Generic"
parameters {
name = "allowed-resource-types"
values = [
"AWS::EC2::Host"
]
}
parameters {
name = "deletion-protection"
values = [
"UNLESS_EMPTY"
]
}
}
}
`, rName))
}

func testAccResourceConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccResourceConfig_base(rName), `
resource "aws_resourcegroups_resource" "test" {
group_arn = aws_resourcegroups_group.test.arn
resource_arn = aws_ec2_host.test.arn
}
`)
}
5 changes: 5 additions & 0 deletions internal/service/resourcegroups/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5ab1842

Please sign in to comment.