| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| // ---------------------------------------------------------------------------- |
| // |
| // *** AUTO GENERATED CODE *** Type: MMv1 *** |
| // |
| // ---------------------------------------------------------------------------- |
| // |
| // 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 compute |
| |
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "log" |
| "net/http" |
| "reflect" |
| "strings" |
| "time" |
| |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| "google.golang.org/api/googleapi" |
| |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" |
| transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" |
| ) |
| |
| // diffsupress for hyperdisk provisioned_iops |
| func hyperDiskIopsUpdateDiffSupress(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { |
| if !strings.Contains(d.Get("type").(string), "hyperdisk") { |
| resourceSchema := ResourceComputeDisk().Schema |
| for field := range resourceSchema { |
| if field == "provisioned_iops" && d.HasChange(field) { |
| if err := d.ForceNew(field); err != nil { |
| return err |
| } |
| } |
| } |
| } |
| |
| return nil |
| } |
| |
| // Suppress all diffs, used for Disk.Interface which is a nonfunctional field |
| func AlwaysDiffSuppress(_, _, _ string, _ *schema.ResourceData) bool { |
| return true |
| } |
| |
| // diffsupress for beta and to check change in source_disk attribute |
| func sourceDiskDiffSupress(_, old, new string, _ *schema.ResourceData) bool { |
| s1 := strings.TrimPrefix(old, "https://www.googleapis.com/compute/beta") |
| s2 := strings.TrimPrefix(new, "https://www.googleapis.com/compute/v1") |
| if strings.HasSuffix(s1, s2) { |
| return true |
| } |
| return false |
| } |
| |
| // Is the new disk size smaller than the old one? |
| func IsDiskShrinkage(_ context.Context, old, new, _ interface{}) bool { |
| // It's okay to remove size entirely. |
| if old == nil || new == nil { |
| return false |
| } |
| return new.(int) < old.(int) |
| } |
| |
| // We cannot suppress the diff for the case when family name is not part of the image name since we can't |
| // make a network call in a DiffSuppressFunc. |
| func DiskImageDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { |
| // Understand that this function solves a messy problem ("how do we tell if the diff between two images |
| // is 'ForceNew-worthy', without making a network call?") in the best way we can: through a series of special |
| // cases and regexes. If you find yourself here because you are trying to add a new special case, |
| // you are probably looking for the diskImageFamilyEquals function and its subfunctions. |
| // In order to keep this maintainable, we need to ensure that the positive and negative examples |
| // in resource_compute_disk_test.go are as complete as possible. |
| |
| // 'old' is read from the API. |
| // It always has the format 'https://www.googleapis.com/compute/v1/projects/(%s)/global/images/(%s)' |
| matches := resolveImageLink.FindStringSubmatch(old) |
| if matches == nil { |
| // Image read from the API doesn't have the expected format. In practice, it should never happen |
| return false |
| } |
| oldProject := matches[1] |
| oldName := matches[2] |
| |
| // Partial or full self link family |
| if resolveImageProjectFamily.MatchString(new) { |
| // Value matches pattern "projects/{project}/global/images/family/{family-name}$" |
| matches := resolveImageProjectFamily.FindStringSubmatch(new) |
| newProject := matches[1] |
| newFamilyName := matches[2] |
| |
| return diskImageProjectNameEquals(oldProject, newProject) && diskImageFamilyEquals(oldName, newFamilyName) |
| } |
| |
| // Partial or full self link image |
| if resolveImageProjectImage.MatchString(new) { |
| // Value matches pattern "projects/{project}/global/images/{image-name}$" |
| matches := resolveImageProjectImage.FindStringSubmatch(new) |
| newProject := matches[1] |
| newImageName := matches[2] |
| |
| return diskImageProjectNameEquals(oldProject, newProject) && diskImageEquals(oldName, newImageName) |
| } |
| |
| // Partial link without project family |
| if resolveImageGlobalFamily.MatchString(new) { |
| // Value is "global/images/family/{family-name}" |
| matches := resolveImageGlobalFamily.FindStringSubmatch(new) |
| familyName := matches[1] |
| |
| return diskImageFamilyEquals(oldName, familyName) |
| } |
| |
| // Partial link without project image |
| if resolveImageGlobalImage.MatchString(new) { |
| // Value is "global/images/{image-name}" |
| matches := resolveImageGlobalImage.FindStringSubmatch(new) |
| imageName := matches[1] |
| |
| return diskImageEquals(oldName, imageName) |
| } |
| |
| // Family shorthand |
| if resolveImageFamilyFamily.MatchString(new) { |
| // Value is "family/{family-name}" |
| matches := resolveImageFamilyFamily.FindStringSubmatch(new) |
| familyName := matches[1] |
| |
| return diskImageFamilyEquals(oldName, familyName) |
| } |
| |
| // Shorthand for image or family |
| if resolveImageProjectImageShorthand.MatchString(new) { |
| // Value is "{project}/{image-name}" or "{project}/{family-name}" |
| matches := resolveImageProjectImageShorthand.FindStringSubmatch(new) |
| newProject := matches[1] |
| newName := matches[2] |
| |
| return diskImageProjectNameEquals(oldProject, newProject) && |
| (diskImageEquals(oldName, newName) || diskImageFamilyEquals(oldName, newName)) |
| } |
| |
| // Image or family only |
| if diskImageEquals(oldName, new) || diskImageFamilyEquals(oldName, new) { |
| // Value is "{image-name}" or "{family-name}" |
| return true |
| } |
| |
| return false |
| } |
| |
| func diskImageProjectNameEquals(project1, project2 string) bool { |
| // Convert short project name to full name |
| // For instance, centos => centos-cloud |
| fullProjectName, ok := ImageMap[project2] |
| if ok { |
| project2 = fullProjectName |
| } |
| |
| return project1 == project2 |
| } |
| |
| func diskImageEquals(oldImageName, newImageName string) bool { |
| return oldImageName == newImageName |
| } |
| |
| func diskImageFamilyEquals(imageName, familyName string) bool { |
| // Handles the case when the image name includes the family name |
| // e.g. image name: debian-11-bullseye-v20220719, family name: debian-11 |
| |
| // First condition is to check if image contains arm64 because of case like: |
| // image name: opensuse-leap-15-4-v20220713-arm64, family name: opensuse-leap (should not be evaluated during handling of amd64 cases) |
| // In second condition, we have to check for amd64 because of cases like: |
| // image name: ubuntu-2210-kinetic-amd64-v20221022, family name: ubuntu-2210 (should not suppress) |
| if !strings.Contains(imageName, "-arm64") && strings.Contains(imageName, strings.TrimSuffix(familyName, "-amd64")) { |
| if strings.Contains(imageName, "-amd64") { |
| return strings.HasSuffix(familyName, "-amd64") |
| } else { |
| return !strings.HasSuffix(familyName, "-amd64") |
| } |
| } |
| |
| // We have to check for arm64 because of cases like: |
| // image name: opensuse-leap-15-4-v20220713-arm64, family name: opensuse-leap (should not suppress) |
| if strings.Contains(imageName, strings.TrimSuffix(familyName, "-arm64")) { |
| if strings.Contains(imageName, "-arm64") { |
| return strings.HasSuffix(familyName, "-arm64") |
| } else { |
| return !strings.HasSuffix(familyName, "-arm64") |
| } |
| } |
| |
| if suppressCanonicalFamilyDiff(imageName, familyName) { |
| return true |
| } |
| |
| if suppressCosFamilyDiff(imageName, familyName) { |
| return true |
| } |
| |
| if suppressWindowsSqlFamilyDiff(imageName, familyName) { |
| return true |
| } |
| |
| if suppressWindowsFamilyDiff(imageName, familyName) { |
| return true |
| } |
| |
| return false |
| } |
| |
| // e.g. image: ubuntu-1404-trusty-v20180122, family: ubuntu-1404-lts |
| func suppressCanonicalFamilyDiff(imageName, familyName string) bool { |
| parts := canonicalUbuntuLtsImage.FindStringSubmatch(imageName) |
| if len(parts) == 4 { |
| var f string |
| if parts[3] == "" { |
| f = fmt.Sprintf("ubuntu-%s%s-lts", parts[1], parts[2]) |
| } else { |
| f = fmt.Sprintf("ubuntu-%s%s-lts-%s", parts[1], parts[2], parts[3]) |
| } |
| if f == familyName { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| // e.g. image: cos-NN-*, family: cos-NN-lts |
| func suppressCosFamilyDiff(imageName, familyName string) bool { |
| parts := cosLtsImage.FindStringSubmatch(imageName) |
| if len(parts) == 2 { |
| f := fmt.Sprintf("cos-%s-lts", parts[1]) |
| if f == familyName { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| // e.g. image: sql-2017-standard-windows-2016-dc-v20180109, family: sql-std-2017-win-2016 |
| // e.g. image: sql-2017-express-windows-2012-r2-dc-v20180109, family: sql-exp-2017-win-2012-r2 |
| func suppressWindowsSqlFamilyDiff(imageName, familyName string) bool { |
| parts := windowsSqlImage.FindStringSubmatch(imageName) |
| if len(parts) == 5 { |
| edition := parts[2] // enterprise, standard or web. |
| sqlVersion := parts[1] |
| windowsVersion := parts[3] |
| |
| // Translate edition |
| switch edition { |
| case "enterprise": |
| edition = "ent" |
| case "standard": |
| edition = "std" |
| case "express": |
| edition = "exp" |
| } |
| |
| var f string |
| if revision := parts[4]; revision != "" { |
| // With revision |
| f = fmt.Sprintf("sql-%s-%s-win-%s-r%s", edition, sqlVersion, windowsVersion, revision) |
| } else { |
| // No revision |
| f = fmt.Sprintf("sql-%s-%s-win-%s", edition, sqlVersion, windowsVersion) |
| } |
| |
| if f == familyName { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| // e.g. image: windows-server-1709-dc-core-v20180109, family: windows-1709-core |
| // e.g. image: windows-server-1709-dc-core-for-containers-v20180109, family: "windows-1709-core-for-containers |
| func suppressWindowsFamilyDiff(imageName, familyName string) bool { |
| updatedFamilyString := strings.Replace(familyName, "windows-", "windows-server-", 1) |
| updatedImageName := strings.Replace(imageName, "-dc-", "-", 1) |
| |
| return strings.Contains(updatedImageName, updatedFamilyString) |
| } |
| |
| func ResourceComputeDisk() *schema.Resource { |
| return &schema.Resource{ |
| Create: resourceComputeDiskCreate, |
| Read: resourceComputeDiskRead, |
| Update: resourceComputeDiskUpdate, |
| Delete: resourceComputeDiskDelete, |
| |
| Importer: &schema.ResourceImporter{ |
| State: resourceComputeDiskImport, |
| }, |
| |
| Timeouts: &schema.ResourceTimeout{ |
| Create: schema.DefaultTimeout(20 * time.Minute), |
| Update: schema.DefaultTimeout(20 * time.Minute), |
| Delete: schema.DefaultTimeout(20 * time.Minute), |
| }, |
| |
| CustomizeDiff: customdiff.All( |
| customdiff.ForceNewIfChange("size", IsDiskShrinkage), |
| hyperDiskIopsUpdateDiffSupress, |
| tpgresource.SetLabelsDiff, |
| tpgresource.DefaultProviderProject, |
| ), |
| |
| Schema: map[string]*schema.Schema{ |
| "name": { |
| Type: schema.TypeString, |
| Required: true, |
| ForceNew: true, |
| Description: `Name of the resource. Provided by the client when the resource is |
| created. The name must be 1-63 characters long, and comply with |
| RFC1035. Specifically, the name must be 1-63 characters long and match |
| the regular expression '[a-z]([-a-z0-9]*[a-z0-9])?' which means the |
| first character must be a lowercase letter, and all following |
| characters must be a dash, lowercase letter, or digit, except the last |
| character, which cannot be a dash.`, |
| }, |
| "access_mode": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| Description: `The accessMode of the disk. |
| For example: |
| * READ_WRITE_SINGLE |
| * READ_WRITE_MANY |
| * READ_ONLY_SINGLE`, |
| }, |
| "async_primary_disk": { |
| Type: schema.TypeList, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkRelativePaths, |
| Description: `A nested object resource`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "disk": { |
| Type: schema.TypeString, |
| Required: true, |
| ForceNew: true, |
| Description: `Primary disk for asynchronous disk replication.`, |
| }, |
| }, |
| }, |
| }, |
| "description": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `An optional description of this resource. Provide this property when |
| you create the resource.`, |
| }, |
| "disk_encryption_key": { |
| Type: schema.TypeList, |
| Optional: true, |
| ForceNew: true, |
| Description: `Encrypts the disk using a customer-supplied encryption key. |
| |
| After you encrypt a disk with a customer-supplied key, you must |
| provide the same key if you use the disk later (e.g. to create a disk |
| snapshot or an image, or to attach the disk to a virtual machine). |
| |
| Customer-supplied encryption keys do not protect access to metadata of |
| the disk. |
| |
| If you do not provide an encryption key when creating the disk, then |
| the disk will be encrypted using an automatically generated key and |
| you do not need to provide a key to use the disk later.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "kms_key_self_link": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkRelativePaths, |
| Description: `The self link of the encryption key used to encrypt the disk. Also called KmsKeyName |
| in the cloud console. Your project's Compute Engine System service account |
| ('service-{{PROJECT_NUMBER}}@compute-system.iam.gserviceaccount.com') must have |
| 'roles/cloudkms.cryptoKeyEncrypterDecrypter' to use this feature. |
| See https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys`, |
| }, |
| "kms_key_service_account": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `The service account used for the encryption request for the given KMS key. |
| If absent, the Compute Engine Service Agent service account is used.`, |
| }, |
| "raw_key": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `Specifies a 256-bit customer-supplied encryption key, encoded in |
| RFC 4648 base64 to either encrypt or decrypt this resource.`, |
| Sensitive: true, |
| }, |
| "rsa_encrypted_key": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `Specifies an RFC 4648 base64 encoded, RSA-wrapped 2048-bit |
| customer-supplied encryption key to either encrypt or decrypt |
| this resource. You can provide either the rawKey or the rsaEncryptedKey.`, |
| Sensitive: true, |
| }, |
| "sha256": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied |
| encryption key that protects this resource.`, |
| }, |
| }, |
| }, |
| }, |
| "enable_confidential_compute": { |
| Type: schema.TypeBool, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| Description: `Whether this disk is using confidential compute mode. |
| Note: Only supported on hyperdisk skus, disk_encryption_key is required when setting to true`, |
| }, |
| "guest_os_features": { |
| Type: schema.TypeSet, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| Description: `A list of features to enable on the guest operating system. |
| Applicable only for bootable disks.`, |
| Elem: computeDiskGuestOsFeaturesSchema(), |
| // Default schema.HashSchema is used. |
| }, |
| "image": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: DiskImageDiffSuppress, |
| Description: `The image from which to initialize this disk. This can be |
| one of: the image's 'self_link', 'projects/{project}/global/images/{image}', |
| 'projects/{project}/global/images/family/{family}', 'global/images/{image}', |
| 'global/images/family/{family}', 'family/{family}', '{project}/{family}', |
| '{project}/{image}', '{family}', or '{image}'. If referred by family, the |
| images names must include the family name. If they don't, use the |
| [google_compute_image data source](/docs/providers/google/d/compute_image.html). |
| For instance, the image 'centos-6-v20180104' includes its family name 'centos-6'. |
| These images can be referred by family name here.`, |
| }, |
| "interface": { |
| Type: schema.TypeString, |
| Optional: true, |
| Deprecated: "`interface` is deprecated and will be removed in a future major release. This field is no longer used and can be safely removed from your configurations; disk interfaces are automatically determined on attachment.", |
| ForceNew: true, |
| DiffSuppressFunc: AlwaysDiffSuppress, |
| Description: `Specifies the disk interface to use for attaching this disk, which is either SCSI or NVME. The default is SCSI.`, |
| Default: "SCSI", |
| }, |
| "labels": { |
| Type: schema.TypeMap, |
| Optional: true, |
| Description: `Labels to apply to this disk. A list of key->value pairs. |
| |
| |
| **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. |
| Please refer to the field 'effective_labels' for all of the labels present on the resource.`, |
| Elem: &schema.Schema{Type: schema.TypeString}, |
| }, |
| "licenses": { |
| Type: schema.TypeList, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| Description: `Any applicable license URI.`, |
| Elem: &schema.Schema{ |
| Type: schema.TypeString, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| }, |
| }, |
| "multi_writer": { |
| Type: schema.TypeBool, |
| Optional: true, |
| ForceNew: true, |
| Description: `Indicates whether or not the disk can be read/write attached to more than one instance.`, |
| }, |
| "physical_block_size_bytes": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| Description: `Physical block size of the persistent disk, in bytes. If not present |
| in a request, a default value is used. Currently supported sizes |
| are 4096 and 16384, other sizes may be added in the future. |
| If an unsupported value is requested, the error message will list |
| the supported values for the caller's project.`, |
| }, |
| "provisioned_iops": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| Description: `Indicates how many IOPS must be provisioned for the disk. |
| Note: Updating currently is only supported by hyperdisk skus without the need to delete and recreate the disk, hyperdisk |
| allows for an update of IOPS every 4 hours. To update your hyperdisk more frequently, you'll need to manually delete and recreate it`, |
| }, |
| "provisioned_throughput": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| Description: `Indicates how much Throughput must be provisioned for the disk. |
| Note: Updating currently is only supported by hyperdisk skus without the need to delete and recreate the disk, hyperdisk |
| allows for an update of Throughput every 4 hours. To update your hyperdisk more frequently, you'll need to manually delete and recreate it`, |
| }, |
| "resource_policies": { |
| Type: schema.TypeList, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| Description: `Resource policies applied to this disk for automatic snapshot creations. |
| |
| ~>**NOTE** This value does not support updating the |
| resource policy, as resource policies can not be updated more than |
| one at a time. Use |
| ['google_compute_disk_resource_policy_attachment'](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_disk_resource_policy_attachment) |
| to allow for updating the resource policy attached to the disk.`, |
| Elem: &schema.Schema{ |
| Type: schema.TypeString, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| }, |
| }, |
| "size": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| Description: `Size of the persistent disk, specified in GB. You can specify this |
| field when creating a persistent disk using the 'image' or |
| 'snapshot' parameter, or specify it alone to create an empty |
| persistent disk. |
| |
| If you specify this field along with 'image' or 'snapshot', |
| the value must not be less than the size of the image |
| or the size of the snapshot. |
| |
| ~>**NOTE** If you change the size, Terraform updates the disk size |
| if upsizing is detected but recreates the disk if downsizing is requested. |
| You can add 'lifecycle.prevent_destroy' in the config to prevent destroying |
| and recreating.`, |
| }, |
| "snapshot": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `The source snapshot used to create this disk. You can provide this as |
| a partial or full URL to the resource. If the snapshot is in another |
| project than this disk, you must supply a full URL. For example, the |
| following are valid values: |
| |
| * 'https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot' |
| * 'projects/project/global/snapshots/snapshot' |
| * 'global/snapshots/snapshot' |
| * 'snapshot'`, |
| }, |
| "source_disk": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: sourceDiskDiffSupress, |
| Description: `The source disk used to create this disk. You can provide this as a partial or full URL to the resource. |
| For example, the following are valid values: |
| |
| * https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/disks/{disk} |
| * https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/disks/{disk} |
| * projects/{project}/zones/{zone}/disks/{disk} |
| * projects/{project}/regions/{region}/disks/{disk} |
| * zones/{zone}/disks/{disk} |
| * regions/{region}/disks/{disk}`, |
| }, |
| "source_image_encryption_key": { |
| Type: schema.TypeList, |
| Optional: true, |
| ForceNew: true, |
| Description: `The customer-supplied encryption key of the source image. Required if |
| the source image is protected by a customer-supplied encryption key.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "kms_key_self_link": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkRelativePaths, |
| Description: `The self link of the encryption key used to encrypt the disk. Also called KmsKeyName |
| in the cloud console. Your project's Compute Engine System service account |
| ('service-{{PROJECT_NUMBER}}@compute-system.iam.gserviceaccount.com') must have |
| 'roles/cloudkms.cryptoKeyEncrypterDecrypter' to use this feature. |
| See https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys`, |
| }, |
| "kms_key_service_account": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `The service account used for the encryption request for the given KMS key. |
| If absent, the Compute Engine Service Agent service account is used.`, |
| }, |
| "raw_key": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `Specifies a 256-bit customer-supplied encryption key, encoded in |
| RFC 4648 base64 to either encrypt or decrypt this resource.`, |
| }, |
| "sha256": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied |
| encryption key that protects this resource.`, |
| }, |
| }, |
| }, |
| }, |
| "source_snapshot_encryption_key": { |
| Type: schema.TypeList, |
| Optional: true, |
| ForceNew: true, |
| Description: `The customer-supplied encryption key of the source snapshot. Required |
| if the source snapshot is protected by a customer-supplied encryption |
| key.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "kms_key_self_link": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkRelativePaths, |
| Description: `The self link of the encryption key used to encrypt the disk. Also called KmsKeyName |
| in the cloud console. Your project's Compute Engine System service account |
| ('service-{{PROJECT_NUMBER}}@compute-system.iam.gserviceaccount.com') must have |
| 'roles/cloudkms.cryptoKeyEncrypterDecrypter' to use this feature. |
| See https://cloud.google.com/compute/docs/disks/customer-managed-encryption#encrypt_a_new_persistent_disk_with_your_own_keys`, |
| }, |
| "kms_key_service_account": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `The service account used for the encryption request for the given KMS key. |
| If absent, the Compute Engine Service Agent service account is used.`, |
| }, |
| "raw_key": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| Description: `Specifies a 256-bit customer-supplied encryption key, encoded in |
| RFC 4648 base64 to either encrypt or decrypt this resource.`, |
| }, |
| "sha256": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied |
| encryption key that protects this resource.`, |
| }, |
| }, |
| }, |
| }, |
| "storage_pool": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareResourceNames, |
| Description: `The URL of the storage pool in which the new disk is created. |
| For example: |
| * https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/storagePools/{storagePool} |
| * /projects/{project}/zones/{zone}/storagePools/{storagePool}`, |
| }, |
| "type": { |
| Type: schema.TypeString, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareResourceNames, |
| Description: `URL of the disk type resource describing which disk type to use to |
| create the disk. Provide this when creating the disk.`, |
| Default: "pd-standard", |
| }, |
| "zone": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `A reference to the zone where the disk resides.`, |
| }, |
| "disk_id": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The unique identifier for the resource. This identifier is defined by the server.`, |
| }, |
| "creation_timestamp": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `Creation timestamp in RFC3339 text format.`, |
| }, |
| "effective_labels": { |
| Type: schema.TypeMap, |
| Computed: true, |
| Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, |
| Elem: &schema.Schema{Type: schema.TypeString}, |
| }, |
| "label_fingerprint": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The fingerprint used for optimistic locking of this resource. Used |
| internally during updates.`, |
| }, |
| "last_attach_timestamp": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `Last attach timestamp in RFC3339 text format.`, |
| }, |
| "last_detach_timestamp": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `Last detach timestamp in RFC3339 text format.`, |
| }, |
| "source_disk_id": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The ID value of the disk used to create this image. This value may |
| be used to determine whether the image was taken from the current |
| or a previous instance of a given disk name.`, |
| }, |
| "source_image_id": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The ID value of the image used to create this disk. This value |
| identifies the exact image that was used to create this persistent |
| disk. For example, if you created the persistent disk from an image |
| that was later deleted and recreated under the same name, the source |
| image ID would identify the exact version of the image that was used.`, |
| }, |
| "source_snapshot_id": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `The unique ID of the snapshot used to create this disk. This value |
| identifies the exact snapshot that was used to create this persistent |
| disk. For example, if you created the persistent disk from a snapshot |
| that was later deleted and recreated under the same name, the source |
| snapshot ID would identify the exact version of the snapshot that was |
| used.`, |
| }, |
| "terraform_labels": { |
| Type: schema.TypeMap, |
| Computed: true, |
| Description: `The combination of labels configured directly on the resource |
| and default labels configured on the provider.`, |
| Elem: &schema.Schema{Type: schema.TypeString}, |
| }, |
| "users": { |
| Type: schema.TypeList, |
| Computed: true, |
| Description: `Links to the users of the disk (attached instances) in form: |
| project/zones/zone/instances/instance`, |
| Elem: &schema.Schema{ |
| Type: schema.TypeString, |
| }, |
| }, |
| "project": { |
| Type: schema.TypeString, |
| Optional: true, |
| Computed: true, |
| ForceNew: true, |
| }, |
| "self_link": { |
| Type: schema.TypeString, |
| Computed: true, |
| }, |
| }, |
| UseJSONNumber: true, |
| } |
| } |
| |
| func computeDiskGuestOsFeaturesSchema() *schema.Resource { |
| return &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "type": { |
| Type: schema.TypeString, |
| Required: true, |
| ForceNew: true, |
| Description: `The type of supported feature. Read [Enabling guest operating system features](https://cloud.google.com/compute/docs/images/create-delete-deprecate-private-images#guest-os-features) to see a list of available options.`, |
| }, |
| }, |
| } |
| } |
| |
| func resourceComputeDiskCreate(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| obj := make(map[string]interface{}) |
| labelFingerprintProp, err := expandComputeDiskLabelFingerprint(d.Get("label_fingerprint"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelFingerprintProp)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { |
| obj["labelFingerprint"] = labelFingerprintProp |
| } |
| descriptionProp, err := expandComputeDiskDescription(d.Get("description"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { |
| obj["description"] = descriptionProp |
| } |
| nameProp, err := expandComputeDiskName(d.Get("name"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { |
| obj["name"] = nameProp |
| } |
| sizeGbProp, err := expandComputeDiskSize(d.Get("size"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("size"); !tpgresource.IsEmptyValue(reflect.ValueOf(sizeGbProp)) && (ok || !reflect.DeepEqual(v, sizeGbProp)) { |
| obj["sizeGb"] = sizeGbProp |
| } |
| physicalBlockSizeBytesProp, err := expandComputeDiskPhysicalBlockSizeBytes(d.Get("physical_block_size_bytes"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("physical_block_size_bytes"); !tpgresource.IsEmptyValue(reflect.ValueOf(physicalBlockSizeBytesProp)) && (ok || !reflect.DeepEqual(v, physicalBlockSizeBytesProp)) { |
| obj["physicalBlockSizeBytes"] = physicalBlockSizeBytesProp |
| } |
| sourceDiskProp, err := expandComputeDiskSourceDisk(d.Get("source_disk"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("source_disk"); !tpgresource.IsEmptyValue(reflect.ValueOf(sourceDiskProp)) && (ok || !reflect.DeepEqual(v, sourceDiskProp)) { |
| obj["sourceDisk"] = sourceDiskProp |
| } |
| typeProp, err := expandComputeDiskType(d.Get("type"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("type"); !tpgresource.IsEmptyValue(reflect.ValueOf(typeProp)) && (ok || !reflect.DeepEqual(v, typeProp)) { |
| obj["type"] = typeProp |
| } |
| sourceImageProp, err := expandComputeDiskImage(d.Get("image"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("image"); !tpgresource.IsEmptyValue(reflect.ValueOf(sourceImageProp)) && (ok || !reflect.DeepEqual(v, sourceImageProp)) { |
| obj["sourceImage"] = sourceImageProp |
| } |
| resourcePoliciesProp, err := expandComputeDiskResourcePolicies(d.Get("resource_policies"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("resource_policies"); !tpgresource.IsEmptyValue(reflect.ValueOf(resourcePoliciesProp)) && (ok || !reflect.DeepEqual(v, resourcePoliciesProp)) { |
| obj["resourcePolicies"] = resourcePoliciesProp |
| } |
| enableConfidentialComputeProp, err := expandComputeDiskEnableConfidentialCompute(d.Get("enable_confidential_compute"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("enable_confidential_compute"); !tpgresource.IsEmptyValue(reflect.ValueOf(enableConfidentialComputeProp)) && (ok || !reflect.DeepEqual(v, enableConfidentialComputeProp)) { |
| obj["enableConfidentialCompute"] = enableConfidentialComputeProp |
| } |
| multiWriterProp, err := expandComputeDiskMultiWriter(d.Get("multi_writer"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("multi_writer"); !tpgresource.IsEmptyValue(reflect.ValueOf(multiWriterProp)) && (ok || !reflect.DeepEqual(v, multiWriterProp)) { |
| obj["multiWriter"] = multiWriterProp |
| } |
| provisionedIopsProp, err := expandComputeDiskProvisionedIops(d.Get("provisioned_iops"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("provisioned_iops"); !tpgresource.IsEmptyValue(reflect.ValueOf(provisionedIopsProp)) && (ok || !reflect.DeepEqual(v, provisionedIopsProp)) { |
| obj["provisionedIops"] = provisionedIopsProp |
| } |
| provisionedThroughputProp, err := expandComputeDiskProvisionedThroughput(d.Get("provisioned_throughput"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("provisioned_throughput"); !tpgresource.IsEmptyValue(reflect.ValueOf(provisionedThroughputProp)) && (ok || !reflect.DeepEqual(v, provisionedThroughputProp)) { |
| obj["provisionedThroughput"] = provisionedThroughputProp |
| } |
| asyncPrimaryDiskProp, err := expandComputeDiskAsyncPrimaryDisk(d.Get("async_primary_disk"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("async_primary_disk"); !tpgresource.IsEmptyValue(reflect.ValueOf(asyncPrimaryDiskProp)) && (ok || !reflect.DeepEqual(v, asyncPrimaryDiskProp)) { |
| obj["asyncPrimaryDisk"] = asyncPrimaryDiskProp |
| } |
| guestOsFeaturesProp, err := expandComputeDiskGuestOsFeatures(d.Get("guest_os_features"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("guest_os_features"); !tpgresource.IsEmptyValue(reflect.ValueOf(guestOsFeaturesProp)) && (ok || !reflect.DeepEqual(v, guestOsFeaturesProp)) { |
| obj["guestOsFeatures"] = guestOsFeaturesProp |
| } |
| licensesProp, err := expandComputeDiskLicenses(d.Get("licenses"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("licenses"); !tpgresource.IsEmptyValue(reflect.ValueOf(licensesProp)) && (ok || !reflect.DeepEqual(v, licensesProp)) { |
| obj["licenses"] = licensesProp |
| } |
| storagePoolProp, err := expandComputeDiskStoragePool(d.Get("storage_pool"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("storage_pool"); !tpgresource.IsEmptyValue(reflect.ValueOf(storagePoolProp)) && (ok || !reflect.DeepEqual(v, storagePoolProp)) { |
| obj["storagePool"] = storagePoolProp |
| } |
| accessModeProp, err := expandComputeDiskAccessMode(d.Get("access_mode"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("access_mode"); !tpgresource.IsEmptyValue(reflect.ValueOf(accessModeProp)) && (ok || !reflect.DeepEqual(v, accessModeProp)) { |
| obj["accessMode"] = accessModeProp |
| } |
| labelsProp, err := expandComputeDiskEffectiveLabels(d.Get("effective_labels"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { |
| obj["labels"] = labelsProp |
| } |
| zoneProp, err := expandComputeDiskZone(d.Get("zone"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("zone"); !tpgresource.IsEmptyValue(reflect.ValueOf(zoneProp)) && (ok || !reflect.DeepEqual(v, zoneProp)) { |
| obj["zone"] = zoneProp |
| } |
| sourceImageEncryptionKeyProp, err := expandComputeDiskSourceImageEncryptionKey(d.Get("source_image_encryption_key"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("source_image_encryption_key"); !tpgresource.IsEmptyValue(reflect.ValueOf(sourceImageEncryptionKeyProp)) && (ok || !reflect.DeepEqual(v, sourceImageEncryptionKeyProp)) { |
| obj["sourceImageEncryptionKey"] = sourceImageEncryptionKeyProp |
| } |
| diskEncryptionKeyProp, err := expandComputeDiskDiskEncryptionKey(d.Get("disk_encryption_key"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("disk_encryption_key"); !tpgresource.IsEmptyValue(reflect.ValueOf(diskEncryptionKeyProp)) && (ok || !reflect.DeepEqual(v, diskEncryptionKeyProp)) { |
| obj["diskEncryptionKey"] = diskEncryptionKeyProp |
| } |
| sourceSnapshotProp, err := expandComputeDiskSnapshot(d.Get("snapshot"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("snapshot"); !tpgresource.IsEmptyValue(reflect.ValueOf(sourceSnapshotProp)) && (ok || !reflect.DeepEqual(v, sourceSnapshotProp)) { |
| obj["sourceSnapshot"] = sourceSnapshotProp |
| } |
| sourceSnapshotEncryptionKeyProp, err := expandComputeDiskSourceSnapshotEncryptionKey(d.Get("source_snapshot_encryption_key"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("source_snapshot_encryption_key"); !tpgresource.IsEmptyValue(reflect.ValueOf(sourceSnapshotEncryptionKeyProp)) && (ok || !reflect.DeepEqual(v, sourceSnapshotEncryptionKeyProp)) { |
| obj["sourceSnapshotEncryptionKey"] = sourceSnapshotEncryptionKeyProp |
| } |
| |
| obj, err = resourceComputeDiskEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks") |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Creating new Disk: %#v", obj) |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for Disk: %s", err) |
| } |
| billingProject = project |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| headers := make(http.Header) |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "POST", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutCreate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error creating Disk: %s", err) |
| } |
| |
| // Store the ID now |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/zones/{{zone}}/disks/{{name}}") |
| if err != nil { |
| return fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Creating Disk", userAgent, |
| d.Timeout(schema.TimeoutCreate)) |
| |
| if err != nil { |
| // The resource didn't actually create |
| d.SetId("") |
| return fmt.Errorf("Error waiting to create Disk: %s", err) |
| } |
| |
| log.Printf("[DEBUG] Finished creating Disk %q: %#v", d.Id(), res) |
| |
| return resourceComputeDiskRead(d, meta) |
| } |
| |
| func resourceComputeDiskRead(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for Disk: %s", err) |
| } |
| billingProject = project |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| headers := make(http.Header) |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "GET", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Headers: headers, |
| }) |
| if err != nil { |
| return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("ComputeDisk %q", d.Id())) |
| } |
| |
| res, err = resourceComputeDiskDecoder(d, meta, res) |
| if err != nil { |
| return err |
| } |
| |
| if res == nil { |
| // Decoding the object has resulted in it being gone. It may be marked deleted |
| log.Printf("[DEBUG] Removing ComputeDisk because it no longer exists.") |
| d.SetId("") |
| return nil |
| } |
| |
| if err := d.Set("project", project); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| |
| if err := d.Set("label_fingerprint", flattenComputeDiskLabelFingerprint(res["labelFingerprint"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("creation_timestamp", flattenComputeDiskCreationTimestamp(res["creationTimestamp"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("description", flattenComputeDiskDescription(res["description"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("last_attach_timestamp", flattenComputeDiskLastAttachTimestamp(res["lastAttachTimestamp"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("last_detach_timestamp", flattenComputeDiskLastDetachTimestamp(res["lastDetachTimestamp"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("labels", flattenComputeDiskLabels(res["labels"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("name", flattenComputeDiskName(res["name"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("size", flattenComputeDiskSize(res["sizeGb"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("users", flattenComputeDiskUsers(res["users"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("physical_block_size_bytes", flattenComputeDiskPhysicalBlockSizeBytes(res["physicalBlockSizeBytes"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_disk", flattenComputeDiskSourceDisk(res["sourceDisk"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_disk_id", flattenComputeDiskSourceDiskId(res["sourceDiskId"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("disk_id", flattenComputeDiskDiskId(res["id"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("type", flattenComputeDiskType(res["type"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("image", flattenComputeDiskImage(res["sourceImage"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("resource_policies", flattenComputeDiskResourcePolicies(res["resourcePolicies"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("enable_confidential_compute", flattenComputeDiskEnableConfidentialCompute(res["enableConfidentialCompute"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("multi_writer", flattenComputeDiskMultiWriter(res["multiWriter"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("provisioned_iops", flattenComputeDiskProvisionedIops(res["provisionedIops"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("provisioned_throughput", flattenComputeDiskProvisionedThroughput(res["provisionedThroughput"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("async_primary_disk", flattenComputeDiskAsyncPrimaryDisk(res["asyncPrimaryDisk"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("guest_os_features", flattenComputeDiskGuestOsFeatures(res["guestOsFeatures"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("licenses", flattenComputeDiskLicenses(res["licenses"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("storage_pool", flattenComputeDiskStoragePool(res["storagePool"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("access_mode", flattenComputeDiskAccessMode(res["accessMode"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("terraform_labels", flattenComputeDiskTerraformLabels(res["labels"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("effective_labels", flattenComputeDiskEffectiveLabels(res["labels"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("zone", flattenComputeDiskZone(res["zone"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_image_encryption_key", flattenComputeDiskSourceImageEncryptionKey(res["sourceImageEncryptionKey"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_image_id", flattenComputeDiskSourceImageId(res["sourceImageId"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("disk_encryption_key", flattenComputeDiskDiskEncryptionKey(res["diskEncryptionKey"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("snapshot", flattenComputeDiskSnapshot(res["sourceSnapshot"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_snapshot_encryption_key", flattenComputeDiskSourceSnapshotEncryptionKey(res["sourceSnapshotEncryptionKey"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("source_snapshot_id", flattenComputeDiskSourceSnapshotId(res["sourceSnapshotId"], d, config)); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { |
| return fmt.Errorf("Error reading Disk: %s", err) |
| } |
| |
| return nil |
| } |
| |
| func resourceComputeDiskUpdate(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for Disk: %s", err) |
| } |
| billingProject = project |
| |
| d.Partial(true) |
| |
| if d.HasChange("label_fingerprint") || d.HasChange("effective_labels") { |
| obj := make(map[string]interface{}) |
| |
| labelFingerprintProp, err := expandComputeDiskLabelFingerprint(d.Get("label_fingerprint"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("label_fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelFingerprintProp)) { |
| obj["labelFingerprint"] = labelFingerprintProp |
| } |
| labelsProp, err := expandComputeDiskEffectiveLabels(d.Get("effective_labels"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { |
| obj["labels"] = labelsProp |
| } |
| |
| obj, err = resourceComputeDiskUpdateEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}/setLabels") |
| if err != nil { |
| return err |
| } |
| |
| headers := make(http.Header) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "POST", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating Disk %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating Disk %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating Disk", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| if d.HasChange("size") { |
| obj := make(map[string]interface{}) |
| |
| sizeGbProp, err := expandComputeDiskSize(d.Get("size"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("size"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sizeGbProp)) { |
| obj["sizeGb"] = sizeGbProp |
| } |
| |
| obj, err = resourceComputeDiskUpdateEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}/resize") |
| if err != nil { |
| return err |
| } |
| |
| headers := make(http.Header) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "POST", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating Disk %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating Disk %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating Disk", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| if d.HasChange("provisioned_iops") { |
| obj := make(map[string]interface{}) |
| |
| provisionedIopsProp, err := expandComputeDiskProvisionedIops(d.Get("provisioned_iops"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("provisioned_iops"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, provisionedIopsProp)) { |
| obj["provisionedIops"] = provisionedIopsProp |
| } |
| |
| obj, err = resourceComputeDiskUpdateEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}?paths=provisionedIops") |
| if err != nil { |
| return err |
| } |
| |
| headers := make(http.Header) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "PATCH", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating Disk %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating Disk %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating Disk", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| if d.HasChange("provisioned_throughput") { |
| obj := make(map[string]interface{}) |
| |
| provisionedThroughputProp, err := expandComputeDiskProvisionedThroughput(d.Get("provisioned_throughput"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("provisioned_throughput"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, provisionedThroughputProp)) { |
| obj["provisionedThroughput"] = provisionedThroughputProp |
| } |
| |
| obj, err = resourceComputeDiskUpdateEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}?paths=provisionedThroughput") |
| if err != nil { |
| return err |
| } |
| |
| headers := make(http.Header) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "PATCH", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating Disk %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating Disk %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating Disk", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| if d.HasChange("access_mode") { |
| obj := make(map[string]interface{}) |
| |
| accessModeProp, err := expandComputeDiskAccessMode(d.Get("access_mode"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("access_mode"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, accessModeProp)) { |
| obj["accessMode"] = accessModeProp |
| } |
| |
| obj, err = resourceComputeDiskUpdateEncoder(d, meta, obj) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}?paths=accessMode") |
| if err != nil { |
| return err |
| } |
| |
| headers := make(http.Header) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "PATCH", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| Headers: headers, |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating Disk %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating Disk %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating Disk", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| |
| d.Partial(false) |
| |
| return resourceComputeDiskRead(d, meta) |
| } |
| |
| func resourceComputeDiskDelete(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for Disk: %s", err) |
| } |
| billingProject = project |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/disks/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| var obj map[string]interface{} |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| headers := make(http.Header) |
| readRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "GET", |
| Project: project, |
| RawURL: url, |
| UserAgent: userAgent, |
| }) |
| if err != nil { |
| return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("ComputeDisk %q", d.Id())) |
| } |
| |
| // if disks are attached to instances, they must be detached before the disk can be deleted |
| if v, ok := readRes["users"].([]interface{}); ok { |
| type detachArgs struct{ project, zone, instance, deviceName string } |
| var detachCalls []detachArgs |
| |
| for _, instance := range tpgresource.ConvertStringArr(v) { |
| self := d.Get("self_link").(string) |
| instanceProject, instanceZone, instanceName, err := tpgresource.GetLocationalResourcePropertiesFromSelfLinkString(instance) |
| if err != nil { |
| return err |
| } |
| |
| i, err := config.NewComputeClient(userAgent).Instances.Get(instanceProject, instanceZone, instanceName).Do() |
| if err != nil { |
| if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { |
| log.Printf("[WARN] instance %q not found, not bothering to detach disks", instance) |
| continue |
| } |
| return fmt.Errorf("Error retrieving instance %s: %s", instance, err.Error()) |
| } |
| for _, disk := range i.Disks { |
| if tpgresource.CompareSelfLinkOrResourceName("", disk.Source, self, nil) { |
| detachCalls = append(detachCalls, detachArgs{ |
| project: instanceProject, |
| zone: tpgresource.GetResourceNameFromSelfLink(i.Zone), |
| instance: i.Name, |
| deviceName: disk.DeviceName, |
| }) |
| } |
| } |
| } |
| |
| for _, call := range detachCalls { |
| op, err := config.NewComputeClient(userAgent).Instances.DetachDisk(call.project, call.zone, call.instance, call.deviceName).Do() |
| if err != nil { |
| return fmt.Errorf("Error detaching disk %s from instance %s/%s/%s: %s", call.deviceName, call.project, |
| call.zone, call.instance, err.Error()) |
| } |
| err = ComputeOperationWaitTime(config, op, call.project, |
| fmt.Sprintf("Detaching disk from %s/%s/%s", call.project, call.zone, call.instance), userAgent, d.Timeout(schema.TimeoutDelete)) |
| if err != nil { |
| var opErr ComputeOperationError |
| if errors.As(err, &opErr) && len(opErr.Errors) == 1 && opErr.Errors[0].Code == "RESOURCE_NOT_FOUND" { |
| log.Printf("[WARN] instance %q was deleted while awaiting detach", call.instance) |
| continue |
| } |
| return err |
| } |
| } |
| } |
| |
| log.Printf("[DEBUG] Deleting Disk %q", d.Id()) |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "DELETE", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutDelete), |
| Headers: headers, |
| }) |
| if err != nil { |
| return transport_tpg.HandleNotFoundError(err, d, "Disk") |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Deleting Disk", userAgent, |
| d.Timeout(schema.TimeoutDelete)) |
| |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Finished deleting Disk %q: %#v", d.Id(), res) |
| return nil |
| } |
| |
| func resourceComputeDiskImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { |
| config := meta.(*transport_tpg.Config) |
| if err := tpgresource.ParseImportId([]string{ |
| "^projects/(?P<project>[^/]+)/zones/(?P<zone>[^/]+)/disks/(?P<name>[^/]+)$", |
| "^(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<zone>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<name>[^/]+)$", |
| }, d, config); err != nil { |
| return nil, err |
| } |
| |
| // Replace import id for the resource id |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/zones/{{zone}}/disks/{{name}}") |
| if err != nil { |
| return nil, fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| return []*schema.ResourceData{d}, nil |
| } |
| |
| func flattenComputeDiskLabelFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskCreationTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskLastAttachTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskLastDetachTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| |
| transformed := make(map[string]interface{}) |
| if l, ok := d.GetOkExists("labels"); ok { |
| for k := range l.(map[string]interface{}) { |
| transformed[k] = v.(map[string]interface{})[k] |
| } |
| } |
| |
| return transformed |
| } |
| |
| func flattenComputeDiskName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSize(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeDiskUsers(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.ConvertAndMapStringArr(v.([]interface{}), tpgresource.ConvertSelfLinkToV1) |
| } |
| |
| func flattenComputeDiskPhysicalBlockSizeBytes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeDiskSourceDisk(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceDiskId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.NameFromSelfLinkStateFunc(v) |
| } |
| |
| func flattenComputeDiskImage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskResourcePolicies(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.ConvertAndMapStringArr(v.([]interface{}), tpgresource.ConvertSelfLinkToV1) |
| } |
| |
| func flattenComputeDiskEnableConfidentialCompute(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskMultiWriter(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskProvisionedIops(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeDiskProvisionedThroughput(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeDiskAsyncPrimaryDisk(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["disk"] = |
| flattenComputeDiskAsyncPrimaryDiskDisk(original["disk"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeDiskAsyncPrimaryDiskDisk(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskGuestOsFeatures(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| l := v.([]interface{}) |
| transformed := schema.NewSet(schema.HashResource(computeDiskGuestOsFeaturesSchema()), []interface{}{}) |
| for _, raw := range l { |
| original := raw.(map[string]interface{}) |
| if len(original) < 1 { |
| // Do not include empty json objects coming back from the api |
| continue |
| } |
| transformed.Add(map[string]interface{}{ |
| "type": flattenComputeDiskGuestOsFeaturesType(original["type"], d, config), |
| }) |
| } |
| return transformed |
| } |
| func flattenComputeDiskGuestOsFeaturesType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskLicenses(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.ConvertAndMapStringArr(v.([]interface{}), tpgresource.ConvertSelfLinkToV1) |
| } |
| |
| func flattenComputeDiskStoragePool(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.NameFromSelfLinkStateFunc(v) |
| } |
| |
| func flattenComputeDiskAccessMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| |
| transformed := make(map[string]interface{}) |
| if l, ok := d.GetOkExists("terraform_labels"); ok { |
| for k := range l.(map[string]interface{}) { |
| transformed[k] = v.(map[string]interface{})[k] |
| } |
| } |
| |
| return transformed |
| } |
| |
| func flattenComputeDiskEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskZone(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.NameFromSelfLinkStateFunc(v) |
| } |
| |
| func flattenComputeDiskSourceImageEncryptionKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["raw_key"] = |
| flattenComputeDiskSourceImageEncryptionKeyRawKey(original["rawKey"], d, config) |
| transformed["sha256"] = |
| flattenComputeDiskSourceImageEncryptionKeySha256(original["sha256"], d, config) |
| transformed["kms_key_self_link"] = |
| flattenComputeDiskSourceImageEncryptionKeyKmsKeySelfLink(original["kmsKeyName"], d, config) |
| transformed["kms_key_service_account"] = |
| flattenComputeDiskSourceImageEncryptionKeyKmsKeyServiceAccount(original["kmsKeyServiceAccount"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeDiskSourceImageEncryptionKeyRawKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceImageEncryptionKeySha256(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceImageEncryptionKeyKmsKeySelfLink(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceImageEncryptionKeyKmsKeyServiceAccount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceImageId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskEncryptionKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["raw_key"] = |
| flattenComputeDiskDiskEncryptionKeyRawKey(original["rawKey"], d, config) |
| transformed["rsa_encrypted_key"] = |
| flattenComputeDiskDiskEncryptionKeyRsaEncryptedKey(original["rsaEncryptedKey"], d, config) |
| transformed["sha256"] = |
| flattenComputeDiskDiskEncryptionKeySha256(original["sha256"], d, config) |
| transformed["kms_key_self_link"] = |
| flattenComputeDiskDiskEncryptionKeyKmsKeySelfLink(original["kmsKeyName"], d, config) |
| transformed["kms_key_service_account"] = |
| flattenComputeDiskDiskEncryptionKeyKmsKeyServiceAccount(original["kmsKeyServiceAccount"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeDiskDiskEncryptionKeyRawKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskEncryptionKeyRsaEncryptedKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskEncryptionKeySha256(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskEncryptionKeyKmsKeySelfLink(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskDiskEncryptionKeyKmsKeyServiceAccount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSnapshot(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.ConvertSelfLinkToV1(v.(string)) |
| } |
| |
| func flattenComputeDiskSourceSnapshotEncryptionKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["raw_key"] = |
| flattenComputeDiskSourceSnapshotEncryptionKeyRawKey(original["rawKey"], d, config) |
| transformed["kms_key_self_link"] = |
| flattenComputeDiskSourceSnapshotEncryptionKeyKmsKeySelfLink(original["kmsKeyName"], d, config) |
| transformed["sha256"] = |
| flattenComputeDiskSourceSnapshotEncryptionKeySha256(original["sha256"], d, config) |
| transformed["kms_key_service_account"] = |
| flattenComputeDiskSourceSnapshotEncryptionKeyKmsKeyServiceAccount(original["kmsKeyServiceAccount"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeDiskSourceSnapshotEncryptionKeyRawKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceSnapshotEncryptionKeyKmsKeySelfLink(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceSnapshotEncryptionKeySha256(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceSnapshotEncryptionKeyKmsKeyServiceAccount(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeDiskSourceSnapshotId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func expandComputeDiskLabelFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSize(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskPhysicalBlockSizeBytes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceDisk(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseZonalFieldValue("diskTypes", v.(string), "project", "zone", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for type: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |
| |
| func expandComputeDiskImage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskResourcePolicies(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| req := make([]interface{}, 0, len(l)) |
| for _, raw := range l { |
| if raw == nil { |
| return nil, fmt.Errorf("Invalid value for resource_policies: nil") |
| } |
| f, err := tpgresource.ParseRegionalFieldValue("resourcePolicies", raw.(string), "project", "region", "zone", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for resource_policies: %s", err) |
| } |
| req = append(req, f.RelativeLink()) |
| } |
| return req, nil |
| } |
| |
| func expandComputeDiskEnableConfidentialCompute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskMultiWriter(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskProvisionedIops(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskProvisionedThroughput(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskAsyncPrimaryDisk(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| if len(l) == 0 || l[0] == nil { |
| return nil, nil |
| } |
| raw := l[0] |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedDisk, err := expandComputeDiskAsyncPrimaryDiskDisk(original["disk"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedDisk); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["disk"] = transformedDisk |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeDiskAsyncPrimaryDiskDisk(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskGuestOsFeatures(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| v = v.(*schema.Set).List() |
| l := v.([]interface{}) |
| req := make([]interface{}, 0, len(l)) |
| for _, raw := range l { |
| if raw == nil { |
| continue |
| } |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedType, err := expandComputeDiskGuestOsFeaturesType(original["type"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedType); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["type"] = transformedType |
| } |
| |
| req = append(req, transformed) |
| } |
| return req, nil |
| } |
| |
| func expandComputeDiskGuestOsFeaturesType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskLicenses(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| req := make([]interface{}, 0, len(l)) |
| for _, raw := range l { |
| if raw == nil { |
| return nil, fmt.Errorf("Invalid value for licenses: nil") |
| } |
| f, err := tpgresource.ParseGlobalFieldValue("licenses", raw.(string), "project", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for licenses: %s", err) |
| } |
| req = append(req, f.RelativeLink()) |
| } |
| return req, nil |
| } |
| |
| func expandComputeDiskStoragePool(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskAccessMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { |
| if v == nil { |
| return map[string]string{}, nil |
| } |
| m := make(map[string]string) |
| for k, val := range v.(map[string]interface{}) { |
| m[k] = val.(string) |
| } |
| return m, nil |
| } |
| |
| func expandComputeDiskZone(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseGlobalFieldValue("zones", v.(string), "project", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for zone: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |
| |
| func expandComputeDiskSourceImageEncryptionKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| if len(l) == 0 || l[0] == nil { |
| return nil, nil |
| } |
| raw := l[0] |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedRawKey, err := expandComputeDiskSourceImageEncryptionKeyRawKey(original["raw_key"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedRawKey); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["rawKey"] = transformedRawKey |
| } |
| |
| transformedSha256, err := expandComputeDiskSourceImageEncryptionKeySha256(original["sha256"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedSha256); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["sha256"] = transformedSha256 |
| } |
| |
| transformedKmsKeySelfLink, err := expandComputeDiskSourceImageEncryptionKeyKmsKeySelfLink(original["kms_key_self_link"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeySelfLink); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyName"] = transformedKmsKeySelfLink |
| } |
| |
| transformedKmsKeyServiceAccount, err := expandComputeDiskSourceImageEncryptionKeyKmsKeyServiceAccount(original["kms_key_service_account"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeyServiceAccount); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyServiceAccount"] = transformedKmsKeyServiceAccount |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeDiskSourceImageEncryptionKeyRawKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceImageEncryptionKeySha256(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceImageEncryptionKeyKmsKeySelfLink(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceImageEncryptionKeyKmsKeyServiceAccount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| if len(l) == 0 || l[0] == nil { |
| return nil, nil |
| } |
| raw := l[0] |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedRawKey, err := expandComputeDiskDiskEncryptionKeyRawKey(original["raw_key"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedRawKey); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["rawKey"] = transformedRawKey |
| } |
| |
| transformedRsaEncryptedKey, err := expandComputeDiskDiskEncryptionKeyRsaEncryptedKey(original["rsa_encrypted_key"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedRsaEncryptedKey); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["rsaEncryptedKey"] = transformedRsaEncryptedKey |
| } |
| |
| transformedSha256, err := expandComputeDiskDiskEncryptionKeySha256(original["sha256"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedSha256); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["sha256"] = transformedSha256 |
| } |
| |
| transformedKmsKeySelfLink, err := expandComputeDiskDiskEncryptionKeyKmsKeySelfLink(original["kms_key_self_link"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeySelfLink); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyName"] = transformedKmsKeySelfLink |
| } |
| |
| transformedKmsKeyServiceAccount, err := expandComputeDiskDiskEncryptionKeyKmsKeyServiceAccount(original["kms_key_service_account"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeyServiceAccount); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyServiceAccount"] = transformedKmsKeyServiceAccount |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKeyRawKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKeyRsaEncryptedKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKeySha256(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKeyKmsKeySelfLink(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskDiskEncryptionKeyKmsKeyServiceAccount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSnapshot(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseGlobalFieldValue("snapshots", v.(string), "project", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for snapshot: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |
| |
| func expandComputeDiskSourceSnapshotEncryptionKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| if len(l) == 0 || l[0] == nil { |
| return nil, nil |
| } |
| raw := l[0] |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedRawKey, err := expandComputeDiskSourceSnapshotEncryptionKeyRawKey(original["raw_key"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedRawKey); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["rawKey"] = transformedRawKey |
| } |
| |
| transformedKmsKeySelfLink, err := expandComputeDiskSourceSnapshotEncryptionKeyKmsKeySelfLink(original["kms_key_self_link"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeySelfLink); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyName"] = transformedKmsKeySelfLink |
| } |
| |
| transformedSha256, err := expandComputeDiskSourceSnapshotEncryptionKeySha256(original["sha256"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedSha256); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["sha256"] = transformedSha256 |
| } |
| |
| transformedKmsKeyServiceAccount, err := expandComputeDiskSourceSnapshotEncryptionKeyKmsKeyServiceAccount(original["kms_key_service_account"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedKmsKeyServiceAccount); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["kmsKeyServiceAccount"] = transformedKmsKeyServiceAccount |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeDiskSourceSnapshotEncryptionKeyRawKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceSnapshotEncryptionKeyKmsKeySelfLink(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceSnapshotEncryptionKeySha256(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeDiskSourceSnapshotEncryptionKeyKmsKeyServiceAccount(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func resourceComputeDiskEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { |
| config := meta.(*transport_tpg.Config) |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return nil, err |
| } |
| |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return nil, err |
| } |
| |
| if v, ok := d.GetOk("type"); ok { |
| log.Printf("[DEBUG] Loading disk type: %s", v.(string)) |
| diskType, err := readDiskType(config, d, v.(string)) |
| if err != nil { |
| return nil, fmt.Errorf( |
| "Error loading disk type '%s': %s", |
| v.(string), err) |
| } |
| |
| obj["type"] = diskType.RelativeLink() |
| } |
| |
| if v, ok := d.GetOk("image"); ok { |
| log.Printf("[DEBUG] Resolving image name: %s", v.(string)) |
| imageUrl, err := ResolveImage(config, project, v.(string), userAgent) |
| if err != nil { |
| return nil, fmt.Errorf( |
| "Error resolving image name '%s': %s", |
| v.(string), err) |
| } |
| |
| obj["sourceImage"] = imageUrl |
| log.Printf("[DEBUG] Image name resolved to: %s", imageUrl) |
| } |
| |
| return obj, nil |
| } |
| |
| func resourceComputeDiskUpdateEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { |
| |
| if (d.HasChange("provisioned_iops") && strings.Contains(d.Get("type").(string), "hyperdisk")) || (d.HasChange("provisioned_throughput") && strings.Contains(d.Get("type").(string), "hyperdisk")) || (d.HasChange("access_mode") && strings.Contains(d.Get("type").(string), "hyperdisk")) { |
| nameProp := d.Get("name") |
| if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { |
| obj["name"] = nameProp |
| } |
| } |
| return obj, nil |
| } |
| |
| func resourceComputeDiskDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { |
| if v, ok := res["diskEncryptionKey"]; ok { |
| original := v.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| // The raw key won't be returned, so we need to use the original. |
| transformed["rawKey"] = d.Get("disk_encryption_key.0.raw_key") |
| transformed["rsaEncryptedKey"] = d.Get("disk_encryption_key.0.rsa_encrypted_key") |
| transformed["sha256"] = original["sha256"] |
| |
| if kmsKeyName, ok := original["kmsKeyName"]; ok { |
| // The response for crypto keys often includes the version of the key which needs to be removed |
| // format: projects/<project>/locations/<region>/keyRings/<keyring>/cryptoKeys/<key>/cryptoKeyVersions/1 |
| transformed["kmsKeyName"] = strings.Split(kmsKeyName.(string), "/cryptoKeyVersions")[0] |
| } |
| |
| if kmsKeyServiceAccount, ok := original["kmsKeyServiceAccount"]; ok { |
| transformed["kmsKeyServiceAccount"] = kmsKeyServiceAccount |
| } |
| |
| res["diskEncryptionKey"] = transformed |
| } |
| |
| if v, ok := res["sourceImageEncryptionKey"]; ok { |
| original := v.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| // The raw key won't be returned, so we need to use the original. |
| transformed["rawKey"] = d.Get("source_image_encryption_key.0.raw_key") |
| transformed["sha256"] = original["sha256"] |
| |
| if kmsKeyName, ok := original["kmsKeyName"]; ok { |
| // The response for crypto keys often includes the version of the key which needs to be removed |
| // format: projects/<project>/locations/<region>/keyRings/<keyring>/cryptoKeys/<key>/cryptoKeyVersions/1 |
| transformed["kmsKeyName"] = strings.Split(kmsKeyName.(string), "/cryptoKeyVersions")[0] |
| } |
| |
| if kmsKeyServiceAccount, ok := original["kmsKeyServiceAccount"]; ok { |
| transformed["kmsKeyServiceAccount"] = kmsKeyServiceAccount |
| } |
| |
| res["sourceImageEncryptionKey"] = transformed |
| } |
| |
| if v, ok := res["sourceSnapshotEncryptionKey"]; ok { |
| original := v.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| // The raw key won't be returned, so we need to use the original. |
| transformed["rawKey"] = d.Get("source_snapshot_encryption_key.0.raw_key") |
| transformed["sha256"] = original["sha256"] |
| |
| if kmsKeyName, ok := original["kmsKeyName"]; ok { |
| // The response for crypto keys often includes the version of the key which needs to be removed |
| // format: projects/<project>/locations/<region>/keyRings/<keyring>/cryptoKeys/<key>/cryptoKeyVersions/1 |
| transformed["kmsKeyName"] = strings.Split(kmsKeyName.(string), "/cryptoKeyVersions")[0] |
| } |
| |
| if kmsKeyServiceAccount, ok := original["kmsKeyServiceAccount"]; ok { |
| transformed["kmsKeyServiceAccount"] = kmsKeyServiceAccount |
| } |
| |
| res["sourceSnapshotEncryptionKey"] = transformed |
| } |
| |
| return res, nil |
| } |