From b030d671b53b748d45c47772eacef53a2be6b14a Mon Sep 17 00:00:00 2001 From: uumas Date: Fri, 9 Jan 2026 17:24:01 +0200 Subject: [PATCH] service: Add support for mounting entire copied directory --- roles/service/meta/argument_specs.yaml | 9 +++-- .../tasks/{templates.yaml => hostmounts.yaml} | 9 +++++ roles/service/tasks/main.yaml | 4 +- roles/service/tasks/validation.yaml | 6 +++ roles/service/vars/main/additional.yaml | 19 ++++++++- roles/service/vars/main/mounts.yaml | 39 ++++++++++++++++++- 6 files changed, 79 insertions(+), 7 deletions(-) rename roles/service/tasks/{templates.yaml => hostmounts.yaml} (72%) diff --git a/roles/service/meta/argument_specs.yaml b/roles/service/meta/argument_specs.yaml index 2eb4b09..da2f16f 100644 --- a/roles/service/meta/argument_specs.yaml +++ b/roles/service/meta/argument_specs.yaml @@ -111,12 +111,14 @@ argument_specs: - volume - bind - template + - copy source: description: - Mount source. - If mount type is volume, name of the volume. - If mount type is bind, host path to bind mount inside the container. - If mount type is template, the name of the template file, must end in .j2 + - If mount type is copy, name of the file or directory to copy. Directory name must end in /. type: str required: true destination: @@ -126,7 +128,7 @@ argument_specs: readonly: description: - If true, volume will be mounted as read only inside the container. - - Defaults to false for volume and bind, true for template + - Defaults to false for volume and bind, true for template and copy type: bool required: false user: @@ -140,10 +142,11 @@ argument_specs: required: false default: "" mode: - description: Templated file permissions + description: + - Templated file or copied directory/file permissions. + - Defaults to 0644 for files, 0755 for directories type: str required: false - default: "0644" volume_device: description: >- The path of a device which is mounted for the volume. diff --git a/roles/service/tasks/templates.yaml b/roles/service/tasks/hostmounts.yaml similarity index 72% rename from roles/service/tasks/templates.yaml rename to roles/service/tasks/hostmounts.yaml index aa4736d..28d9bf8 100644 --- a/roles/service/tasks/templates.yaml +++ b/roles/service/tasks/hostmounts.yaml @@ -25,3 +25,12 @@ mode: "{{ item[0].mode | default('0644') }}" notify: Restart container service {{ service_name }} loop: "{{ _service_all_template_mounts | zip(_service_all_template_mount_host_files) }}" + +- name: Copy files for copy mounts + ansible.builtin.copy: + src: "{{ item[0].source }}" + dest: "{{ item[1] }}" + mode: "{{ item[0].mode | default('0644') }}" + directory_mode: "0755" + notify: Restart container service {{ service_name }} + loop: "{{ _service_all_copy_mounts | zip(_service_all_copy_mount_host_files) }}" diff --git a/roles/service/tasks/main.yaml b/roles/service/tasks/main.yaml index 0999827..77b1b38 100644 --- a/roles/service/tasks/main.yaml +++ b/roles/service/tasks/main.yaml @@ -15,8 +15,8 @@ when: _service_container_secrets | length > 0 - name: Template mounts for {{ service_name }} - ansible.builtin.include_tasks: templates.yaml - when: _service_template_mounts | length > 0 + ansible.builtin.include_tasks: hostmounts.yaml + when: (_service_template_mounts + _service_copy_mounts) | length > 0 - name: Additional containers for {{ service_name }} ansible.builtin.include_tasks: additional.yaml diff --git a/roles/service/tasks/validation.yaml b/roles/service/tasks/validation.yaml index 70a1ebc..5d35bcd 100644 --- a/roles/service/tasks/validation.yaml +++ b/roles/service/tasks/validation.yaml @@ -19,3 +19,9 @@ msg: "Template mount source file name needs to end in .j2. The file {{ item.source }} of {{ service_name }} doesn't." when: "item.source | split('.') | last != 'j2'" loop: "{{ _service_template_mounts }}" + +- name: Fail if copy mount source doesn't end with / + ansible.builtin.fail: + msg: "Copy mount source name must end with /. The file {{ item.source }} of {{ service_name }} doesn't" + when: "not item.source.endswith('/')" + loop: "{{ _service_copy_mounts }}" diff --git a/roles/service/vars/main/additional.yaml b/roles/service/vars/main/additional.yaml index 6b71806..bc03b32 100644 --- a/roles/service/vars/main/additional.yaml +++ b/roles/service/vars/main/additional.yaml @@ -21,6 +21,7 @@ _service_additional_container_ip: >- _service_additional_volume_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'volume') }}" _service_additional_template_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'template') }}" +_service_additional_copy_mounts: "{{ _service_additional_container.mounts | selectattr('type', '==', 'copy') }}" _service_additional_host_directory: "/srv/{{ service_name }}" _service_additional_container_volume_mounts: >- @@ -50,12 +51,28 @@ _service_additional_container_template_mounts: >- ) | map('combine') }} +_service_additional_container_copy_mounts: >- + {{ + ([{'readonly': true}] * _service_additional_copy_mounts | length) | + zip( + _service_additional_copy_mounts | + community.general.remove_keys(['mode']), + _service_additional_copy_mounts | + map(attribute='source') | + map('regex_replace', '\/$', '') | + map('regex_replace', '^', _service_host_directory ~ '/mounts/') | + map('community.general.dict_kv', 'source'), + ([{'type': 'bind'}] * _service_additional_copy_mounts | length) + ) | + map('combine') + }} _service_additional_container_mounts: >- {{ _service_additional_container_volume_mounts + _service_additional_container_bind_mounts + - _service_additional_container_template_mounts + _service_additional_container_template_mounts + + _service_additional_container_copy_mounts if _service_additional_container.mounts is defined else _service_container_mounts diff --git a/roles/service/vars/main/mounts.yaml b/roles/service/vars/main/mounts.yaml index 6bca609..d36de2a 100644 --- a/roles/service/vars/main/mounts.yaml +++ b/roles/service/vars/main/mounts.yaml @@ -1,6 +1,7 @@ --- _service_volume_mounts: "{{ service_container_mounts | selectattr('type', '==', 'volume') }}" _service_template_mounts: "{{ service_container_mounts | selectattr('type', '==', 'template') }}" +_service_copy_mounts: "{{ service_container_mounts | selectattr('type', '==', 'copy') }}" _service_host_directory: "/srv/{{ service_name }}" _service_container_volume_mounts: >- @@ -30,12 +31,28 @@ _service_container_template_mounts: >- ) | map('combine') }} +_service_container_copy_mounts: >- + {{ + ([{'readonly': true}] * _service_copy_mounts | length) | + zip( + _service_copy_mounts | + community.general.remove_keys(['mode']), + _service_copy_mounts | + map(attribute='source') | + map('regex_replace', '\/$', '') | + map('regex_replace', '^', _service_host_directory ~ '/mounts/') | + map('community.general.dict_kv', 'source'), + ([{'type': 'bind'}] * _service_copy_mounts | length) + ) | + map('combine') + }} _service_container_mounts: >- {{ _service_container_volume_mounts + _service_container_bind_mounts + - _service_container_template_mounts + _service_container_template_mounts + + _service_container_copy_mounts }} @@ -67,3 +84,23 @@ _service_all_template_mount_host_files: >- map('regex_replace', '\.j2$', '') | map('regex_replace', '^', _service_host_directory ~ '/mounts/') }} + +_service_all_copy_mounts: >- + {{ + ( + _service_copy_mounts + + ( + _service_additional_containers | + map(attribute='mounts', default=[]) | + flatten + ) + ) | + selectattr('type', '==', 'copy') | + unique + }} +_service_all_copy_mount_host_files: >- + {{ + _service_all_copy_mounts | + map(attribute='source') | + map('regex_replace', '^', _service_host_directory ~ '/mounts/') + }}