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