github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/image.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "regexp" 6 "strings" 7 8 "google.golang.org/api/googleapi" 9 ) 10 11 const ( 12 resolveImageProjectRegex = "[-_a-zA-Z0-9]*" 13 resolveImageFamilyRegex = "[-_a-zA-Z0-9]*" 14 resolveImageImageRegex = "[-_a-zA-Z0-9]*" 15 ) 16 17 var ( 18 resolveImageProjectImage = regexp.MustCompile(fmt.Sprintf("^projects/(%s)/global/images/(%s)$", resolveImageProjectRegex, resolveImageImageRegex)) 19 resolveImageProjectFamily = regexp.MustCompile(fmt.Sprintf("^projects/(%s)/global/images/family/(%s)$", resolveImageProjectRegex, resolveImageFamilyRegex)) 20 resolveImageGlobalImage = regexp.MustCompile(fmt.Sprintf("^global/images/(%s)$", resolveImageImageRegex)) 21 resolveImageGlobalFamily = regexp.MustCompile(fmt.Sprintf("^global/images/family/(%s)$", resolveImageFamilyRegex)) 22 resolveImageFamilyFamily = regexp.MustCompile(fmt.Sprintf("^family/(%s)$", resolveImageFamilyRegex)) 23 resolveImageProjectImageShorthand = regexp.MustCompile(fmt.Sprintf("^(%s)/(%s)$", resolveImageProjectRegex, resolveImageImageRegex)) 24 resolveImageProjectFamilyShorthand = regexp.MustCompile(fmt.Sprintf("^(%s)/(%s)$", resolveImageProjectRegex, resolveImageFamilyRegex)) 25 resolveImageFamily = regexp.MustCompile(fmt.Sprintf("^(%s)$", resolveImageFamilyRegex)) 26 resolveImageImage = regexp.MustCompile(fmt.Sprintf("^(%s)$", resolveImageImageRegex)) 27 resolveImageLink = regexp.MustCompile(fmt.Sprintf("^https://www.googleapis.com/compute/v1/projects/(%s)/global/images/(%s)", resolveImageProjectRegex, resolveImageImageRegex)) 28 ) 29 30 func resolveImageImageExists(c *Config, project, name string) (bool, error) { 31 if _, err := c.clientCompute.Images.Get(project, name).Do(); err == nil { 32 return true, nil 33 } else if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 34 return false, nil 35 } else { 36 return false, fmt.Errorf("Error checking if image %s exists: %s", name, err) 37 } 38 } 39 40 func resolveImageFamilyExists(c *Config, project, name string) (bool, error) { 41 if _, err := c.clientCompute.Images.GetFromFamily(project, name).Do(); err == nil { 42 return true, nil 43 } else if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 44 return false, nil 45 } else { 46 return false, fmt.Errorf("Error checking if family %s exists: %s", name, err) 47 } 48 } 49 50 func sanityTestRegexMatches(expected int, got []string, regexType, name string) error { 51 if len(got)-1 != expected { // subtract one, index zero is the entire matched expression 52 return fmt.Errorf("Expected %d %s regex matches, got %d for %s", expected, regexType, len(got)-1, name) 53 } 54 return nil 55 } 56 57 // If the given name is a URL, return it. 58 // If it's in the form projects/{project}/global/images/{image}, return it 59 // If it's in the form projects/{project}/global/images/family/{family}, return it 60 // If it's in the form global/images/{image}, return it 61 // If it's in the form global/images/family/{family}, return it 62 // If it's in the form family/{family}, check if it's a family in the current project. If it is, return it as global/images/family/{family}. 63 // 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}. 64 // If it's in the form {project}/{family-or-image}, check if it's an image in the named project. If it is, return it as projects/{project}/global/images/{image}. 65 // If not, check if it's a family in the named project. If it is, return it as projects/{project}/global/images/family/{family}. 66 // If it's in the form {family-or-image}, check if it's an image in the current project. If it is, return it as global/images/{image}. 67 // If not, check if it could be a GCP-provided image, and if it exists. If it does, return it as projects/{project}/global/images/{image}. 68 // If not, check if it's a family in the current project. If it is, return it as global/images/family/{family}. 69 // 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} 70 func resolveImage(c *Config, name string) (string, error) { 71 // built-in projects to look for images/families containing the string 72 // on the left in 73 imageMap := map[string]string{ 74 "centos": "centos-cloud", 75 "coreos": "coreos-cloud", 76 "debian": "debian-cloud", 77 "opensuse": "opensuse-cloud", 78 "rhel": "rhel-cloud", 79 "sles": "suse-cloud", 80 "ubuntu": "ubuntu-os-cloud", 81 "windows": "windows-cloud", 82 } 83 var builtInProject string 84 for k, v := range imageMap { 85 if strings.Contains(name, k) { 86 builtInProject = v 87 break 88 } 89 } 90 switch { 91 case resolveImageLink.MatchString(name): // https://www.googleapis.com/compute/v1/projects/xyz/global/images/xyz 92 return name, nil 93 case resolveImageProjectImage.MatchString(name): // projects/xyz/global/images/xyz 94 res := resolveImageProjectImage.FindStringSubmatch(name) 95 if err := sanityTestRegexMatches(2, res, "project image", name); err != nil { 96 return "", err 97 } 98 return fmt.Sprintf("projects/%s/global/images/%s", res[1], res[2]), nil 99 case resolveImageProjectFamily.MatchString(name): // projects/xyz/global/images/family/xyz 100 res := resolveImageProjectFamily.FindStringSubmatch(name) 101 if err := sanityTestRegexMatches(2, res, "project family", name); err != nil { 102 return "", err 103 } 104 return fmt.Sprintf("projects/%s/global/images/family/%s", res[1], res[2]), nil 105 case resolveImageGlobalImage.MatchString(name): // global/images/xyz 106 res := resolveImageGlobalImage.FindStringSubmatch(name) 107 if err := sanityTestRegexMatches(1, res, "global image", name); err != nil { 108 return "", err 109 } 110 return fmt.Sprintf("global/images/%s", res[1]), nil 111 case resolveImageGlobalFamily.MatchString(name): // global/images/family/xyz 112 res := resolveImageGlobalFamily.FindStringSubmatch(name) 113 if err := sanityTestRegexMatches(1, res, "global family", name); err != nil { 114 return "", err 115 } 116 return fmt.Sprintf("global/images/family/%s", res[1]), nil 117 case resolveImageFamilyFamily.MatchString(name): // family/xyz 118 res := resolveImageFamilyFamily.FindStringSubmatch(name) 119 if err := sanityTestRegexMatches(1, res, "family family", name); err != nil { 120 return "", err 121 } 122 if ok, err := resolveImageFamilyExists(c, c.Project, res[1]); err != nil { 123 return "", err 124 } else if ok { 125 return fmt.Sprintf("global/images/family/%s", res[1]), nil 126 } 127 if builtInProject != "" { 128 if ok, err := resolveImageFamilyExists(c, builtInProject, res[1]); err != nil { 129 return "", err 130 } else if ok { 131 return fmt.Sprintf("projects/%s/global/images/family/%s", builtInProject, res[1]), nil 132 } 133 } 134 case resolveImageProjectImageShorthand.MatchString(name): // xyz/xyz 135 res := resolveImageProjectImageShorthand.FindStringSubmatch(name) 136 if err := sanityTestRegexMatches(2, res, "project image shorthand", name); err != nil { 137 return "", err 138 } 139 if ok, err := resolveImageImageExists(c, res[1], res[2]); err != nil { 140 return "", err 141 } else if ok { 142 return fmt.Sprintf("projects/%s/global/images/%s", res[1], res[2]), nil 143 } 144 fallthrough // check if it's a family 145 case resolveImageProjectFamilyShorthand.MatchString(name): // xyz/xyz 146 res := resolveImageProjectFamilyShorthand.FindStringSubmatch(name) 147 if err := sanityTestRegexMatches(2, res, "project family shorthand", name); err != nil { 148 return "", err 149 } 150 if ok, err := resolveImageFamilyExists(c, res[1], res[2]); err != nil { 151 return "", err 152 } else if ok { 153 return fmt.Sprintf("projects/%s/global/images/family/%s", res[1], res[2]), nil 154 } 155 case resolveImageImage.MatchString(name): // xyz 156 res := resolveImageImage.FindStringSubmatch(name) 157 if err := sanityTestRegexMatches(1, res, "image", name); err != nil { 158 return "", err 159 } 160 if ok, err := resolveImageImageExists(c, c.Project, res[1]); err != nil { 161 return "", err 162 } else if ok { 163 return fmt.Sprintf("global/images/%s", res[1]), nil 164 } 165 if builtInProject != "" { 166 // check the images GCP provides 167 if ok, err := resolveImageImageExists(c, builtInProject, res[1]); err != nil { 168 return "", err 169 } else if ok { 170 return fmt.Sprintf("projects/%s/global/images/%s", builtInProject, res[1]), nil 171 } 172 } 173 fallthrough // check if the name is a family, instead of an image 174 case resolveImageFamily.MatchString(name): // xyz 175 res := resolveImageFamily.FindStringSubmatch(name) 176 if err := sanityTestRegexMatches(1, res, "family", name); err != nil { 177 return "", err 178 } 179 if ok, err := resolveImageFamilyExists(c, c.Project, res[1]); err != nil { 180 return "", err 181 } else if ok { 182 return fmt.Sprintf("global/images/family/%s", res[1]), nil 183 } 184 if builtInProject != "" { 185 // check the families GCP provides 186 if ok, err := resolveImageFamilyExists(c, builtInProject, res[1]); err != nil { 187 return "", err 188 } else if ok { 189 return fmt.Sprintf("projects/%s/global/images/family/%s", builtInProject, res[1]), nil 190 } 191 } 192 } 193 return "", fmt.Errorf("Could not find image or family %s", name) 194 }