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  }