~gz/juju-core/trunk

« back to all changes in this revision

Viewing changes to cmd/plugins/juju-metadata/validatetoolsmetadata.go

[r=wallyworld] Parse and validate tools metadata

Tools metadata in simplestreams format can be parsed and
validated. A new environs/tools package is created, and the
existing environs/tools.go is moved there, and the new
simplestreams support added also. The agent/tools package
is disambiguated as agenttools where there were clashes.

The metadata plugin is extended to support validating tools
metadata in the same way as image metadata. The next branches
will support using the tools metadata when finding tools to
bootstrap with.

https://codereview.appspot.com/12833043/

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
        "net/http"
 
9
        "os"
 
10
        "strings"
 
11
 
 
12
        "launchpad.net/gnuflag"
 
13
 
 
14
        "launchpad.net/juju-core/cmd"
 
15
        "launchpad.net/juju-core/environs"
 
16
        "launchpad.net/juju-core/environs/simplestreams"
 
17
        "launchpad.net/juju-core/environs/tools"
 
18
        "launchpad.net/juju-core/version"
 
19
)
 
20
 
 
21
// ValidateToolsMetadataCommand
 
22
type ValidateToolsMetadataCommand struct {
 
23
        cmd.EnvCommandBase
 
24
        providerType string
 
25
        metadataDir  string
 
26
        series       string
 
27
        region       string
 
28
        endpoint     string
 
29
        version      string
 
30
}
 
31
 
 
32
var validateToolsMetadataDoc = `
 
33
validate-tools loads simplestreams metadata and validates the contents by looking for tools
 
34
belonging to the specified series, version, and architecture, for the specified cloud.
 
35
 
 
36
The cloud specificaton comes from the current Juju environment, as specified in the usual way
 
37
from either ~/.juju/environments.yaml, the -e option, or JUJU_ENV. Series, Region, and Endpoint
 
38
are the key attributes.
 
39
 
 
40
The key environment attributes may be overridden using command arguments, so that the validation
 
41
may be peformed on arbitary metadata.
 
42
 
 
43
Examples:
 
44
 
 
45
- validate using the current environment settings but with series raring
 
46
 juju metadata validate-tools -s raring
 
47
 
 
48
- validate using the current environment settings but with Juju version 1.11.4
 
49
 juju metadata validate-tools -j 1.11.4
 
50
 
 
51
- validate using the current environment settings and list all tools found for any series
 
52
 juju metadata validate-tools --series=
 
53
 
 
54
- validate using the current environment settings but with series raring and using metadata from local directory
 
55
 juju metadata validate-images -s raring -d <some directory>
 
56
 
 
57
A key use case is to validate newly generated metadata prior to deployment to production.
 
58
In this case, the metadata is placed in a local directory, a cloud provider type is specified (ec2, openstack etc),
 
59
and the validation is performed for each supported series, version, and arcgitecture.
 
60
 
 
61
Example bash snippet:
 
62
 
 
63
#!/bin/bash
 
64
 
 
65
juju metadata validate-tools -p ec2 -r us-east-1 -s precise --juju-version 1.12.0 -d <some directory>
 
66
RETVAL=$?
 
67
[ $RETVAL -eq 0 ] && echo Success
 
68
[ $RETVAL -ne 0 ] && echo Failure
 
69
`
 
70
 
 
71
func (c *ValidateToolsMetadataCommand) Info() *cmd.Info {
 
72
        return &cmd.Info{
 
73
                Name:    "validate-tools",
 
74
                Purpose: "validate tools metadata and ensure tools tarball(s) exist for Juju version(s)",
 
75
                Doc:     validateToolsMetadataDoc,
 
76
        }
 
77
}
 
78
 
 
79
func (c *ValidateToolsMetadataCommand) SetFlags(f *gnuflag.FlagSet) {
 
80
        c.EnvCommandBase.SetFlags(f)
 
81
        f.StringVar(&c.providerType, "p", "", "the provider type eg ec2, openstack")
 
82
        f.StringVar(&c.metadataDir, "d", "", "directory where metadata files are found")
 
83
        f.StringVar(&c.series, "s", "", "the series for which to validate (overrides env config series)")
 
84
        f.StringVar(&c.series, "series", "", "")
 
85
        f.StringVar(&c.region, "r", "", "the region for which to validate (overrides env config region)")
 
86
        f.StringVar(&c.endpoint, "u", "", "the cloud endpoint URL for which to validate (overrides env config endpoint)")
 
87
        f.StringVar(&c.version, "j", "current", "the Juju version (use 'current' for current version)")
 
88
        f.StringVar(&c.version, "juju-version", "", "")
 
89
}
 
90
 
 
91
func (c *ValidateToolsMetadataCommand) Init(args []string) error {
 
92
        if c.providerType != "" {
 
93
                if c.region == "" {
 
94
                        return fmt.Errorf("region required if provider type is specified")
 
95
                }
 
96
                if c.metadataDir == "" {
 
97
                        return fmt.Errorf("metadata directory required if provider type is specified")
 
98
                }
 
99
        }
 
100
        if c.version == "current" {
 
101
                c.version = version.CurrentNumber().String()
 
102
        }
 
103
        return c.EnvCommandBase.Init(args)
 
104
}
 
105
 
 
106
func (c *ValidateToolsMetadataCommand) Run(context *cmd.Context) error {
 
107
        var params *simplestreams.MetadataLookupParams
 
108
 
 
109
        if c.providerType == "" {
 
110
                environ, err := environs.NewFromName(c.EnvName)
 
111
                if err != nil {
 
112
                        return err
 
113
                }
 
114
                mdLookup, ok := environ.(simplestreams.MetadataValidator)
 
115
                if !ok {
 
116
                        return fmt.Errorf("%s provider does not support tools metadata validation", environ.Config().Type())
 
117
                }
 
118
                params, err = mdLookup.MetadataLookupParams(c.region)
 
119
                if err != nil {
 
120
                        return err
 
121
                }
 
122
        } else {
 
123
                prov, err := environs.Provider(c.providerType)
 
124
                if err != nil {
 
125
                        return err
 
126
                }
 
127
                mdLookup, ok := prov.(simplestreams.MetadataValidator)
 
128
                if !ok {
 
129
                        return fmt.Errorf("%s provider does not support tools metadata validation", c.providerType)
 
130
                }
 
131
                params, err = mdLookup.MetadataLookupParams(c.region)
 
132
                if err != nil {
 
133
                        return err
 
134
                }
 
135
        }
 
136
 
 
137
        if c.series != "" {
 
138
                params.Series = c.series
 
139
        }
 
140
        if c.region != "" {
 
141
                params.Region = c.region
 
142
        }
 
143
        if c.endpoint != "" {
 
144
                params.Endpoint = c.endpoint
 
145
        }
 
146
        // If the metadata files are to be loaded from a directory, we need to register
 
147
        // a file http transport.
 
148
        if c.metadataDir != "" {
 
149
                if _, err := os.Stat(c.metadataDir); err != nil {
 
150
                        return err
 
151
                }
 
152
 
 
153
                params.BaseURLs = []string{"file://" + c.metadataDir}
 
154
                t := &http.Transport{}
 
155
                t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
 
156
                c := &http.Client{Transport: t}
 
157
                simplestreams.SetHttpClient(c)
 
158
        }
 
159
 
 
160
        versions, err := tools.ValidateToolsMetadata(&tools.ToolsMetadataLookupParams{
 
161
                MetadataLookupParams: *params,
 
162
                Version:              c.version,
 
163
        })
 
164
        if err != nil {
 
165
                return err
 
166
        }
 
167
 
 
168
        if len(versions) > 0 {
 
169
                fmt.Fprintf(context.Stdout, "matching tools versions:\n%s\n", strings.Join(versions, "\n"))
 
170
        } else {
 
171
                return fmt.Errorf("no matching tools using URLs:\n%s", strings.Join(params.BaseURLs, "\n"))
 
172
        }
 
173
        return nil
 
174
}