1package linodego
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7)
8
9// NodeBalancerConfig objects allow a NodeBalancer to accept traffic on a new port
10type NodeBalancerConfig struct {
11	ID             int                     `json:"id"`
12	Port           int                     `json:"port"`
13	Protocol       ConfigProtocol          `json:"protocol"`
14	ProxyProtocol  ConfigProxyProtocol     `json:"proxy_protocol"`
15	Algorithm      ConfigAlgorithm         `json:"algorithm"`
16	Stickiness     ConfigStickiness        `json:"stickiness"`
17	Check          ConfigCheck             `json:"check"`
18	CheckInterval  int                     `json:"check_interval"`
19	CheckAttempts  int                     `json:"check_attempts"`
20	CheckPath      string                  `json:"check_path"`
21	CheckBody      string                  `json:"check_body"`
22	CheckPassive   bool                    `json:"check_passive"`
23	CheckTimeout   int                     `json:"check_timeout"`
24	CipherSuite    ConfigCipher            `json:"cipher_suite"`
25	NodeBalancerID int                     `json:"nodebalancer_id"`
26	SSLCommonName  string                  `json:"ssl_commonname"`
27	SSLFingerprint string                  `json:"ssl_fingerprint"`
28	SSLCert        string                  `json:"ssl_cert"`
29	SSLKey         string                  `json:"ssl_key"`
30	NodesStatus    *NodeBalancerNodeStatus `json:"nodes_status"`
31}
32
33// ConfigAlgorithm constants start with Algorithm and include Linode API NodeBalancer Config Algorithms
34type ConfigAlgorithm string
35
36// ConfigAlgorithm constants reflect the NodeBalancer Config Algorithm
37const (
38	AlgorithmRoundRobin ConfigAlgorithm = "roundrobin"
39	AlgorithmLeastConn  ConfigAlgorithm = "leastconn"
40	AlgorithmSource     ConfigAlgorithm = "source"
41)
42
43// ConfigStickiness constants start with Stickiness and include Linode API NodeBalancer Config Stickiness
44type ConfigStickiness string
45
46// ConfigStickiness constants reflect the node stickiness method for a NodeBalancer Config
47const (
48	StickinessNone       ConfigStickiness = "none"
49	StickinessTable      ConfigStickiness = "table"
50	StickinessHTTPCookie ConfigStickiness = "http_cookie"
51)
52
53// ConfigCheck constants start with Check and include Linode API NodeBalancer Config Check methods
54type ConfigCheck string
55
56// ConfigCheck constants reflect the node health status checking method for a NodeBalancer Config
57const (
58	CheckNone       ConfigCheck = "none"
59	CheckConnection ConfigCheck = "connection"
60	CheckHTTP       ConfigCheck = "http"
61	CheckHTTPBody   ConfigCheck = "http_body"
62)
63
64// ConfigProtocol constants start with Protocol and include Linode API Nodebalancer Config protocols
65type ConfigProtocol string
66
67// ConfigProtocol constants reflect the protocol used by a NodeBalancer Config
68const (
69	ProtocolHTTP  ConfigProtocol = "http"
70	ProtocolHTTPS ConfigProtocol = "https"
71	ProtocolTCP   ConfigProtocol = "tcp"
72)
73
74// ConfigProxyProtocol constants start with ProxyProtocol and include Linode API NodeBalancer Config proxy protocol versions
75type ConfigProxyProtocol string
76
77// ConfigProxyProtocol constatns reflect the proxy protocol version used by a NodeBalancer Config
78const (
79	ProxyProtocolNone ConfigProxyProtocol = "none"
80	ProxyProtocolV1   ConfigProxyProtocol = "v1"
81	ProxyProtocolV2   ConfigProxyProtocol = "v2"
82)
83
84// ConfigCipher constants start with Cipher and include Linode API NodeBalancer Config Cipher values
85type ConfigCipher string
86
87// ConfigCipher constants reflect the preferred cipher set for a NodeBalancer Config
88const (
89	CipherRecommended ConfigCipher = "recommended"
90	CipherLegacy      ConfigCipher = "legacy"
91)
92
93// NodeBalancerNodeStatus represents the total number of nodes whose status is Up or Down
94type NodeBalancerNodeStatus struct {
95	Up   int `json:"up"`
96	Down int `json:"down"`
97}
98
99// NodeBalancerConfigCreateOptions are permitted by CreateNodeBalancerConfig
100type NodeBalancerConfigCreateOptions struct {
101	Port          int                             `json:"port"`
102	Protocol      ConfigProtocol                  `json:"protocol,omitempty"`
103	ProxyProtocol ConfigProxyProtocol             `json:"proxy_protocol,omitempty"`
104	Algorithm     ConfigAlgorithm                 `json:"algorithm,omitempty"`
105	Stickiness    ConfigStickiness                `json:"stickiness,omitempty"`
106	Check         ConfigCheck                     `json:"check,omitempty"`
107	CheckInterval int                             `json:"check_interval,omitempty"`
108	CheckAttempts int                             `json:"check_attempts,omitempty"`
109	CheckPath     string                          `json:"check_path,omitempty"`
110	CheckBody     string                          `json:"check_body,omitempty"`
111	CheckPassive  *bool                           `json:"check_passive,omitempty"`
112	CheckTimeout  int                             `json:"check_timeout,omitempty"`
113	CipherSuite   ConfigCipher                    `json:"cipher_suite,omitempty"`
114	SSLCert       string                          `json:"ssl_cert,omitempty"`
115	SSLKey        string                          `json:"ssl_key,omitempty"`
116	Nodes         []NodeBalancerNodeCreateOptions `json:"nodes,omitempty"`
117}
118
119// NodeBalancerConfigRebuildOptions used by RebuildNodeBalancerConfig
120type NodeBalancerConfigRebuildOptions struct {
121	Port          int                             `json:"port"`
122	Protocol      ConfigProtocol                  `json:"protocol,omitempty"`
123	ProxyProtocol ConfigProxyProtocol             `json:"proxy_protocol,omitempty"`
124	Algorithm     ConfigAlgorithm                 `json:"algorithm,omitempty"`
125	Stickiness    ConfigStickiness                `json:"stickiness,omitempty"`
126	Check         ConfigCheck                     `json:"check,omitempty"`
127	CheckInterval int                             `json:"check_interval,omitempty"`
128	CheckAttempts int                             `json:"check_attempts,omitempty"`
129	CheckPath     string                          `json:"check_path,omitempty"`
130	CheckBody     string                          `json:"check_body,omitempty"`
131	CheckPassive  *bool                           `json:"check_passive,omitempty"`
132	CheckTimeout  int                             `json:"check_timeout,omitempty"`
133	CipherSuite   ConfigCipher                    `json:"cipher_suite,omitempty"`
134	SSLCert       string                          `json:"ssl_cert,omitempty"`
135	SSLKey        string                          `json:"ssl_key,omitempty"`
136	Nodes         []NodeBalancerNodeCreateOptions `json:"nodes"`
137}
138
139// NodeBalancerConfigUpdateOptions are permitted by UpdateNodeBalancerConfig
140type NodeBalancerConfigUpdateOptions NodeBalancerConfigCreateOptions
141
142// GetCreateOptions converts a NodeBalancerConfig to NodeBalancerConfigCreateOptions for use in CreateNodeBalancerConfig
143func (i NodeBalancerConfig) GetCreateOptions() NodeBalancerConfigCreateOptions {
144	return NodeBalancerConfigCreateOptions{
145		Port:          i.Port,
146		Protocol:      i.Protocol,
147		ProxyProtocol: i.ProxyProtocol,
148		Algorithm:     i.Algorithm,
149		Stickiness:    i.Stickiness,
150		Check:         i.Check,
151		CheckInterval: i.CheckInterval,
152		CheckAttempts: i.CheckAttempts,
153		CheckTimeout:  i.CheckTimeout,
154		CheckPath:     i.CheckPath,
155		CheckBody:     i.CheckBody,
156		CheckPassive:  copyBool(&i.CheckPassive),
157		CipherSuite:   i.CipherSuite,
158		SSLCert:       i.SSLCert,
159		SSLKey:        i.SSLKey,
160	}
161}
162
163// GetUpdateOptions converts a NodeBalancerConfig to NodeBalancerConfigUpdateOptions for use in UpdateNodeBalancerConfig
164func (i NodeBalancerConfig) GetUpdateOptions() NodeBalancerConfigUpdateOptions {
165	return NodeBalancerConfigUpdateOptions{
166		Port:          i.Port,
167		Protocol:      i.Protocol,
168		ProxyProtocol: i.ProxyProtocol,
169		Algorithm:     i.Algorithm,
170		Stickiness:    i.Stickiness,
171		Check:         i.Check,
172		CheckInterval: i.CheckInterval,
173		CheckAttempts: i.CheckAttempts,
174		CheckPath:     i.CheckPath,
175		CheckBody:     i.CheckBody,
176		CheckPassive:  copyBool(&i.CheckPassive),
177		CheckTimeout:  i.CheckTimeout,
178		CipherSuite:   i.CipherSuite,
179		SSLCert:       i.SSLCert,
180		SSLKey:        i.SSLKey,
181	}
182}
183
184// GetRebuildOptions converts a NodeBalancerConfig to NodeBalancerConfigRebuildOptions for use in RebuildNodeBalancerConfig
185func (i NodeBalancerConfig) GetRebuildOptions() NodeBalancerConfigRebuildOptions {
186	return NodeBalancerConfigRebuildOptions{
187		Port:          i.Port,
188		Protocol:      i.Protocol,
189		ProxyProtocol: i.ProxyProtocol,
190		Algorithm:     i.Algorithm,
191		Stickiness:    i.Stickiness,
192		Check:         i.Check,
193		CheckInterval: i.CheckInterval,
194		CheckAttempts: i.CheckAttempts,
195		CheckTimeout:  i.CheckTimeout,
196		CheckPath:     i.CheckPath,
197		CheckBody:     i.CheckBody,
198		CheckPassive:  copyBool(&i.CheckPassive),
199		CipherSuite:   i.CipherSuite,
200		SSLCert:       i.SSLCert,
201		SSLKey:        i.SSLKey,
202		Nodes:         make([]NodeBalancerNodeCreateOptions, 0),
203	}
204}
205
206// NodeBalancerConfigsPagedResponse represents a paginated NodeBalancerConfig API response
207type NodeBalancerConfigsPagedResponse struct {
208	*PageOptions
209	Data []NodeBalancerConfig `json:"data"`
210}
211
212// endpointWithID gets the endpoint URL for NodeBalancerConfig
213func (NodeBalancerConfigsPagedResponse) endpointWithID(c *Client, id int) string {
214	endpoint, err := c.NodeBalancerConfigs.endpointWithParams(id)
215	if err != nil {
216		panic(err)
217	}
218	return endpoint
219}
220
221// appendData appends NodeBalancerConfigs when processing paginated NodeBalancerConfig responses
222func (resp *NodeBalancerConfigsPagedResponse) appendData(r *NodeBalancerConfigsPagedResponse) {
223	resp.Data = append(resp.Data, r.Data...)
224}
225
226// ListNodeBalancerConfigs lists NodeBalancerConfigs
227func (c *Client) ListNodeBalancerConfigs(ctx context.Context, nodebalancerID int, opts *ListOptions) ([]NodeBalancerConfig, error) {
228	response := NodeBalancerConfigsPagedResponse{}
229	err := c.listHelperWithID(ctx, &response, nodebalancerID, opts)
230	if err != nil {
231		return nil, err
232	}
233	return response.Data, nil
234}
235
236// GetNodeBalancerConfig gets the template with the provided ID
237func (c *Client) GetNodeBalancerConfig(ctx context.Context, nodebalancerID int, configID int) (*NodeBalancerConfig, error) {
238	e, err := c.NodeBalancerConfigs.endpointWithParams(nodebalancerID)
239	if err != nil {
240		return nil, err
241	}
242	e = fmt.Sprintf("%s/%d", e, configID)
243	r, err := coupleAPIErrors(c.R(ctx).SetResult(&NodeBalancerConfig{}).Get(e))
244	if err != nil {
245		return nil, err
246	}
247	return r.Result().(*NodeBalancerConfig), nil
248}
249
250// CreateNodeBalancerConfig creates a NodeBalancerConfig
251func (c *Client) CreateNodeBalancerConfig(ctx context.Context, nodebalancerID int, nodebalancerConfig NodeBalancerConfigCreateOptions) (*NodeBalancerConfig, error) {
252	var body string
253	e, err := c.NodeBalancerConfigs.endpointWithParams(nodebalancerID)
254	if err != nil {
255		return nil, err
256	}
257
258	req := c.R(ctx).SetResult(&NodeBalancerConfig{})
259
260	if bodyData, err := json.Marshal(nodebalancerConfig); err == nil {
261		body = string(bodyData)
262	} else {
263		return nil, NewError(err)
264	}
265
266	r, err := coupleAPIErrors(req.
267		SetHeader("Content-Type", "application/json").
268		SetBody(body).
269		Post(e))
270	if err != nil {
271		return nil, err
272	}
273	return r.Result().(*NodeBalancerConfig), nil
274}
275
276// UpdateNodeBalancerConfig updates the NodeBalancerConfig with the specified id
277func (c *Client) UpdateNodeBalancerConfig(ctx context.Context, nodebalancerID int, configID int, updateOpts NodeBalancerConfigUpdateOptions) (*NodeBalancerConfig, error) {
278	var body string
279	e, err := c.NodeBalancerConfigs.endpointWithParams(nodebalancerID)
280	if err != nil {
281		return nil, err
282	}
283	e = fmt.Sprintf("%s/%d", e, configID)
284
285	req := c.R(ctx).SetResult(&NodeBalancerConfig{})
286
287	if bodyData, err := json.Marshal(updateOpts); err == nil {
288		body = string(bodyData)
289	} else {
290		return nil, NewError(err)
291	}
292
293	r, err := coupleAPIErrors(req.
294		SetBody(body).
295		Put(e))
296	if err != nil {
297		return nil, err
298	}
299	return r.Result().(*NodeBalancerConfig), nil
300}
301
302// DeleteNodeBalancerConfig deletes the NodeBalancerConfig with the specified id
303func (c *Client) DeleteNodeBalancerConfig(ctx context.Context, nodebalancerID int, configID int) error {
304	e, err := c.NodeBalancerConfigs.endpointWithParams(nodebalancerID)
305	if err != nil {
306		return err
307	}
308	e = fmt.Sprintf("%s/%d", e, configID)
309
310	_, err = coupleAPIErrors(c.R(ctx).Delete(e))
311	return err
312}
313
314// RebuildNodeBalancerConfig updates the NodeBalancer with the specified id
315func (c *Client) RebuildNodeBalancerConfig(ctx context.Context, nodeBalancerID int, configID int, rebuildOpts NodeBalancerConfigRebuildOptions) (*NodeBalancerConfig, error) {
316	var body string
317	e, err := c.NodeBalancerConfigs.endpointWithParams(nodeBalancerID)
318	if err != nil {
319		return nil, err
320	}
321	e = fmt.Sprintf("%s/%d/rebuild", e, configID)
322
323	req := c.R(ctx).SetResult(&NodeBalancerConfig{})
324
325	if bodyData, err := json.Marshal(rebuildOpts); err == nil {
326		body = string(bodyData)
327	} else {
328		return nil, NewError(err)
329	}
330
331	r, err := coupleAPIErrors(req.
332		SetBody(body).
333		Post(e))
334	if err != nil {
335		return nil, err
336	}
337	return r.Result().(*NodeBalancerConfig), nil
338}
339