blob: 52061a19b73a445a0f1a488561d0d2308611ee94 [file] [log] [blame]
Brad Ison53e997c2016-03-26 18:02:05 -04001package policies
2
3import (
Brad Isone7d6dfc2016-04-06 14:55:07 -04004 "errors"
5
Brad Ison53e997c2016-03-26 18:02:05 -04006 "github.com/rackspace/gophercloud"
7 "github.com/rackspace/gophercloud/pagination"
8)
9
Brad Isone7d6dfc2016-04-06 14:55:07 -040010// Validation errors returned by create or update operations.
11var (
Brad Ison4d1a9a62016-04-07 21:31:52 -040012 ErrNoName = errors.New("Policy name cannot by empty.")
13 ErrNoArgs = errors.New("Args cannot be nil for schedule policies.")
Brad Isoneedc8d92016-04-11 13:15:16 -040014 ErrCooldownRange = errors.New("Cooldown is out of range (0, 86400).")
15 ErrUnknownType = errors.New("Unknown policy type.")
16 ErrUnknownAdjustment = errors.New("Unknown adjustment type.")
Brad Isone7d6dfc2016-04-06 14:55:07 -040017)
18
Brad Ison53e997c2016-03-26 18:02:05 -040019// List returns all scaling policies for a group.
20func List(client *gophercloud.ServiceClient, groupID string) pagination.Pager {
21 url := listURL(client, groupID)
22
23 createPageFn := func(r pagination.PageResult) pagination.Page {
24 return PolicyPage{pagination.SinglePageBase(r)}
25 }
26
27 return pagination.NewPager(client, url, createPageFn)
28}
Brad Isone7d6dfc2016-04-06 14:55:07 -040029
30// CreateOptsBuilder is the interface responsible for generating the map that
31// will be marshalled to JSON for a Create operation.
32type CreateOptsBuilder interface {
33 ToPolicyCreateMap() ([]map[string]interface{}, error)
34}
35
Brad Isone7d6dfc2016-04-06 14:55:07 -040036// CreateOpts is a slice of CreateOpt structs that allow the user to create
37// multiple policies in a single operation.
38type CreateOpts []CreateOpt
39
40// CreateOpt represents the options to create a policy.
41type CreateOpt struct {
42 // Name [required] is a name for the policy.
43 Name string
44
45 // Type [required] of policy, i.e. either "webhook" or "schedule".
46 Type Type
47
48 // Cooldown [required] period in seconds.
49 Cooldown int
50
Brad Isonb35ef6d2016-04-09 16:54:57 -040051 // AdjustmentType [requried] is the method used to change the capacity of
52 // the group, i.e. one of: Change, ChangePercent, or DesiredCapacity.
53 AdjustmentType AdjustmentType
54
55 // AdjustmentValue [required] is the numeric value of the adjustment. For
56 // adjustments of type Change or DesiredCapacity, this will be converted to
57 // an integer.
58 AdjustmentValue float64
Brad Isone7d6dfc2016-04-06 14:55:07 -040059
60 // Additional configuration options for some types of policy.
61 Args map[string]interface{}
62}
63
64// ToPolicyCreateMap converts a slice of CreateOpt structs into a map for use
65// in the request body of a Create operation.
66func (opts CreateOpts) ToPolicyCreateMap() ([]map[string]interface{}, error) {
67 var policies []map[string]interface{}
68
69 for _, o := range opts {
70 if o.Name == "" {
71 return nil, ErrNoName
72 }
73
74 if o.Type == Schedule && o.Args == nil {
75 return nil, ErrNoArgs
76 }
77
Brad Isoneedc8d92016-04-11 13:15:16 -040078 if ok := validateType(o.Type); !ok {
79 return nil, ErrUnknownType
80 }
81
82 if ok := validateCooldown(o.Cooldown); !ok {
83 return nil, ErrCooldownRange
84 }
85
Brad Isone7d6dfc2016-04-06 14:55:07 -040086 policy := make(map[string]interface{})
87
88 policy["name"] = o.Name
89 policy["type"] = o.Type
90 policy["cooldown"] = o.Cooldown
91
Brad Isonb35ef6d2016-04-09 16:54:57 -040092 err := setAdjustment(o.AdjustmentType, o.AdjustmentValue, policy)
93
94 if err != nil {
Brad Ison4d1a9a62016-04-07 21:31:52 -040095 return nil, err
96 }
Brad Isone7d6dfc2016-04-06 14:55:07 -040097
98 if o.Args != nil {
99 policy["args"] = o.Args
100 }
101
102 policies = append(policies, policy)
103 }
104
105 return policies, nil
106}
107
108// Create requests a new policy be created and associated with the given group.
109func Create(client *gophercloud.ServiceClient, groupID string, opts CreateOptsBuilder) CreateResult {
110 var res CreateResult
111
112 reqBody, err := opts.ToPolicyCreateMap()
113
114 if err != nil {
115 res.Err = err
116 return res
117 }
118
119 _, res.Err = client.Post(createURL(client, groupID), reqBody, &res.Body, nil)
120
121 return res
122}
Brad Ison55523e52016-04-06 19:25:20 -0400123
124// Get requests the details of a single policy with the given ID.
125func Get(client *gophercloud.ServiceClient, groupID, policyID string) GetResult {
126 var result GetResult
127
128 _, result.Err = client.Get(getURL(client, groupID, policyID), &result.Body, nil)
129
130 return result
131}
Brad Isonac037d52016-04-07 19:41:29 -0400132
133// UpdateOptsBuilder is the interface responsible for generating the map
134// structure for producing JSON for an Update operation.
135type UpdateOptsBuilder interface {
136 ToPolicyUpdateMap() (map[string]interface{}, error)
137}
138
139// UpdateOpts represents the options for updating an existing policy.
140//
141// Update operations completely replace the configuration being updated. Empty
142// values in the update are accepted and overwrite previously specified
143// parameters.
144type UpdateOpts struct {
145 // Name [required] is a name for the policy.
146 Name string
147
148 // Type [required] of policy, i.e. either "webhook" or "schedule".
149 Type Type
150
151 // Cooldown [required] period in seconds. If you don't specify a cooldown,
152 // it will default to zero, and the policy will be configured as such.
153 Cooldown int
154
Brad Isonb35ef6d2016-04-09 16:54:57 -0400155 // AdjustmentType [requried] is the method used to change the capacity of
156 // the group, i.e. one of: Change, ChangePercent, or DesiredCapacity.
157 AdjustmentType AdjustmentType
158
159 // AdjustmentValue [required] is the numeric value of the adjustment. For
160 // adjustments of type Change or DesiredCapacity, this will be converted to
161 // an integer.
162 AdjustmentValue float64
Brad Isonac037d52016-04-07 19:41:29 -0400163
164 // Additional configuration options for some types of policy.
165 Args map[string]interface{}
166}
167
168// ToPolicyUpdateMap converts an UpdateOpts struct into a map for use as the
169// request body in an Update request.
170func (opts UpdateOpts) ToPolicyUpdateMap() (map[string]interface{}, error) {
171 if opts.Name == "" {
172 return nil, ErrNoName
173 }
174
175 if opts.Type == Schedule && opts.Args == nil {
176 return nil, ErrNoArgs
177 }
178
Brad Isoneedc8d92016-04-11 13:15:16 -0400179 if ok := validateType(opts.Type); !ok {
180 return nil, ErrUnknownType
181 }
182
183 if ok := validateCooldown(opts.Cooldown); !ok {
184 return nil, ErrCooldownRange
185 }
186
Brad Isonac037d52016-04-07 19:41:29 -0400187 policy := make(map[string]interface{})
188
189 policy["name"] = opts.Name
190 policy["type"] = opts.Type
191 policy["cooldown"] = opts.Cooldown
192
Brad Isonb35ef6d2016-04-09 16:54:57 -0400193 err := setAdjustment(opts.AdjustmentType, opts.AdjustmentValue, policy)
194
195 if err != nil {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400196 return nil, err
197 }
Brad Isonac037d52016-04-07 19:41:29 -0400198
199 if opts.Args != nil {
200 policy["args"] = opts.Args
201 }
202
203 return policy, nil
204}
205
206// Update requests the configuration of the given policy be updated.
207func Update(client *gophercloud.ServiceClient, groupID, policyID string, opts UpdateOptsBuilder) UpdateResult {
208 var result UpdateResult
209
210 url := updateURL(client, groupID, policyID)
211 reqBody, err := opts.ToPolicyUpdateMap()
212
213 if err != nil {
214 result.Err = err
215 return result
216 }
217
218 _, result.Err = client.Put(url, reqBody, nil, &gophercloud.RequestOpts{
219 OkCodes: []int{204},
220 })
221
222 return result
223}
Brad Ison124df8e2016-04-07 19:51:51 -0400224
225// Delete requests the given policy be permanently deleted.
226func Delete(client *gophercloud.ServiceClient, groupID, policyID string) DeleteResult {
227 var result DeleteResult
228
229 url := deleteURL(client, groupID, policyID)
230 _, result.Err = client.Delete(url, &gophercloud.RequestOpts{
231 OkCodes: []int{204},
232 })
233
234 return result
235}
Brad Ison42f8dfb2016-04-07 20:26:06 -0400236
237// Execute requests the given policy be executed immediately.
238func Execute(client *gophercloud.ServiceClient, groupID, policyID string) ExecuteResult {
239 var result ExecuteResult
240
241 url := executeURL(client, groupID, policyID)
242 _, result.Err = client.Post(url, nil, &result.Body, &gophercloud.RequestOpts{
243 OkCodes: []int{202},
244 })
245
246 return result
247}
Brad Ison4d1a9a62016-04-07 21:31:52 -0400248
249// Validate and set an adjustment on the given request body.
Brad Isonb35ef6d2016-04-09 16:54:57 -0400250func setAdjustment(t AdjustmentType, v float64, body map[string]interface{}) error {
251 key := string(t)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400252
Brad Isonb35ef6d2016-04-09 16:54:57 -0400253 switch t {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400254 case ChangePercent:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400255 body[key] = v
Brad Ison4d1a9a62016-04-07 21:31:52 -0400256
257 case Change, DesiredCapacity:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400258 body[key] = int(v)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400259
260 default:
Brad Isoneedc8d92016-04-11 13:15:16 -0400261 return ErrUnknownAdjustment
Brad Ison4d1a9a62016-04-07 21:31:52 -0400262 }
263
264 return nil
265}
Brad Isoneedc8d92016-04-11 13:15:16 -0400266
267func validateType(t Type) (ok bool) {
268 switch t {
269 case Schedule, Webhook:
270 ok = true
271 return
272
273 default:
274 ok = false
275 return
276 }
277}
278
279func validateCooldown(cooldown int) (ok bool) {
280 if cooldown < 0 || cooldown > 86400 {
281 ok = false
282 return
283 }
284
285 ok = true
286 return
287}