Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions netloadbalancer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

type NetLoadBalancer struct {
// This NetLoadBalancer's unique ID.
ID int `json:"id"`
// This NetLoadBalancer's label. These must be unique on your Account.
Label string `json:"label"`
// The Region where this NetLoadBalancer is located.
Region string `json:"region"`
// The IPv4 address of this NetLoadBalancer.
AddressV4 string `json:"address_v4"`
// The IPv6 address of this NetLoadBalancer.
AddressV6 string `json:"address_v6"`
// The status of this NetLoadBalancer.
Status string `json:"status"`
// This NetLoadBalancer's date and time of creation.
Created *time.Time `json:"-"`
// This NetLoadBalancer's date and time of last update.
Updated *time.Time `json:"-"`
// This NetLoadBalancer's date and time of last composite update.
LastCompositeUpdated *time.Time `json:"-"`
// An array of listeners for this NetLoadBalancer.
Listeners []NetLoadBalancerListener `json:"listeners"`
}

type NetLoadBalancerCreateOptions struct {
// This NetLoadBalancer's label. These must be unique on your Account.
Label string `json:"label"`
// The Region where this NetLoadBalancer is located.
Region string `json:"region"`
// An array of listeners for this NetLoadBalancer.
Listeners []NetLoadBalancerListenerCreateOptions `json:"listeners,omitempty"`
}

type NetLoadBalancerUpdateOptions struct {
// This NetLoadBalancer's label. These must be unique on your Account.
Label string `json:"label,omitempty"`
// An array of listeners for this NetLoadBalancer.
Listeners []NetLoadBalancerListenerUpdateOptions `json:"listeners,omitempty"`
}

func (i *NetLoadBalancer) UnmarshalJSON(b []byte) error {
type Mask NetLoadBalancer

p := struct {
*Mask

Check failure on line 54 in netloadbalancer.go

View workflow job for this annotation

GitHub Actions / lint-tidy

there must be an empty line separating embedded fields from regular fields (embeddedstructfieldcheck)
Created *parseabletime.ParseableTime `json:"created"`
Updated *parseabletime.ParseableTime `json:"updated"`
LastCompositeUpdated *parseabletime.ParseableTime `json:"last_composite_updated"`
}{
Mask: (*Mask)(i),
}

if err := json.Unmarshal(b, &p); err != nil {
return err
}

i.Created = (*time.Time)(p.Created)
i.Updated = (*time.Time)(p.Updated)
i.LastCompositeUpdated = (*time.Time)(p.LastCompositeUpdated)

return nil
}

func (i *NetLoadBalancer) GetCreateOptions() NetLoadBalancerCreateOptions {
opts := make([]NetLoadBalancerListenerCreateOptions, len(i.Listeners))
for i, listener := range i.Listeners {
opts[i] = listener.GetCreateOptions()
}
return NetLoadBalancerCreateOptions{

Check failure on line 78 in netloadbalancer.go

View workflow job for this annotation

GitHub Actions / lint-tidy

missing whitespace above this line (too many lines above return) (wsl_v5)
Label: i.Label,
Region: i.Region,
Listeners: opts,
}
}

func (i *NetLoadBalancer) GetUpdateOptions() NetLoadBalancerUpdateOptions {
opts := make([]NetLoadBalancerListenerUpdateOptions, len(i.Listeners))
for i, listener := range i.Listeners {
opts[i] = listener.GetUpdateOptions()
}
return NetLoadBalancerUpdateOptions{

Check failure on line 90 in netloadbalancer.go

View workflow job for this annotation

GitHub Actions / lint-tidy

missing whitespace above this line (too many lines above return) (wsl_v5)
Label: i.Label,
Listeners: opts,
}
}

// ListNetLoadBalancers retrieves a list of NetLoadBalancers
func (c *Client) ListNetLoadBalancers(ctx context.Context, opts *ListOptions) ([]NetLoadBalancer, error) {
return getPaginatedResults[NetLoadBalancer](ctx, c, "netloadbalancers", opts)
}

// GetNetLoadBalancer retrieves a NetLoadBalancer by ID
func (c *Client) GetNetLoadBalancer(ctx context.Context, netloadbalancerID int) (*NetLoadBalancer, error) {
e := formatAPIPath("netloadbalancers/%d", netloadbalancerID)
return doGETRequest[NetLoadBalancer](ctx, c, e)
}

// CreateNetLoadBalancer creates a new NetLoadBalancer
func (c *Client) CreateNetLoadBalancer(ctx context.Context, opts NetLoadBalancerCreateOptions) (*NetLoadBalancer, error) {
return doPOSTRequest[NetLoadBalancer](ctx, c, "netloadbalancers", opts)
}

// UpdateNetLoadBalancer updates a NetLoadBalancer
func (c *Client) UpdateNetLoadBalancer(ctx context.Context, netloadbalancerID int, opts NetLoadBalancerUpdateOptions) (*NetLoadBalancer, error) {
e := formatAPIPath("netloadbalancers/%d", netloadbalancerID)
return doPUTRequest[NetLoadBalancer](ctx, c, e, opts)
}

// DeleteNetLoadBalancer deletes a NetLoadBalancer
func (c *Client) DeleteNetLoadBalancer(ctx context.Context, netloadbalancerID int) error {
e := formatAPIPath("netloadbalancers/%d", netloadbalancerID)
return doDELETERequest(ctx, c, e)
}
133 changes: 133 additions & 0 deletions netloadbalancer_listeners.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

type NetLoadBalancerListener struct {
// This NetLoadBalancerListener's unique ID.
ID int `json:"id"`
// The protocol of this NetLoadBalancerListener.
Protocol string `json:"protocol"`
// The port of this NetLoadBalancerListener.
Port int `json:"port"`
// This NetLoadBalancerListener's label.
Label string `json:"label"`
// This NetLoadBalancerListener's date and time of creation.
Created *time.Time `json:"-"`
// This NetLoadBalancerListener's date and time of last update.
Updated *time.Time `json:"-"`
}

// Need a create options and update options for the NetLoadBalancerListener

Check failure on line 26 in netloadbalancer_listeners.go

View workflow job for this annotation

GitHub Actions / lint-tidy

godoc should start with symbol name ("NetLoadBalancerListenerCreateOptions") (godoclint)
type NetLoadBalancerListenerCreateOptions struct {
// The protocol of this NetLoadBalancerListener.
Protocol string `json:"protocol,omitempty"`
// The port of this NetLoadBalancerListener.
Port int `json:"port,omitempty"`
// The label of this NetLoadBalancerListener.
Label string `json:"label,omitempty"`
// The nodes of this NetLoadBalancerListener.
Nodes []NetLoadBalancerNodeCreateOptions `json:"nodes,omitempty"`
}

type NetLoadBalancerListenerUpdateOptions struct {
// The protocol of this NetLoadBalancerListener.
Protocol string `json:"protocol,omitempty"`
// The port of this NetLoadBalancerListener.
Port int `json:"port"`
// The label of this NetLoadBalancerListener.
Label string `json:"label,omitempty"`
// The nodes of this NetLoadBalancerListener.
Nodes []NetLoadBalancerNodeUpdateOptions `json:"nodes,omitempty"`
}

type NetLoadBalancerListenerNodeWeightsUpdateOptions struct {
// The nodes of this NetLoadBalancerListener.
Nodes []NetLoadBalancerListenerNodeWeightUpdateOptions `json:"nodes,omitempty"`
}

type NetLoadBalancerListenerNodeWeightUpdateOptions struct {
// The ID of the node to update.
ID int `json:"id"`
// The weight of the node.
Weight int `json:"weight"`
}

func (i *NetLoadBalancerListener) UnmarshalJSON(b []byte) error {
type Mask NetLoadBalancerListener

p := struct {
*Mask

Check failure on line 65 in netloadbalancer_listeners.go

View workflow job for this annotation

GitHub Actions / lint-tidy

there must be an empty line separating embedded fields from regular fields (embeddedstructfieldcheck)
Created *parseabletime.ParseableTime `json:"created"`
Updated *parseabletime.ParseableTime `json:"updated"`
}{
Mask: (*Mask)(i),
}

if err := json.Unmarshal(b, &p); err != nil {
return err
}

i.Created = (*time.Time)(p.Created)
i.Updated = (*time.Time)(p.Updated)

return nil
}

// GetCreateOptions returns the create options for the NetLoadBalancerListener but does not include the nodes
func (i *NetLoadBalancerListener) GetCreateOptions() NetLoadBalancerListenerCreateOptions {
return NetLoadBalancerListenerCreateOptions{
Protocol: i.Protocol,
Port: i.Port,
Label: i.Label,
}
}

func (i *NetLoadBalancerListener) GetUpdateOptions() NetLoadBalancerListenerUpdateOptions {
return NetLoadBalancerListenerUpdateOptions{
Label: i.Label,
}
}

// CreateNetLoadBalancerListener creates a new NetLoadBalancerListener
func (c *Client) CreateNetLoadBalancerListener(ctx context.Context, netloadbalancerID int, opts NetLoadBalancerListenerCreateOptions) (*NetLoadBalancerListener, error) {

Check failure on line 98 in netloadbalancer_listeners.go

View workflow job for this annotation

GitHub Actions / lint-tidy

File is not properly formatted (golines)
e := formatAPIPath("netloadbalancers/%d/listeners", netloadbalancerID)
return doPOSTRequest[NetLoadBalancerListener](ctx, c, e, opts)
}

// ListNetLoadBalancerListeners retrieves a list of NetLoadBalancerListeners
func (c *Client) ListNetLoadBalancerListeners(ctx context.Context, netloadbalancerID int, opts *ListOptions) ([]NetLoadBalancerListener, error) {
e := formatAPIPath("netloadbalancers/%d/listeners", netloadbalancerID)
return getPaginatedResults[NetLoadBalancerListener](ctx, c, e, opts)
}

// GetNetLoadBalancerListener retrieves a NetLoadBalancerListener by ID
func (c *Client) GetNetLoadBalancerListener(ctx context.Context, netloadbalancerID int, listenerID int) (*NetLoadBalancerListener, error) {
e := formatAPIPath("netloadbalancers/%d/listeners/%d", netloadbalancerID, listenerID)
return doGETRequest[NetLoadBalancerListener](ctx, c, e)
}

// UpdateNetLoadBalancerListener updates a NetLoadBalancerListener
func (c *Client) UpdateNetLoadBalancerListener(ctx context.Context, netloadbalancerID int, listenerID int, opts NetLoadBalancerListenerUpdateOptions) (*NetLoadBalancerListener, error) {
e := formatAPIPath("netloadbalancers/%d/listeners/%d", netloadbalancerID, listenerID)
return doPUTRequest[NetLoadBalancerListener](ctx, c, e, opts)
}

// DeleteNetLoadBalancerListener deletes a NetLoadBalancerListener
func (c *Client) DeleteNetLoadBalancerListener(ctx context.Context, netloadbalancerID int, listenerID int) error {
e := formatAPIPath("netloadbalancers/%d/listeners/%d", netloadbalancerID, listenerID)
return doDELETERequest(ctx, c, e)
}

// UpdateNetLoadBalancerListenerNodeWeights updates the weights of the nodes of a NetLoadBalancerListener
// Use this to update the weights of the nodes of a NetLoadBalancerListener in case of frequent changes
// High frequency updates are allowed. No response is returned.
func (c *Client) UpdateNetLoadBalancerListenerNodeWeights(ctx context.Context, netloadbalancerID int, listenerID int, opts NetLoadBalancerListenerNodeWeightsUpdateOptions) error {
e := formatAPIPath("netloadbalancers/%d/listeners/%d/node-weights", netloadbalancerID, listenerID)
return doPOSTRequestNoResponseBody(ctx, c, e, opts)
}
120 changes: 120 additions & 0 deletions netloadbalancer_nodes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package linodego

import (
"context"
"encoding/json"
"time"

"github.com/linode/linodego/internal/parseabletime"
)

type NetLoadBalancerNode struct {
// This NetLoadBalancerNode's unique ID.
ID int `json:"id"`
// The ID of the Linode this NetLoadBalancerNode is associated with.
LinodeID int `json:"linode_id"`
// The IPv6 address of this NetLoadBalancerNode.
AddressV6 string `json:"address_v6"`
// This NetLoadBalancerNode's label.
Label string `json:"label"`
// The weight of this NetLoadBalancerNode.
Weight int `json:"weight"`
// This NetLoadBalancerNode's date and time of creation.
Created *time.Time `json:"-"`
// This NetLoadBalancerNode's date and time of last update.
Updated *time.Time `json:"-"`
// This NetLoadBalancerNode's date and time of last weight update.
WeightUpdated *time.Time `json:"-"`
}

type NetLoadBalancerNodeCreateOptions struct {
// The label of the node.
Label string `json:"label"`
// The IPv6 address of the node.
AddressV6 string `json:"address_v6"`
// The weight of the node.
Weight int `json:"weight,omitempty"`
}

type NetLoadBalancerNodeUpdateOptions struct {
// The label of the node.
Label string `json:"label"`
// The IPv6 address of the node.
AddressV6 string `json:"address_v6"`
// The weight of the node.
Weight int `json:"weight,omitempty"`
}

type NetLoadBalancerNodeLabelUpdateOptions struct {
// The label of the node.
Label string `json:"label"`
}

func (i *NetLoadBalancerNode) UnmarshalJSON(b []byte) error {
type Mask NetLoadBalancerNode

p := struct {
*Mask

Check failure on line 57 in netloadbalancer_nodes.go

View workflow job for this annotation

GitHub Actions / lint-tidy

there must be an empty line separating embedded fields from regular fields (embeddedstructfieldcheck)
Created *parseabletime.ParseableTime `json:"created"`
Updated *parseabletime.ParseableTime `json:"updated"`
WeightUpdated *parseabletime.ParseableTime `json:"weight_updated"`
}{
Mask: (*Mask)(i),
}

if err := json.Unmarshal(b, &p); err != nil {
return err
}

i.Created = (*time.Time)(p.Created)
i.Updated = (*time.Time)(p.Updated)
i.WeightUpdated = (*time.Time)(p.WeightUpdated)

return nil
}

func (i *NetLoadBalancerNode) GetCreateOptions() NetLoadBalancerNodeCreateOptions {
return NetLoadBalancerNodeCreateOptions{
Label: i.Label,
AddressV6: i.AddressV6,
Weight: i.Weight,
}
}

func (i *NetLoadBalancerNode) GetUpdateOptions() NetLoadBalancerNodeUpdateOptions {
return NetLoadBalancerNodeUpdateOptions{
Label: i.Label,

Check failure on line 86 in netloadbalancer_nodes.go

View workflow job for this annotation

GitHub Actions / lint-tidy

File is not properly formatted (gci)
AddressV6: i.AddressV6,
Weight: i.Weight,
}
}

// CreateNetLoadBalancerNode creates a new NetLoadBalancerNode
func (c *Client) CreateNetLoadBalancerNode(ctx context.Context, netloadbalancerID int, listenerID int, opts NetLoadBalancerNodeCreateOptions) (*NetLoadBalancerNode, error) {

Check failure on line 93 in netloadbalancer_nodes.go

View workflow job for this annotation

GitHub Actions / lint-tidy

File is not properly formatted (golines)
e := formatAPIPath("netloadbalancers/%d/listeners/%d/nodes", netloadbalancerID, listenerID)
return doPOSTRequest[NetLoadBalancerNode](ctx, c, e, opts)
}

// ListNetLoadBalancerNodes retrieves a list of NetLoadBalancerNodes
func (c *Client) ListNetLoadBalancerNodes(ctx context.Context, netloadbalancerID int, listenerID int, opts *ListOptions) ([]NetLoadBalancerNode, error) {
e := formatAPIPath("netloadbalancers/%d/listeners/%d/nodes", netloadbalancerID, listenerID)
return getPaginatedResults[NetLoadBalancerNode](ctx, c, e, opts)
}

// GetNetLoadBalancerNode retrieves a NetLoadBalancerNode by ID
func (c *Client) GetNetLoadBalancerNode(ctx context.Context, netloadbalancerID int, listenerID int, nodeID int) (*NetLoadBalancerNode, error) {
e := formatAPIPath("netloadbalancers/%d/listeners/%d/nodes/%d", netloadbalancerID, listenerID, nodeID)
return doGETRequest[NetLoadBalancerNode](ctx, c, e)
}

// UpdateNetLoadBalancerNode updates a NetLoadBalancerNode
func (c *Client) UpdateNetLoadBalancerNode(ctx context.Context, netloadbalancerID int, listenerID int, nodeID int, opts NetLoadBalancerNodeLabelUpdateOptions) (*NetLoadBalancerNode, error) {
e := formatAPIPath("netloadbalancers/%d/listeners/%d/nodes/%d", netloadbalancerID, listenerID, nodeID)
return doPUTRequest[NetLoadBalancerNode](ctx, c, e, opts)
}

// DeleteNetLoadBalancerNode deletes a NetLoadBalancerNode
func (c *Client) DeleteNetLoadBalancerNode(ctx context.Context, netloadbalancerID int, listenerID int, nodeID int) error {
e := formatAPIPath("netloadbalancers/%d/listeners/%d/nodes/%d", netloadbalancerID, listenerID, nodeID)
return doDELETERequest(ctx, c, e)
}
12 changes: 12 additions & 0 deletions test/unit/fixtures/netloadbalancer_create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"id": 123,
"label": "Test NetLoadBalancer",
"region": "us-east",
"address_v4": "192.0.2.1",
"address_v6": "2600:3c03::f03c:91ff:fe24:1234",
"status": "active",
"listeners": [],
"created": "2025-01-15T08:00:00",
"updated": "2025-02-05T12:00:00",
"last_composite_updated": "2025-02-05T12:00:00"
}
Loading
Loading