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  }