256 lines
5.8 KiB
Go
256 lines
5.8 KiB
Go
|
package openstack
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"sort"
|
||
|
|
||
|
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
|
||
|
"github.com/gophercloud/gophercloud/pagination"
|
||
|
|
||
|
"github.com/hashicorp/terraform/helper/schema"
|
||
|
)
|
||
|
|
||
|
func dataSourceImagesImageV2() *schema.Resource {
|
||
|
return &schema.Resource{
|
||
|
Read: dataSourceImagesImageV2Read,
|
||
|
|
||
|
Schema: map[string]*schema.Schema{
|
||
|
"region": &schema.Schema{
|
||
|
Type: schema.TypeString,
|
||
|
Required: true,
|
||
|
ForceNew: true,
|
||
|
DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
|
||
|
},
|
||
|
|
||
|
"name": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"visibility": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"owner": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"size_min": {
|
||
|
Type: schema.TypeInt,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"size_max": {
|
||
|
Type: schema.TypeInt,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"sort_key": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
Default: "name",
|
||
|
},
|
||
|
|
||
|
"sort_direction": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
Default: "asc",
|
||
|
ValidateFunc: dataSourceImagesImageV2SortDirection,
|
||
|
},
|
||
|
|
||
|
"tag": {
|
||
|
Type: schema.TypeString,
|
||
|
Optional: true,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
"most_recent": {
|
||
|
Type: schema.TypeBool,
|
||
|
Optional: true,
|
||
|
Default: false,
|
||
|
ForceNew: true,
|
||
|
},
|
||
|
|
||
|
// Computed values
|
||
|
"container_format": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"disk_format": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"min_disk_gb": {
|
||
|
Type: schema.TypeInt,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"min_ram_mb": {
|
||
|
Type: schema.TypeInt,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"protected": {
|
||
|
Type: schema.TypeBool,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"checksum": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"size_bytes": {
|
||
|
Type: schema.TypeInt,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"metadata": {
|
||
|
Type: schema.TypeMap,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"updated_at": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"file": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
|
||
|
"schema": {
|
||
|
Type: schema.TypeString,
|
||
|
Computed: true,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// dataSourceImagesImageV2Read performs the image lookup.
|
||
|
func dataSourceImagesImageV2Read(d *schema.ResourceData, meta interface{}) error {
|
||
|
config := meta.(*Config)
|
||
|
imageClient, err := config.imageV2Client(GetRegion(d))
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Error creating OpenStack image client: %s", err)
|
||
|
}
|
||
|
|
||
|
visibility := resourceImagesImageV2VisibilityFromString(d.Get("visibility").(string))
|
||
|
|
||
|
listOpts := images.ListOpts{
|
||
|
Name: d.Get("name").(string),
|
||
|
Visibility: visibility,
|
||
|
Owner: d.Get("owner").(string),
|
||
|
Status: images.ImageStatusActive,
|
||
|
SizeMin: int64(d.Get("size_min").(int)),
|
||
|
SizeMax: int64(d.Get("size_max").(int)),
|
||
|
SortKey: d.Get("sort_key").(string),
|
||
|
SortDir: d.Get("sort_direction").(string),
|
||
|
Tag: d.Get("tag").(string),
|
||
|
}
|
||
|
|
||
|
var allImages []images.Image
|
||
|
pager := images.List(imageClient, listOpts)
|
||
|
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
||
|
images, err := images.ExtractImages(page)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
|
||
|
for _, i := range images {
|
||
|
allImages = append(allImages, i)
|
||
|
}
|
||
|
|
||
|
return true, nil
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("Unable to retrieve images: %s", err)
|
||
|
}
|
||
|
|
||
|
var image images.Image
|
||
|
if len(allImages) < 1 {
|
||
|
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
|
||
|
}
|
||
|
|
||
|
if len(allImages) > 1 {
|
||
|
recent := d.Get("most_recent").(bool)
|
||
|
log.Printf("[DEBUG] openstack_images_image: multiple results found and `most_recent` is set to: %t", recent)
|
||
|
if recent {
|
||
|
image = mostRecentImage(allImages)
|
||
|
} else {
|
||
|
return fmt.Errorf("Your query returned more than one result. Please try a more " +
|
||
|
"specific search criteria, or set `most_recent` attribute to true.")
|
||
|
}
|
||
|
} else {
|
||
|
image = allImages[0]
|
||
|
}
|
||
|
|
||
|
log.Printf("[DEBUG] openstack_images_image: Single Image found: %s", image.ID)
|
||
|
return dataSourceImagesImageV2Attributes(d, &image)
|
||
|
}
|
||
|
|
||
|
// dataSourceImagesImageV2Attributes populates the fields of an Image resource.
|
||
|
func dataSourceImagesImageV2Attributes(d *schema.ResourceData, image *images.Image) error {
|
||
|
log.Printf("[DEBUG] openstack_images_image details: %#v", image)
|
||
|
|
||
|
d.SetId(image.ID)
|
||
|
d.Set("name", image.Name)
|
||
|
d.Set("tags", image.Tags)
|
||
|
d.Set("container_format", image.ContainerFormat)
|
||
|
d.Set("disk_format", image.DiskFormat)
|
||
|
d.Set("min_disk_gb", image.MinDiskGigabytes)
|
||
|
d.Set("min_ram_mb", image.MinRAMMegabytes)
|
||
|
d.Set("owner", image.Owner)
|
||
|
d.Set("protected", image.Protected)
|
||
|
d.Set("visibility", image.Visibility)
|
||
|
d.Set("checksum", image.Checksum)
|
||
|
d.Set("size_bytes", image.SizeBytes)
|
||
|
d.Set("metadata", image.Metadata)
|
||
|
d.Set("created_at", image.CreatedAt)
|
||
|
d.Set("updated_at", image.UpdatedAt)
|
||
|
d.Set("file", image.File)
|
||
|
d.Set("schema", image.Schema)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type imageSort []images.Image
|
||
|
|
||
|
func (a imageSort) Len() int { return len(a) }
|
||
|
func (a imageSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||
|
func (a imageSort) Less(i, j int) bool {
|
||
|
itime := a[i].UpdatedAt
|
||
|
jtime := a[j].UpdatedAt
|
||
|
return itime.Unix() < jtime.Unix()
|
||
|
}
|
||
|
|
||
|
// Returns the most recent Image out of a slice of images.
|
||
|
func mostRecentImage(images []images.Image) images.Image {
|
||
|
sortedImages := images
|
||
|
sort.Sort(imageSort(sortedImages))
|
||
|
return sortedImages[len(sortedImages)-1]
|
||
|
}
|
||
|
|
||
|
func dataSourceImagesImageV2SortDirection(v interface{}, k string) (ws []string, errors []error) {
|
||
|
value := v.(string)
|
||
|
if value != "asc" && value != "desc" {
|
||
|
err := fmt.Errorf("%s must be either asc or desc", k)
|
||
|
errors = append(errors, err)
|
||
|
}
|
||
|
return
|
||
|
}
|