github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/environs/gui/simplestreams.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package gui
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/utils"
    12  	"github.com/juju/version"
    13  
    14  	"github.com/juju/juju/environs/simplestreams"
    15  	"github.com/juju/juju/juju"
    16  	jujuversion "github.com/juju/juju/version"
    17  )
    18  
    19  const (
    20  	// DefaultBaseURL holds the default simplestreams data source URL from
    21  	// where to retrieve Juju GUI archives.
    22  	DefaultBaseURL = "https://streams.canonical.com/juju/gui"
    23  	// ReleasedStream and DevelStreams hold stream names to use when fetching
    24  	// Juju GUI archives.
    25  	ReleasedStream = "released"
    26  	DevelStream    = "devel"
    27  
    28  	downloadType      = "content-download"
    29  	sourceDescription = "gui simplestreams"
    30  	streamsVersion    = "v1"
    31  )
    32  
    33  func init() {
    34  	simplestreams.RegisterStructTags(Metadata{})
    35  }
    36  
    37  // DataSource creates and returns a new simplestreams signed data source for
    38  // fetching Juju GUI archives, at the given URL.
    39  func NewDataSource(baseURL string) simplestreams.DataSource {
    40  	requireSigned := true
    41  	return simplestreams.NewURLSignedDataSource(
    42  		sourceDescription,
    43  		baseURL,
    44  		juju.JujuPublicKey,
    45  		utils.VerifySSLHostnames,
    46  		simplestreams.DEFAULT_CLOUD_DATA,
    47  		requireSigned)
    48  }
    49  
    50  // FetchMetadata fetches and returns Juju GUI metadata from simplestreams,
    51  // sorted by version descending.
    52  func FetchMetadata(stream string, sources ...simplestreams.DataSource) ([]*Metadata, error) {
    53  	params := simplestreams.GetMetadataParams{
    54  		StreamsVersion: streamsVersion,
    55  		LookupConstraint: &constraint{
    56  			LookupParams: simplestreams.LookupParams{Stream: stream},
    57  			majorVersion: jujuversion.Current.Major,
    58  		},
    59  		ValueParams: simplestreams.ValueParams{
    60  			DataType:        downloadType,
    61  			MirrorContentId: contentId(stream),
    62  			FilterFunc:      appendArchives,
    63  			ValueTemplate:   Metadata{},
    64  		},
    65  	}
    66  	items, _, err := simplestreams.GetMetadata(sources, params)
    67  	if err != nil {
    68  		return nil, errors.Annotate(err, "error fetching simplestreams metadata")
    69  	}
    70  	allMeta := make([]*Metadata, len(items))
    71  	for i, item := range items {
    72  		allMeta[i] = item.(*Metadata)
    73  	}
    74  	sort.Sort(byVersion(allMeta))
    75  	return allMeta, nil
    76  }
    77  
    78  // Metadata is the type used to retrieve GUI archive metadata information from
    79  // simplestream. Tags for this structure are registered in init().
    80  type Metadata struct {
    81  	Size   int64  `json:"size"`
    82  	SHA256 string `json:"sha256"`
    83  	Path   string `json:"path"`
    84  
    85  	JujuMajorVersion int    `json:"juju-version"`
    86  	StringVersion    string `json:"version"`
    87  
    88  	Version  version.Number           `json:"-"`
    89  	FullPath string                   `json:"-"`
    90  	Source   simplestreams.DataSource `json:"-"`
    91  }
    92  
    93  // byVersion is used to sort GUI metadata by version, most recent first.
    94  type byVersion []*Metadata
    95  
    96  // Len implements sort.Interface.
    97  func (b byVersion) Len() int { return len(b) }
    98  
    99  // Swap implements sort.Interface.
   100  func (b byVersion) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
   101  
   102  // Less implements sort.Interface.
   103  func (b byVersion) Less(i, j int) bool { return b[i].Version.Compare(b[j].Version) > 0 }
   104  
   105  // constraint is used as simplestreams.LookupConstraint when retrieving Juju
   106  // GUI metadata information.
   107  type constraint struct {
   108  	simplestreams.LookupParams
   109  	majorVersion int
   110  }
   111  
   112  // IndexIds generates a string array representing index ids formed similarly to
   113  // an ISCSI qualified name (IQN).
   114  func (c *constraint) IndexIds() []string {
   115  	return []string{contentId(c.Stream)}
   116  }
   117  
   118  // ProductIds generates a string array representing product ids formed
   119  // similarly to an ISCSI qualified name (IQN).
   120  func (c *constraint) ProductIds() ([]string, error) {
   121  	return []string{"com.canonical.streams:gui"}, nil
   122  }
   123  
   124  // contentId returns the GUI content id in simplestreams for the given stream.
   125  func contentId(stream string) string {
   126  	return fmt.Sprintf("com.canonical.streams:%s:gui", stream)
   127  }
   128  
   129  // appendArchives collects all matching Juju GUI archive metadata information.
   130  func appendArchives(
   131  	source simplestreams.DataSource,
   132  	matchingItems []interface{},
   133  	items map[string]interface{},
   134  	cons simplestreams.LookupConstraint,
   135  ) ([]interface{}, error) {
   136  	var majorVersion int
   137  	if guiConstraint, ok := cons.(*constraint); ok {
   138  		majorVersion = guiConstraint.majorVersion
   139  	}
   140  	for _, item := range items {
   141  		meta := item.(*Metadata)
   142  		if majorVersion != 0 && majorVersion != meta.JujuMajorVersion {
   143  			continue
   144  		}
   145  		fullPath, err := source.URL(meta.Path)
   146  		if err != nil {
   147  			return nil, errors.Annotate(err, "cannot retrieve metadata full path")
   148  		}
   149  		meta.FullPath = fullPath
   150  		vers, err := version.Parse(meta.StringVersion)
   151  		if err != nil {
   152  			return nil, errors.Annotate(err, "cannot parse metadata version")
   153  		}
   154  		meta.Version = vers
   155  		meta.Source = source
   156  		matchingItems = append(matchingItems, meta)
   157  	}
   158  	return matchingItems, nil
   159  }