Skip to content

Commit

Permalink
Added support for NodeBalancers UDP
Browse files Browse the repository at this point in the history
  • Loading branch information
ezilber-akamai committed Jan 17, 2025
1 parent 4da84f0 commit 2a31306
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 21 deletions.
16 changes: 8 additions & 8 deletions docs/inventory/instance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,19 @@ Parameters


**parent_group (type=str):**
\• parent group for keyed group.
\• parent group for keyed group


**prefix (type=str):**
\• A keyed group name will start with this prefix.
\• A keyed group name will start with this prefix


**separator (type=str, default=_):**
\• separator used to build the keyed group name.
\• separator used to build the keyed group name


**key (type=str):**
\• The key from input dictionary used to generate groups.
\• The key from input dictionary used to generate groups


**default_value (type=str):**
Expand All @@ -98,7 +98,7 @@ Parameters


**trailing_separator (type=bool, default=True):**
\• Set this option to :literal:`false` to omit the :literal:`keyed\_groups[].separator` after the host variable when the value is an empty string.
\• Set this option to :literal:`False` to omit the :literal:`keyed\_groups[].separator` after the host variable when the value is an empty string.

\• This option is mutually exclusive with :literal:`keyed\_groups[].default\_value`.

Expand All @@ -109,13 +109,13 @@ Parameters


**leading_separator (type=boolean, default=True):**
\• Use in conjunction with :literal:`keyed\_groups`.
\• Use in conjunction with keyed\_groups.

\• By default, a keyed group that does not have a prefix or a separator provided will have a name that starts with an underscore.

\• This is because the default prefix is :literal:`""` and the default separator is :literal:`"\_"`.
\• This is because the default prefix is "" and the default separator is "\_".

\• Set this option to :literal:`false` to omit the leading underscore (or other separator) if no prefix is given.
\• Set this option to False to omit the leading underscore (or other separator) if no prefix is given.

\• If the group name is derived from a mapping the separator is still used to concatenate the items.

Expand Down
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
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
linode-api4>=5.24.0
git+https://github.com/linode/python-linode-api.git@2d23cefc18bc17d80ca117a6e372ff5ef937ff38#egg=linode-api4
polling==0.3.2
ansible-specdoc>=0.0.15
ansible-specdoc>=0.0.15
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 "" }}'

0 comments on commit 2a31306

Please sign in to comment.