-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19304 from coderGo93/macie2-member-invitation
New resource for Macie2 Member and Invitation Accepter
- Loading branch information
Showing
13 changed files
with
1,318 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
```release-note:new-resource | ||
aws_macie2_member | ||
``` | ||
|
||
```release-note:new-resource | ||
aws_macie2_invitation_accepter | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package finder | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/macie2" | ||
) | ||
|
||
// MemberNotAssociated Return a list of members not associated and compare with account ID | ||
func MemberNotAssociated(conn *macie2.Macie2, accountID string) (*macie2.Member, error) { | ||
input := &macie2.ListMembersInput{ | ||
OnlyAssociated: aws.String("false"), | ||
} | ||
var result *macie2.Member | ||
|
||
err := conn.ListMembersPages(input, func(page *macie2.ListMembersOutput, lastPage bool) bool { | ||
if page == nil { | ||
return !lastPage | ||
} | ||
|
||
for _, member := range page.Members { | ||
if member == nil { | ||
continue | ||
} | ||
|
||
if aws.StringValue(member.AccountId) == accountID { | ||
result = member | ||
return false | ||
} | ||
} | ||
|
||
return !lastPage | ||
}) | ||
|
||
return result, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package waiter | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/macie2" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/macie2/finder" | ||
) | ||
|
||
// MemberRelationshipStatus fetches the Member and its relationship status | ||
func MemberRelationshipStatus(conn *macie2.Macie2, adminAccountID string) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
adminAccount, err := finder.MemberNotAssociated(conn, adminAccountID) | ||
|
||
if err != nil { | ||
return nil, "Unknown", err | ||
} | ||
|
||
if adminAccount == nil { | ||
return adminAccount, "NotFound", nil | ||
} | ||
|
||
return adminAccount, aws.StringValue(adminAccount.RelationshipStatus), nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package waiter | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/service/macie2" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
const ( | ||
// Maximum amount of time to wait for the MemberRelationshipStatus to be Invited, Enabled, or Paused | ||
MemberInvitedTimeout = 5 * time.Minute | ||
) | ||
|
||
// MemberInvited waits for an AdminAccount to return Invited, Enabled and Paused | ||
func MemberInvited(ctx context.Context, conn *macie2.Macie2, adminAccountID string) (*macie2.Member, error) { | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{macie2.RelationshipStatusCreated, macie2.RelationshipStatusEmailVerificationInProgress}, | ||
Target: []string{macie2.RelationshipStatusInvited, macie2.RelationshipStatusEnabled, macie2.RelationshipStatusPaused}, | ||
Refresh: MemberRelationshipStatus(conn, adminAccountID), | ||
Timeout: MemberInvitedTimeout, | ||
} | ||
|
||
outputRaw, err := stateConf.WaitForStateContext(ctx) | ||
|
||
if output, ok := outputRaw.(*macie2.Member); ok { | ||
return output, err | ||
} | ||
|
||
return nil, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package aws | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/macie2" | ||
"github.com/hashicorp/aws-sdk-go-base/tfawserr" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
func resourceAwsMacie2InvitationAccepter() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateWithoutTimeout: resourceMacie2InvitationAccepterCreate, | ||
ReadWithoutTimeout: resourceMacie2InvitationAccepterRead, | ||
DeleteWithoutTimeout: resourceMacie2InvitationAccepterDelete, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"administrator_account_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateAwsAccountId, | ||
}, | ||
"invitation_id": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
Timeouts: &schema.ResourceTimeout{ | ||
Create: schema.DefaultTimeout(1 * time.Minute), | ||
}, | ||
} | ||
} | ||
|
||
func resourceMacie2InvitationAccepterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
conn := meta.(*AWSClient).macie2conn | ||
|
||
adminAccountID := d.Get("administrator_account_id").(string) | ||
var invitationID string | ||
|
||
listInvitationsInput := &macie2.ListInvitationsInput{} | ||
|
||
err := resource.RetryContext(ctx, d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { | ||
err := conn.ListInvitationsPages(listInvitationsInput, func(page *macie2.ListInvitationsOutput, lastPage bool) bool { | ||
for _, invitation := range page.Invitations { | ||
if aws.StringValue(invitation.AccountId) == adminAccountID { | ||
invitationID = aws.StringValue(invitation.InvitationId) | ||
return false | ||
} | ||
} | ||
return !lastPage | ||
}) | ||
|
||
if err != nil { | ||
return resource.NonRetryableError(err) | ||
} | ||
|
||
if invitationID == "" { | ||
return resource.RetryableError(fmt.Errorf("unable to find pending Macie Invitation for administrator account ID (%s)", adminAccountID)) | ||
} | ||
|
||
return nil | ||
}) | ||
|
||
if isResourceTimeoutError(err) { | ||
err = conn.ListInvitationsPages(listInvitationsInput, func(page *macie2.ListInvitationsOutput, lastPage bool) bool { | ||
for _, invitation := range page.Invitations { | ||
if aws.StringValue(invitation.AccountId) == adminAccountID { | ||
invitationID = aws.StringValue(invitation.InvitationId) | ||
return false | ||
} | ||
} | ||
return !lastPage | ||
}) | ||
} | ||
if err != nil { | ||
return diag.FromErr(fmt.Errorf("error listing Macie InvitationAccepter (%s): %w", d.Id(), err)) | ||
} | ||
|
||
acceptInvitationInput := &macie2.AcceptInvitationInput{ | ||
InvitationId: aws.String(invitationID), | ||
AdministratorAccountId: aws.String(adminAccountID), | ||
} | ||
|
||
_, err = conn.AcceptInvitationWithContext(ctx, acceptInvitationInput) | ||
|
||
if err != nil { | ||
return diag.FromErr(fmt.Errorf("error accepting Macie InvitationAccepter (%s): %w", d.Id(), err)) | ||
} | ||
|
||
d.SetId(adminAccountID) | ||
|
||
return resourceMacie2InvitationAccepterRead(ctx, d, meta) | ||
} | ||
|
||
func resourceMacie2InvitationAccepterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
conn := meta.(*AWSClient).macie2conn | ||
|
||
var err error | ||
|
||
input := &macie2.GetAdministratorAccountInput{} | ||
|
||
output, err := conn.GetAdministratorAccountWithContext(ctx, input) | ||
|
||
if tfawserr.ErrCodeEquals(err, macie2.ErrCodeResourceNotFoundException) || | ||
tfawserr.ErrMessageContains(err, macie2.ErrCodeAccessDeniedException, "Macie is not enabled") { | ||
log.Printf("[WARN] Macie InvitationAccepter (%s) not found, removing from state", d.Id()) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
if err != nil { | ||
return diag.FromErr(fmt.Errorf("error reading Macie InvitationAccepter (%s): %w", d.Id(), err)) | ||
} | ||
|
||
if output == nil || output.Administrator == nil { | ||
return diag.FromErr(fmt.Errorf("error reading Macie InvitationAccepter (%s): %w", d.Id(), err)) | ||
} | ||
|
||
d.Set("administrator_account_id", output.Administrator.AccountId) | ||
d.Set("invitation_id", output.Administrator.InvitationId) | ||
return nil | ||
} | ||
|
||
func resourceMacie2InvitationAccepterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
conn := meta.(*AWSClient).macie2conn | ||
|
||
input := &macie2.DisassociateFromAdministratorAccountInput{} | ||
|
||
_, err := conn.DisassociateFromAdministratorAccountWithContext(ctx, input) | ||
if err != nil { | ||
if tfawserr.ErrCodeEquals(err, macie2.ErrCodeResourceNotFoundException) || | ||
tfawserr.ErrMessageContains(err, macie2.ErrCodeAccessDeniedException, "Macie is not enabled") { | ||
return nil | ||
} | ||
return diag.FromErr(fmt.Errorf("error disassociating Macie InvitationAccepter (%s): %w", d.Id(), err)) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.