diff --git a/changelogs/fragments/124_acl.yml b/changelogs/fragments/124_acl.yml new file mode 100644 index 0000000..5eee72a --- /dev/null +++ b/changelogs/fragments/124_acl.yml @@ -0,0 +1,3 @@ +--- +minor_changes: +- acl - add new alias ``recurse`` for ``recursive`` parameter (https://github.com/ansible-collections/ansible.posix/issues/124). diff --git a/changelogs/fragments/175_synchronize.yml b/changelogs/fragments/175_synchronize.yml new file mode 100644 index 0000000..4d1a161 --- /dev/null +++ b/changelogs/fragments/175_synchronize.yml @@ -0,0 +1,3 @@ +--- +trivial: +- synchronize - fix typo in ``delete`` parameter (https://github.com/ansible-collections/ansible.posix/issues/175). diff --git a/changelogs/fragments/179_firewalld.yml b/changelogs/fragments/179_firewalld.yml new file mode 100644 index 0000000..782cebb --- /dev/null +++ b/changelogs/fragments/179_firewalld.yml @@ -0,0 +1,3 @@ +--- +bugfixes: +- firewalld - ensure idempotency with firewalld 0.9.3 (https://github.com/ansible-collections/ansible.posix/issues/179). diff --git a/changelogs/fragments/193_firewalld.yml b/changelogs/fragments/193_firewalld.yml new file mode 100644 index 0000000..088a268 --- /dev/null +++ b/changelogs/fragments/193_firewalld.yml @@ -0,0 +1,3 @@ +--- +trivial: +- firewalld - specify unit for ``timeout`` parameter in docs (https://github.com/ansible-collections/ansible.posix/issues/193). diff --git a/changelogs/fragments/196_boot_opt_for_linux.yml b/changelogs/fragments/196_boot_opt_for_linux.yml new file mode 100644 index 0000000..62afecf --- /dev/null +++ b/changelogs/fragments/196_boot_opt_for_linux.yml @@ -0,0 +1,4 @@ +--- +minor_changes: + - mount - Change behavior of ``boot`` option to set ``noauto`` on Linux nodes + (https://github.com/ansible-collections/ansible.posix/issues/28). diff --git a/changelogs/fragments/203_boot_opt_for_bsd.yml b/changelogs/fragments/203_boot_opt_for_bsd.yml new file mode 100644 index 0000000..0fdd50a --- /dev/null +++ b/changelogs/fragments/203_boot_opt_for_bsd.yml @@ -0,0 +1,4 @@ +--- +minor_changes: + - mount - Change behavior of ``boot`` option to set ``noauto`` on BSD nodes + (https://github.com/ansible-collections/ansible.posix/issues/28). diff --git a/changelogs/fragments/204_csh_shell.yml b/changelogs/fragments/204_csh_shell.yml new file mode 100644 index 0000000..6d157a8 --- /dev/null +++ b/changelogs/fragments/204_csh_shell.yml @@ -0,0 +1,3 @@ +--- +bugfixes: +- csh - define ``ECHO`` and ``COMMAND_SEP`` (https://github.com/ansible-collections/ansible.posix/issues/204). diff --git a/changelogs/fragments/207-mount_tests.yml b/changelogs/fragments/207-mount_tests.yml new file mode 100644 index 0000000..f5256d6 --- /dev/null +++ b/changelogs/fragments/207-mount_tests.yml @@ -0,0 +1,3 @@ +--- +trivial: + - Make the mount module integration tests more human readable. diff --git a/plugins/modules/acl.py b/plugins/modules/acl.py index c4a5542..a2e3d6d 100644 --- a/plugins/modules/acl.py +++ b/plugins/modules/acl.py @@ -67,8 +67,10 @@ options: description: - Recursively sets the specified ACL. - Incompatible with C(state=query). + - Alias C(recurse) added in version 1.3.0. type: bool default: no + aliases: [ recurse ] use_nfsv4_acls: description: - Use NFSv4 ACLs instead of POSIX ACLs. @@ -273,7 +275,7 @@ def main(): ), follow=dict(type='bool', default=True), default=dict(type='bool', default=False), - recursive=dict(type='bool', default=False), + recursive=dict(type='bool', default=False, aliases=['recurse']), recalculate_mask=dict( type='str', default='default', diff --git a/plugins/modules/firewalld.py b/plugins/modules/firewalld.py index c87dd36..30acedf 100644 --- a/plugins/modules/firewalld.py +++ b/plugins/modules/firewalld.py @@ -99,7 +99,7 @@ options: choices: [ absent, disabled, enabled, present ] timeout: description: - - The amount of time the rule should be in effect for when non-permanent. + - The amount of time in seconds the rule should be in effect for when non-permanent. type: int default: 0 masquerade: @@ -393,26 +393,14 @@ class PortTransaction(FirewallTransaction): ) def get_enabled_immediate(self, port, protocol, timeout): - port_proto = [port, protocol] if self.fw_offline: - fw_zone, fw_settings = self.get_fw_zone_settings() - ports_list = fw_settings.getPorts() - else: - ports_list = self.fw.getPorts(self.zone) - - if port_proto in ports_list: - return True - else: - return False + dummy, fw_settings = self.get_fw_zone_settings() + return fw_settings.queryPort(port=port, protocol=protocol) + return self.fw.queryPort(zone=self.zone, port=port, protocol=protocol) def get_enabled_permanent(self, port, protocol, timeout): - port_proto = (port, protocol) - fw_zone, fw_settings = self.get_fw_zone_settings() - - if port_proto in fw_settings.getPorts(): - return True - else: - return False + dummy, fw_settings = self.get_fw_zone_settings() + return fw_settings.queryPort(port=port, protocol=protocol) def set_enabled_immediate(self, port, protocol, timeout): self.fw.addPort(self.zone, port, protocol, timeout) @@ -715,26 +703,14 @@ class ForwardPortTransaction(FirewallTransaction): ) def get_enabled_immediate(self, port, proto, toport, toaddr, timeout): - forward_port = [port, proto, toport, toaddr] if self.fw_offline: - fw_zone, fw_settings = self.get_fw_zone_settings() - forward_list = fw_settings.getForwardPorts() - else: - forward_list = self.fw.getForwardPorts(self.zone) - - if forward_port in forward_list: - return True - else: - return False + dummy, fw_settings = self.get_fw_zone_settings() + return fw_settings.queryForwardPort(port=port, protocol=proto, to_port=toport, to_addr=toaddr) + return self.fw.queryForwardPort(port=port, protocol=proto, to_port=toport, to_addr=toaddr) def get_enabled_permanent(self, port, proto, toport, toaddr, timeout): - forward_port = (port, proto, toport, toaddr) - fw_zone, fw_settings = self.get_fw_zone_settings() - - if forward_port in fw_settings.getForwardPorts(): - return True - else: - return False + dummy, fw_settings = self.get_fw_zone_settings() + return fw_settings.queryForwardPort(port=port, protocol=proto, to_port=toport, to_addr=toaddr) def set_enabled_immediate(self, port, proto, toport, toaddr, timeout): self.fw.addForwardPort(self.zone, port, proto, toport, toaddr, timeout) diff --git a/plugins/modules/mount.py b/plugins/modules/mount.py index e077ccf..ae2ac27 100644 --- a/plugins/modules/mount.py +++ b/plugins/modules/mount.py @@ -93,7 +93,13 @@ options: boot: description: - Determines if the filesystem should be mounted on boot. - - Only applies to Solaris systems. + - Only applies to Solaris and Linux systems. + - For Solaris systems, C(true) will set C(yes) as the value of mount at boot + in I(/etc/vfstab). + - For Linux, FreeBSD, NetBSD and OpenBSD systems, C(false) will add C(noauto) + to mount options in I(/etc/fstab). + - To avoid mount option conflicts, if C(noauto) specified in C(opts), + mount module will ignore C(boot). type: bool default: yes backup: @@ -169,6 +175,15 @@ EXAMPLES = r''' opts: rw,sync,hard,intr state: mounted fstype: nfs + +- name: Mount NFS volumes with noauto according to boot option + ansible.posix.mount: + src: 192.168.1.100:/nfs/ssd/shared_data + path: /mnt/shared_data + opts: rw,sync,hard,intr + boot: no + state: mounted + fstype: nfs ''' import errno @@ -231,7 +246,7 @@ def _set_mount_save_old(module, args): old_lines = [] exists = False changed = False - escaped_args = dict([(k, _escape_fstab(v)) for k, v in iteritems(args)]) + escaped_args = dict([(k, _escape_fstab(v)) for k, v in iteritems(args) if k != 'warnings']) new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n' if platform.system() == 'SunOS': @@ -677,7 +692,8 @@ def main(): opts='-', passno='-', fstab=module.params['fstab'], - boot='yes' if module.params['boot'] else 'no' + boot='yes' if module.params['boot'] else 'no', + warnings=[] ) if args['fstab'] is None: args['fstab'] = '/etc/vfstab' @@ -687,7 +703,9 @@ def main(): opts='defaults', dump='0', passno='0', - fstab=module.params['fstab'] + fstab=module.params['fstab'], + boot='yes', + warnings=[] ) if args['fstab'] is None: args['fstab'] = '/etc/fstab' @@ -705,14 +723,27 @@ def main(): linux_mounts = get_linux_mounts(module) if linux_mounts is None: - args['warnings'] = ( - 'Cannot open file /proc/self/mountinfo. ' - 'Bind mounts might be misinterpreted.') + args['warnings'].append('Cannot open file /proc/self/mountinfo.' + ' Bind mounts might be misinterpreted.') # Override defaults with user specified params for key in ('src', 'fstype', 'passno', 'opts', 'dump', 'fstab'): if module.params[key] is not None: args[key] = module.params[key] + if platform.system().lower() == 'linux' or platform.system().lower().endswith('bsd'): + # Linux, FreeBSD, NetBSD and OpenBSD have 'noauto' as mount option to + # handle mount on boot. To avoid mount option conflicts, if 'noauto' + # specified in 'opts', mount module will ignore 'boot'. + opts = args['opts'].split(',') + if 'noauto' in opts: + args['warnings'].append("Ignore the 'boot' due to 'opts' contains 'noauto'.") + elif not module.params['boot']: + args['boot'] = 'no' + if 'defaults' in opts: + args['warnings'].append("Ignore the 'boot' due to 'opts' contains 'defaults'.") + else: + opts.append('noauto') + args['opts'] = ','.join(opts) # If fstab file does not exist, we first need to create it. This mainly # happens when fstab option is passed to the module. diff --git a/plugins/modules/synchronize.py b/plugins/modules/synchronize.py index dafaf78..2676275 100644 --- a/plugins/modules/synchronize.py +++ b/plugins/modules/synchronize.py @@ -73,9 +73,9 @@ options: default: no delete: description: - - Delete files in C(dest) that don't exist (after transfer, not before) in the C(src) path. - - This option requires C(recursive=yes). - - This option ignores excluded files and behaves like the rsync opt --delete-excluded. + - Delete files in I(dest) that do not exist (after transfer, not before) in the I(src) path. + - This option requires I(recursive=yes). + - This option ignores excluded files and behaves like the rsync opt C(--delete-after). type: bool default: no dirs: diff --git a/plugins/shell/csh.py b/plugins/shell/csh.py index 18dee95..bce5734 100644 --- a/plugins/shell/csh.py +++ b/plugins/shell/csh.py @@ -26,6 +26,10 @@ class ShellModule(ShellBase): # Family of shells this has. Must match the filename without extension SHELL_FAMILY = 'csh' + # commonly used + ECHO = 'echo' + COMMAND_SEP = ';' + # How to end lines in a python script one-liner _SHELL_EMBEDDED_PY_EOL = '\\\n' _SHELL_REDIRECT_ALLNULL = '>& /dev/null' diff --git a/tests/integration/targets/firewalld/tasks/main.yml b/tests/integration/targets/firewalld/tasks/main.yml index 84af185..4e83ee8 100644 --- a/tests/integration/targets/firewalld/tasks/main.yml +++ b/tests/integration/targets/firewalld/tasks/main.yml @@ -1,20 +1,6 @@ # Test playbook for the firewalld module # (c) 2017, Adam Miller - -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - name: Run firewalld tests block: diff --git a/tests/integration/targets/firewalld/tasks/port_forward_test_cases.yml b/tests/integration/targets/firewalld/tasks/port_forward_test_cases.yml index c2a982d..78a451d 100644 --- a/tests/integration/targets/firewalld/tasks/port_forward_test_cases.yml +++ b/tests/integration/targets/firewalld/tasks/port_forward_test_cases.yml @@ -1,20 +1,6 @@ # Test playbook for the firewalld module - port operations # (c) 2017, Adam Miller - -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - name: firewalld port forward test permanent enabled firewalld: diff --git a/tests/integration/targets/firewalld/tasks/port_test_cases.yml b/tests/integration/targets/firewalld/tasks/port_test_cases.yml index 5891e75..2beb8ca 100644 --- a/tests/integration/targets/firewalld/tasks/port_test_cases.yml +++ b/tests/integration/targets/firewalld/tasks/port_test_cases.yml @@ -1,20 +1,63 @@ # Test playbook for the firewalld module - port operations # (c) 2017, Adam Miller +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +- name: firewalld port range test permanent enabled + firewalld: + port: 5500-6950/tcp + permanent: true + state: enabled + register: result + +- name: assert firewalld port range test permanent enabled worked + assert: + that: + - result is changed + +- name: firewalld port range test permanent enabled rerun (verify not changed) + firewalld: + port: 5500-6950/tcp + permanent: true + state: enabled + register: result + +- name: assert firewalld port range test permanent enabled rerun worked (verify not changed) + assert: + that: + - result is not changed + +- name: firewalld port test permanent enabled + firewalld: + port: 6900/tcp + permanent: true + state: enabled + register: result + +- name: assert firewalld port test permanent enabled worked + assert: + that: + - result is changed + +- name: firewalld port test permanent enabled + firewalld: + port: 6900/tcp + permanent: true + state: enabled + register: result + +- name: assert firewalld port test permanent enabled worked + assert: + that: + - result is not changed + +- name: firewalld port test disabled + firewalld: + port: "{{ item }}" + permanent: true + state: disabled + loop: + - 6900/tcp + - 5500-6950/tcp - name: firewalld port test permanent enabled firewalld: diff --git a/tests/integration/targets/firewalld/tasks/run_all_tests.yml b/tests/integration/targets/firewalld/tasks/run_all_tests.yml index 79c0ca7..f46deb6 100644 --- a/tests/integration/targets/firewalld/tasks/run_all_tests.yml +++ b/tests/integration/targets/firewalld/tasks/run_all_tests.yml @@ -1,20 +1,6 @@ # Test playbook for the firewalld module # (c) 2017, Adam Miller - -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - name: Ensure /run/firewalld exists file: @@ -28,8 +14,6 @@ # firewalld port operation test cases - include_tasks: port_test_cases.yml - # Skipping on CentOS 8 due to https://github.com/ansible/ansible/issues/64750 - when: not (ansible_facts.distribution == "CentOS" and ansible_distribution_major_version is version('8', '==')) # firewalld source operation test cases - import_tasks: source_test_cases.yml diff --git a/tests/integration/targets/mount/tasks/main.yml b/tests/integration/targets/mount/tasks/main.yml index 56036b8..3747c85 100644 --- a/tests/integration/targets/mount/tasks/main.yml +++ b/tests/integration/targets/mount/tasks/main.yml @@ -2,10 +2,12 @@ file: state: directory path: '{{ output_dir }}/mount_dest' + - name: Create a directory to bind mount file: state: directory path: '{{ output_dir }}/mount_source' + - name: Put something in the directory so we see that it worked copy: content: 'Testing @@ -13,6 +15,7 @@ ' dest: '{{ output_dir }}/mount_source/test_file' register: orig_info + - name: Bind mount a filesystem (Linux) mount: src: '{{ output_dir }}/mount_source' @@ -22,6 +25,7 @@ opts: bind when: ansible_system == 'Linux' register: bind_result_linux + - name: Bind mount a filesystem (FreeBSD) mount: src: '{{ output_dir }}/mount_source' @@ -30,11 +34,13 @@ fstype: nullfs when: ansible_system == 'FreeBSD' register: bind_result_freebsd + - name: get checksum for bind mounted file stat: path: '{{ output_dir }}/mount_dest/test_file' when: ansible_system in ('FreeBSD', 'Linux') register: dest_stat + - name: assert the bind mount was successful assert: that: @@ -42,6 +48,7 @@ - dest_stat['stat']['exists'] - orig_info['checksum'] == dest_stat['stat']['checksum'] when: ansible_system in ('FreeBSD', 'Linux') + - name: Bind mount a filesystem (Linux) mount: src: '{{ output_dir }}/mount_source' @@ -51,6 +58,7 @@ opts: bind when: ansible_system == 'Linux' register: bind_result_linux + - name: Bind mount a filesystem (FreeBSD) mount: src: '{{ output_dir }}/mount_source' @@ -59,11 +67,13 @@ fstype: nullfs when: ansible_system == 'FreeBSD' register: bind_result_freebsd + - name: Make sure we didn't mount a second time assert: that: - (ansible_system == 'Linux' and not bind_result_linux['changed']) or (ansible_system == 'FreeBSD' and not bind_result_freebsd['changed']) when: ansible_system in ('FreeBSD', 'Linux') + - name: Remount filesystem with different opts (Linux) mount: src: '{{ output_dir }}/mount_source' @@ -73,6 +83,7 @@ opts: bind,ro when: ansible_system == 'Linux' register: bind_result_linux + - name: Remount filesystem with different opts (FreeBSD) mount: src: '{{ output_dir }}/mount_source' @@ -82,9 +93,11 @@ opts: ro when: ansible_system == 'FreeBSD' register: bind_result_freebsd + - name: Get mount options shell: mount | grep mount_dest | grep -E -w '(ro|read-only)' | wc -l register: remount_options + - name: Make sure the filesystem now has the new opts assert: that: @@ -92,17 +105,20 @@ - '''1'' in remount_options.stdout' - 1 == remount_options.stdout_lines | length when: ansible_system in ('FreeBSD', 'Linux') + - name: Unmount the bind mount mount: name: '{{ output_dir }}/mount_dest' state: absent when: ansible_system in ('Linux', 'FreeBSD') register: unmount_result + - name: Make sure the file no longer exists in dest stat: path: '{{ output_dir }}/mount_dest/test_file' when: ansible_system in ('FreeBSD', 'Linux') register: dest_stat + - name: Check that we unmounted assert: that: @@ -216,6 +232,7 @@ community.general.system.filesystem: fstype: ext3 dev: /tmp/myfs.img + - name: Mount the FS for the first time mount: path: /tmp/myfs @@ -271,6 +288,47 @@ src: /tmp/myfs.img opts: loop state: absent + - name: Remove the test FS + file: + path: '{{ item }}' + state: absent + loop: + - /tmp/myfs.img + - /tmp/myfs + when: ansible_system in ('Linux') + +- name: Block to test boot option for Linux + block: + - name: Create empty file + community.general.filesize: + path: /tmp/myfs.img + size: 20M + + - name: Format FS + community.general.filesystem: + fstype: ext3 + dev: /tmp/myfs.img + + - name: Mount the FS with noauto option + mount: + path: /tmp/myfs + src: /tmp/myfs.img + fstype: ext3 + state: mounted + boot: no + opts: rw,user,async + register: mount_info + + - name: assert the mount without noauto was successful + assert: + that: + - mount_info['opts'] == 'rw,user,async,noauto' + + - name: Unmount FS + mount: + path: /tmp/myfs + state: absent + - name: Remove the test FS file: path: '{{ item }}'