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