launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/tools/boilerplate.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package tools 5 6 import ( 7 "bytes" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "text/template" 13 "time" 14 15 "launchpad.net/juju-core/environs/simplestreams" 16 "launchpad.net/juju-core/juju/osenv" 17 ) 18 19 const ( 20 defaultIndexFileName = "index.json" 21 defaultToolsFileName = "toolsmetadata.json" 22 streamsDir = "streams/v1" 23 ) 24 25 // Boilerplate generates some basic simplestreams metadata using the specified cloud and tools details. 26 func Boilerplate(tm *ToolsMetadata, cloudSpec *simplestreams.CloudSpec) ([]string, error) { 27 return MakeBoilerplate(tm, cloudSpec, true) 28 } 29 30 // MakeBoilerplate exists so it can be called by tests. See Boilerplate above. It provides an option to retain 31 // the streams directories when writing the generated metadata files. 32 func MakeBoilerplate(tm *ToolsMetadata, cloudSpec *simplestreams.CloudSpec, flattenPath bool) ([]string, error) { 33 indexFileName := defaultIndexFileName 34 toolsFileName := defaultToolsFileName 35 now := time.Now() 36 imparams := toolsMetadataParams{ 37 ToolsBinarySize: tm.Size, 38 ToolsBinaryPath: tm.Path, 39 ToolsBinarySHA256: tm.SHA256, 40 Version: tm.Version, 41 Arch: tm.Arch, 42 Series: tm.Release, 43 Region: cloudSpec.Region, 44 URL: cloudSpec.Endpoint, 45 Path: streamsDir, 46 ToolsFileName: toolsFileName, 47 Updated: now.Format(time.RFC1123Z), 48 VersionKey: now.Format("20060102"), 49 } 50 51 var err error 52 imparams.SeriesVersion, err = simplestreams.SeriesVersion(tm.Release) 53 if err != nil { 54 return nil, fmt.Errorf("invalid series %q", tm.Release) 55 } 56 57 if !flattenPath { 58 streamsPath := osenv.JujuHomePath(streamsDir) 59 if err := os.MkdirAll(streamsPath, 0755); err != nil { 60 return nil, err 61 } 62 indexFileName = filepath.Join(streamsDir, indexFileName) 63 toolsFileName = filepath.Join(streamsDir, toolsFileName) 64 } 65 err = writeJsonFile(imparams, indexFileName, indexBoilerplate) 66 if err != nil { 67 return nil, err 68 } 69 err = writeJsonFile(imparams, toolsFileName, productBoilerplate) 70 if err != nil { 71 return nil, err 72 } 73 return []string{indexFileName, toolsFileName}, nil 74 } 75 76 type toolsMetadataParams struct { 77 ToolsBinaryPath string 78 ToolsBinarySize int64 79 ToolsBinarySHA256 string 80 Region string 81 URL string 82 Updated string 83 Arch string 84 Path string 85 Series string 86 SeriesVersion string 87 Version string 88 VersionKey string 89 ToolsFileName string 90 } 91 92 func writeJsonFile(imparams toolsMetadataParams, filename, boilerplate string) error { 93 t := template.Must(template.New("").Parse(boilerplate)) 94 var metadata bytes.Buffer 95 if err := t.Execute(&metadata, imparams); err != nil { 96 panic(fmt.Errorf("cannot generate %s metdata: %v", filename, err)) 97 } 98 data := metadata.Bytes() 99 path := osenv.JujuHomePath(filename) 100 if err := ioutil.WriteFile(path, data, 0666); err != nil { 101 return err 102 } 103 return nil 104 } 105 106 var indexBoilerplate = ` 107 { 108 "index": { 109 "com.ubuntu.juju:custom": { 110 "updated": "{{.Updated}}", 111 "cloudname": "custom", 112 "datatype": "content-download", 113 "format": "products:1.0", 114 "products": [ 115 "com.ubuntu.juju:{{.SeriesVersion}}:{{.Arch}}" 116 ], 117 "path": "{{.Path}}/{{.ToolsFileName}}" 118 } 119 }, 120 "updated": "{{.Updated}}", 121 "format": "index:1.0" 122 } 123 ` 124 125 var productBoilerplate = ` 126 { 127 "content_id": "com.ubuntu.juju:custom", 128 "format": "products:1.0", 129 "updated": "{{.Updated}}", 130 "datatype": "content-download", 131 "products": { 132 "com.ubuntu.juju:{{.SeriesVersion}}:{{.Arch}}": { 133 "release": "{{.Series}}", 134 "arch": "{{.Arch}}", 135 "versions": { 136 "{{.VersionKey}}": { 137 "items": { 138 "{{.Series}}{{.Version}}": { 139 "version": "{{.Version}}", 140 "size": {{.ToolsBinarySize}}, 141 "path": "{{.ToolsBinaryPath}}", 142 "ftype": "tar.gz", 143 "sha256": "{{.ToolsBinarySHA256}}" 144 } 145 }, 146 "pubname": "juju-{{.Series}}-{{.Arch}}-{{.VersionKey}}", 147 "label": "custom" 148 } 149 } 150 } 151 } 152 } 153 `