github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/cmd/juju/block/unblock.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package block
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	"launchpad.net/gnuflag"
    13  
    14  	"github.com/juju/juju/cmd/modelcmd"
    15  )
    16  
    17  // NewUnblockCommand returns a new command that removes the block from
    18  // the specified operation.
    19  func NewUnblockCommand() cmd.Command {
    20  	c := &unblockCommand{}
    21  	c.getClient = func() (UnblockClientAPI, error) {
    22  		return getBlockAPI(&c.ModelCommandBase)
    23  	}
    24  	return modelcmd.Wrap(c)
    25  }
    26  
    27  // unblockCommand removes the block from desired operation.
    28  type unblockCommand struct {
    29  	modelcmd.ModelCommandBase
    30  	operation string
    31  	getClient func() (UnblockClientAPI, error)
    32  }
    33  
    34  var (
    35  	unblockDoc = `
    36  
    37  Juju allows to safeguard deployed models from unintentional damage by preventing
    38  execution of operations that could alter model.
    39  
    40  This is done by blocking certain commands from successful execution. Blocked commands
    41  must be manually unblocked to proceed.
    42  
    43  Some commands offer a --force option that can be used to bypass a block.
    44  
    45  Commands that can be unblocked are grouped based on logical operations as follows:
    46  
    47  destroy-model includes command:
    48      destroy-model
    49  
    50  remove-object includes termination commands:
    51      destroy-model
    52      remove-machine
    53      remove-relation
    54      remove-service
    55      remove-unit
    56  
    57  all-changes includes all alteration commands
    58      add-machine
    59      add-relation
    60      add-unit
    61      authorised-keys add
    62      authorised-keys delete
    63      authorised-keys import
    64      deploy
    65      destroy-model
    66      enable-ha
    67      expose
    68      remove-machine
    69      remove-relation
    70      remove-service
    71      remove-unit
    72      resolved
    73      retry-provisioning
    74      run
    75      set
    76      set-constraints
    77      set-model-config
    78      sync-tools
    79      unexpose
    80      unset
    81      unset-model-config
    82      upgrade-charm
    83      upgrade-juju
    84      add-user
    85      change-user-password
    86      disable-user
    87      enable-user
    88  
    89  Examples:
    90     To allow the model to be destroyed:
    91     juju unblock destroy-model
    92  
    93     To allow the machines, services, units and relations to be removed:
    94     juju unblock remove-object
    95  
    96     To allow changes to the model:
    97     juju unblock all-changes
    98  
    99  See Also:
   100     juju help block
   101  `
   102  
   103  	// blockArgsFmt has formatted representation of block command valid arguments.
   104  	blockArgsFmt = fmt.Sprintf(strings.Join(blockArgs, " | "))
   105  )
   106  
   107  // assignValidOperation verifies that supplied operation is supported.
   108  func (p *unblockCommand) assignValidOperation(cmd string, args []string) error {
   109  	if len(args) < 1 {
   110  		return errors.Trace(errors.Errorf("must specify one of [%v] to %v", blockArgsFmt, cmd))
   111  	}
   112  	var err error
   113  	p.operation, err = p.obtainValidArgument(args[0])
   114  	return err
   115  }
   116  
   117  // obtainValidArgument returns polished argument:
   118  // it checks that the argument is a supported operation and
   119  // forces it into lower case for consistency.
   120  func (p *unblockCommand) obtainValidArgument(arg string) (string, error) {
   121  	for _, valid := range blockArgs {
   122  		if strings.EqualFold(valid, arg) {
   123  			return strings.ToLower(arg), nil
   124  		}
   125  	}
   126  	return "", errors.Trace(errors.Errorf("%q is not a valid argument: use one of [%v]", arg, blockArgsFmt))
   127  }
   128  
   129  // Info provides information about command.
   130  // Satisfying Command interface.
   131  func (c *unblockCommand) Info() *cmd.Info {
   132  	return &cmd.Info{
   133  		Name:    "unblock",
   134  		Args:    blockArgsFmt,
   135  		Purpose: "unblock an operation that would alter a running model",
   136  		Doc:     unblockDoc,
   137  	}
   138  }
   139  
   140  // Init initializes the command.
   141  // Satisfying Command interface.
   142  func (c *unblockCommand) Init(args []string) error {
   143  	if len(args) > 1 {
   144  		return errors.Trace(errors.New("can only specify block type"))
   145  	}
   146  
   147  	return c.assignValidOperation("unblock", args)
   148  }
   149  
   150  // SetFlags implements Command.SetFlags.
   151  func (c *unblockCommand) SetFlags(f *gnuflag.FlagSet) {
   152  	c.ModelCommandBase.SetFlags(f)
   153  }
   154  
   155  // Run unblocks previously blocked commands.
   156  // Satisfying Command interface.
   157  func (c *unblockCommand) Run(_ *cmd.Context) error {
   158  	client, err := c.getClient()
   159  	if err != nil {
   160  		return errors.Trace(err)
   161  	}
   162  	defer client.Close()
   163  
   164  	return client.SwitchBlockOff(TypeFromOperation(c.operation))
   165  }
   166  
   167  // UnblockClientAPI defines the client API methods that unblock command uses.
   168  type UnblockClientAPI interface {
   169  	Close() error
   170  	SwitchBlockOff(blockType string) error
   171  }
   172  
   173  var getUnblockClientAPI = func(p *unblockCommand) (UnblockClientAPI, error) {
   174  	return getBlockAPI(&p.ModelCommandBase)
   175  }