github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/plugins/juju-metadata/toolsmetadata.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/loggo" 11 "github.com/juju/utils" 12 "launchpad.net/gnuflag" 13 14 "github.com/juju/juju/cmd/envcmd" 15 "github.com/juju/juju/environs/filestorage" 16 "github.com/juju/juju/environs/simplestreams" 17 "github.com/juju/juju/environs/storage" 18 envtools "github.com/juju/juju/environs/tools" 19 "github.com/juju/juju/juju/osenv" 20 coretools "github.com/juju/juju/tools" 21 "github.com/juju/juju/version" 22 ) 23 24 // ToolsMetadataCommand is used to generate simplestreams metadata for juju tools. 25 type ToolsMetadataCommand struct { 26 envcmd.EnvCommandBase 27 fetch bool 28 metadataDir string 29 stream string 30 clean bool 31 public bool 32 } 33 34 var toolsMetadataDoc = ` 35 generate-tools creates simplestreams tools metadata. 36 37 This command works by scanning a directory for tools tarballs from which to generate 38 simplestreams tools metadata. The working directory is specified using the -d argument 39 (defaults to ~/.juju). The working directory is expected to contain a named subdirectory 40 containing tools tarballs, and is where the resulting metadata is written. 41 42 The stream for which metadata is generated is specified using the --stream parameter 43 (default is "released"). Metadata can be generated for any supported stream - released, 44 proposed, testing, devel. 45 46 Tools tarballs can are located in either a sub directory called "releases" (legacy), 47 or a directory named after the stream. By default, if no --stream argument is provided, 48 metadata for tools in the "released" stream is generated by scanning for tool tarballs 49 in the "releases" directory. By specifying a stream explcitly, tools tarballs are 50 expected to be located in a directory named after the stream. 51 52 Newly generated metadata will be merged with any exisitng metadata that is already there. 53 To first remove metadata for the specified stream before generating new metadata, 54 use the --clean option. 55 56 Examples: 57 58 - generate metadata for "released" tools, looking in the "releases" directory: 59 60 juju metadata generate-tools -d <workingdir> 61 62 - generate metadata for "released" tools, looking in the "released" directory: 63 64 juju metadata generate-tools -d <workingdir> --stream released 65 66 - generate metadata for "proposed" tools, looking in the "proposed" directory: 67 68 juju metadata generate-tools -d <workingdir> --stream proposed 69 70 - generate metadata for "proposed" tools, first removing existing "proposed" metadata: 71 72 juju metadata generate-tools -d <workingdir> --stream proposed --clean 73 74 ` 75 76 func (c *ToolsMetadataCommand) Info() *cmd.Info { 77 return &cmd.Info{ 78 Name: "generate-tools", 79 Purpose: "generate simplestreams tools metadata", 80 Doc: toolsMetadataDoc, 81 } 82 } 83 84 func (c *ToolsMetadataCommand) SetFlags(f *gnuflag.FlagSet) { 85 f.StringVar(&c.metadataDir, "d", "", "local directory in which to store metadata") 86 // If no stream is specified, we'll generate metadata for the legacy tools location. 87 f.StringVar(&c.stream, "stream", "", "simplestreams stream for which to generate the metadata") 88 f.BoolVar(&c.clean, "clean", false, "remove any existing metadata for the specified stream before generating new metadata") 89 f.BoolVar(&c.public, "public", false, "tools are for a public cloud, so generate mirrors information") 90 } 91 92 func (c *ToolsMetadataCommand) Run(context *cmd.Context) error { 93 loggo.RegisterWriter("toolsmetadata", cmd.NewCommandLogWriter("juju.environs.tools", context.Stdout, context.Stderr), loggo.INFO) 94 defer loggo.RemoveWriter("toolsmetadata") 95 if c.metadataDir == "" { 96 c.metadataDir = osenv.JujuHome() 97 } else { 98 c.metadataDir = context.AbsPath(c.metadataDir) 99 } 100 101 sourceStorage, err := filestorage.NewFileStorageReader(c.metadataDir) 102 if err != nil { 103 return err 104 } 105 106 // We now store the tools in a directory named after their stream, but the 107 // legacy behaviour is to store all tools in a single "releases" directory. 108 toolsDir := c.stream 109 if c.stream == "" { 110 fmt.Fprintf(context.Stdout, "No stream specified, defaulting to released tools in the releases directory.\n") 111 c.stream = envtools.ReleasedStream 112 toolsDir = envtools.LegacyReleaseDirectory 113 } 114 fmt.Fprintf(context.Stdout, "Finding tools in %s for stream %s.\n", c.metadataDir, c.stream) 115 const minorVersion = -1 116 toolsList, err := envtools.ReadList(sourceStorage, toolsDir, version.Current.Major, minorVersion) 117 if err == envtools.ErrNoTools { 118 var source string 119 source, err = envtools.ToolsURL(envtools.DefaultBaseURL) 120 if err != nil { 121 return err 122 } 123 sourceDataSource := simplestreams.NewURLDataSource("local source", source, utils.VerifySSLHostnames) 124 toolsList, err = envtools.FindToolsForCloud( 125 []simplestreams.DataSource{sourceDataSource}, simplestreams.CloudSpec{}, c.stream, 126 version.Current.Major, minorVersion, coretools.Filter{}) 127 } 128 if err != nil { 129 return err 130 } 131 132 targetStorage, err := filestorage.NewFileStorageWriter(c.metadataDir) 133 if err != nil { 134 return err 135 } 136 writeMirrors := envtools.DoNotWriteMirrors 137 if c.public { 138 writeMirrors = envtools.WriteMirrors 139 } 140 return mergeAndWriteMetadata(targetStorage, toolsDir, c.stream, c.clean, toolsList, writeMirrors) 141 } 142 143 // This is essentially the same as tools.MergeAndWriteMetadata, but also 144 // resolves metadata for existing tools by fetching them and computing 145 // size/sha256 locally. 146 func mergeAndWriteMetadata( 147 stor storage.Storage, toolsDir, stream string, clean bool, toolsList coretools.List, writeMirrors envtools.ShouldWriteMirrors, 148 ) error { 149 existing, err := envtools.ReadAllMetadata(stor) 150 if err != nil { 151 return err 152 } 153 if clean { 154 delete(existing, stream) 155 } 156 metadata := envtools.MetadataFromTools(toolsList, toolsDir) 157 var mergedMetadata []*envtools.ToolsMetadata 158 if mergedMetadata, err = envtools.MergeMetadata(metadata, existing[stream]); err != nil { 159 return err 160 } 161 if err = envtools.ResolveMetadata(stor, toolsDir, mergedMetadata); err != nil { 162 return err 163 } 164 existing[stream] = mergedMetadata 165 return envtools.WriteMetadata(stor, existing, []string{stream}, writeMirrors) 166 }