github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/alicloud/data_source_alicloud_images.go (about) 1 package alicloud 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "sort" 8 "time" 9 10 "github.com/denverdino/aliyungo/ecs" 11 "github.com/hashicorp/terraform/helper/schema" 12 ) 13 14 func dataSourceAlicloudImages() *schema.Resource { 15 return &schema.Resource{ 16 Read: dataSourceAlicloudImagesRead, 17 18 Schema: map[string]*schema.Schema{ 19 "name_regex": { 20 Type: schema.TypeString, 21 Optional: true, 22 ForceNew: true, 23 ValidateFunc: validateNameRegex, 24 }, 25 "most_recent": { 26 Type: schema.TypeBool, 27 Optional: true, 28 Default: false, 29 ForceNew: true, 30 }, 31 "owners": { 32 Type: schema.TypeString, 33 Optional: true, 34 ForceNew: true, 35 ValidateFunc: validateImageOwners, 36 }, 37 // Computed values. 38 "images": { 39 Type: schema.TypeList, 40 Computed: true, 41 Elem: &schema.Resource{ 42 Schema: map[string]*schema.Schema{ 43 "id": { 44 Type: schema.TypeString, 45 Computed: true, 46 }, 47 "image_id": { 48 Type: schema.TypeString, 49 Computed: true, 50 }, 51 "architecture": { 52 Type: schema.TypeString, 53 Computed: true, 54 }, 55 "creation_time": { 56 Type: schema.TypeString, 57 Computed: true, 58 }, 59 "description": { 60 Type: schema.TypeString, 61 Computed: true, 62 }, 63 "image_owner_alias": { 64 Type: schema.TypeString, 65 Computed: true, 66 }, 67 "os_type": { 68 Type: schema.TypeString, 69 Computed: true, 70 }, 71 "os_name": { 72 Type: schema.TypeString, 73 Computed: true, 74 }, 75 "name": { 76 Type: schema.TypeString, 77 Computed: true, 78 }, 79 "platform": { 80 Type: schema.TypeString, 81 Computed: true, 82 }, 83 "status": { 84 Type: schema.TypeString, 85 Computed: true, 86 }, 87 "state": { 88 Type: schema.TypeString, 89 Computed: true, 90 }, 91 "size": { 92 Type: schema.TypeInt, 93 Computed: true, 94 }, 95 // Complex computed values 96 "disk_device_mappings": { 97 Type: schema.TypeList, 98 Computed: true, 99 //Set: imageDiskDeviceMappingHash, 100 Elem: &schema.Resource{ 101 Schema: map[string]*schema.Schema{ 102 "device": { 103 Type: schema.TypeString, 104 Computed: true, 105 }, 106 "size": { 107 Type: schema.TypeString, 108 Computed: true, 109 }, 110 "snapshot_id": { 111 Type: schema.TypeString, 112 Computed: true, 113 }, 114 }, 115 }, 116 }, 117 "product_code": { 118 Type: schema.TypeString, 119 Computed: true, 120 }, 121 "is_self_shared": { 122 Type: schema.TypeString, 123 Computed: true, 124 }, 125 "is_subscribed": { 126 Type: schema.TypeBool, 127 Computed: true, 128 }, 129 "is_copied": { 130 Type: schema.TypeBool, 131 Computed: true, 132 }, 133 "is_support_io_optimized": { 134 Type: schema.TypeBool, 135 Computed: true, 136 }, 137 "image_version": { 138 Type: schema.TypeString, 139 Computed: true, 140 }, 141 "progress": { 142 Type: schema.TypeString, 143 Computed: true, 144 }, 145 "usage": { 146 Type: schema.TypeString, 147 Computed: true, 148 }, 149 150 "tags": tagsSchema(), 151 }, 152 }, 153 }, 154 }, 155 } 156 } 157 158 // dataSourceAlicloudImagesDescriptionRead performs the Alicloud Image lookup. 159 func dataSourceAlicloudImagesRead(d *schema.ResourceData, meta interface{}) error { 160 conn := meta.(*AliyunClient).ecsconn 161 162 nameRegex, nameRegexOk := d.GetOk("name_regex") 163 owners, ownersOk := d.GetOk("owners") 164 mostRecent, mostRecentOk := d.GetOk("most_recent") 165 166 if nameRegexOk == false && ownersOk == false && mostRecentOk == false { 167 return fmt.Errorf("One of name_regex, owners or most_recent must be assigned") 168 } 169 170 params := &ecs.DescribeImagesArgs{ 171 RegionId: getRegion(d, meta), 172 } 173 174 if ownersOk { 175 params.ImageOwnerAlias = ecs.ImageOwnerAlias(owners.(string)) 176 } 177 178 var allImages []ecs.ImageType 179 180 for { 181 images, paginationResult, err := conn.DescribeImages(params) 182 if err != nil { 183 break 184 } 185 186 allImages = append(allImages, images...) 187 188 pagination := paginationResult.NextPage() 189 if pagination == nil { 190 break 191 } 192 193 params.Pagination = *pagination 194 } 195 196 var filteredImages []ecs.ImageType 197 if nameRegexOk { 198 r := regexp.MustCompile(nameRegex.(string)) 199 for _, image := range allImages { 200 // Check for a very rare case where the response would include no 201 // image name. No name means nothing to attempt a match against, 202 // therefore we are skipping such image. 203 if image.ImageName == "" { 204 log.Printf("[WARN] Unable to find Image name to match against "+ 205 "for image ID %q, nothing to do.", 206 image.ImageId) 207 continue 208 } 209 if r.MatchString(image.ImageName) { 210 filteredImages = append(filteredImages, image) 211 } 212 } 213 } else { 214 filteredImages = allImages[:] 215 } 216 217 var images []ecs.ImageType 218 if len(filteredImages) < 1 { 219 return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") 220 } 221 222 log.Printf("[DEBUG] alicloud_image - multiple results found and `most_recent` is set to: %t", mostRecent.(bool)) 223 if len(filteredImages) > 1 && mostRecent.(bool) { 224 // Query returned single result. 225 images = append(images, mostRecentImage(filteredImages)) 226 } else { 227 images = filteredImages 228 } 229 230 log.Printf("[DEBUG] alicloud_image - Images found: %#v", images) 231 return imagesDescriptionAttributes(d, images, meta) 232 } 233 234 // populate the numerous fields that the image description returns. 235 func imagesDescriptionAttributes(d *schema.ResourceData, images []ecs.ImageType, meta interface{}) error { 236 var ids []string 237 var s []map[string]interface{} 238 for _, image := range images { 239 mapping := map[string]interface{}{ 240 "id": image.ImageId, 241 "architecture": image.Architecture, 242 "creation_time": image.CreationTime.String(), 243 "description": image.Description, 244 "image_id": image.ImageId, 245 "image_owner_alias": image.ImageOwnerAlias, 246 "os_name": image.OSName, 247 "os_type": image.OSType, 248 "name": image.ImageName, 249 "platform": image.Platform, 250 "status": image.Status, 251 "state": image.Status, 252 "size": image.Size, 253 "is_self_shared": image.IsSelfShared, 254 "is_subscribed": image.IsSubscribed, 255 "is_copied": image.IsCopied, 256 "is_support_io_optimized": image.IsSupportIoOptimized, 257 "image_version": image.ImageVersion, 258 "progress": image.Progress, 259 "usage": image.Usage, 260 "product_code": image.ProductCode, 261 262 // Complex types get their own functions 263 "disk_device_mappings": imageDiskDeviceMappings(image.DiskDeviceMappings.DiskDeviceMapping), 264 "tags": imageTagsMappings(d, image.ImageId, meta), 265 } 266 267 log.Printf("[DEBUG] alicloud_image - adding image mapping: %v", mapping) 268 ids = append(ids, image.ImageId) 269 s = append(s, mapping) 270 } 271 272 d.SetId(dataResourceIdHash(ids)) 273 if err := d.Set("images", s); err != nil { 274 return err 275 } 276 return nil 277 } 278 279 //Find most recent image 280 type imageSort []ecs.ImageType 281 282 func (a imageSort) Len() int { 283 return len(a) 284 } 285 func (a imageSort) Swap(i, j int) { 286 a[i], a[j] = a[j], a[i] 287 } 288 func (a imageSort) Less(i, j int) bool { 289 itime, _ := time.Parse(time.RFC3339, a[i].CreationTime.String()) 290 jtime, _ := time.Parse(time.RFC3339, a[j].CreationTime.String()) 291 return itime.Unix() < jtime.Unix() 292 } 293 294 // Returns the most recent Image out of a slice of images. 295 func mostRecentImage(images []ecs.ImageType) ecs.ImageType { 296 sortedImages := images 297 sort.Sort(imageSort(sortedImages)) 298 return sortedImages[len(sortedImages)-1] 299 } 300 301 // Returns a set of disk device mappings. 302 func imageDiskDeviceMappings(m []ecs.DiskDeviceMapping) []map[string]interface{} { 303 var s []map[string]interface{} 304 305 for _, v := range m { 306 mapping := map[string]interface{}{ 307 "device": v.Device, 308 "size": v.Size, 309 "snapshot_id": v.SnapshotId, 310 } 311 312 log.Printf("[DEBUG] alicloud_image - adding disk device mapping: %v", mapping) 313 s = append(s, mapping) 314 } 315 316 return s 317 } 318 319 //Returns a mapping of image tags 320 func imageTagsMappings(d *schema.ResourceData, imageId string, meta interface{}) map[string]string { 321 client := meta.(*AliyunClient) 322 conn := client.ecsconn 323 324 tags, _, err := conn.DescribeTags(&ecs.DescribeTagsArgs{ 325 RegionId: getRegion(d, meta), 326 ResourceType: ecs.TagResourceImage, 327 ResourceId: imageId, 328 }) 329 330 if err != nil { 331 log.Printf("[ERROR] DescribeTags for image got error: %#v", err) 332 return nil 333 } 334 335 log.Printf("[DEBUG] DescribeTags for image : %v", tags) 336 return tagsToMap(tags) 337 }