Skip to content

Commit 215183d

Browse files
committed
Add AWS QuickSight IAM Policy Assignment
Cribbed from prior art implementation here: hashicorp/terraform-provider-aws#12279
1 parent 3536aed commit 215183d

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed

aws/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ func Provider() terraform.ResourceProvider {
173173
"aws_iam_role_policy_attachment": resourceAwsIamRolePolicyAttachment(),
174174
"aws_quicksight_data_source": resourceAwsQuickSightDataSource(),
175175
"aws_quicksight_group_membership": resourceAwsQuickSightGroupMembership(),
176+
"aws_quicksight_iam_policy_assignment": resourceAwsQuickSightIAMPolicyAssignment(),
176177
"aws_internet_gateway_detach": resourceAwsInternetGatewayDetach(),
177178
"aws_internet_gateway_delete": resourceAwsInternetGatewayDelete(),
178179
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
package aws
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
6+
"log"
7+
"regexp"
8+
"strings"
9+
"time"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
12+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
13+
14+
"github.com/aws/aws-sdk-go/aws"
15+
"github.com/aws/aws-sdk-go/service/quicksight"
16+
)
17+
18+
var resourceAwsQuickSighIAMPolicyAttachmentCUPendingStates = []string{
19+
quicksight.AssignmentStatusDisabled,
20+
quicksight.AssignmentStatusDraft,
21+
"",
22+
}
23+
24+
func resourceAwsQuickSightIAMPolicyAssignment() *schema.Resource {
25+
return &schema.Resource{
26+
Create: resourceAwsQuickSightIAMPolicyAssignmentCreate,
27+
Read: resourceAwsQuickSightIAMPolicyAssignmentRead,
28+
Update: resourceAwsQuickSightIAMPolicyAssignmentUpdate,
29+
Delete: resourceAwsQuickSightIAMPolicyAssignmentDelete,
30+
31+
Importer: &schema.ResourceImporter{
32+
State: schema.ImportStatePassthrough,
33+
},
34+
35+
Timeouts: &schema.ResourceTimeout{
36+
Create: schema.DefaultTimeout(60 * time.Second),
37+
Read: schema.DefaultTimeout(60 * time.Second),
38+
Update: schema.DefaultTimeout(60 * time.Second),
39+
Delete: schema.DefaultTimeout(60 * time.Second),
40+
},
41+
42+
Schema: map[string]*schema.Schema{
43+
"assignment_name": {
44+
Type: schema.TypeString,
45+
Required: true,
46+
ValidateFunc: validation.StringMatch(
47+
regexp.MustCompile("^[a-zA-Z0-9]*$"),
48+
"The value may only contain alphanumeric value. Special chars not allowed"),
49+
},
50+
51+
"assignment_status": {
52+
Type: schema.TypeString,
53+
Required: true,
54+
},
55+
56+
"aws_account_id": {
57+
Type: schema.TypeString,
58+
Optional: true,
59+
Computed: true,
60+
ForceNew: true,
61+
},
62+
63+
"groups": {
64+
Type: schema.TypeSet,
65+
Elem: &schema.Schema{Type: schema.TypeString},
66+
Set: schema.HashString,
67+
Optional: true,
68+
},
69+
70+
"users": {
71+
Type: schema.TypeSet,
72+
Elem: &schema.Schema{Type: schema.TypeString},
73+
Set: schema.HashString,
74+
Optional: true,
75+
},
76+
77+
"policy_arn": {
78+
Type: schema.TypeString,
79+
Required: true,
80+
},
81+
82+
"namespace": {
83+
Type: schema.TypeString,
84+
Default: "default",
85+
Optional: true,
86+
ValidateFunc: validation.StringInSlice([]string{
87+
"default",
88+
}, false),
89+
},
90+
},
91+
}
92+
}
93+
94+
func resourceAwsQuickSightIAMPolicyAssignmentCreate(d *schema.ResourceData, meta interface{}) error {
95+
conn := meta.(*AWSClient).quicksightconn
96+
97+
awsAccountId := d.Get("aws_account_id").(string)
98+
namespace := d.Get("namespace").(string)
99+
assignmentName := d.Get("assignment_name").(string)
100+
101+
if v, ok := d.GetOk("aws_account_id"); ok {
102+
awsAccountId = v.(string)
103+
}
104+
105+
identities := make(map[string][]*string)
106+
if groupAttr := d.Get("groups").(*schema.Set); groupAttr.Len() > 0 {
107+
identities["Group"] = expandStringList(groupAttr.List())
108+
}
109+
110+
if userAttr := d.Get("users").(*schema.Set); userAttr.Len() > 0 {
111+
identities["User"] = expandStringList(userAttr.List())
112+
}
113+
114+
createOpts := &quicksight.CreateIAMPolicyAssignmentInput{
115+
AssignmentName: aws.String(assignmentName),
116+
AssignmentStatus: aws.String(d.Get("assignment_status").(string)),
117+
AwsAccountId: aws.String(awsAccountId),
118+
Identities: identities,
119+
Namespace: aws.String(namespace),
120+
PolicyArn: aws.String(d.Get("policy_arn").(string)),
121+
}
122+
123+
resp, err := conn.CreateIAMPolicyAssignment(createOpts)
124+
if err != nil {
125+
return fmt.Errorf("Error creating QuickSight IAM Policy Assignment: %s", err)
126+
}
127+
128+
_, err = waitIAMPolicyAttachmentCreate(conn, awsAccountId, assignmentName, namespace, d.Timeout(schema.TimeoutCreate))
129+
if err != nil {
130+
return fmt.Errorf("Error waiting for Data Source (%s) to become available: %s", assignmentName, err)
131+
}
132+
133+
d.SetId(fmt.Sprintf("%s/%s/%s", awsAccountId, namespace, aws.StringValue(resp.AssignmentName)))
134+
return resourceAwsQuickSightIAMPolicyAssignmentRead(d, meta)
135+
}
136+
137+
func waitIAMPolicyAttachmentCreate(conn *quicksight.QuickSight, awsAccountId, assignmentName, namespace string, timeout time.Duration) (interface{}, error) {
138+
stateChangeConf := &resource.StateChangeConf{
139+
Pending: resourceAwsQuickSighIAMPolicyAttachmentCUPendingStates,
140+
Target: []string{quicksight.AssignmentStatusEnabled},
141+
Refresh: iamPolicyAttachmentStateRefreshFunc(conn, awsAccountId, assignmentName, namespace),
142+
Timeout: timeout,
143+
Delay: 5 * time.Second,
144+
}
145+
return stateChangeConf.WaitForState()
146+
}
147+
148+
func iamPolicyAttachmentStateRefreshFunc(conn *quicksight.QuickSight, awsAccountId, assignmentName, namespace string) resource.StateRefreshFunc {
149+
return func() (interface{}, string, error) {
150+
req := &quicksight.DescribeIAMPolicyAssignmentInput{
151+
AssignmentName: aws.String(assignmentName),
152+
AwsAccountId: aws.String(awsAccountId),
153+
Namespace: aws.String(namespace),
154+
}
155+
resp, err := conn.DescribeIAMPolicyAssignment(req)
156+
if err != nil {
157+
return nil, "", err
158+
}
159+
160+
assignmentId := resp.IAMPolicyAssignment.AssignmentId
161+
state := ""
162+
if aws.StringValue(resp.IAMPolicyAssignment.AssignmentStatus) == quicksight.AssignmentStatusEnabled {
163+
state = quicksight.AssignmentStatusEnabled
164+
}
165+
return assignmentId, state, nil
166+
}
167+
}
168+
169+
func resourceAwsQuickSightIAMPolicyAssignmentRead(d *schema.ResourceData, meta interface{}) error {
170+
conn := meta.(*AWSClient).quicksightconn
171+
172+
awsAccountID, namespace, assignmentName, err := resourceAwsQuickSightIAMPolicyAssignmentParseID(d.Id())
173+
if err != nil {
174+
return err
175+
}
176+
177+
descOpts := &quicksight.DescribeIAMPolicyAssignmentInput{
178+
AssignmentName: aws.String(assignmentName),
179+
AwsAccountId: aws.String(awsAccountID),
180+
Namespace: aws.String(namespace),
181+
}
182+
183+
resp, err := conn.DescribeIAMPolicyAssignment(descOpts)
184+
if isAWSErr(err, quicksight.ErrCodeResourceNotFoundException, "") {
185+
log.Printf("[WARN] QuickSight IAM Policy Assignment %s not found", d.Id())
186+
d.SetId("")
187+
return nil
188+
}
189+
if err != nil {
190+
return fmt.Errorf("Error describing QuickSight IAM Policy Assignment (%s): %s", d.Id(), err)
191+
}
192+
193+
d.Set("aws_account_id", resp.IAMPolicyAssignment.AwsAccountId)
194+
d.Set("namespace", namespace)
195+
d.Set("assignment_id", resp.IAMPolicyAssignment.AssignmentId)
196+
d.Set("assignment_name", resp.IAMPolicyAssignment.AssignmentName)
197+
d.Set("assignment_status", resp.IAMPolicyAssignment.AssignmentStatus)
198+
d.Set("identities", resp.IAMPolicyAssignment.Identities)
199+
d.Set("groups", resp.IAMPolicyAssignment.Identities["group"])
200+
d.Set("users", resp.IAMPolicyAssignment.Identities["user"])
201+
d.Set("policy_arn", resp.IAMPolicyAssignment.PolicyArn)
202+
203+
return nil
204+
}
205+
206+
func resourceAwsQuickSightIAMPolicyAssignmentUpdate(d *schema.ResourceData, meta interface{}) error {
207+
conn := meta.(*AWSClient).quicksightconn
208+
awsAccountID, namespace, assignmentName, err := resourceAwsQuickSightIAMPolicyAssignmentParseID(d.Id())
209+
if err != nil {
210+
return err
211+
}
212+
213+
identities := make(map[string][]*string)
214+
if groupAttr := d.Get("groups").(*schema.Set); groupAttr.Len() > 0 {
215+
identities["Group"] = expandStringList(groupAttr.List())
216+
}
217+
if userAttr := d.Get("users").(*schema.Set); userAttr.Len() > 0 {
218+
identities["User"] = expandStringList(userAttr.List())
219+
}
220+
221+
updateOpts := &quicksight.UpdateIAMPolicyAssignmentInput{
222+
AssignmentName: aws.String(assignmentName),
223+
AssignmentStatus: aws.String(d.Get("assignment_status").(string)),
224+
AwsAccountId: aws.String(awsAccountID),
225+
Identities: identities,
226+
Namespace: aws.String(namespace),
227+
PolicyArn: aws.String(d.Get("policy_arn").(string)),
228+
}
229+
230+
_, err = conn.UpdateIAMPolicyAssignment(updateOpts)
231+
if isAWSErr(err, quicksight.ErrCodeResourceNotFoundException, "") {
232+
log.Printf("[ERROR] QuickSight IAM Policy Assignment %s not found", d.Id())
233+
d.SetId("")
234+
return nil
235+
}
236+
if err != nil {
237+
return fmt.Errorf("Error updating QuickSight IAM Policy Assignment %s: %s", d.Id(), err)
238+
}
239+
return resourceAwsQuickSightIAMPolicyAssignmentRead(d, meta)
240+
}
241+
242+
func resourceAwsQuickSightIAMPolicyAssignmentDelete(d *schema.ResourceData, meta interface{}) error {
243+
conn := meta.(*AWSClient).quicksightconn
244+
245+
awsAccountID, namespace, assignmentName, err := resourceAwsQuickSightIAMPolicyAssignmentParseID(d.Id())
246+
if err != nil {
247+
return err
248+
}
249+
250+
deleteOpts := &quicksight.DeleteIAMPolicyAssignmentInput{
251+
AssignmentName: aws.String(assignmentName),
252+
AwsAccountId: aws.String(awsAccountID),
253+
Namespace: aws.String(namespace),
254+
}
255+
256+
if _, err := conn.DeleteIAMPolicyAssignment(deleteOpts); err != nil {
257+
if isAWSErr(err, quicksight.ErrCodeResourceNotFoundException, "") {
258+
return nil
259+
}
260+
return fmt.Errorf("Error deleting QuickSight IAM Policy Assignment %s: %s", d.Id(), err)
261+
}
262+
263+
return nil
264+
}
265+
266+
func resourceAwsQuickSightIAMPolicyAssignmentParseID(id string) (string, string, string, error) {
267+
parts := strings.SplitN(id, "/", 3)
268+
if len(parts) < 3 || parts[0] == "" || parts[1] == "" || parts[2] == "" {
269+
return "", "", "", fmt.Errorf("unexpected format of ID (%s), expected AWS_ACCOUNT_ID/NAMESPACE/GROUP_NAME", id)
270+
}
271+
return parts[0], parts[1], parts[2], nil
272+
}

0 commit comments

Comments
 (0)