Skip to content

Commit 5c91abc

Browse files
DenBekejerome-quere
authored andcommitted
feat: added scaleway_storage_object_bucket resource (scaleway#150)
1 parent 3a1a580 commit 5c91abc

File tree

11 files changed

+411
-17
lines changed

11 files changed

+411
-17
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module github.com/terraform-providers/terraform-provider-scaleway
22

33
require (
4+
github.com/aws/aws-sdk-go v1.19.18
45
github.com/hashicorp/go-retryablehttp v0.5.2
56
github.com/hashicorp/terraform v0.12.1
6-
github.com/mitchellh/go-homedir v1.0.0
7+
github.com/mitchellh/go-homedir v1.1.0
78
github.com/nicolai86/scaleway-sdk v0.0.0-20181024210327-b20018e944c4
89
github.com/scaleway/scaleway-sdk-go v0.0.0-20190628150506-6175a43111c8
910
github.com/stretchr/testify v1.3.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK
257257
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
258258
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
259259
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
260+
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
261+
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
260262
github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb h1:GRiLv4rgyqjqzxbhJke65IYUf4NCOOvrPOJbV/sPxkM=
261263
github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM=
262264
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=

scaleway/config.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import (
1212
"os"
1313
"time"
1414

15+
"github.com/aws/aws-sdk-go/aws"
16+
"github.com/aws/aws-sdk-go/aws/credentials"
17+
"github.com/aws/aws-sdk-go/aws/session"
18+
"github.com/aws/aws-sdk-go/service/s3"
1519
"github.com/hashicorp/go-retryablehttp"
1620
"github.com/hashicorp/terraform/helper/logging"
1721
sdk "github.com/nicolai86/scaleway-sdk"
@@ -32,11 +36,34 @@ type Meta struct {
3236
// scwClient is the Scaleway SDK client.
3337
scwClient *scw.Client
3438

39+
// s3Client is the S3 client
40+
s3Client *s3.S3
41+
3542
// Deprecated: deprecatedClient is the deprecated Scaleway SDK (will be removed in `v2.0.0`).
3643
deprecatedClient *sdk.API
3744
}
3845

39-
// bootstrapScwClient returns a new scw.Client from the configuration.
46+
// bootstrap initializes all the clients for this meta config object.
47+
func (m *Meta) bootstrap() error {
48+
err := m.bootstrapScwClient()
49+
if err != nil {
50+
return err
51+
}
52+
53+
err = m.bootstrapDeprecatedClient()
54+
if err != nil {
55+
return err
56+
}
57+
58+
err = m.bootstrapS3Client()
59+
if err != nil {
60+
return err
61+
}
62+
63+
return nil
64+
}
65+
66+
// bootstrapScwClient initializes a new scw.Client from the configuration.
4067
func (m *Meta) bootstrapScwClient() error {
4168
options := []scw.ClientOption{
4269
scw.WithHTTPClient(createRetryableHTTPClient(false)),
@@ -115,7 +142,7 @@ func (c *client) Do(r *http.Request) (*http.Response, error) {
115142
return c.Client.Do(req)
116143
}
117144

118-
// bootstrapDeprecatedClient creates a new deprecated client from the configuration.
145+
// bootstrapDeprecatedClient initializes a new deprecated client from the configuration.
119146
func (m *Meta) bootstrapDeprecatedClient() error {
120147
options := func(sdkApi *sdk.API) {
121148
sdkApi.Client = createRetryableHTTPClient(true)
@@ -143,6 +170,30 @@ func (m *Meta) bootstrapDeprecatedClient() error {
143170
return nil
144171
}
145172

173+
// bootstrapS3Client initializes a new s3 client from the configuration.
174+
func (m *Meta) bootstrapS3Client() error {
175+
var err error
176+
177+
config := &aws.Config{}
178+
config.WithRegion(string(m.DefaultRegion))
179+
config.WithCredentials(credentials.NewStaticCredentials(m.AccessKey, m.SecretKey, ""))
180+
config.WithEndpoint(m.getS3Endpoint(m.DefaultRegion))
181+
182+
s, err := session.NewSession(config)
183+
if err != nil {
184+
return err
185+
}
186+
187+
m.s3Client = s3.New(s)
188+
return nil
189+
}
190+
191+
// getS3Endpoint returns the correct S3 endpoint for object storage based on the current region
192+
func (m *Meta) getS3Endpoint(region utils.Region) string {
193+
return "https://s3." + string(region) + ".scw.cloud"
194+
195+
}
196+
146197
// deprecatedScalewayConfig is the structure of the deprecated Scaleway config file.
147198
type deprecatedScalewayConfig struct {
148199
Organization string `json:"organization"`

scaleway/helper_storage_object.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package scaleway
2+
3+
import (
4+
"github.com/aws/aws-sdk-go/service/s3"
5+
"github.com/hashicorp/terraform/helper/schema"
6+
"github.com/scaleway/scaleway-sdk-go/utils"
7+
)
8+
9+
// getS3ClientWithRegion returns a new S3 client with the correct region extracted from the resource data.
10+
func getS3ClientWithRegion(d *schema.ResourceData, m interface{}) (*s3.S3, utils.Region, error) {
11+
meta := m.(*Meta)
12+
13+
region, err := getRegion(d, meta)
14+
if err != nil {
15+
return nil, "", err
16+
}
17+
18+
if region != meta.DefaultRegion {
19+
// if the region is not the same as the default region:
20+
// we have to clone the meta object with the new region and create a new S3 client.
21+
newMeta := *meta
22+
newMeta.DefaultRegion = region
23+
24+
err := newMeta.bootstrapS3Client()
25+
if err != nil {
26+
return nil, "", err
27+
}
28+
return newMeta.s3Client, region, nil
29+
}
30+
31+
return meta.s3Client, region, err
32+
}
33+
34+
// getS3ClientWithRegion returns a new S3 client with the correct region and id extracted from the resource data.
35+
func getS3ClientWithRegionAndID(m interface{}, id string) (*s3.S3, utils.Region, string, error) {
36+
meta := m.(*Meta)
37+
38+
region, id, err := parseRegionalID(id)
39+
if err != nil {
40+
return nil, "", id, err
41+
}
42+
43+
if region != meta.DefaultRegion {
44+
// if the region is not the same as the default region:
45+
// we have to clone the meta object with the new region and create a new S3 client.
46+
newMeta := *meta
47+
newMeta.DefaultRegion = region
48+
49+
err := newMeta.bootstrapS3Client()
50+
if err != nil {
51+
return nil, "", id, err
52+
}
53+
return newMeta.s3Client, region, id, nil
54+
}
55+
56+
return meta.s3Client, region, id, err
57+
58+
}

scaleway/helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"github.com/hashicorp/terraform/helper/resource"
1111
"github.com/hashicorp/terraform/helper/schema"
1212
"github.com/hashicorp/terraform/terraform"
13-
"github.com/nicolai86/scaleway-sdk"
13+
api "github.com/nicolai86/scaleway-sdk"
1414
"github.com/scaleway/scaleway-sdk-go/namegenerator"
1515
"github.com/scaleway/scaleway-sdk-go/scw"
1616
"github.com/scaleway/scaleway-sdk-go/utils"

scaleway/provider.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ func Provider() terraform.ResourceProvider {
156156
"scaleway_compute_instance_ip": resourceScalewayComputeInstanceIP(),
157157
"scaleway_compute_instance_volume": resourceScalewayComputeInstanceVolume(),
158158
"scaleway_compute_instance_server": resourceScalewayComputeInstanceServer(),
159+
"scaleway_storage_object_bucket": resourceScalewayStorageObjectBucket(),
159160
"scaleway_user_data": resourceScalewayUserData(),
160161
"scaleway_server": resourceScalewayServer(),
161162
"scaleway_token": resourceScalewayToken(),
@@ -229,12 +230,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
229230
DefaultZone: zone,
230231
}
231232

232-
err = meta.bootstrapScwClient()
233-
if err != nil {
234-
return nil, err
235-
}
236-
237-
err = meta.bootstrapDeprecatedClient()
233+
meta.bootstrap()
238234
if err != nil {
239235
return nil, err
240236
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/aws/aws-sdk-go/aws"
7+
"github.com/aws/aws-sdk-go/aws/awserr"
8+
"github.com/aws/aws-sdk-go/service/s3"
9+
"github.com/hashicorp/terraform/helper/schema"
10+
"github.com/hashicorp/terraform/helper/validation"
11+
)
12+
13+
func resourceScalewayStorageObjectBucket() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceScalewayStorageObjectBucketCreate,
16+
Read: resourceScalewayStorageObjectBucketRead,
17+
Update: resourceScalewayStorageObjectBucketUpdate,
18+
Delete: resourceScalewayStorageObjectBucketDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
23+
Schema: map[string]*schema.Schema{
24+
"name": {
25+
Type: schema.TypeString,
26+
Required: true,
27+
ForceNew: true,
28+
Description: "The name of the bucket",
29+
},
30+
"acl": {
31+
Type: schema.TypeString,
32+
Optional: true,
33+
Default: "private",
34+
Description: "ACL of the bucket: either 'public-read' or 'private'.",
35+
ValidateFunc: validation.StringInSlice([]string{
36+
"private",
37+
"public-read",
38+
"public-read-write",
39+
"aws-exec-read",
40+
"authenticated-read",
41+
"bucket-owner-read",
42+
"bucket-owner-full-control",
43+
"log-delivery-write",
44+
}, false),
45+
},
46+
"region": regionSchema(),
47+
},
48+
}
49+
}
50+
51+
func resourceScalewayStorageObjectBucketCreate(d *schema.ResourceData, m interface{}) error {
52+
bucketName := d.Get("name").(string)
53+
acl := d.Get("acl").(string)
54+
55+
s3Client, region, err := getS3ClientWithRegion(d, m)
56+
57+
_, err = s3Client.CreateBucket(&s3.CreateBucketInput{
58+
Bucket: aws.String(bucketName),
59+
ACL: aws.String(acl),
60+
})
61+
if err != nil {
62+
return err
63+
}
64+
65+
d.SetId(newRegionalId(region, bucketName))
66+
67+
return resourceScalewayStorageObjectBucketRead(d, m)
68+
}
69+
70+
func resourceScalewayStorageObjectBucketRead(d *schema.ResourceData, m interface{}) error {
71+
s3Client, _, bucketName, err := getS3ClientWithRegionAndID(m, d.Id())
72+
if err != nil {
73+
return err
74+
}
75+
76+
_, err = s3Client.ListObjects(&s3.ListObjectsInput{
77+
Bucket: aws.String(bucketName),
78+
})
79+
if err != nil {
80+
if serr, ok := err.(awserr.Error); ok && serr.Code() == s3.ErrCodeNoSuchBucket {
81+
l.Errorf("Bucket %q was not found - removing from state!", bucketName)
82+
d.SetId("")
83+
return nil
84+
}
85+
return fmt.Errorf("couldn't read bucket: %s", err)
86+
}
87+
88+
return nil
89+
}
90+
91+
func resourceScalewayStorageObjectBucketUpdate(d *schema.ResourceData, m interface{}) error {
92+
s3Client, _, bucketName, err := getS3ClientWithRegionAndID(m, d.Id())
93+
if err != nil {
94+
return err
95+
}
96+
97+
if d.HasChange("acl") {
98+
acl := d.Get("acl").(string)
99+
100+
_, err := s3Client.PutBucketAcl(&s3.PutBucketAclInput{
101+
Bucket: aws.String(bucketName),
102+
ACL: aws.String(acl),
103+
})
104+
if err != nil {
105+
l.Errorf("Couldn't update bucket ACL: %s", err)
106+
return fmt.Errorf("couldn't update bucket ACL: %s", err)
107+
}
108+
}
109+
110+
return resourceScalewayStorageObjectBucketRead(d, m)
111+
}
112+
113+
func resourceScalewayStorageObjectBucketDelete(d *schema.ResourceData, m interface{}) error {
114+
s3Client, _, bucketName, err := getS3ClientWithRegionAndID(m, d.Id())
115+
if err != nil {
116+
return err
117+
}
118+
119+
_, err = s3Client.DeleteBucket(&s3.DeleteBucketInput{
120+
Bucket: aws.String(bucketName),
121+
})
122+
return err
123+
}

0 commit comments

Comments
 (0)