diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index d98ec1820..cafda7ef8 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -45,9 +45,11 @@ func testAccPreCheck(t *testing.T) { } OS_REGION_NAME = v - v = os.Getenv("OS_IMAGE_ID") - if v == "" { - t.Fatal("OS_IMAGE_ID must be set for acceptance tests") + v1 := os.Getenv("OS_IMAGE_ID") + v2 := os.Getenv("OS_IMAGE_NAME") + + if v1 == "" && v2 == "" { + t.Fatal("OS_IMAGE_ID or OS_IMAGE_NAME must be set for acceptance tests") } v = os.Getenv("OS_POOL_NAME") diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index a60279c3d..c56f86792 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -13,6 +13,7 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" + "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" "github.com/rackspace/gophercloud/openstack/networking/v2/networks" @@ -39,12 +40,18 @@ func resourceComputeInstanceV2() *schema.Resource { Required: true, ForceNew: false, }, - "image_ref": &schema.Schema{ + "image_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: false, + ForceNew: true, DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, + "image_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_IMAGE_NAME"), + }, "flavor_ref": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -165,9 +172,14 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e var createOpts servers.CreateOptsBuilder + imageId, err := getImageID(computeClient, d) + if err != nil { + return err + } + createOpts = &servers.CreateOpts{ Name: d.Get("name").(string), - ImageRef: d.Get("image_ref").(string), + ImageRef: imageId, FlavorRef: d.Get("flavor_ref").(string), SecurityGroups: resourceInstanceSecGroupsV2(d), AvailabilityZone: d.Get("availability_zone").(string), @@ -659,3 +671,36 @@ func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips. } return ips, nil } + +func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) { + imageID := d.Get("image_id").(string) + imageName := d.Get("image_name").(string) + if imageID == "" { + pager := images.ListDetail(client, nil) + + pager.EachPage(func(page pagination.Page) (bool, error) { + imageList, err := images.ExtractImages(page) + + if err != nil { + return false, err + } + + for _, i := range imageList { + if i.Name == imageName { + imageID = i.ID + } + } + return true, nil + }) + + if imageID == "" { + return "", fmt.Errorf("Unable to find image: %v", imageName) + } + } + + if imageID == "" && imageName == "" { + return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") + } + + return imageID, nil +}