github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/romulus/setplan/set_plan.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The setplan package contains the implementation of the juju set-plan
     5  // command.
     6  package setplan
     7  
     8  import (
     9  	"encoding/json"
    10  	"net/url"
    11  
    12  	"github.com/juju/juju/core/model"
    13  
    14  	"github.com/juju/cmd"
    15  	"github.com/juju/errors"
    16  	api "github.com/juju/romulus/api/plan"
    17  	"gopkg.in/juju/names.v2"
    18  	"gopkg.in/macaroon.v2-unstable"
    19  
    20  	"github.com/juju/juju/api/application"
    21  	jujucmd "github.com/juju/juju/cmd"
    22  	rcmd "github.com/juju/juju/cmd/juju/romulus"
    23  	"github.com/juju/juju/cmd/modelcmd"
    24  )
    25  
    26  // authorizationClient defines the interface of an api client that
    27  // the command uses to create an authorization macaroon.
    28  type authorizationClient interface {
    29  	// Authorize returns the authorization macaroon for the specified environment,
    30  	// charm url, application name and plan.
    31  	Authorize(environmentUUID, charmURL, applicationName, plan string, visitWebPage func(*url.URL) error) (*macaroon.Macaroon, error)
    32  }
    33  
    34  var newAuthorizationClient = func(options ...api.ClientOption) (authorizationClient, error) {
    35  	return api.NewAuthorizationClient(options...)
    36  }
    37  
    38  // NewSetPlanCommand returns a new command that is used to set metric credentials for a
    39  // deployed application.
    40  func NewSetPlanCommand() cmd.Command {
    41  	return modelcmd.Wrap(&setPlanCommand{})
    42  }
    43  
    44  // setPlanCommand is a command-line tool for setting
    45  // Application.MetricCredential for development & demonstration purposes.
    46  type setPlanCommand struct {
    47  	modelcmd.ModelCommandBase
    48  
    49  	Application string
    50  	Plan        string
    51  }
    52  
    53  // Info implements cmd.Command.
    54  func (c *setPlanCommand) Info() *cmd.Info {
    55  	return jujucmd.Info(&cmd.Info{
    56  		Name:    "set-plan",
    57  		Args:    "<application name> <plan>",
    58  		Purpose: "Set the plan for an application.",
    59  		Doc: `
    60  Set the plan for the deployed application, effective immediately.
    61  
    62  The specified plan name must be a valid plan that is offered for this
    63  particular charm. Use "juju list-plans <charm>" for more information.
    64  
    65  Examples:
    66      juju set-plan myapp example/uptime
    67  `,
    68  	})
    69  }
    70  
    71  // Init implements cmd.Command.
    72  func (c *setPlanCommand) Init(args []string) error {
    73  	if len(args) < 2 {
    74  		return errors.New("need to specify application name and plan url")
    75  	}
    76  
    77  	applicationName := args[0]
    78  	if !names.IsValidApplication(applicationName) {
    79  		return errors.Errorf("invalid application name %q", applicationName)
    80  	}
    81  
    82  	c.Plan = args[1]
    83  	c.Application = applicationName
    84  
    85  	return c.ModelCommandBase.Init(args[2:])
    86  }
    87  
    88  func (c *setPlanCommand) requestMetricCredentials(client *application.Client, ctx *cmd.Context) ([]byte, error) {
    89  	charmURL, err := client.GetCharmURL(model.GenerationCurrent, c.Application)
    90  	if err != nil {
    91  		return nil, errors.Trace(err)
    92  	}
    93  
    94  	hc, err := c.BakeryClient()
    95  	if err != nil {
    96  		return nil, errors.Trace(err)
    97  	}
    98  	apiRoot, err := rcmd.GetMeteringURLForModelCmd(&c.ModelCommandBase)
    99  	if err != nil {
   100  		return nil, errors.Trace(err)
   101  	}
   102  	authClient, err := newAuthorizationClient(api.APIRoot(apiRoot), api.HTTPClient(hc))
   103  	if err != nil {
   104  		return nil, errors.Trace(err)
   105  	}
   106  	m, err := authClient.Authorize(client.ModelUUID(), charmURL.String(), c.Application, c.Plan, hc.VisitWebPage)
   107  	if err != nil {
   108  		return nil, errors.Trace(err)
   109  	}
   110  	ms := macaroon.Slice{m}
   111  	return json.Marshal(ms)
   112  }
   113  
   114  // Run implements cmd.Command.
   115  func (c *setPlanCommand) Run(ctx *cmd.Context) error {
   116  	root, err := c.NewAPIRoot()
   117  	if err != nil {
   118  		return errors.Trace(err)
   119  	}
   120  	client := application.NewClient(root)
   121  	credentials, err := c.requestMetricCredentials(client, ctx)
   122  	if err != nil {
   123  		return errors.Trace(err)
   124  	}
   125  	err = client.SetMetricCredentials(c.Application, credentials)
   126  	if err != nil {
   127  		return errors.Trace(err)
   128  	}
   129  	return nil
   130  }