Backport #42013 for 2.6 - linenfile empty regexp warning (#42204)

* Add warning when using an empty regexp in lineinfile (#42013)

* Revert "Account for empty string regexp in lineinfile (#41451)"

This reverts commit 4b5b4a760c.

* Use context managers for interacting with files

* Store line and regexp parameters in a variable

* Add warning when regexp is an empty string

* Remove '=' from error messages

* Update warning message and add changelog

* Add tests

* Improve warning message

Offer an equivalent regexp that won't trigger the warning.
Update tests to match new warning.

* Add porting guide entry for lineinfile change

# Conflicts:
#	docs/docsite/rst/porting_guides/porting_guide_2.7.rst
#	lib/ansible/modules/files/lineinfile.py
#	test/integration/targets/lineinfile/tasks/main.yml

* Add porting guide info
This commit is contained in:
Sam Doran 2018-07-09 14:26:45 -04:00 committed by Matt Clay
parent 1d759ffa2f
commit 3bec68a3b3
4 changed files with 63 additions and 8 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- lineinfile - add warning when using an empty regexp (https://github.com/ansible/ansible/issues/29443)

View file

@ -73,6 +73,11 @@ Noteworthy module changes
* The ``k8s`` module will not automatically change ``Project`` creation requests into ``ProjectRequest`` creation requests as the ``openshift_raw`` module did. You must now specify the ``ProjectRequest`` kind explicitly.
* The ``k8s`` module will not automatically remove secrets from the Ansible return values (and by extension the log). In order to prevent secret values in a task from being logged, specify the ``no_log`` parameter on the task block.
* The ``k8s_scale`` module now supports scalable OpenShift objects, such as ``DeploymentConfig``.
* The ``lineinfile`` module was changed to show a warning when using an empty string as a regexp.
Since an empty regexp matches every line in a file, it will replace the last line in a file rather
than inserting. If this is the desired behavior, use ``'^'`` which will match every line and
will not trigger the warning.
Plugins

View file

@ -479,17 +479,25 @@ def main():
backrefs = params['backrefs']
path = params['path']
firstmatch = params['firstmatch']
regexp = params['regexp']
line = params['line']
if regexp == '':
module.warn(
"The regular expression is an empty string, which will match every line in the file. "
"This may have unintended consequences, such as replacing the last line in the file rather than appending. "
"If this is desired, use '^' to match every line in the file and avoid this warning.")
b_path = to_bytes(path, errors='surrogate_or_strict')
if os.path.isdir(b_path):
module.fail_json(rc=256, msg='Path %s is a directory !' % path)
if params['state'] == 'present':
if backrefs and params['regexp'] is None:
module.fail_json(msg='regexp= is required with backrefs=true')
if backrefs and regexp is None:
module.fail_json(msg='regexp is required with backrefs=true')
if params.get('line', None) is None:
module.fail_json(msg='line= is required with state=present')
if line is None:
module.fail_json(msg='line is required with state=present')
# Deal with the insertafter default value manually, to avoid errors
# because of the mutually_exclusive mechanism.
@ -497,13 +505,11 @@ def main():
if ins_bef is None and ins_aft is None:
ins_aft = 'EOF'
line = params['line']
present(module, path, params['regexp'], line,
ins_aft, ins_bef, create, backup, backrefs, firstmatch)
else:
if params['regexp'] is None and params.get('line', None) is None:
module.fail_json(msg='one of line= or regexp= is required with state=absent')
if regexp is None and line is None:
module.fail_json(msg='one of line or regexp is required with state=absent')
absent(module, path, params['regexp'], params.get('line', None), backup)

View file

@ -717,3 +717,45 @@
assert:
that:
- result.stat.checksum == 'eca8d8ea089d4ea57a3b87d4091599ca8b60dfd2'
###################################################################
# Issue 29443
# When using an empty regexp, replace the last line (since it matches every line)
# but also provide a warning.
- name: Deploy the test file for lineinfile
copy:
src: test.txt
dest: "{{ output_dir }}/test.txt"
register: result
- name: Assert that the test file was deployed
assert:
that:
- result is changed
- result.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'
- result.state == 'file'
- name: Insert a line in the file using an empty string as a regular expression
lineinfile:
path: "{{ output_dir }}/test.txt"
regexp: ''
line: This is line 6
register: insert_empty_regexp
- name: Stat the file
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: Assert that the file contents match what is expected and a warning was displayed
assert:
that:
- insert_empty_regexp is changed
- warning_message in insert_empty_regexp.warnings
- result.stat.checksum == '23555a98ceaa88756b4c7c7bba49d9f86eed868f'
vars:
warning_message: >-
The regular expression is an empty string, which will match every line in the file.
This may have unintended consequences, such as replacing the last line in the file rather than appending.
If this is desired, use '^' to match every line in the file and avoid this warning.