blob: 25747b8c18f9faf4ed092b1037cbd6ff142feebd [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.")
14 ErrInvalidAdjustment = errors.New("Invalid adjustment type.")
Brad Isone7d6dfc2016-04-06 14:55:07 -040015)
16
Brad Ison53e997c2016-03-26 18:02:05 -040017// List returns all scaling policies for a group.
18func List(client *gophercloud.ServiceClient, groupID string) pagination.Pager {
19 url := listURL(client, groupID)
20
21 createPageFn := func(r pagination.PageResult) pagination.Page {
22 return PolicyPage{pagination.SinglePageBase(r)}
23 }
24
25 return pagination.NewPager(client, url, createPageFn)
26}
Brad Isone7d6dfc2016-04-06 14:55:07 -040027
28// CreateOptsBuilder is the interface responsible for generating the map that
29// will be marshalled to JSON for a Create operation.
30type CreateOptsBuilder interface {
31 ToPolicyCreateMap() ([]map[string]interface{}, error)
32}
33
Brad Isone7d6dfc2016-04-06 14:55:07 -040034// AdjustmentType represents the way in which a policy will change a group.
35type AdjustmentType string
36
37// Valid types of adjustments for a policy.
38const (
39 Change AdjustmentType = "change"
40 ChangePercent AdjustmentType = "changePercent"
41 DesiredCapacity AdjustmentType = "desiredCapacity"
42)
43
44// CreateOpts is a slice of CreateOpt structs that allow the user to create
45// multiple policies in a single operation.
46type CreateOpts []CreateOpt
47
48// CreateOpt represents the options to create a policy.
49type CreateOpt struct {
50 // Name [required] is a name for the policy.
51 Name string
52
53 // Type [required] of policy, i.e. either "webhook" or "schedule".
54 Type Type
55
56 // Cooldown [required] period in seconds.
57 Cooldown int
58
Brad Isonb35ef6d2016-04-09 16:54:57 -040059 // AdjustmentType [requried] is the method used to change the capacity of
60 // the group, i.e. one of: Change, ChangePercent, or DesiredCapacity.
61 AdjustmentType AdjustmentType
62
63 // AdjustmentValue [required] is the numeric value of the adjustment. For
64 // adjustments of type Change or DesiredCapacity, this will be converted to
65 // an integer.
66 AdjustmentValue float64
Brad Isone7d6dfc2016-04-06 14:55:07 -040067
68 // Additional configuration options for some types of policy.
69 Args map[string]interface{}
70}
71
72// ToPolicyCreateMap converts a slice of CreateOpt structs into a map for use
73// in the request body of a Create operation.
74func (opts CreateOpts) ToPolicyCreateMap() ([]map[string]interface{}, error) {
75 var policies []map[string]interface{}
76
77 for _, o := range opts {
78 if o.Name == "" {
79 return nil, ErrNoName
80 }
81
82 if o.Type == Schedule && o.Args == nil {
83 return nil, ErrNoArgs
84 }
85
86 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
179 policy := make(map[string]interface{})
180
181 policy["name"] = opts.Name
182 policy["type"] = opts.Type
183 policy["cooldown"] = opts.Cooldown
184
Brad Isonb35ef6d2016-04-09 16:54:57 -0400185 err := setAdjustment(opts.AdjustmentType, opts.AdjustmentValue, policy)
186
187 if err != nil {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400188 return nil, err
189 }
Brad Isonac037d52016-04-07 19:41:29 -0400190
191 if opts.Args != nil {
192 policy["args"] = opts.Args
193 }
194
195 return policy, nil
196}
197
198// Update requests the configuration of the given policy be updated.
199func Update(client *gophercloud.ServiceClient, groupID, policyID string, opts UpdateOptsBuilder) UpdateResult {
200 var result UpdateResult
201
202 url := updateURL(client, groupID, policyID)
203 reqBody, err := opts.ToPolicyUpdateMap()
204
205 if err != nil {
206 result.Err = err
207 return result
208 }
209
210 _, result.Err = client.Put(url, reqBody, nil, &gophercloud.RequestOpts{
211 OkCodes: []int{204},
212 })
213
214 return result
215}
Brad Ison124df8e2016-04-07 19:51:51 -0400216
217// Delete requests the given policy be permanently deleted.
218func Delete(client *gophercloud.ServiceClient, groupID, policyID string) DeleteResult {
219 var result DeleteResult
220
221 url := deleteURL(client, groupID, policyID)
222 _, result.Err = client.Delete(url, &gophercloud.RequestOpts{
223 OkCodes: []int{204},
224 })
225
226 return result
227}
Brad Ison42f8dfb2016-04-07 20:26:06 -0400228
229// Execute requests the given policy be executed immediately.
230func Execute(client *gophercloud.ServiceClient, groupID, policyID string) ExecuteResult {
231 var result ExecuteResult
232
233 url := executeURL(client, groupID, policyID)
234 _, result.Err = client.Post(url, nil, &result.Body, &gophercloud.RequestOpts{
235 OkCodes: []int{202},
236 })
237
238 return result
239}
Brad Ison4d1a9a62016-04-07 21:31:52 -0400240
241// Validate and set an adjustment on the given request body.
Brad Isonb35ef6d2016-04-09 16:54:57 -0400242func setAdjustment(t AdjustmentType, v float64, body map[string]interface{}) error {
243 key := string(t)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400244
Brad Isonb35ef6d2016-04-09 16:54:57 -0400245 switch t {
Brad Ison4d1a9a62016-04-07 21:31:52 -0400246 case ChangePercent:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400247 body[key] = v
Brad Ison4d1a9a62016-04-07 21:31:52 -0400248
249 case Change, DesiredCapacity:
Brad Isonb35ef6d2016-04-09 16:54:57 -0400250 body[key] = int(v)
Brad Ison4d1a9a62016-04-07 21:31:52 -0400251
252 default:
253 return ErrInvalidAdjustment
254 }
255
256 return nil
257}