Remove deprecated fields from Snapshot (#2624)

This commit is contained in:
The Magician 2018-12-14 09:50:01 -08:00 committed by Nathan McKinley
parent 77a67eb04f
commit 42eee720ed
4 changed files with 187 additions and 925 deletions

View File

@ -21,145 +21,10 @@ import (
"strconv"
"time"
"github.com/hashicorp/terraform/helper/customdiff"
"github.com/hashicorp/terraform/helper/schema"
compute "google.golang.org/api/compute/v1"
)
func customDiffComputeSnapshotSnapshotEncryptionKeys(diff *schema.ResourceDiff, meta interface{}) error {
oldConvenience, newConvenience := diff.GetChange("snapshot_encryption_key_raw")
oldNewField, newNewField := diff.GetChange("snapshot_encryption_key.0.raw_key")
if newConvenience != "" && newNewField != "" {
return fmt.Errorf("can't use snapshot_encryption_key_raw and snapshot_encryption_key.0.raw_key at the same time." +
"If you're removing snapshot_encryption_key.0.raw_key, set the value to \"\" instead. This is due to limitations in Terraform.")
}
// Either field (convenience or new) has a value
// and then has another different value, so we ForceNew.
// We need to handle _EVERY_ ForceNew case in this diff
if oldConvenience != "" && newConvenience != "" && oldConvenience != newConvenience {
return diff.ForceNew("snapshot_encryption_key_raw")
}
if oldNewField != "" && newNewField != "" && oldNewField != newNewField {
return diff.ForceNew("snapshot_encryption_key.0.raw_key")
}
// Our resource isn't using either field, then uses one;
// ForceNew on whichever one is now using it.
if (oldConvenience == "" && oldNewField == "" && newConvenience != "") || (oldConvenience == "" && oldNewField == "" && newNewField != "") {
if oldConvenience == "" && newConvenience != "" {
return diff.ForceNew("snapshot_encryption_key_raw")
} else {
return diff.ForceNew("snapshot_encryption_key.0.raw_key")
}
}
// convenience no longer used
if oldConvenience != "" && newConvenience == "" {
if newNewField == "" {
// convenience is being nulled, and the new field is empty as well
// we've stopped using the field altogether
return diff.ForceNew("snapshot_encryption_key_raw")
} else if oldConvenience != newNewField {
// convenience is being nulled, and the new field has a new value
// so we ForceNew on either field
return diff.ForceNew("snapshot_encryption_key_raw")
} else {
// If we reach it here, we're using the same value in the new field as we had in the convenience field
}
}
// new no longer used
// note that it will remain _set_ because of how Computed fields work
// unset fields will have their values kept in state as a non-zero value
if oldNewField != "" && newNewField == "" {
if newConvenience == "" {
// new field is being nulled, and the convenience field is empty as well
// we've stopped using the field altogether
return diff.ForceNew("snapshot_encryption_key.0.raw_key")
} else if oldNewField != newConvenience {
// new is being nulled, and the convenience field has a new value
// so we ForceNew on either field
// This stops a really opaque diffs don't match during apply error. Without this, wee see
// a diff from the old state -> new state with a ForceNew at plan time (as expected!)
// But during apply time the entire nested object is nil in old state unexpectedly.
// So we just force the diff to match more by nilling it here, which is unclear why it
// works, and probably a worse UX with some real ugly diff, but also makes the tests pass.
// Computed nested fields are hard.
err := diff.SetNew("snapshot_encryption_key", nil)
if err != nil {
return err
}
return diff.ForceNew("snapshot_encryption_key.0.raw_key")
} else {
// If we reach it here, we're using the same value in the convenience field as we had in the new field
}
}
return nil
}
func customDiffComputeSnapshotSourceDiskEncryptionKeys(diff *schema.ResourceDiff, meta interface{}) error {
oldConvenience, newConvenience := diff.GetChange("source_disk_encryption_key_raw")
oldNewField, newNewField := diff.GetChange("source_disk_encryption_key.0.raw_key")
// Either field has a value and then has another value
// We need to handle _EVERY_ ForceNew case in this diff
if oldConvenience != "" && newConvenience != "" && oldConvenience != newConvenience {
return diff.ForceNew("source_disk_encryption_key_raw")
}
if oldNewField != "" && newNewField != "" && oldNewField != newNewField {
return diff.ForceNew("source_disk_encryption_key.0.raw_key")
}
// Our resource isn't using either field, then uses one;
// ForceNew on whichever one is now using it.
if (oldConvenience == "" && oldNewField == "" && newConvenience != "") || (oldConvenience == "" && oldNewField == "" && newNewField != "") {
if oldConvenience == "" && newConvenience != "" {
return diff.ForceNew("source_disk_encryption_key_raw")
} else {
return diff.ForceNew("source_disk_encryption_key.0.raw_key")
}
}
// convenience no longer used
if oldConvenience != "" && newConvenience == "" {
if newNewField == "" {
// convenience is being nulled, and the new field is empty as well
// we've stopped using the field altogether
return diff.ForceNew("source_disk_encryption_key_raw")
} else if oldConvenience != newNewField {
// convenience is being nulled, and the new field has a new value
// so we ForceNew on either field
return diff.ForceNew("source_disk_encryption_key_raw")
} else {
// If we reach it here, we're using the same value in the new field as we had in the convenience field
}
}
// new no longer used
if oldNewField != "" && newNewField == "" {
if newConvenience == "" {
// new field is being nulled, and the convenience field is empty as well
// we've stopped using the field altogether
return diff.ForceNew("source_disk_encryption_key.0.raw_key")
} else if newConvenience != oldNewField {
// new is being nulled, and the convenience field has a new value
// so we ForceNew on either field
return diff.ForceNew("source_disk_encryption_key.0.raw_key")
} else {
// If we reach it here, we're using the same value in the convenience field as we had in the new field
}
}
return nil
}
func resourceComputeSnapshot() *schema.Resource {
return &schema.Resource{
Create: resourceComputeSnapshotCreate,
@ -177,11 +42,6 @@ func resourceComputeSnapshot() *schema.Resource {
Delete: schema.DefaultTimeout(300 * time.Second),
},
CustomizeDiff: customdiff.All(
customDiffComputeSnapshotSnapshotEncryptionKeys,
customDiffComputeSnapshotSourceDiskEncryptionKeys,
),
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
@ -206,14 +66,15 @@ func resourceComputeSnapshot() *schema.Resource {
},
"snapshot_encryption_key": {
Type: schema.TypeList,
Computed: true,
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"raw_key": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
},
"sha256": {
@ -226,12 +87,14 @@ func resourceComputeSnapshot() *schema.Resource {
"source_disk_encryption_key": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"raw_key": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Sensitive: true,
},
},
@ -278,29 +141,29 @@ func resourceComputeSnapshot() *schema.Resource {
},
"snapshot_encryption_key_raw": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Deprecated: "Use snapshot_encryption_key.raw_key instead.",
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Removed: "Use snapshot_encryption_key.raw_key instead.",
},
"snapshot_encryption_key_sha256": {
Type: schema.TypeString,
Computed: true,
Deprecated: "Use snapshot_encryption_key.sha256 instead.",
Type: schema.TypeString,
Computed: true,
Removed: "Use snapshot_encryption_key.sha256 instead.",
},
"source_disk_encryption_key_raw": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Deprecated: "Use source_disk_encryption_key.raw_key instead.",
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Removed: "Use source_disk_encryption_key.raw_key instead.",
},
"source_disk_encryption_key_sha256": {
Type: schema.TypeString,
Computed: true,
Deprecated: "Use source_disk_encryption_key.sha256 instead.",
Type: schema.TypeString,
Computed: true,
Removed: "Use source_disk_encryption_key.sha256 instead.",
},
"project": {
Type: schema.TypeString,
@ -713,47 +576,62 @@ func expandComputeSnapshotZone(v interface{}, d *schema.ResourceData, config *Co
func expandComputeSnapshotSnapshotEncryptionKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, 1)
if len(l) == 1 && l[0].(map[string]interface{})["raw_key"] != "" {
// There is a value
outMap := make(map[string]interface{})
outMap["rawKey"] = l[0].(map[string]interface{})["raw_key"]
req = append(req, outMap)
} else {
// Check alternative setting?
if altV, ok := d.GetOk("snapshot_encryption_key_raw"); ok && altV != "" {
outMap := make(map[string]interface{})
outMap["rawKey"] = altV
req = append(req, outMap)
}
if len(l) == 0 || l[0] == nil {
return nil, nil
}
return req, nil
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedRawKey, err := expandComputeSnapshotSnapshotEncryptionKeyRawKey(original["raw_key"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedRawKey); val.IsValid() && !isEmptyValue(val) {
transformed["rawKey"] = transformedRawKey
}
transformedSha256, err := expandComputeSnapshotSnapshotEncryptionKeySha256(original["sha256"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSha256); val.IsValid() && !isEmptyValue(val) {
transformed["sha256"] = transformedSha256
}
return transformed, nil
}
func expandComputeSnapshotSnapshotEncryptionKeyRawKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandComputeSnapshotSnapshotEncryptionKeySha256(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func expandComputeSnapshotSourceDiskEncryptionKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, 1)
if len(l) == 1 {
// There is a value
outMap := make(map[string]interface{})
outMap["rawKey"] = l[0].(map[string]interface{})["raw_key"]
req = append(req, outMap)
} else {
// Check alternative setting?
if altV, ok := d.GetOk("source_disk_encryption_key_raw"); ok && altV != "" {
outMap := make(map[string]interface{})
outMap["rawKey"] = altV
req = append(req, outMap)
}
if len(l) == 0 || l[0] == nil {
return nil, nil
}
return req, nil
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})
transformedRawKey, err := expandComputeSnapshotSourceDiskEncryptionKeyRawKey(original["raw_key"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedRawKey); val.IsValid() && !isEmptyValue(val) {
transformed["rawKey"] = transformedRawKey
}
return transformed, nil
}
func expandComputeSnapshotSourceDiskEncryptionKeyRawKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) {
return v, nil
}
func resourceComputeSnapshotDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
d.Set("source_disk_link", ConvertSelfLinkToV1(res["sourceDisk"].(string)))
if snapshotEncryptionKey := res["snapshotEncryptionKey"]; snapshotEncryptionKey != nil {
d.Set("snapshot_encryption_key_sha256", snapshotEncryptionKey.((map[string]interface{}))["sha256"])
}
return res, nil
}

View File

@ -0,0 +1,94 @@
// ----------------------------------------------------------------------------
//
// *** AUTO GENERATED CODE *** AUTO GENERATED CODE ***
//
// ----------------------------------------------------------------------------
//
// This file is automatically generated by Magic Modules and manual
// changes will be clobbered when the file is regenerated.
//
// Please read more about how to change this file in
// .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccComputeSnapshot_snapshotBasicExample(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeSnapshot_snapshotBasicExample(acctest.RandString(10)),
},
{
ResourceName: "google_compute_snapshot.snapshot",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone", "source_disk_encryption_key"},
},
},
})
}
func testAccComputeSnapshot_snapshotBasicExample(val string) string {
return fmt.Sprintf(`
resource "google_compute_snapshot" "snapshot" {
name = "my-snapshot-%s"
source_disk = "${google_compute_disk.persistent.name}"
zone = "us-central1-a"
labels = {
my_label = "value"
}
}
data "google_compute_image" "debian" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "persistent" {
name = "debian-disk-%s"
image = "${data.google_compute_image.debian.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
}
`, val, val,
)
}
func testAccCheckComputeSnapshotDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_snapshot" {
continue
}
config := testAccProvider.Meta().(*Config)
url, err := replaceVarsForTest(rs, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/snapshots/{{name}}")
if err != nil {
return err
}
_, err = sendRequest(config, "GET", url, nil)
if err == nil {
return fmt.Errorf("ComputeSnapshot still exists at %s", url)
}
}
return nil
}

View File

@ -2,47 +2,16 @@ package google
import (
"fmt"
"regexp"
"testing"
"reflect"
"strings"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
)
func TestAccComputeSnapshot_basic(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_basic(snapshotName, diskName, "my-value"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_update(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
@ -50,480 +19,52 @@ func TestAccComputeSnapshot_update(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccComputeSnapshot_basic(snapshotName, diskName, "my-value"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
{
ResourceName: "google_compute_snapshot.foobar",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
},
{
Config: testAccComputeSnapshot_basic(snapshotName, diskName, "my-updated-value"),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
{
ResourceName: "google_compute_snapshot.foobar",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
},
},
})
}
func TestAccComputeSnapshot_encryptionBasic(t *testing.T) {
func TestAccComputeSnapshot_encryption(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
{
ResourceName: "google_compute_snapshot.foobar",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone", "snapshot_encryption_key", "source_disk_encryption_key"},
},
},
})
}
func TestAccComputeSnapshot_encryptionModify(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionDelta(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionModifyBad(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionDeltaBad(snapshotName, diskName),
ExpectError: regexp.MustCompile("customerEncryptionKeyIsIncorrect"),
},
},
})
}
func TestAccComputeSnapshot_encryptionOld(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOld(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionUpgrade(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOld(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionUpgradeModify(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOld(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionDelta(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionUpgradeModifyBad(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOld(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionDeltaBad(snapshotName, diskName),
ExpectError: regexp.MustCompile("customerEncryptionKeyIsIncorrect"),
},
},
})
}
func TestAccComputeSnapshot_encryptionDowngrade(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOldGuarded(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionDowngradeModify(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOldDelta1(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOldDelta2(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
},
})
}
func TestAccComputeSnapshot_encryptionDowngradeModifyBad(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOldDeltaBad(snapshotName, diskName),
ExpectError: regexp.MustCompile("customerEncryptionKeyIsIncorrect"),
},
},
})
}
func TestAccComputeSnapshot_encryptionOldRemove(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryptionOld(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionNone(snapshotName, diskName),
ExpectError: regexp.MustCompile("resourceIsEncryptedWithCustomerEncryptionKey"),
},
},
})
}
func TestAccComputeSnapshot_encryptionRemove(t *testing.T) {
t.Parallel()
snapshotName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
diskName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var snapshot compute.Snapshot
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSnapshotDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSnapshot_encryption(snapshotName, diskName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSnapshotExists(
"google_compute_snapshot.foobar", &snapshot),
),
},
resource.TestStep{
Config: testAccComputeSnapshot_encryptionNone(snapshotName, diskName),
ExpectError: regexp.MustCompile("resourceIsEncryptedWithCustomerEncryptionKey"),
},
},
})
}
func testAccCheckComputeSnapshotDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_snapshot" {
continue
}
_, err := config.clientCompute.Snapshots.Get(
config.Project, rs.Primary.ID).Do()
if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
return nil
} else if ok {
return fmt.Errorf("Error while requesting Google Cloud Plateform: http code error : %d, http message error: %s", gerr.Code, gerr.Message)
}
return fmt.Errorf("Error while requesting Google Cloud Plateform")
}
return fmt.Errorf("Snapshot still exists")
}
return nil
}
func testAccCheckComputeSnapshotExists(n string, snapshot *compute.Snapshot) 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")
}
config := testAccProvider.Meta().(*Config)
found, err := config.clientCompute.Snapshots.Get(
config.Project, rs.Primary.ID).Do()
if err != nil {
return err
}
if found.Name != rs.Primary.ID {
return fmt.Errorf("Snapshot %s not found", n)
}
attr := rs.Primary.Attributes["snapshot_encryption_key_sha256"]
if found.SnapshotEncryptionKey != nil && found.SnapshotEncryptionKey.Sha256 != attr {
return fmt.Errorf("Snapshot %s has mismatched encryption key (Sha256).\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SnapshotEncryptionKey.Sha256)
} else if found.SnapshotEncryptionKey == nil && attr != "" {
return fmt.Errorf("Snapshot %s has mismatched encryption key.\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SnapshotEncryptionKey)
}
attr = rs.Primary.Attributes["source_disk_encryption_key_sha256"]
if found.SourceDiskEncryptionKey != nil && found.SourceDiskEncryptionKey.Sha256 != attr {
return fmt.Errorf("Snapshot %s has mismatched source disk encryption key (Sha256).\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SourceDiskEncryptionKey.Sha256)
} else if found.SourceDiskEncryptionKey == nil && attr != "" {
return fmt.Errorf("Snapshot %s has mismatched source disk encryption key.\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SourceDiskEncryptionKey)
}
attr = rs.Primary.Attributes["source_disk_link"]
if found.SourceDisk != attr {
return fmt.Errorf("Snapshot %s has mismatched source disk link.\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SourceDisk)
}
foundDisk, errDisk := config.clientCompute.Disks.Get(
config.Project, rs.Primary.Attributes["zone"], rs.Primary.Attributes["source_disk"]).Do()
if errDisk != nil {
return errDisk
}
if foundDisk.SelfLink != attr {
return fmt.Errorf("Snapshot %s has mismatched source disk\nTF State: %+v.\nGCP State: %+v",
n, attr, foundDisk.SelfLink)
}
attr = rs.Primary.Attributes["self_link"]
if found.SelfLink != attr {
return fmt.Errorf("Snapshot %s has mismatched self link.\nTF State: %+v.\nGCP State: %+v",
n, attr, found.SelfLink)
}
// We should have a map
attr, ok = rs.Primary.Attributes["labels.%"]
if !ok {
return fmt.Errorf("Snapshot %s has no labels map in attributes", n)
}
// Parse out our map
attrMap := make(map[string]string)
for k, v := range rs.Primary.Attributes {
if !strings.HasPrefix(k, "labels.") || k == "labels.%" {
continue
}
key := k[len("labels."):]
attrMap[key] = v
}
if (len(attrMap) != 0 || len(found.Labels) != 0) && !reflect.DeepEqual(attrMap, found.Labels) {
return fmt.Errorf("Snapshot %s has mismatched labels.\nTF State: %+v\nGCP State: %+v",
n, attrMap, found.Labels)
}
attr = rs.Primary.Attributes["label_fingerprint"]
if found.LabelFingerprint != attr {
return fmt.Errorf("Snapshot %s has mismatched label fingerprint\nTF State: %+v.\nGCP State: %+v",
n, attr, found.LabelFingerprint)
}
*snapshot = *found
return nil
}
}
func testAccComputeSnapshot_basic(snapshotName, diskName, labelValue string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
@ -580,246 +121,3 @@ resource "google_compute_snapshot" "foobar" {
}
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionOld(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
source_disk_encryption_key_raw = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
snapshot_encryption_key_raw = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionOldGuarded(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = ""
}
source_disk_encryption_key_raw = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
snapshot_encryption_key_raw = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionDelta(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
source_disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionOldDelta1(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = ""
}
source_disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
snapshot_encryption_key_raw = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionOldDelta2(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = ""
}
source_disk_encryption_key_raw = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
snapshot_encryption_key_raw = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionDeltaBad(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
source_disk_encryption_key {
raw_key = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionOldDeltaBad(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
snapshot_encryption_key {
raw_key = ""
}
source_disk_encryption_key_raw = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
snapshot_encryption_key_raw = "Sznt5GBBAJky3BgBVbDOMLY3TlStz7RikXujsFQ0GlA="
}`, diskName, snapshotName)
}
func testAccComputeSnapshot_encryptionNone(snapshotName string, diskName string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_disk" "foobar" {
name = "%s"
image = "${data.google_compute_image.my_image.self_link}"
size = 10
type = "pd-ssd"
zone = "us-central1-a"
disk_encryption_key {
raw_key = "SGVsbG8gZnJvbSBHb29nbGUgQ2xvdWQgUGxhdGZvcm0="
}
}
resource "google_compute_snapshot" "foobar" {
name = "%s"
source_disk = "${google_compute_disk.foobar.name}"
zone = "us-central1-a"
}`, diskName, snapshotName)
}

View File

@ -41,6 +41,11 @@ To get more information about Snapshot, see:
* How-to Guides
* [Official Documentation](https://cloud.google.com/compute/docs/disks/create-snapshots)
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_working_dir=snapshot_basic&cloudshell_image=gcr.io%2Fgraphite-cloud-shell-images%2Fterraform%3Alatest&open_in_editor=main.tf&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
</a>
</div>
## Example Usage - Snapshot Basic
@ -50,7 +55,7 @@ resource "google_compute_snapshot" "snapshot" {
source_disk = "${google_compute_disk.persistent.name}"
zone = "us-central1-a"
labels = {
my_label = "%s"
my_label = "value"
}
}
@ -135,13 +140,6 @@ The `source_disk_encryption_key` block supports:
Specifies a 256-bit customer-supplied encryption key, encoded in
RFC 4648 base64 to either encrypt or decrypt this resource.
* (Deprecated) `snapshot_encryption_key_raw`: (Optional) This is an alias for
`snapshot_encryption_key.0.raw_key`. This field has been deprecated
and will be removed in a future provider version.
* (Deprecated) `source_disk_encryption_key_raw`: (Optional) This is an alias for
`source_disk_encryption_key.0.raw_key`. This field has been deprecated
and will be removed in a future provider version.
## Attributes Reference
In addition to the arguments listed above, the following computed attributes are exported:
@ -173,12 +171,6 @@ In addition to the arguments listed above, the following computed attributes are
* `self_link` - The URI of the created resource.
* (Deprecated) `snapshot_encryption_key_sha256`: This is an alias for
`source_disk_encryption_key.0.sha256`. This attribute has been deprecated
and will be removed in a future provider version.
* (Deprecated) `source_disk_encryption_key_sha256`: This attribute has never had
a value and will be removed in a future provider version.
## Timeouts
This resource provides the following