github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/environs/tools/marshal.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // The tools package supports locating, parsing, and filtering Ubuntu tools metadata in simplestreams format. 5 // See http://launchpad.net/simplestreams and in particular the doc/README file in that project for more information 6 // about the file formats. 7 package tools 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "time" 13 14 "github.com/juju/collections/set" 15 "github.com/juju/os/series" 16 17 "github.com/juju/juju/environs/simplestreams" 18 ) 19 20 // ToolsContentId returns the tools content id for the given stream. 21 func ToolsContentId(stream string) string { 22 return fmt.Sprintf("com.ubuntu.juju:%s:tools", stream) 23 } 24 25 // ProductMetadataPath returns the tools product metadata path for the given stream. 26 func ProductMetadataPath(stream string) string { 27 return fmt.Sprintf("streams/v1/com.ubuntu.juju-%s-tools.json", stream) 28 } 29 30 // MarshalToolsMetadataJSON marshals tools metadata to index and products JSON. 31 // updated is the time at which the JSON file was updated. 32 func MarshalToolsMetadataJSON(metadata map[string][]*ToolsMetadata, updated time.Time) (index, legacyIndex []byte, products map[string][]byte, err error) { 33 if index, legacyIndex, err = marshalToolsMetadataIndexJSON(metadata, updated); err != nil { 34 return nil, nil, nil, err 35 } 36 if products, err = MarshalToolsMetadataProductsJSON(metadata, updated); err != nil { 37 return nil, nil, nil, err 38 } 39 return index, legacyIndex, products, err 40 } 41 42 // marshalToolsMetadataIndexJSON marshals tools metadata to index JSON. 43 // updated is the time at which the JSON file was updated. 44 func marshalToolsMetadataIndexJSON(streamMetadata map[string][]*ToolsMetadata, updated time.Time) (out, outlegacy []byte, err error) { 45 var indices simplestreams.Indices 46 indices.Updated = updated.Format(time.RFC1123Z) 47 indices.Format = simplestreams.IndexFormat 48 indices.Indexes = make(map[string]*simplestreams.IndexMetadata, len(streamMetadata)) 49 50 var indicesLegacy simplestreams.Indices 51 indicesLegacy.Updated = updated.Format(time.RFC1123Z) 52 indicesLegacy.Format = simplestreams.IndexFormat 53 54 for stream, metadata := range streamMetadata { 55 var productIds []string 56 for _, t := range metadata { 57 id, err := t.productId() 58 if err != nil { 59 if series.IsUnknownSeriesVersionError(err) { 60 logger.Infof("ignoring tools metadata with unknown series %q", t.Release) 61 continue 62 } 63 return nil, nil, err 64 } 65 productIds = append(productIds, id) 66 } 67 indexMetadata := &simplestreams.IndexMetadata{ 68 Updated: indices.Updated, 69 Format: simplestreams.ProductFormat, 70 DataType: ContentDownload, 71 ProductsFilePath: ProductMetadataPath(stream), 72 ProductIds: set.NewStrings(productIds...).SortedValues(), 73 } 74 indices.Indexes[ToolsContentId(stream)] = indexMetadata 75 if stream == ReleasedStream { 76 indicesLegacy.Indexes = make(map[string]*simplestreams.IndexMetadata, 1) 77 indicesLegacy.Indexes[ToolsContentId(stream)] = indexMetadata 78 } 79 } 80 out, err = json.MarshalIndent(&indices, "", " ") 81 if len(indicesLegacy.Indexes) == 0 { 82 return out, nil, err 83 } 84 outlegacy, err = json.MarshalIndent(&indicesLegacy, "", " ") 85 if err != nil { 86 return nil, nil, err 87 } 88 return out, outlegacy, nil 89 } 90 91 // MarshalToolsMetadataProductsJSON marshals tools metadata to products JSON. 92 // updated is the time at which the JSON file was updated. 93 func MarshalToolsMetadataProductsJSON( 94 streamMetadata map[string][]*ToolsMetadata, updated time.Time, 95 ) (out map[string][]byte, err error) { 96 97 out = make(map[string][]byte, len(streamMetadata)) 98 for stream, metadata := range streamMetadata { 99 var cloud simplestreams.CloudMetadata 100 cloud.Updated = updated.Format(time.RFC1123Z) 101 cloud.Format = simplestreams.ProductFormat 102 cloud.ContentId = ToolsContentId(stream) 103 cloud.Products = make(map[string]simplestreams.MetadataCatalog) 104 itemsversion := updated.Format("20060102") // YYYYMMDD 105 for _, t := range metadata { 106 id, err := t.productId() 107 if err != nil { 108 if series.IsUnknownSeriesVersionError(err) { 109 continue 110 } 111 return nil, err 112 } 113 itemid := fmt.Sprintf("%s-%s-%s", t.Version, t.Release, t.Arch) 114 if catalog, ok := cloud.Products[id]; ok { 115 catalog.Items[itemsversion].Items[itemid] = t 116 } else { 117 catalog = simplestreams.MetadataCatalog{ 118 Arch: t.Arch, 119 Version: t.Version, 120 Items: map[string]*simplestreams.ItemCollection{ 121 itemsversion: { 122 Items: map[string]interface{}{itemid: t}, 123 }, 124 }, 125 } 126 cloud.Products[id] = catalog 127 } 128 } 129 if out[stream], err = json.MarshalIndent(&cloud, "", " "); err != nil { 130 return nil, err 131 } 132 } 133 return out, nil 134 }