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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package budget defines the command used to update budgets.
     5  package budget
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/juju/cmd"
    13  	"github.com/juju/errors"
    14  	"github.com/juju/gnuflag"
    15  	api "github.com/juju/romulus/api/budget"
    16  	"github.com/juju/utils"
    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  )
    23  
    24  type budgetCommand struct {
    25  	modelcmd.ModelCommandBase
    26  	modelUUID string
    27  	api       apiClient
    28  	Wallet    string
    29  	Limit     string
    30  }
    31  
    32  // NewBudgetCommand returns a new budgetCommand.
    33  func NewBudgetCommand() cmd.Command {
    34  	return modelcmd.Wrap(&budgetCommand{})
    35  }
    36  
    37  func (c *budgetCommand) newBudgetAPIClient(apiRoot string, bakery *httpbakery.Client) (apiClient, error) {
    38  	if c.api != nil {
    39  		return c.api, nil
    40  	}
    41  	var err error
    42  	c.api, err = api.NewClient(api.APIRoot(apiRoot), api.HTTPClient(bakery))
    43  	if err != nil {
    44  		return nil, errors.Trace(err)
    45  	}
    46  	return c.api, nil
    47  }
    48  
    49  type apiClient interface {
    50  	UpdateBudget(string, string, string) (string, error)
    51  }
    52  
    53  const doc = `
    54  Updates an existing budget for a model.
    55  
    56  Examples:
    57      # Sets the budget for the current model to 10.
    58      juju budget 10
    59      # Moves the budget for the current model to wallet 'personal' and sets the limit to 10.
    60      juju budget personal:10
    61  `
    62  
    63  // Info implements cmd.Command.Info.
    64  func (c *budgetCommand) Info() *cmd.Info {
    65  	return jujucmd.Info(&cmd.Info{
    66  		Name:    "budget",
    67  		Args:    "[<wallet>:]<limit>",
    68  		Purpose: "Update a budget.",
    69  		Doc:     doc,
    70  	})
    71  }
    72  
    73  func (c *budgetCommand) SetFlags(f *gnuflag.FlagSet) {
    74  	f.StringVar(&c.modelUUID, "model-uuid", "", "Model uuid to set budget for.")
    75  	c.ModelCommandBase.SetFlags(f)
    76  }
    77  
    78  func budgetDefinition(input string) (wallet, limit string, err error) {
    79  	tokens := strings.Split(input, ":")
    80  	switch len(tokens) {
    81  	case 1:
    82  		return "", tokens[0], nil
    83  	case 2:
    84  		return tokens[0], tokens[1], nil
    85  	default:
    86  		return "", "", errors.Errorf("invalid budget definition: %v", input)
    87  	}
    88  }
    89  
    90  // Init implements cmd.Command.Init.
    91  func (c *budgetCommand) Init(args []string) error {
    92  	if len(args) < 1 {
    93  		return errors.New("value required")
    94  	}
    95  
    96  	wallet, limit, err := budgetDefinition(args[0])
    97  	if err != nil {
    98  		return errors.Trace(err)
    99  	}
   100  	if _, err := strconv.ParseInt(limit, 10, 32); err != nil {
   101  		return errors.New("budget limit needs to be a whole number")
   102  	}
   103  	c.Wallet = wallet
   104  	c.Limit = limit
   105  	if c.modelUUID != "" {
   106  		if !utils.IsValidUUIDString(c.modelUUID) {
   107  			return errors.NotValidf("provided model UUID %q", c.modelUUID)
   108  		}
   109  	}
   110  	return c.ModelCommandBase.Init(args[1:])
   111  }
   112  
   113  func (c *budgetCommand) getModelUUID() (string, error) {
   114  	if c.modelUUID != "" {
   115  		return c.modelUUID, nil
   116  	}
   117  	_, details, err := c.ModelCommandBase.ModelDetails()
   118  	if err != nil {
   119  		return "", errors.Trace(err)
   120  	}
   121  	return details.ModelUUID, nil
   122  }
   123  
   124  // Run implements cmd.Command.Run and contains most of the setwallet logic.
   125  func (c *budgetCommand) Run(ctx *cmd.Context) error {
   126  	modelUUID, err := c.getModelUUID()
   127  	if err != nil {
   128  		return errors.Annotate(err, "failed to get model uuid")
   129  	}
   130  	client, err := c.BakeryClient()
   131  	if err != nil {
   132  		return errors.Annotate(err, "failed to create an http client")
   133  	}
   134  	apiRoot, err := rcmd.GetMeteringURLForModelCmd(&c.ModelCommandBase)
   135  	if err != nil {
   136  		return errors.Trace(err)
   137  	}
   138  	api, err := c.newBudgetAPIClient(apiRoot, client)
   139  	if err != nil {
   140  		return errors.Annotate(err, "failed to create an api client")
   141  	}
   142  	resp, err := api.UpdateBudget(modelUUID, c.Wallet, c.Limit)
   143  	if err != nil {
   144  		return errors.Annotate(err, "failed to update the budget")
   145  	}
   146  	fmt.Fprintln(ctx.Stdout, resp)
   147  	return nil
   148  }