Skip to content

Commit dd55a03

Browse files
committed
CR updates: align with API and update overall provider design patterns
1 parent b68c7a3 commit dd55a03

File tree

7 files changed

+628
-19
lines changed

7 files changed

+628
-19
lines changed

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,7 @@ func Provider() *schema.Provider {
15961596
"aws_s3_bucket_policy": s3.ResourceBucketPolicy(),
15971597
"aws_s3_bucket_public_access_block": s3.ResourceBucketPublicAccessBlock(),
15981598
"aws_s3_bucket_replication_configuration": s3.ResourceBucketReplicationConfiguration(),
1599+
"aws_s3_bucket_versioning": s3.ResourceBucketVersioning(),
15991600
"aws_s3_object_copy": s3.ResourceObjectCopy(),
16001601

16011602
"aws_s3_access_point": s3control.ResourceAccessPoint(),

internal/service/s3/bucket.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -781,13 +781,13 @@ func resourceBucketUpdate(d *schema.ResourceData, meta interface{}) error {
781781

782782
if d.IsNewResource() {
783783
if versioning := expandVersioningWhenIsNewResource(v); versioning != nil {
784-
err := resourceBucketVersioningUpdate(conn, d.Id(), versioning)
784+
err := resourceBucketInternalVersioningUpdate(conn, d.Id(), versioning)
785785
if err != nil {
786786
return err
787787
}
788788
}
789789
} else {
790-
if err := resourceBucketVersioningUpdate(conn, d.Id(), expandVersioning(v)); err != nil {
790+
if err := resourceBucketInternalVersioningUpdate(conn, d.Id(), expandVersioning(v)); err != nil {
791791
return err
792792
}
793793
}
@@ -1851,7 +1851,7 @@ func resourceBucketACLUpdate(conn *s3.S3, d *schema.ResourceData) error {
18511851
return nil
18521852
}
18531853

1854-
func resourceBucketVersioningUpdate(conn *s3.S3, bucket string, versioningConfig *s3.VersioningConfiguration) error {
1854+
func resourceBucketInternalVersioningUpdate(conn *s3.S3, bucket string, versioningConfig *s3.VersioningConfiguration) error {
18551855
input := &s3.PutBucketVersioningInput{
18561856
Bucket: aws.String(bucket),
18571857
VersioningConfiguration: versioningConfig,
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package s3
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
"github.com/aws/aws-sdk-go/aws"
9+
"github.com/aws/aws-sdk-go/service/s3"
10+
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
14+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
15+
"github.com/hashicorp/terraform-provider-aws/internal/verify"
16+
)
17+
18+
func ResourceBucketVersioning() *schema.Resource {
19+
return &schema.Resource{
20+
CreateContext: resourceBucketVersioningCreate,
21+
ReadContext: resourceBucketVersioningRead,
22+
UpdateContext: resourceBucketVersioningUpdate,
23+
DeleteContext: resourceBucketVersioningDelete,
24+
Importer: &schema.ResourceImporter{
25+
StateContext: schema.ImportStatePassthroughContext,
26+
},
27+
28+
Schema: map[string]*schema.Schema{
29+
"bucket": {
30+
Type: schema.TypeString,
31+
Required: true,
32+
ForceNew: true,
33+
ValidateFunc: validation.StringLenBetween(1, 63),
34+
},
35+
"expected_bucket_owner": {
36+
Type: schema.TypeString,
37+
Optional: true,
38+
ForceNew: true,
39+
ValidateFunc: verify.ValidAccountID,
40+
},
41+
"mfa": {
42+
Type: schema.TypeString,
43+
Optional: true,
44+
},
45+
"versioning_configuration": {
46+
Type: schema.TypeList,
47+
Required: true,
48+
MaxItems: 1,
49+
Elem: &schema.Resource{
50+
Schema: map[string]*schema.Schema{
51+
"mfa_delete": {
52+
Type: schema.TypeString,
53+
Optional: true,
54+
ValidateFunc: validation.StringInSlice(s3.MFADelete_Values(), false),
55+
},
56+
"status": {
57+
Type: schema.TypeString,
58+
Required: true,
59+
ValidateFunc: validation.StringInSlice(s3.BucketVersioningStatus_Values(), false),
60+
},
61+
},
62+
},
63+
},
64+
},
65+
}
66+
}
67+
68+
func resourceBucketVersioningCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
69+
conn := meta.(*conns.AWSClient).S3Conn
70+
71+
bucket := d.Get("bucket").(string)
72+
expectedBucketOwner := d.Get("expected_bucket_owner").(string)
73+
74+
input := &s3.PutBucketVersioningInput{
75+
Bucket: aws.String(bucket),
76+
VersioningConfiguration: expandBucketVersioningConfiguration(d.Get("versioning_configuration").([]interface{})),
77+
}
78+
79+
if expectedBucketOwner != "" {
80+
input.ExpectedBucketOwner = aws.String(expectedBucketOwner)
81+
}
82+
83+
if v, ok := d.GetOk("mfa"); ok {
84+
input.MFA = aws.String(v.(string))
85+
}
86+
87+
_, err := verify.RetryOnAWSCode(s3.ErrCodeNoSuchBucket, func() (interface{}, error) {
88+
return conn.PutBucketVersioningWithContext(ctx, input)
89+
})
90+
91+
if err != nil {
92+
return diag.FromErr(fmt.Errorf("error creating S3 bucket versioning for %s: %w", bucket, err))
93+
}
94+
95+
d.SetId(CreateResourceID(bucket, expectedBucketOwner))
96+
97+
return resourceBucketVersioningRead(ctx, d, meta)
98+
}
99+
100+
func resourceBucketVersioningRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
101+
conn := meta.(*conns.AWSClient).S3Conn
102+
103+
bucket, expectedBucketOwner, err := ParseResourceID(d.Id())
104+
if err != nil {
105+
return diag.FromErr(err)
106+
}
107+
108+
input := &s3.GetBucketVersioningInput{
109+
Bucket: aws.String(bucket),
110+
}
111+
112+
if expectedBucketOwner != "" {
113+
input.ExpectedBucketOwner = aws.String(expectedBucketOwner)
114+
}
115+
116+
output, err := conn.GetBucketVersioningWithContext(ctx, input)
117+
118+
if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchBucket) {
119+
log.Printf("[WARN] S3 Bucket Versioning (%s) not found, removing from state", d.Id())
120+
d.SetId("")
121+
return nil
122+
}
123+
124+
if err != nil {
125+
return diag.FromErr(fmt.Errorf("error getting S3 bucket versioning (%s): %w", d.Id(), err))
126+
}
127+
128+
if output == nil {
129+
if d.IsNewResource() {
130+
return diag.FromErr(fmt.Errorf("error getting S3 bucket versioning (%s): empty output", d.Id()))
131+
}
132+
log.Printf("[WARN] S3 Bucket Versioning (%s) not found, removing from state", d.Id())
133+
d.SetId("")
134+
return nil
135+
}
136+
137+
d.Set("bucket", bucket)
138+
d.Set("expected_bucket_owner", expectedBucketOwner)
139+
if err := d.Set("versioning_configuration", flattenBucketVersioningConfiguration(output)); err != nil {
140+
return diag.FromErr(fmt.Errorf("error setting versioning_configuration: %w", err))
141+
}
142+
143+
return nil
144+
}
145+
146+
func resourceBucketVersioningUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
147+
conn := meta.(*conns.AWSClient).S3Conn
148+
149+
bucket, expectedBucketOwner, err := ParseResourceID(d.Id())
150+
if err != nil {
151+
return diag.FromErr(err)
152+
}
153+
154+
input := &s3.PutBucketVersioningInput{
155+
Bucket: aws.String(bucket),
156+
VersioningConfiguration: expandBucketVersioningConfiguration(d.Get("versioning_configuration").([]interface{})),
157+
}
158+
159+
if expectedBucketOwner != "" {
160+
input.ExpectedBucketOwner = aws.String(expectedBucketOwner)
161+
}
162+
163+
if v, ok := d.GetOk("mfa"); ok {
164+
input.MFA = aws.String(v.(string))
165+
}
166+
167+
_, err = conn.PutBucketVersioningWithContext(ctx, input)
168+
169+
if err != nil {
170+
return diag.FromErr(fmt.Errorf("error updating S3 bucket versioning (%s): %w", d.Id(), err))
171+
}
172+
173+
return resourceBucketVersioningRead(ctx, d, meta)
174+
}
175+
176+
func resourceBucketVersioningDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
177+
conn := meta.(*conns.AWSClient).S3Conn
178+
179+
bucket, expectedBucketOwner, err := ParseResourceID(d.Id())
180+
if err != nil {
181+
return diag.FromErr(err)
182+
}
183+
184+
input := &s3.PutBucketVersioningInput{
185+
Bucket: aws.String(bucket),
186+
VersioningConfiguration: &s3.VersioningConfiguration{
187+
// Status must be provided thus to "remove" this resource,
188+
// we suspend versioning
189+
Status: aws.String(s3.BucketVersioningStatusSuspended),
190+
},
191+
}
192+
193+
if expectedBucketOwner != "" {
194+
input.ExpectedBucketOwner = aws.String(expectedBucketOwner)
195+
}
196+
197+
_, err = conn.PutBucketVersioningWithContext(ctx, input)
198+
199+
if tfawserr.ErrCodeEquals(err, s3.ErrCodeNoSuchBucket) {
200+
return nil
201+
}
202+
203+
if err != nil {
204+
return diag.FromErr(fmt.Errorf("error deleting S3 bucket versioning (%s): %w", d.Id(), err))
205+
}
206+
207+
return nil
208+
}
209+
210+
func expandBucketVersioningConfiguration(l []interface{}) *s3.VersioningConfiguration {
211+
if len(l) == 0 || l[0] == nil {
212+
return nil
213+
}
214+
215+
tfMap, ok := l[0].(map[string]interface{})
216+
if !ok {
217+
return nil
218+
}
219+
220+
result := &s3.VersioningConfiguration{}
221+
222+
if v, ok := tfMap["mfa_delete"].(string); ok && v != "" {
223+
result.MFADelete = aws.String(v)
224+
}
225+
226+
if v, ok := tfMap["status"].(string); ok && v != "" {
227+
result.Status = aws.String(v)
228+
}
229+
230+
return result
231+
}
232+
233+
func flattenBucketVersioningConfiguration(config *s3.GetBucketVersioningOutput) []interface{} {
234+
if config == nil {
235+
return []interface{}{}
236+
}
237+
238+
m := make(map[string]interface{})
239+
240+
if config.MFADelete != nil {
241+
m["mfa_delete"] = aws.StringValue(config.MFADelete)
242+
}
243+
244+
if config.Status != nil {
245+
m["status"] = aws.StringValue(config.Status)
246+
}
247+
248+
return []interface{}{m}
249+
}

0 commit comments

Comments
 (0)