github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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/cmd" 12 "github.com/juju/utils" 13 "launchpad.net/gnuflag" 14 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/configstore" 17 "github.com/juju/juju/environs/simplestreams" 18 "github.com/juju/juju/environs/tools" 19 "github.com/juju/juju/juju/arch" 20 "github.com/juju/juju/version" 21 ) 22 23 // ValidateToolsMetadataCommand 24 type ValidateToolsMetadataCommand struct { 25 ImageMetadataCommandBase 26 out cmd.Output 27 providerType string 28 metadataDir string 29 stream 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-tools -s raring -d <some directory> 81 82 - validate for the proposed stream 83 84 juju metadata validate-tools --stream proposed 85 86 A key use case is to validate newly generated metadata prior to deployment to 87 production. In this case, the metadata is placed in a local directory, a cloud 88 provider type is specified (ec2, openstack etc), and the validation is performed 89 for each supported series, version, and arcgitecture. 90 91 Example bash snippet: 92 93 #!/bin/bash 94 95 juju metadata validate-tools -p ec2 -r us-east-1 -s precise --juju-version 1.12.0 -d <some directory> 96 RETVAL=$? 97 [ $RETVAL -eq 0 ] && echo Success 98 [ $RETVAL -ne 0 ] && echo Failure 99 ` 100 101 func (c *ValidateToolsMetadataCommand) Info() *cmd.Info { 102 return &cmd.Info{ 103 Name: "validate-tools", 104 Purpose: "validate tools metadata and ensure tools tarball(s) exist for Juju version(s)", 105 Doc: validateToolsMetadataDoc, 106 } 107 } 108 109 func (c *ValidateToolsMetadataCommand) SetFlags(f *gnuflag.FlagSet) { 110 c.out.AddFlags(f, "smart", cmd.DefaultFormatters) 111 f.StringVar(&c.providerType, "p", "", "the provider type eg ec2, openstack") 112 f.StringVar(&c.metadataDir, "d", "", "directory where metadata files are found") 113 f.StringVar(&c.series, "s", "", "the series for which to validate (overrides env config series)") 114 f.StringVar(&c.series, "series", "", "") 115 f.StringVar(&c.region, "r", "", "the region for which to validate (overrides env config region)") 116 f.StringVar(&c.endpoint, "u", "", "the cloud endpoint URL for which to validate (overrides env config endpoint)") 117 f.StringVar(&c.exactVersion, "j", "current", "the Juju version (use 'current' for current version)") 118 f.StringVar(&c.exactVersion, "juju-version", "", "") 119 f.StringVar(&c.partVersion, "m", "", "the Juju major[.minor] version") 120 f.StringVar(&c.partVersion, "majorminor-version", "", "") 121 f.StringVar(&c.stream, "stream", tools.ReleasedStream, "simplestreams stream for which to generate the metadata") 122 } 123 124 func (c *ValidateToolsMetadataCommand) Init(args []string) error { 125 if c.providerType != "" { 126 if c.region == "" { 127 return fmt.Errorf("region required if provider type is specified") 128 } 129 if c.metadataDir == "" { 130 return fmt.Errorf("metadata directory required if provider type is specified") 131 } 132 } 133 if c.exactVersion == "current" { 134 c.exactVersion = version.Current.Number.String() 135 } 136 if c.partVersion != "" { 137 var err error 138 if c.major, c.minor, err = version.ParseMajorMinor(c.partVersion); err != nil { 139 return err 140 } 141 } 142 return cmd.CheckEmpty(args) 143 } 144 145 func (c *ValidateToolsMetadataCommand) Run(context *cmd.Context) error { 146 var params *simplestreams.MetadataLookupParams 147 148 if c.providerType == "" { 149 store, err := configstore.Default() 150 if err != nil { 151 return err 152 } 153 environ, err := c.prepare(context, store) 154 if err == nil { 155 mdLookup, ok := environ.(simplestreams.MetadataValidator) 156 if !ok { 157 return fmt.Errorf("%s provider does not support tools metadata validation", environ.Config().Type()) 158 } 159 params, err = mdLookup.MetadataLookupParams(c.region) 160 if err != nil { 161 return err 162 } 163 params.Sources, err = tools.GetMetadataSources(environ) 164 if err != nil { 165 return err 166 } 167 } else { 168 if c.metadataDir == "" { 169 return err 170 } 171 params = &simplestreams.MetadataLookupParams{ 172 Architectures: arch.AllSupportedArches, 173 } 174 } 175 } else { 176 prov, err := environs.Provider(c.providerType) 177 if err != nil { 178 return err 179 } 180 mdLookup, ok := prov.(simplestreams.MetadataValidator) 181 if !ok { 182 return fmt.Errorf("%s provider does not support tools metadata validation", c.providerType) 183 } 184 params, err = mdLookup.MetadataLookupParams(c.region) 185 if err != nil { 186 return err 187 } 188 } 189 190 if c.series != "" { 191 params.Series = c.series 192 } 193 if c.region != "" { 194 params.Region = c.region 195 } 196 if c.endpoint != "" { 197 params.Endpoint = c.endpoint 198 } 199 if c.metadataDir != "" { 200 if _, err := os.Stat(c.metadataDir); err != nil { 201 return err 202 } 203 toolsURL, err := tools.ToolsURL(c.metadataDir) 204 if err != nil { 205 return err 206 } 207 params.Sources = []simplestreams.DataSource{simplestreams.NewURLDataSource( 208 "local metadata directory", toolsURL, utils.VerifySSLHostnames), 209 } 210 } 211 params.Stream = c.stream 212 213 versions, resolveInfo, err := tools.ValidateToolsMetadata(&tools.ToolsMetadataLookupParams{ 214 MetadataLookupParams: *params, 215 Version: c.exactVersion, 216 Major: c.major, 217 Minor: c.minor, 218 }) 219 if err != nil { 220 if resolveInfo != nil { 221 metadata := map[string]interface{}{ 222 "Resolve Metadata": *resolveInfo, 223 } 224 if metadataYaml, yamlErr := cmd.FormatYaml(metadata); yamlErr == nil { 225 err = fmt.Errorf("%v\n%v", err, string(metadataYaml)) 226 } 227 } 228 return err 229 } 230 231 if len(versions) > 0 { 232 metadata := map[string]interface{}{ 233 "Matching Tools Versions": versions, 234 "Resolve Metadata": *resolveInfo, 235 } 236 c.out.Write(context, metadata) 237 } else { 238 var sources []string 239 for _, s := range params.Sources { 240 url, err := s.URL("") 241 if err == nil { 242 sources = append(sources, fmt.Sprintf("- %s (%s)", s.Description(), url)) 243 } 244 } 245 return fmt.Errorf("no matching tools using sources:\n%s", strings.Join(sources, "\n")) 246 } 247 return nil 248 }