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