github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/environment/destroy.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for infos. 3 4 package environment 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "launchpad.net/gnuflag" 12 13 "github.com/juju/juju/apiserver/params" 14 jujucmd "github.com/juju/juju/cmd" 15 "github.com/juju/juju/cmd/envcmd" 16 "github.com/juju/juju/cmd/juju/block" 17 "github.com/juju/juju/environs" 18 "github.com/juju/juju/environs/configstore" 19 ) 20 21 // DestroyCommand destroys the specified environment. 22 type DestroyCommand struct { 23 envcmd.EnvCommandBase 24 envName string 25 assumeYes bool 26 api DestroyEnvironmentAPI 27 } 28 29 var destroyDoc = `Destroys the specified environment` 30 var destroyEnvMsg = ` 31 WARNING! This command will destroy the %q environment. 32 This includes all machines, services, data and other resources. 33 34 Continue [y/N]? `[1:] 35 36 // DestroyEnvironmentAPI defines the methods on the environmentmanager 37 // API that the destroy command calls. It is exported for mocking in tests. 38 type DestroyEnvironmentAPI interface { 39 Close() error 40 DestroyEnvironment() error 41 } 42 43 // Info implements Command.Info. 44 func (c *DestroyCommand) Info() *cmd.Info { 45 return &cmd.Info{ 46 Name: "destroy", 47 Args: "<environment name>", 48 Purpose: "terminate all machines and other associated resources for a non-system environment", 49 Doc: destroyDoc, 50 } 51 } 52 53 // SetFlags implements Command.SetFlags. 54 func (c *DestroyCommand) SetFlags(f *gnuflag.FlagSet) { 55 f.BoolVar(&c.assumeYes, "y", false, "Do not ask for confirmation") 56 f.BoolVar(&c.assumeYes, "yes", false, "") 57 } 58 59 // Init implements Command.Init. 60 func (c *DestroyCommand) Init(args []string) error { 61 switch len(args) { 62 case 0: 63 return errors.New("no environment specified") 64 case 1: 65 c.envName = args[0] 66 c.SetEnvName(c.envName) 67 return nil 68 default: 69 return cmd.CheckEmpty(args[1:]) 70 } 71 } 72 73 func (c *DestroyCommand) getAPI() (DestroyEnvironmentAPI, error) { 74 if c.api != nil { 75 return c.api, nil 76 } 77 return c.NewAPIClient() 78 } 79 80 // Run implements Command.Run 81 func (c *DestroyCommand) Run(ctx *cmd.Context) error { 82 store, err := configstore.Default() 83 if err != nil { 84 return errors.Annotate(err, "cannot open environment info storage") 85 } 86 87 cfgInfo, err := store.ReadInfo(c.envName) 88 if err != nil { 89 return errors.Annotate(err, "cannot read environment info") 90 } 91 92 // Verify that we're not destroying a system 93 apiEndpoint := cfgInfo.APIEndpoint() 94 if apiEndpoint.ServerUUID != "" && apiEndpoint.EnvironUUID == apiEndpoint.ServerUUID { 95 return errors.Errorf("%q is a system; use 'juju system destroy' to destroy it", c.envName) 96 } 97 98 if !c.assumeYes { 99 fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.envName) 100 101 if err := jujucmd.UserConfirmYes(ctx); err != nil { 102 return errors.Annotate(err, "environment destruction") 103 } 104 } 105 106 // Attempt to connect to the API. If we can't, fail the destroy. 107 api, err := c.getAPI() 108 if err != nil { 109 return errors.Annotate(err, "cannot connect to API") 110 } 111 defer api.Close() 112 113 // Attempt to destroy the environment. 114 err = api.DestroyEnvironment() 115 if err != nil { 116 return c.handleError(errors.Annotate(err, "cannot destroy environment")) 117 } 118 119 return environs.DestroyInfo(c.envName, store) 120 } 121 122 func (c *DestroyCommand) handleError(err error) error { 123 if err == nil { 124 return nil 125 } 126 if params.IsCodeOperationBlocked(err) { 127 return block.ProcessBlockedError(err, block.BlockDestroy) 128 } 129 logger.Errorf(`failed to destroy environment %q`, c.envName) 130 return err 131 }