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