github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/application/setseries.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package application
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/gnuflag"
    10  	"github.com/juju/utils/series"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/api"
    14  	"github.com/juju/juju/api/application"
    15  	"github.com/juju/juju/apiserver/params"
    16  	jujucmd "github.com/juju/juju/cmd"
    17  	"github.com/juju/juju/cmd/juju/block"
    18  	"github.com/juju/juju/cmd/modelcmd"
    19  )
    20  
    21  // NewSetSeriesCommand returns a command which updates the series of
    22  // an application.
    23  func NewSetSeriesCommand() cmd.Command {
    24  	return modelcmd.Wrap(&setSeriesCommand{})
    25  }
    26  
    27  // setSeriesAPI defines a subset of the application facade, as required
    28  // by the set-series command.
    29  type setSeriesAPI interface {
    30  	BestAPIVersion() int
    31  	Close() error
    32  	UpdateApplicationSeries(string, string, bool) error
    33  }
    34  
    35  // setSeriesCommand is responsible for updating the series of an application or machine.
    36  type setSeriesCommand struct {
    37  	modelcmd.ModelCommandBase
    38  	modelcmd.IAASOnlyCommand
    39  
    40  	setSeriesClient setSeriesAPI
    41  
    42  	applicationName string
    43  	force           bool
    44  	series          string
    45  }
    46  
    47  var setSeriesDoc = `
    48  When no options are set, an application series value will be set within juju.
    49  
    50  The update is disallowed unless the --force option is used if the requested
    51  series is not explicitly supported by the application's charm and all
    52  subordinates, as well as any other charms which may be deployed to the same
    53  machine.
    54  
    55  Examples:
    56  	juju set-series <application> <series>
    57  	juju set-series <application> <series> --force
    58  
    59  See also:
    60      status
    61      upgrade-charm
    62  `
    63  
    64  func (c *setSeriesCommand) Info() *cmd.Info {
    65  	return jujucmd.Info(&cmd.Info{
    66  		Name:    "set-series",
    67  		Args:    "<application> <series>",
    68  		Purpose: "Set an application's series.",
    69  		Doc:     setSeriesDoc,
    70  	})
    71  }
    72  
    73  func (c *setSeriesCommand) SetFlags(f *gnuflag.FlagSet) {
    74  	c.ModelCommandBase.SetFlags(f)
    75  	f.BoolVar(&c.force, "force", false, "Set even if the series is not supported by the charm and/or related subordinate charms.")
    76  }
    77  
    78  // Init implements cmd.Command.
    79  func (c *setSeriesCommand) Init(args []string) error {
    80  	switch len(args) {
    81  	case 2:
    82  		if names.IsValidApplication(args[0]) {
    83  			c.applicationName = args[0]
    84  		} else {
    85  			return errors.Errorf("invalid application name %q", args[0])
    86  		}
    87  		if _, err := series.GetOSFromSeries(args[1]); err != nil {
    88  			return errors.Errorf("invalid series %q", args[1])
    89  		}
    90  		c.series = args[1]
    91  	case 1:
    92  		if _, err := series.GetOSFromSeries(args[0]); err != nil {
    93  			return errors.Errorf("no series specified")
    94  		} else {
    95  			return errors.Errorf("no application name")
    96  		}
    97  	case 0:
    98  		return errors.Errorf("application name and series required")
    99  	default:
   100  		return cmd.CheckEmpty(args[2:])
   101  	}
   102  	return nil
   103  }
   104  
   105  // Run implements cmd.Run.
   106  func (c *setSeriesCommand) Run(ctx *cmd.Context) error {
   107  	var apiRoot api.Connection
   108  	if c.setSeriesClient == nil {
   109  		var err error
   110  		apiRoot, err = c.NewAPIRoot()
   111  		if err != nil {
   112  			return errors.Trace(err)
   113  		}
   114  		defer apiRoot.Close()
   115  	}
   116  
   117  	if c.applicationName != "" {
   118  		if c.setSeriesClient == nil {
   119  			c.setSeriesClient = application.NewClient(apiRoot)
   120  			defer c.setSeriesClient.Close()
   121  		}
   122  		if c.setSeriesClient.BestAPIVersion() < 5 {
   123  			return errors.New("setting the application series is not supported by this API server")
   124  		}
   125  		return c.updateApplicationSeries()
   126  	}
   127  
   128  	// This should never happen...
   129  	return errors.New("no application nor machine name specified")
   130  }
   131  
   132  func (c *setSeriesCommand) updateApplicationSeries() error {
   133  	err := block.ProcessBlockedError(
   134  		c.setSeriesClient.UpdateApplicationSeries(c.applicationName, c.series, c.force),
   135  		block.BlockChange)
   136  
   137  	if params.IsCodeIncompatibleSeries(err) {
   138  		return errors.Errorf("%v. Use --force to set the series anyway.", err)
   139  	}
   140  	return err
   141  }