load_balancer.go raw
1 package govultr
2
3 import (
4 "context"
5 "fmt"
6 "net/http"
7
8 "github.com/google/go-querystring/query"
9 )
10
11 const lbPath = "/v2/load-balancers"
12
13 // LoadBalancerService is the interface to interact with the server endpoints on the Vultr API
14 // Link : https://www.vultr.com/api/#tag/load-balancer
15 type LoadBalancerService interface {
16 Create(ctx context.Context, createReq *LoadBalancerReq) (*LoadBalancer, *http.Response, error)
17 Get(ctx context.Context, lbID string) (*LoadBalancer, *http.Response, error)
18 Update(ctx context.Context, lbID string, updateReq *LoadBalancerReq) error
19 Delete(ctx context.Context, lbID string) error
20 DeleteSSL(ctx context.Context, lbID string) error
21 DeleteAutoSSL(ctx context.Context, lbID string) error
22 List(ctx context.Context, options *ListOptions) ([]LoadBalancer, *Meta, *http.Response, error)
23 CreateForwardingRule(ctx context.Context, lbID string, rule *ForwardingRule) (*ForwardingRule, *http.Response, error)
24 GetForwardingRule(ctx context.Context, lbID string, ruleID string) (*ForwardingRule, *http.Response, error)
25 DeleteForwardingRule(ctx context.Context, lbID string, RuleID string) error
26 ListForwardingRules(ctx context.Context, lbID string, options *ListOptions) ([]ForwardingRule, *Meta, *http.Response, error)
27 ListFirewallRules(ctx context.Context, lbID string, options *ListOptions) ([]LBFirewallRule, *Meta, *http.Response, error)
28 GetFirewallRule(ctx context.Context, lbID string, ruleID string) (*LBFirewallRule, *http.Response, error)
29 }
30
31 // LoadBalancerHandler handles interaction with the server methods for the Vultr API
32 type LoadBalancerHandler struct {
33 client *Client
34 }
35
36 // LoadBalancer represent the structure of a load balancer
37 type LoadBalancer struct {
38 ID string `json:"id,omitempty"`
39 DateCreated string `json:"date_created,omitempty"`
40 Region string `json:"region,omitempty"`
41 Label string `json:"label,omitempty"`
42 Status string `json:"status,omitempty"`
43 IPV4 string `json:"ipv4,omitempty"`
44 IPV6 string `json:"ipv6,omitempty"`
45 Instances []string `json:"instances,omitempty"`
46 Nodes int `json:"nodes,omitempty"`
47 HealthCheck *HealthCheck `json:"health_check,omitempty"`
48 GenericInfo *GenericInfo `json:"generic_info,omitempty"`
49 SSLInfo *bool `json:"has_ssl,omitempty"`
50 AutoSSL *AutoSSL `json:"auto_ssl,omitempty"`
51 HTTP2 *bool `json:"http2,omitempty"`
52 HTTP3 *bool `json:"http3,omitempty"`
53 ForwardingRules []ForwardingRule `json:"forwarding_rules,omitempty"`
54 FirewallRules []LBFirewallRule `json:"firewall_rules,omitempty"`
55 GlobalRegions []string `json:"global_regions,omitempty"`
56 }
57
58 // LoadBalancerReq gives options for creating or updating a load balancer
59 type LoadBalancerReq struct {
60 Region string `json:"region,omitempty"`
61 Label string `json:"label,omitempty"`
62 Instances []string `json:"instances,omitempty"`
63 Nodes int `json:"nodes,omitempty"`
64 HealthCheck *HealthCheck `json:"health_check,omitempty"`
65 StickySessions *StickySessions `json:"sticky_session,omitempty"`
66 ForwardingRules []ForwardingRule `json:"forwarding_rules,omitempty"`
67 SSL *SSL `json:"ssl,omitempty"`
68 AutoSSL *AutoSSL `json:"auto_ssl,omitempty"`
69 SSLRedirect *bool `json:"ssl_redirect,omitempty"`
70 HTTP2 *bool `json:"http2,omitempty"`
71 HTTP3 *bool `json:"http3,omitempty"`
72 ProxyProtocol *bool `json:"proxy_protocol,omitempty"`
73 BalancingAlgorithm string `json:"balancing_algorithm,omitempty"`
74 FirewallRules []LBFirewallRule `json:"firewall_rules,omitempty"`
75 Timeout int `json:"timeout,omitempty"`
76 VPC *string `json:"vpc,omitempty"`
77 GlobalRegions []string `json:"global_regions,omitempty"`
78 }
79
80 // InstanceList represents instances that are attached to your load balancer
81 type InstanceList struct {
82 InstanceList []string
83 }
84
85 // HealthCheck represents your health check configuration for your load balancer.
86 type HealthCheck struct {
87 Protocol string `json:"protocol,omitempty"`
88 Port int `json:"port,omitempty"`
89 Path string `json:"path,omitempty"`
90 CheckInterval int `json:"check_interval,omitempty"`
91 ResponseTimeout int `json:"response_timeout,omitempty"`
92 UnhealthyThreshold int `json:"unhealthy_threshold,omitempty"`
93 HealthyThreshold int `json:"healthy_threshold,omitempty"`
94 }
95
96 // GenericInfo represents generic configuration of your load balancer
97 type GenericInfo struct {
98 BalancingAlgorithm string `json:"balancing_algorithm,omitempty"`
99 Timeout int `json:"timeout,omitempty"`
100 SSLRedirect *bool `json:"ssl_redirect,omitempty"`
101 StickySessions *StickySessions `json:"sticky_sessions,omitempty"`
102 ProxyProtocol *bool `json:"proxy_protocol,omitempty"`
103 VPC string `json:"vpc,omitempty"`
104 }
105
106 // StickySessions represents cookie for your load balancer
107 type StickySessions struct {
108 CookieName string `json:"cookie_name,omitempty"`
109 }
110
111 // ForwardingRules represent a list of forwarding rules
112 type ForwardingRules struct {
113 ForwardRuleList []ForwardingRule `json:"forwarding_rules,omitempty"`
114 }
115
116 // ForwardingRule represent a single forwarding rule
117 type ForwardingRule struct {
118 RuleID string `json:"id,omitempty"`
119 FrontendProtocol string `json:"frontend_protocol,omitempty"`
120 FrontendPort int `json:"frontend_port,omitempty"`
121 BackendProtocol string `json:"backend_protocol,omitempty"`
122 BackendPort int `json:"backend_port,omitempty"`
123 }
124
125 // LBFirewallRule represent a single firewall rule
126 type LBFirewallRule struct {
127 RuleID string `json:"id,omitempty"`
128 Port int `json:"port,omitempty"`
129 IPType string `json:"ip_type,omitempty"`
130 Source string `json:"source,omitempty"`
131 }
132
133 // SSL represents valid SSL config
134 type SSL struct {
135 PrivateKey string `json:"private_key,omitempty"`
136 Certificate string `json:"certificate,omitempty"`
137 Chain string `json:"chain,omitempty"`
138 PrivateKeyB64 string `json:"private_key_b64,omitempty"`
139 CertificateB64 string `json:"certificate_b64,omitempty"`
140 ChainB64 string `json:"chain_b64,omitempty"`
141 }
142
143 // AutoSSL represents valid AutoSSL config
144 type AutoSSL struct {
145 DomainZone string `json:"domain_zone"`
146 DomainSub string `json:"domain_sub,omitempty"`
147 Domain string `json:"domain,omitempty"`
148 }
149
150 type lbsBase struct {
151 LoadBalancers []LoadBalancer `json:"load_balancers"`
152 Meta *Meta `json:"meta"`
153 }
154
155 type lbBase struct {
156 LoadBalancer *LoadBalancer `json:"load_balancer"`
157 }
158
159 type lbRulesBase struct {
160 ForwardingRules []ForwardingRule `json:"forwarding_rules"`
161 Meta *Meta `json:"meta"`
162 }
163
164 type lbRuleBase struct {
165 ForwardingRule *ForwardingRule `json:"forwarding_rule"`
166 }
167
168 type lbFWRulesBase struct {
169 FirewallRules []LBFirewallRule `json:"firewall_rules"`
170 Meta *Meta `json:"meta"`
171 }
172
173 type lbFWRuleBase struct {
174 FirewallRule *LBFirewallRule `json:"firewall_rule"`
175 }
176
177 // Create a load balancer
178 func (l *LoadBalancerHandler) Create(ctx context.Context, createReq *LoadBalancerReq) (*LoadBalancer, *http.Response, error) {
179 req, err := l.client.NewRequest(ctx, http.MethodPost, lbPath, createReq)
180 if err != nil {
181 return nil, nil, err
182 }
183
184 var lb = new(lbBase)
185 resp, err := l.client.DoWithContext(ctx, req, &lb)
186 if err != nil {
187 return nil, resp, err
188 }
189
190 return lb.LoadBalancer, resp, nil
191 }
192
193 // Get a load balancer
194 func (l *LoadBalancerHandler) Get(ctx context.Context, lbID string) (*LoadBalancer, *http.Response, error) {
195 uri := fmt.Sprintf("%s/%s", lbPath, lbID)
196 req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
197 if err != nil {
198 return nil, nil, err
199 }
200
201 var lb = new(lbBase)
202 resp, err := l.client.DoWithContext(ctx, req, lb)
203 if err != nil {
204 return nil, resp, err
205 }
206
207 return lb.LoadBalancer, resp, nil
208 }
209
210 // Update updates your your load balancer
211 func (l *LoadBalancerHandler) Update(ctx context.Context, lbID string, updateReq *LoadBalancerReq) error {
212 uri := fmt.Sprintf("%s/%s", lbPath, lbID)
213 req, err := l.client.NewRequest(ctx, http.MethodPatch, uri, updateReq)
214 if err != nil {
215 return err
216 }
217
218 _, err = l.client.DoWithContext(ctx, req, nil)
219 return err
220 }
221
222 // Delete a load balancer subscription.
223 func (l *LoadBalancerHandler) Delete(ctx context.Context, lbID string) error {
224 uri := fmt.Sprintf("%s/%s", lbPath, lbID)
225 req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
226 if err != nil {
227 return err
228 }
229 _, err = l.client.DoWithContext(ctx, req, nil)
230 return err
231 }
232
233 // List all load balancer subscriptions on the current account.
234 func (l *LoadBalancerHandler) List(ctx context.Context, options *ListOptions) ([]LoadBalancer, *Meta, *http.Response, error) { //nolint:dupl
235 req, err := l.client.NewRequest(ctx, http.MethodGet, lbPath, nil)
236 if err != nil {
237 return nil, nil, nil, err
238 }
239
240 newValues, err := query.Values(options)
241 if err != nil {
242 return nil, nil, nil, err
243 }
244
245 req.URL.RawQuery = newValues.Encode()
246
247 lbs := new(lbsBase)
248 resp, err := l.client.DoWithContext(ctx, req, &lbs)
249 if err != nil {
250 return nil, nil, resp, err
251 }
252
253 return lbs.LoadBalancers, lbs.Meta, resp, nil
254 }
255
256 // CreateForwardingRule will create a new forwarding rule for your load balancer subscription.
257 // Note the RuleID will be returned in the ForwardingRule struct
258 func (l *LoadBalancerHandler) CreateForwardingRule(ctx context.Context, lbID string, rule *ForwardingRule) (*ForwardingRule, *http.Response, error) { //nolint:lll
259 uri := fmt.Sprintf("%s/%s/forwarding-rules", lbPath, lbID)
260 req, err := l.client.NewRequest(ctx, http.MethodPost, uri, rule)
261 if err != nil {
262 return nil, nil, err
263 }
264
265 fwRule := new(lbRuleBase)
266 resp, err := l.client.DoWithContext(ctx, req, fwRule)
267 if err != nil {
268 return nil, resp, err
269 }
270
271 return fwRule.ForwardingRule, resp, nil
272 }
273
274 // GetForwardingRule will get a forwarding rule from your load balancer subscription.
275 func (l *LoadBalancerHandler) GetForwardingRule(ctx context.Context, lbID, ruleID string) (*ForwardingRule, *http.Response, error) {
276 uri := fmt.Sprintf("%s/%s/forwarding-rules/%s", lbPath, lbID, ruleID)
277 req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
278 if err != nil {
279 return nil, nil, err
280 }
281
282 fwRule := new(lbRuleBase)
283 resp, err := l.client.DoWithContext(ctx, req, fwRule)
284 if err != nil {
285 return nil, resp, err
286 }
287
288 return fwRule.ForwardingRule, resp, nil
289 }
290
291 // ListForwardingRules lists all forwarding rules for a load balancer subscription
292 func (l *LoadBalancerHandler) ListForwardingRules(ctx context.Context, lbID string, options *ListOptions) ([]ForwardingRule, *Meta, *http.Response, error) { //nolint:dupl,lll
293 uri := fmt.Sprintf("%s/%s/forwarding-rules", lbPath, lbID)
294 req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
295 if err != nil {
296 return nil, nil, nil, err
297 }
298
299 newValues, err := query.Values(options)
300 if err != nil {
301 return nil, nil, nil, err
302 }
303
304 req.URL.RawQuery = newValues.Encode()
305
306 fwRules := new(lbRulesBase)
307 resp, err := l.client.DoWithContext(ctx, req, &fwRules)
308 if err != nil {
309 return nil, nil, resp, err
310 }
311
312 return fwRules.ForwardingRules, fwRules.Meta, resp, nil
313 }
314
315 // DeleteForwardingRule removes a forwarding rule from a load balancer subscription
316 func (l *LoadBalancerHandler) DeleteForwardingRule(ctx context.Context, lbID, ruleID string) error {
317 uri := fmt.Sprintf("%s/%s/forwarding-rules/%s", lbPath, lbID, ruleID)
318 req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
319 if err != nil {
320 return err
321 }
322
323 _, err = l.client.DoWithContext(ctx, req, nil)
324 return err
325 }
326
327 // GetFirewallRule will get a firewall rule from your load balancer subscription.
328 func (l *LoadBalancerHandler) GetFirewallRule(ctx context.Context, lbID, ruleID string) (*LBFirewallRule, *http.Response, error) {
329 uri := fmt.Sprintf("%s/%s/firewall-rules/%s", lbPath, lbID, ruleID)
330 req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
331 if err != nil {
332 return nil, nil, err
333 }
334
335 fwRule := new(lbFWRuleBase)
336 resp, err := l.client.DoWithContext(ctx, req, fwRule)
337 if err != nil {
338 return nil, resp, err
339 }
340
341 return fwRule.FirewallRule, resp, nil
342 }
343
344 // ListFirewallRules lists all firewall rules for a load balancer subscription
345 func (l *LoadBalancerHandler) ListFirewallRules(ctx context.Context, lbID string, options *ListOptions) ([]LBFirewallRule, *Meta, *http.Response, error) { //nolint:dupl,lll
346 uri := fmt.Sprintf("%s/%s/firewall-rules", lbPath, lbID)
347 req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
348 if err != nil {
349 return nil, nil, nil, err
350 }
351
352 newValues, err := query.Values(options)
353 if err != nil {
354 return nil, nil, nil, err
355 }
356
357 req.URL.RawQuery = newValues.Encode()
358
359 fwRules := new(lbFWRulesBase)
360 resp, err := l.client.DoWithContext(ctx, req, &fwRules)
361 if err != nil {
362 return nil, nil, resp, err
363 }
364
365 return fwRules.FirewallRules, fwRules.Meta, resp, nil
366 }
367
368 // DeleteSSL removes the SSL configuration from a load balancer subscription.
369 func (l *LoadBalancerHandler) DeleteSSL(ctx context.Context, lbID string) error {
370 uri := fmt.Sprintf("%s/%s/ssl", lbPath, lbID)
371 req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
372 if err != nil {
373 return err
374 }
375
376 _, err = l.client.DoWithContext(ctx, req, nil)
377 return err
378 }
379
380 // DeleteAutoSSL removes the AutoSSL configuration from a load balancer subscription.
381 func (l *LoadBalancerHandler) DeleteAutoSSL(ctx context.Context, lbID string) error {
382 uri := fmt.Sprintf("%s/%s/auto_ssl", lbPath, lbID)
383 req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
384 if err != nil {
385 return err
386 }
387
388 _, err = l.client.DoWithContext(ctx, req, nil)
389 return err
390 }
391