github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/destroyenvironment.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package main
     5  
     6  import (
     7  	"bufio"
     8  	stderrors "errors"
     9  	"fmt"
    10  	"io"
    11  	"strings"
    12  
    13  	"github.com/juju/cmd"
    14  	"github.com/juju/errors"
    15  	"launchpad.net/gnuflag"
    16  
    17  	"github.com/juju/juju/apiserver/params"
    18  	"github.com/juju/juju/cmd/envcmd"
    19  	"github.com/juju/juju/cmd/juju/block"
    20  	"github.com/juju/juju/environs"
    21  	"github.com/juju/juju/environs/configstore"
    22  	"github.com/juju/juju/juju"
    23  )
    24  
    25  var NoEnvironmentError = stderrors.New("no environment specified")
    26  var DoubleEnvironmentError = stderrors.New("you cannot supply both -e and the envname as a positional argument")
    27  
    28  // DestroyEnvironmentCommand destroys an environment.
    29  type DestroyEnvironmentCommand struct {
    30  	envcmd.EnvCommandBase
    31  	cmd.CommandBase
    32  	envName   string
    33  	assumeYes bool
    34  	force     bool
    35  }
    36  
    37  func (c *DestroyEnvironmentCommand) Info() *cmd.Info {
    38  	return &cmd.Info{
    39  		Name:    "destroy-environment",
    40  		Args:    "<environment name>",
    41  		Purpose: "terminate all machines and other associated resources for an environment",
    42  	}
    43  }
    44  
    45  func (c *DestroyEnvironmentCommand) SetFlags(f *gnuflag.FlagSet) {
    46  	f.BoolVar(&c.assumeYes, "y", false, "Do not ask for confirmation")
    47  	f.BoolVar(&c.assumeYes, "yes", false, "")
    48  	f.BoolVar(&c.force, "force", false, "Forcefully destroy the environment, directly through the environment provider")
    49  	f.StringVar(&c.envName, "e", "", "juju environment to operate in")
    50  	f.StringVar(&c.envName, "environment", "", "juju environment to operate in")
    51  }
    52  
    53  func (c *DestroyEnvironmentCommand) Init(args []string) error {
    54  	if c.envName != "" {
    55  		logger.Warningf("-e/--environment flag is deprecated in 1.18, " +
    56  			"please supply environment as a positional parameter")
    57  		// They supplied the -e flag
    58  		if len(args) == 0 {
    59  			// We're happy, we have enough information
    60  			return nil
    61  		}
    62  		// You can't supply -e ENV and ENV as a positional argument
    63  		return DoubleEnvironmentError
    64  	}
    65  	// No -e flag means they must supply the environment positionally
    66  	switch len(args) {
    67  	case 0:
    68  		return NoEnvironmentError
    69  	case 1:
    70  		c.envName = args[0]
    71  		return nil
    72  	default:
    73  		return cmd.CheckEmpty(args[1:])
    74  	}
    75  }
    76  
    77  func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) {
    78  	store, err := configstore.Default()
    79  	if err != nil {
    80  		return fmt.Errorf("cannot open environment info storage: %v", err)
    81  	}
    82  	environ, err := environs.NewFromName(c.envName, store)
    83  	if err != nil {
    84  		if environs.IsEmptyConfig(err) {
    85  			// Delete the .jenv file and call it done.
    86  			ctx.Infof("removing empty environment file")
    87  			return environs.DestroyInfo(c.envName, store)
    88  		}
    89  		return err
    90  	}
    91  	if !c.assumeYes {
    92  		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.envName, environ.Config().Type())
    93  
    94  		scanner := bufio.NewScanner(ctx.Stdin)
    95  		scanner.Scan()
    96  		err := scanner.Err()
    97  		if err != nil && err != io.EOF {
    98  			return fmt.Errorf("Environment destruction aborted: %s", err)
    99  		}
   100  		answer := strings.ToLower(scanner.Text())
   101  		if answer != "y" && answer != "yes" {
   102  			return stderrors.New("environment destruction aborted")
   103  		}
   104  	}
   105  	// If --force is supplied, then don't attempt to use the API.
   106  	// This is necessary to destroy broken environments, where the
   107  	// API server is inaccessible or faulty.
   108  	if !c.force {
   109  		defer func() {
   110  			result = c.ensureUserFriendlyErrorLog(result)
   111  		}()
   112  		apiclient, err := juju.NewAPIClientFromName(c.envName)
   113  		if err != nil {
   114  			return errors.Annotate(err, "cannot connect to API")
   115  		}
   116  		defer apiclient.Close()
   117  		err = apiclient.DestroyEnvironment()
   118  		if cmdErr := processDestroyError(err); cmdErr != nil {
   119  			return cmdErr
   120  		}
   121  	}
   122  	return environs.Destroy(environ, store)
   123  }
   124  
   125  // processDestroyError determines how to format error message based on its code.
   126  // Note that CodeNotImplemented errors have not be propogated in previous implementation.
   127  // This behaviour was preserved.
   128  func processDestroyError(err error) error {
   129  	if err == nil || params.IsCodeNotImplemented(err) {
   130  		return nil
   131  	}
   132  	if params.IsCodeOperationBlocked(err) {
   133  		return err
   134  	}
   135  	return errors.Annotate(err, "destroying environment")
   136  }
   137  
   138  // ensureUserFriendlyErrorLog ensures that error will be logged and displayed
   139  // in a user-friendly manner with readable and digestable error message.
   140  func (c *DestroyEnvironmentCommand) ensureUserFriendlyErrorLog(err error) error {
   141  	if err == nil {
   142  		return nil
   143  	}
   144  	if params.IsCodeOperationBlocked(err) {
   145  		return block.ProcessBlockedError(err, block.BlockDestroy)
   146  	}
   147  	logger.Errorf(stdFailureMsg, c.envName)
   148  	return err
   149  }
   150  
   151  var destroyEnvMsg = `
   152  WARNING! this command will destroy the %q environment (type: %s)
   153  This includes all machines, services, data and other resources.
   154  
   155  Continue [y/N]? `[1:]
   156  
   157  var stdFailureMsg = `failed to destroy environment %q
   158  
   159  If the environment is unusable, then you may run
   160  
   161      juju destroy-environment --force
   162  
   163  to forcefully destroy the environment. Upon doing so, review
   164  your environment provider console for any resources that need
   165  to be cleaned up. Using force will also by-pass destroy-envrionment block.
   166  
   167  `