blob: 63b851377d142f5e2a7177c04fc34e4022865eb2 [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 Hannaford1c817312014-11-04 10:56:58 +010012 "github.com/rackspace/gophercloud/rackspace/lb/v1/vips"
Jamie Hannaford186d4e22014-10-31 12:26:11 +010013)
14
15// ListOptsBuilder allows extensions to add additional parameters to the
16// List request.
17type ListOptsBuilder interface {
18 ToLBListQuery() (string, error)
19}
20
21// ListOpts allows the filtering and sorting of paginated collections through
22// the API.
23type ListOpts struct {
24 ChangesSince string `q:"changes-since"`
25 Status Status `q:"status"`
26 NodeAddr string `q:"nodeaddress"`
27 Marker string `q:"marker"`
28 Limit int `q:"limit"`
29}
30
31// ToLBListQuery formats a ListOpts into a query string.
32func (opts ListOpts) ToLBListQuery() (string, error) {
33 q, err := gophercloud.BuildQueryString(opts)
34 if err != nil {
35 return "", err
36 }
37 return q.String(), nil
38}
39
Jamie Hannafordb2007ee2014-11-03 16:24:43 +010040// List is the operation responsible for returning a paginated collection of
41// load balancers. You may pass in a ListOpts struct to filter results.
Jamie Hannaford186d4e22014-10-31 12:26:11 +010042func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
43 url := rootURL(client)
44 if opts != nil {
45 query, err := opts.ToLBListQuery()
46 if err != nil {
47 return pagination.Pager{Err: err}
48 }
49 url += query
50 }
51
52 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
53 return LBPage{pagination.LinkedPageBase{PageResult: r}}
54 })
55}
Jamie Hannaforde09b6822014-10-31 15:33:57 +010056
57type enabledState *bool
58
Jamie Hannafordb2007ee2014-11-03 16:24:43 +010059// Convenience vars to help setting enabled state.
Jamie Hannaforde09b6822014-10-31 15:33:57 +010060var (
61 iTrue = true
62 iFalse = false
63
64 Enabled enabledState = &iTrue
65 Disabled enabledState = &iFalse
66)
67
68// CreateOptsBuilder is the interface options structs have to satisfy in order
69// to be used in the main Create operation in this package. Since many
70// extensions decorate or modify the common logic, it is useful for them to
71// satisfy a basic interface in order for them to be used.
72type CreateOptsBuilder interface {
73 ToLBCreateMap() (map[string]interface{}, error)
74}
75
76// CreateOpts is the common options struct used in this package's Create
77// operation.
78type CreateOpts struct {
79 // Required - name of the load balancer to create. The name must be 128
80 // characters or fewer in length, and all UTF-8 characters are valid.
81 Name string
82
83 // Optional - nodes to be added.
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010084 Nodes []nodes.Node
Jamie Hannaforde09b6822014-10-31 15:33:57 +010085
86 // Required - protocol of the service that is being load balanced.
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +010087 // See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
88 // for a full list of supported protocols.
89 Protocol string
Jamie Hannaforde09b6822014-10-31 15:33:57 +010090
91 // Optional - enables or disables Half-Closed support for the load balancer.
92 // Half-Closed support provides the ability for one end of the connection to
93 // terminate its output, while still receiving data from the other end. Only
94 // available for TCP/TCP_CLIENT_FIRST protocols.
95 HalfClosed enabledState
96
97 // Optional - the type of virtual IPs you want associated with the load
98 // balancer.
Jamie Hannaford1c817312014-11-04 10:56:58 +010099 VIPs []vips.VIP
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100100
101 // Optional - the access list management feature allows fine-grained network
102 // access controls to be applied to the load balancer virtual IP address.
103 AccessList string
104
105 // Optional - algorithm that defines how traffic should be directed between
106 // back-end nodes.
Jamie Hannaford46336282014-11-04 14:48:20 +0100107 Algorithm string
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100108
109 // Optional - current connection logging configuration.
110 ConnectionLogging *ConnectionLogging
111
112 // Optional - specifies a limit on the number of connections per IP address
113 // to help mitigate malicious or abusive traffic to your applications.
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100114 ConnThrottle *ConnectionThrottle
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100115
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100116 // Optional -
117 //HealthMonitor string
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100118
119 // Optional - arbitrary information that can be associated with each LB.
120 Metadata map[string]interface{}
121
122 // Optional - port number for the service you are load balancing.
123 Port int
124
125 // Optional - the timeout value for the load balancer and communications with
126 // its nodes. Defaults to 30 seconds with a maximum of 120 seconds.
127 Timeout int
128
129 // Optional - specifies whether multiple requests from clients are directed
130 // to the same node.
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100131 SessionPersistence *SessionPersistence
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100132
133 // Optional - enables or disables HTTP to HTTPS redirection for the load
134 // balancer. When enabled, any HTTP request returns status code 301 (Moved
135 // Permanently), and the requester is redirected to the requested URL via the
136 // HTTPS protocol on port 443. For example, http://example.com/page.html
137 // would be redirected to https://example.com/page.html. Only available for
138 // HTTPS protocol (port=443), or HTTP protocol with a properly configured SSL
139 // termination (secureTrafficOnly=true, securePort=443).
140 HTTPSRedirect enabledState
141}
142
143var (
144 errNameRequired = errors.New("Name is a required attribute")
145 errTimeoutExceeded = errors.New("Timeout must be less than 120")
146)
147
148// ToLBCreateMap casts a CreateOpts struct to a map.
149func (opts CreateOpts) ToLBCreateMap() (map[string]interface{}, error) {
150 lb := make(map[string]interface{})
151
152 if opts.Name == "" {
153 return lb, errNameRequired
154 }
155 if opts.Timeout > 120 {
156 return lb, errTimeoutExceeded
157 }
158
159 lb["name"] = opts.Name
160
161 if len(opts.Nodes) > 0 {
162 nodes := []map[string]interface{}{}
163 for _, n := range opts.Nodes {
164 nodes = append(nodes, map[string]interface{}{
165 "address": n.Address,
166 "port": n.Port,
167 "condition": n.Condition,
168 })
169 }
170 lb["nodes"] = nodes
171 }
172
173 if opts.Protocol != "" {
174 lb["protocol"] = opts.Protocol
175 }
176 if opts.HalfClosed != nil {
177 lb["halfClosed"] = opts.HalfClosed
178 }
179
180 if len(opts.VIPs) > 0 {
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100181 lb["virtualIps"] = opts.VIPs
182 }
183
184 // if opts.AccessList != "" {
185 // lb["accessList"] = opts.AccessList
186 // }
187 if opts.Algorithm != "" {
188 lb["algorithm"] = opts.Algorithm
189 }
190 if opts.ConnectionLogging != nil {
191 lb["connectionLogging"] = &opts.ConnectionLogging
192 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100193 if opts.ConnThrottle != nil {
194 lb["connectionThrottle"] = &opts.ConnThrottle
195 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100196 // if opts.HealthMonitor != "" {
197 // lb["healthMonitor"] = opts.HealthMonitor
198 // }
199 if len(opts.Metadata) != 0 {
200 lb["metadata"] = opts.Metadata
201 }
202 if opts.Port > 0 {
203 lb["port"] = opts.Port
204 }
205 if opts.Timeout > 0 {
206 lb["timeout"] = opts.Timeout
207 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100208 if opts.SessionPersistence != nil {
209 lb["sessionPersistence"] = &opts.SessionPersistence
210 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100211 if opts.HTTPSRedirect != nil {
212 lb["httpsRedirect"] = &opts.HTTPSRedirect
213 }
214
215 return map[string]interface{}{"loadBalancer": lb}, nil
216}
217
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100218// Create is the operation responsible for asynchronously provisioning a new
219// load balancer based on the configuration defined in CreateOpts. Once the
220// request is validated and progress has started on the provisioning process, a
221// response struct is returned. When extracted (with Extract()), you have
222// to the load balancer's unique ID and status.
223//
224// Once an ID is attained, you can check on the progress of the operation by
225// calling Get and passing in the ID. If the corresponding request cannot be
226// fulfilled due to insufficient or invalid data, a HTTP 400 (Bad Request)
227// error response is returned with information regarding the nature of the
228// failure in the body of the response. Failures in the validation process are
229// non-recoverable and require the caller to correct the cause of the failure.
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100230func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
231 var res CreateResult
232
233 reqBody, err := opts.ToLBCreateMap()
234 if err != nil {
235 res.Err = err
236 return res
237 }
238
239 _, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
240 MoreHeaders: c.AuthenticatedHeaders(),
241 ReqBody: &reqBody,
242 Results: &res.Body,
243 OkCodes: []int{200},
244 })
245
246 return res
247}
Jamie Hannaford1c260332014-10-31 15:57:22 +0100248
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100249// Get is the operation responsible for providing detailed information
250// regarding a specific load balancer which is configured and associated with
251// your account. This operation is not capable of returning details for a load
252// balancer which has been deleted.
Jamie Hannaford07c06962014-10-31 16:42:03 +0100253func Get(c *gophercloud.ServiceClient, id int) GetResult {
254 var res GetResult
255
256 _, res.Err = perigee.Request("GET", resourceURL(c, id), perigee.Options{
257 MoreHeaders: c.AuthenticatedHeaders(),
258 Results: &res.Body,
259 OkCodes: []int{200},
260 })
261
262 return res
263}
264
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100265// BulkDelete removes all the load balancers referenced in the slice of IDs.
266// Any and all configuration data associated with these load balancers are
267// immediately purged and is not recoverable.
268//
269// If one of the items in the list cannot be removed due to its current status,
270// a 400 Bad Request error is returned along with the IDs of the ones the
271// system identified as potential failures for this request.
Jamie Hannaford1c260332014-10-31 15:57:22 +0100272func BulkDelete(c *gophercloud.ServiceClient, ids []int) DeleteResult {
273 var res DeleteResult
274
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +0100275 if len(ids) > 10 || len(ids) == 0 {
276 res.Err = errors.New("You must provide a minimum of 1 and a maximum of 10 LB IDs")
277 return res
278 }
279
Jamie Hannaford1c260332014-10-31 15:57:22 +0100280 url := rootURL(c)
Jamie Hannaford940159d2014-11-03 13:04:08 +0100281 url += v1.IDSliceToQueryString("id", ids)
Jamie Hannaford1c260332014-10-31 15:57:22 +0100282
283 _, res.Err = perigee.Request("DELETE", url, perigee.Options{
284 MoreHeaders: c.AuthenticatedHeaders(),
285 OkCodes: []int{202},
286 })
287
288 return res
289}
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100290
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100291// Delete removes a single load balancer.
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100292func Delete(c *gophercloud.ServiceClient, id int) DeleteResult {
293 var res DeleteResult
294
295 _, res.Err = perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
296 MoreHeaders: c.AuthenticatedHeaders(),
297 OkCodes: []int{202},
298 })
299
300 return res
301}
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100302
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100303// UpdateOptsBuilder represents a type that can be converted into a JSON-like
304// map structure.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100305type UpdateOptsBuilder interface {
306 ToLBUpdateMap() (map[string]interface{}, error)
307}
308
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100309// UpdateOpts represent the options for updating an existing load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100310type UpdateOpts struct {
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100311 // Optional - new name of the load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100312 Name string
313
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100314 // Optional - the new protocol you want your load balancer to have.
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +0100315 // See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
316 // for a full list of supported protocols.
317 Protocol string
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100318
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100319 // Optional - see the HalfClosed field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100320 HalfClosed enabledState
321
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100322 // Optional - see the Algorithm field in CreateOpts for more information.
Jamie Hannaford46336282014-11-04 14:48:20 +0100323 Algorithm string
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100324
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100325 // Optional - see the Port field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100326 Port int
327
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100328 // Optional - see the Timeout field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100329 Timeout int
330
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100331 // Optional - see the HTTPSRedirect field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100332 HTTPSRedirect enabledState
333}
334
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100335// ToLBUpdateMap casts an UpdateOpts struct to a map.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100336func (opts UpdateOpts) ToLBUpdateMap() (map[string]interface{}, error) {
337 lb := make(map[string]interface{})
338
339 if opts.Name != "" {
340 lb["name"] = opts.Name
341 }
342 if opts.Protocol != "" {
343 lb["protocol"] = opts.Protocol
344 }
345 if opts.HalfClosed != nil {
346 lb["halfClosed"] = opts.HalfClosed
347 }
348 if opts.Algorithm != "" {
349 lb["algorithm"] = opts.Algorithm
350 }
351 if opts.Port > 0 {
352 lb["port"] = opts.Port
353 }
354 if opts.Timeout > 0 {
355 lb["timeout"] = opts.Timeout
356 }
357 if opts.HTTPSRedirect != nil {
358 lb["httpsRedirect"] = &opts.HTTPSRedirect
359 }
360
361 return map[string]interface{}{"loadBalancer": lb}, nil
362}
363
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100364// Update is the operation responsible for asynchronously updating the
365// attributes of a specific load balancer. Upon successful validation of the
366// request, the service returns a 202 Accepted response and the load balancer
367// enters a PENDING_UPDATE state. A user can poll the load balancer with Get to
368// wait for the changes to be applied. When this happens, the load balancer will
369// return to an ACTIVE state.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100370func Update(c *gophercloud.ServiceClient, id int, opts UpdateOptsBuilder) UpdateResult {
371 var res UpdateResult
372
373 reqBody, err := opts.ToLBUpdateMap()
374 if err != nil {
375 res.Err = err
376 return res
377 }
378
379 _, res.Err = perigee.Request("PUT", resourceURL(c, id), perigee.Options{
380 MoreHeaders: c.AuthenticatedHeaders(),
381 ReqBody: &reqBody,
382 OkCodes: []int{200},
383 })
384
385 return res
386}
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +0100387
388// ListProtocols is the operation responsible for returning a paginated
389// collection of load balancer protocols.
390func ListProtocols(client *gophercloud.ServiceClient) pagination.Pager {
391 url := protocolsURL(client)
392 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
393 return ProtocolPage{pagination.SinglePageBase(r)}
394 })
395}
Jamie Hannaford46336282014-11-04 14:48:20 +0100396
397// ListAlgorithms is the operation responsible for returning a paginated
398// collection of load balancer algorithms.
399func ListAlgorithms(client *gophercloud.ServiceClient) pagination.Pager {
400 url := algorithmsURL(client)
401 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
402 return AlgorithmPage{pagination.SinglePageBase(r)}
403 })
404}