tpgtools/ignored_handwritten/disk_utils.go (212 lines of code) (raw):
package google
import (
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
tpgcompute "github.com/hashicorp/terraform-provider-google/google/services/compute"
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
)
// Is the new disk size smaller than the old one?
func isDiskShrinkage(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 := tpgcompute.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
if strings.Contains(imageName, familyName) {
return true
}
if suppressCanonicalFamilyDiff(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) == 3 {
f := fmt.Sprintf("ubuntu-%s%s-lts", parts[1], parts[2])
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 expandComputeDiskType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) *string {
if v == "" {
return nil
}
f, err := tpgresource.ParseZonalFieldValue("diskTypes", v.(string), "project", "zone", d, config, true)
if err != nil {
return nil
}
rl := f.RelativeLink()
return &rl
}
func expandComputeDiskSourceImage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) *string {
if v == "" {
return nil
}
if v == nil {
return nil
}
project, err := tpgresource.GetProject(d, config)
if err != nil {
return nil
}
f, err := tpgcompute.ResolveImage(config, project, v.(string))
if err != nil {
return nil
}
return &f
}
func expandComputeDiskSnapshot(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) *string {
if v == "" {
return nil
}
f, err := tpgresource.ParseGlobalFieldValue("snapshots", v.(string), "project", d, config, true)
if err != nil {
return nil
}
rl := f.RelativeLink()
return &rl
}
func ConvertSelfLinkToV1UnlessNil(v interface{}) *string {
if v == nil {
return nil
}
vptr := v.(*string)
if vptr == nil {
return nil
}
val := ConvertSelfLinkToV1(*vptr)
return &val
}
func flattenComputeDiskSnapshot(v interface{}, d *schema.ResourceData, meta interface{}) *string {
config := meta.(*transport_tpg.Config)
if v == nil {
return nil
}
vptr := v.(*string)
if vptr == nil {
return nil
}
val, err := tpgresource.ParseGlobalFieldValue("snapshots", *vptr, "project", d, config, true)
if err != nil {
return nil
}
rl := val.RelativeLink()
return &rl
}
func flattenComputeDiskImage(v interface{}, d *schema.ResourceData, meta interface{}) *string {
config := meta.(*transport_tpg.Config)
if v == nil {
return nil
}
project, err := tpgresource.GetProject(d, config)
if err != nil {
return nil
}
vptr := v.(*string)
if vptr == nil {
return nil
}
f, err := tpgcompute.ResolveImage(config, project, *vptr)
if err != nil {
return nil
}
return &f
}