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 }