Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 1 | package policies |
| 2 | |
| 3 | import ( |
| 4 | "github.com/mitchellh/mapstructure" |
| 5 | |
| 6 | "github.com/rackspace/gophercloud" |
| 7 | "github.com/rackspace/gophercloud/pagination" |
| 8 | ) |
| 9 | |
| 10 | type policyResult struct { |
| 11 | gophercloud.Result |
| 12 | } |
| 13 | |
Brad Ison | 55523e5 | 2016-04-06 19:25:20 -0400 | [diff] [blame] | 14 | // Extract interprets any policyResult as a Policy, if possible. |
| 15 | func (r policyResult) Extract() (*Policy, error) { |
| 16 | if r.Err != nil { |
| 17 | return nil, r.Err |
| 18 | } |
| 19 | |
| 20 | var response struct { |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 21 | Policy policy `mapstructure:"policy"` |
Brad Ison | 55523e5 | 2016-04-06 19:25:20 -0400 | [diff] [blame] | 22 | } |
| 23 | |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 24 | if err := mapstructure.Decode(r.Body, &response); err != nil { |
| 25 | return nil, err |
| 26 | } |
Brad Ison | 55523e5 | 2016-04-06 19:25:20 -0400 | [diff] [blame] | 27 | |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 28 | policy := response.Policy.toExported() |
| 29 | |
| 30 | return &policy, nil |
Brad Ison | 55523e5 | 2016-04-06 19:25:20 -0400 | [diff] [blame] | 31 | } |
| 32 | |
Brad Ison | e7d6dfc | 2016-04-06 14:55:07 -0400 | [diff] [blame] | 33 | // CreateResult represents the result of a create operation. |
| 34 | type CreateResult struct { |
| 35 | policyResult |
| 36 | } |
| 37 | |
| 38 | // Extract extracts a slice of Policies from a CreateResult. Multiple policies |
| 39 | // can be created in a single operation, so the result of a create is always a |
| 40 | // list of policies. |
| 41 | func (res CreateResult) Extract() ([]Policy, error) { |
| 42 | if res.Err != nil { |
| 43 | return nil, res.Err |
| 44 | } |
| 45 | |
| 46 | return commonExtractPolicies(res.Body) |
| 47 | } |
| 48 | |
Brad Ison | 55523e5 | 2016-04-06 19:25:20 -0400 | [diff] [blame] | 49 | // GetResult temporarily contains the response from a Get call. |
| 50 | type GetResult struct { |
| 51 | policyResult |
| 52 | } |
| 53 | |
Brad Ison | ac037d5 | 2016-04-07 19:41:29 -0400 | [diff] [blame] | 54 | // UpdateResult represents the result of an update operation. |
| 55 | type UpdateResult struct { |
| 56 | gophercloud.ErrResult |
| 57 | } |
| 58 | |
Brad Ison | 124df8e | 2016-04-07 19:51:51 -0400 | [diff] [blame] | 59 | // DeleteResult represents the result of a delete operation. |
| 60 | type DeleteResult struct { |
| 61 | gophercloud.ErrResult |
| 62 | } |
| 63 | |
Brad Ison | 42f8dfb | 2016-04-07 20:26:06 -0400 | [diff] [blame] | 64 | // ExecuteResult represents the result of an execute operation. |
| 65 | type ExecuteResult struct { |
| 66 | gophercloud.ErrResult |
| 67 | } |
| 68 | |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 69 | // Type represents a type of scaling policy. |
| 70 | type Type string |
| 71 | |
| 72 | const ( |
| 73 | // Schedule policies run at given times. |
| 74 | Schedule Type = "schedule" |
| 75 | |
| 76 | // Webhook policies are triggered by HTTP requests. |
| 77 | Webhook Type = "webhook" |
| 78 | ) |
| 79 | |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 80 | // AdjustmentType represents the way in which a policy will change a group. |
| 81 | type AdjustmentType string |
| 82 | |
| 83 | // Valid types of adjustments for a policy. |
| 84 | const ( |
| 85 | Change AdjustmentType = "change" |
| 86 | ChangePercent AdjustmentType = "changePercent" |
| 87 | DesiredCapacity AdjustmentType = "desiredCapacity" |
| 88 | ) |
| 89 | |
| 90 | // Policy represents a scaling policy. |
| 91 | type Policy struct { |
| 92 | // UUID for the policy. |
| 93 | ID string |
| 94 | |
| 95 | // Name of the policy. |
| 96 | Name string |
| 97 | |
| 98 | // Type of scaling policy. |
| 99 | Type Type |
| 100 | |
| 101 | // Cooldown period, in seconds. |
| 102 | Cooldown int |
| 103 | |
| 104 | // The type of adjustment in capacity to be made. |
| 105 | AdjustmentType AdjustmentType |
| 106 | |
| 107 | // The numeric value of the adjustment in capacity. |
| 108 | AdjustmentValue float64 |
| 109 | |
| 110 | // Additional configuration options for some types of policy. |
| 111 | Args map[string]interface{} |
| 112 | } |
| 113 | |
| 114 | // This is an intermediate representation of the exported Policy type. The |
| 115 | // fields in API responses vary by policy type and configuration. This lets us |
| 116 | // decode responses then normalize them into a Policy. |
| 117 | type policy struct { |
| 118 | ID string `mapstructure:"id"` |
| 119 | Name string `mapstructure:"name"` |
| 120 | Type Type `mapstructure:"type"` |
| 121 | Cooldown int `mapstructure:"cooldown"` |
| 122 | |
| 123 | // The API will respond with exactly one of these omitting the others. |
| 124 | Change interface{} `mapstructure:"change"` |
| 125 | ChangePercent interface{} `mapstructure:"changePercent"` |
| 126 | DesiredCapacity interface{} `mapstructure:"desiredCapacity"` |
| 127 | |
| 128 | // Additional configuration options for schedule policies. |
| 129 | Args map[string]interface{} `mapstructure:"args"` |
| 130 | } |
| 131 | |
| 132 | // Assemble a Policy from the intermediate policy struct. |
| 133 | func (p policy) toExported() Policy { |
| 134 | policy := Policy{} |
| 135 | |
| 136 | policy.ID = p.ID |
| 137 | policy.Name = p.Name |
| 138 | policy.Type = p.Type |
| 139 | policy.Cooldown = p.Cooldown |
| 140 | |
| 141 | policy.Args = p.Args |
| 142 | |
| 143 | if v, ok := p.Change.(float64); ok { |
| 144 | policy.AdjustmentType = Change |
| 145 | policy.AdjustmentValue = v |
| 146 | } else if v, ok := p.ChangePercent.(float64); ok { |
| 147 | policy.AdjustmentType = ChangePercent |
| 148 | policy.AdjustmentValue = v |
| 149 | } else if v, ok := p.DesiredCapacity.(float64); ok { |
| 150 | policy.AdjustmentType = DesiredCapacity |
| 151 | policy.AdjustmentValue = v |
| 152 | } |
| 153 | |
| 154 | return policy |
| 155 | } |
| 156 | |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 157 | // PolicyPage is the page returned by a pager when traversing over a collection |
| 158 | // of scaling policies. |
| 159 | type PolicyPage struct { |
| 160 | pagination.SinglePageBase |
| 161 | } |
| 162 | |
| 163 | // IsEmpty returns true if a page contains no Policy results. |
| 164 | func (page PolicyPage) IsEmpty() (bool, error) { |
| 165 | policies, err := ExtractPolicies(page) |
| 166 | |
| 167 | if err != nil { |
| 168 | return true, err |
| 169 | } |
| 170 | |
| 171 | return len(policies) == 0, nil |
| 172 | } |
| 173 | |
| 174 | // ExtractPolicies interprets the results of a single page from a List() call, |
| 175 | // producing a slice of Policies. |
| 176 | func ExtractPolicies(page pagination.Page) ([]Policy, error) { |
Brad Ison | e7d6dfc | 2016-04-06 14:55:07 -0400 | [diff] [blame] | 177 | return commonExtractPolicies(page.(PolicyPage).Body) |
| 178 | } |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 179 | |
Brad Ison | e7d6dfc | 2016-04-06 14:55:07 -0400 | [diff] [blame] | 180 | func commonExtractPolicies(body interface{}) ([]Policy, error) { |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 181 | var response struct { |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 182 | Policies []policy `mapstructure:"policies"` |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 183 | } |
| 184 | |
Brad Ison | e7d6dfc | 2016-04-06 14:55:07 -0400 | [diff] [blame] | 185 | err := mapstructure.Decode(body, &response) |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 186 | |
| 187 | if err != nil { |
| 188 | return nil, err |
| 189 | } |
| 190 | |
Brad Ison | 2b73916 | 2016-04-11 12:40:11 -0400 | [diff] [blame] | 191 | policies := make([]Policy, len(response.Policies)) |
| 192 | |
| 193 | for i, p := range response.Policies { |
| 194 | policies[i] = p.toExported() |
| 195 | } |
| 196 | |
| 197 | return policies, nil |
Brad Ison | 53e997c | 2016-03-26 18:02:05 -0400 | [diff] [blame] | 198 | } |