diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index 5166e460..62ca183d 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -148,6 +148,7 @@ pull=dict(type='str', choices=['always', 'missing', 'never', 'newer']), quadlet_dir=dict(type='path'), quadlet_filename=dict(type='str'), + quadlet_file_mode=dict(type='raw'), quadlet_options=dict(type='list', elements='str'), rdt_class=dict(type='str'), read_only=dict(type='bool'), diff --git a/plugins/module_utils/podman/podman_pod_lib.py b/plugins/module_utils/podman/podman_pod_lib.py index 8f315a5c..17c42548 100644 --- a/plugins/module_utils/podman/podman_pod_lib.py +++ b/plugins/module_utils/podman/podman_pod_lib.py @@ -71,6 +71,7 @@ elements='str', aliases=['ports']), quadlet_dir=dict(type='path'), quadlet_filename=dict(type='str'), + quadlet_file_mode=dict(type='raw', required=False), quadlet_options=dict(type='list', elements='str'), restart_policy=dict(type='str', required=False), security_opt=dict(type='list', elements='str', required=False), diff --git a/plugins/module_utils/podman/quadlet.py b/plugins/module_utils/podman/quadlet.py index ec11a7e0..1ea4efa8 100644 --- a/plugins/module_utils/podman/quadlet.py +++ b/plugins/module_utils/podman/quadlet.py @@ -706,6 +706,11 @@ def create_quadlet_state(module, issuer): # Check if the directory exists and is writable if not module.check_mode: check_quadlet_directory(module, quadlet_dir) + # Specify file permissions + mode = module.params.get('quadlet_file_mode', None) + if mode is None and not os.path.exists(quadlet_file_path): + # default mode for new quadlet file only + mode = '0640' # Check if file already exists and if it's different quadlet = class_map[issuer](module.params) quadlet_content = quadlet.create_quadlet_content() @@ -713,6 +718,8 @@ def create_quadlet_state(module, issuer): if bool(file_diff): if not module.check_mode: quadlet.write_to_file(quadlet_file_path) + if mode is not None: + module.set_mode_if_different(quadlet_file_path, mode, False) results_update = { 'changed': True, "diff": { @@ -720,7 +727,15 @@ def create_quadlet_state(module, issuer): "after": "\n".join(file_diff[1]) if isinstance(file_diff[1], list) else file_diff[1] + "\n", }} else: - results_update = {} + # adjust file permissions + diff = {} + if mode is not None and module.set_mode_if_different(quadlet_file_path, mode, False, diff): + results_update = { + 'changed': True, + 'diff': diff + } + else: + results_update = {} return results_update # Check with following command: diff --git a/plugins/modules/podman_container.py b/plugins/modules/podman_container.py index 52c376f8..785fb2c0 100644 --- a/plugins/modules/podman_container.py +++ b/plugins/modules/podman_container.py @@ -876,6 +876,20 @@ description: - Name of quadlet file to write. By default it takes C(name) value. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default V('0640') mask will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual container args @@ -1214,6 +1228,7 @@ image: nginx state: quadlet quadlet_filename: custome-container + quadlet_file_mode: '0640' device: "/dev/sda:/dev/xvda:rwm" ports: - "8080:80" diff --git a/plugins/modules/podman_image.py b/plugins/modules/podman_image.py index 38e9b695..64824066 100644 --- a/plugins/modules/podman_image.py +++ b/plugins/modules/podman_image.py @@ -204,6 +204,20 @@ description: - Name of quadlet file to write. By default it takes image name without prefixes and tags. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default V('0640') mask will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual network args @@ -332,6 +346,7 @@ state: quadlet quadlet_dir: /etc/containers/systemd quadlet_filename: alpine-latest + quadlet_file_mode: '0640' quadlet_options: - Variant=arm/v7 - | @@ -961,6 +976,7 @@ def main(): ca_cert_dir=dict(type='path'), quadlet_dir=dict(type='path', required=False), quadlet_filename=dict(type='str'), + quadlet_file_mode=dict(type='raw', required=False), quadlet_options=dict(type='list', elements='str', required=False), build=dict( type='dict', diff --git a/plugins/modules/podman_network.py b/plugins/modules/podman_network.py index 4fb0b6de..c5853bd1 100644 --- a/plugins/modules/podman_network.py +++ b/plugins/modules/podman_network.py @@ -219,6 +219,20 @@ description: - Name of quadlet file to write. By default it takes I(name) value. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default V('0640') mask will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual network args @@ -859,6 +873,7 @@ def main(): route=dict(type='list', elements='str', required=False), quadlet_dir=dict(type='path', required=False), quadlet_filename=dict(type='str', required=False), + quadlet_file_mode=dict(type='raw', required=False), quadlet_options=dict(type='list', elements='str', required=False), net_config=dict(type='list', required=False, elements='dict', options=dict( diff --git a/plugins/modules/podman_play.py b/plugins/modules/podman_play.py index 66138efc..67c6838d 100644 --- a/plugins/modules/podman_play.py +++ b/plugins/modules/podman_play.py @@ -171,6 +171,20 @@ description: - Name of quadlet file to write. Must be specified if state is quadlet. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default V('0640') mask will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual network args @@ -208,6 +222,7 @@ greet_to: world userns: host quadlet_filename: kube-pod + quadlet_file_mode: '0640' quadlet_options: - "SetWorkingDirectory=yaml" - "ExitCodePropagation=any" @@ -413,6 +428,7 @@ def main(): choices=["debug", "info", "warn", "error", "fatal", "panic"]), quadlet_dir=dict(type='path', required=False), quadlet_filename=dict(type='str', required=False), + quadlet_file_mode=dict(type='raw', required=False), quadlet_options=dict(type='list', elements='str', required=False), ), supports_check_mode=True, diff --git a/plugins/modules/podman_pod.py b/plugins/modules/podman_pod.py index 8cc291e3..04fc81f9 100644 --- a/plugins/modules/podman_pod.py +++ b/plugins/modules/podman_pod.py @@ -371,6 +371,20 @@ description: - Name of quadlet file to write. By default it takes I(name) value. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default C(umask) on the system will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual container args diff --git a/plugins/modules/podman_volume.py b/plugins/modules/podman_volume.py index 5aa8695f..e808103e 100644 --- a/plugins/modules/podman_volume.py +++ b/plugins/modules/podman_volume.py @@ -76,6 +76,20 @@ description: - Name of quadlet file to write. By default it takes I(name) value. type: str + quadlet_file_mode: + description: + - The permissions of the quadlet file. + - The O(quadlet_file_mode) can be specied as octal numbers or as a symbolic mode (for example, V(u+rwx) or V(u=rw,g=r,o=r)). + For octal numbers format, you must either add a leading zero so that Ansible's YAML parser knows it is an + octal number (like V(0644) or V(01777)) or quote it (like V('644') or V('1777')) so Ansible receives a string + and can do its own conversion from string into number. Giving Ansible a number without following one of these + rules will end up with a decimal number which will have unexpected results. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does not) exist, the default V('0640') mask will be used + when setting the mode for the newly created file. + - If O(quadlet_file_mode) is not specified and the quadlet file B(does) exist, the mode of the existing file will be used. + - Specifying O(quadlet_file_mode) is the best way to ensure files are created with the correct permissions. + type: raw + required: false quadlet_options: description: - Options for the quadlet file. Provide missing in usual network args @@ -127,6 +141,7 @@ state: quadlet name: quadlet_volume quadlet_filename: custom-name + quadlet_file_mode: '0640' quadlet_options: - Group=192 - Copy=true @@ -569,6 +584,7 @@ def main(): debug=dict(type='bool', default=False), quadlet_dir=dict(type='path', required=False), quadlet_filename=dict(type='str', required=False), + quadlet_file_mode=dict(type='raw', required=False), quadlet_options=dict(type='list', elements='str', required=False), )) diff --git a/tests/integration/targets/podman_container/tasks/main.yml b/tests/integration/targets/podman_container/tasks/main.yml index 3f939121..26eca770 100644 --- a/tests/integration/targets/podman_container/tasks/main.yml +++ b/tests/integration/targets/podman_container/tasks/main.yml @@ -1191,6 +1191,69 @@ that: - quadlet_file_custom3.stat.exists + - name: Fail if wrong default file mode + assert: + that: + - quadlet_file_custom3.stat.mode == '0640' + + - name: Create a Quadlet for container with file mode + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container-quadlet-mode + image: alpine + state: quadlet + quadlet_file_mode: '0644' + + - name: Check file mode + stat: + path: ~/.config/containers/systemd/container-quadlet-mode.container + register: quadlet_file_mode1 + + - name: Fail if file is present and with correct mode + assert: + that: + - quadlet_file_mode1.stat.exists + - quadlet_file_mode1.stat.mode == '0644' + + - name: Create same Quadlet for container without file mode + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container-quadlet-mode + image: alpine + state: quadlet + register: quad_mode2 + + - name: Check file mode + stat: + path: ~/.config/containers/systemd/container-quadlet-mode.container + register: quadlet_file_mode2 + + - name: Check if existing mode is preserve + assert: + that: + - quad_mode2 is not changed + - quadlet_file_mode2.stat.mode == '0644' + + - name: Create same Quadlet for container with only file mode changed + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container-quadlet-mode + image: alpine + state: quadlet + quadlet_file_mode: '0640' + register: quad_mode3 + + - name: Check file mode + stat: + path: ~/.config/containers/systemd/container-quadlet-mode.container + register: quadlet_file_mode3 + + - name: Fail if file is present and with correct mode + assert: + that: + - quad_mode3 is changed + - quadlet_file_mode3.stat.mode == '0640' + - name: Create a Quadlet for container containers.podman.podman_container: executable: "{{ test_executable | default('podman') }}" diff --git a/tests/integration/targets/podman_image/tasks/main.yml b/tests/integration/targets/podman_image/tasks/main.yml index b5a3ca56..261202c9 100644 --- a/tests/integration/targets/podman_image/tasks/main.yml +++ b/tests/integration/targets/podman_image/tasks/main.yml @@ -460,10 +460,11 @@ path: /tmp/customfile.image register: quadlet_file_custom - - name: Fail if no file is present + - name: Fail if no file is present or wrong mode assert: that: - quadlet_file_custom.stat.exists + - quadlet_file_custom.stat.mode == '0640' - name: Create quadlet image file containers.podman.podman_image: @@ -476,6 +477,7 @@ password: pass validate_certs: false quadlet_dir: /tmp/ + quadlet_file_mode: '0644' quadlet_options: - "ImageTag=quay.io/coreos/coreos-installer:12345" - "AllTags=true" @@ -493,6 +495,11 @@ that: - quadlet_file.stat.exists + - name: Check quadlet file mode is correct + assert: + that: + - quadlet_file.stat.mode == '0644' + - name: Check for the existence of lines in /tmp/coreos-installer.image lineinfile: path: /tmp/coreos-installer.image diff --git a/tests/integration/targets/podman_network/tasks/main.yml b/tests/integration/targets/podman_network/tasks/main.yml index 4bfb4b0c..f31ba4c5 100644 --- a/tests/integration/targets/podman_network/tasks/main.yml +++ b/tests/integration/targets/podman_network/tasks/main.yml @@ -709,16 +709,18 @@ state: quadlet quadlet_dir: /tmp quadlet_filename: customfile + quadlet_file_mode: '0644' - name: Check if files exists stat: path: /tmp/customfile.network register: quadlet_file_custom - - name: Fail if no file is present + - name: Fail if no file is present or wrong mode assert: that: - quadlet_file_custom.stat.exists + - quadlet_file_custom.stat.mode == '0644' - name: Create quadlet network file containers.podman.podman_network: diff --git a/tests/integration/targets/podman_play/tasks/main.yml b/tests/integration/targets/podman_play/tasks/main.yml index d22615e4..16583e9b 100644 --- a/tests/integration/targets/podman_play/tasks/main.yml +++ b/tests/integration/targets/podman_play/tasks/main.yml @@ -138,16 +138,18 @@ state: quadlet quadlet_dir: /tmp quadlet_filename: customfile + quadlet_file_mode: '0644' - name: Check if files exists stat: path: /tmp/customfile.kube register: quadlet_file_custom - - name: Fail if no file is present + - name: Fail if no file is present or wrong mode assert: that: - quadlet_file_custom.stat.exists + - quadlet_file_custom.stat.mode == '0644' - name: Create a kube quadlet without filename containers.podman.podman_play: diff --git a/tests/integration/targets/podman_pod/tasks/main.yml b/tests/integration/targets/podman_pod/tasks/main.yml index c148f9a9..54a66b4d 100644 --- a/tests/integration/targets/podman_pod/tasks/main.yml +++ b/tests/integration/targets/podman_pod/tasks/main.yml @@ -989,16 +989,18 @@ network: examplenet quadlet_dir: /tmp quadlet_filename: customfile + quadlet_file_mode: '0644' - name: Check if files exists stat: path: /tmp/customfile.pod register: quadlet_file_custom - - name: Fail if no file is present + - name: Fail if no file is present or wrong mode assert: that: - quadlet_file_custom.stat.exists + - quadlet_file_custom.stat.mode == '0644' - name: Create a Quadlet pod file containers.podman.podman_pod: diff --git a/tests/integration/targets/podman_volume/tasks/main.yml b/tests/integration/targets/podman_volume/tasks/main.yml index 0b52fbfc..41759109 100644 --- a/tests/integration/targets/podman_volume/tasks/main.yml +++ b/tests/integration/targets/podman_volume/tasks/main.yml @@ -241,16 +241,18 @@ state: quadlet quadlet_dir: /tmp quadlet_filename: customfile + quadlet_file_mode: '0644' - name: Check if files exists stat: path: /tmp/customfile.volume register: quadlet_file_custom - - name: Fail if no file is present + - name: Fail if no file is present or wrong mode assert: that: - quadlet_file_custom.stat.exists + - quadlet_file_custom.stat.mode == '0644' - name: Create quadlet volume file containers.podman.podman_volume: