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  }