ansible/test/integration/targets/lineinfile/tasks/main.yml
Sam Doran 0fa56ed65d Add warning when using an empty regexp in lineinfile (#42013) (#42207)
* 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

(cherry picked from commit fb55038d75)
2018-07-05 09:41:07 -07:00

761 lines
20 KiB
YAML

# test code for the lineinfile module
# (c) 2014, James Cammarata <jcammarata@ansible.com>
# 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 <http://www.gnu.org/licenses/>.
- 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 at the beginning of the file, and back it up
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New line at the beginning"
insertbefore: "BOF"
backup: yes
register: result1
- name: insert a line at the beginning of the file again
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New line at the beginning"
insertbefore: "BOF"
register: result2
- name: assert that the line was inserted at the head of the file
assert:
that:
- result1 is changed
- result2 is not changed
- result1.msg == 'line added'
- result1.backup != ''
- name: stat the backup file
stat:
path: "{{ result1.backup }}"
register: result
- name: assert the backup file matches the previous hash
assert:
that:
- "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
- name: stat the test after the insert at the head
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test hash is what we expect for the file with the insert at the head
assert:
that:
- "result.stat.checksum == '7eade4042b23b800958fe807b5bfc29f8541ec09'"
- name: insert a line at the end of the file
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New line at the end"
insertafter: "EOF"
register: result
- name: assert that the line was inserted at the end of the file
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: stat the test after the insert at the end
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after the insert at the end
assert:
that:
- "result.stat.checksum == 'fb57af7dc10a1006061b000f1f04c38e4bef50a9'"
- name: insert a line after the first line
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New line after line 1"
insertafter: "^This is line 1$"
register: result
- name: assert that the line was inserted after the first line
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: stat the test after insert after the first line
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after the insert after the first line
assert:
that:
- "result.stat.checksum == '5348da605b1bc93dbadf3a16474cdf22ef975bec'"
- name: insert a line before the last line
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New line after line 5"
insertbefore: "^This is line 5$"
register: result
- name: assert that the line was inserted before the last line
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: stat the test after the insert before the last line
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after the insert before the last line
assert:
that:
- "result.stat.checksum == 'e1cae425403507feea4b55bb30a74decfdd4a23e'"
- name: replace a line with backrefs
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "This is line 3"
backrefs: yes
regexp: "^(REF) .* \\1$"
register: result
- name: assert that the line with backrefs was changed
assert:
that:
- result is changed
- "result.msg == 'line replaced'"
- name: stat the test after the backref line was replaced
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after backref line was replaced
assert:
that:
- "result.stat.checksum == '2ccdf45d20298f9eaece73b713648e5489a52444'"
- name: remove the middle line
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: absent
regexp: "^This is line 3$"
register: result
- name: assert that the line was removed
assert:
that:
- result is changed
- "result.msg == '1 line(s) removed'"
- name: stat the test after the middle line was removed
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after the middle line was removed
assert:
that:
- "result.stat.checksum == 'a6ba6865547c19d4c203c38a35e728d6d1942c75'"
- name: run a validation script that succeeds
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: absent
regexp: "^This is line 5$"
validate: "true %s"
register: result
- name: assert that the file validated after removing a line
assert:
that:
- result is changed
- "result.msg == '1 line(s) removed'"
- name: stat the test after the validation succeeded
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after the validation succeeded
assert:
that:
- "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"
- name: run a validation script that fails
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: absent
regexp: "^This is line 1$"
validate: "/bin/false %s"
register: result
ignore_errors: yes
- name: assert that the validate failed
assert:
that:
- "result.failed == true"
- name: stat the test after the validation failed
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches the previous after the validation failed
assert:
that:
- "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"
- name: use create=yes
lineinfile:
dest: "{{ output_dir }}/new_test.txt"
create: yes
insertbefore: BOF
state: present
line: "This is a new file"
register: result
- name: assert that the new file was created
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: validate that the newly created file exists
stat:
path: "{{ output_dir }}/new_test.txt"
register: result
ignore_errors: yes
- name: assert the newly created test checksum matches
assert:
that:
- "result.stat.checksum == '038f10f9e31202451b093163e81e06fbac0c6f3a'"
# Test EOF in cases where file has no newline at EOF
- name: testnoeof deploy the file for lineinfile
copy:
src: testnoeof.txt
dest: "{{ output_dir }}/testnoeof.txt"
register: result
- name: testnoeof insert a line at the end of the file
lineinfile:
dest: "{{ output_dir }}/testnoeof.txt"
state: present
line: "New line at the end"
insertafter: "EOF"
register: result
- name: testempty assert that the line was inserted at the end of the file
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: insert a multiple lines at the end of the file
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "This is a line\nwith \\n character"
insertafter: "EOF"
register: result
- name: assert that the multiple lines was inserted
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: testnoeof stat the no newline EOF test after the insert at the end
stat:
path: "{{ output_dir }}/testnoeof.txt"
register: result
- name: testnoeof assert test checksum matches after the insert at the end
assert:
that:
- "result.stat.checksum == 'f9af7008e3cb67575ce653d094c79cabebf6e523'"
# Test EOF with empty file to make sure no unnecessary newline is added
- name: testempty deploy the testempty file for lineinfile
copy:
src: testempty.txt
dest: "{{ output_dir }}/testempty.txt"
register: result
- name: testempty insert a line at the end of the file
lineinfile:
dest: "{{ output_dir }}/testempty.txt"
state: present
line: "New line at the end"
insertafter: "EOF"
register: result
- name: testempty assert that the line was inserted at the end of the file
assert:
that:
- result is changed
- "result.msg == 'line added'"
- name: testempty stat the test after the insert at the end
stat:
path: "{{ output_dir }}/testempty.txt"
register: result
- name: testempty assert test checksum matches after the insert at the end
assert:
that:
- "result.stat.checksum == 'f440dc65ea9cec3fd496c1479ddf937e1b949412'"
- stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after inserting multiple lines
assert:
that:
- "result.stat.checksum == 'bf5b711f8f0509355aaeb9d0d61e3e82337c1365'"
- name: replace a line with backrefs included in the line
lineinfile:
dest: "{{ output_dir }}/test.txt"
state: present
line: "New \\1 created with the backref"
backrefs: yes
regexp: "^This is (line 4)$"
register: result
- name: assert that the line with backrefs was changed
assert:
that:
- result is changed
- "result.msg == 'line replaced'"
- name: stat the test after the backref line was replaced
stat:
path: "{{ output_dir }}/test.txt"
register: result
- name: assert test checksum matches after backref line was replaced
assert:
that:
- "result.stat.checksum == '04b7a54d0fb233a4e26c9e625325bb4874841b3c'"
###################################################################
# issue 8535
- name: create a new file for testing quoting issues
file:
dest: "{{ output_dir }}/test_quoting.txt"
state: touch
register: result
- name: assert the new file was created
assert:
that:
- result is changed
- name: use with_items to add code-like strings to the quoting txt file
lineinfile:
dest: "{{ output_dir }}/test_quoting.txt"
line: "{{ item }}"
insertbefore: BOF
with_items:
- "'foo'"
- "dotenv.load();"
- "var dotenv = require('dotenv');"
register: result
- name: assert the quote test file was modified correctly
assert:
that:
- result.results|length == 3
- result.results[0] is changed
- result.results[0].item == "'foo'"
- result.results[1] is changed
- result.results[1].item == "dotenv.load();"
- result.results[2] is changed
- result.results[2].item == "var dotenv = require('dotenv');"
- name: stat the quote test file
stat:
path: "{{ output_dir }}/test_quoting.txt"
register: result
- name: assert test checksum matches after backref line was replaced
assert:
that:
- "result.stat.checksum == '7dc3cb033c3971e73af0eaed6623d4e71e5743f1'"
- name: insert a line into the quoted file with a single quote
lineinfile:
dest: "{{ output_dir }}/test_quoting.txt"
line: "import g'"
register: result
- name: assert that the quoted file was changed
assert:
that:
- result is changed
- name: stat the quote test file
stat:
path: "{{ output_dir }}/test_quoting.txt"
register: result
- name: assert test checksum matches after backref line was replaced
assert:
that:
- "result.stat.checksum == '73b271c2cc1cef5663713bc0f00444b4bf9f4543'"
- name: insert a line into the quoted file with many double quotation strings
lineinfile:
dest: "{{ output_dir }}/test_quoting.txt"
line: "\"quote\" and \"unquote\""
register: result
- name: assert that the quoted file was changed
assert:
that:
- result is changed
- name: stat the quote test file
stat:
path: "{{ output_dir }}/test_quoting.txt"
register: result
- name: assert test checksum matches after backref line was replaced
assert:
that:
- "result.stat.checksum == 'b10ab2a3c3b6492680c8d0b1d6f35aa6b8f9e731'"
###################################################################
# Issue 28721
- name: Deploy the testmultiple file
copy:
src: testmultiple.txt
dest: "{{ output_dir }}/testmultiple.txt"
register: result
- name: Assert that the testmultiple file was deployed
assert:
that:
- result is changed
- result.checksum == '3e0090a34fb641f3c01e9011546ff586260ea0ea'
- result.state == 'file'
# Test insertafter
- name: Write the same line to a file inserted after different lines
lineinfile:
path: "{{ output_dir }}/testmultiple.txt"
insertafter: "{{ item.regex }}"
line: "{{ item.replace }}"
register: _multitest_1
with_items: "{{ test_regexp }}"
- name: Do the same thing again to check for changes
lineinfile:
path: "{{ output_dir }}/testmultiple.txt"
insertafter: "{{ item.regex }}"
line: "{{ item.replace }}"
register: _multitest_2
with_items: "{{ test_regexp }}"
- name: Assert that the file was changed the first time but not the second time
assert:
that:
- item.0 is changed
- item.1 is not changed
with_together:
- "{{ _multitest_1.results }}"
- "{{ _multitest_2.results }}"
- name: Stat the insertafter file
stat:
path: "{{ output_dir }}/testmultiple.txt"
register: result
- name: Assert that the insertafter file matches expected checksum
assert:
that:
- result.stat.checksum == '282fedf460b3ed7357667a9c8b457ec67b53b6ea'
# Test insertbefore
- name: Write the same line to a file inserted before different lines
lineinfile:
path: "{{ output_dir }}/testmultiple.txt"
insertbefore: "{{ item.regex }}"
line: "{{ item.replace }}"
register: _multitest_3
with_items: "{{ test_regexp }}"
- name: Do the same thing again to check for changes
lineinfile:
path: "{{ output_dir }}/testmultiple.txt"
insertbefore: "{{ item.regex }}"
line: "{{ item.replace }}"
register: _multitest_4
with_items: "{{ test_regexp }}"
- name: Assert that the file was changed the first time but not the second time
assert:
that:
- item.0 is changed
- item.1 is not changed
with_together:
- "{{ _multitest_3.results }}"
- "{{ _multitest_4.results }}"
- name: Stat the insertbefore file
stat:
path: "{{ output_dir }}/testmultiple.txt"
register: result
- name: Assert that the insertbefore file matches expected checksum
assert:
that:
- result.stat.checksum == 'a8452bb3643be8d18ba3fc212632b1633bd9f885'
###################################################################
# Issue 36156
# Test insertbefore and insertafter with regexp
- name: Deploy the test.conf file
copy:
src: test.conf
dest: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the test.conf file was deployed
assert:
that:
- result is changed
- result.checksum == '6037f13e419b132eb3fd20a89e60c6c87a6add38'
- result.state == 'file'
# Test instertafter
- name: Insert lines after with regexp
lineinfile:
path: "{{ output_dir }}/test.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
insertafter: "{{ item.after }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_5
- name: Do the same thing again and check for changes
lineinfile:
path: "{{ output_dir }}/test.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
insertafter: "{{ item.after }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_6
- name: Assert that the file was changed the first time but not the second time
assert:
that:
- item.0 is changed
- item.1 is not changed
with_together:
- "{{ _multitest_5.results }}"
- "{{ _multitest_6.results }}"
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file contents match what is expected
assert:
that:
- result.stat.checksum == '06e2c456e5028dd7bcd0b117b5927a1139458c82'
- name: Do the same thing a third time without regexp and check for changes
lineinfile:
path: "{{ output_dir }}/test.conf"
line: "{{ item.line }}"
insertafter: "{{ item.after }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_7
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file was changed when no regexp was provided
assert:
that:
- item is changed
with_items: "{{ _multitest_7.results }}"
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file contents match what is expected
assert:
that:
- result.stat.checksum == '5bf50f3d74afd20de4010ca5c04bc7037b062d30'
# Test insertbefore
- name: Deploy the test.conf file
copy:
src: test.conf
dest: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the test.conf file was deployed
assert:
that:
- result is changed
- result.checksum == '6037f13e419b132eb3fd20a89e60c6c87a6add38'
- result.state == 'file'
- name: Insert lines before with regexp
lineinfile:
path: "{{ output_dir }}/test.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
insertbefore: "{{ item.before }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_8
- name: Do the same thing again and check for changes
lineinfile:
path: "{{ output_dir }}/test.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
insertbefore: "{{ item.before }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_9
- name: Assert that the file was changed the first time but not the second time
assert:
that:
- item.0 is changed
- item.1 is not changed
with_together:
- "{{ _multitest_8.results }}"
- "{{ _multitest_9.results }}"
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file contents match what is expected
assert:
that:
- result.stat.checksum == 'c3be9438a07c44d4c256cebfcdbca15a15b1db91'
- name: Do the same thing a third time without regexp and check for changes
lineinfile:
path: "{{ output_dir }}/test.conf"
line: "{{ item.line }}"
insertbefore: "{{ item.before }}"
with_items: "{{ test_befaf_regexp }}"
register: _multitest_10
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file was changed when no regexp was provided
assert:
that:
- item is changed
with_items: "{{ _multitest_10.results }}"
- name: Stat the file
stat:
path: "{{ output_dir }}/test.conf"
register: result
- name: Assert that the file contents match what is expected
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.