~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/plugins/juju-metadata/toolsmetadata.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/modelcmd"
 
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/keys"
 
20
        "github.com/juju/juju/juju/osenv"
 
21
        coretools "github.com/juju/juju/tools"
 
22
)
 
23
 
 
24
func newToolsMetadataCommand() cmd.Command {
 
25
        return modelcmd.Wrap(&toolsMetadataCommand{})
 
26
}
 
27
 
 
28
// toolsMetadataCommand is used to generate simplestreams metadata for juju tools.
 
29
type toolsMetadataCommand struct {
 
30
        modelcmd.ModelCommandBase
 
31
        fetch       bool
 
32
        metadataDir string
 
33
        stream      string
 
34
        clean       bool
 
35
        public      bool
 
36
}
 
37
 
 
38
var toolsMetadataDoc = `
 
39
generate-tools creates simplestreams tools metadata.
 
40
 
 
41
This command works by scanning a directory for tools tarballs from which to generate
 
42
simplestreams tools metadata. The working directory is specified using the -d argument
 
43
(defaults to $JUJU_DATA or if not defined $XDG_DATA_HOME/juju or if that is not defined
 
44
~/.local/share/juju). The working directory is expected to contain a named subdirectory
 
45
containing tools tarballs, and is where the resulting metadata is written.
 
46
 
 
47
The stream for which metadata is generated is specified using the --stream parameter
 
48
(default is "released"). Metadata can be generated for any supported stream - released,
 
49
proposed, testing, devel.
 
50
 
 
51
Tools tarballs can are located in either a sub directory called "releases" (legacy),
 
52
or a directory named after the stream. By default, if no --stream argument is provided,
 
53
metadata for tools in the "released" stream is generated by scanning for tool tarballs
 
54
in the "releases" directory. By specifying a stream explcitly, tools tarballs are
 
55
expected to be located in a directory named after the stream.
 
56
 
 
57
Newly generated metadata will be merged with any exisitng metadata that is already there.
 
58
To first remove metadata for the specified stream before generating new metadata,
 
59
use the --clean option.
 
60
 
 
61
Examples:
 
62
 
 
63
  - generate metadata for "released" tools, looking in the "releases" directory:
 
64
 
 
65
   juju metadata generate-tools -d <workingdir>
 
66
 
 
67
  - generate metadata for "released" tools, looking in the "released" directory:
 
68
 
 
69
   juju metadata generate-tools -d <workingdir> --stream released
 
70
 
 
71
  - generate metadata for "proposed" tools, looking in the "proposed" directory:
 
72
 
 
73
   juju metadata generate-tools -d <workingdir> --stream proposed
 
74
 
 
75
  - generate metadata for "proposed" tools, first removing existing "proposed" metadata:
 
76
 
 
77
   juju metadata generate-tools -d <workingdir> --stream proposed --clean
 
78
 
 
79
`
 
80
 
 
81
func (c *toolsMetadataCommand) Info() *cmd.Info {
 
82
        return &cmd.Info{
 
83
                Name:    "generate-tools",
 
84
                Purpose: "generate simplestreams tools metadata",
 
85
                Doc:     toolsMetadataDoc,
 
86
        }
 
87
}
 
88
 
 
89
func (c *toolsMetadataCommand) SetFlags(f *gnuflag.FlagSet) {
 
90
        f.StringVar(&c.metadataDir, "d", "", "local directory in which to store metadata")
 
91
        // If no stream is specified, we'll generate metadata for the legacy tools location.
 
92
        f.StringVar(&c.stream, "stream", "", "simplestreams stream for which to generate the metadata")
 
93
        f.BoolVar(&c.clean, "clean", false, "remove any existing metadata for the specified stream before generating new metadata")
 
94
        f.BoolVar(&c.public, "public", false, "tools are for a public cloud, so generate mirrors information")
 
95
}
 
96
 
 
97
func (c *toolsMetadataCommand) Run(context *cmd.Context) error {
 
98
        writer := loggo.NewMinimumLevelWriter(
 
99
                cmd.NewCommandLogWriter("juju.environs.tools", context.Stdout, context.Stderr),
 
100
                loggo.INFO)
 
101
        loggo.RegisterWriter("toolsmetadata", writer)
 
102
        defer loggo.RemoveWriter("toolsmetadata")
 
103
        if c.metadataDir == "" {
 
104
                c.metadataDir = osenv.JujuXDGDataHome()
 
105
        } else {
 
106
                c.metadataDir = context.AbsPath(c.metadataDir)
 
107
        }
 
108
 
 
109
        sourceStorage, err := filestorage.NewFileStorageReader(c.metadataDir)
 
110
        if err != nil {
 
111
                return err
 
112
        }
 
113
 
 
114
        // We now store the tools in a directory named after their stream, but the
 
115
        // legacy behaviour is to store all tools in a single "releases" directory.
 
116
        toolsDir := c.stream
 
117
        if c.stream == "" {
 
118
                fmt.Fprintf(context.Stdout, "No stream specified, defaulting to released tools in the releases directory.\n")
 
119
                c.stream = envtools.ReleasedStream
 
120
                toolsDir = envtools.LegacyReleaseDirectory
 
121
        }
 
122
        fmt.Fprintf(context.Stdout, "Finding tools in %s for stream %s.\n", c.metadataDir, c.stream)
 
123
        toolsList, err := envtools.ReadList(sourceStorage, toolsDir, -1, -1)
 
124
        if err == envtools.ErrNoTools {
 
125
                var source string
 
126
                source, err = envtools.ToolsURL(envtools.DefaultBaseURL)
 
127
                if err != nil {
 
128
                        return err
 
129
                }
 
130
                toolsList, err = envtools.FindToolsForCloud(toolsDataSources(source), simplestreams.CloudSpec{}, c.stream, -1, -1, coretools.Filter{})
 
131
        }
 
132
        if err != nil {
 
133
                return err
 
134
        }
 
135
 
 
136
        targetStorage, err := filestorage.NewFileStorageWriter(c.metadataDir)
 
137
        if err != nil {
 
138
                return err
 
139
        }
 
140
        writeMirrors := envtools.DoNotWriteMirrors
 
141
        if c.public {
 
142
                writeMirrors = envtools.WriteMirrors
 
143
        }
 
144
        return mergeAndWriteMetadata(targetStorage, toolsDir, c.stream, c.clean, toolsList, writeMirrors)
 
145
}
 
146
 
 
147
func toolsDataSources(urls ...string) []simplestreams.DataSource {
 
148
        dataSources := make([]simplestreams.DataSource, len(urls))
 
149
        for i, url := range urls {
 
150
                dataSources[i] = simplestreams.NewURLSignedDataSource(
 
151
                        "local source",
 
152
                        url,
 
153
                        keys.JujuPublicKey,
 
154
                        utils.VerifySSLHostnames,
 
155
                        simplestreams.CUSTOM_CLOUD_DATA,
 
156
                        false)
 
157
        }
 
158
        return dataSources
 
159
}
 
160
 
 
161
// This is essentially the same as tools.MergeAndWriteMetadata, but also
 
162
// resolves metadata for existing tools by fetching them and computing
 
163
// size/sha256 locally.
 
164
func mergeAndWriteMetadata(
 
165
        stor storage.Storage, toolsDir, stream string, clean bool, toolsList coretools.List, writeMirrors envtools.ShouldWriteMirrors,
 
166
) error {
 
167
        existing, err := envtools.ReadAllMetadata(stor)
 
168
        if err != nil {
 
169
                return err
 
170
        }
 
171
        if clean {
 
172
                delete(existing, stream)
 
173
        }
 
174
        metadata := envtools.MetadataFromTools(toolsList, toolsDir)
 
175
        var mergedMetadata []*envtools.ToolsMetadata
 
176
        if mergedMetadata, err = envtools.MergeMetadata(metadata, existing[stream]); err != nil {
 
177
                return err
 
178
        }
 
179
        if err = envtools.ResolveMetadata(stor, toolsDir, mergedMetadata); err != nil {
 
180
                return err
 
181
        }
 
182
        existing[stream] = mergedMetadata
 
183
        return envtools.WriteMetadata(stor, existing, []string{stream}, writeMirrors)
 
184
}