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  }