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