github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 "github.com/juju/juju/environs/simplestreams" 12 ) 13 14 // signedImageDataOnly is defined here to allow tests to override the content. 15 // If true, only inline PGP signed image metadata will be used. 16 var signedImageDataOnly = true 17 18 // defaultCpuPower is larger the smallest instance's cpuPower, and no larger than 19 // any other instance type's cpuPower. It is used when no explicit CpuPower 20 // constraint exists, preventing the smallest instance from being chosen unless 21 // the user has clearly indicated that they are willing to accept poor performance. 22 const defaultCpuPower = 100 23 24 // filterImages returns only that subset of the input (in the same order) that 25 // this provider finds suitable. 26 func filterImages(images []*imagemetadata.ImageMetadata, ic *instances.InstanceConstraint) []*imagemetadata.ImageMetadata { 27 // Gather the images for each available storage type. 28 imagesByStorage := make(map[string][]*imagemetadata.ImageMetadata) 29 for _, image := range images { 30 imagesByStorage[image.Storage] = append(imagesByStorage[image.Storage], image) 31 } 32 // If a storage constraint has been specified, use that or else default to ssd. 33 storageTypes := []string{ssdStorage} 34 if ic != nil && len(ic.Storage) > 0 { 35 storageTypes = ic.Storage 36 } 37 // Return the first set of images for which we have a storage type match. 38 for _, storageType := range storageTypes { 39 if len(imagesByStorage[storageType]) > 0 { 40 return imagesByStorage[storageType] 41 } 42 } 43 return nil 44 } 45 46 // findInstanceSpec returns an InstanceSpec satisfying the supplied instanceConstraint. 47 func findInstanceSpec( 48 sources []simplestreams.DataSource, stream string, ic *instances.InstanceConstraint) (*instances.InstanceSpec, error) { 49 50 // If the instance type is set, don't also set a default CPU power 51 // as this is implied. 52 cons := ic.Constraints 53 if cons.CpuPower == nil && (cons.InstanceType == nil || *cons.InstanceType == "") { 54 ic.Constraints.CpuPower = instances.CpuPower(defaultCpuPower) 55 } 56 ec2Region := allRegions[ic.Region] 57 imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ 58 CloudSpec: simplestreams.CloudSpec{ic.Region, ec2Region.EC2Endpoint}, 59 Series: []string{ic.Series}, 60 Arches: ic.Arches, 61 Stream: stream, 62 }) 63 matchingImages, _, err := imagemetadata.Fetch(sources, imageConstraint, signedImageDataOnly) 64 if err != nil { 65 return nil, err 66 } 67 if len(matchingImages) == 0 { 68 logger.Warningf("no matching image meta data for constraints: %v", ic) 69 } 70 suitableImages := filterImages(matchingImages, ic) 71 images := instances.ImageMetadataToImages(suitableImages) 72 73 // Make a copy of the known EC2 instance types, filling in the cost for the specified region. 74 regionCosts := allRegionCosts[ic.Region] 75 if len(regionCosts) == 0 && len(allRegionCosts) > 0 { 76 return nil, fmt.Errorf("no instance types found in %s", ic.Region) 77 } 78 79 var itypesWithCosts []instances.InstanceType 80 for _, itype := range allInstanceTypes { 81 cost, ok := regionCosts[itype.Name] 82 if !ok { 83 continue 84 } 85 itWithCost := itype 86 itWithCost.Cost = cost 87 itypesWithCosts = append(itypesWithCosts, itWithCost) 88 } 89 return instances.FindInstanceSpec(images, ic, itypesWithCosts) 90 }