github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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  }