Better DiffSuppressFunc for disk image field (#884)

* Proper DiffSuppress for disk image field

* Add support for more possible image format
This commit is contained in:
Vincent Roseberry 2017-12-21 10:00:35 -08:00 committed by GitHub
parent 68c4bdb5c6
commit bded8d19ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 252 additions and 16 deletions

View File

@ -15,8 +15,8 @@ const (
)
var (
resolveImageProjectImage = regexp.MustCompile(fmt.Sprintf("^projects/(%s)/global/images/(%s)$", resolveImageProjectRegex, resolveImageImageRegex))
resolveImageProjectFamily = regexp.MustCompile(fmt.Sprintf("^projects/(%s)/global/images/family/(%s)$", resolveImageProjectRegex, resolveImageFamilyRegex))
resolveImageProjectImage = regexp.MustCompile(fmt.Sprintf("projects/(%s)/global/images/(%s)$", resolveImageProjectRegex, resolveImageImageRegex))
resolveImageProjectFamily = regexp.MustCompile(fmt.Sprintf("projects/(%s)/global/images/family/(%s)$", resolveImageProjectRegex, resolveImageFamilyRegex))
resolveImageGlobalImage = regexp.MustCompile(fmt.Sprintf("^global/images/(%s)$", resolveImageImageRegex))
resolveImageGlobalFamily = regexp.MustCompile(fmt.Sprintf("^global/images/family/(%s)$", resolveImageFamilyRegex))
resolveImageFamilyFamily = regexp.MustCompile(fmt.Sprintf("^family/(%s)$", resolveImageFamilyRegex))
@ -24,9 +24,22 @@ var (
resolveImageProjectFamilyShorthand = regexp.MustCompile(fmt.Sprintf("^(%s)/(%s)$", resolveImageProjectRegex, resolveImageFamilyRegex))
resolveImageFamily = regexp.MustCompile(fmt.Sprintf("^(%s)$", resolveImageFamilyRegex))
resolveImageImage = regexp.MustCompile(fmt.Sprintf("^(%s)$", resolveImageImageRegex))
resolveImageLink = regexp.MustCompile(fmt.Sprintf("^https://www.googleapis.com/compute/v1/projects/(%s)/global/images/(%s)", resolveImageProjectRegex, resolveImageImageRegex))
resolveImageLink = regexp.MustCompile(fmt.Sprintf("^https://www.googleapis.com/compute/[a-z0-9]+/projects/(%s)/global/images/(%s)", resolveImageProjectRegex, resolveImageImageRegex))
)
// built-in projects to look for images/families containing the string
// on the left in
var imageMap = map[string]string{
"centos": "centos-cloud",
"coreos": "coreos-cloud",
"debian": "debian-cloud",
"opensuse": "opensuse-cloud",
"rhel": "rhel-cloud",
"sles": "suse-cloud",
"ubuntu": "ubuntu-os-cloud",
"windows": "windows-cloud",
}
func resolveImageImageExists(c *Config, project, name string) (bool, error) {
if _, err := c.clientCompute.Images.Get(project, name).Do(); err == nil {
return true, nil
@ -68,18 +81,6 @@ func sanityTestRegexMatches(expected int, got []string, regexType, name string)
// If not, check if it's a family in the current project. If it is, return it as global/images/family/{family}.
// If not, check if it could be a GCP-provided family, and if it exists. If it does, return it as projects/{project}/global/images/family/{family}
func resolveImage(c *Config, project, name string) (string, error) {
// built-in projects to look for images/families containing the string
// on the left in
imageMap := map[string]string{
"centos": "centos-cloud",
"coreos": "coreos-cloud",
"debian": "debian-cloud",
"opensuse": "opensuse-cloud",
"rhel": "rhel-cloud",
"sles": "suse-cloud",
"ubuntu": "ubuntu-os-cloud",
"windows": "windows-cloud",
}
var builtInProject string
for k, v := range imageMap {
if strings.Contains(name, k) {

View File

@ -65,7 +65,7 @@ func resourceComputeDisk() *schema.Resource {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
DiffSuppressFunc: linkDiffSuppress,
DiffSuppressFunc: diskImageDiffSuppress,
},
"project": &schema.Schema{
@ -407,3 +407,94 @@ func resourceComputeDiskDelete(d *schema.ResourceData, meta interface{}) error {
d.SetId("")
return nil
}
// 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 {
// '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, oldName, newProject, newFamilyName)
}
// Partial or full self link image
if resolveImageProjectImage.MatchString(new) {
// Value matches pattern "projects/{project}/global/images/{image-name}$"
// or "projects/{project}/global/images/{image-name-latest}$"
matches := resolveImageProjectImage.FindStringSubmatch(new)
newProject := matches[1]
newImageName := matches[2]
return diskImageProjectNameEquals(oldProject, oldName, newProject, 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 strings.Contains(oldName, familyName)
}
// Partial link without project image
if resolveImageGlobalImage.MatchString(new) {
// Value is "global/images/family/{image-name}" or "global/images/family/{image-name-latest}"
matches := resolveImageGlobalImage.FindStringSubmatch(new)
imageName := matches[1]
return strings.Contains(oldName, imageName)
}
// Family shorthand
if resolveImageFamilyFamily.MatchString(new) {
// Value is "family/{family-name}"
matches := resolveImageFamilyFamily.FindStringSubmatch(new)
familyName := matches[1]
return strings.Contains(oldName, familyName)
}
// Shorthand for image
if resolveImageProjectImageShorthand.MatchString(new) {
// Value is "{project}/{image-name}" or "{project}/{image-name-latest}"
matches := resolveImageProjectImageShorthand.FindStringSubmatch(new)
newProject := matches[1]
newName := matches[2]
return diskImageProjectNameEquals(oldProject, oldName, newProject, newName)
}
// Image or family only
if strings.Contains(oldName, new) {
// Value is "{image-name}" or "{family-name}" or "{image-name-latest}"
return true
}
return false
}
func diskImageProjectNameEquals(project1, name1, project2, name2 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 && strings.Contains(name1, name2)
}

View File

@ -12,6 +12,150 @@ import (
"google.golang.org/api/compute/v1"
)
func TestDiskImageDiffSuppress(t *testing.T) {
cases := map[string]struct {
Old, New string
ExpectDiffSuppress bool
}{
// Full & partial links
"matching self_link with different api version": {
Old: "https://www.googleapis.com/compute/beta/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
ExpectDiffSuppress: true,
},
"matching image partial self_link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "projects/debian-cloud/global/images/debian-8-jessie-v20171213",
ExpectDiffSuppress: true,
},
"matching image partial no project self_link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "global/images/debian-8-jessie-v20171213",
ExpectDiffSuppress: true,
},
"different image self_link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-jessie-v20171213",
ExpectDiffSuppress: false,
},
"different image partial self_link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "projects/debian-cloud/global/images/debian-7-jessie-v20171213",
ExpectDiffSuppress: false,
},
"different image partial no project self_link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "global/images/debian-7-jessie-v20171213",
ExpectDiffSuppress: false,
},
// Image name
"matching image name": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-8-jessie-v20171213",
ExpectDiffSuppress: true,
},
"different image name": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-7-jessie-v20171213",
ExpectDiffSuppress: false,
},
// Image short hand
"matching image short hand": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-cloud/debian-8-jessie-v20171213",
ExpectDiffSuppress: true,
},
"matching image short hand but different project": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "different-cloud/debian-8-jessie-v20171213",
ExpectDiffSuppress: false,
},
"different image short hand": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-cloud/debian-7-jessie-v20171213",
ExpectDiffSuppress: false,
},
// Latest image short hand
"matching latest image short hand": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-cloud/debian-8",
ExpectDiffSuppress: true,
},
"matching latest image short hand with project short name": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian/debian-8",
ExpectDiffSuppress: true,
},
"matching latest image short hand but different project": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "different-cloud/debian-8",
ExpectDiffSuppress: false,
},
"different latest image short hand": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "debian-cloud/debian-7",
ExpectDiffSuppress: false,
},
// Image Family
"matching image family": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "family/debian-8",
ExpectDiffSuppress: true,
},
"matching image family self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-8",
ExpectDiffSuppress: true,
},
"matching image family partial self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "projects/debian-cloud/global/images/family/debian-8",
ExpectDiffSuppress: true,
},
"matching image family partial no project self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "global/images/family/debian-8",
ExpectDiffSuppress: true,
},
"different image family": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "family/debian-7",
ExpectDiffSuppress: false,
},
"different image family self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-7",
ExpectDiffSuppress: false,
},
"different image family partial self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "projects/debian-cloud/global/images/family/debian-7",
ExpectDiffSuppress: false,
},
"different image family partial no project self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "global/images/family/debian-7",
ExpectDiffSuppress: false,
},
"matching image family but different project in self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "https://www.googleapis.com/compute/v1/projects/other-cloud/global/images/family/debian-8",
ExpectDiffSuppress: false,
},
"different image family but different project in partial self link": {
Old: "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20171213",
New: "projects/other-cloud/global/images/family/debian-8",
ExpectDiffSuppress: false,
},
}
for tn, tc := range cases {
if diskImageDiffSuppress("image", tc.Old, tc.New, nil) != tc.ExpectDiffSuppress {
t.Errorf("bad: %s, %q => %q expect DiffSuppress to return %t", tn, tc.Old, tc.New, tc.ExpectDiffSuppress)
}
}
}
func TestAccComputeDisk_basic(t *testing.T) {
t.Parallel()