1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for infos.
10
"github.com/juju/errors"
11
"github.com/juju/loggo"
12
"launchpad.net/gnuflag"
14
"github.com/juju/juju/api/modelmanager"
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"
21
var logger = loggo.GetLogger("juju.cmd.juju.model")
23
// NewDestroyCommand returns a command used to destroy a model.
24
func NewDestroyCommand() cmd.Command {
27
modelcmd.ModelSkipDefault,
28
modelcmd.ModelSkipFlags,
32
// destroyCommand destroys the specified model.
33
type destroyCommand struct {
34
modelcmd.ModelCommandBase
41
Destroys the specified model. This will result in the non-recoverable
42
removal of all the units operating in the model and any resources stored
43
there. Due to the irreversible nature of the command, it will prompt for
44
confirmation (unless overridden with the '-y' option) before taking any
49
juju destroy-model test
50
juju destroy-model -y mymodel
52
See also: destroy-controller
55
WARNING! This command will destroy the %q model.
56
This includes all machines, applications, data and other resources.
60
// DestroyModelAPI defines the methods on the modelmanager
61
// API that the destroy command calls. It is exported for mocking in tests.
62
type DestroyModelAPI interface {
67
// Info implements Command.Info.
68
func (c *destroyCommand) Info() *cmd.Info {
70
Name: "destroy-model",
71
Args: "[<controller name>:]<model name>",
72
Purpose: "Terminate all machines and resources for a non-controller model.",
77
// SetFlags implements Command.SetFlags.
78
func (c *destroyCommand) SetFlags(f *gnuflag.FlagSet) {
79
f.BoolVar(&c.assumeYes, "y", false, "Do not prompt for confirmation")
80
f.BoolVar(&c.assumeYes, "yes", false, "")
83
// Init implements Command.Init.
84
func (c *destroyCommand) Init(args []string) error {
87
return errors.New("no model specified")
89
return c.SetModelName(args[0])
91
return cmd.CheckEmpty(args[1:])
95
func (c *destroyCommand) getAPI() (DestroyModelAPI, error) {
99
root, err := c.NewAPIRoot()
101
return nil, errors.Trace(err)
103
return modelmanager.NewClient(root), nil
106
// Run implements Command.Run
107
func (c *destroyCommand) Run(ctx *cmd.Context) error {
108
store := c.ClientStore()
109
controllerName := c.ControllerName()
110
modelName := c.ModelName()
112
controllerDetails, err := store.ControllerByName(controllerName)
114
return errors.Annotate(err, "cannot read controller details")
116
modelDetails, err := store.ModelByName(controllerName, modelName)
118
return errors.Annotate(err, "cannot read model info")
120
if modelDetails.ModelUUID == controllerDetails.ControllerUUID {
121
return errors.Errorf("%q is a controller; use 'juju destroy-controller' to destroy it", modelName)
125
fmt.Fprintf(ctx.Stdout, destroyEnvMsg, modelName)
127
if err := jujucmd.UserConfirmYes(ctx); err != nil {
128
return errors.Annotate(err, "model destruction")
132
// Attempt to connect to the API. If we can't, fail the destroy.
133
api, err := c.getAPI()
135
return errors.Annotate(err, "cannot connect to API")
139
// Attempt to destroy the model.
140
err = api.DestroyModel()
142
return c.handleError(errors.Annotate(err, "cannot destroy model"), modelName)
145
err = store.RemoveModel(controllerName, modelName)
146
if err != nil && !errors.IsNotFound(err) {
147
return errors.Trace(err)
152
func (c *destroyCommand) handleError(err error, modelName string) error {
156
if params.IsCodeOperationBlocked(err) {
157
return block.ProcessBlockedError(err, block.BlockDestroy)
159
logger.Errorf(`failed to destroy model %q`, modelName)