github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/romulus/allocate/allocate.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package allocate
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/gnuflag"
    14  	"github.com/juju/juju/cmd/modelcmd"
    15  	"github.com/juju/utils"
    16  	"gopkg.in/macaroon-bakery.v1/httpbakery"
    17  
    18  	api "github.com/juju/romulus/api/budget"
    19  )
    20  
    21  var budgetWithLimitRe = regexp.MustCompile(`^[a-zA-Z0-9\-]+:[0-9]+$`)
    22  
    23  type allocateCommand struct {
    24  	modelcmd.ModelCommandBase
    25  	api       apiClient
    26  	Budget    string
    27  	ModelUUID string
    28  	Services  []string
    29  	Limit     string
    30  }
    31  
    32  // NewAllocateCommand returns a new allocateCommand
    33  func NewAllocateCommand() modelcmd.ModelCommand {
    34  	return &allocateCommand{}
    35  }
    36  
    37  const doc = `
    38  Allocate budget for the specified applications, replacing any prior allocations
    39  made for the specified applications.
    40  
    41  Examples:
    42      # Assigns application "db" to an allocation on budget "somebudget" with
    43      # the limit "42".
    44      juju allocate somebudget:42 db
    45  
    46      # Application names assume the current selected model, unless otherwise
    47      # specified with:
    48      juju allocate -m [<controller name:]<model name> ...
    49  
    50      # Models may also be referenced by UUID when necessary:
    51       juju allocate --model-uuid <uuid> ...
    52  `
    53  
    54  // SetFlags implements cmd.Command.SetFlags.
    55  func (c *allocateCommand) SetFlags(f *gnuflag.FlagSet) {
    56  	c.ModelCommandBase.SetFlags(f)
    57  	f.StringVar(&c.ModelUUID, "model-uuid", "", "Model UUID of allocation")
    58  }
    59  
    60  // Info implements cmd.Command.Info.
    61  func (c *allocateCommand) Info() *cmd.Info {
    62  	return &cmd.Info{
    63  		Name:    "allocate",
    64  		Args:    "<budget>:<value> <application> [<application2> ...]",
    65  		Purpose: "Allocate budget to applications.",
    66  		Doc:     doc,
    67  	}
    68  }
    69  
    70  // Init implements cmd.Command.Init.
    71  func (c *allocateCommand) Init(args []string) error {
    72  	if len(args) < 2 {
    73  		return errors.New("budget and application name required")
    74  	}
    75  	budgetWithLimit := args[0]
    76  	var err error
    77  	c.Budget, c.Limit, err = parseBudgetWithLimit(budgetWithLimit)
    78  	if err != nil {
    79  		return errors.Annotate(err, `expected args in the form "budget:limit [application ...]"`)
    80  	}
    81  	if c.ModelUUID == "" {
    82  		c.ModelUUID, err = c.modelUUID()
    83  		if err != nil {
    84  			return err
    85  		}
    86  	} else {
    87  		if !utils.IsValidUUIDString(c.ModelUUID) {
    88  			return errors.NotValidf("model UUID %q", c.ModelUUID)
    89  		}
    90  	}
    91  
    92  	c.Services = args[1:]
    93  	return nil
    94  }
    95  
    96  // Run implements cmd.Command.Run and has most of the logic for the run command.
    97  func (c *allocateCommand) Run(ctx *cmd.Context) error {
    98  	client, err := c.BakeryClient()
    99  	if err != nil {
   100  		return errors.Annotate(err, "failed to create an http client")
   101  	}
   102  	api, err := c.newAPIClient(client)
   103  	if err != nil {
   104  		return errors.Annotate(err, "failed to create an api client")
   105  	}
   106  	resp, err := api.CreateAllocation(c.Budget, c.Limit, c.ModelUUID, c.Services)
   107  	if err != nil {
   108  		return errors.Annotate(err, "failed to create allocation")
   109  	}
   110  	fmt.Fprintln(ctx.Stdout, resp)
   111  	return nil
   112  }
   113  
   114  func (c *allocateCommand) modelUUID() (string, error) {
   115  	model, err := c.ClientStore().ModelByName(c.ControllerName(), c.ModelName())
   116  	if err != nil {
   117  		return "", errors.Trace(err)
   118  	}
   119  	return model.ModelUUID, nil
   120  }
   121  
   122  func parseBudgetWithLimit(bl string) (string, string, error) {
   123  	if !budgetWithLimitRe.MatchString(bl) {
   124  		return "", "", errors.New("invalid budget specification, expecting <budget>:<limit>")
   125  	}
   126  	parts := strings.Split(bl, ":")
   127  	return parts[0], parts[1], nil
   128  }
   129  
   130  func (c *allocateCommand) newAPIClient(bakery *httpbakery.Client) (apiClient, error) {
   131  	if c.api != nil {
   132  		return c.api, nil
   133  	}
   134  	c.api = api.NewClient(bakery)
   135  	return c.api, nil
   136  }
   137  
   138  type apiClient interface {
   139  	CreateAllocation(string, string, string, []string) (string, error)
   140  }