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