blob: a26e8ce196932638a06b7bf9a125894777b5db37 [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 Hannafordcfe2f282014-11-07 15:11:21 +010011 "github.com/rackspace/gophercloud/rackspace/lb/v1/acl"
12 "github.com/rackspace/gophercloud/rackspace/lb/v1/monitors"
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010013 "github.com/rackspace/gophercloud/rackspace/lb/v1/nodes"
Jamie Hannaford6bc93aa2014-11-06 12:37:52 +010014 "github.com/rackspace/gophercloud/rackspace/lb/v1/sessions"
Jamie Hannafordcfe2f282014-11-07 15:11:21 +010015 "github.com/rackspace/gophercloud/rackspace/lb/v1/throttle"
Jamie Hannaford1c817312014-11-04 10:56:58 +010016 "github.com/rackspace/gophercloud/rackspace/lb/v1/vips"
Jamie Hannaford186d4e22014-10-31 12:26:11 +010017)
18
Jamie Hannafordcfe2f282014-11-07 15:11:21 +010019var (
20 errNameRequired = errors.New("Name is a required attribute")
21 errTimeoutExceeded = errors.New("Timeout must be less than 120")
22)
23
Jamie Hannaford186d4e22014-10-31 12:26:11 +010024// ListOptsBuilder allows extensions to add additional parameters to the
25// List request.
26type ListOptsBuilder interface {
27 ToLBListQuery() (string, error)
28}
29
30// ListOpts allows the filtering and sorting of paginated collections through
31// the API.
32type ListOpts struct {
33 ChangesSince string `q:"changes-since"`
34 Status Status `q:"status"`
35 NodeAddr string `q:"nodeaddress"`
36 Marker string `q:"marker"`
37 Limit int `q:"limit"`
38}
39
40// ToLBListQuery formats a ListOpts into a query string.
41func (opts ListOpts) ToLBListQuery() (string, error) {
42 q, err := gophercloud.BuildQueryString(opts)
43 if err != nil {
44 return "", err
45 }
46 return q.String(), nil
47}
48
Jamie Hannafordb2007ee2014-11-03 16:24:43 +010049// List is the operation responsible for returning a paginated collection of
50// load balancers. You may pass in a ListOpts struct to filter results.
Jamie Hannaford186d4e22014-10-31 12:26:11 +010051func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
52 url := rootURL(client)
53 if opts != nil {
54 query, err := opts.ToLBListQuery()
55 if err != nil {
56 return pagination.Pager{Err: err}
57 }
58 url += query
59 }
60
61 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
62 return LBPage{pagination.LinkedPageBase{PageResult: r}}
63 })
64}
Jamie Hannaforde09b6822014-10-31 15:33:57 +010065
Jamie Hannaforde09b6822014-10-31 15:33:57 +010066// CreateOptsBuilder is the interface options structs have to satisfy in order
67// to be used in the main Create operation in this package. Since many
68// extensions decorate or modify the common logic, it is useful for them to
69// satisfy a basic interface in order for them to be used.
70type CreateOptsBuilder interface {
71 ToLBCreateMap() (map[string]interface{}, error)
72}
73
74// CreateOpts is the common options struct used in this package's Create
75// operation.
76type CreateOpts struct {
77 // Required - name of the load balancer to create. The name must be 128
78 // characters or fewer in length, and all UTF-8 characters are valid.
79 Name string
80
81 // Optional - nodes to be added.
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010082 Nodes []nodes.Node
Jamie Hannaforde09b6822014-10-31 15:33:57 +010083
84 // Required - protocol of the service that is being load balanced.
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +010085 // See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
86 // for a full list of supported protocols.
87 Protocol string
Jamie Hannaforde09b6822014-10-31 15:33:57 +010088
89 // Optional - enables or disables Half-Closed support for the load balancer.
90 // Half-Closed support provides the ability for one end of the connection to
91 // terminate its output, while still receiving data from the other end. Only
92 // available for TCP/TCP_CLIENT_FIRST protocols.
Jamie Hannafordcfe2f282014-11-07 15:11:21 +010093 HalfClosed gophercloud.EnabledState
Jamie Hannaforde09b6822014-10-31 15:33:57 +010094
95 // Optional - the type of virtual IPs you want associated with the load
96 // balancer.
Jamie Hannaford1c817312014-11-04 10:56:58 +010097 VIPs []vips.VIP
Jamie Hannaforde09b6822014-10-31 15:33:57 +010098
99 // Optional - the access list management feature allows fine-grained network
100 // access controls to be applied to the load balancer virtual IP address.
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100101 AccessList *acl.AccessList
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100102
103 // Optional - algorithm that defines how traffic should be directed between
104 // back-end nodes.
Jamie Hannaford46336282014-11-04 14:48:20 +0100105 Algorithm string
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100106
107 // Optional - current connection logging configuration.
108 ConnectionLogging *ConnectionLogging
109
110 // Optional - specifies a limit on the number of connections per IP address
111 // to help mitigate malicious or abusive traffic to your applications.
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100112 ConnThrottle *throttle.ConnectionThrottle
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100113
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100114 // Optional
115 HealthMonitor *monitors.Monitor
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100116
117 // Optional - arbitrary information that can be associated with each LB.
118 Metadata map[string]interface{}
119
120 // Optional - port number for the service you are load balancing.
121 Port int
122
123 // Optional - the timeout value for the load balancer and communications with
124 // its nodes. Defaults to 30 seconds with a maximum of 120 seconds.
125 Timeout int
126
127 // Optional - specifies whether multiple requests from clients are directed
128 // to the same node.
Jamie Hannaford6bc93aa2014-11-06 12:37:52 +0100129 SessionPersistence *sessions.SessionPersistence
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100130
131 // Optional - enables or disables HTTP to HTTPS redirection for the load
132 // balancer. When enabled, any HTTP request returns status code 301 (Moved
133 // Permanently), and the requester is redirected to the requested URL via the
134 // HTTPS protocol on port 443. For example, http://example.com/page.html
135 // would be redirected to https://example.com/page.html. Only available for
136 // HTTPS protocol (port=443), or HTTP protocol with a properly configured SSL
137 // termination (secureTrafficOnly=true, securePort=443).
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100138 HTTPSRedirect gophercloud.EnabledState
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100139}
140
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100141// 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 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100172 if len(opts.VIPs) > 0 {
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100173 lb["virtualIps"] = opts.VIPs
174 }
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100175 if opts.AccessList != nil {
176 lb["accessList"] = &opts.AccessList
177 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100178 if opts.Algorithm != "" {
179 lb["algorithm"] = opts.Algorithm
180 }
181 if opts.ConnectionLogging != nil {
182 lb["connectionLogging"] = &opts.ConnectionLogging
183 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100184 if opts.ConnThrottle != nil {
185 lb["connectionThrottle"] = &opts.ConnThrottle
186 }
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100187 if opts.HealthMonitor != nil {
188 lb["healthMonitor"] = &opts.HealthMonitor
189 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100190 if len(opts.Metadata) != 0 {
191 lb["metadata"] = opts.Metadata
192 }
193 if opts.Port > 0 {
194 lb["port"] = opts.Port
195 }
196 if opts.Timeout > 0 {
197 lb["timeout"] = opts.Timeout
198 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100199 if opts.SessionPersistence != nil {
200 lb["sessionPersistence"] = &opts.SessionPersistence
201 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100202 if opts.HTTPSRedirect != nil {
203 lb["httpsRedirect"] = &opts.HTTPSRedirect
204 }
205
206 return map[string]interface{}{"loadBalancer": lb}, nil
207}
208
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100209// Create is the operation responsible for asynchronously provisioning a new
210// load balancer based on the configuration defined in CreateOpts. Once the
211// request is validated and progress has started on the provisioning process, a
212// response struct is returned. When extracted (with Extract()), you have
213// to the load balancer's unique ID and status.
214//
215// Once an ID is attained, you can check on the progress of the operation by
216// calling Get and passing in the ID. If the corresponding request cannot be
217// fulfilled due to insufficient or invalid data, a HTTP 400 (Bad Request)
218// error response is returned with information regarding the nature of the
219// failure in the body of the response. Failures in the validation process are
220// non-recoverable and require the caller to correct the cause of the failure.
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100221func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
222 var res CreateResult
223
224 reqBody, err := opts.ToLBCreateMap()
225 if err != nil {
226 res.Err = err
227 return res
228 }
229
230 _, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
231 MoreHeaders: c.AuthenticatedHeaders(),
232 ReqBody: &reqBody,
233 Results: &res.Body,
Jamie Hannafordd56375d2014-11-05 12:38:04 +0100234 OkCodes: []int{202},
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100235 })
236
237 return res
238}
Jamie Hannaford1c260332014-10-31 15:57:22 +0100239
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100240// Get is the operation responsible for providing detailed information
241// regarding a specific load balancer which is configured and associated with
242// your account. This operation is not capable of returning details for a load
243// balancer which has been deleted.
Jamie Hannaford07c06962014-10-31 16:42:03 +0100244func Get(c *gophercloud.ServiceClient, id int) GetResult {
245 var res GetResult
246
247 _, res.Err = perigee.Request("GET", resourceURL(c, id), perigee.Options{
248 MoreHeaders: c.AuthenticatedHeaders(),
249 Results: &res.Body,
250 OkCodes: []int{200},
251 })
252
253 return res
254}
255
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100256// BulkDelete removes all the load balancers referenced in the slice of IDs.
257// Any and all configuration data associated with these load balancers are
258// immediately purged and is not recoverable.
259//
260// If one of the items in the list cannot be removed due to its current status,
261// a 400 Bad Request error is returned along with the IDs of the ones the
262// system identified as potential failures for this request.
Jamie Hannaford1c260332014-10-31 15:57:22 +0100263func BulkDelete(c *gophercloud.ServiceClient, ids []int) DeleteResult {
264 var res DeleteResult
265
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +0100266 if len(ids) > 10 || len(ids) == 0 {
267 res.Err = errors.New("You must provide a minimum of 1 and a maximum of 10 LB IDs")
268 return res
269 }
270
Jamie Hannaford1c260332014-10-31 15:57:22 +0100271 url := rootURL(c)
Jamie Hannaford940159d2014-11-03 13:04:08 +0100272 url += v1.IDSliceToQueryString("id", ids)
Jamie Hannaford1c260332014-10-31 15:57:22 +0100273
274 _, res.Err = perigee.Request("DELETE", url, perigee.Options{
275 MoreHeaders: c.AuthenticatedHeaders(),
276 OkCodes: []int{202},
277 })
278
279 return res
280}
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100281
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100282// Delete removes a single load balancer.
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100283func Delete(c *gophercloud.ServiceClient, id int) DeleteResult {
284 var res DeleteResult
285
286 _, res.Err = perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
287 MoreHeaders: c.AuthenticatedHeaders(),
288 OkCodes: []int{202},
289 })
290
291 return res
292}
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100293
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100294// UpdateOptsBuilder represents a type that can be converted into a JSON-like
295// map structure.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100296type UpdateOptsBuilder interface {
297 ToLBUpdateMap() (map[string]interface{}, error)
298}
299
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100300// UpdateOpts represent the options for updating an existing load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100301type UpdateOpts struct {
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100302 // Optional - new name of the load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100303 Name string
304
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100305 // Optional - the new protocol you want your load balancer to have.
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +0100306 // See http://docs.rackspace.com/loadbalancers/api/v1.0/clb-devguide/content/protocols.html
307 // for a full list of supported protocols.
308 Protocol string
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100309
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100310 // Optional - see the HalfClosed field in CreateOpts for more information.
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100311 HalfClosed gophercloud.EnabledState
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100312
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100313 // Optional - see the Algorithm field in CreateOpts for more information.
Jamie Hannaford46336282014-11-04 14:48:20 +0100314 Algorithm string
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100315
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100316 // Optional - see the Port field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100317 Port int
318
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100319 // Optional - see the Timeout field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100320 Timeout int
321
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100322 // Optional - see the HTTPSRedirect field in CreateOpts for more information.
Jamie Hannafordcfe2f282014-11-07 15:11:21 +0100323 HTTPSRedirect gophercloud.EnabledState
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100324}
325
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100326// ToLBUpdateMap casts an UpdateOpts struct to a map.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100327func (opts UpdateOpts) ToLBUpdateMap() (map[string]interface{}, error) {
328 lb := make(map[string]interface{})
329
330 if opts.Name != "" {
331 lb["name"] = opts.Name
332 }
333 if opts.Protocol != "" {
334 lb["protocol"] = opts.Protocol
335 }
336 if opts.HalfClosed != nil {
337 lb["halfClosed"] = opts.HalfClosed
338 }
339 if opts.Algorithm != "" {
340 lb["algorithm"] = opts.Algorithm
341 }
342 if opts.Port > 0 {
343 lb["port"] = opts.Port
344 }
345 if opts.Timeout > 0 {
346 lb["timeout"] = opts.Timeout
347 }
348 if opts.HTTPSRedirect != nil {
349 lb["httpsRedirect"] = &opts.HTTPSRedirect
350 }
351
352 return map[string]interface{}{"loadBalancer": lb}, nil
353}
354
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100355// Update is the operation responsible for asynchronously updating the
356// attributes of a specific load balancer. Upon successful validation of the
357// request, the service returns a 202 Accepted response and the load balancer
358// enters a PENDING_UPDATE state. A user can poll the load balancer with Get to
359// wait for the changes to be applied. When this happens, the load balancer will
360// return to an ACTIVE state.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100361func Update(c *gophercloud.ServiceClient, id int, opts UpdateOptsBuilder) UpdateResult {
362 var res UpdateResult
363
364 reqBody, err := opts.ToLBUpdateMap()
365 if err != nil {
366 res.Err = err
367 return res
368 }
369
370 _, res.Err = perigee.Request("PUT", resourceURL(c, id), perigee.Options{
371 MoreHeaders: c.AuthenticatedHeaders(),
372 ReqBody: &reqBody,
Jamie Hannafordd56375d2014-11-05 12:38:04 +0100373 OkCodes: []int{202},
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100374 })
375
376 return res
377}
Jamie Hannaford4ab9aea2014-11-04 14:38:06 +0100378
379// ListProtocols is the operation responsible for returning a paginated
380// collection of load balancer protocols.
381func ListProtocols(client *gophercloud.ServiceClient) pagination.Pager {
382 url := protocolsURL(client)
383 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
384 return ProtocolPage{pagination.SinglePageBase(r)}
385 })
386}
Jamie Hannaford46336282014-11-04 14:48:20 +0100387
388// ListAlgorithms is the operation responsible for returning a paginated
389// collection of load balancer algorithms.
390func ListAlgorithms(client *gophercloud.ServiceClient) pagination.Pager {
391 url := algorithmsURL(client)
392 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
393 return AlgorithmPage{pagination.SinglePageBase(r)}
394 })
395}