github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/remove.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/gnuflag"
    10  
    11  	"github.com/juju/juju/apiserver/params"
    12  	jujucmd "github.com/juju/juju/cmd"
    13  	"github.com/juju/juju/cmd/juju/common"
    14  	"github.com/juju/juju/cmd/modelcmd"
    15  )
    16  
    17  // NewRemoveStorageCommandWithAPI returns a command
    18  // used to remove storage from the model.
    19  func NewRemoveStorageCommandWithAPI() cmd.Command {
    20  	cmd := &removeStorageCommand{}
    21  	cmd.newStorageRemoverCloser = func() (StorageRemoverCloser, error) {
    22  		return cmd.NewStorageAPI()
    23  	}
    24  	return modelcmd.Wrap(cmd)
    25  }
    26  
    27  const (
    28  	removeStorageCommandDoc = `
    29  Removes storage from the model. Specify one or more
    30  storage IDs, as output by "juju storage".
    31  
    32  By default, remove-storage will fail if the storage
    33  is attached to any units. To override this behaviour,
    34  you can use "juju remove-storage --force".
    35  
    36  Examples:
    37      # Remove the detached storage pgdata/0.
    38      juju remove-storage pgdata/0
    39  
    40      # Remove the possibly attached storage pgdata/0.
    41      juju remove-storage --force pgdata/0
    42  
    43      # Remove the storage pgdata/0, without destroying
    44      # the corresponding cloud storage.
    45      juju remove-storage --no-destroy pgdata/0
    46  `
    47  	removeStorageCommandArgs = `<storage> [<storage> ...]`
    48  )
    49  
    50  type removeStorageCommand struct {
    51  	StorageCommandBase
    52  	modelcmd.IAASOnlyCommand
    53  	newStorageRemoverCloser NewStorageRemoverCloserFunc
    54  	storageIds              []string
    55  	force                   bool
    56  	noDestroy               bool
    57  }
    58  
    59  // Info implements Command.Info.
    60  func (c *removeStorageCommand) Info() *cmd.Info {
    61  	return jujucmd.Info(&cmd.Info{
    62  		Name:    "remove-storage",
    63  		Purpose: "Removes storage from the model.",
    64  		Doc:     removeStorageCommandDoc,
    65  		Args:    removeStorageCommandArgs,
    66  	})
    67  }
    68  
    69  func (c *removeStorageCommand) SetFlags(f *gnuflag.FlagSet) {
    70  	c.StorageCommandBase.SetFlags(f)
    71  	f.BoolVar(&c.force, "force", false, "Remove storage even if it is currently attached")
    72  	f.BoolVar(&c.noDestroy, "no-destroy", false, "Remove the storage without destroying it")
    73  }
    74  
    75  // Init implements Command.Init.
    76  func (c *removeStorageCommand) Init(args []string) error {
    77  	if len(args) < 1 {
    78  		return errors.New("remove-storage requires at least one storage ID")
    79  	}
    80  	c.storageIds = args
    81  	return nil
    82  }
    83  
    84  // Run implements Command.Run.
    85  func (c *removeStorageCommand) Run(ctx *cmd.Context) error {
    86  	remover, err := c.newStorageRemoverCloser()
    87  	if err != nil {
    88  		return errors.Trace(err)
    89  	}
    90  	defer remover.Close()
    91  
    92  	destroyAttachments := c.force
    93  	destroyStorage := !c.noDestroy
    94  	results, err := remover.Remove(c.storageIds, destroyAttachments, destroyStorage)
    95  	if err != nil {
    96  		if params.IsCodeUnauthorized(err) {
    97  			common.PermissionsMessage(ctx.Stderr, "remove storage")
    98  		}
    99  		return err
   100  	}
   101  	for i, result := range results {
   102  		if result.Error == nil {
   103  			ctx.Infof("removing %s", c.storageIds[i])
   104  		}
   105  	}
   106  	anyFailed := false
   107  	anyAttached := false
   108  	for i, result := range results {
   109  		if result.Error != nil {
   110  			ctx.Infof("failed to remove %s: %s", c.storageIds[i], result.Error)
   111  			if params.IsCodeStorageAttached(result.Error) {
   112  				anyAttached = true
   113  			}
   114  			anyFailed = true
   115  		}
   116  	}
   117  	if anyAttached {
   118  		ctx.Infof(`
   119  Use the --force option to remove attached storage, or use
   120  "juju detach-storage" to explicitly detach the storage
   121  before removing.`)
   122  	}
   123  	if anyFailed {
   124  		return cmd.ErrSilent
   125  	}
   126  	return nil
   127  }
   128  
   129  // NewStorageRemoverCloserFunc is the type of a function that returns an
   130  // StorageRemoverCloser.
   131  type NewStorageRemoverCloserFunc func() (StorageRemoverCloser, error)
   132  
   133  // StorageRemoverCloser extends StorageRemover with a Closer method.
   134  type StorageRemoverCloser interface {
   135  	StorageRemover
   136  	Close() error
   137  }
   138  
   139  // StorageRemover defines an interface for destroying storage instances
   140  // with the specified IDs.
   141  type StorageRemover interface {
   142  	Remove(
   143  		storageIds []string,
   144  		destroyAttachments, destroyStorage bool,
   145  	) ([]params.ErrorResult, error)
   146  }