github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/application/removeapplication.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package application 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 "github.com/juju/romulus/api/budget" 10 wireformat "github.com/juju/romulus/wireformat/budget" 11 "gopkg.in/juju/charm.v6-unstable" 12 "gopkg.in/juju/names.v2" 13 "gopkg.in/macaroon-bakery.v1/httpbakery" 14 15 "github.com/juju/juju/api/application" 16 "github.com/juju/juju/api/charms" 17 "github.com/juju/juju/cmd/juju/block" 18 "github.com/juju/juju/cmd/modelcmd" 19 ) 20 21 // NewRemoveServiceCommand returns a command which removes an application. 22 func NewRemoveServiceCommand() cmd.Command { 23 return modelcmd.Wrap(&removeServiceCommand{}) 24 } 25 26 // removeServiceCommand causes an existing application to be destroyed. 27 type removeServiceCommand struct { 28 modelcmd.ModelCommandBase 29 ApplicationName string 30 } 31 32 var helpSummaryRmSvc = ` 33 Remove an application from the model.`[1:] 34 35 var helpDetailsRmSvc = ` 36 Removing an application will terminate any relations that application has, remove 37 all units of the application, and in the case that this leaves machines with 38 no running applications, Juju will also remove the machine. For this reason, 39 you should retrieve any logs or data required from applications and units 40 before removing them. Removing units which are co-located with units of 41 other charms or a Juju controller will not result in the removal of the 42 machine. 43 44 Examples: 45 juju remove-application hadoop 46 juju remove-application -m test-model mariadb`[1:] 47 48 func (c *removeServiceCommand) Info() *cmd.Info { 49 return &cmd.Info{ 50 Name: "remove-application", 51 Args: "<application>", 52 Purpose: helpSummaryRmSvc, 53 Doc: helpDetailsRmSvc, 54 } 55 } 56 57 func (c *removeServiceCommand) Init(args []string) error { 58 if len(args) == 0 { 59 return errors.Errorf("no application specified") 60 } 61 if !names.IsValidApplication(args[0]) { 62 return errors.Errorf("invalid application name %q", args[0]) 63 } 64 c.ApplicationName, args = args[0], args[1:] 65 return cmd.CheckEmpty(args) 66 } 67 68 type ServiceAPI interface { 69 Close() error 70 Destroy(serviceName string) error 71 DestroyUnits(unitNames ...string) error 72 GetCharmURL(serviceName string) (*charm.URL, error) 73 ModelUUID() string 74 } 75 76 func (c *removeServiceCommand) getAPI() (ServiceAPI, error) { 77 root, err := c.NewAPIRoot() 78 if err != nil { 79 return nil, errors.Trace(err) 80 } 81 return application.NewClient(root), nil 82 } 83 84 func (c *removeServiceCommand) Run(ctx *cmd.Context) error { 85 client, err := c.getAPI() 86 if err != nil { 87 return err 88 } 89 defer client.Close() 90 err = block.ProcessBlockedError(client.Destroy(c.ApplicationName), block.BlockRemove) 91 if err != nil { 92 return err 93 } 94 return c.removeAllocation(ctx) 95 } 96 97 func (c *removeServiceCommand) removeAllocation(ctx *cmd.Context) error { 98 client, err := c.getAPI() 99 if err != nil { 100 return err 101 } 102 charmURL, err := client.GetCharmURL(c.ApplicationName) 103 if err != nil { 104 return errors.Trace(err) 105 } 106 if charmURL.Schema == "local" { 107 return nil 108 } 109 110 root, err := c.NewAPIRoot() 111 if err != nil { 112 return errors.Trace(err) 113 } 114 charmsClient := charms.NewClient(root) 115 metered, err := charmsClient.IsMetered(charmURL.String()) 116 if err != nil { 117 return errors.Trace(err) 118 } 119 if !metered { 120 return nil 121 } 122 123 modelUUID := client.ModelUUID() 124 bakeryClient, err := c.BakeryClient() 125 if err != nil { 126 return errors.Trace(err) 127 } 128 budgetClient := getBudgetAPIClient(bakeryClient) 129 130 resp, err := budgetClient.DeleteAllocation(modelUUID, c.ApplicationName) 131 if wireformat.IsNotAvail(err) { 132 logger.Warningf("allocation not removed: %v", err) 133 } else if err != nil { 134 return err 135 } 136 if resp != "" { 137 logger.Infof(resp) 138 } 139 return nil 140 } 141 142 var getBudgetAPIClient = getBudgetAPIClientImpl 143 144 func getBudgetAPIClientImpl(bakeryClient *httpbakery.Client) budgetAPIClient { 145 return budget.NewClient(bakeryClient) 146 } 147 148 type budgetAPIClient interface { 149 DeleteAllocation(string, string) (string, error) 150 }