# test code for the lineinfile module # (c) 2014, James Cammarata # 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: 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: Assert that the line is added once only assert: that: - _multitest_1.results.0 is changed - _multitest_1.results.1 is not changed - _multitest_1.results.2 is not changed - _multitest_1.results.3 is not changed - 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 line is not added anymore assert: that: - _multitest_2.results.0 is not changed - _multitest_2.results.1 is not changed - _multitest_2.results.2 is not changed - _multitest_2.results.3 is not changed - 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 == 'c6733b6c53ddd0e11e6ba39daa556ef8f4840761' # Test insertbefore - 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' - 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: Assert that the line is added once only assert: that: - _multitest_3.results.0 is changed - _multitest_3.results.1 is not changed - _multitest_3.results.2 is not changed - _multitest_3.results.3 is not changed - 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 line is not added anymore assert: that: - _multitest_4.results.0 is not changed - _multitest_4.results.1 is not changed - _multitest_4.results.2 is not changed - _multitest_4.results.3 is not changed - 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 == '5d298651fbc377b45257da10308a9dc2fe1f8be5' ################################################################### # 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 not 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 == '06e2c456e5028dd7bcd0b117b5927a1139458c82' # 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 not 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 == 'c3be9438a07c44d4c256cebfcdbca15a15b1db91' - name: Copy empty file to test with insertbefore copy: src: testempty.txt dest: "{{ output_dir }}/testempty.txt" - name: Add a line to empty file with insertbefore lineinfile: path: "{{ output_dir }}/testempty.txt" line: top insertbefore: '^not in the file$' register: oneline_insbefore_test1 - name: Add a line to file with only one line using insertbefore lineinfile: path: "{{ output_dir }}/testempty.txt" line: top insertbefore: '^not in the file$' register: oneline_insbefore_test2 - name: Stat the file stat: path: "{{ output_dir }}/testempty.txt" register: oneline_insbefore_file - name: Assert that insertebefore worked properly with a one line file assert: that: - oneline_insbefore_test1 is changed - oneline_insbefore_test2 is not changed - oneline_insbefore_file.stat.checksum == '4dca56d05a21f0d018cd311f43e134e4501cf6d9' ################################################################### # 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.