blob: 0aef0cdaca248c439b682bc12c92dd6f82fe5d65 [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
Jamie Hannafordb2007ee2014-11-03 16:24:43 +010039// List is the operation responsible for returning a paginated collection of
40// load balancers. You may pass in a ListOpts struct to filter results.
Jamie Hannaford186d4e22014-10-31 12:26:11 +010041func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
42 url := rootURL(client)
43 if opts != nil {
44 query, err := opts.ToLBListQuery()
45 if err != nil {
46 return pagination.Pager{Err: err}
47 }
48 url += query
49 }
50
51 return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
52 return LBPage{pagination.LinkedPageBase{PageResult: r}}
53 })
54}
Jamie Hannaforde09b6822014-10-31 15:33:57 +010055
56type enabledState *bool
57
Jamie Hannafordb2007ee2014-11-03 16:24:43 +010058// Convenience vars to help setting enabled state.
Jamie Hannaforde09b6822014-10-31 15:33:57 +010059var (
60 iTrue = true
61 iFalse = false
62
63 Enabled enabledState = &iTrue
64 Disabled enabledState = &iFalse
65)
66
67// CreateOptsBuilder is the interface options structs have to satisfy in order
68// to be used in the main Create operation in this package. Since many
69// extensions decorate or modify the common logic, it is useful for them to
70// satisfy a basic interface in order for them to be used.
71type CreateOptsBuilder interface {
72 ToLBCreateMap() (map[string]interface{}, error)
73}
74
75// CreateOpts is the common options struct used in this package's Create
76// operation.
77type CreateOpts struct {
78 // Required - name of the load balancer to create. The name must be 128
79 // characters or fewer in length, and all UTF-8 characters are valid.
80 Name string
81
82 // Optional - nodes to be added.
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +010083 Nodes []nodes.Node
Jamie Hannaforde09b6822014-10-31 15:33:57 +010084
85 // Required - protocol of the service that is being load balanced.
86 Protocol Protocol
87
88 // Optional - enables or disables Half-Closed support for the load balancer.
89 // Half-Closed support provides the ability for one end of the connection to
90 // terminate its output, while still receiving data from the other end. Only
91 // available for TCP/TCP_CLIENT_FIRST protocols.
92 HalfClosed enabledState
93
94 // Optional - the type of virtual IPs you want associated with the load
95 // balancer.
96 VIPs []VIP
97
98 // Optional - the access list management feature allows fine-grained network
99 // access controls to be applied to the load balancer virtual IP address.
100 AccessList string
101
102 // Optional - algorithm that defines how traffic should be directed between
103 // back-end nodes.
104 Algorithm Algorithm
105
106 // Optional - current connection logging configuration.
107 ConnectionLogging *ConnectionLogging
108
109 // Optional - specifies a limit on the number of connections per IP address
110 // to help mitigate malicious or abusive traffic to your applications.
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100111 ConnThrottle *ConnectionThrottle
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100112
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100113 // Optional -
114 //HealthMonitor string
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100115
116 // Optional - arbitrary information that can be associated with each LB.
117 Metadata map[string]interface{}
118
119 // Optional - port number for the service you are load balancing.
120 Port int
121
122 // Optional - the timeout value for the load balancer and communications with
123 // its nodes. Defaults to 30 seconds with a maximum of 120 seconds.
124 Timeout int
125
126 // Optional - specifies whether multiple requests from clients are directed
127 // to the same node.
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100128 SessionPersistence *SessionPersistence
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100129
130 // Optional - enables or disables HTTP to HTTPS redirection for the load
131 // balancer. When enabled, any HTTP request returns status code 301 (Moved
132 // Permanently), and the requester is redirected to the requested URL via the
133 // HTTPS protocol on port 443. For example, http://example.com/page.html
134 // would be redirected to https://example.com/page.html. Only available for
135 // HTTPS protocol (port=443), or HTTP protocol with a properly configured SSL
136 // termination (secureTrafficOnly=true, securePort=443).
137 HTTPSRedirect enabledState
138}
139
140var (
141 errNameRequired = errors.New("Name is a required attribute")
142 errTimeoutExceeded = errors.New("Timeout must be less than 120")
143)
144
145// ToLBCreateMap casts a CreateOpts struct to a map.
146func (opts CreateOpts) ToLBCreateMap() (map[string]interface{}, error) {
147 lb := make(map[string]interface{})
148
149 if opts.Name == "" {
150 return lb, errNameRequired
151 }
152 if opts.Timeout > 120 {
153 return lb, errTimeoutExceeded
154 }
155
156 lb["name"] = opts.Name
157
158 if len(opts.Nodes) > 0 {
159 nodes := []map[string]interface{}{}
160 for _, n := range opts.Nodes {
161 nodes = append(nodes, map[string]interface{}{
162 "address": n.Address,
163 "port": n.Port,
164 "condition": n.Condition,
165 })
166 }
167 lb["nodes"] = nodes
168 }
169
170 if opts.Protocol != "" {
171 lb["protocol"] = opts.Protocol
172 }
173 if opts.HalfClosed != nil {
174 lb["halfClosed"] = opts.HalfClosed
175 }
176
177 if len(opts.VIPs) > 0 {
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100178 lb["virtualIps"] = opts.VIPs
179 }
180
181 // if opts.AccessList != "" {
182 // lb["accessList"] = opts.AccessList
183 // }
184 if opts.Algorithm != "" {
185 lb["algorithm"] = opts.Algorithm
186 }
187 if opts.ConnectionLogging != nil {
188 lb["connectionLogging"] = &opts.ConnectionLogging
189 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100190 if opts.ConnThrottle != nil {
191 lb["connectionThrottle"] = &opts.ConnThrottle
192 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100193 // if opts.HealthMonitor != "" {
194 // lb["healthMonitor"] = opts.HealthMonitor
195 // }
196 if len(opts.Metadata) != 0 {
197 lb["metadata"] = opts.Metadata
198 }
199 if opts.Port > 0 {
200 lb["port"] = opts.Port
201 }
202 if opts.Timeout > 0 {
203 lb["timeout"] = opts.Timeout
204 }
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100205 if opts.SessionPersistence != nil {
206 lb["sessionPersistence"] = &opts.SessionPersistence
207 }
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100208 if opts.HTTPSRedirect != nil {
209 lb["httpsRedirect"] = &opts.HTTPSRedirect
210 }
211
212 return map[string]interface{}{"loadBalancer": lb}, nil
213}
214
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100215// Create is the operation responsible for asynchronously provisioning a new
216// load balancer based on the configuration defined in CreateOpts. Once the
217// request is validated and progress has started on the provisioning process, a
218// response struct is returned. When extracted (with Extract()), you have
219// to the load balancer's unique ID and status.
220//
221// Once an ID is attained, you can check on the progress of the operation by
222// calling Get and passing in the ID. If the corresponding request cannot be
223// fulfilled due to insufficient or invalid data, a HTTP 400 (Bad Request)
224// error response is returned with information regarding the nature of the
225// failure in the body of the response. Failures in the validation process are
226// non-recoverable and require the caller to correct the cause of the failure.
Jamie Hannaforde09b6822014-10-31 15:33:57 +0100227func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
228 var res CreateResult
229
230 reqBody, err := opts.ToLBCreateMap()
231 if err != nil {
232 res.Err = err
233 return res
234 }
235
236 _, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
237 MoreHeaders: c.AuthenticatedHeaders(),
238 ReqBody: &reqBody,
239 Results: &res.Body,
240 OkCodes: []int{200},
241 })
242
243 return res
244}
Jamie Hannaford1c260332014-10-31 15:57:22 +0100245
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100246// Get is the operation responsible for providing detailed information
247// regarding a specific load balancer which is configured and associated with
248// your account. This operation is not capable of returning details for a load
249// balancer which has been deleted.
Jamie Hannaford07c06962014-10-31 16:42:03 +0100250func Get(c *gophercloud.ServiceClient, id int) GetResult {
251 var res GetResult
252
253 _, res.Err = perigee.Request("GET", resourceURL(c, id), perigee.Options{
254 MoreHeaders: c.AuthenticatedHeaders(),
255 Results: &res.Body,
256 OkCodes: []int{200},
257 })
258
259 return res
260}
261
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100262// BulkDelete removes all the load balancers referenced in the slice of IDs.
263// Any and all configuration data associated with these load balancers are
264// immediately purged and is not recoverable.
265//
266// If one of the items in the list cannot be removed due to its current status,
267// a 400 Bad Request error is returned along with the IDs of the ones the
268// system identified as potential failures for this request.
Jamie Hannaford1c260332014-10-31 15:57:22 +0100269func BulkDelete(c *gophercloud.ServiceClient, ids []int) DeleteResult {
270 var res DeleteResult
271
Jamie Hannaford0a9a6be2014-11-03 12:55:38 +0100272 if len(ids) > 10 || len(ids) == 0 {
273 res.Err = errors.New("You must provide a minimum of 1 and a maximum of 10 LB IDs")
274 return res
275 }
276
Jamie Hannaford1c260332014-10-31 15:57:22 +0100277 url := rootURL(c)
Jamie Hannaford940159d2014-11-03 13:04:08 +0100278 url += v1.IDSliceToQueryString("id", ids)
Jamie Hannaford1c260332014-10-31 15:57:22 +0100279
280 _, res.Err = perigee.Request("DELETE", url, perigee.Options{
281 MoreHeaders: c.AuthenticatedHeaders(),
282 OkCodes: []int{202},
283 })
284
285 return res
286}
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100287
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100288// Delete removes a single load balancer.
Jamie Hannaford5f95e6a2014-10-31 16:13:44 +0100289func Delete(c *gophercloud.ServiceClient, id int) DeleteResult {
290 var res DeleteResult
291
292 _, res.Err = perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
293 MoreHeaders: c.AuthenticatedHeaders(),
294 OkCodes: []int{202},
295 })
296
297 return res
298}
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100299
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100300// UpdateOptsBuilder represents a type that can be converted into a JSON-like
301// map structure.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100302type UpdateOptsBuilder interface {
303 ToLBUpdateMap() (map[string]interface{}, error)
304}
305
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100306// UpdateOpts represent the options for updating an existing load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100307type UpdateOpts struct {
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100308 // Optional - new name of the load balancer.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100309 Name string
310
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100311 // Optional - the new protocol you want your load balancer to have.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100312 Protocol Protocol
313
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100314 // Optional - see the HalfClosed field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100315 HalfClosed enabledState
316
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100317 // Optional - see the Algorithm field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100318 Algorithm Algorithm
319
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100320 // Optional - see the Port field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100321 Port int
322
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100323 // Optional - see the Timeout field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100324 Timeout int
325
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100326 // Optional - see the HTTPSRedirect field in CreateOpts for more information.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100327 HTTPSRedirect enabledState
328}
329
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100330// ToLBUpdateMap casts an UpdateOpts struct to a map.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100331func (opts UpdateOpts) ToLBUpdateMap() (map[string]interface{}, error) {
332 lb := make(map[string]interface{})
333
334 if opts.Name != "" {
335 lb["name"] = opts.Name
336 }
337 if opts.Protocol != "" {
338 lb["protocol"] = opts.Protocol
339 }
340 if opts.HalfClosed != nil {
341 lb["halfClosed"] = opts.HalfClosed
342 }
343 if opts.Algorithm != "" {
344 lb["algorithm"] = opts.Algorithm
345 }
346 if opts.Port > 0 {
347 lb["port"] = opts.Port
348 }
349 if opts.Timeout > 0 {
350 lb["timeout"] = opts.Timeout
351 }
352 if opts.HTTPSRedirect != nil {
353 lb["httpsRedirect"] = &opts.HTTPSRedirect
354 }
355
356 return map[string]interface{}{"loadBalancer": lb}, nil
357}
358
Jamie Hannafordb2007ee2014-11-03 16:24:43 +0100359// Update is the operation responsible for asynchronously updating the
360// attributes of a specific load balancer. Upon successful validation of the
361// request, the service returns a 202 Accepted response and the load balancer
362// enters a PENDING_UPDATE state. A user can poll the load balancer with Get to
363// wait for the changes to be applied. When this happens, the load balancer will
364// return to an ACTIVE state.
Jamie Hannaford76fcc832014-10-31 16:56:50 +0100365func Update(c *gophercloud.ServiceClient, id int, opts UpdateOptsBuilder) UpdateResult {
366 var res UpdateResult
367
368 reqBody, err := opts.ToLBUpdateMap()
369 if err != nil {
370 res.Err = err
371 return res
372 }
373
374 _, res.Err = perigee.Request("PUT", resourceURL(c, id), perigee.Options{
375 MoreHeaders: c.AuthenticatedHeaders(),
376 ReqBody: &reqBody,
377 OkCodes: []int{200},
378 })
379
380 return res
381}