Search code examples
ansibleansible-inventory

Ansible add lines to file with split variable


I made a UI that I use to configure our servers. I put the new IP's or servernames into a txt field and have ansbible playbooks ran on them depending on the type of server it is instead of using an inventory file. I'm trying to get ansible to add lines to a file for each value in the {{ips}} variable and not have them all on the same line.

I have tried a few different ways including lineinfile, blockinfile and replace seems to get me closer than the others, but I am still not able to get the results I want.

- name: Add new lines
    replace:
      path: /foo/bar
      regexp: '^# Test Line'
      replace: "# Test Line\n/foo/bar {{ ips }}"

This add one line with all the IP's in the ips variable.

# Test Line
/foo/bar test1,test2

What I am trying to get is.

# Test Line
/foo/bar test1
/foo/bar test2

It is hard to account for how many ip's will be in the variable at a time. Sometimes it's one sometimes it's 10.


Solution

  • In the following solution:

    • I'm using the python split inside a Jinja2 expression to create a list out of your string of comma separated ip strings. This will only work if the format stays the same.
    • I loop over that list with lineinfile, using the insertafter option

    I made sure the solution handles dupes nicely if needed.

    This is the demo playbook

    ---
    - name: test for So
      hosts: localhost
    
      vars:
        test_file: /tmp/test_file.txt
        first_ips: 127.0.0.1,127.0.0.2
        more_ips: 10.35.26.1,10.35.26.2
        dupe_ips: 127.0.0.2,10.35.26.1
    
      tasks:
        - name: Make sure we start from scratch
          shell: echo "I'm a line of text\n\n# Test Line\n\nThis is the end, my only friend" > {{ test_file }}
    
        - name: Show file at start
          debug:
            msg: "{{ lookup('file', test_file).split('\n') }}"
    
        - name: Add first ips
          lineinfile:
            path: "{{ test_file }}"
            insertafter: "# Test Line"
            line: "/foo/bar {{ item }}"
          loop: "{{ first_ips.split(',') }}"
    
        - name: Show file with first ips
          debug:
            msg: "{{ lookup('file', test_file).split('\n') }}"
    
        - name: Add second list of ips
          lineinfile:
            path: "{{ test_file }}"
            insertafter: "# Test Line"
            line: "/foo/bar {{ item }}"
          loop: "{{ more_ips.split(',') }}"
    
        - name: Show file with more ips
          debug:
            msg: "{{ lookup('file', test_file).split('\n') }}"
    
        - name: Test if dupes are handled correctly
          lineinfile:
            path: "{{ test_file }}"
            insertafter: "# Test Line"
            line: "/foo/bar {{ item }}"
          loop: "{{ dupe_ips.split(',') }}"
    
        - name: Show file that should not have changed
          debug:
            msg: "{{ lookup('file', test_file).split('\n') }}"
    

    And here is the result. My debug task is showing the result file as a list of lines for display purpose when running the playbook. cat the file yourself if you want to see the result without the extra quotes and commas.

    PLAY [test for So] *******************************************************************
    
    TASK [Gathering Facts] ***************************************************************
    ok: [localhost]
    
    TASK [Make sure we start from scratch] ***********************************************
    changed: [localhost]
    
    TASK [Show file at start] ************************************************************
    ok: [localhost] => {
        "msg": [
            "I'm a line of text",
            "",
            "# Test Line",
            "",
            "This is the end, my only friend"
        ]
    }
    
    TASK [Add first ips] *****************************************************************
    changed: [localhost] => (item=/foo/bar 127.0.0.1)
    changed: [localhost] => (item=/foo/bar 127.0.0.2)
    
    TASK [Show file with first ips] ******************************************************
    ok: [localhost] => {
        "msg": [
            "I'm a line of text",
            "",
            "# Test Line",
            "/foo/bar 127.0.0.2",
            "/foo/bar 127.0.0.1",
            "",
            "This is the end, my only friend"
        ]
    }
    
    TASK [Add second list of ips] ********************************************************
    changed: [localhost] => (item=/foo/bar 10.35.26.1)
    changed: [localhost] => (item=/foo/bar 10.35.26.2)
    
    TASK [Show file with more ips] *******************************************************
    ok: [localhost] => {
        "msg": [
            "I'm a line of text",
            "",
            "# Test Line",
            "/foo/bar 10.35.26.2",
            "/foo/bar 10.35.26.1",
            "/foo/bar 127.0.0.2",
            "/foo/bar 127.0.0.1",
            "",
            "This is the end, my only friend"
        ]
    }
    
    TASK [Test if dupes are handled correctly] *******************************************
    ok: [localhost] => (item=/foo/bar 127.0.0.2)
    ok: [localhost] => (item=/foo/bar 10.35.26.1)
    
    TASK [Show file that should not have changed] ****************************************
    ok: [localhost] => {
        "msg": [
            "I'm a line of text",
            "",
            "# Test Line",
            "/foo/bar 10.35.26.2",
            "/foo/bar 10.35.26.1",
            "/foo/bar 127.0.0.2",
            "/foo/bar 127.0.0.1",
            "",
            "This is the end, my only friend"
        ]
    }
    
    PLAY RECAP ***************************************************************************
    localhost                  : ok=9    changed=3    unreachable=0    failed=0