github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/model/destroy.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for infos. 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 "github.com/juju/loggo" 13 "gopkg.in/juju/names.v2" 14 15 "github.com/juju/juju/api/modelmanager" 16 "github.com/juju/juju/apiserver/params" 17 jujucmd "github.com/juju/juju/cmd" 18 "github.com/juju/juju/cmd/juju/block" 19 "github.com/juju/juju/cmd/modelcmd" 20 ) 21 22 var logger = loggo.GetLogger("juju.cmd.juju.model") 23 24 // NewDestroyCommand returns a command used to destroy a model. 25 func NewDestroyCommand() cmd.Command { 26 return modelcmd.Wrap( 27 &destroyCommand{}, 28 modelcmd.WrapSkipDefaultModel, 29 modelcmd.WrapSkipModelFlags, 30 ) 31 } 32 33 // destroyCommand destroys the specified model. 34 type destroyCommand struct { 35 modelcmd.ModelCommandBase 36 envName string 37 assumeYes bool 38 api DestroyModelAPI 39 } 40 41 var destroyDoc = ` 42 Destroys the specified model. This will result in the non-recoverable 43 removal of all the units operating in the model and any resources stored 44 there. Due to the irreversible nature of the command, it will prompt for 45 confirmation (unless overridden with the '-y' option) before taking any 46 action. 47 48 Examples: 49 50 juju destroy-model test 51 juju destroy-model -y mymodel 52 53 See also: 54 destroy-controller 55 ` 56 var destroyEnvMsg = ` 57 WARNING! This command will destroy the %q model. 58 This includes all machines, applications, data and other resources. 59 60 Continue [y/N]? `[1:] 61 62 // DestroyModelAPI defines the methods on the modelmanager 63 // API that the destroy command calls. It is exported for mocking in tests. 64 type DestroyModelAPI interface { 65 Close() error 66 DestroyModel(names.ModelTag) error 67 } 68 69 // Info implements Command.Info. 70 func (c *destroyCommand) Info() *cmd.Info { 71 return &cmd.Info{ 72 Name: "destroy-model", 73 Args: "[<controller name>:]<model name>", 74 Purpose: "Terminate all machines and resources for a non-controller model.", 75 Doc: destroyDoc, 76 } 77 } 78 79 // SetFlags implements Command.SetFlags. 80 func (c *destroyCommand) SetFlags(f *gnuflag.FlagSet) { 81 c.ModelCommandBase.SetFlags(f) 82 f.BoolVar(&c.assumeYes, "y", false, "Do not prompt for confirmation") 83 f.BoolVar(&c.assumeYes, "yes", false, "") 84 } 85 86 // Init implements Command.Init. 87 func (c *destroyCommand) Init(args []string) error { 88 switch len(args) { 89 case 0: 90 return errors.New("no model specified") 91 case 1: 92 return c.SetModelName(args[0]) 93 default: 94 return cmd.CheckEmpty(args[1:]) 95 } 96 } 97 98 func (c *destroyCommand) getAPI() (DestroyModelAPI, error) { 99 if c.api != nil { 100 return c.api, nil 101 } 102 root, err := c.NewControllerAPIRoot() 103 if err != nil { 104 return nil, errors.Trace(err) 105 } 106 return modelmanager.NewClient(root), nil 107 } 108 109 // Run implements Command.Run 110 func (c *destroyCommand) Run(ctx *cmd.Context) error { 111 store := c.ClientStore() 112 controllerName := c.ControllerName() 113 modelName := c.ModelName() 114 115 controllerDetails, err := store.ControllerByName(controllerName) 116 if err != nil { 117 return errors.Annotate(err, "cannot read controller details") 118 } 119 modelDetails, err := store.ModelByName(controllerName, modelName) 120 if err != nil { 121 return errors.Annotate(err, "cannot read model info") 122 } 123 if modelDetails.ModelUUID == controllerDetails.ControllerUUID { 124 return errors.Errorf("%q is a controller; use 'juju destroy-controller' to destroy it", modelName) 125 } 126 127 if !c.assumeYes { 128 fmt.Fprintf(ctx.Stdout, destroyEnvMsg, modelName) 129 130 if err := jujucmd.UserConfirmYes(ctx); err != nil { 131 return errors.Annotate(err, "model destruction") 132 } 133 } 134 135 // Attempt to connect to the API. If we can't, fail the destroy. 136 api, err := c.getAPI() 137 if err != nil { 138 return errors.Annotate(err, "cannot connect to API") 139 } 140 defer api.Close() 141 142 // Attempt to destroy the model. 143 err = api.DestroyModel(names.NewModelTag(modelDetails.ModelUUID)) 144 if err != nil { 145 return c.handleError(errors.Annotate(err, "cannot destroy model"), modelName) 146 } 147 148 err = store.RemoveModel(controllerName, modelName) 149 if err != nil && !errors.IsNotFound(err) { 150 return errors.Trace(err) 151 } 152 return nil 153 } 154 155 func (c *destroyCommand) handleError(err error, modelName string) error { 156 if err == nil { 157 return nil 158 } 159 if params.IsCodeOperationBlocked(err) { 160 return block.ProcessBlockedError(err, block.BlockDestroy) 161 } 162 logger.Errorf(`failed to destroy model %q`, modelName) 163 return err 164 }