Skip to content

Commit

Permalink
Simplestreams: Define a simplestreams type
Browse files Browse the repository at this point in the history
By defining a simplestreams type we no longer need to pass the factory
everywhere as we can just use a type to hold that information.
  • Loading branch information
SimonRichardson committed Jun 3, 2021
1 parent 71f0554 commit 6a3173a
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 45 deletions.
3 changes: 2 additions & 1 deletion environs/gui/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ func FetchMetadata(stream string, major, minor int, sources ...simplestreams.Dat
ValueTemplate: Metadata{},
},
}
items, _, err := simplestreams.GetMetadata(simplestreams.DefaultDataSourceFactory(), sources, params)
ss := simplestreams.NewSimpleStreams(simplestreams.DefaultDataSourceFactory())
items, _, err := ss.GetMetadata(sources, params)
if err != nil {
return nil, errors.Annotate(err, "error fetching simplestreams metadata")
}
Expand Down
3 changes: 2 additions & 1 deletion environs/imagedownloads/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ func Fetch(
ValueTemplate: Metadata{},
},
}
items, resolveInfo, err := simplestreams.GetMetadata(simplestreams.DefaultDataSourceFactory(), src, params)
ss := simplestreams.NewSimpleStreams(simplestreams.DefaultDataSourceFactory())
items, resolveInfo, err := ss.GetMetadata(src, params)
if err != nil {
return nil, resolveInfo, err
}
Expand Down
17 changes: 8 additions & 9 deletions environs/imagemetadata/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,12 @@ func (im *ImageMetadata) productId() string {
return fmt.Sprintf("com.ubuntu.cloud%s:server:%s:%s", stream, im.Version, im.Arch)
}

// Fetch returns a list of images for the specified cloud matching the constraint.
// The base URL locations are as specified - the first location which has a file is the one used.
// Signed data is preferred, but if there is no signed data available and onlySigned is false,
// then unsigned data is used.
func Fetch(
sources []simplestreams.DataSource, cons *ImageConstraint,
) ([]*ImageMetadata, *simplestreams.ResolveInfo, error) {

// Fetch returns a list of images for the specified cloud matching the
// constraint. The base URL locations are as specified - the first location
// which has a file is the one used.
// Signed data is preferred, but if there is no signed data available and
// onlySigned is false, then unsigned data is used.
func Fetch(sources []simplestreams.DataSource, cons *ImageConstraint) ([]*ImageMetadata, *simplestreams.ResolveInfo, error) {
params := simplestreams.GetMetadataParams{
StreamsVersion: currentStreamsVersion,
LookupConstraint: cons,
Expand All @@ -233,7 +231,8 @@ func Fetch(
ValueTemplate: ImageMetadata{},
},
}
items, resolveInfo, err := simplestreams.GetMetadata(simplestreams.DefaultDataSourceFactory(), sources, params)
ss := simplestreams.NewSimpleStreams(simplestreams.DefaultDataSourceFactory())
items, resolveInfo, err := ss.GetMetadata(sources, params)
if err != nil {
return nil, resolveInfo, err
}
Expand Down
76 changes: 49 additions & 27 deletions environs/simplestreams/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ func (p LookupParams) Params() LookupParams {
// Not every model attribute is defined here, only the ones we care about.
// See the doc/README file in lp:simplestreams for more information.

// Metadata attribute values may point to a map of attribute values (aka aliases) and these attributes
// are used to override/augment the existing attributes.
// Metadata attribute values may point to a map of attribute values (aka
// aliases) and these attributes are used to override/augment the existing
// attributes.
type attributeValues map[string]string
type aliasesByAttribute map[string]attributeValues

Expand Down Expand Up @@ -307,9 +308,10 @@ func (entries IndexMetadataSlice) filter(match func(*IndexMetadata) bool) IndexM
return result
}

// noMatchingProductsError is used to indicate that metadata files have been located,
// but there is no metadata satisfying a product criteria.
// It is used to distinguish from the situation where the metadata files could not be found.
// noMatchingProductsError is used to indicate that metadata files have been
// located, but there is no metadata satisfying a product criteria.
// It is used to distinguish from the situation where the metadata files could
// not be found.
type noMatchingProductsError struct {
msg string
}
Expand Down Expand Up @@ -337,7 +339,8 @@ const (
SignedSuffix = ".sjson"
UnsignedSuffix = ".json"

// These constants define the currently supported simplestreams data formats.
// These constants define the currently supported simplestreams data
// formats.
IndexFormat = "index:1.0"
ProductFormat = "products:1.0"
MirrorFormat = "mirrors:1.0"
Expand All @@ -348,7 +351,8 @@ const (
// returned interface slice.
type AppendMatchingFunc func(DataSource, []interface{}, map[string]interface{}, LookupConstraint) ([]interface{}, error)

// ValueParams contains the information required to pull out from the metadata structs of a particular type.
// ValueParams contains the information required to pull out from the metadata
// structs of a particular type.
type ValueParams struct {
// The simplestreams data type key.
DataType string
Expand Down Expand Up @@ -379,24 +383,44 @@ func UnsignedMirror(streamsVersion string) string {
return fmt.Sprintf(unsignedMirror, streamsVersion)
}

// Simplestreams defines a type for encapsulating the functionality for
// requesting simplestreams data.
//
// TODO (stickupkid): This requires more work. The idea is to localize all
// package level functions up on to this type. Passing the type through layers
// becomes simple.
type Simplestreams struct {
factory DataSourceFactory
}

// NewSimpleStreams creates a new simplestreams accessor.
func NewSimpleStreams(factory DataSourceFactory) *Simplestreams {
return &Simplestreams{
factory: factory,
}
}

// GetMetadataParams defines parameters used to load simplestreams metadata.
type GetMetadataParams struct {
StreamsVersion string
LookupConstraint LookupConstraint
ValueParams ValueParams
}

// GetMetadata returns metadata records matching the specified constraint,looking in each source for signed metadata.
// If onlySigned is false and no signed metadata is found in a source, the source is used to look for unsigned metadata.
// Each source is tried in turn until at least one signed (or unsigned) match is found.
func GetMetadata(factory DataSourceFactory, sources []DataSource, params GetMetadataParams) (items []interface{}, resolveInfo *ResolveInfo, err error) {
// GetMetadata returns metadata records matching the specified constraint,
// looking in each source for signed metadata. If onlySigned is false and no
// signed metadata is found in a source, the source is used to look for
// unsigned metadata.
// Each source is tried in turn until at least one signed (or unsigned) match
// is found.
func (s Simplestreams) GetMetadata(sources []DataSource, params GetMetadataParams) (items []interface{}, resolveInfo *ResolveInfo, err error) {
for _, source := range sources {
logger.Tracef("searching for signed metadata in datasource %q", source.Description())
items, resolveInfo, err = getMaybeSignedMetadata(factory, source, params, true)
items, resolveInfo, err = s.getMaybeSignedMetadata(source, params, true)
// If no items are found using signed metadata, check unsigned.
if err != nil && len(items) == 0 && !source.RequireSigned() {
logger.Tracef("falling back to search for unsigned metadata in datasource %q", source.Description())
items, resolveInfo, err = getMaybeSignedMetadata(factory, source, params, false)
items, resolveInfo, err = s.getMaybeSignedMetadata(source, params, false)
}
if err == nil {
break
Expand All @@ -410,7 +434,7 @@ func GetMetadata(factory DataSourceFactory, sources []DataSource, params GetMeta
}

// getMaybeSignedMetadata returns metadata records matching the specified constraint in params.
func getMaybeSignedMetadata(factory DataSourceFactory, source DataSource, params GetMetadataParams, signed bool) ([]interface{}, *ResolveInfo, error) {
func (s Simplestreams) getMaybeSignedMetadata(source DataSource, params GetMetadataParams, signed bool) ([]interface{}, *ResolveInfo, error) {

makeIndexPath := func(basePath string) string {
pathNoSuffix := fmt.Sprintf(basePath, params.StreamsVersion)
Expand All @@ -430,8 +454,7 @@ func getMaybeSignedMetadata(factory DataSourceFactory, source DataSource, params
mirrorsPath := fmt.Sprintf(defaultMirrorsPath, params.StreamsVersion)
cons := params.LookupConstraint

indexRef, indexURL, err := fetchIndex(
factory,
indexRef, indexURL, err := s.fetchIndex(
source,
indexPath,
mirrorsPath,
Expand All @@ -446,8 +469,7 @@ func getMaybeSignedMetadata(factory DataSourceFactory, source DataSource, params
logger.Tracef("%s not accessed, trying legacy index path: %s", indexPath, legacyIndexPath)

indexPath = legacyIndexPath
indexRef, indexURL, err = fetchIndex(
factory,
indexRef, indexURL, err = s.fetchIndex(
source,
indexPath,
mirrorsPath,
Expand Down Expand Up @@ -481,16 +503,16 @@ func getMaybeSignedMetadata(factory DataSourceFactory, source DataSource, params
}

// fetchIndex attempts to load the index file at indexPath in source.
func fetchIndex(factory DataSourceFactory, source DataSource, indexPath string, mirrorsPath string, cloudSpec CloudSpec,
func (s Simplestreams) fetchIndex(source DataSource, indexPath string, mirrorsPath string, cloudSpec CloudSpec,
signed bool, params ValueParams) (indexRef *IndexReference, indexURL string, _ error) {
indexURL, err := source.URL(indexPath)
if err != nil {
// Some providers return an error if asked for the URL of a non-existent file.
// So the best we can do is use the relative path for the URL when logging messages.
// Some providers return an error if asked for the URL of a non-existent
// file. The best we can do is use the relative path for the URL when
// logging messages.
indexURL = indexPath
}
indexRef, err = GetIndexWithFormat(
factory,
indexRef, err = s.GetIndexWithFormat(
source,
indexPath, IndexFormat,
mirrorsPath,
Expand All @@ -501,7 +523,8 @@ func fetchIndex(factory DataSourceFactory, source DataSource, indexPath string,
return indexRef, indexURL, err
}

// fetchData gets all the data from the given source located at the specified path.
// fetchData gets all the data from the given source located at the specified
// path.
// It returns the data found and the full URL used.
func fetchData(source DataSource, path string, requireSigned bool) (data []byte, dataURL string, err error) {
rc, dataURL, err := source.Fetch(path)
Expand Down Expand Up @@ -541,7 +564,7 @@ func (defaultDataSourceFactory) NewDataSource(cfg Config) DataSource {

// GetIndexWithFormat returns a simplestreams index of the specified format.
// Exported for testing.
func GetIndexWithFormat(factory DataSourceFactory, source DataSource,
func (s Simplestreams) GetIndexWithFormat(source DataSource,
indexPath, indexFormat, mirrorsPath string, requireSigned bool,
cloudSpec CloudSpec, params ValueParams) (*IndexReference, error) {

Expand Down Expand Up @@ -580,7 +603,7 @@ func GetIndexWithFormat(factory DataSourceFactory, source DataSource,
source, mirrors, params.DataType, params.MirrorContentId, cloudSpec, requireSigned)
if err == nil {
logger.Debugf("using mirrored products path: %s", path.Join(mirrorInfo.MirrorURL, mirrorInfo.Path))
indexRef.Source = factory.NewDataSource(Config{
indexRef.Source = s.factory.NewDataSource(Config{
Description: "mirror",
BaseURL: mirrorInfo.MirrorURL,
PublicSigningKey: source.PublicSigningKey(),
Expand All @@ -599,7 +622,6 @@ func GetIndexWithFormat(factory DataSourceFactory, source DataSource,

// getMirrorRefs parses and returns a simplestreams mirror reference.
func getMirrorRefs(source DataSource, baseMirrorsPath string, requireSigned bool) (MirrorRefs, string, error) {

mirrorsPath := baseMirrorsPath + UnsignedSuffix
if requireSigned {
mirrorsPath = baseMirrorsPath + SignedSuffix
Expand Down
7 changes: 4 additions & 3 deletions environs/simplestreams/simplestreams_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ func (s *simplestreamsSuite) TestGetMetadataNoMatching(c *gc.C) {
ValueParams: simplestreams.ValueParams{DataType: "image-ids"},
}

items, resolveInfo, err := simplestreams.GetMetadata(sstesting.TestDataSourceFactory(), sources, params)
ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
items, resolveInfo, err := ss.GetMetadata(sources, params)
c.Assert(err, jc.ErrorIsNil)
c.Assert(items, gc.HasLen, 0)
c.Assert(resolveInfo, gc.DeepEquals, &simplestreams.ResolveInfo{
Expand Down Expand Up @@ -493,8 +494,8 @@ func (s *simplestreamsSuite) TestGetMirrorMetadata(c *gc.C) {
DataType: "content-download",
MirrorContentId: "com.ubuntu.juju:released:agents",
}
indexRef, err := simplestreams.GetIndexWithFormat(
sstesting.TestDataSourceFactory(),
ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
indexRef, err := ss.GetIndexWithFormat(
s.Source, s.IndexPath(), sstesting.Index_v1,
simplestreams.MirrorsPath("v1"), s.RequireSigned, cloud, params)
if !c.Check(err, jc.ErrorIsNil) {
Expand Down
4 changes: 2 additions & 2 deletions environs/simplestreams/testing/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,8 @@ func (s *LocalLiveSimplestreamsSuite) GetIndexRef(format string) (*simplestreams
DataType: s.DataType,
ValueTemplate: TestItem{},
}
return simplestreams.GetIndexWithFormat(
TestDataSourceFactory(),
ss := simplestreams.NewSimpleStreams(TestDataSourceFactory())
return ss.GetIndexWithFormat(
s.Source, s.IndexPath(),
format,
simplestreams.MirrorsPath(s.StreamsVersion),
Expand Down
3 changes: 2 additions & 1 deletion environs/tools/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ func Fetch(factory simplestreams.DataSourceFactory,
ValueTemplate: ToolsMetadata{},
},
}
items, resolveInfo, err := simplestreams.GetMetadata(factory, sources, params)
ss := simplestreams.NewSimpleStreams(factory)
items, resolveInfo, err := ss.GetMetadata(sources, params)
if err != nil {
return nil, nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion provider/vsphere/image_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ func imageMetadataFetch(sources []simplestreams.DataSource, cons *imagemetadata.
ValueTemplate: OvaFileMetadata{},
},
}
items, _, err := simplestreams.GetMetadata(simplestreams.DefaultDataSourceFactory(), sources, params)
ss := simplestreams.NewSimpleStreams(simplestreams.DefaultDataSourceFactory())
items, _, err := ss.GetMetadata(sources, params)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down

0 comments on commit 6a3173a

Please sign in to comment.