github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/ec2/image.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/juju/environs/imagemetadata"
    10  	"github.com/juju/juju/environs/instances"
    11  )
    12  
    13  // defaultCpuPower is larger the smallest instance's cpuPower, and no larger than
    14  // any other instance type's cpuPower. It is used when no explicit CpuPower
    15  // constraint exists, preventing the smallest instance from being chosen unless
    16  // the user has clearly indicated that they are willing to accept poor performance.
    17  const defaultCpuPower = 100
    18  
    19  // filterImages returns only that subset of the input (in the same order) that
    20  // this provider finds suitable.
    21  func filterImages(images []*imagemetadata.ImageMetadata, ic *instances.InstanceConstraint) []*imagemetadata.ImageMetadata {
    22  	// Gather the images for each available storage type.
    23  	imagesByStorage := make(map[string][]*imagemetadata.ImageMetadata)
    24  	for _, image := range images {
    25  		imagesByStorage[image.Storage] = append(imagesByStorage[image.Storage], image)
    26  	}
    27  	logger.Debugf("images by storage type %+v", imagesByStorage)
    28  	// If a storage constraint has been specified, use that or else default to ssd.
    29  	storageTypes := []string{ssdStorage}
    30  	if ic != nil && len(ic.Storage) > 0 {
    31  		storageTypes = ic.Storage
    32  	}
    33  	logger.Debugf("filtering storage types %+v", storageTypes)
    34  	// Return the first set of images for which we have a storage type match.
    35  	for _, storageType := range storageTypes {
    36  		if len(imagesByStorage[storageType]) > 0 {
    37  			return imagesByStorage[storageType]
    38  		}
    39  	}
    40  	// If the user specifies an image ID during bootstrap, then it will not
    41  	// have a storage type.
    42  	return imagesByStorage[""]
    43  }
    44  
    45  // findInstanceSpec returns an InstanceSpec satisfying the supplied instanceConstraint.
    46  func findInstanceSpec(
    47  	allImageMetadata []*imagemetadata.ImageMetadata,
    48  	ic *instances.InstanceConstraint,
    49  ) (*instances.InstanceSpec, error) {
    50  	logger.Debugf("received %d image(s)", len(allImageMetadata))
    51  	// If the instance type is set, don't also set a default CPU power
    52  	// as this is implied.
    53  	cons := ic.Constraints
    54  	if cons.CpuPower == nil && (cons.InstanceType == nil || *cons.InstanceType == "") {
    55  		ic.Constraints.CpuPower = instances.CpuPower(defaultCpuPower)
    56  	}
    57  	suitableImages := filterImages(allImageMetadata, ic)
    58  	logger.Debugf("found %d suitable image(s)", len(suitableImages))
    59  	images := instances.ImageMetadataToImages(suitableImages)
    60  
    61  	// Make a copy of the known EC2 instance types, filling in the cost for the specified region.
    62  	regionCosts := allRegionCosts[ic.Region]
    63  	if len(regionCosts) == 0 && len(allRegionCosts) > 0 {
    64  		return nil, fmt.Errorf("no instance types found in %s", ic.Region)
    65  	}
    66  
    67  	var itypesWithCosts []instances.InstanceType
    68  	for _, itype := range allInstanceTypes {
    69  		cost, ok := regionCosts[itype.Name]
    70  		if !ok {
    71  			continue
    72  		}
    73  		itWithCost := itype
    74  		itWithCost.Cost = cost
    75  		itypesWithCosts = append(itypesWithCosts, itWithCost)
    76  	}
    77  	return instances.FindInstanceSpec(images, ic, itypesWithCosts)
    78  }