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