Skip to content

Commit 28647b1

Browse files
authored
feat(object): enable versionning on bucket resource (#656)
1 parent 195704a commit 28647b1

6 files changed

+227
-6
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/google/go-cmp v0.5.2
77
github.com/hashicorp/go-retryablehttp v0.6.7
88
github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0
9-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201109203223-9446a84bfb2a
9+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201113152841-1153aa56e20e
1010
github.com/stretchr/testify v1.6.1
1111
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
1212
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201106174615-fd524d38cee8
303303
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201106174615-fd524d38cee8/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
304304
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201109203223-9446a84bfb2a h1:bcVe/pXc4HWi8RwkiiYOdIjYWjQvR5eeMRaepXGW298=
305305
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201109203223-9446a84bfb2a/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
306+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201113152841-1153aa56e20e h1:KW5n7q2CMM/MsFNAwdZWB0UioVa3E3XQSrKRZcjmaGo=
307+
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201113152841-1153aa56e20e/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
306308
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
307309
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
308310
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=

scaleway/helpers_object.go

+48
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package scaleway
22

33
import (
4+
"errors"
45
"fmt"
6+
"os"
7+
"strings"
58

69
"github.com/aws/aws-sdk-go/aws"
10+
"github.com/aws/aws-sdk-go/aws/awserr"
711
"github.com/aws/aws-sdk-go/aws/credentials"
812
"github.com/aws/aws-sdk-go/aws/session"
913
"github.com/aws/aws-sdk-go/service/s3"
@@ -16,6 +20,9 @@ func newS3Client(region, accessKey, secretKey string) (*s3.S3, error) {
1620
config.WithRegion(region)
1721
config.WithCredentials(credentials.NewStaticCredentials(accessKey, secretKey, ""))
1822
config.WithEndpoint("https://s3." + region + ".scw.cloud")
23+
if strings.ToLower(os.Getenv("TF_LOG")) == "debug" {
24+
config.WithLogLevel(aws.LogDebugWithHTTPBody)
25+
}
1926

2027
s, err := session.NewSession(config)
2128
if err != nil {
@@ -98,3 +105,44 @@ func expandObjectBucketTags(tags interface{}) []*s3.Tag {
98105
func objectBucketEndpointURL(bucketName string, region scw.Region) string {
99106
return fmt.Sprintf("https://%s.s3.%s.scw.cloud", bucketName, region)
100107
}
108+
109+
// Returns true if the error matches all these conditions:
110+
// * err is of type awserr.Error
111+
// * Error.Code() matches code
112+
// * Error.Message() contains message
113+
func isS3Err(err error, code string, message string) bool {
114+
var awsErr awserr.Error
115+
if errors.As(err, &awsErr) {
116+
return awsErr.Code() == code && strings.Contains(awsErr.Message(), message)
117+
}
118+
return false
119+
}
120+
121+
func flattenObjectBucketVersioning(versioningResponse *s3.GetBucketVersioningOutput) []map[string]interface{} {
122+
vcl := make([]map[string]interface{}, 0, 1)
123+
vc := make(map[string]interface{})
124+
if versioningResponse.Status != nil && aws.StringValue(versioningResponse.Status) == s3.BucketVersioningStatusEnabled {
125+
vc["enabled"] = true
126+
} else {
127+
vc["enabled"] = false
128+
}
129+
vcl = append(vcl, vc)
130+
return vcl
131+
}
132+
133+
func expandObjectBucketVersioning(v []interface{}) *s3.VersioningConfiguration {
134+
vc := &s3.VersioningConfiguration{}
135+
136+
if len(v) > 0 {
137+
c := v[0].(map[string]interface{})
138+
139+
if c["enabled"].(bool) {
140+
vc.Status = aws.String(s3.BucketVersioningStatusEnabled)
141+
} else {
142+
vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
143+
}
144+
} else {
145+
vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
146+
}
147+
return vc
148+
}

scaleway/provider_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scaleway
22

33
import (
4+
"context"
45
"flag"
56
"net/http"
67
"os"
@@ -91,6 +92,7 @@ type TestTools struct {
9192
Meta *Meta
9293
ProviderFactories map[string]func() (*schema.Provider, error)
9394
Cleanup func()
95+
ctx context.Context
9496
}
9597

9698
func NewTestTools(t *testing.T) *TestTools {
@@ -115,5 +117,6 @@ func NewTestTools(t *testing.T) *TestTools {
115117
},
116118
},
117119
Cleanup: cleanup,
120+
ctx: context.Background(),
118121
}
119122
}

scaleway/resource_object_bucket.go

+54-5
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,30 @@ func resourceScalewayObjectBucket() *schema.Resource {
5454
Computed: true,
5555
},
5656
"region": regionSchema(),
57+
"versioning": {
58+
Type: schema.TypeList,
59+
Optional: true,
60+
Computed: true,
61+
MaxItems: 1,
62+
Elem: &schema.Resource{
63+
Schema: map[string]*schema.Schema{
64+
"enabled": {
65+
Type: schema.TypeBool,
66+
Optional: true,
67+
Default: false,
68+
},
69+
},
70+
},
71+
},
5772
},
5873
}
5974
}
6075

61-
func resourceScalewayObjectBucketCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
76+
func resourceScalewayObjectBucketCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
6277
bucketName := d.Get("name").(string)
6378
acl := d.Get("acl").(string)
6479

65-
s3Client, region, err := s3ClientWithRegion(d, m)
80+
s3Client, region, err := s3ClientWithRegion(d, meta)
6681
if err != nil {
6782
return diag.FromErr(err)
6883
}
@@ -91,11 +106,11 @@ func resourceScalewayObjectBucketCreate(ctx context.Context, d *schema.ResourceD
91106

92107
d.SetId(newRegionalIDString(region, bucketName))
93108

94-
return resourceScalewayObjectBucketRead(ctx, d, m)
109+
return resourceScalewayObjectBucketRead(ctx, d, meta)
95110
}
96111

97-
func resourceScalewayObjectBucketRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
98-
s3Client, region, bucketName, err := s3ClientWithRegionAndName(m, d.Id())
112+
func resourceScalewayObjectBucketRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
113+
s3Client, region, bucketName, err := s3ClientWithRegionAndName(meta, d.Id())
99114
if err != nil {
100115
return diag.FromErr(err)
101116
}
@@ -140,6 +155,15 @@ func resourceScalewayObjectBucketRead(ctx context.Context, d *schema.ResourceDat
140155

141156
_ = d.Set("endpoint", objectBucketEndpointURL(bucketName, region))
142157

158+
// Read the versioning configuration
159+
versioningResponse, err := s3Client.GetBucketVersioningWithContext(ctx, &s3.GetBucketVersioningInput{
160+
Bucket: aws.String(bucketName),
161+
})
162+
if err != nil {
163+
return diag.FromErr(err)
164+
}
165+
_ = d.Set("versioning", flattenObjectBucketVersioning(versioningResponse))
166+
143167
return nil
144168
}
145169

@@ -162,6 +186,12 @@ func resourceScalewayObjectBucketUpdate(ctx context.Context, d *schema.ResourceD
162186
}
163187
}
164188

189+
if d.HasChange("versioning") {
190+
if err := resourceScalewayObjectBucketVersioningUpdate(ctx, s3Client, d); err != nil {
191+
return diag.FromErr(err)
192+
}
193+
}
194+
165195
if d.HasChange("tags") {
166196
tagsSet := expandObjectBucketTags(d.Get("tags"))
167197

@@ -194,3 +224,22 @@ func resourceScalewayObjectBucketDelete(ctx context.Context, d *schema.ResourceD
194224

195225
return nil
196226
}
227+
228+
func resourceScalewayObjectBucketVersioningUpdate(ctx context.Context, s3conn *s3.S3, d *schema.ResourceData) error {
229+
v := d.Get("versioning").([]interface{})
230+
bucketName := d.Get("name").(string)
231+
vc := expandObjectBucketVersioning(v)
232+
233+
i := &s3.PutBucketVersioningInput{
234+
Bucket: aws.String(bucketName),
235+
VersioningConfiguration: vc,
236+
}
237+
l.Debugf("S3 put bucket versioning: %#v", i)
238+
239+
_, err := s3conn.PutBucketVersioningWithContext(ctx, i)
240+
if err != nil {
241+
return fmt.Errorf("error putting S3 versioning: %s", err)
242+
}
243+
244+
return nil
245+
}

scaleway/resource_object_bucket_test.go

+119
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/aws/aws-sdk-go/aws"
910
"github.com/aws/aws-sdk-go/aws/awserr"
1011
"github.com/aws/aws-sdk-go/service/s3"
1112
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
@@ -142,3 +143,121 @@ func testSweepStorageObjectBucket(_ string) error {
142143
return nil
143144
})
144145
}
146+
147+
func TestAccScalewayObjectBucket_Versioning(t *testing.T) {
148+
tt := NewTestTools(t)
149+
defer tt.Cleanup()
150+
151+
bucketName := "tf-test-bucket-testaccscalewayobjectbucket-versioning"
152+
resourceName := "scaleway_object_bucket.bucket"
153+
154+
resource.ParallelTest(t, resource.TestCase{
155+
PreCheck: func() { testAccPreCheck(t) },
156+
ProviderFactories: tt.ProviderFactories,
157+
CheckDestroy: testAccCheckScalewayObjectBucketDestroy(tt),
158+
Steps: []resource.TestStep{
159+
{
160+
Config: fmt.Sprintf(`
161+
resource "scaleway_object_bucket" "bucket" {
162+
name = "%s"
163+
}
164+
`, bucketName),
165+
Check: resource.ComposeTestCheckFunc(
166+
testAccCheckScalewayObjectBucketExists(tt, resourceName, bucketName),
167+
testAccCheckScalewayObjectBucketVersioning(tt, s3.BucketVersioningStatusSuspended, bucketName),
168+
),
169+
},
170+
{
171+
ResourceName: resourceName,
172+
ImportState: true,
173+
ImportStateVerify: true,
174+
ImportStateVerifyIgnore: []string{"force_destroy", "acl"},
175+
},
176+
{
177+
Config: fmt.Sprintf(`
178+
resource "scaleway_object_bucket" "bucket" {
179+
name = "%s"
180+
versioning {
181+
enabled = true
182+
}
183+
}`, bucketName),
184+
Check: resource.ComposeTestCheckFunc(
185+
testAccCheckScalewayObjectBucketExists(tt, resourceName, bucketName),
186+
testAccCheckScalewayObjectBucketVersioning(tt, s3.BucketVersioningStatusEnabled, bucketName),
187+
),
188+
},
189+
{
190+
Config: fmt.Sprintf(`
191+
resource "scaleway_object_bucket" "bucket" {
192+
name = "%s"
193+
versioning {
194+
enabled = false
195+
}
196+
}`, bucketName),
197+
Check: resource.ComposeTestCheckFunc(
198+
testAccCheckScalewayObjectBucketExists(tt, resourceName, bucketName),
199+
testAccCheckScalewayObjectBucketVersioning(tt, s3.BucketVersioningStatusSuspended, bucketName),
200+
),
201+
},
202+
},
203+
})
204+
}
205+
206+
func testAccCheckScalewayObjectBucketExists(tt *TestTools, n string, bucketName string) resource.TestCheckFunc {
207+
return func(s *terraform.State) error {
208+
rs, ok := s.RootModule().Resources[n]
209+
if !ok {
210+
return fmt.Errorf("not found: %s", n)
211+
}
212+
213+
if rs.Primary.ID == "" {
214+
return fmt.Errorf("no ID is set")
215+
}
216+
217+
conn, err := newS3ClientFromMeta(tt.Meta)
218+
if err != nil {
219+
return fmt.Errorf("error while creating S3client: %s", err)
220+
}
221+
222+
_, err = conn.HeadBucketWithContext(tt.ctx, &s3.HeadBucketInput{
223+
Bucket: aws.String(bucketName),
224+
})
225+
226+
if err != nil {
227+
if isS3Err(err, s3.ErrCodeNoSuchBucket, "") {
228+
return fmt.Errorf("s3 bucket not found")
229+
}
230+
return err
231+
}
232+
return nil
233+
}
234+
}
235+
236+
func testAccCheckScalewayObjectBucketVersioning(tt *TestTools, versioningStatus string, bucketName string) resource.TestCheckFunc {
237+
return func(s *terraform.State) error {
238+
conn, err := newS3ClientFromMeta(tt.Meta)
239+
if err != nil {
240+
return fmt.Errorf("error while creating S3client: %s", err)
241+
}
242+
243+
out, err := conn.GetBucketVersioningWithContext(tt.ctx, &s3.GetBucketVersioningInput{
244+
Bucket: aws.String(bucketName),
245+
})
246+
247+
if err != nil {
248+
return fmt.Errorf("GetBucketVersioning error: %v", err)
249+
}
250+
251+
if v := out.Status; v == nil {
252+
if versioningStatus != "" {
253+
return fmt.Errorf("bad error versioning status, found nil, expected: %s", versioningStatus)
254+
}
255+
} else {
256+
if *v != versioningStatus {
257+
return fmt.Errorf("bad error versioning status, expected: %s, got %s", versioningStatus, *v)
258+
}
259+
}
260+
261+
return nil
262+
}
263+
}

0 commit comments

Comments
 (0)