digitalocean_spaces_bucket: support bucket versioning (#409)
* digitalocean_spaces_bucket: support bucket versioning * document versioning argument * remove debugging code * Update digitalocean/resource_digitalocean_spaces_bucket.go Co-Authored-By: Andrew Starr-Bochicchio <andrewsomething@users.noreply.github.com> * test that removing the versioning block will disable versionin Co-authored-by: Andrew Starr-Bochicchio <andrewsomething@users.noreply.github.com>
This commit is contained in:
parent
132f587f34
commit
d7f2efda35
|
@ -81,6 +81,26 @@ func resourceDigitalOceanBucket() *schema.Resource {
|
|||
},
|
||||
},
|
||||
},
|
||||
// This is structured as a subobject in case Spaces supports more of s3.VersioningConfiguration
|
||||
// than just enabling bucket versioning.
|
||||
"versioning": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"enabled": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
||||
return old == "1" && new == "0"
|
||||
},
|
||||
},
|
||||
|
||||
"bucket_domain_name": {
|
||||
Type: schema.TypeString,
|
||||
Description: "The FQDN of the bucket",
|
||||
|
@ -160,6 +180,12 @@ func resourceDigitalOceanBucketUpdate(d *schema.ResourceData, meta interface{})
|
|||
}
|
||||
}
|
||||
|
||||
if d.HasChange("versioning") {
|
||||
if err := resourceDigitalOceanSpacesBucketVersioningUpdate(svc, d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return resourceDigitalOceanBucketRead(d, meta)
|
||||
}
|
||||
|
||||
|
@ -198,7 +224,6 @@ func resourceDigitalOceanBucketRead(d *schema.ResourceData, meta interface{}) er
|
|||
d.Set("bucket_domain_name", bucketDomainName(d.Get("name").(string), d.Get("region").(string)))
|
||||
|
||||
// Add the region as an attribute
|
||||
|
||||
locationResponse, err := retryOnAwsCode("NoSuchBucket", func() (interface{}, error) {
|
||||
return svc.GetBucketLocation(
|
||||
&s3.GetBucketLocationInput{
|
||||
|
@ -218,8 +243,33 @@ func resourceDigitalOceanBucketRead(d *schema.ResourceData, meta interface{}) er
|
|||
return err
|
||||
}
|
||||
|
||||
// Read the versioning configuration
|
||||
versioningResponse, err := retryOnAwsCode(s3.ErrCodeNoSuchBucket, func() (interface{}, error) {
|
||||
return svc.GetBucketVersioning(&s3.GetBucketVersioningInput{
|
||||
Bucket: aws.String(d.Id()),
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vcl := make([]map[string]interface{}, 0, 1)
|
||||
if versioning, ok := versioningResponse.(*s3.GetBucketVersioningOutput); ok {
|
||||
vc := make(map[string]interface{})
|
||||
if versioning.Status != nil && *versioning.Status == s3.BucketVersioningStatusEnabled {
|
||||
vc["enabled"] = true
|
||||
} else {
|
||||
vc["enabled"] = false
|
||||
}
|
||||
vcl = append(vcl, vc)
|
||||
}
|
||||
if err := d.Set("versioning", vcl); err != nil {
|
||||
return fmt.Errorf("error setting versioning: %s", err)
|
||||
}
|
||||
|
||||
// Set the bucket's name.
|
||||
d.Set("name", d.Get("name").(string))
|
||||
|
||||
// Set the URN attribute.
|
||||
urn := fmt.Sprintf("do:space:%s", d.Get("name"))
|
||||
d.Set("urn", urn)
|
||||
|
||||
|
@ -381,6 +431,39 @@ func resourceDigitalOceanBucketCorsUpdate(svc *s3.S3, d *schema.ResourceData) er
|
|||
return nil
|
||||
}
|
||||
|
||||
func resourceDigitalOceanSpacesBucketVersioningUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
|
||||
v := d.Get("versioning").([]interface{})
|
||||
bucket := d.Get("name").(string)
|
||||
vc := &s3.VersioningConfiguration{}
|
||||
|
||||
if len(v) > 0 {
|
||||
c := v[0].(map[string]interface{})
|
||||
|
||||
if c["enabled"].(bool) {
|
||||
vc.Status = aws.String(s3.BucketVersioningStatusEnabled)
|
||||
} else {
|
||||
vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
|
||||
}
|
||||
} else {
|
||||
vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
|
||||
}
|
||||
|
||||
i := &s3.PutBucketVersioningInput{
|
||||
Bucket: aws.String(bucket),
|
||||
VersioningConfiguration: vc,
|
||||
}
|
||||
log.Printf("[DEBUG] Spaces PUT bucket versioning: %#v", i)
|
||||
|
||||
_, err := retryOnAwsCode(s3.ErrCodeNoSuchBucket, func() (interface{}, error) {
|
||||
return s3conn.PutBucketVersioning(i)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error putting Spaces versioning: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceDigitalOceanBucketImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||
if strings.Contains(d.Id(), ",") {
|
||||
s := strings.Split(d.Id(), ",")
|
||||
|
|
|
@ -225,6 +225,82 @@ func TestAccDigitalOceanBucket_shouldFailNotFound(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccDigitalOceanBucket_Versioning(t *testing.T) {
|
||||
rInt := acctest.RandInt()
|
||||
resourceName := "digitalocean_spaces_bucket.bucket"
|
||||
|
||||
makeConfig := func(includeClause, versioning bool) string {
|
||||
versioningClause := ""
|
||||
if includeClause {
|
||||
versioningClause = fmt.Sprintf(`
|
||||
versioning {
|
||||
enabled = %v
|
||||
}
|
||||
`, versioning)
|
||||
}
|
||||
return fmt.Sprintf(`
|
||||
resource "digitalocean_spaces_bucket" "bucket" {
|
||||
name = "tf-test-bucket-%d"
|
||||
region = "ams3"
|
||||
%s
|
||||
}
|
||||
`, rInt, versioningClause)
|
||||
}
|
||||
|
||||
resource.ParallelTest(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
// No versioning configured.
|
||||
Config: makeConfig(false, false),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanBucketExists(resourceName),
|
||||
testAccCheckDigitalOceanBucketVersioning(
|
||||
resourceName, ""),
|
||||
),
|
||||
},
|
||||
{
|
||||
// Enable versioning
|
||||
Config: makeConfig(true, true),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanBucketExists(resourceName),
|
||||
testAccCheckDigitalOceanBucketVersioning(
|
||||
resourceName, s3.BucketVersioningStatusEnabled),
|
||||
),
|
||||
},
|
||||
{
|
||||
// Explicitly disable versioning
|
||||
Config: makeConfig(true, false),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanBucketExists(resourceName),
|
||||
testAccCheckDigitalOceanBucketVersioning(
|
||||
resourceName, s3.BucketVersioningStatusSuspended),
|
||||
),
|
||||
},
|
||||
{
|
||||
// Re-enable versioning
|
||||
Config: makeConfig(true, true),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanBucketExists(resourceName),
|
||||
testAccCheckDigitalOceanBucketVersioning(
|
||||
resourceName, s3.BucketVersioningStatusEnabled),
|
||||
),
|
||||
},
|
||||
{
|
||||
// Remove the clause completely. Should disable versioning.
|
||||
Config: makeConfig(false, false),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDigitalOceanBucketExists(resourceName),
|
||||
testAccCheckDigitalOceanBucketVersioning(
|
||||
resourceName, s3.BucketVersioningStatusSuspended),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDigitalOceanBucketDestroy(s *terraform.State) error {
|
||||
return testAccCheckDigitalOceanBucketDestroyWithProvider(s, testAccProvider)
|
||||
}
|
||||
|
@ -372,6 +448,44 @@ func testAccCheckDigitalOceanBucketCors(n string, corsRules []*s3.CORSRule) reso
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckDigitalOceanBucketVersioning(n string, versioningStatus string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs := s.RootModule().Resources[n]
|
||||
|
||||
sesh, err := session.NewSession(&aws.Config{
|
||||
Region: aws.String(rs.Primary.Attributes["region"]),
|
||||
Credentials: credentials.NewStaticCredentials(os.Getenv("SPACES_ACCESS_KEY_ID"), os.Getenv("SPACES_SECRET_ACCESS_KEY"), "")},
|
||||
)
|
||||
svc := s3.New(sesh, &aws.Config{
|
||||
Endpoint: aws.String(fmt.Sprintf("https://%s.digitaloceanspaces.com", rs.Primary.Attributes["region"]))},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
out, err := svc.GetBucketVersioning(&s3.GetBucketVersioningInput{
|
||||
Bucket: aws.String(rs.Primary.ID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetBucketVersioning error: %v", err)
|
||||
}
|
||||
|
||||
if v := out.Status; v == nil {
|
||||
if versioningStatus != "" {
|
||||
return fmt.Errorf("bad error versioning status, found nil, expected: %s", versioningStatus)
|
||||
}
|
||||
} else {
|
||||
if *v != versioningStatus {
|
||||
return fmt.Errorf("bad error versioning status, expected: %s, got %s", versioningStatus, *v)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func isAWSErr(err error, code string, message string) bool {
|
||||
if err, ok := err.(awserr.Error); ok {
|
||||
return err.Code() == code && strings.Contains(err.Message(), message)
|
||||
|
|
|
@ -78,6 +78,8 @@ The following arguments are supported:
|
|||
* `name` - (Required) The name of the bucket
|
||||
* `region` - The region where the bucket resides (Defaults to `nyc3`)
|
||||
* `acl` - Canned ACL applied on bucket creation (`private` or `public-read`)
|
||||
* `cors_rule` - (Optional) A rule of Cross-Origin Resource Sharing (documented below).
|
||||
* `versioning` - (Optional) A state of versioning (documented below)
|
||||
* `force_destroy` - Unless `true`, the bucket will only be destroyed if empty (Defaults to `false`)
|
||||
|
||||
The `cors_rule` object supports the following:
|
||||
|
@ -87,6 +89,11 @@ The `cors_rule` object supports the following:
|
|||
* `allowed_origins` - (Required) A list of hosts from which requests using the specified methods are allowed. A host may contain one wildcard (e.g. http://*.example.com).
|
||||
* `max_age_seconds` - (Optional) The time in seconds that browser can cache the response for a preflight request.
|
||||
|
||||
The `versioning` object supports the following:
|
||||
|
||||
* `enabled` - (Optional) Enable versioning. Once you version-enable a bucket, it can never return to an unversioned
|
||||
state. You can, however, suspend versioning on that bucket.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
|
Loading…
Reference in New Issue