blob: 99d8b1a0fb7f98417abcbcce536206d2bf6f5d34 [file] [log] [blame]
Brad Ison53e997c2016-03-26 18:02:05 -04001package policies
2
3import (
Brad Isona06e2ca2016-04-11 14:59:06 -04004 "time"
5
Brad Ison53e997c2016-03-26 18:02:05 -04006 "github.com/mitchellh/mapstructure"
7
8 "github.com/rackspace/gophercloud"
9 "github.com/rackspace/gophercloud/pagination"
10)
11
12type policyResult struct {
13 gophercloud.Result
14}
15
Brad Ison55523e52016-04-06 19:25:20 -040016// Extract interprets any policyResult as a Policy, if possible.
17func (r policyResult) Extract() (*Policy, error) {
18 if r.Err != nil {
19 return nil, r.Err
20 }
21
22 var response struct {
Brad Ison2b739162016-04-11 12:40:11 -040023 Policy policy `mapstructure:"policy"`
Brad Ison55523e52016-04-06 19:25:20 -040024 }
25
Brad Ison2b739162016-04-11 12:40:11 -040026 if err := mapstructure.Decode(r.Body, &response); err != nil {
27 return nil, err
28 }
Brad Ison55523e52016-04-06 19:25:20 -040029
Brad Ison2b739162016-04-11 12:40:11 -040030 policy := response.Policy.toExported()
31
32 return &policy, nil
Brad Ison55523e52016-04-06 19:25:20 -040033}
34
Brad Isone7d6dfc2016-04-06 14:55:07 -040035// CreateResult represents the result of a create operation.
36type CreateResult struct {
37 policyResult
38}
39
40// Extract extracts a slice of Policies from a CreateResult. Multiple policies
41// can be created in a single operation, so the result of a create is always a
42// list of policies.
43func (res CreateResult) Extract() ([]Policy, error) {
44 if res.Err != nil {
45 return nil, res.Err
46 }
47
48 return commonExtractPolicies(res.Body)
49}
50
Brad Ison55523e52016-04-06 19:25:20 -040051// GetResult temporarily contains the response from a Get call.
52type GetResult struct {
53 policyResult
54}
55
Brad Isonac037d52016-04-07 19:41:29 -040056// UpdateResult represents the result of an update operation.
57type UpdateResult struct {
58 gophercloud.ErrResult
59}
60
Brad Ison124df8e2016-04-07 19:51:51 -040061// DeleteResult represents the result of a delete operation.
62type DeleteResult struct {
63 gophercloud.ErrResult
64}
65
Brad Ison42f8dfb2016-04-07 20:26:06 -040066// ExecuteResult represents the result of an execute operation.
67type ExecuteResult struct {
68 gophercloud.ErrResult
69}
70
Brad Ison53e997c2016-03-26 18:02:05 -040071// Type represents a type of scaling policy.
72type Type string
73
74const (
75 // Schedule policies run at given times.
76 Schedule Type = "schedule"
77
78 // Webhook policies are triggered by HTTP requests.
79 Webhook Type = "webhook"
80)
81
Brad Ison2b739162016-04-11 12:40:11 -040082// AdjustmentType represents the way in which a policy will change a group.
83type AdjustmentType string
84
85// Valid types of adjustments for a policy.
86const (
87 Change AdjustmentType = "change"
88 ChangePercent AdjustmentType = "changePercent"
89 DesiredCapacity AdjustmentType = "desiredCapacity"
90)
91
Brad Isona06e2ca2016-04-11 14:59:06 -040092// ScheduleArgs is implemented by types that can be converted into arguments for
93// policies with type Schedule.
94type ScheduleArgs interface {
95 ToPolicyArgs() (map[string]string, error)
96}
97
98// At satisfies the ScheduleArgs interface and can be used to configure a policy
99// to execute a particular time.
100type At time.Time
101
102// ToPolicyArgs returns a key and value for use in constructing arguments to
103// schedule policies.
104func (at At) ToPolicyArgs() (map[string]string, error) {
105 t := time.Time(at)
106
107 args := make(map[string]string)
108 args["at"] = t.UTC().Format(time.RFC3339)
109
110 return args, nil
111}
112
113// Cron satisfies the ScheduleArgs interface and can be used to configure a
114// policy that executes at regular intervals.
115type Cron string
116
117// ToPolicyArgs returns a key and value for use in constructing arguments to
118// schedule policies.
119func (cron Cron) ToPolicyArgs() (map[string]string, error) {
120 if cron == "" {
121 return nil, ErrEmptyCron
122 }
123
124 args := make(map[string]string)
125 args["cron"] = string(cron)
126
127 return args, nil
128}
129
Brad Ison2b739162016-04-11 12:40:11 -0400130// Policy represents a scaling policy.
131type Policy struct {
132 // UUID for the policy.
133 ID string
134
135 // Name of the policy.
136 Name string
137
138 // Type of scaling policy.
139 Type Type
140
141 // Cooldown period, in seconds.
142 Cooldown int
143
144 // The type of adjustment in capacity to be made.
145 AdjustmentType AdjustmentType
146
147 // The numeric value of the adjustment in capacity.
148 AdjustmentValue float64
149
Brad Isona06e2ca2016-04-11 14:59:06 -0400150 // Arguments determining Schedule policy behavior, or nil for Webhook
151 // policies.
152 Schedule ScheduleArgs
Brad Ison2b739162016-04-11 12:40:11 -0400153}
154
155// This is an intermediate representation of the exported Policy type. The
156// fields in API responses vary by policy type and configuration. This lets us
157// decode responses then normalize them into a Policy.
158type policy struct {
159 ID string `mapstructure:"id"`
160 Name string `mapstructure:"name"`
161 Type Type `mapstructure:"type"`
162 Cooldown int `mapstructure:"cooldown"`
163
164 // The API will respond with exactly one of these omitting the others.
165 Change interface{} `mapstructure:"change"`
166 ChangePercent interface{} `mapstructure:"changePercent"`
167 DesiredCapacity interface{} `mapstructure:"desiredCapacity"`
168
169 // Additional configuration options for schedule policies.
Brad Isona06e2ca2016-04-11 14:59:06 -0400170 Args map[string]string `mapstructure:"args"`
Brad Ison2b739162016-04-11 12:40:11 -0400171}
172
173// Assemble a Policy from the intermediate policy struct.
174func (p policy) toExported() Policy {
175 policy := Policy{}
176
177 policy.ID = p.ID
178 policy.Name = p.Name
179 policy.Type = p.Type
180 policy.Cooldown = p.Cooldown
181
Brad Isona06e2ca2016-04-11 14:59:06 -0400182 if cron, ok := p.Args["cron"]; ok {
183 policy.Schedule = Cron(cron)
184 } else if at, ok := p.Args["at"]; ok {
185 // Set an At schedule if the "at" argument parses as an RFC3339 time.
186 if t, err := time.Parse(time.RFC3339, at); err == nil {
187 policy.Schedule = At(t)
188 }
189 }
Brad Ison2b739162016-04-11 12:40:11 -0400190
191 if v, ok := p.Change.(float64); ok {
192 policy.AdjustmentType = Change
193 policy.AdjustmentValue = v
194 } else if v, ok := p.ChangePercent.(float64); ok {
195 policy.AdjustmentType = ChangePercent
196 policy.AdjustmentValue = v
197 } else if v, ok := p.DesiredCapacity.(float64); ok {
198 policy.AdjustmentType = DesiredCapacity
199 policy.AdjustmentValue = v
200 }
201
202 return policy
203}
204
Brad Ison53e997c2016-03-26 18:02:05 -0400205// PolicyPage is the page returned by a pager when traversing over a collection
206// of scaling policies.
207type PolicyPage struct {
208 pagination.SinglePageBase
209}
210
211// IsEmpty returns true if a page contains no Policy results.
212func (page PolicyPage) IsEmpty() (bool, error) {
213 policies, err := ExtractPolicies(page)
214
215 if err != nil {
216 return true, err
217 }
218
219 return len(policies) == 0, nil
220}
221
222// ExtractPolicies interprets the results of a single page from a List() call,
223// producing a slice of Policies.
224func ExtractPolicies(page pagination.Page) ([]Policy, error) {
Brad Isone7d6dfc2016-04-06 14:55:07 -0400225 return commonExtractPolicies(page.(PolicyPage).Body)
226}
Brad Ison53e997c2016-03-26 18:02:05 -0400227
Brad Isone7d6dfc2016-04-06 14:55:07 -0400228func commonExtractPolicies(body interface{}) ([]Policy, error) {
Brad Ison53e997c2016-03-26 18:02:05 -0400229 var response struct {
Brad Ison2b739162016-04-11 12:40:11 -0400230 Policies []policy `mapstructure:"policies"`
Brad Ison53e997c2016-03-26 18:02:05 -0400231 }
232
Brad Isone7d6dfc2016-04-06 14:55:07 -0400233 err := mapstructure.Decode(body, &response)
Brad Ison53e997c2016-03-26 18:02:05 -0400234
235 if err != nil {
236 return nil, err
237 }
238
Brad Ison2b739162016-04-11 12:40:11 -0400239 policies := make([]Policy, len(response.Policies))
240
241 for i, p := range response.Policies {
242 policies[i] = p.toExported()
243 }
244
245 return policies, nil
Brad Ison53e997c2016-03-26 18:02:05 -0400246}