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

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package model
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/gnuflag"
    12  
    13  	"github.com/juju/juju/api/modelgeneration"
    14  	jujucmd "github.com/juju/juju/cmd"
    15  	"github.com/juju/juju/cmd/modelcmd"
    16  	"github.com/juju/juju/core/model"
    17  )
    18  
    19  const (
    20  	switchGenerationSummary = "Switch to the given generation."
    21  	switchGenerationDoc     = `
    22  Switch to the given generation, either current or next. 
    23  
    24  Examples:
    25      juju switch-generation next
    26  
    27  See also:
    28      add-generation
    29      advance-generation
    30      cancel-generation
    31  `
    32  )
    33  
    34  // NewSwitchGenerationCommand wraps switchGenerationCommand with sane model settings.
    35  func NewSwitchGenerationCommand() cmd.Command {
    36  	return modelcmd.Wrap(&switchGenerationCommand{})
    37  }
    38  
    39  // switchGenerationCommand is the simplified command for accessing and setting
    40  // attributes related to switching model generations.
    41  type switchGenerationCommand struct {
    42  	modelcmd.ModelCommandBase
    43  
    44  	api SwitchGenerationCommandAPI
    45  
    46  	generation string
    47  }
    48  
    49  // SwitchGenerationCommandAPI defines an API interface to be used during testing.
    50  //go:generate mockgen -package mocks -destination ./mocks/switchgeneration_mock.go github.com/juju/juju/cmd/juju/model SwitchGenerationCommandAPI
    51  type SwitchGenerationCommandAPI interface {
    52  	Close() error
    53  	HasNextGeneration(string) (bool, error)
    54  }
    55  
    56  // Info implements part of the cmd.Command interface.
    57  func (c *switchGenerationCommand) Info() *cmd.Info {
    58  	info := &cmd.Info{
    59  		Args:    "<current|next>",
    60  		Name:    "switch-generation",
    61  		Purpose: switchGenerationSummary,
    62  		Doc:     switchGenerationDoc,
    63  	}
    64  	return jujucmd.Info(info)
    65  }
    66  
    67  // SetFlags implements part of the cmd.Command interface.
    68  func (c *switchGenerationCommand) SetFlags(f *gnuflag.FlagSet) {
    69  	c.ModelCommandBase.SetFlags(f)
    70  }
    71  
    72  // Init implements part of the cmd.Command interface.
    73  func (c *switchGenerationCommand) Init(args []string) error {
    74  	if len(args) != 1 {
    75  		return errors.Errorf("Must specify 'current' or 'next'")
    76  	}
    77  
    78  	if args[0] != "current" && args[0] != "next" {
    79  		return errors.Errorf("Must specify 'current' or 'next'")
    80  	}
    81  
    82  	c.generation = args[0]
    83  	return nil
    84  }
    85  
    86  // getAPI returns the API. This allows passing in a test SwitchGenerationCommandAPI
    87  // Run (cmd.Command) sets the active generation in the local store.
    88  // implementation.
    89  func (c *switchGenerationCommand) getAPI() (SwitchGenerationCommandAPI, error) {
    90  	if c.api != nil {
    91  		return c.api, nil
    92  	}
    93  	api, err := c.NewAPIRoot()
    94  	if err != nil {
    95  		return nil, errors.Annotate(err, "opening API connection")
    96  	}
    97  	client := modelgeneration.NewClient(api)
    98  	return client, nil
    99  }
   100  
   101  // Run (cmd.Command) sets the active generation in the local store.
   102  func (c *switchGenerationCommand) Run(ctx *cmd.Context) error {
   103  	// If attempting to set the active generation to "next",
   104  	// check that the model has such a generation.
   105  	if c.generation == string(model.GenerationNext) {
   106  		client, err := c.getAPI()
   107  		if err != nil {
   108  			return err
   109  		}
   110  		defer func() { _ = client.Close() }()
   111  
   112  		_, modelDetails, err := c.ModelDetails()
   113  		if err != nil {
   114  			return errors.Annotate(err, "getting model details")
   115  		}
   116  		hasNext, err := client.HasNextGeneration(modelDetails.ModelUUID)
   117  		if err != nil {
   118  			return errors.Annotate(err, "checking for next generation")
   119  		}
   120  		if !hasNext {
   121  			return errors.New("this model has no next generation")
   122  		}
   123  	}
   124  
   125  	if err := c.SetModelGeneration(model.GenerationVersion(c.generation)); err != nil {
   126  		return err
   127  	}
   128  	msg := fmt.Sprintf("target generation set to %s\n", c.generation)
   129  	_, err := ctx.Stdout.Write([]byte(msg))
   130  	return err
   131  }