File: results.go

package info (click to toggle)
golang-github-rackspace-gophercloud 1.0.0%2Bgit20160603.920.934dbf8-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 4,936 kB
  • ctags: 6,116
  • sloc: sh: 16; makefile: 4
file content (246 lines) | stat: -rw-r--r-- 6,113 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package policies

import (
	"time"

	"github.com/mitchellh/mapstructure"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/pagination"
)

type policyResult struct {
	gophercloud.Result
}

// Extract interprets any policyResult as a Policy, if possible.
func (r policyResult) Extract() (*Policy, error) {
	if r.Err != nil {
		return nil, r.Err
	}

	var response struct {
		Policy policy `mapstructure:"policy"`
	}

	if err := mapstructure.Decode(r.Body, &response); err != nil {
		return nil, err
	}

	policy := response.Policy.toExported()

	return &policy, nil
}

// CreateResult represents the result of a create operation.
type CreateResult struct {
	policyResult
}

// Extract extracts a slice of Policies from a CreateResult.  Multiple policies
// can be created in a single operation, so the result of a create is always a
// list of policies.
func (res CreateResult) Extract() ([]Policy, error) {
	if res.Err != nil {
		return nil, res.Err
	}

	return commonExtractPolicies(res.Body)
}

// GetResult temporarily contains the response from a Get call.
type GetResult struct {
	policyResult
}

// UpdateResult represents the result of an update operation.
type UpdateResult struct {
	gophercloud.ErrResult
}

// DeleteResult represents the result of a delete operation.
type DeleteResult struct {
	gophercloud.ErrResult
}

// ExecuteResult represents the result of an execute operation.
type ExecuteResult struct {
	gophercloud.ErrResult
}

// Type represents a type of scaling policy.
type Type string

const (
	// Schedule policies run at given times.
	Schedule Type = "schedule"

	// Webhook policies are triggered by HTTP requests.
	Webhook Type = "webhook"
)

// AdjustmentType represents the way in which a policy will change a group.
type AdjustmentType string

// Valid types of adjustments for a policy.
const (
	Change          AdjustmentType = "change"
	ChangePercent   AdjustmentType = "changePercent"
	DesiredCapacity AdjustmentType = "desiredCapacity"
)

// ScheduleArgs is implemented by types that can be converted into arguments for
// policies with type Schedule.
type ScheduleArgs interface {
	ToPolicyArgs() (map[string]string, error)
}

// At satisfies the ScheduleArgs interface and can be used to configure a policy
// to execute a particular time.
type At time.Time

// ToPolicyArgs returns a key and value for use in constructing arguments to
// schedule policies.
func (at At) ToPolicyArgs() (map[string]string, error) {
	t := time.Time(at)

	args := make(map[string]string)
	args["at"] = t.UTC().Format(time.RFC3339)

	return args, nil
}

// Cron satisfies the ScheduleArgs interface and can be used to configure a
// policy that executes at regular intervals.
type Cron string

// ToPolicyArgs returns a key and value for use in constructing arguments to
// schedule policies.
func (cron Cron) ToPolicyArgs() (map[string]string, error) {
	if cron == "" {
		return nil, ErrEmptyCron
	}

	args := make(map[string]string)
	args["cron"] = string(cron)

	return args, nil
}

// Policy represents a scaling policy.
type Policy struct {
	// UUID for the policy.
	ID string

	// Name of the policy.
	Name string

	// Type of scaling policy.
	Type Type

	// Cooldown period, in seconds.
	Cooldown int

	// The type of adjustment in capacity to be made.
	AdjustmentType AdjustmentType

	// The numeric value of the adjustment in capacity.
	AdjustmentValue float64

	// Arguments determining Schedule policy behavior, or nil for Webhook
	// policies.
	Schedule ScheduleArgs
}

// This is an intermediate representation of the exported Policy type.  The
// fields in API responses vary by policy type and configuration.  This lets us
// decode responses then normalize them into a Policy.
type policy struct {
	ID       string `mapstructure:"id"`
	Name     string `mapstructure:"name"`
	Type     Type   `mapstructure:"type"`
	Cooldown int    `mapstructure:"cooldown"`

	// The API will respond with exactly one of these omitting the others.
	Change          interface{} `mapstructure:"change"`
	ChangePercent   interface{} `mapstructure:"changePercent"`
	DesiredCapacity interface{} `mapstructure:"desiredCapacity"`

	// Additional configuration options for schedule policies.
	Args map[string]string `mapstructure:"args"`
}

// Assemble a Policy from the intermediate policy struct.
func (p policy) toExported() Policy {
	policy := Policy{}

	policy.ID = p.ID
	policy.Name = p.Name
	policy.Type = p.Type
	policy.Cooldown = p.Cooldown

	if cron, ok := p.Args["cron"]; ok {
		policy.Schedule = Cron(cron)
	} else if at, ok := p.Args["at"]; ok {
		// Set an At schedule if the "at" argument parses as an RFC3339 time.
		if t, err := time.Parse(time.RFC3339, at); err == nil {
			policy.Schedule = At(t)
		}
	}

	if v, ok := p.Change.(float64); ok {
		policy.AdjustmentType = Change
		policy.AdjustmentValue = v
	} else if v, ok := p.ChangePercent.(float64); ok {
		policy.AdjustmentType = ChangePercent
		policy.AdjustmentValue = v
	} else if v, ok := p.DesiredCapacity.(float64); ok {
		policy.AdjustmentType = DesiredCapacity
		policy.AdjustmentValue = v
	}

	return policy
}

// PolicyPage is the page returned by a pager when traversing over a collection
// of scaling policies.
type PolicyPage struct {
	pagination.SinglePageBase
}

// IsEmpty returns true if a page contains no Policy results.
func (page PolicyPage) IsEmpty() (bool, error) {
	policies, err := ExtractPolicies(page)

	if err != nil {
		return true, err
	}

	return len(policies) == 0, nil
}

// ExtractPolicies interprets the results of a single page from a List() call,
// producing a slice of Policies.
func ExtractPolicies(page pagination.Page) ([]Policy, error) {
	return commonExtractPolicies(page.(PolicyPage).Body)
}

func commonExtractPolicies(body interface{}) ([]Policy, error) {
	var response struct {
		Policies []policy `mapstructure:"policies"`
	}

	err := mapstructure.Decode(body, &response)

	if err != nil {
		return nil, err
	}

	policies := make([]Policy, len(response.Policies))

	for i, p := range response.Policies {
		policies[i] = p.toExported()
	}

	return policies, nil
}