[ansible] ansible: lineinfile for several lines?

The same way there is a module lineinfile to add one line in a file, is there a way to add several lines?

I do not want to use a template because you have to provide the whole file. I just want to add something to an existing file without necessarily knowing what the file already contains so a template is not an option.

This question is related to ansible

The answer is

You can try using blockinfile instead.

You can do something like

- blockinfile: |
    dest=/etc/network/interfaces backup=yes
    content="iface eth0 inet static

You can use a loop to do it. Here's an example using a with_items loop:

- name: Set some kernel parameters
    dest: /etc/sysctl.conf
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    - { regexp: '^kernel.shmall', line: 'kernel.shmall = 2097152' }
    - { regexp: '^kernel.shmmax', line: 'kernel.shmmax = 134217728' }
    - { regexp: '^fs.file-max', line: 'fs.file-max = 65536' }

Here is a noise-free version of the solution which is to use with_items:

- name: add lines
    dest: fruits.txt
    line: '{{ item }}'
    - 'Orange'
    - 'Apple'
    - 'Banana' 

For each item, if the item exists in fruits.txt no action is taken.

If the item does not exist it will be appended to the end of the file.


To add multiple lines you can use lineinfile module with with_items also including variable vars here to make it simple :)

- hosts: localhost  #change Host group as par inventory
  gather_facts: no
  become: yes
    test_server: ""
    test_server_name: "test-server"
    file_dest: "/etc/test/test_agentd.conf"

  - name: configuring test.conf
      dest: "{{ item.dest }}"
      regexp: "{{ item.regexp }}"
      line: "{{ item.line }}"
      - { dest: '"{{ file_dest }}"', regexp: 'Server=', line: 'Server="{{test_server}}"' }
      - { dest: '"{{ file_dest }}"', regexp: 'ServerActive=', line: 'ServerActive="{{test_server}}"' }
      - { dest: '"{{ file_dest }}"', regexp: 'Hostname=', line: 'Hostname="{{test_server_name}}"' }

To add multiple Lines in a configuration file you can use " " instead of ' ' and escape sequence \n for the new line in lineinfile ansible module:

- name: Configure core-site.xml
    path: /etc/hadoop/core-site.xml
    insertafter: '^<configuration>'
    line: "Line 1 \n Line 2 \n Line 3"

It's not ideal, but you're allowed multiple calls to lineinfile. Using that with insert_after, you can get the result you want:

- name: Set first line at EOF (1/3)
  lineinfile: dest=/path/to/file regexp="^string 1" line="string 1"
- name: Set second line after first (2/3)
  lineinfile: dest=/path/to/file regexp="^string 2" line="string 2" insertafter="^string 1"
- name: Set third line after second (3/3)
  lineinfile: dest=/path/to/file regexp="^string 3" line="string 3" insertafter="^string 2"

To add multiple lines you can use blockfile:

- name: Add mappings to /etc/hosts
    path: /etc/hosts
    block: |
      '  server.example.com'
      '  server1.example.com'

to Add one line you can use lininfile:

- name: server.example.com in /etc/hosts
    path: /etc/hosts
    line: ' server.example.com server'
    state: present

If you need to configure a set of unique property=value lines, I recommend a more concise loop. For example:

- name: Configure kernel parameters
    dest: /etc/sysctl.conf
    regexp: "^{{ item.property | regex_escape() }}="
    line: "{{ item.property }}={{ item.value }}"
    - { property: 'kernel.shmall', value: '2097152' }
    - { property: 'kernel.shmmax', value: '134217728' }
    - { property: 'fs.file-max', value: '65536' }

Using a dict as suggested by Alix Axel and adding automatic removing of matching commented out entries,

- name: Configure IPV4 Forwarding
    path: /etc/sysctl.conf
    regexp: "^#? *{{ item.key | regex_escape() }}="
    line: "{{ item.key }}={{ item.value }}"
    'net.ipv4.ip_forward': 1

I was able to do that by using \n in the line parameter.

It is specially useful if the file can be validated, and adding a single line generates an invalid file.

In my case, I was adding AuthorizedKeysCommand and AuthorizedKeysCommandUser to sshd_config, with the following command:

- lineinfile: dest=/etc/ssh/sshd_config line='AuthorizedKeysCommand /etc/ssh/ldap-keys\nAuthorizedKeysCommandUser nobody' validate='/usr/sbin/sshd -T -f %s'

Adding only one of the options generates a file that fails validation.