blob: 7aadf983d2892eb3a0ccd6ecfce3b777d800a7ac [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 Isona06e2ca2016-04-11 14:59:06 -040012 ErrNoName = errors.New("Policy name cannot be empty.")
13 ErrNoSchedule = errors.New("Schedule 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 Isona06e2ca2016-04-11 14:59:06 -040017 ErrEmptyCron = errors.New("Cron argument cannot be empty.")
Brad Isone7d6dfc2016-04-06 14:55:07 -040018)
19
Brad Ison53e997c2016-03-26 18:02:05 -040020// List returns all scaling policies for a group.
21func List(client *gophercloud.ServiceClient, groupID string) pagination.Pager {
22 url := listURL(client, groupID)
23
24 createPageFn := func(r pagination.PageResult) pagination.Page {
25 return PolicyPage{pagination.SinglePageBase(r)}
26 }
27
28 return pagination.NewPager(client, url, createPageFn)
29}
Brad Isone7d6dfc2016-04-06 14:55:07 -040030
31// CreateOptsBuilder is the interface responsible for generating the map that
32// will be marshalled to JSON for a Create operation.
33type CreateOptsBuilder interface {
34 ToPolicyCreateMap() ([]map[string]interface{}, error)
35}
36
Brad Isone7d6dfc2016-04-06 14:55:07 -040037// CreateOpts is a slice of CreateOpt structs that allow the user to create
38// multiple policies in a single operation.
39type CreateOpts []CreateOpt
40
41// CreateOpt represents the options to create a policy.
42type CreateOpt struct {
43 // Name [required] is a name for the policy.
44 Name string
45
46 // Type [required] of policy, i.e. either "webhook" or "schedule".
47 Type Type
48
49 // Cooldown [required] period in seconds.
50 Cooldown int
51
Brad Isonb35ef6d2016-04-09 16:54:57 -040052 // AdjustmentType [requried] is the method used to change the capacity of
53 // the group, i.e. one of: Change, ChangePercent, or DesiredCapacity.
54 AdjustmentType AdjustmentType
55
56 // AdjustmentValue [required] is the numeric value of the adjustment. For
57 // adjustments of type Change or DesiredCapacity, this will be converted to
58 // an integer.
59 AdjustmentValue float64
Brad Isone7d6dfc2016-04-06 14:55:07 -040060
Brad Isona06e2ca2016-04-11 14:59:06 -040061 // Value determining Schedule policy behavior, or nil for Webhook policies.
62 // This should be an appropriately configured Cron or an At value.
63 Schedule ScheduleArgs
Brad Isone7d6dfc2016-04-06 14:55:07 -040064}
65
66// ToPolicyCreateMap converts a slice of CreateOpt structs into a map for use
67// in the request body of a Create operation.
68func (opts CreateOpts) ToPolicyCreateMap() ([]map[string]interface{}, error) {
69 var policies []map[string]interface{}
70
71 for _, o := range opts {
72 if o.Name == "" {
73 return nil, ErrNoName
74 }
75
Brad Isona06e2ca2016-04-11 14:59:06 -040076 if o.Type == Schedule && o.Schedule == nil {
77 return nil, ErrNoSchedule
Brad Isone7d6dfc2016-04-06 14:55:07 -040078 }
79
Brad Isoneedc8d92016-04-11 13:15:16 -040080 if ok := validateType(o.Type); !ok {
81 return nil, ErrUnknownType
82 }
83
84 if ok := validateCooldown(o.Cooldown); !ok {
85 return nil, ErrCooldownRange
86 }
87
Brad Isone7d6dfc2016-04-06 14:55:07 -040088 policy := make(map[string]interface{})
89
90 policy["name"] = o.Name
91 policy["type"] = o.Type
92 policy["cooldown"] = o.Cooldown
93
Brad Isonb35ef6d2016-04-09 16:54:57 -040094 err := setAdjustment(o.AdjustmentType, o.AdjustmentValue, policy)
95
96 if err != nil {
Brad Ison4d1a9a62016-04-07 21:31:52 -040097 return nil, err
98 }
Brad Isone7d6dfc2016-04-06 14:55:07 -040099
Brad Isona06e2ca2016-04-11 14:59:06 -0400100 if o.Schedule != nil {
101 args, err := o.Schedule.ToPolicyArgs()
102
103 if err != nil {
104 return nil, err
105 }
106
107 policy["args"] = args
Brad Isone7d6dfc2016-04-06 14:55:07 -0400108 }
109
110 policies = append(policies, policy)
111 }
112
113 return policies, nil
114}
115
116// Create requests a new policy be created and associated with the given group.
117func Create(client *gophercloud.ServiceClient, groupID string, opts CreateOptsBuilder) CreateResult {
118 var res CreateResult
119
120 reqBody, err := opts.ToPolicyCreateMap()
121
122 if err != nil {
123 res.Err = err
124 return res
125 }
126
127 _, res.Err = client.Post(createURL(client, groupID), reqBody, &res.Body, nil)
128
129 return res
130}
Brad Ison55523e52016-04-06 19:25:20 -0400131
132// Get requests the details of a single policy with the given ID.
133func Get(client *gophercloud.ServiceClient, groupID, policyID string) GetResult {
134 var result GetResult
135
136 _, result.Err = client.Get(getURL(client, groupID, policyID), &result.Body, nil)
137
138 return result
139}
Brad Isonac037d52016-04-07 19:41:29 -0400140
141// UpdateOptsBuilder is the interface responsible for generating the map
142// structure for producing JSON for an Update operation.
143type UpdateOptsBuilder interface {
144 ToPolicyUpdateMap() (map[string]interface{}, error)
145}
146
147// UpdateOpts represents the options for updating an existing policy.
148//
149// Update operations completely replace the configuration being updated. Empty
150// values in the update are accepted and overwrite previously specified
151// parameters.
152type UpdateOpts struct {
153 // Name [required] is a name for the policy.
154 Name string
155
156 // Type [required] of policy, i.e. either "webhook" or "schedule".
157 Type Type
158
159 // Cooldown [required] period in seconds. If you don't specify a cooldown,
160 // it will default to zero, and the policy will be configured as such.
161 Cooldown int
162
Brad Isonb35ef6d2016-04-09 16:54:57 -0400163 // AdjustmentType [requried] is the method used to change the capacity of
164 // the group, i.e. one of: Change, ChangePercent, or DesiredCapacity.
165 AdjustmentType AdjustmentType
166
167 // AdjustmentValue [required] is the numeric value of the adjustment. For
168 // adjustments of type Change or DesiredCapacity, this will be converted to
169 // an integer.
170 AdjustmentValue float64
Brad Isonac037d52016-04-07 19:41:29 -0400171
Brad Isona06e2ca2016-04-11 14:59:06 -0400172 // Value determining Schedule policy behavior, or nil for Webhook policies.
173 // This should be an appropriately configured Cron or an At value.
174 Schedule ScheduleArgs
Brad Isonac037d52016-04-07 19:41:29 -0400175}
176
177// ToPolicyUpdateMap converts an UpdateOpts struct into a map for use as the
178// request body in an Update request.
179func (opts UpdateOpts) ToPolicyUpdateMap() (map[string]interface{}, error) {
180 if opts.Name == "" {
181 return nil, ErrNoName
182 }
183
Brad Isona06e2ca2016-04-11 14:59:06 -0400184 if opts.Type == Schedule && opts.Schedule == nil {
185 return nil, ErrNoSchedule
Brad Isonac037d52016-04-07 19:41:29 -0400186 }
187
Brad Isoneedc8d92016-04-11 13:15:16 -0400188 if ok := validateType(opts.Type); !ok {
189 return nil, ErrUnknownType
190 }
191
192 if ok := validateCooldown(opts.Cooldown); !ok {
193 return nil, ErrCooldownRange
194 }
195
Brad Isonac037d52016-04-07 19:41:29 -0400196 policy := make(map[string]interface{})
197
198 policy["name"] = opts.Name
199 policy["type"] = opts.Type
200 policy["cooldown"] = opts.Cooldown
201
Brad Isonb35ef6d2016-04-09 16:54:57 -0400202 err := setAdjustment(opts.AdjustmentType, opts.AdjustmentValue, policy)
203
204 if err != nil {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400205 return nil, err
206 }
Brad Isonac037d52016-04-07 19:41:29 -0400207
Brad Isona06e2ca2016-04-11 14:59:06 -0400208 if opts.Schedule != nil {
209 args, err := opts.Schedule.ToPolicyArgs()
210
211 if err != nil {
212 return nil, err
213 }
214
215 policy["args"] = args
Brad Isonac037d52016-04-07 19:41:29 -0400216 }
217
218 return policy, nil
219}
220
221// Update requests the configuration of the given policy be updated.
222func Update(client *gophercloud.ServiceClient, groupID, policyID string, opts UpdateOptsBuilder) UpdateResult {
223 var result UpdateResult
224
225 url := updateURL(client, groupID, policyID)
226 reqBody, err := opts.ToPolicyUpdateMap()
227
228 if err != nil {
229 result.Err = err
230 return result
231 }
232
233 _, result.Err = client.Put(url, reqBody, nil, &gophercloud.RequestOpts{
234 OkCodes: []int{204},
235 })
236
237 return result
238}
Brad Ison124df8e2016-04-07 19:51:51 -0400239
240// Delete requests the given policy be permanently deleted.
241func Delete(client *gophercloud.ServiceClient, groupID, policyID string) DeleteResult {
242 var result DeleteResult
243
244 url := deleteURL(client, groupID, policyID)
245 _, result.Err = client.Delete(url, &gophercloud.RequestOpts{
246 OkCodes: []int{204},
247 })
248
249 return result
250}
Brad Ison42f8dfb2016-04-07 20:26:06 -0400251
252// Execute requests the given policy be executed immediately.
253func Execute(client *gophercloud.ServiceClient, groupID, policyID string) ExecuteResult {
254 var result ExecuteResult
255
256 url := executeURL(client, groupID, policyID)
257 _, result.Err = client.Post(url, nil, &result.Body, &gophercloud.RequestOpts{
258 OkCodes: []int{202},
259 })
260
261 return result
262}
Brad Ison4d1a9a62016-04-07 21:31:52 -0400263
264// Validate and set an adjustment on the given request body.
Brad Isonb35ef6d2016-04-09 16:54:57 -0400265func setAdjustment(t AdjustmentType, v float64, body map[string]interface{}) error {
266 key := string(t)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400267
Brad Isonb35ef6d2016-04-09 16:54:57 -0400268 switch t {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400269 case ChangePercent:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400270 body[key] = v
Brad Ison4d1a9a62016-04-07 21:31:52 -0400271
272 case Change, DesiredCapacity:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400273 body[key] = int(v)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400274
275 default:
Brad Isoneedc8d92016-04-11 13:15:16 -0400276 return ErrUnknownAdjustment
Brad Ison4d1a9a62016-04-07 21:31:52 -0400277 }
278
279 return nil
280}
Brad Isoneedc8d92016-04-11 13:15:16 -0400281
282func validateType(t Type) (ok bool) {
283 switch t {
284 case Schedule, Webhook:
285 ok = true
286 return
287
288 default:
289 ok = false
290 return
291 }
292}
293
294func validateCooldown(cooldown int) (ok bool) {
295 if cooldown < 0 || cooldown > 86400 {
296 ok = false
297 return
298 }
299
300 ok = true
301 return
302}