github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/cmd/plugins/juju-metadata/validatetoolsmetadata.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 "os" 9 "strings" 10 11 "github.com/juju/utils" 12 "launchpad.net/gnuflag" 13 14 "github.com/juju/juju/cmd" 15 "github.com/juju/juju/cmd/envcmd" 16 "github.com/juju/juju/environs" 17 "github.com/juju/juju/environs/configstore" 18 "github.com/juju/juju/environs/simplestreams" 19 "github.com/juju/juju/environs/tools" 20 "github.com/juju/juju/juju/arch" 21 "github.com/juju/juju/version" 22 ) 23 24 // ValidateToolsMetadataCommand 25 type ValidateToolsMetadataCommand struct { 26 envcmd.EnvCommandBase 27 out cmd.Output 28 providerType string 29 metadataDir string 30 series string 31 region string 32 endpoint string 33 exactVersion string 34 partVersion string 35 major int 36 minor int 37 } 38 39 var validateToolsMetadataDoc = ` 40 validate-tools loads simplestreams metadata and validates the contents by 41 looking for tools belonging to the specified series, architecture, for the 42 specified cloud. If version is specified, tools matching the exact specified 43 version are found. It is also possible to just specify the major (and optionally 44 minor) version numbers to search for. 45 46 The cloud specification comes from the current Juju environment, as specified in 47 the usual way from either ~/.juju/environments.yaml, the -e option, or JUJU_ENV. 48 Series, Region, and Endpoint are the key attributes. 49 50 It is possible to specify a local directory containing tools metadata, in which 51 case cloud attributes like provider type, region etc are optional. 52 53 The key environment attributes may be overridden using command arguments, so 54 that the validation may be peformed on arbitary metadata. 55 56 Examples: 57 58 - validate using the current environment settings but with series raring 59 60 juju metadata validate-tools -s raring 61 62 - validate using the current environment settings but with Juju version 1.11.4 63 64 juju metadata validate-tools -j 1.11.4 65 66 - validate using the current environment settings but with Juju major version 2 67 68 juju metadata validate-tools -m 2 69 70 - validate using the current environment settings but with Juju major.minor version 2.1 71 72 juju metadata validate-tools -m 2.1 73 74 - validate using the current environment settings and list all tools found for any series 75 76 juju metadata validate-tools --series= 77 78 - validate with series raring and using metadata from local directory 79 80 juju metadata validate-images -s raring -d <some directory> 81 82 A key use case is to validate newly generated metadata prior to deployment to 83 production. In this case, the metadata is placed in a local directory, a cloud 84 provider type is specified (ec2, openstack etc), and the validation is performed 85 for each supported series, version, and arcgitecture. 86 87 Example bash snippet: 88 89 #!/bin/bash 90 91 juju metadata validate-tools -p ec2 -r us-east-1 -s precise --juju-version 1.12.0 -d <some directory> 92 RETVAL=$? 93 [ $RETVAL -eq 0 ] && echo Success 94 [ $RETVAL -ne 0 ] && echo Failure 95 ` 96 97 func (c *ValidateToolsMetadataCommand) Info() *cmd.Info { 98 return &cmd.Info{ 99 Name: "validate-tools", 100 Purpose: "validate tools metadata and ensure tools tarball(s) exist for Juju version(s)", 101 Doc: validateToolsMetadataDoc, 102 } 103 } 104 105 func (c *ValidateToolsMetadataCommand) SetFlags(f *gnuflag.FlagSet) { 106 c.out.AddFlags(f, "smart", cmd.DefaultFormatters) 107 f.StringVar(&c.providerType, "p", "", "the provider type eg ec2, openstack") 108 f.StringVar(&c.metadataDir, "d", "", "directory where metadata files are found") 109 f.StringVar(&c.series, "s", "", "the series for which to validate (overrides env config series)") 110 f.StringVar(&c.series, "series", "", "") 111 f.StringVar(&c.region, "r", "", "the region for which to validate (overrides env config region)") 112 f.StringVar(&c.endpoint, "u", "", "the cloud endpoint URL for which to validate (overrides env config endpoint)") 113 f.StringVar(&c.exactVersion, "j", "current", "the Juju version (use 'current' for current version)") 114 f.StringVar(&c.exactVersion, "juju-version", "", "") 115 f.StringVar(&c.partVersion, "m", "", "the Juju major[.minor] version") 116 f.StringVar(&c.partVersion, "majorminor-version", "", "") 117 } 118 119 func (c *ValidateToolsMetadataCommand) Init(args []string) error { 120 if c.providerType != "" { 121 if c.region == "" { 122 return fmt.Errorf("region required if provider type is specified") 123 } 124 if c.metadataDir == "" { 125 return fmt.Errorf("metadata directory required if provider type is specified") 126 } 127 } 128 if c.exactVersion == "current" { 129 c.exactVersion = version.Current.Number.String() 130 } 131 if c.partVersion != "" { 132 var err error 133 if c.major, c.minor, err = version.ParseMajorMinor(c.partVersion); err != nil { 134 return err 135 } 136 } 137 return cmd.CheckEmpty(args) 138 } 139 140 func (c *ValidateToolsMetadataCommand) Run(context *cmd.Context) error { 141 var params *simplestreams.MetadataLookupParams 142 143 if c.providerType == "" { 144 store, err := configstore.Default() 145 if err != nil { 146 return err 147 } 148 environ, err := environs.PrepareFromName(c.EnvName, context, store) 149 if err == nil { 150 mdLookup, ok := environ.(simplestreams.MetadataValidator) 151 if !ok { 152 return fmt.Errorf("%s provider does not support tools metadata validation", environ.Config().Type()) 153 } 154 params, err = mdLookup.MetadataLookupParams(c.region) 155 if err != nil { 156 return err 157 } 158 params.Sources, err = tools.GetMetadataSources(environ) 159 if err != nil { 160 return err 161 } 162 } else { 163 if c.metadataDir == "" { 164 return err 165 } 166 params = &simplestreams.MetadataLookupParams{ 167 Architectures: arch.AllSupportedArches, 168 } 169 } 170 } else { 171 prov, err := environs.Provider(c.providerType) 172 if err != nil { 173 return err 174 } 175 mdLookup, ok := prov.(simplestreams.MetadataValidator) 176 if !ok { 177 return fmt.Errorf("%s provider does not support tools metadata validation", c.providerType) 178 } 179 params, err = mdLookup.MetadataLookupParams(c.region) 180 if err != nil { 181 return err 182 } 183 } 184 185 if c.series != "" { 186 params.Series = c.series 187 } 188 if c.region != "" { 189 params.Region = c.region 190 } 191 if c.endpoint != "" { 192 params.Endpoint = c.endpoint 193 } 194 if c.metadataDir != "" { 195 if _, err := os.Stat(c.metadataDir); err != nil { 196 return err 197 } 198 toolsURL, err := tools.ToolsURL(c.metadataDir) 199 if err != nil { 200 return err 201 } 202 params.Sources = []simplestreams.DataSource{simplestreams.NewURLDataSource( 203 "local metadata directory", toolsURL, utils.VerifySSLHostnames), 204 } 205 } 206 207 versions, resolveInfo, err := tools.ValidateToolsMetadata(&tools.ToolsMetadataLookupParams{ 208 MetadataLookupParams: *params, 209 Version: c.exactVersion, 210 Major: c.major, 211 Minor: c.minor, 212 }) 213 if err != nil { 214 if resolveInfo != nil { 215 metadata := map[string]interface{}{ 216 "Resolve Metadata": *resolveInfo, 217 } 218 if metadataYaml, yamlErr := cmd.FormatYaml(metadata); yamlErr == nil { 219 err = fmt.Errorf("%v\n%v", err, string(metadataYaml)) 220 } 221 } 222 return err 223 } 224 225 if len(versions) > 0 { 226 metadata := map[string]interface{}{ 227 "Matching Tools Versions": versions, 228 "Resolve Metadata": *resolveInfo, 229 } 230 c.out.Write(context, metadata) 231 } else { 232 var sources []string 233 for _, s := range params.Sources { 234 url, err := s.URL("") 235 if err == nil { 236 sources = append(sources, fmt.Sprintf("- %s (%s)", s.Description(), url)) 237 } 238 } 239 return fmt.Errorf("no matching tools using sources:\n%s", strings.Join(sources, "\n")) 240 } 241 return nil 242 }