terraform-provider-greenhost/digitalocean/resource_digitalocean_space...

580 lines
16 KiB
Go
Raw Normal View History

package digitalocean
import (
"fmt"
"log"
"os"
"reflect"
"testing"
Upgrade to terraform-plugin-sdk (#321) * Upgrade to terraform-plugin-sdk After following the [guide](https://www.terraform.io/docs/extend/plugin-sdk.html#using-tf-sdk-migrator) Check ``` ▶ GO111MODULE=on tf-sdk-migrator check Checking Go runtime version ... Go version 1.12.10: OK. Checking whether provider uses Go modules... Go modules in use: OK. Checking version of github.com/hashicorp/terraform-plugin-sdk to determine if provider was already migrated... Checking version of github.com/hashicorp/terraform used in provider... Terraform version 0.12.8: OK. Checking whether provider uses deprecated SDK packages or identifiers... No imports of deprecated SDK packages or identifiers: OK. All constraints satisfied. Provider can be migrated to the new SDK. ``` Migrate ``` ▶ GO111MODULE=on tf-sdk-migrator migrate Checking Go runtime version ... Go version 1.12.10: OK. Checking whether provider uses Go modules... Go modules in use: OK. Checking version of github.com/hashicorp/terraform-plugin-sdk to determine if provider was already migrated... Checking version of github.com/hashicorp/terraform used in provider... Terraform version 0.12.8: OK. Checking whether provider uses deprecated SDK packages or identifiers... No imports of deprecated SDK packages or identifiers: OK. All constraints satisfied. Provider can be migrated to the new SDK. Rewriting provider go.mod file... Rewriting SDK package imports... Running `go mod tidy`... Success! Provider is migrated to github.com/hashicorp/terraform-plugin-sdk v1.1.0. It looks like this provider vendors dependencies. Don't forget to run `go mod vendor`. Make sure to review all changes and run all tests. ``` * Fix build under go 1.13.x.
2019-10-22 21:44:03 +00:00
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
Upgrade to terraform-plugin-sdk (#321) * Upgrade to terraform-plugin-sdk After following the [guide](https://www.terraform.io/docs/extend/plugin-sdk.html#using-tf-sdk-migrator) Check ``` ▶ GO111MODULE=on tf-sdk-migrator check Checking Go runtime version ... Go version 1.12.10: OK. Checking whether provider uses Go modules... Go modules in use: OK. Checking version of github.com/hashicorp/terraform-plugin-sdk to determine if provider was already migrated... Checking version of github.com/hashicorp/terraform used in provider... Terraform version 0.12.8: OK. Checking whether provider uses deprecated SDK packages or identifiers... No imports of deprecated SDK packages or identifiers: OK. All constraints satisfied. Provider can be migrated to the new SDK. ``` Migrate ``` ▶ GO111MODULE=on tf-sdk-migrator migrate Checking Go runtime version ... Go version 1.12.10: OK. Checking whether provider uses Go modules... Go modules in use: OK. Checking version of github.com/hashicorp/terraform-plugin-sdk to determine if provider was already migrated... Checking version of github.com/hashicorp/terraform used in provider... Terraform version 0.12.8: OK. Checking whether provider uses deprecated SDK packages or identifiers... No imports of deprecated SDK packages or identifiers: OK. All constraints satisfied. Provider can be migrated to the new SDK. Rewriting provider go.mod file... Rewriting SDK package imports... Running `go mod tidy`... Success! Provider is migrated to github.com/hashicorp/terraform-plugin-sdk v1.1.0. It looks like this provider vendors dependencies. Don't forget to run `go mod vendor`. Make sure to review all changes and run all tests. ``` * Fix build under go 1.13.x.
2019-10-22 21:44:03 +00:00
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func TestAccDigitalOceanBucket_basic(t *testing.T) {
rInt := acctest.RandInt()
expectedRegion := "ams3"
expectedBucketName := testAccBucketName(rInt)
expectBucketURN := fmt.Sprintf("do:space:%s", expectedBucketName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
/*
IDRefreshName: "digitalocean_spaces_bucket.bucket",
IDRefreshIgnore: []string{"force_destroy"},
*/
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: testAccDigitalOceanBucketConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
resource.TestCheckResourceAttr(
"digitalocean_spaces_bucket.bucket", "region", expectedRegion),
resource.TestCheckResourceAttr(
"digitalocean_spaces_bucket.bucket", "name", expectedBucketName),
resource.TestCheckResourceAttr("digitalocean_spaces_bucket.bucket", "urn", expectBucketURN),
),
},
},
})
}
func TestAccDigitalOceanBucket_region(t *testing.T) {
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: testAccDigitalOceanBucketConfigWithRegion(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
resource.TestCheckResourceAttr("digitalocean_spaces_bucket.bucket", "region", "ams3"),
),
},
},
})
}
func TestAccDigitalOceanBucket_UpdateAcl(t *testing.T) {
ri := acctest.RandInt()
2018-12-05 05:17:22 +00:00
preConfig := fmt.Sprintf(testAccDigitalOceanBucketConfigWithACL, ri)
postConfig := fmt.Sprintf(testAccDigitalOceanBucketConfigWithACLUpdate, ri)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: preConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
resource.TestCheckResourceAttr(
"digitalocean_spaces_bucket.bucket", "acl", "public-read"),
),
},
{
Config: postConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
resource.TestCheckResourceAttr(
"digitalocean_spaces_bucket.bucket", "acl", "private"),
),
},
},
})
}
func TestAccDigitalOceanBucket_UpdateCors(t *testing.T) {
ri := acctest.RandInt()
preConfig := fmt.Sprintf(testAccDigitalOceanBucketConfigWithCORS, ri)
postConfig := fmt.Sprintf(testAccDigitalOceanBucketConfigWithCORSUpdate, ri)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: preConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
resource.TestCheckNoResourceAttr(
"digitalocean_spaces_bucket.bucket", "cors_rule"),
),
},
{
Config: postConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
testAccCheckDigitalOceanBucketCors(
"digitalocean_spaces_bucket.bucket",
[]*s3.CORSRule{
{
AllowedHeaders: []*string{aws.String("*")},
AllowedMethods: []*string{aws.String("PUT"), aws.String("POST")},
AllowedOrigins: []*string{aws.String("https://www.example.com")},
MaxAgeSeconds: aws.Int64(3000),
},
},
),
),
},
},
})
}
func TestAccDigitalOceanBucket_WithCors(t *testing.T) {
ri := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDigitalOceanBucketConfigWithCORSUpdate, ri),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
testAccCheckDigitalOceanBucketCors(
"digitalocean_spaces_bucket.bucket",
[]*s3.CORSRule{
{
AllowedHeaders: []*string{aws.String("*")},
AllowedMethods: []*string{aws.String("PUT"), aws.String("POST")},
AllowedOrigins: []*string{aws.String("https://www.example.com")},
MaxAgeSeconds: aws.Int64(3000),
},
},
),
),
},
},
})
}
func TestAccDigitalOceanBucket_WithMultipleCorsRules(t *testing.T) {
ri := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testAccDigitalOceanBucketConfigWithMultiCORS, ri),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
testAccCheckDigitalOceanBucketCors(
"digitalocean_spaces_bucket.bucket",
[]*s3.CORSRule{
{
AllowedHeaders: []*string{aws.String("*")},
AllowedMethods: []*string{aws.String("GET")},
AllowedOrigins: []*string{aws.String("*")},
MaxAgeSeconds: aws.Int64(3000),
},
{
AllowedHeaders: []*string{aws.String("*")},
AllowedMethods: []*string{aws.String("PUT"), aws.String("DELETE"), aws.String("POST")},
AllowedOrigins: []*string{aws.String("https://www.example.com")},
MaxAgeSeconds: aws.Int64(3000),
},
},
),
),
},
},
})
}
// Test TestAccDigitalOceanBucket_shouldFailNotFound is designed to fail with a "plan
// not empty" error in Terraform, to check against regresssions.
// See https://github.com/hashicorp/terraform/pull/2925
func TestAccDigitalOceanBucket_shouldFailNotFound(t *testing.T) {
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDigitalOceanBucketDestroy,
Steps: []resource.TestStep{
{
Config: testAccDigitalOceanBucketDestroyedConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckDigitalOceanBucketExists("digitalocean_spaces_bucket.bucket"),
testAccCheckDigitalOceanDestroyBucket("digitalocean_spaces_bucket.bucket"),
),
ExpectNonEmptyPlan: true,
},
},
})
}
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)
}
func testAccCheckDigitalOceanBucketDestroyWithProvider(s *terraform.State, provider *schema.Provider) error {
for _, rs := range s.RootModule().Resources {
2018-12-05 05:17:22 +00:00
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"), "")},
2018-12-05 05:17:22 +00:00
)
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)
}
if rs.Type != "digitalocean_spaces_bucket" {
continue
}
2018-12-05 05:17:22 +00:00
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{
Bucket: aws.String(rs.Primary.ID),
})
if err != nil {
if isAWSErr(err, s3.ErrCodeNoSuchBucket, "") {
return nil
}
return err
}
}
return nil
}
func testAccCheckDigitalOceanBucketExists(n string) resource.TestCheckFunc {
return testAccCheckDigitalOceanBucketExistsWithProvider(n, func() *schema.Provider { return testAccProvider })
}
func testAccCheckDigitalOceanBucketExistsWithProvider(n string, providerF func() *schema.Provider) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
sesh, err := session.NewSession(&aws.Config{
2018-12-05 05:17:22 +00:00
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{
2018-12-05 05:17:22 +00:00
Endpoint: aws.String(fmt.Sprintf("https://%s.digitaloceanspaces.com", rs.Primary.Attributes["region"]))},
)
if err != nil {
log.Fatal(err)
}
_, err = svc.HeadBucket(&s3.HeadBucketInput{
Bucket: aws.String(rs.Primary.ID),
})
if err != nil {
if isAWSErr(err, s3.ErrCodeNoSuchBucket, "") {
return fmt.Errorf("Spaces bucket not found")
}
return err
}
return nil
}
}
func testAccCheckDigitalOceanDestroyBucket(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Spaces Bucket ID is set")
}
sesh, err := session.NewSession(&aws.Config{
2018-12-05 05:17:22 +00:00
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{
2018-12-05 05:17:22 +00:00
Endpoint: aws.String(fmt.Sprintf("https://%s.digitaloceanspaces.com", rs.Primary.Attributes["region"]))},
)
if err != nil {
log.Fatal(err)
}
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{
Bucket: aws.String(rs.Primary.ID),
})
if err != nil {
return fmt.Errorf("Error destroying Bucket (%s) in testAccCheckDigitalOceanDestroyBucket: %s", rs.Primary.ID, err)
}
return nil
}
}
func testAccCheckDigitalOceanBucketCors(n string, corsRules []*s3.CORSRule) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Spaces Bucket ID is set")
}
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"]))},
)
out, err := svc.GetBucketCors(&s3.GetBucketCorsInput{
Bucket: aws.String(rs.Primary.ID),
})
if err != nil {
return fmt.Errorf("GetBucketCors error: %v", err)
}
if !reflect.DeepEqual(out.CORSRules, corsRules) {
return fmt.Errorf("bad error cors rule, expected: %v, got %v", corsRules, out.CORSRules)
}
return nil
}
}
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
}
}
// These need a bit of randomness as the name can only be used once globally
func testAccBucketName(randInt int) string {
return fmt.Sprintf("tf-test-bucket-%d", randInt)
}
func testAccDigitalOceanBucketConfig(randInt int) string {
return fmt.Sprintf(`
resource "digitalocean_spaces_bucket" "bucket" {
2018-11-26 00:11:47 +00:00
name = "tf-test-bucket-%d"
acl = "public-read"
region = "ams3"
}
`, randInt)
}
func testAccDigitalOceanBucketDestroyedConfig(randInt int) string {
return fmt.Sprintf(`
resource "digitalocean_spaces_bucket" "bucket" {
2018-11-26 00:11:47 +00:00
name = "tf-test-bucket-%d"
acl = "public-read"
}
`, randInt)
}
func testAccDigitalOceanBucketConfigWithRegion(randInt int) string {
return fmt.Sprintf(`
resource "digitalocean_spaces_bucket" "bucket" {
2018-11-26 00:11:47 +00:00
name = "tf-test-bucket-%d"
region = "ams3"
}
`, randInt)
}
2018-12-05 05:17:22 +00:00
func testAccDigitalOceanBucketConfigImport(randInt int) string {
return fmt.Sprintf(`
resource "digitalocean_spaces_bucket" "bucket" {
name = "tf-test-bucket-%d"
region = "sfo2"
2018-12-05 05:17:22 +00:00
}
`, randInt)
}
var testAccDigitalOceanBucketConfigWithACL = `
resource "digitalocean_spaces_bucket" "bucket" {
2018-11-26 00:11:47 +00:00
name = "tf-test-bucket-%d"
acl = "public-read"
}
`
2018-12-05 05:17:22 +00:00
var testAccDigitalOceanBucketConfigWithACLUpdate = `
resource "digitalocean_spaces_bucket" "bucket" {
2018-11-26 00:11:47 +00:00
name = "tf-test-bucket-%d"
acl = "private"
}
`
var testAccDigitalOceanBucketConfigWithCORS = `
resource "digitalocean_spaces_bucket" "bucket" {
name = "tf-test-bucket-%d"
}
`
var testAccDigitalOceanBucketConfigWithCORSUpdate = `
resource "digitalocean_spaces_bucket" "bucket" {
name = "tf-test-bucket-%d"
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["PUT","POST"]
allowed_origins = ["https://www.example.com"]
max_age_seconds = 3000
}
}
`
var testAccDigitalOceanBucketConfigWithMultiCORS = `
resource "digitalocean_spaces_bucket" "bucket" {
name = "tf-test-bucket-%d"
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET"]
allowed_origins = ["*"]
max_age_seconds = 3000
}
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["PUT", "DELETE", "POST"]
allowed_origins = ["https://www.example.com"]
max_age_seconds = 3000
}
}
`