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