diff --git a/docs/modules/nodebalancer.md b/docs/modules/nodebalancer.md
index 7f5d487d..35ad0244 100644
--- a/docs/modules/nodebalancer.md
+++ b/docs/modules/nodebalancer.md
@@ -2,6 +2,8 @@
Manage a Linode NodeBalancer.
+NOTE: UDP NodeBalancer may not currently be available to all users.
+
- [Minimum Required Fields](#minimum-required-fields)
- [Examples](#examples)
- [Parameters](#parameters)
@@ -46,6 +48,7 @@ Manage a Linode NodeBalancer.
| `label` |
`str` | **Required** | The unique label to give this NodeBalancer. |
| `state` | `str` | **Required** | The desired state of the target. **(Choices: `present`, `absent`)** |
| `client_conn_throttle` | `int` | Optional | Throttle connections per second. Set to 0 (zero) to disable throttling. **(Updatable)** |
+| `client_udp_sess_throttle` | `int` | Optional | Throttle UDP sessions per second (0-20). Set to 0 (zero) to disable throttling. **(Updatable)** |
| `region` | `str` | Optional | The ID of the Region to create this NodeBalancer in. |
| `firewall_id` | `int` | Optional | The ID of the Firewall to assign this NodeBalancer to. |
| `tags` | `list` | Optional | Tags to assign to this NodeBalancer. **(Updatable)** |
@@ -55,7 +58,7 @@ Manage a Linode NodeBalancer.
| Field | Type | Required | Description |
|-----------|------|----------|------------------------------------------------------------------------------|
-| `algorithm` | `str` | Optional | What algorithm this NodeBalancer should use for routing traffic to backends. **(Choices: `roundrobin`, `leastconn`, `source`; Updatable)** |
+| `algorithm` | `str` | Optional | What algorithm this NodeBalancer should use for routing traffic to backends. **(Choices: `roundrobin`, `leastconn`, `source`, `ring_hash`; Updatable)** |
| `check` | `str` | Optional | The type of check to perform against backends to ensure they are serving requests. **(Choices: `none`, `connection`, `http`, `http_body`; Updatable)** |
| `check_attempts` | `int` | Optional | How many times to attempt a check before considering a backend to be down. **(Updatable)** |
| `check_body` | `str` | Optional | 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)** |
@@ -63,14 +66,15 @@ Manage a Linode NodeBalancer.
| `check_passive` | `bool` | Optional | 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` | `str` | Optional | 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` | `int` | Optional | How long, in seconds, to wait for a check attempt before considering it failed. **(Updatable)** |
-| `cipher_suite` | `str` | Optional | What ciphers to use for SSL connections served by this NodeBalancer. **(Choices: `recommended`, `legacy`; Default: `recommended`; Updatable)** |
+| `udp_check_port` | `int` | Optional | Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic. **(Updatable)** |
+| `cipher_suite` | `str` | Optional | What ciphers to use for SSL connections served by this NodeBalancer. **(Choices: `recommended`, `legacy`, `none`; Updatable)** |
| `port` | `int` | Optional | The port this Config is for. **(Updatable)** |
-| `protocol` | `str` | Optional | The protocol this port is configured to serve. **(Choices: `http`, `https`, `tcp`; Updatable)** |
+| `protocol` | `str` | Optional | The protocol this port is configured to serve. **(Choices: `http`, `https`, `tcp`, `udp`; Updatable)** |
| `proxy_protocol` | `str` | Optional | 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` | `bool` | Optional | 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` | `str` | Optional | 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` | `str` | Optional | The PEM-formatted private key for the SSL certificate set in the ssl_cert field. **(Updatable)** |
-| `stickiness` | `str` | Optional | Controls how session stickiness is handled on this port. **(Choices: `none`, `table`, `http_cookie`; Updatable)** |
+| `stickiness` | `str` | Optional | Controls how session stickiness is handled on this port. **(Choices: `none`, `table`, `http_cookie`, `session`, `source_ip`; Updatable)** |
| [`nodes` (sub-options)](#nodes) | `list` | Optional | A list of nodes to apply to this config. These can alternatively be configured through the nodebalancer_node module. **(Updatable)** |
### nodes
diff --git a/plugins/modules/nodebalancer.py b/plugins/modules/nodebalancer.py
index 124acdf9..5dcc0f0b 100644
--- a/plugins/modules/nodebalancer.py
+++ b/plugins/modules/nodebalancer.py
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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."],
@@ -271,7 +287,10 @@
SPECDOC_META = SpecDocMeta(
- description=["Manage a Linode NodeBalancer."],
+ description=[
+ "Manage a Linode NodeBalancer.",
+ "NOTE: UDP NodeBalancer may not currently be available to all users.",
+ ],
requirements=global_requirements,
author=global_authors,
options=linode_nodebalancer_spec,
@@ -305,7 +324,11 @@
},
)
-MUTABLE_FIELDS: Set[str] = {"client_conn_throttle", "tags"}
+MUTABLE_FIELDS: Set[str] = {
+ "client_conn_throttle",
+ "tags",
+ "client_udp_sess_throttle",
+}
DOCUMENTATION = r"""
"""
@@ -372,7 +395,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:
diff --git a/requirements.txt b/requirements.txt
index 05222cc5..880fb53f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
-linode-api4>=5.31.0
+linode-api4>=5.32.0
polling==0.3.2
ansible-specdoc>=0.0.19
diff --git a/tests/integration/targets/nodebalancer_udp/tasks/main.yaml b/tests/integration/targets/nodebalancer_udp/tasks/main.yaml
new file mode 100644
index 00000000..7c75b7c5
--- /dev/null
+++ b/tests/integration/targets/nodebalancer_udp/tasks/main.yaml
@@ -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 "" }}'
\ No newline at end of file