github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/romulus/showwallet/show_wallet.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package showwallet 5 6 import ( 7 "fmt" 8 "io" 9 10 "github.com/gosuri/uitable" 11 "github.com/juju/cmd" 12 "github.com/juju/errors" 13 "github.com/juju/gnuflag" 14 "github.com/juju/loggo" 15 api "github.com/juju/romulus/api/budget" 16 wireformat "github.com/juju/romulus/wireformat/budget" 17 "gopkg.in/macaroon-bakery.v2-unstable/httpbakery" 18 19 jujucmd "github.com/juju/juju/cmd" 20 rcmd "github.com/juju/juju/cmd/juju/romulus" 21 "github.com/juju/juju/cmd/modelcmd" 22 "github.com/juju/juju/jujuclient" 23 ) 24 25 var logger = loggo.GetLogger("romulus.cmd.showwallet") 26 27 // NewShowWalletCommand returns a new command that is used 28 // to show details of the specified wireformat. 29 func NewShowWalletCommand() modelcmd.ControllerCommand { 30 return modelcmd.WrapController(&showWalletCommand{}) 31 } 32 33 type showWalletCommand struct { 34 modelcmd.ControllerCommandBase 35 36 out cmd.Output 37 wallet string 38 } 39 40 const showWalletDoc = ` 41 Display wallet usage information. 42 43 Examples: 44 juju show-wallet personal 45 ` 46 47 // Info implements cmd.Command.Info. 48 func (c *showWalletCommand) Info() *cmd.Info { 49 return jujucmd.Info(&cmd.Info{ 50 Name: "show-wallet", 51 Args: "<wallet>", 52 Purpose: "Show details about a wallet.", 53 Doc: showWalletDoc, 54 }) 55 } 56 57 // Init implements cmd.Command.Init. 58 func (c *showWalletCommand) Init(args []string) error { 59 if len(args) < 1 { 60 return errors.New("missing arguments") 61 } 62 c.wallet, args = args[0], args[1:] 63 64 return c.CommandBase.Init(args) 65 } 66 67 // SetFlags implements cmd.Command.SetFlags. 68 func (c *showWalletCommand) SetFlags(f *gnuflag.FlagSet) { 69 c.CommandBase.SetFlags(f) 70 c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{ 71 "tabular": c.formatTabular, 72 "json": cmd.FormatJson, 73 }) 74 } 75 76 func (c *showWalletCommand) Run(ctx *cmd.Context) error { 77 client, err := c.BakeryClient() 78 if err != nil { 79 return errors.Annotate(err, "failed to create an http client") 80 } 81 apiRoot, err := rcmd.GetMeteringURLForControllerCmd(&c.ControllerCommandBase) 82 if err != nil { 83 return errors.Trace(err) 84 } 85 api, err := newWalletAPIClient(apiRoot, client) 86 if err != nil { 87 return errors.Annotate(err, "failed to create an api client") 88 } 89 wallet, err := api.GetWallet(c.wallet) 90 if err != nil { 91 return errors.Annotate(err, "failed to retrieve the wallet") 92 } 93 err = c.out.Write(ctx, wallet) 94 return errors.Trace(err) 95 } 96 97 // formatTabular returns a tabular view of available wallets. 98 func (c *showWalletCommand) formatTabular(writer io.Writer, value interface{}) error { 99 b, ok := value.(*wireformat.WalletWithBudgets) 100 if !ok { 101 return errors.Errorf("expected value of type %T, got %T", b, value) 102 } 103 104 table := uitable.New() 105 table.MaxColWidth = 50 106 table.Wrap = true 107 for _, col := range []int{2, 3, 5} { 108 table.RightAlign(col) 109 } 110 111 uuidToModelName, err := c.modelNameMap() 112 if err != nil { 113 logger.Warningf("failed to read juju client model names") 114 uuidToModelName = map[string]string{} 115 } 116 table.AddRow("Model", "Spent", "Budgeted", "By", "Usage") 117 for _, budget := range b.Budgets { 118 modelName := uuidToModelName[budget.Model] 119 if modelName == "" { 120 modelName = budget.Model 121 } 122 table.AddRow(modelName, budget.Consumed, budget.Limit, budget.Owner, budget.Usage) 123 } 124 table.AddRow("", "", "", "") 125 table.AddRow("Total", b.Total.Consumed, b.Total.Budgeted, "", b.Total.Usage) 126 table.AddRow("Wallet", "", b.Limit, "") 127 table.AddRow("Unallocated", "", b.Total.Unallocated, "") 128 fmt.Fprint(writer, table) 129 return nil 130 } 131 132 func (c *showWalletCommand) modelNameMap() (map[string]string, error) { 133 store := newJujuclientStore() 134 uuidToName := map[string]string{} 135 controllers, err := store.AllControllers() 136 if err != nil { 137 return nil, errors.Trace(err) 138 } 139 for cname := range controllers { 140 models, err := store.AllModels(cname) 141 if err != nil { 142 return nil, errors.Trace(err) 143 } 144 for mname, mdetails := range models { 145 uuidToName[mdetails.ModelUUID] = cname + ":" + mname 146 } 147 } 148 return uuidToName, nil 149 } 150 151 var newWalletAPIClient = newWalletAPIClientImpl 152 153 func newWalletAPIClientImpl(apiRoot string, c *httpbakery.Client) (walletAPIClient, error) { 154 return api.NewClient(api.APIRoot(apiRoot), api.HTTPClient(c)) 155 } 156 157 type walletAPIClient interface { 158 GetWallet(string) (*wireformat.WalletWithBudgets, error) 159 } 160 161 var newJujuclientStore = jujuclient.NewFileClientStore