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 }