blob: 5d45c14c22fba987514bffad4b420f0959d248a1 [file] [log] [blame]
Jamie Hannafordfba65af2014-11-03 10:32:37 +01001package lbs
Jamie Hannaford186d4e22014-10-31 12:26:11 +01002
3import (
Jamie Hannaforde09b6822014-10-31 15:33:57 +01004 "errors"
5
6 "github.com/racker/perigee"
7
Jamie Hannaford186d4e22014-10-31 12:26:11 +01008 "github.com/rackspace/gophercloud"
9 "github.com/rackspace/gophercloud/pagination"
Jamie Hannaford940159d2014-11-03 13:04:08 +010010 "github.com/rackspace/gophercloud/rackspace/lb/v1"
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010011 "github.com/rackspace/gophercloud/rackspace/lb/v1/nodes"
Jamie Hannaford186d4e22014-10-31 12:26:11 +010012)
13
14// ListOptsBuilder allows extensions to add additional parameters to the
15// List request.
16type ListOptsBuilder interface {
17 ToLBListQuery() (string, error)
18}
19
20// ListOpts allows the filtering and sorting of paginated collections through
21// the API.
22type ListOpts struct {
23 ChangesSince string `q:"changes-since"`
24 Status Status `q:"status"`
25 NodeAddr string `q:"nodeaddress"`
26 Marker string `q:"marker"`
27 Limit int `q:"limit"`
28}
29
30// ToLBListQuery formats a ListOpts into a query string.
31func (opts ListOpts) ToLBListQuery() (string, error) {
32 q, err := gophercloud.BuildQueryString(opts)
33 if err != nil {
34 return "", err
35 }
36 return q.String(), nil
37}
38
39func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
40 url := rootURL(client)
41 if opts != nil {
42 query, err := opts.ToLBListQuery()
43 if err != nil {
44 return pagination.Pager{Err: err}
45 }
46 url += query
47 }
48
49 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
50 return LBPage{pagination.LinkedPageBase{PageResult: r}}
51 })
52}
Jamie Hannaforde09b6822014-10-31 15:33:57 +010053
54type enabledState *bool
55
56var (
57 iTrue = true
58 iFalse = false
59
60 Enabled enabledState = &iTrue
61 Disabled enabledState = &iFalse
62)
63
64// CreateOptsBuilder is the interface options structs have to satisfy in order
65// to be used in the main Create operation in this package. Since many
66// extensions decorate or modify the common logic, it is useful for them to
67// satisfy a basic interface in order for them to be used.
68type CreateOptsBuilder interface {
69 ToLBCreateMap() (map[string]interface{}, error)
70}
71
72// CreateOpts is the common options struct used in this package's Create
73// operation.
74type CreateOpts struct {
75 // Required - name of the load balancer to create. The name must be 128
76 // characters or fewer in length, and all UTF-8 characters are valid.
77 Name string
78
79 // Optional - nodes to be added.
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010080 Nodes []nodes.Node
Jamie Hannaforde09b6822014-10-31 15:33:57 +010081
82 // Required - protocol of the service that is being load balanced.
83 Protocol Protocol
84
85 // Optional - enables or disables Half-Closed support for the load balancer.
86 // Half-Closed support provides the ability for one end of the connection to
87 // terminate its output, while still receiving data from the other end. Only
88 // available for TCP/TCP_CLIENT_FIRST protocols.
89 HalfClosed enabledState
90
91 // Optional - the type of virtual IPs you want associated with the load
92 // balancer.
93 VIPs []VIP
94
95 // Optional - the access list management feature allows fine-grained network
96 // access controls to be applied to the load balancer virtual IP address.
97 AccessList string
98
99 // Optional - algorithm that defines how traffic should be directed between
100 // back-end nodes.
101 Algorithm Algorithm
102
103 // Optional - current connection logging configuration.
104 ConnectionLogging *ConnectionLogging
105
106 // Optional - specifies a limit on the number of connections per IP address
107 // to help mitigate malicious or abusive traffic to your applications.
108 //??? ConnThrottle string
109
110 //??? HealthMonitor string
111
112 // Optional - arbitrary information that can be associated with each LB.
113 Metadata map[string]interface{}
114
115 // Optional - port number for the service you are load balancing.
116 Port int
117
118 // Optional - the timeout value for the load balancer and communications with
119 // its nodes. Defaults to 30 seconds with a maximum of 120 seconds.
120 Timeout int
121
122 // Optional - specifies whether multiple requests from clients are directed
123 // to the same node.
124 //??? SessionPersistence
125
126 // Optional - enables or disables HTTP to HTTPS redirection for the load
127 // balancer. When enabled, any HTTP request returns status code 301 (Moved
128 // Permanently), and the requester is redirected to the requested URL via the
129 // HTTPS protocol on port 443. For example, http://example.com/page.html
130 // would be redirected to https://example.com/page.html. Only available for
131 // HTTPS protocol (port=443), or HTTP protocol with a properly configured SSL
132 // termination (secureTrafficOnly=true, securePort=443).
133 HTTPSRedirect enabledState
134}
135
136var (
137 errNameRequired = errors.New("Name is a required attribute")
138 errTimeoutExceeded = errors.New("Timeout must be less than 120")
139)
140
141// ToLBCreateMap casts a CreateOpts struct to a map.
142func (opts CreateOpts) ToLBCreateMap() (map[string]interface{}, error) {
143 lb := make(map[string]interface{})
144
145 if opts.Name == "" {
146 return lb, errNameRequired
147 }
148 if opts.Timeout > 120 {
149 return lb, errTimeoutExceeded
150 }
151
152 lb["name"] = opts.Name
153
154 if len(opts.Nodes) > 0 {
155 nodes := []map[string]interface{}{}
156 for _, n := range opts.Nodes {
157 nodes = append(nodes, map[string]interface{}{
158 "address": n.Address,
159 "port": n.Port,
160 "condition": n.Condition,
161 })
162 }
163 lb["nodes"] = nodes
164 }
165
166 if opts.Protocol != "" {
167 lb["protocol"] = opts.Protocol
168 }
169 if opts.HalfClosed != nil {
170 lb["halfClosed"] = opts.HalfClosed
171 }
172
173 if len(opts.VIPs) > 0 {
174
175 lb["virtualIps"] = opts.VIPs
176 }
177
178 // if opts.AccessList != "" {
179 // lb["accessList"] = opts.AccessList
180 // }
181 if opts.Algorithm != "" {
182 lb["algorithm"] = opts.Algorithm
183 }
184 if opts.ConnectionLogging != nil {
185 lb["connectionLogging"] = &opts.ConnectionLogging
186 }
187 // if opts.ConnThrottle != "" {
188 // lb["connectionThrottle"] = opts.ConnThrottle
189 // }
190 // if opts.HealthMonitor != "" {
191 // lb["healthMonitor"] = opts.HealthMonitor
192 // }
193 if len(opts.Metadata) != 0 {
194 lb["metadata"] = opts.Metadata
195 }
196 if opts.Port > 0 {
197 lb["port"] = opts.Port
198 }
199 if opts.Timeout > 0 {
200 lb["timeout"] = opts.Timeout
201 }
202 // if opts.SessionPersistence != "" {
203 // lb["sessionPersistence"] = opts.SessionPersistence
204 // }
205 if opts.HTTPSRedirect != nil {
206 lb["httpsRedirect"] = &opts.HTTPSRedirect
207 }
208
209 return map[string]interface{}{"loadBalancer": lb}, nil
210}
211
212func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
213 var res CreateResult
214
215 reqBody, err := opts.ToLBCreateMap()
216 if err != nil {
217 res.Err = err
218 return res
219 }
220
221 _, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
222 MoreHeaders: c.AuthenticatedHeaders(),
223 ReqBody: &reqBody,
224 Results: &res.Body,
225 OkCodes: []int{200},
226 })
227
228 return res
229}
Jamie Hannaford1c260332014-10-31 15:57:22 +0100230
Jamie Hannaford07c06962014-10-31 16:42:03 +0100231func Get(c *gophercloud.ServiceClient, id int) GetResult {
232 var res GetResult
233
234 _, res.Err = perigee.Request("GET", resourceURL(c, id), perigee.Options{
235 MoreHeaders: c.AuthenticatedHeaders(),
236 Results: &res.Body,
237 OkCodes: []int{200},
238 })
239
240 return res
241}
242
Jamie Hannaford1c260332014-10-31 15:57:22 +0100243func BulkDelete(c *gophercloud.ServiceClient, ids []int) DeleteResult {
244 var res DeleteResult
245
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +0100246 if len(ids) > 10 || len(ids) == 0 {
247 res.Err = errors.New("You must provide a minimum of 1 and a maximum of 10 LB IDs")
248 return res
249 }
250
Jamie Hannaford1c260332014-10-31 15:57:22 +0100251 url := rootURL(c)
Jamie Hannaford940159d2014-11-03 13:04:08 +0100252 url += v1.IDSliceToQueryString("id", ids)
Jamie Hannaford1c260332014-10-31 15:57:22 +0100253
254 _, res.Err = perigee.Request("DELETE", url, perigee.Options{
255 MoreHeaders: c.AuthenticatedHeaders(),
256 OkCodes: []int{202},
257 })
258
259 return res
260}
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100261
262func Delete(c *gophercloud.ServiceClient, id int) DeleteResult {
263 var res DeleteResult
264
265 _, res.Err = perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
266 MoreHeaders: c.AuthenticatedHeaders(),
267 OkCodes: []int{202},
268 })
269
270 return res
271}
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100272
273type UpdateOptsBuilder interface {
274 ToLBUpdateMap() (map[string]interface{}, error)
275}
276
277type UpdateOpts struct {
278 Name string
279
280 Protocol Protocol
281
282 HalfClosed enabledState
283
284 Algorithm Algorithm
285
286 Port int
287
288 Timeout int
289
290 HTTPSRedirect enabledState
291}
292
293// ToLBUpdateMap casts a CreateOpts struct to a map.
294func (opts UpdateOpts) ToLBUpdateMap() (map[string]interface{}, error) {
295 lb := make(map[string]interface{})
296
297 if opts.Name != "" {
298 lb["name"] = opts.Name
299 }
300 if opts.Protocol != "" {
301 lb["protocol"] = opts.Protocol
302 }
303 if opts.HalfClosed != nil {
304 lb["halfClosed"] = opts.HalfClosed
305 }
306 if opts.Algorithm != "" {
307 lb["algorithm"] = opts.Algorithm
308 }
309 if opts.Port > 0 {
310 lb["port"] = opts.Port
311 }
312 if opts.Timeout > 0 {
313 lb["timeout"] = opts.Timeout
314 }
315 if opts.HTTPSRedirect != nil {
316 lb["httpsRedirect"] = &opts.HTTPSRedirect
317 }
318
319 return map[string]interface{}{"loadBalancer": lb}, nil
320}
321
322func Update(c *gophercloud.ServiceClient, id int, opts UpdateOptsBuilder) UpdateResult {
323 var res UpdateResult
324
325 reqBody, err := opts.ToLBUpdateMap()
326 if err != nil {
327 res.Err = err
328 return res
329 }
330
331 _, res.Err = perigee.Request("PUT", resourceURL(c, id), perigee.Options{
332 MoreHeaders: c.AuthenticatedHeaders(),
333 ReqBody: &reqBody,
334 OkCodes: []int{200},
335 })
336
337 return res
338}