github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/openstack/data_source_openstack_images_image_v2.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "sort" 7 8 "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" 9 "github.com/gophercloud/gophercloud/pagination" 10 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 func dataSourceImagesImageV2() *schema.Resource { 15 return &schema.Resource{ 16 Read: dataSourceImagesImageV2Read, 17 18 Schema: map[string]*schema.Schema{ 19 "region": &schema.Schema{ 20 Type: schema.TypeString, 21 Required: true, 22 ForceNew: true, 23 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 24 }, 25 26 "name": { 27 Type: schema.TypeString, 28 Optional: true, 29 ForceNew: true, 30 }, 31 32 "visibility": { 33 Type: schema.TypeString, 34 Optional: true, 35 ForceNew: true, 36 }, 37 38 "owner": { 39 Type: schema.TypeString, 40 Optional: true, 41 ForceNew: true, 42 }, 43 44 "size_min": { 45 Type: schema.TypeInt, 46 Optional: true, 47 ForceNew: true, 48 }, 49 50 "size_max": { 51 Type: schema.TypeInt, 52 Optional: true, 53 ForceNew: true, 54 }, 55 56 "sort_key": { 57 Type: schema.TypeString, 58 Optional: true, 59 ForceNew: true, 60 Default: "name", 61 }, 62 63 "sort_direction": { 64 Type: schema.TypeString, 65 Optional: true, 66 ForceNew: true, 67 Default: "asc", 68 ValidateFunc: dataSourceImagesImageV2SortDirection, 69 }, 70 71 "tag": { 72 Type: schema.TypeString, 73 Optional: true, 74 ForceNew: true, 75 }, 76 77 "most_recent": { 78 Type: schema.TypeBool, 79 Optional: true, 80 Default: false, 81 ForceNew: true, 82 }, 83 84 // Computed values 85 "container_format": { 86 Type: schema.TypeString, 87 Computed: true, 88 }, 89 90 "disk_format": { 91 Type: schema.TypeString, 92 Computed: true, 93 }, 94 95 "min_disk_gb": { 96 Type: schema.TypeInt, 97 Computed: true, 98 }, 99 100 "min_ram_mb": { 101 Type: schema.TypeInt, 102 Computed: true, 103 }, 104 105 "protected": { 106 Type: schema.TypeBool, 107 Computed: true, 108 }, 109 110 "checksum": { 111 Type: schema.TypeString, 112 Computed: true, 113 }, 114 115 "size_bytes": { 116 Type: schema.TypeInt, 117 Computed: true, 118 }, 119 120 "metadata": { 121 Type: schema.TypeMap, 122 Computed: true, 123 }, 124 125 "updated_at": { 126 Type: schema.TypeString, 127 Computed: true, 128 }, 129 130 "file": { 131 Type: schema.TypeString, 132 Computed: true, 133 }, 134 135 "schema": { 136 Type: schema.TypeString, 137 Computed: true, 138 }, 139 }, 140 } 141 } 142 143 // dataSourceImagesImageV2Read performs the image lookup. 144 func dataSourceImagesImageV2Read(d *schema.ResourceData, meta interface{}) error { 145 config := meta.(*Config) 146 imageClient, err := config.imageV2Client(GetRegion(d)) 147 if err != nil { 148 return fmt.Errorf("Error creating OpenStack image client: %s", err) 149 } 150 151 visibility := resourceImagesImageV2VisibilityFromString(d.Get("visibility").(string)) 152 153 listOpts := images.ListOpts{ 154 Name: d.Get("name").(string), 155 Visibility: visibility, 156 Owner: d.Get("owner").(string), 157 Status: images.ImageStatusActive, 158 SizeMin: int64(d.Get("size_min").(int)), 159 SizeMax: int64(d.Get("size_max").(int)), 160 SortKey: d.Get("sort_key").(string), 161 SortDir: d.Get("sort_direction").(string), 162 Tag: d.Get("tag").(string), 163 } 164 165 var allImages []images.Image 166 pager := images.List(imageClient, listOpts) 167 err = pager.EachPage(func(page pagination.Page) (bool, error) { 168 images, err := images.ExtractImages(page) 169 if err != nil { 170 return false, err 171 } 172 173 for _, i := range images { 174 allImages = append(allImages, i) 175 } 176 177 return true, nil 178 }) 179 180 if err != nil { 181 return fmt.Errorf("Unable to retrieve images: %s", err) 182 } 183 184 var image images.Image 185 if len(allImages) < 1 { 186 return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") 187 } 188 189 if len(allImages) > 1 { 190 recent := d.Get("most_recent").(bool) 191 log.Printf("[DEBUG] openstack_images_image: multiple results found and `most_recent` is set to: %t", recent) 192 if recent { 193 image = mostRecentImage(allImages) 194 } else { 195 return fmt.Errorf("Your query returned more than one result. Please try a more " + 196 "specific search criteria, or set `most_recent` attribute to true.") 197 } 198 } else { 199 image = allImages[0] 200 } 201 202 log.Printf("[DEBUG] openstack_images_image: Single Image found: %s", image.ID) 203 return dataSourceImagesImageV2Attributes(d, &image) 204 } 205 206 // dataSourceImagesImageV2Attributes populates the fields of an Image resource. 207 func dataSourceImagesImageV2Attributes(d *schema.ResourceData, image *images.Image) error { 208 log.Printf("[DEBUG] openstack_images_image details: %#v", image) 209 210 d.SetId(image.ID) 211 d.Set("name", image.Name) 212 d.Set("tags", image.Tags) 213 d.Set("container_format", image.ContainerFormat) 214 d.Set("disk_format", image.DiskFormat) 215 d.Set("min_disk_gb", image.MinDiskGigabytes) 216 d.Set("min_ram_mb", image.MinRAMMegabytes) 217 d.Set("owner", image.Owner) 218 d.Set("protected", image.Protected) 219 d.Set("visibility", image.Visibility) 220 d.Set("checksum", image.Checksum) 221 d.Set("size_bytes", image.SizeBytes) 222 d.Set("metadata", image.Metadata) 223 d.Set("created_at", image.CreatedAt) 224 d.Set("updated_at", image.UpdatedAt) 225 d.Set("file", image.File) 226 d.Set("schema", image.Schema) 227 228 return nil 229 } 230 231 type imageSort []images.Image 232 233 func (a imageSort) Len() int { return len(a) } 234 func (a imageSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 235 func (a imageSort) Less(i, j int) bool { 236 itime := a[i].UpdatedAt 237 jtime := a[j].UpdatedAt 238 return itime.Unix() < jtime.Unix() 239 } 240 241 // Returns the most recent Image out of a slice of images. 242 func mostRecentImage(images []images.Image) images.Image { 243 sortedImages := images 244 sort.Sort(imageSort(sortedImages)) 245 return sortedImages[len(sortedImages)-1] 246 } 247 248 func dataSourceImagesImageV2SortDirection(v interface{}, k string) (ws []string, errors []error) { 249 value := v.(string) 250 if value != "asc" && value != "desc" { 251 err := fmt.Errorf("%s must be either asc or desc", k) 252 errors = append(errors, err) 253 } 254 return 255 }