Merge pull request #892 from sparkprime/gcp_image
Allow specifying project or full URL when specifying image
This commit is contained in:
commit
a880368d8e
|
@ -1,44 +1,75 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/google-api-go-client/compute/v1"
|
||||
)
|
||||
|
||||
// readImage finds the image with the given name.
|
||||
func readImage(c *Config, name string) (*compute.Image, error) {
|
||||
// First, always try ourselves first.
|
||||
image, err := c.clientCompute.Images.Get(c.Project, name).Do()
|
||||
if err == nil && image != nil && image.SelfLink != "" {
|
||||
return image, nil
|
||||
}
|
||||
// If the given name is a URL, return it.
|
||||
// If it is of the form project/name, use that URL.
|
||||
// If it is of the form name then look in the configured project and then hosted image projects.
|
||||
func resolveImage(c *Config, name string) (string, error) {
|
||||
|
||||
// This is a map of names to the project name where a public image is
|
||||
// hosted. GCE doesn't have an API to simply look up an image without
|
||||
// a project so we do this jank thing.
|
||||
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",
|
||||
}
|
||||
|
||||
// If we match a lookup for an alternate project, then try that next.
|
||||
// If not, we return the error.
|
||||
var project string
|
||||
for k, v := range imageMap {
|
||||
if strings.Contains(name, k) {
|
||||
project = v
|
||||
break
|
||||
if strings.HasPrefix(name, "https://www.googleapis.com/compute/v1/") {
|
||||
return name, nil
|
||||
|
||||
} else {
|
||||
splitName := strings.Split(name, "/")
|
||||
if len(splitName) == 1 {
|
||||
|
||||
// Must infer the project name:
|
||||
|
||||
// First, try the configured project.
|
||||
image, err := c.clientCompute.Images.Get(c.Project, name).Do()
|
||||
if err == nil {
|
||||
return image.SelfLink, nil
|
||||
}
|
||||
|
||||
// If we match a lookup for an alternate project, then try that next.
|
||||
// If not, we return the original error.
|
||||
|
||||
// If the image name contains the left hand side, we use the project from the right hand
|
||||
// side.
|
||||
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 project string
|
||||
for k, v := range imageMap {
|
||||
if strings.Contains(name, k) {
|
||||
project = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if project == "" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// There was a match, but the image still may not exist, so check it:
|
||||
image, err = c.clientCompute.Images.Get(project, name).Do()
|
||||
if err == nil {
|
||||
return image.SelfLink, nil
|
||||
}
|
||||
|
||||
return "", err
|
||||
|
||||
} else if len(splitName) == 2 {
|
||||
image, err := c.clientCompute.Images.Get(splitName[0], splitName[1]).Do()
|
||||
if err == nil {
|
||||
return image.SelfLink, nil
|
||||
}
|
||||
return "", err
|
||||
|
||||
} else {
|
||||
return "", fmt.Errorf("Invalid image name, require URL, project/name, or just name: %s", name)
|
||||
}
|
||||
}
|
||||
if project == "" {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.clientCompute.Images.Get(project, name).Do()
|
||||
}
|
||||
|
|
|
@ -70,15 +70,15 @@ func resourceComputeDiskCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
|
||||
// If we were given a source image, load that.
|
||||
if v, ok := d.GetOk("image"); ok {
|
||||
log.Printf("[DEBUG] Loading image: %s", v.(string))
|
||||
image, err := readImage(config, v.(string))
|
||||
log.Printf("[DEBUG] Resolving image name: %s", v.(string))
|
||||
imageUrl, err := resolveImage(config, v.(string))
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error loading image '%s': %s",
|
||||
"Error resolving image name '%s': %s",
|
||||
v.(string), err)
|
||||
}
|
||||
|
||||
disk.SourceImage = image.SelfLink
|
||||
disk.SourceImage = imageUrl
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("type"); ok {
|
||||
|
|
|
@ -304,15 +304,17 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
|
|||
// Load up the image for this disk if specified
|
||||
if v, ok := d.GetOk(prefix + ".image"); ok {
|
||||
imageName := v.(string)
|
||||
image, err := readImage(config, imageName)
|
||||
|
||||
|
||||
imageUrl, err := resolveImage(config, imageName)
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error loading image '%s': %s",
|
||||
"Error resolving image name '%s': %s",
|
||||
imageName, err)
|
||||
}
|
||||
|
||||
disk.InitializeParams = &compute.AttachedDiskInitializeParams{
|
||||
SourceImage: image.SelfLink,
|
||||
SourceImage: imageUrl,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,50 @@ func TestAccComputeInstance_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccComputeInstance_basic2(t *testing.T) {
|
||||
var instance compute.Instance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeInstance_basic2,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeInstanceExists(
|
||||
"google_compute_instance.foobar", &instance),
|
||||
testAccCheckComputeInstanceTag(&instance, "foo"),
|
||||
testAccCheckComputeInstanceMetadata(&instance, "foo", "bar"),
|
||||
testAccCheckComputeInstanceDisk(&instance, "terraform-test", true, true),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeInstance_basic3(t *testing.T) {
|
||||
var instance compute.Instance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckComputeInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccComputeInstance_basic3,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeInstanceExists(
|
||||
"google_compute_instance.foobar", &instance),
|
||||
testAccCheckComputeInstanceTag(&instance, "foo"),
|
||||
testAccCheckComputeInstanceMetadata(&instance, "foo", "bar"),
|
||||
testAccCheckComputeInstanceDisk(&instance, "terraform-test", true, true),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccComputeInstance_IP(t *testing.T) {
|
||||
var instance compute.Instance
|
||||
|
||||
|
@ -345,6 +389,49 @@ resource "google_compute_instance" "foobar" {
|
|||
}
|
||||
}`
|
||||
|
||||
const testAccComputeInstance_basic2 = `
|
||||
resource "google_compute_instance" "foobar" {
|
||||
name = "terraform-test"
|
||||
machine_type = "n1-standard-1"
|
||||
zone = "us-central1-a"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
}`
|
||||
|
||||
const testAccComputeInstance_basic3 = `
|
||||
resource "google_compute_instance" "foobar" {
|
||||
name = "terraform-test"
|
||||
machine_type = "n1-standard-1"
|
||||
zone = "us-central1-a"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
image = "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140814"
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
}`
|
||||
|
||||
// Update metadata, tags, and network_interface
|
||||
const testAccComputeInstance_update = `
|
||||
resource "google_compute_instance" "foobar" {
|
||||
|
|
|
@ -30,7 +30,9 @@ The following arguments are supported:
|
|||
|
||||
* `zone` - (Required) The zone where this disk will be available.
|
||||
|
||||
* `image` - (Optional) The machine image to base this disk off of.
|
||||
* `image` - (Optional) The image from which to initialize this disk. Either the full URL, a
|
||||
contraction of the form "project/name", or just a name (in which case the current project is
|
||||
used).
|
||||
|
||||
* `size` - (Optional) The size of the image in gigabytes. If not specified,
|
||||
it will inherit the size of its base image.
|
||||
|
|
|
@ -84,8 +84,9 @@ The `disk` block supports:
|
|||
* `disk` - (Required if image not set) The name of the disk (such as
|
||||
those managed by `google_compute_disk`) to attach.
|
||||
|
||||
* `image` - (Required if disk not set) The name of the image to base
|
||||
this disk off of.
|
||||
* `image` - (Required if disk not set) The image from which to initialize this
|
||||
disk. Either the full URL, a contraction of the form "project/name", or just
|
||||
a name (in which case the current project is used).
|
||||
|
||||
* `auto_delete` - (Optional) Whether or not the disk should be auto-deleted.
|
||||
This defaults to true.
|
||||
|
|
Loading…
Reference in New Issue