func (s *simplestreamsSuite) TestFetch(c *gc.C) { for i, t := range fetchTests { c.Logf("test %d", i) cloudSpec := simplestreams.CloudSpec{t.region, "https://ec2.us-east-1.amazonaws.com"} if t.region == "" { cloudSpec = simplestreams.EmptyCloudSpec } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Series: []string{"precise"}, Arches: t.arches, }) // Add invalid datasource and check later that resolveInfo is correct. invalidSource := simplestreams.NewURLDataSource("invalid", "file://invalid", utils.VerifySSLHostnames) images, resolveInfo, err := imagemetadata.Fetch( []simplestreams.DataSource{invalidSource, s.Source}, simplestreams.DefaultIndexPath, imageConstraint, s.RequireSigned) if !c.Check(err, gc.IsNil) { continue } for _, testImage := range t.images { testImage.Version = t.version } c.Check(images, gc.DeepEquals, t.images) c.Check(resolveInfo, gc.DeepEquals, &simplestreams.ResolveInfo{ Source: "test roundtripper", Signed: s.RequireSigned, IndexURL: "test:/streams/v1/index.json", MirrorURL: "", }) } }
func (s *signedSuite) TestSignedImageMetadataInvalidSignature(c *gc.C) { signedSource := simplestreams.NewURLDataSource("test", "signedtest://host/signed", utils.VerifySSLHostnames) imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{"us-east-1", "https://ec2.us-east-1.amazonaws.com"}, Series: []string{"precise"}, Arches: []string{"amd64"}, }) imagemetadata.SetSigningPublicKey(s.origKey) _, _, err := imagemetadata.Fetch( []simplestreams.DataSource{signedSource}, simplestreams.DefaultIndexPath, imageConstraint, true) c.Assert(err, gc.ErrorMatches, "cannot read index data.*") }
// SupportedArchitectures returns all the image architectures for env matching the constraints. func SupportedArchitectures(env environs.Environ, imageConstraint *imagemetadata.ImageConstraint) ([]string, error) { sources, err := imagemetadata.GetMetadataSources(env) if err != nil { return nil, err } matchingImages, _, err := imagemetadata.Fetch(sources, simplestreams.DefaultIndexPath, imageConstraint, false) if err != nil { return nil, err } var arches = set.NewStrings() for _, im := range matchingImages { arches.Add(im.Arch) } return arches.Values(), nil }
func (s *signedSuite) TestSignedImageMetadata(c *gc.C) { signedSource := simplestreams.NewURLDataSource("test", "signedtest://host/signed", utils.VerifySSLHostnames) imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{"us-east-1", "https://ec2.us-east-1.amazonaws.com"}, Series: []string{"precise"}, Arches: []string{"amd64"}, }) images, resolveInfo, err := imagemetadata.Fetch( []simplestreams.DataSource{signedSource}, simplestreams.DefaultIndexPath, imageConstraint, true) c.Assert(err, gc.IsNil) c.Assert(len(images), gc.Equals, 1) c.Assert(images[0].Id, gc.Equals, "ami-123456") c.Check(resolveInfo, gc.DeepEquals, &simplestreams.ResolveInfo{ Source: "test", Signed: true, IndexURL: "signedtest://host/signed/streams/v1/index.sjson", MirrorURL: "", }) }
// findInstanceSpec returns an image and instance type satisfying the constraint. // The instance type comes from querying the flavors supported by the deployment. func findInstanceSpec(e *environ, ic *instances.InstanceConstraint) (*instances.InstanceSpec, error) { // first construct all available instance types from the supported flavors. nova := e.nova() flavors, err := nova.ListFlavorsDetail() if err != nil { return nil, err } allInstanceTypes := []instances.InstanceType{} for _, flavor := range flavors { instanceType := instances.InstanceType{ Id: flavor.Id, Name: flavor.Name, Arches: ic.Arches, Mem: uint64(flavor.RAM), CpuCores: uint64(flavor.VCPUs), RootDisk: uint64(flavor.Disk * 1024), // tags not currently supported on openstack } allInstanceTypes = append(allInstanceTypes, instanceType) } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{ic.Region, e.ecfg().authURL()}, Series: []string{ic.Series}, Arches: ic.Arches, Stream: e.Config().ImageStream(), }) sources, err := imagemetadata.GetMetadataSources(e) if err != nil { return nil, err } // TODO (wallyworld): use an env parameter (default true) to mandate use of only signed image metadata. matchingImages, _, err := imagemetadata.Fetch(sources, simplestreams.DefaultIndexPath, imageConstraint, false) if err != nil { return nil, err } images := instances.ImageMetadataToImages(matchingImages) spec, err := instances.FindInstanceSpec(images, ic, allInstanceTypes) if err != nil { return nil, err } return spec, nil }
// findInstanceSpec returns an InstanceSpec satisfying the supplied instanceConstraint. func findInstanceSpec( sources []simplestreams.DataSource, stream string, ic *instances.InstanceConstraint) (*instances.InstanceSpec, error) { if ic.Constraints.CpuPower == nil { ic.Constraints.CpuPower = instances.CpuPower(defaultCpuPower) } ec2Region := allRegions[ic.Region] imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{ic.Region, ec2Region.EC2Endpoint}, Series: []string{ic.Series}, Arches: ic.Arches, Stream: stream, }) matchingImages, _, err := imagemetadata.Fetch( sources, simplestreams.DefaultIndexPath, imageConstraint, signedImageDataOnly) if err != nil { return nil, err } if len(matchingImages) == 0 { logger.Warningf("no matching image meta data for constraints: %v", ic) } suitableImages := filterImages(matchingImages) images := instances.ImageMetadataToImages(suitableImages) // Make a copy of the known EC2 instance types, filling in the cost for the specified region. regionCosts := allRegionCosts[ic.Region] if len(regionCosts) == 0 && len(allRegionCosts) > 0 { return nil, fmt.Errorf("no instance types found in %s", ic.Region) } var itypesWithCosts []instances.InstanceType for _, itype := range allInstanceTypes { cost, ok := regionCosts[itype.Name] if !ok { continue } itWithCost := itype itWithCost.Cost = cost itypesWithCosts = append(itypesWithCosts, itWithCost) } return instances.FindInstanceSpec(images, ic, itypesWithCosts) }
// findMatchingImages queries simplestreams for OS images that match the given // requirements. // // If it finds no matching images, that's an error. func findMatchingImages(e *azureEnviron, location, series string, arches []string) ([]*imagemetadata.ImageMetadata, error) { endpoint := getEndpoint(location) constraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{location, endpoint}, Series: []string{series}, Arches: arches, Stream: e.Config().ImageStream(), }) sources, err := imagemetadata.GetMetadataSources(e) if err != nil { return nil, err } indexPath := simplestreams.DefaultIndexPath images, _, err := imagemetadata.Fetch(sources, indexPath, constraint, signedImageDataOnly) if len(images) == 0 || errors.IsNotFound(err) { return nil, fmt.Errorf("no OS images found for location %q, series %q, architectures %q (and endpoint: %q)", location, series, arches, endpoint) } else if err != nil { return nil, err } return images, nil }