Skip to content

project: NodeBalancers UDP #674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
10 changes: 6 additions & 4 deletions docs/modules/nodebalancer.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Manage a Linode NodeBalancer.
| `label` | <center>`str`</center> | <center>**Required**</center> | The unique label to give this NodeBalancer. |
| `state` | <center>`str`</center> | <center>**Required**</center> | The desired state of the target. **(Choices: `present`, `absent`)** |
| `client_conn_throttle` | <center>`int`</center> | <center>Optional</center> | Throttle connections per second. Set to 0 (zero) to disable throttling. **(Updatable)** |
| `client_udp_sess_throttle` | <center>`int`</center> | <center>Optional</center> | Throttle UDP sessions per second (0-20). Set to 0 (zero) to disable throttling. **(Updatable)** |
| `region` | <center>`str`</center> | <center>Optional</center> | The ID of the Region to create this NodeBalancer in. |
| `firewall_id` | <center>`int`</center> | <center>Optional</center> | The ID of the Firewall to assign this NodeBalancer to. |
| `tags` | <center>`list`</center> | <center>Optional</center> | Tags to assign to this NodeBalancer. **(Updatable)** |
Expand All @@ -55,22 +56,23 @@ Manage a Linode NodeBalancer.

| Field | Type | Required | Description |
|-----------|------|----------|------------------------------------------------------------------------------|
| `algorithm` | <center>`str`</center> | <center>Optional</center> | What algorithm this NodeBalancer should use for routing traffic to backends. **(Choices: `roundrobin`, `leastconn`, `source`; Updatable)** |
| `algorithm` | <center>`str`</center> | <center>Optional</center> | What algorithm this NodeBalancer should use for routing traffic to backends. **(Choices: `roundrobin`, `leastconn`, `source`, `ring_hash`; Updatable)** |
| `check` | <center>`str`</center> | <center>Optional</center> | The type of check to perform against backends to ensure they are serving requests. **(Choices: `none`, `connection`, `http`, `http_body`; Updatable)** |
| `check_attempts` | <center>`int`</center> | <center>Optional</center> | How many times to attempt a check before considering a backend to be down. **(Updatable)** |
| `check_body` | <center>`str`</center> | <center>Optional</center> | This value must be present in the response body of the check in order for it to pass. If this value is not present in the response body of a check request, the backend is considered to be down. **(Updatable)** |
| `check_interval` | <center>`int`</center> | <center>Optional</center> | How often, in seconds, to check that backends are up and serving requests. **(Updatable)** |
| `check_passive` | <center>`bool`</center> | <center>Optional</center> | If true, any response from this backend with a 5xx status code will be enough for it to be considered unhealthy and taken out of rotation. **(Updatable)** |
| `check_path` | <center>`str`</center> | <center>Optional</center> | The URL path to check on each backend. If the backend does not respond to this request it is considered to be down. **(Updatable)** |
| `check_timeout` | <center>`int`</center> | <center>Optional</center> | How long, in seconds, to wait for a check attempt before considering it failed. **(Updatable)** |
| `cipher_suite` | <center>`str`</center> | <center>Optional</center> | What ciphers to use for SSL connections served by this NodeBalancer. **(Choices: `recommended`, `legacy`; Default: `recommended`; Updatable)** |
| `udp_check_port` | <center>`int`</center> | <center>Optional</center> | Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic. **(Updatable)** |
| `cipher_suite` | <center>`str`</center> | <center>Optional</center> | What ciphers to use for SSL connections served by this NodeBalancer. **(Choices: `recommended`, `legacy`, `none`; Updatable)** |
| `port` | <center>`int`</center> | <center>Optional</center> | The port this Config is for. **(Updatable)** |
| `protocol` | <center>`str`</center> | <center>Optional</center> | The protocol this port is configured to serve. **(Choices: `http`, `https`, `tcp`; Updatable)** |
| `protocol` | <center>`str`</center> | <center>Optional</center> | The protocol this port is configured to serve. **(Choices: `http`, `https`, `tcp`, `udp`; Updatable)** |
| `proxy_protocol` | <center>`str`</center> | <center>Optional</center> | ProxyProtocol is a TCP extension that sends initial TCP connection information such as source/destination IPs and ports to backend devices. **(Choices: `none`, `v1`, `v2`; Updatable)** |
| `recreate` | <center>`bool`</center> | <center>Optional</center> | If true, the config will be forcibly recreated on every run. This is useful for updates to redacted fields (`ssl_cert`, `ssl_key`) **(Default: `False`)** |
| `ssl_cert` | <center>`str`</center> | <center>Optional</center> | The PEM-formatted public SSL certificate (or the combined PEM-formatted SSL certificate and Certificate Authority chain) that should be served on this NodeBalancerConfig’s port. **(Updatable)** |
| `ssl_key` | <center>`str`</center> | <center>Optional</center> | The PEM-formatted private key for the SSL certificate set in the ssl_cert field. **(Updatable)** |
| `stickiness` | <center>`str`</center> | <center>Optional</center> | Controls how session stickiness is handled on this port. **(Choices: `none`, `table`, `http_cookie`; Updatable)** |
| `stickiness` | <center>`str`</center> | <center>Optional</center> | Controls how session stickiness is handled on this port. **(Choices: `none`, `table`, `http_cookie`, `session`, `source_ip`; Updatable)** |
| [`nodes` (sub-options)](#nodes) | <center>`list`</center> | <center>Optional</center> | A list of nodes to apply to this config. These can alternatively be configured through the nodebalancer_node module. **(Updatable)** |

### nodes
Expand Down
41 changes: 34 additions & 7 deletions plugins/modules/nodebalancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"What algorithm this NodeBalancer should use "
"for routing traffic to backends."
],
choices=["roundrobin", "leastconn", "source"],
choices=["roundrobin", "leastconn", "source", "ring_hash"],
),
"check": SpecField(
type=FieldType.string,
Expand Down Expand Up @@ -143,15 +143,23 @@
"failed."
],
),
"udp_check_port": SpecField(
type=FieldType.integer,
required=False,
editable=True,
description=[
"Specifies the port on the backend node used for active health checks, which "
"may differ from the port serving traffic."
],
),
"cipher_suite": SpecField(
type=FieldType.string,
required=False,
default="recommended",
editable=True,
description=[
"What ciphers to use for SSL connections served by this NodeBalancer."
],
choices=["recommended", "legacy"],
choices=["recommended", "legacy", "none"],
),
"port": SpecField(
type=FieldType.integer,
Expand All @@ -164,7 +172,7 @@
required=False,
editable=True,
description=["The protocol this port is configured to serve."],
choices=["http", "https", "tcp"],
choices=["http", "https", "tcp", "udp"],
),
"proxy_protocol": SpecField(
type=FieldType.string,
Expand Down Expand Up @@ -211,7 +219,7 @@
description=[
"Controls how session stickiness is handled on this port."
],
choices=["none", "table", "http_cookie"],
choices=["none", "table", "http_cookie", "session", "source_ip"],
),
"nodes": SpecField(
type=FieldType.list,
Expand Down Expand Up @@ -240,6 +248,14 @@
"Set to 0 (zero) to disable throttling.",
],
),
"client_udp_sess_throttle": SpecField(
type=FieldType.integer,
editable=True,
description=[
"Throttle UDP sessions per second (0-20).",
"Set to 0 (zero) to disable throttling.",
],
),
"region": SpecField(
type=FieldType.string,
description=["The ID of the Region to create this NodeBalancer in."],
Expand Down Expand Up @@ -305,7 +321,11 @@
},
)

MUTABLE_FIELDS: Set[str] = {"client_conn_throttle", "tags"}
MUTABLE_FIELDS: Set[str] = {
"client_conn_throttle",
"tags",
"client_udp_sess_throttle",
}

DOCUMENTATION = r"""
"""
Expand Down Expand Up @@ -372,7 +392,14 @@ def _create_nodebalancer(self) -> Optional[NodeBalancer]:
params = {
k: v
for k, v in self.module.params.items()
if k in {"client_conn_throttle", "label", "firewall_id", "tags"}
if k
in {
"client_udp_sess_throttle",
"client_conn_throttle",
"label",
"firewall_id",
"tags",
}
}

try:
Expand Down
7 changes: 5 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
linode-api4>=5.29.0
# TODO (NodeBalancers UDP): Uncomment after feature released in Python SDK
# linode-api4>=5.29.0
git+https://github.com/linode/linode_api4-python.git@proj/nb-udp
Comment on lines +1 to +3
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reminder: Replace this after Python SDK release


polling==0.3.2
ansible-specdoc>=0.0.19
ansible-specdoc>=0.0.19
95 changes: 95 additions & 0 deletions tests/integration/targets/nodebalancer_udp/tasks/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
- name: nodebalancer_udp
block:
- set_fact:
r: "{{ 1000000000 | random }}"

- name: create nodebalancer
linode.cloud.nodebalancer:
label: 'ansible-test-{{ r }}'
region: ap-northeast
client_udp_sess_throttle: 3
state: present
firewall_id: '{{ firewall_id }}'
register: create_nodebalancer

- name: Assert NodeBalancer is created
assert:
that:
- create_nodebalancer.changed
- create_nodebalancer.configs|length == 0
- create_nodebalancer.node_balancer.client_udp_sess_throttle == 3

- name: Add NodeBalancer config
linode.cloud.nodebalancer:
label: '{{ create_nodebalancer.node_balancer.label }}'
region: ap-northeast
client_udp_sess_throttle: 3
state: present
configs:
- port: 80
protocol: udp
algorithm: roundrobin
udp_check_port: 12345
register: create_config

- name: Assert nb config is added
assert:
that:
- create_config.configs|length == 1
- create_config.configs[0].port == 80
- create_config.configs[0].udp_check_port == 12345

- name: Update NodeBalancer config
linode.cloud.nodebalancer:
label: '{{ create_nodebalancer.node_balancer.label }}'
region: ap-northeast
client_udp_sess_throttle: 3
state: present
configs:
- port: 80
protocol: udp
algorithm: roundrobin
udp_check_port: 1234
register: update_config

- name: Assert nb config is updated
assert:
that:
- update_config.configs|length == 1
- update_config.configs[0].udp_check_port == 1234
- update_config.changed

- name: Get nodebalancer_info
linode.cloud.nodebalancer_info:
label: '{{ create_nodebalancer.node_balancer.label }}'
register: nb_info

- name: Assert nb info
assert:
that:
- nb_info.node_balancer.id == create_nodebalancer.node_balancer.id
- nb_info.configs[0].udp_check_port == 1234
- nb_info.configs[0].udp_session_timeout == 16
- nb_info.node_balancer.client_udp_sess_throttle == 3

always:
- ignore_errors: yes
block:
- name: Delete the NodeBalancer
linode.cloud.nodebalancer:
label: '{{ create_nodebalancer.node_balancer.label }}'
state: absent
register: delete

- name: Assert NodeBalancer delete
assert:
that:
- delete.changed
- delete.node_balancer.id == create_nodebalancer.node_balancer.id

environment:
LINODE_UA_PREFIX: '{{ ua_prefix }}'
LINODE_API_TOKEN: '{{ api_token }}'
LINODE_API_URL: '{{ api_url }}'
LINODE_API_VERSION: '{{ api_version }}'
LINODE_CA: '{{ ca_file or "" }}'