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  }