From 77bd260f923d0e35df34e9f4edcdab531371bfa8 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 14:50:58 +0300 Subject: [PATCH 1/8] Fix kernel_blacklist crashes --- plugins/modules/kernel_blacklist.py | 30 ++++++++----- .../targets/kernel_blacklist/tasks/main.yml | 42 +++++++++++++++++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/plugins/modules/kernel_blacklist.py b/plugins/modules/kernel_blacklist.py index e1cf3fddb5..6a62a0fa57 100644 --- a/plugins/modules/kernel_blacklist.py +++ b/plugins/modules/kernel_blacklist.py @@ -69,15 +69,20 @@ class Blacklist(StateModuleHelper): def __init_module__(self): self.pattern = re.compile(r'^blacklist\s+{0}$'.format(re.escape(self.vars.name))) self.vars.filename = self.vars.blacklist_file - self.vars.set('file_exists', os.path.exists(self.vars.filename), output=False, change=True) - if not self.vars.file_exists: - with open(self.vars.filename, 'a'): - pass - self.vars.file_exists = True - self.vars.set('lines', [], change=True, diff=True) - else: - with open(self.vars.filename) as fd: - self.vars.set('lines', [x.rstrip() for x in fd.readlines()], change=True, diff=True) + + try: + if not os.path.exists(self.vars.filename): + os.makedirs(os.path.dirname(self.vars.filename), exist_ok=True) + with open(self.vars.filename, 'a'): + pass + self.vars.set('lines', [], change=True, diff=True) + else: + with open(self.vars.filename) as fd: + self.vars.set('lines', [x.rstrip() for x in fd.readlines()], change=True, diff=True) + except (OSError, IOError) as e: + self.module.fail_json(msg=f"Error accessing or creating blacklist file '{self.vars.filename}': {e}") + + self.vars.set('file_exists', True, output=False, change=True) self.vars.set('is_blacklisted', self._is_module_blocked(), change=True) def _is_module_blocked(self): @@ -104,8 +109,11 @@ class Blacklist(StateModuleHelper): def __quit_module__(self): if self.has_changed() and not self.module.check_mode: bkp = self.module.backup_local(self.vars.filename) - with open(self.vars.filename, "w") as fd: - fd.writelines(["{0}\n".format(x) for x in self.vars.lines]) + try: + with open(self.vars.filename, "w") as fd: + fd.writelines(f"{x}\n" for x in self.vars.lines) + except (OSError, IOError) as e: + self.module.fail_json(msg=f"Failed to write to blacklist file '{self.vars.filename}': {e}") self.module.add_cleanup_file(bkp) diff --git a/tests/integration/targets/kernel_blacklist/tasks/main.yml b/tests/integration/targets/kernel_blacklist/tasks/main.yml index aecc9b68d5..63b1e40f3b 100644 --- a/tests/integration/targets/kernel_blacklist/tasks/main.yml +++ b/tests/integration/targets/kernel_blacklist/tasks/main.yml @@ -153,3 +153,45 @@ - cls_rsvp loop_control: loop_var: line_item + +- name: Create file owned by nobody + ansible.builtin.copy: + dest: /tmp/test-blacklist-perm.conf + content: "" + owner: nobody + mode: '0600' + become: true + +- name: Run kernel_blacklist with unreadable file + community.general.kernel_blacklist: + name: lp + state: present + blacklist_file: /tmp/test-blacklist-perm.conf + ignore_errors: true + register: result_perm + +- name: Assert module fails gracefully with permission error + ansible.builtin.assert: + that: + - result_perm.failed + - "result_perm.msg is match(\"Failed to write to blacklist file '/tmp/test-blacklist-perm.conf': \\\\[Errno 13\\\\] Permission denied: '.*'\")" + + +- name: Ensure non-existing path + ansible.builtin.file: + path: /tmp/nonexistent-dir + state: absent + +- name: Run kernel_blacklist with nonexistent path + community.general.kernel_blacklist: + name: lp + state: present + blacklist_file: /tmp/nonexistent-dir/blacklist.conf + ignore_errors: true + register: result_missing + +- name: Assert module fails gracefully with file not found error + ansible.builtin.assert: + that: + - result_missing.failed + - "result_missing.msg is match(\"Error accessing or creating blacklist file '/tmp/nonexistent-dir/blacklist.conf': \\\\[Errno 2\\\\] No such file or directory: '.*'\")" From b3ea9f091ac45c5aaffbbceff57625e1dcf0a08b Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 15:06:36 +0300 Subject: [PATCH 2/8] Do not create directory --- plugins/modules/kernel_blacklist.py | 9 ++++++--- .../integration/targets/kernel_blacklist/tasks/main.yml | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/modules/kernel_blacklist.py b/plugins/modules/kernel_blacklist.py index 6a62a0fa57..2b18fa1892 100644 --- a/plugins/modules/kernel_blacklist.py +++ b/plugins/modules/kernel_blacklist.py @@ -69,12 +69,15 @@ class Blacklist(StateModuleHelper): def __init_module__(self): self.pattern = re.compile(r'^blacklist\s+{0}$'.format(re.escape(self.vars.name))) self.vars.filename = self.vars.blacklist_file - try: - if not os.path.exists(self.vars.filename): - os.makedirs(os.path.dirname(self.vars.filename), exist_ok=True) + dirpath = os.path.dirname(self.vars.filename) + if not os.path.isdir(dirpath): + self.module.fail_json(msg=f"The directory '{dirpath}' does not exist.") + self.vars.set('file_exists', os.path.exists(self.vars.filename), output=False, change=True) + if not self.vars.file_exists: with open(self.vars.filename, 'a'): pass + self.vars.file_exists = True self.vars.set('lines', [], change=True, diff=True) else: with open(self.vars.filename) as fd: diff --git a/tests/integration/targets/kernel_blacklist/tasks/main.yml b/tests/integration/targets/kernel_blacklist/tasks/main.yml index 63b1e40f3b..1d8c7dc20b 100644 --- a/tests/integration/targets/kernel_blacklist/tasks/main.yml +++ b/tests/integration/targets/kernel_blacklist/tasks/main.yml @@ -190,8 +190,8 @@ ignore_errors: true register: result_missing -- name: Assert module fails gracefully with file not found error +- name: Assert module fails gracefully with missing directory error ansible.builtin.assert: that: - result_missing.failed - - "result_missing.msg is match(\"Error accessing or creating blacklist file '/tmp/nonexistent-dir/blacklist.conf': \\\\[Errno 2\\\\] No such file or directory: '.*'\")" + - result_missing.msg == "The directory '/tmp/nonexistent-dir' does not exist." From 8372e4f00d10cf949f31eeb38e2f641ebd2cb575 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 15:11:04 +0300 Subject: [PATCH 3/8] Add changelog --- ...0484-kernel_blacklist-handle-file-exceptions-gracefully.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml diff --git a/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml b/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml new file mode 100644 index 0000000000..62e03a2174 --- /dev/null +++ b/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml @@ -0,0 +1,3 @@ +bugfixes: + - kernel_blacklist - Handle file exceptions gracefully + (https://github.com/ansible-collections/community.general/issues/10482, https://github.com/ansible-collections/community.general/pull/10484). \ No newline at end of file From 930e9c8575b368816797f10632bdbad78c587628 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 15:18:12 +0300 Subject: [PATCH 4/8] Make code compatible with python 2.7 --- plugins/modules/kernel_blacklist.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/modules/kernel_blacklist.py b/plugins/modules/kernel_blacklist.py index 2b18fa1892..71b4481b3d 100644 --- a/plugins/modules/kernel_blacklist.py +++ b/plugins/modules/kernel_blacklist.py @@ -72,7 +72,7 @@ class Blacklist(StateModuleHelper): try: dirpath = os.path.dirname(self.vars.filename) if not os.path.isdir(dirpath): - self.module.fail_json(msg=f"The directory '{dirpath}' does not exist.") + self.module.fail_json(msg="The directory '{}' does not exist.".format(dirpath)) self.vars.set('file_exists', os.path.exists(self.vars.filename), output=False, change=True) if not self.vars.file_exists: with open(self.vars.filename, 'a'): @@ -83,7 +83,7 @@ class Blacklist(StateModuleHelper): with open(self.vars.filename) as fd: self.vars.set('lines', [x.rstrip() for x in fd.readlines()], change=True, diff=True) except (OSError, IOError) as e: - self.module.fail_json(msg=f"Error accessing or creating blacklist file '{self.vars.filename}': {e}") + self.module.fail_json(msg="Error accessing or creating blacklist file '{}': {}".format(self.vars.filename, e)) self.vars.set('file_exists', True, output=False, change=True) self.vars.set('is_blacklisted', self._is_module_blocked(), change=True) @@ -114,9 +114,9 @@ class Blacklist(StateModuleHelper): bkp = self.module.backup_local(self.vars.filename) try: with open(self.vars.filename, "w") as fd: - fd.writelines(f"{x}\n" for x in self.vars.lines) + fd.writelines(["{0}\n".format(x) for x in self.vars.lines]) except (OSError, IOError) as e: - self.module.fail_json(msg=f"Failed to write to blacklist file '{self.vars.filename}': {e}") + self.module.fail_json(msg="Failed to write to blacklist file '{}': {}".format(self.vars.filename, e)) self.module.add_cleanup_file(bkp) From 85d6f5a812309439023d84069ad597f150655383 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos <56369797+gdrosos@users.noreply.github.com> Date: Sun, 27 Jul 2025 17:12:02 +0300 Subject: [PATCH 5/8] Update 10484-kernel_blacklist-handle-file-exceptions-gracefully.yml Co-authored-by: Felix Fontein --- ...10484-kernel_blacklist-handle-file-exceptions-gracefully.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml b/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml index 62e03a2174..1562d2671d 100644 --- a/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml +++ b/changelogs/fragments/10484-kernel_blacklist-handle-file-exceptions-gracefully.yml @@ -1,3 +1,3 @@ bugfixes: - - kernel_blacklist - Handle file exceptions gracefully + - kernel_blacklist - handle file exceptions gracefully (https://github.com/ansible-collections/community.general/issues/10482, https://github.com/ansible-collections/community.general/pull/10484). \ No newline at end of file From f15752e5edad21823c98efb7623c6f39527d5065 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos <56369797+gdrosos@users.noreply.github.com> Date: Sun, 27 Jul 2025 18:49:41 +0300 Subject: [PATCH 6/8] Update plugins/modules/kernel_blacklist.py Co-authored-by: Felix Fontein --- plugins/modules/kernel_blacklist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/kernel_blacklist.py b/plugins/modules/kernel_blacklist.py index 71b4481b3d..2db298b92e 100644 --- a/plugins/modules/kernel_blacklist.py +++ b/plugins/modules/kernel_blacklist.py @@ -83,7 +83,7 @@ class Blacklist(StateModuleHelper): with open(self.vars.filename) as fd: self.vars.set('lines', [x.rstrip() for x in fd.readlines()], change=True, diff=True) except (OSError, IOError) as e: - self.module.fail_json(msg="Error accessing or creating blacklist file '{}': {}".format(self.vars.filename, e)) + self.module.fail_json(msg="Error accessing or creating blacklist file {!r}: {}".format(self.vars.filename, e)) self.vars.set('file_exists', True, output=False, change=True) self.vars.set('is_blacklisted', self._is_module_blocked(), change=True) From c9d783bab4e1c6a8c34d5dd6c081a52540309783 Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 18:52:05 +0300 Subject: [PATCH 7/8] Ensure python does the string quoting on kernel_blacklist --- plugins/modules/kernel_blacklist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/kernel_blacklist.py b/plugins/modules/kernel_blacklist.py index 2db298b92e..504f831954 100644 --- a/plugins/modules/kernel_blacklist.py +++ b/plugins/modules/kernel_blacklist.py @@ -72,7 +72,7 @@ class Blacklist(StateModuleHelper): try: dirpath = os.path.dirname(self.vars.filename) if not os.path.isdir(dirpath): - self.module.fail_json(msg="The directory '{}' does not exist.".format(dirpath)) + self.module.fail_json(msg="The directory {!r} does not exist.".format(dirpath)) self.vars.set('file_exists', os.path.exists(self.vars.filename), output=False, change=True) if not self.vars.file_exists: with open(self.vars.filename, 'a'): @@ -116,7 +116,7 @@ class Blacklist(StateModuleHelper): with open(self.vars.filename, "w") as fd: fd.writelines(["{0}\n".format(x) for x in self.vars.lines]) except (OSError, IOError) as e: - self.module.fail_json(msg="Failed to write to blacklist file '{}': {}".format(self.vars.filename, e)) + self.module.fail_json(msg="Failed to write to blacklist file {!r}: {}".format(self.vars.filename, e)) self.module.add_cleanup_file(bkp) From 1548e339ebad3aa9f4aa270ecf4cf27733aace1e Mon Sep 17 00:00:00 2001 From: Giorgos Drosos Date: Sun, 27 Jul 2025 19:00:34 +0300 Subject: [PATCH 8/8] Fix failing test --- .../targets/kernel_blacklist/tasks/main.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/integration/targets/kernel_blacklist/tasks/main.yml b/tests/integration/targets/kernel_blacklist/tasks/main.yml index 1d8c7dc20b..7ef0617f50 100644 --- a/tests/integration/targets/kernel_blacklist/tasks/main.yml +++ b/tests/integration/targets/kernel_blacklist/tasks/main.yml @@ -154,13 +154,19 @@ loop_control: loop_var: line_item +- name: Resolve UID of nobody + ansible.builtin.command: id -u nobody + register: nobody_uid + ignore_errors: true + - name: Create file owned by nobody ansible.builtin.copy: dest: /tmp/test-blacklist-perm.conf content: "" - owner: nobody + owner: "{{ nobody_uid.stdout | int }}" mode: '0600' become: true + when: nobody_uid.rc == 0 - name: Run kernel_blacklist with unreadable file community.general.kernel_blacklist: @@ -169,13 +175,14 @@ blacklist_file: /tmp/test-blacklist-perm.conf ignore_errors: true register: result_perm + when: nobody_uid.rc == 0 - name: Assert module fails gracefully with permission error ansible.builtin.assert: that: - result_perm.failed - "result_perm.msg is match(\"Failed to write to blacklist file '/tmp/test-blacklist-perm.conf': \\\\[Errno 13\\\\] Permission denied: '.*'\")" - + when: nobody_uid.rc == 0 - name: Ensure non-existing path ansible.builtin.file: