github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/alicloud/data_source_alicloud_images.go (about) 1 package alicloud 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "sort" 8 9 "github.com/denverdino/aliyungo/ecs" 10 "github.com/hashicorp/terraform/helper/schema" 11 "time" 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 resp, _, err := conn.DescribeImages(params) 179 if err != nil { 180 return err 181 } 182 183 var filteredImages []ecs.ImageType 184 if nameRegexOk { 185 r := regexp.MustCompile(nameRegex.(string)) 186 for _, image := range resp { 187 // Check for a very rare case where the response would include no 188 // image name. No name means nothing to attempt a match against, 189 // therefore we are skipping such image. 190 if image.ImageName == "" { 191 log.Printf("[WARN] Unable to find Image name to match against "+ 192 "for image ID %q, nothing to do.", 193 image.ImageId) 194 continue 195 } 196 if r.MatchString(image.ImageName) { 197 filteredImages = append(filteredImages, image) 198 } 199 } 200 } else { 201 filteredImages = resp[:] 202 } 203 204 var images []ecs.ImageType 205 if len(filteredImages) < 1 { 206 return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") 207 } 208 209 log.Printf("[DEBUG] alicloud_image - multiple results found and `most_recent` is set to: %t", mostRecent.(bool)) 210 if len(filteredImages) > 1 && mostRecent.(bool) { 211 // Query returned single result. 212 images = append(images, mostRecentImage(filteredImages)) 213 } else { 214 images = filteredImages 215 } 216 217 log.Printf("[DEBUG] alicloud_image - Images found: %#v", images) 218 return imagesDescriptionAttributes(d, images, meta) 219 } 220 221 // populate the numerous fields that the image description returns. 222 func imagesDescriptionAttributes(d *schema.ResourceData, images []ecs.ImageType, meta interface{}) error { 223 var ids []string 224 var s []map[string]interface{} 225 for _, image := range images { 226 mapping := map[string]interface{}{ 227 "id": image.ImageId, 228 "architecture": image.Architecture, 229 "creation_time": image.CreationTime.String(), 230 "description": image.Description, 231 "image_id": image.ImageId, 232 "image_owner_alias": image.ImageOwnerAlias, 233 "os_name": image.OSName, 234 "os_type": image.OSType, 235 "name": image.ImageName, 236 "platform": image.Platform, 237 "status": image.Status, 238 "state": image.Status, 239 "size": image.Size, 240 "is_self_shared": image.IsSelfShared, 241 "is_subscribed": image.IsSubscribed, 242 "is_copied": image.IsCopied, 243 "is_support_io_optimized": image.IsSupportIoOptimized, 244 "image_version": image.ImageVersion, 245 "progress": image.Progress, 246 "usage": image.Usage, 247 "product_code": image.ProductCode, 248 249 // Complex types get their own functions 250 "disk_device_mappings": imageDiskDeviceMappings(image.DiskDeviceMappings.DiskDeviceMapping), 251 "tags": imageTagsMappings(d, image.ImageId, meta), 252 } 253 254 log.Printf("[DEBUG] alicloud_image - adding image mapping: %v", mapping) 255 ids = append(ids, image.ImageId) 256 s = append(s, mapping) 257 } 258 259 d.SetId(dataResourceIdHash(ids)) 260 if err := d.Set("images", s); err != nil { 261 return err 262 } 263 return nil 264 } 265 266 //Find most recent image 267 type imageSort []ecs.ImageType 268 269 func (a imageSort) Len() int { 270 return len(a) 271 } 272 func (a imageSort) Swap(i, j int) { 273 a[i], a[j] = a[j], a[i] 274 } 275 func (a imageSort) Less(i, j int) bool { 276 itime, _ := time.Parse(time.RFC3339, a[i].CreationTime.String()) 277 jtime, _ := time.Parse(time.RFC3339, a[j].CreationTime.String()) 278 return itime.Unix() < jtime.Unix() 279 } 280 281 // Returns the most recent Image out of a slice of images. 282 func mostRecentImage(images []ecs.ImageType) ecs.ImageType { 283 sortedImages := images 284 sort.Sort(imageSort(sortedImages)) 285 return sortedImages[len(sortedImages)-1] 286 } 287 288 // Returns a set of disk device mappings. 289 func imageDiskDeviceMappings(m []ecs.DiskDeviceMapping) []map[string]interface{} { 290 var s []map[string]interface{} 291 292 for _, v := range m { 293 mapping := map[string]interface{}{ 294 "device": v.Device, 295 "size": v.Size, 296 "snapshot_id": v.SnapshotId, 297 } 298 299 log.Printf("[DEBUG] alicloud_image - adding disk device mapping: %v", mapping) 300 s = append(s, mapping) 301 } 302 303 return s 304 } 305 306 //Returns a mapping of image tags 307 func imageTagsMappings(d *schema.ResourceData, imageId string, meta interface{}) map[string]string { 308 client := meta.(*AliyunClient) 309 conn := client.ecsconn 310 311 tags, _, err := conn.DescribeTags(&ecs.DescribeTagsArgs{ 312 RegionId: getRegion(d, meta), 313 ResourceType: ecs.TagResourceImage, 314 ResourceId: imageId, 315 }) 316 317 if err != nil { 318 log.Printf("[ERROR] DescribeTags for image got error: %#v", err) 319 return nil 320 } 321 322 log.Printf("[DEBUG] DescribeTags for image : %v", tags) 323 return tagsToMap(tags) 324 }