From 294b931d19891b71dd2caffc9d725433fbcb31a9 Mon Sep 17 00:00:00 2001 From: uumas Date: Thu, 12 Mar 2026 00:32:10 +0200 Subject: [PATCH] service: Support publishing arbitary ports through sockets --- roles/service/meta/argument_specs.yaml | 37 ++++++++++++++++++++-- roles/service/tasks/additional.yaml | 8 ++++- roles/service/tasks/additional_socat.yaml | 12 +++++++ roles/service/tasks/main.yaml | 16 ++++++++-- roles/service/vars/main/additional.yaml | 29 +++++++++++++++++ roles/service/vars/main/general.yaml | 4 +++ roles/service/vars/main/publish_ports.yaml | 21 ++++++++++++ 7 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 roles/service/tasks/additional_socat.yaml create mode 100644 roles/service/vars/main/publish_ports.yaml diff --git a/roles/service/meta/argument_specs.yaml b/roles/service/meta/argument_specs.yaml index 1b82d7e..393e80c 100644 --- a/roles/service/meta/argument_specs.yaml +++ b/roles/service/meta/argument_specs.yaml @@ -93,11 +93,44 @@ argument_specs: default: [] elements: str service_container_publish_ports: - description: "A list of published ports in docker format (::)" + description: A list of ports to publish outside the container type: list required: false default: [] - elements: str + elements: dict + options: + name: + description: + - Name of the port. + - If type is socket, the socket will be created at /run/-.sock on the host. + - If type is not socket, this is just informative. + type: str + required: true + container_port: + description: Container port to publish + type: int + required: true + type: + description: Whether to publish as a port or socket + type: str + required: false + default: port + choices: + - socket + - port + host_address: + description: + - IP or hostname to listen on on the host + - Ignored if type is socket + type: str + required: false + default: 0.0.0.0 + host_port: + description: + - Port to listen on on the host + - Required if type is port, ignored otherwise + type: int + required: false service_container_mounts: description: List of bind mounts or volumes to be mounted inside the service container(s). type: list diff --git a/roles/service/tasks/additional.yaml b/roles/service/tasks/additional.yaml index 8d9124d..ce9cf4e 100644 --- a/roles/service/tasks/additional.yaml +++ b/roles/service/tasks/additional.yaml @@ -9,7 +9,7 @@ container_entrypoint: "{{ _service_additional_container.entrypoint | default('') }}" container_user: "{{ service_container_user }}" container_mounts: "{{ _service_additional_container_mounts }}" - container_publish_ports: "{{ _service_additional_container.publish_ports | default([]) }}" + container_publish_ports: "{{ _service_additional_container_publish_ports }}" container_networks: "{{ _service_container_networks }}" container_ip: "{{ _service_additional_container_ip }}" container_secrets: "{{ _service_additional_container.secrets | default(_service_container_secrets) }}" @@ -23,3 +23,9 @@ loop_control: loop_var: _service_additional_container index_var: _service_additional_container_index + +- name: Socat sockets for additional containers of {{ service_name }} + ansible.builtin.include_tasks: additional_socat.yaml + loop: "{{ _service_additional_containers }}" + loop_control: + loop_var: _service_additional_container diff --git a/roles/service/tasks/additional_socat.yaml b/roles/service/tasks/additional_socat.yaml new file mode 100644 index 0000000..c29ec58 --- /dev/null +++ b/roles/service/tasks/additional_socat.yaml @@ -0,0 +1,12 @@ +--- +- name: Socat for socket published ports of {{ service_name }} + ansible.builtin.include_role: + name: socat + loop: "{{ _service_additional_container_publish_socket_ports }}" + loop_control: + loop_var: publish_port + vars: + socat_service_name: "{{ service_name }}-{{ publish_port.name }}" + socat_target_container: "{{ _service_additional_container.name }}" + socat_target_http_port: "{{ publish_port.container_port }}" + socat_auto_update: "{{ service_auto_update }}" diff --git a/roles/service/tasks/main.yaml b/roles/service/tasks/main.yaml index f833319..2e2c998 100644 --- a/roles/service/tasks/main.yaml +++ b/roles/service/tasks/main.yaml @@ -37,7 +37,7 @@ container_user: "{{ service_container_user }}" container_mounts: "{{ _service_container_mounts }}" container_devices: "{{ service_container_devices }}" - container_publish_ports: "{{ service_container_publish_ports }}" + container_publish_ports: "{{ _service_container_publish_ports }}" container_networks: "{{ _service_container_networks }}" container_ip: "{{ service_container_ip }}" container_secrets: "{{ _service_container_secrets }}" @@ -47,7 +47,7 @@ container_wants: "{{ _service_container_wants }}" container_auto_update: "{{ service_auto_update }}" -- name: Socat for {{ service_name }} +- name: Socat for http of {{ service_name }} ansible.builtin.include_role: name: socat when: service_container_http_port > 0 @@ -58,6 +58,18 @@ {{ service_container_ip | ansible.utils.ipmath(3) if _service_static_ip else '' }} socat_auto_update: "{{ service_auto_update }}" +- name: Socat for socket published ports of {{ service_name }} + ansible.builtin.include_role: + name: socat + loop: "{{ _service_container_publish_socket_ports }}" + loop_control: + loop_var: publish_port + vars: + socat_service_name: "{{ service_name }}-{{ publish_port.name }}" + socat_target_container: "{{ service_name }}" + socat_target_http_port: "{{ publish_port.container_port }}" + socat_auto_update: "{{ service_auto_update }}" + - name: Reverse proxy for {{ service_name }} ansible.builtin.include_tasks: proxy.yaml when: service_domains | length > 0 diff --git a/roles/service/vars/main/additional.yaml b/roles/service/vars/main/additional.yaml index bc03b32..9c1f5c5 100644 --- a/roles/service/vars/main/additional.yaml +++ b/roles/service/vars/main/additional.yaml @@ -18,6 +18,35 @@ _service_additional_container_ip: >- if _service_static_ip else '' }} +_service_additional_container_publish_ports_with_defaults: >- + {{ + ([{ 'type': 'port', 'host_address': '0.0.0.0' }] * _service_additional_container.publish_ports | length) + | zip(_service_additional_container.publish_ports) + | map('combine') + }} +_service_additional_container_publish_socket_ports: >- + {{ + _service_additional_container_publish_ports_with_defaults | selectattr('type', '==', 'socket') + if _service_additional_container.publish_ports is defined + else + [] + }} +_service_additional_container_publish_port_ports: >- + {{ + _service_additional_container_publish_ports_with_defaults | selectattr('type', '==', 'port') + if _service_additional_container.publish_ports is defined + else + [] + }} + +_service_additional_container_publish_ports: >- + {{ + _service_additional_container_publish_port_ports | map(attribute='host_address') | + zip( + _service_additional_container_publish_port_ports | map(attribute='host_port'), + _service_additional_container_publish_port_ports | map(attribute='container_port') + ) | map('join', ':') + }} _service_additional_volume_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'volume') }}" _service_additional_template_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'template') }}" diff --git a/roles/service/vars/main/general.yaml b/roles/service/vars/main/general.yaml index f01f3d6..00ab459 100644 --- a/roles/service/vars/main/general.yaml +++ b/roles/service/vars/main/general.yaml @@ -14,6 +14,10 @@ _service_container_wants: >- service_wants + ([service_name + '-socat.socket'] if service_container_http_port > 0 else []) + ([service_name + '-oauth2-proxy-socat.socket'] if _service_oauth2_proxy else []) + + _service_container_publish_socket_ports + | map(attribute='name') + | map('regex_replace', '^', service_name ~ '-') + | map('regex_replace', '$', '-socat.socket') + _service_additional_containers | map(attribute='name') | map('regex_replace', '$', '.service') diff --git a/roles/service/vars/main/publish_ports.yaml b/roles/service/vars/main/publish_ports.yaml new file mode 100644 index 0000000..fce6ef4 --- /dev/null +++ b/roles/service/vars/main/publish_ports.yaml @@ -0,0 +1,21 @@ +--- +_service_container_publish_ports_with_defaults: >- + {{ + ([{ 'type': 'port', 'host_address': '0.0.0.0' }] * service_container_publish_ports | length) + | zip(service_container_publish_ports) + | map('combine') + }} + +_service_container_publish_socket_ports: >- + {{ _service_container_publish_ports_with_defaults | selectattr('type', '==', 'socket') }} +_service_container_publish_port_ports: >- + {{ _service_container_publish_ports_with_defaults | selectattr('type', '==', 'port') }} + +_service_container_publish_ports: >- + {{ + _service_container_publish_port_ports | map(attribute='host_address') | + zip( + _service_container_publish_port_ports | map(attribute='host_port'), + _service_container_publish_port_ports | map(attribute='container_port') + ) | map('join', ':') + }}