Skip to content

Commit 85893b6

Browse files
committed
Merge branch 'YakDriver-ram-invite'
2 parents fde3387 + c03d1a9 commit 85893b6

6 files changed

+497
-2
lines changed

aws/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ func Provider() terraform.ResourceProvider {
635635
"aws_ram_principal_association": resourceAwsRamPrincipalAssociation(),
636636
"aws_ram_resource_association": resourceAwsRamResourceAssociation(),
637637
"aws_ram_resource_share": resourceAwsRamResourceShare(),
638+
"aws_ram_resource_share_accepter": resourceAwsRamResourceShareAccepter(),
638639
"aws_rds_cluster": resourceAwsRDSCluster(),
639640
"aws_rds_cluster_endpoint": resourceAwsRDSClusterEndpoint(),
640641
"aws_rds_cluster_instance": resourceAwsRDSClusterInstance(),
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
package aws
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"strings"
7+
"time"
8+
9+
"github.com/aws/aws-sdk-go/aws"
10+
"github.com/aws/aws-sdk-go/service/ram"
11+
12+
"github.com/hashicorp/terraform/helper/resource"
13+
"github.com/hashicorp/terraform/helper/schema"
14+
)
15+
16+
func resourceAwsRamResourceShareAccepter() *schema.Resource {
17+
return &schema.Resource{
18+
Create: resourceAwsRamResourceShareAccepterCreate,
19+
Read: resourceAwsRamResourceShareAccepterRead,
20+
Delete: resourceAwsRamResourceShareAccepterDelete,
21+
22+
Importer: &schema.ResourceImporter{
23+
State: schema.ImportStatePassthrough,
24+
},
25+
26+
Timeouts: &schema.ResourceTimeout{
27+
Create: schema.DefaultTimeout(5 * time.Minute),
28+
Delete: schema.DefaultTimeout(5 * time.Minute),
29+
},
30+
31+
Schema: map[string]*schema.Schema{
32+
"share_arn": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
ForceNew: true,
36+
ValidateFunc: validateArn,
37+
},
38+
39+
"invitation_arn": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
},
43+
44+
"share_id": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
},
48+
49+
"status": {
50+
Type: schema.TypeString,
51+
Computed: true,
52+
},
53+
54+
"receiver_account_id": {
55+
Type: schema.TypeString,
56+
Computed: true,
57+
},
58+
59+
"sender_account_id": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
},
63+
64+
"share_name": {
65+
Type: schema.TypeString,
66+
Computed: true,
67+
},
68+
69+
"resources": {
70+
Type: schema.TypeList,
71+
Computed: true,
72+
Elem: &schema.Schema{
73+
Type: schema.TypeString,
74+
},
75+
},
76+
},
77+
}
78+
}
79+
80+
func resourceAwsRamResourceShareAccepterCreate(d *schema.ResourceData, meta interface{}) error {
81+
conn := meta.(*AWSClient).ramconn
82+
83+
shareARN := d.Get("share_arn").(string)
84+
85+
invitation, err := resourceAwsRamResourceShareGetInvitation(conn, shareARN, ram.ResourceShareInvitationStatusPending)
86+
87+
if err != nil {
88+
return err
89+
}
90+
91+
if invitation == nil || aws.StringValue(invitation.ResourceShareInvitationArn) == "" {
92+
return fmt.Errorf(
93+
"No RAM Resource Share (%s) invitation found\n\n" +
94+
"NOTE: If both AWS accounts are in the same AWS Organization and RAM Sharing with AWS Organizations is enabled, this resource is not necessary",
95+
shareARN)
96+
}
97+
98+
input := &ram.AcceptResourceShareInvitationInput{
99+
ClientToken: aws.String(resource.UniqueId()),
100+
ResourceShareInvitationArn: invitation.ResourceShareInvitationArn,
101+
}
102+
103+
log.Printf("[DEBUG] Accept RAM resource share invitation request: %s", input)
104+
output, err := conn.AcceptResourceShareInvitation(input)
105+
106+
if err != nil {
107+
return fmt.Errorf("Error accepting RAM resource share invitation: %s", err)
108+
}
109+
110+
d.SetId(shareARN)
111+
112+
stateConf := &resource.StateChangeConf{
113+
Pending: []string{ram.ResourceShareInvitationStatusPending},
114+
Target: []string{ram.ResourceShareInvitationStatusAccepted},
115+
Refresh: resourceAwsRamResourceShareAccepterStateRefreshFunc(
116+
conn,
117+
aws.StringValue(output.ResourceShareInvitation.ResourceShareInvitationArn)),
118+
Timeout: d.Timeout(schema.TimeoutCreate),
119+
}
120+
121+
_, err = stateConf.WaitForState()
122+
123+
if err != nil {
124+
return fmt.Errorf("Error waiting for RAM resource share (%s) state: %s", d.Id(), err)
125+
}
126+
127+
return resourceAwsRamResourceShareAccepterRead(d, meta)
128+
}
129+
130+
func resourceAwsRamResourceShareAccepterRead(d *schema.ResourceData, meta interface{}) error {
131+
conn := meta.(*AWSClient).ramconn
132+
133+
invitation, err := resourceAwsRamResourceShareGetInvitation(conn, d.Id(), ram.ResourceShareInvitationStatusAccepted)
134+
135+
if err == nil && invitation == nil {
136+
log.Printf("[WARN] No RAM resource share invitation by ARN (%s) found, removing from state", d.Id())
137+
d.SetId("")
138+
return nil
139+
}
140+
141+
if err != nil {
142+
return err
143+
}
144+
145+
d.Set("status", invitation.Status)
146+
d.Set("receiver_account_id", invitation.ReceiverAccountId)
147+
d.Set("sender_account_id", invitation.SenderAccountId)
148+
d.Set("share_arn", invitation.ResourceShareArn)
149+
d.Set("invitation_arn", invitation.ResourceShareInvitationArn)
150+
d.Set("share_id", resourceAwsRamResourceShareGetIDFromARN(d.Id()))
151+
d.Set("share_name", invitation.ResourceShareName)
152+
153+
listInput := &ram.ListResourcesInput{
154+
MaxResults: aws.Int64(int64(500)),
155+
ResourceOwner: aws.String(ram.ResourceOwnerOtherAccounts),
156+
ResourceShareArns: aws.StringSlice([]string{d.Id()}),
157+
Principal: invitation.SenderAccountId,
158+
}
159+
160+
var resourceARNs []*string
161+
err = conn.ListResourcesPages(listInput, func(page *ram.ListResourcesOutput, lastPage bool) bool {
162+
for _, resource := range page.Resources {
163+
resourceARNs = append(resourceARNs, resource.Arn)
164+
}
165+
166+
return !lastPage
167+
})
168+
169+
if err != nil {
170+
return fmt.Errorf("Error reading RAM resource share resources %s: %s", d.Id(), err)
171+
}
172+
173+
if err := d.Set("resources", flattenStringList(resourceARNs)); err != nil {
174+
return fmt.Errorf("unable to set resources: %s", err)
175+
}
176+
177+
return nil
178+
}
179+
180+
func resourceAwsRamResourceShareAccepterDelete(d *schema.ResourceData, meta interface{}) error {
181+
conn := meta.(*AWSClient).ramconn
182+
183+
receiverAccountID := d.Get("receiver_account_id").(string)
184+
185+
if receiverAccountID == "" {
186+
return fmt.Errorf("The receiver account ID is required to leave a resource share")
187+
}
188+
189+
input := &ram.DisassociateResourceShareInput{
190+
ClientToken: aws.String(resource.UniqueId()),
191+
ResourceShareArn: aws.String(d.Id()),
192+
Principals: []*string{aws.String(receiverAccountID)},
193+
}
194+
log.Printf("[DEBUG] Leave RAM resource share request: %s", input)
195+
196+
_, err := conn.DisassociateResourceShare(input)
197+
198+
if err != nil {
199+
return fmt.Errorf("Error leaving RAM resource share: %s", err)
200+
}
201+
202+
stateConf := &resource.StateChangeConf{
203+
Pending: []string{ram.ResourceShareAssociationStatusAssociated},
204+
Target: []string{ram.ResourceShareAssociationStatusDisassociated},
205+
Refresh: resourceAwsRamResourceShareStateRefreshFunc(conn, d.Id()),
206+
Timeout: d.Timeout(schema.TimeoutDelete),
207+
}
208+
209+
if _, err := stateConf.WaitForState(); err != nil {
210+
if isAWSErr(err, ram.ErrCodeUnknownResourceException, "") {
211+
// what we want
212+
return nil
213+
}
214+
return fmt.Errorf("Error waiting for RAM resource share (%s) state: %s", d.Id(), err)
215+
}
216+
217+
return nil
218+
}
219+
220+
func resourceAwsRamResourceShareGetInvitation(conn *ram.RAM, resourceShareARN, status string) (*ram.ResourceShareInvitation, error) {
221+
input := &ram.GetResourceShareInvitationsInput{
222+
ResourceShareArns: []*string{aws.String(resourceShareARN)},
223+
}
224+
225+
var invitation *ram.ResourceShareInvitation
226+
err := conn.GetResourceShareInvitationsPages(input, func(page *ram.GetResourceShareInvitationsOutput, lastPage bool) bool {
227+
for _, rsi := range page.ResourceShareInvitations {
228+
if aws.StringValue(rsi.Status) == status {
229+
invitation = rsi
230+
return false
231+
}
232+
}
233+
234+
return !lastPage
235+
})
236+
237+
if invitation == nil {
238+
return nil, nil
239+
}
240+
241+
if err != nil {
242+
return nil, fmt.Errorf("Error reading RAM resource share invitation %s: %s", resourceShareARN, err)
243+
}
244+
245+
return invitation, nil
246+
}
247+
248+
func resourceAwsRamResourceShareAccepterStateRefreshFunc(conn *ram.RAM, invitationArn string) resource.StateRefreshFunc {
249+
return func() (interface{}, string, error) {
250+
request := &ram.GetResourceShareInvitationsInput{
251+
ResourceShareInvitationArns: []*string{aws.String(invitationArn)},
252+
}
253+
254+
output, err := conn.GetResourceShareInvitations(request)
255+
256+
if err != nil {
257+
return nil, "Unable to get resource share invitations", err
258+
}
259+
260+
if len(output.ResourceShareInvitations) == 0 {
261+
return nil, "Resource share invitation not found", nil
262+
}
263+
264+
invitation := output.ResourceShareInvitations[0]
265+
266+
return invitation, aws.StringValue(invitation.Status), nil
267+
}
268+
}
269+
270+
func resourceAwsRamResourceShareGetIDFromARN(arn string) string {
271+
return strings.Replace(arn[strings.LastIndex(arn, ":")+1:], "resource-share/", "rs-", -1)
272+
}

0 commit comments

Comments
 (0)