~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/romulus/cmd/allocate/allocate.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        "launchpad.net/gnuflag"
 
12
 
 
13
        "github.com/juju/cmd"
 
14
        "github.com/juju/errors"
 
15
        "github.com/juju/juju/cmd/modelcmd"
 
16
        "github.com/juju/utils"
 
17
        "gopkg.in/macaroon-bakery.v1/httpbakery"
 
18
 
 
19
        api "github.com/juju/romulus/api/budget"
 
20
)
 
21
 
 
22
var budgetWithLimitRe = regexp.MustCompile(`^[a-zA-Z0-9\-]+:[0-9]+$`)
 
23
 
 
24
type allocateCommand struct {
 
25
        modelcmd.ModelCommandBase
 
26
        api       apiClient
 
27
        Budget    string
 
28
        ModelUUID string
 
29
        Services  []string
 
30
        Limit     string
 
31
}
 
32
 
 
33
// NewAllocateCommand returns a new allocateCommand
 
34
func NewAllocateCommand() modelcmd.ModelCommand {
 
35
        return &allocateCommand{}
 
36
}
 
37
 
 
38
const doc = `
 
39
Allocate budget for the specified applications, replacing any prior allocations
 
40
made for the specified applications.
 
41
 
 
42
Examples:
 
43
    # Assigns application "db" to an allocation on budget "somebudget" with
 
44
    # the limit "42".
 
45
    juju allocate somebudget:42 db
 
46
 
 
47
    # Application names assume the current selected model, unless otherwise
 
48
    # specified with:
 
49
    juju allocate -m [<controller name:]<model name> ...
 
50
 
 
51
    # Models may also be referenced by UUID when necessary:
 
52
     juju allocate --model-uuid <uuid> ...
 
53
`
 
54
 
 
55
// SetFlags implements cmd.Command.SetFlags.
 
56
func (c *allocateCommand) SetFlags(f *gnuflag.FlagSet) {
 
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
}