// checkToolsSeries verifies that all the given possible tools are for the // given OS series. func checkToolsSeries(toolsList coretools.List, series string) error { toolsSeries := toolsList.AllSeries() if len(toolsSeries) != 1 { return fmt.Errorf("expected single series, got %v", toolsSeries) } if toolsSeries[0] != series { return fmt.Errorf("tools mismatch: expected series %v, got %v", series, toolsSeries[0]) } return nil }
// bootstrapImageMetadata returns the image metadata to use for bootstrapping // the given environment. If the environment provider does not make use of // simplestreams, no metadata will be returned. // // If a bootstrap image ID is specified, image metadata will be synthesised // using that image ID, and the architecture and series specified by the // initiator. In addition, the custom image metadata that is saved into the // state database will have the synthesised image metadata added to it. func bootstrapImageMetadata( environ environs.Environ, availableTools coretools.List, bootstrapImageId string, customImageMetadata *[]*imagemetadata.ImageMetadata, ) ([]*imagemetadata.ImageMetadata, error) { hasRegion, ok := environ.(simplestreams.HasRegion) if !ok { if bootstrapImageId != "" { // We only support specifying image IDs for providers // that use simplestreams for now. return nil, errors.NotSupportedf( "specifying bootstrap image for %q provider", environ.Config().Type(), ) } // No region, no metadata. return nil, nil } region, err := hasRegion.Region() if err != nil { return nil, errors.Trace(err) } if bootstrapImageId != "" { arches := availableTools.Arches() if len(arches) != 1 { return nil, errors.NotValidf("multiple architectures with bootstrap image") } allSeries := availableTools.AllSeries() if len(allSeries) != 1 { return nil, errors.NotValidf("multiple series with bootstrap image") } seriesVersion, err := series.SeriesVersion(allSeries[0]) if err != nil { return nil, errors.Trace(err) } // The returned metadata does not have information about the // storage or virtualisation type. Any provider that wants to // filter on those properties should allow for empty values. meta := &imagemetadata.ImageMetadata{ Id: bootstrapImageId, Arch: arches[0], Version: seriesVersion, RegionName: region.Region, Endpoint: region.Endpoint, Stream: environ.Config().ImageStream(), } *customImageMetadata = append(*customImageMetadata, meta) return []*imagemetadata.ImageMetadata{meta}, nil } // For providers that support making use of simplestreams // image metadata, search public image metadata. We need // to pass this onto Bootstrap for selecting images. sources, err := environs.ImageMetadataSources(environ) if err != nil { return nil, errors.Trace(err) } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: region, Series: availableTools.AllSeries(), Arches: availableTools.Arches(), Stream: environ.Config().ImageStream(), }) logger.Debugf("constraints for image metadata lookup %v", imageConstraint) // Get image metadata from all data sources. // Since order of data source matters, order of image metadata matters too. Append is important here. var publicImageMetadata []*imagemetadata.ImageMetadata for _, source := range sources { sourceMetadata, _, err := imagemetadata.Fetch([]simplestreams.DataSource{source}, imageConstraint) if err != nil { logger.Debugf("ignoring image metadata in %s: %v", source.Description(), err) // Just keep looking... continue } logger.Debugf("found %d image metadata in %s", len(sourceMetadata), source.Description()) publicImageMetadata = append(publicImageMetadata, sourceMetadata...) } logger.Debugf("found %d image metadata from all image data sources", len(publicImageMetadata)) if len(publicImageMetadata) == 0 { return nil, errors.New("no image metadata found") } return publicImageMetadata, nil }
// bootstrapImageMetadata returns the image metadata to use for bootstrapping // the given environment. If the environment provider does not make use of // simplestreams, no metadata will be returned. // // If a bootstrap image ID is specified, image metadat will be synthesised // using that image ID, and the architecture and series specified by the // initiator. In addition, the custom image metadat that is saved into the // state database will have the synthesised image metadata added to it. func bootstrapImageMetadata( environ environs.Environ, availableTools coretools.List, bootstrapImageId string, customImageMetadata *[]*imagemetadata.ImageMetadata, ) ([]*imagemetadata.ImageMetadata, error) { hasRegion, ok := environ.(simplestreams.HasRegion) if !ok { if bootstrapImageId != "" { // We only support specifying image IDs for providers // that use simplestreams for now. return nil, errors.NotSupportedf( "specifying bootstrap image for %q provider", environ.Config().Type(), ) } // No region, no metadata. return nil, nil } region, err := hasRegion.Region() if err != nil { return nil, errors.Trace(err) } if bootstrapImageId != "" { arches := availableTools.Arches() if len(arches) != 1 { return nil, errors.NotValidf("multiple architectures with bootstrap image") } allSeries := availableTools.AllSeries() if len(allSeries) != 1 { return nil, errors.NotValidf("multiple series with bootstrap image") } seriesVersion, err := series.SeriesVersion(allSeries[0]) if err != nil { return nil, errors.Trace(err) } // The returned metadata does not have information about the // storage or virtualisation type. Any provider that wants to // filter on those properties should allow for empty values. meta := &imagemetadata.ImageMetadata{ Id: bootstrapImageId, Arch: arches[0], Version: seriesVersion, RegionName: region.Region, Endpoint: region.Endpoint, Stream: environ.Config().ImageStream(), } *customImageMetadata = append(*customImageMetadata, meta) return []*imagemetadata.ImageMetadata{meta}, nil } // For providers that support making use of simplestreams // image metadata, search public image metadata. We need // to pass this onto Bootstrap for selecting images. sources, err := environs.ImageMetadataSources(environ) if err != nil { return nil, errors.Trace(err) } imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: region, Series: availableTools.AllSeries(), Arches: availableTools.Arches(), Stream: environ.Config().ImageStream(), }) publicImageMetadata, _, err := imagemetadata.Fetch(sources, imageConstraint) if err != nil { return nil, errors.Annotate(err, "searching image metadata") } return publicImageMetadata, nil }