// setPrivateMetadataSources sets the default tools metadata source // for tools syncing, and adds an image metadata source after verifying // the contents. func setPrivateMetadataSources(metadataDir string) ([]*imagemetadata.ImageMetadata, error) { logger.Infof("Setting default tools and image metadata sources: %s", metadataDir) tools.DefaultBaseURL = metadataDir imageMetadataDir := filepath.Join(metadataDir, storage.BaseImagesPath) if _, err := os.Stat(imageMetadataDir); err != nil { if !os.IsNotExist(err) { return nil, errors.Annotate(err, "cannot access image metadata") } return nil, nil } baseURL := fmt.Sprintf("file://%s", filepath.ToSlash(imageMetadataDir)) publicKey, _ := simplestreams.UserPublicSigningKey() datasource := simplestreams.NewURLSignedDataSource("bootstrap metadata", baseURL, publicKey, utils.NoVerifySSLHostnames, simplestreams.CUSTOM_CLOUD_DATA, false) // Read the image metadata, as we'll want to upload it to the environment. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{}) existingMetadata, _, err := imagemetadata.Fetch([]simplestreams.DataSource{datasource}, imageConstraint) if err != nil && !errors.IsNotFound(err) { return nil, errors.Annotate(err, "cannot read image metadata") } // Add an image metadata datasource for constraint validation, etc. environs.RegisterUserImageDataSourceFunc("bootstrap metadata", func(environs.Environ) (simplestreams.DataSource, error) { return datasource, nil }) logger.Infof("custom image metadata added to search path") return existingMetadata, nil }
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, simplestreams.DEFAULT_CLOUD_DATA, s.RequireSigned) images, resolveInfo, err := imagemetadata.Fetch( []simplestreams.DataSource{invalidSource, s.Source}, imageConstraint) if !c.Check(err, jc.ErrorIsNil) { 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: "", }) } }
// setPrivateMetadataSources sets the default tools metadata source // for tools syncing, and adds an image metadata source after verifying // the contents. func setPrivateMetadataSources(env environs.Environ, metadataDir string) ([]*imagemetadata.ImageMetadata, error) { logger.Infof("Setting default tools and image metadata sources: %s", metadataDir) tools.DefaultBaseURL = metadataDir imageMetadataDir := filepath.Join(metadataDir, storage.BaseImagesPath) if _, err := os.Stat(imageMetadataDir); err != nil { if !os.IsNotExist(err) { return nil, errors.Annotate(err, "cannot access image metadata") } return nil, nil } baseURL := fmt.Sprintf("file://%s", filepath.ToSlash(imageMetadataDir)) datasource := simplestreams.NewURLDataSource("bootstrap metadata", baseURL, utils.NoVerifySSLHostnames) // Read the image metadata, as we'll want to upload it to the environment. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{}) existingMetadata, _, err := imagemetadata.Fetch( []simplestreams.DataSource{datasource}, imageConstraint, false) if err != nil && !errors.IsNotFound(err) { return nil, errors.Annotate(err, "cannot read image metadata") } // Add an image metadata datasource for constraint validation, etc. // TODO (anastasiamac 2015-09-26) Delete when search path is modified to look // into state first. environs.RegisterUserImageDataSourceFunc("bootstrap metadata", func(environs.Environ) (simplestreams.DataSource, error) { return datasource, nil }) logger.Infof("custom image metadata added to search path") return existingMetadata, nil }
// constructImageConstraint returns model-specific criteria used to look for image metadata. func (p *ProvisionerAPI) constructImageConstraint(m *state.Machine) (*imagemetadata.ImageConstraint, environs.Environ, error) { // If we can determine current region, // we want only metadata specific to this region. cloud, env, err := p.obtainEnvCloudConfig() if err != nil { return nil, nil, errors.Trace(err) } lookup := simplestreams.LookupParams{ Series: []string{m.Series()}, Stream: env.Config().ImageStream(), } mcons, err := m.Constraints() if err != nil { return nil, nil, errors.Annotatef(err, "cannot get machine constraints for machine %v", m.MachineTag().Id()) } if mcons.Arch != nil { lookup.Arches = []string{*mcons.Arch} } if cloud != nil { lookup.CloudSpec = *cloud } return imagemetadata.NewImageConstraint(lookup), env, nil }
// FindInstanceSpec returns an InstanceSpec satisfying the supplied instanceConstraint. func (env *joyentEnviron) FindInstanceSpec(ic *instances.InstanceConstraint) (*instances.InstanceSpec, error) { // Require at least one VCPU so we get KVM rather than smart package. if ic.Constraints.CpuCores == nil { ic.Constraints.CpuCores = &defaultCpuCores } allInstanceTypes, err := env.listInstanceTypes() if err != nil { return nil, err } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{ic.Region, env.Ecfg().SdcUrl()}, Series: []string{ic.Series}, Arches: ic.Arches, }) sources, err := environs.ImageMetadataSources(env) if err != nil { return nil, err } matchingImages, _, err := imagemetadata.Fetch(sources, imageConstraint, signedImageDataOnly) 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 }
func SetImageMetadata(env environs.Environ, series, arches []string, out *[]*imagemetadata.ImageMetadata) error { hasRegion, ok := env.(simplestreams.HasRegion) if !ok { return nil } sources, err := environs.ImageMetadataSources(env) if err != nil { return errors.Trace(err) } region, err := hasRegion.Region() if err != nil { return errors.Trace(err) } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: region, Series: series, Arches: arches, Stream: env.Config().ImageStream(), }) imageMetadata, _, err := imagemetadata.Fetch(sources, imageConstraint) if err != nil { return errors.Trace(err) } *out = imageMetadata return nil }
func (s *archSuite) TestSupportedArchitecturesNone(c *gc.C) { env, cloudSpec := s.setupMetadata(c, nil) imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, }) arches, err := common.SupportedArchitectures(env, imageConstraint) c.Assert(err, jc.ErrorIsNil) c.Assert(arches, gc.HasLen, 0) }
func (s *archSuite) TestSupportedArchitecturesMany(c *gc.C) { env, cloudSpec := s.setupMetadata(c, []string{"ppc64el", "amd64"}) imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, }) arches, err := common.SupportedArchitectures(env, imageConstraint) c.Assert(err, jc.ErrorIsNil) c.Assert(arches, jc.SameContents, []string{"amd64", "ppc64el"}) }
func (s *productSpecSuite) TestId(c *gc.C) { imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ Series: []string{"precise"}, Arches: []string{"amd64"}, Stream: "daily", }) ids, err := imageConstraint.ProductIds() c.Assert(err, jc.ErrorIsNil) c.Assert(ids, gc.DeepEquals, []string{"com.ubuntu.cloud.daily:server:12.04:amd64"}) }
func (s *signedSuite) TestSignedImageMetadataInvalidSignature(c *gc.C) { signedSource := simplestreams.NewURLDataSource("test", "test://host/signed", utils.VerifySSLHostnames, simplestreams.DEFAULT_CLOUD_DATA, true) 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}, imageConstraint) c.Assert(err, gc.ErrorMatches, "cannot read index data.*") }
func (s *productSpecSuite) TestIdWithDefaultStream(c *gc.C) { imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ Series: []string{"precise"}, Arches: []string{"amd64"}, }) for _, stream := range []string{"", "released"} { imageConstraint.Stream = stream ids, err := imageConstraint.ProductIds() c.Assert(err, jc.ErrorIsNil) c.Assert(ids, gc.DeepEquals, []string{"com.ubuntu.cloud:server:12.04:amd64"}) } }
func assertFetch(c *gc.C, stor storage.Storage, series, arch, region, endpoint, id string) { cons := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{region, endpoint}, Series: []string{series}, Arches: []string{arch}, }) dataSource := storage.NewStorageSimpleStreamsDataSource("test datasource", stor, "images") metadata, _, err := imagemetadata.Fetch([]simplestreams.DataSource{dataSource}, cons, false) c.Assert(err, jc.ErrorIsNil) c.Assert(metadata, gc.HasLen, 1) c.Assert(metadata[0].Id, gc.Equals, id) }
func (env *environ) lookupArchitectures() ([]string, error) { // Create a filter to get all images from our region and for the // correct stream. cloudSpec, err := env.Region() if err != nil { return nil, errors.Trace(err) } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Stream: env.Config().ImageStream(), }) archList, err := supportedArchitectures(env, imageConstraint) return archList, errors.Trace(err) }
func assertFetch(c *gc.C, stor storage.Storage, series, arch, region, endpoint string, ids ...string) { cons := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{region, endpoint}, Series: []string{series}, Arches: []string{arch}, }) dataSource := storage.NewStorageSimpleStreamsDataSource("test datasource", stor, "images", simplestreams.DEFAULT_CLOUD_DATA, false) metadata, _, err := imagemetadata.Fetch([]simplestreams.DataSource{dataSource}, cons) c.Assert(err, jc.ErrorIsNil) c.Assert(metadata, gc.HasLen, len(ids)) for i, id := range ids { c.Assert(metadata[i].Id, gc.Equals, id) } }
func (s *imageSuite) TestFindInstanceSpec(c *gc.C) { for _, t := range findInstanceSpecTests { c.Logf("test: %v", t.desc) t.init() cons := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{t.region, "ep"}, Series: []string{"precise"}, Arches: t.arches, Stream: t.stream, }) imageMeta, err := imagemetadata.GetLatestImageIdMetadata( []byte(jsonImagesContent), simplestreams.NewURLDataSource("test", "some-url", utils.VerifySSLHostnames), cons) c.Assert(err, jc.ErrorIsNil) var images []Image for _, imageMetadata := range imageMeta { im := *imageMetadata images = append(images, Image{ Id: im.Id, VirtType: im.VirtType, Arch: im.Arch, }) } imageCons := constraints.MustParse(t.constraints) spec, err := FindInstanceSpec(images, &InstanceConstraint{ Series: "precise", Region: t.region, Arches: t.arches, Constraints: imageCons, }, t.instanceTypes) if t.err != "" { c.Check(err, gc.ErrorMatches, t.err) continue } else { if !c.Check(err, jc.ErrorIsNil) { continue } c.Check(spec.Image.Id, gc.Equals, t.imageId) if len(t.instanceTypes) == 1 { c.Check(spec.InstanceType, gc.DeepEquals, t.instanceTypes[0]) } if imageCons.HasInstanceType() { c.Assert(spec.InstanceType.Name, gc.Equals, *imageCons.InstanceType) } } } }
func (api *API) retrievePublished() error { envCfg, err := api.metadata.ModelConfig() if err != nil { return errors.Annotatef(err, "getting environ config") } env, err := environs.New(envCfg) if err != nil { return errors.Annotatef(err, "getting environ") } sources, err := environs.ImageMetadataSources(env) if err != nil { return errors.Annotatef(err, "getting cloud specific image metadata sources") } cons := envmetadata.NewImageConstraint(simplestreams.LookupParams{}) if inst, ok := env.(simplestreams.HasRegion); !ok { // Published image metadata for some providers are in simple streams. // Providers that do not rely on simplestreams, don't need to do anything here. return nil } else { // If we can determine current region, // we want only metadata specific to this region. cloud, err := inst.Region() if err != nil { return errors.Annotatef(err, "getting cloud specific region information") } cons.CloudSpec = cloud } // We want all relevant metadata from all data sources. for _, source := range sources { logger.Debugf("looking in data source %v", source.Description()) metadata, info, err := envmetadata.Fetch([]simplestreams.DataSource{source}, cons) if err != nil { // Do not stop looking in other data sources if there is an issue here. logger.Errorf("encountered %v while getting published images metadata from %v", err, source.Description()) continue } err = api.saveAll(info, source.Priority(), metadata) if err != nil { // Do not stop looking in other data sources if there is an issue here. logger.Errorf("encountered %v while saving published images metadata from %v", err, source.Description()) } } return nil }
// saveCustomImageMetadata reads the custom image metadata from disk, // and saves it in state server. func (c *BootstrapCommand) saveCustomImageMetadata(st *state.State) error { logger.Debugf("saving custom image metadata from %q", c.ImageMetadataDir) baseURL := fmt.Sprintf("file://%s", filepath.ToSlash(c.ImageMetadataDir)) datasource := simplestreams.NewURLDataSource("bootstrap metadata", baseURL, utils.NoVerifySSLHostnames) // Read the image metadata, as we'll want to upload it to the environment. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{}) existingMetadata, _, err := imagemetadata.Fetch( []simplestreams.DataSource{datasource}, imageConstraint, false) if err != nil && !errors.IsNotFound(err) { return errors.Annotate(err, "cannot read image metadata") } if len(existingMetadata) == 0 { return nil } msg := "" for _, one := range existingMetadata { m := cloudimagemetadata.Metadata{ cloudimagemetadata.MetadataAttributes{ Stream: one.Stream, Region: one.RegionName, Arch: one.Arch, VirtType: one.VirtType, RootStorageType: one.Storage, Source: "custom", }, one.Id, } s, err := seriesFromVersion(one.Version) if err != nil { return errors.Annotatef(err, "cannot determine series for version %v", one.Version) } m.Series = s err = st.CloudImageMetadataStorage.SaveMetadata(m) if err != nil { return errors.Annotatef(err, "cannot cache image metadata %v", m) } } if len(msg) > 0 { return errors.New(msg) } return nil }
// SupportedArchitectures is specified on the EnvironCapability interface. func (e *Environ) SupportedArchitectures() ([]string, error) { e.archMutex.Lock() defer e.archMutex.Unlock() if e.supportedArchitectures != nil { return e.supportedArchitectures, nil } // Create a filter to get all images from our region and for the correct stream. cloudSpec, err := e.Region() if err != nil { return nil, err } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Stream: e.Config().ImageStream(), }) e.supportedArchitectures, err = common.SupportedArchitectures(e, imageConstraint) return e.supportedArchitectures, err }
func (s *signedSuite) TestSignedImageMetadata(c *gc.C) { signedSource := simplestreams.NewURLSignedDataSource("test", "test://host/signed", sstesting.SignedMetadataPublicKey, utils.VerifySSLHostnames, simplestreams.DEFAULT_CLOUD_DATA, true) 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}, imageConstraint) c.Assert(err, jc.ErrorIsNil) 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: "test://host/signed/streams/v1/index.sjson", MirrorURL: "", }) }
// findInstanceSpec returns an InstanceSpec satisfying the supplied instanceConstraint. func findInstanceSpec( sources []simplestreams.DataSource, stream string, ic *instances.InstanceConstraint) (*instances.InstanceSpec, error) { // If the instance type is set, don't also set a default CPU power // as this is implied. cons := ic.Constraints if cons.CpuPower == nil && (cons.InstanceType == nil || *cons.InstanceType == "") { 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, 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, ic) 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) }
// storeImageMetadataFromFiles puts image metadata found in sources into state. func storeImageMetadataFromFiles(st *state.State, env environs.Environ, source simplestreams.DataSource) error { // Read the image metadata, as we'll want to upload it to the environment. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{}) if inst, ok := env.(simplestreams.HasRegion); ok { // If we can determine current region, // we want only metadata specific to this region. cloud, err := inst.Region() if err != nil { return err } imageConstraint.CloudSpec = cloud } existingMetadata, info, err := imagemetadata.Fetch([]simplestreams.DataSource{source}, imageConstraint) if err != nil && !errors.IsNotFound(err) { return errors.Annotate(err, "cannot read image metadata") } return storeImageMetadataInState(st, info.Source, source.Priority(), existingMetadata) }
// 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 }
func registerSimpleStreamsTests() { gc.Suite(&simplestreamsSuite{ LocalLiveSimplestreamsSuite: sstesting.LocalLiveSimplestreamsSuite{ Source: simplestreams.NewURLDataSource( "test roundtripper", "test:", utils.VerifySSLHostnames), RequireSigned: false, DataType: imagemetadata.ImageIds, ValidConstraint: imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{ Region: "us-east-1", Endpoint: "https://ec2.us-east-1.amazonaws.com", }, Series: []string{"precise"}, Arches: []string{"amd64", "arm"}, }), }, }) gc.Suite(&signedSuite{}) }
func (env *environ) SupportedArchitectures() ([]string, error) { env.archMutex.Lock() defer env.archMutex.Unlock() if env.supportedArchitectures != nil { return env.supportedArchitectures, nil } logger.Debugf("Getting supported architectures from simplestream.") cloudSpec, err := env.Region() if err != nil { return nil, err } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Stream: env.Config().ImageStream(), }) env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint) logger.Debugf("Supported architectures: %v", env.supportedArchitectures) return env.supportedArchitectures, err }
// SupportedArchitectures is specified on the EnvironCapability interface. func (env *joyentEnviron) SupportedArchitectures() ([]string, error) { env.archLock.Lock() defer env.archLock.Unlock() if env.supportedArchitectures != nil { return env.supportedArchitectures, nil } cfg := env.Ecfg() // Create a filter to get all images from our region and for the correct stream. cloudSpec := simplestreams.CloudSpec{ Region: cfg.Region(), Endpoint: cfg.SdcUrl(), } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Stream: cfg.ImageStream(), }) var err error env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint) return env.supportedArchitectures, err }
func Test(t *stdtesting.T) { if *live { if *vendor == "" { t.Fatal("missing vendor") } var ok bool var testData liveTestData if testData, ok = liveURLs[*vendor]; !ok { keys := reflect.ValueOf(liveURLs).MapKeys() t.Fatalf("Unknown vendor %s. Must be one of %s", *vendor, keys) } registerLiveSimpleStreamsTests(testData.baseURL, imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: testData.validCloudSpec, Series: []string{"quantal"}, Arches: []string{"amd64"}, }), testData.requireSigned) } registerSimpleStreamsTests() gc.TestingT(t) }
// 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 := environs.ImageMetadataSources(e) if err != nil { return nil, err } images, _, err := imagemetadata.Fetch(sources, 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 }
// SupportedArchitectures is specified on the EnvironCapability interface. func (env *azureEnviron) SupportedArchitectures() ([]string, error) { env.archMutex.Lock() defer env.archMutex.Unlock() if env.supportedArchitectures != nil { return env.supportedArchitectures, nil } // Create a filter to get all images from our region and for the correct stream. ecfg := env.getSnapshot().ecfg region := ecfg.location() cloudSpec := simplestreams.CloudSpec{ Region: region, Endpoint: getEndpoint(region), } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: cloudSpec, Stream: ecfg.ImageStream(), }) var err error env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint) return env.supportedArchitectures, err }
func (api *API) retrievePublished() ([]*envmetadata.ImageMetadata, error) { // Get environ envCfg, err := api.metadata.EnvironConfig() env, err := environs.New(envCfg) if err != nil { return nil, errors.Trace(err) } // Get all images metadata sources for this environ. sources, err := environs.ImageMetadataSources(env) if err != nil { return nil, err } // We want all metadata. cons := envmetadata.NewImageConstraint(simplestreams.LookupParams{}) metadata, _, err := envmetadata.Fetch(sources, cons, false) if err != nil { return nil, err } return metadata, nil }
func (env *environ) lookupArchitectures() ([]string, error) { // Create a filter to get all images for the // correct stream. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ Stream: env.Config().ImageStream(), }) sources, err := environs.ImageMetadataSources(env) if err != nil { return nil, errors.Trace(err) } matchingImages, err := imageMetadataFetch(sources, imageConstraint) if err != nil { return nil, errors.Trace(err) } var arches = set.NewStrings() for _, im := range matchingImages { arches.Add(im.Arch) } return arches.Values(), nil }