playbook to comment out one line and add another line in a file

269 views
Skip to first unread message

Tony Wong

unread,
May 3, 2022, 1:10:06 PM5/3/22
to Ansible Project
how do i use ansible to remotely comment out a line in a docker-compose file and add a line

like this

#image: gralog/graylog:4.2.5
image: graylog/graylog4.2.8

then do a docker compose down
and docker-compose up -d


i need to run this on multiple nodes

Vladimir Botka

unread,
May 3, 2022, 2:52:24 PM5/3/22
to Tony Wong, ansible...@googlegroups.com
On Tue, 3 May 2022 10:10:06 -0700 (PDT)
Tony Wong <tdub...@gmail.com> wrote:

> comment out a line in a docker-compose
> file and add a line
>
> #image: gralog/graylog:4.2.5
> image: graylog/graylog4.2.8

I assume, the expected result is below. If not confirm your example
and ignore the rest here

#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8

For example, create a dictionary of the disabled and enabled versions

versions:
4.2.5: false
4.2.8: true

Then the *lineinfile* task below should comment out disabled versions
and add enabled versions

- lineinfile:
path: docker-compose
regex: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
line: '{{ hash }}image: graylog/graylog{{ item.key }}'
loop: "{{ versions|dict2items }}"
vars:
hash: "{{ item.value|ternary('', '#') }}"

--
Vladimir Botka

Tony Wong

unread,
May 4, 2022, 4:51:00 PM5/4/22
to Vladimir Botka, ansible...@googlegroups.com
do ytou mean like this


---
- name: change file add line
  hosts: k8s

 
  versions:
    4.2.5: false
    4.2.8: true  

  tasks:
    - name: change file add line
      lineinfile:

        regex: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
        line: '{{ hash }}image: graylog/graylog{{ item.key }}'
        path: /tmp/temp.txt
      loop:

        vars:
          hash: "{{ item.value|ternary('', '#') }}"

Vladimir Botka

unread,
May 4, 2022, 6:14:13 PM5/4/22
to Tony Wong, ansible...@googlegroups.com
See the complete example below

shell> cat docker-compose
image: graylog/graylog4.2.5


shell> cat pb.yml
---
- hosts: localhost
vars:
versions:
4.2.5: false
4.2.8: true
tasks:
- lineinfile:
path: docker-compose
regex: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
line: '{{ hash }}image: graylog/graylog{{ item.key }}'
loop: "{{ versions|dict2items }}"
vars:
hash: "{{ item.value|ternary('', '#') }}"


shell> ansible-playbook pb.yml

PLAY [localhost]
***************************************************************

TASK [lineinfile]
***************************************************************
changed: [localhost] => (item={'key': '4.2.5', 'value': False})
changed: [localhost] => (item={'key': '4.2.8', 'value': True})

PLAY RECAP
***************************************************************
localhost: ok=1 changed=1 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0


shell> cat docker-compose
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8


--
Vladimir Botka

Tony Wong

unread,
May 4, 2022, 10:09:54 PM5/4/22
to Vladimir Botka, ansible...@googlegroups.com
Got it, thanks! 

Tony Wong

unread,
May 5, 2022, 1:03:30 PM5/5/22
to Vladimir Botka, ansible...@googlegroups.com

I was abl to get my first node changed but the other 2 had this added

image: gralog/graylog:4.2.5
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8

Todd Lewis

unread,
May 5, 2022, 5:27:16 PM5/5/22
to Ansible Project
I don't think you can get `line_in_file` to do what you want. `line_in_file` is designed to operate on a single line. Keeping the commented out line greatly complicates matters. How many patchlevels to you intend to maintain as comments?

You may be able to do it with `replace` and a lot of testing. But I'd strongly encourage you to reconsider using `#` as a poor replacement for revision control.

Vladimir Botka

unread,
May 5, 2022, 6:51:57 PM5/5/22
to Tony Wong, ansible...@googlegroups.com
On Thu, 5 May 2022 10:03:02 -0700
Tony Wong <tdub...@gmail.com> wrote:

> I was abl to get my first node changed but the other 2 had this added
>
> image: gralog/graylog:4.2.5
> #image: graylog/graylog4.2.5
> image: graylog/graylog4.2.8

'y' is missing in 'gralog/graylog:4.2.5' in the first line. This is
the reason why the first line wasn't replaced. Instead, the second
line was added.

--
Vladimir Botka

Tony Wong

unread,
May 5, 2022, 10:22:17 PM5/5/22
to Vladimir Botka, ansible...@googlegroups.com
it only works for first node. When i run the playbook against 3 nodes the 2nd and 3rd node have this

image: graylog/graylog:4.2.5
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8

Tony Wong

unread,
May 5, 2022, 10:23:16 PM5/5/22
to Vladimir Botka, ansible...@googlegroups.com
this is the playbook

---
- name: test
  hosts: k8s

  vars:
    versions:
      4.2.5: false
      4.2.8: true
  tasks:
    - name: test
      lineinfile:
        path: /tmp/temp.txt

        regex: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
        line: '{{ hash }}image: graylog/graylog{{ item.key }}'
      loop: "{{ versions|dict2items }}"
      vars:
        hash: "{{ item.value|ternary('', '#') }}"

Tony Wong

unread,
May 5, 2022, 10:41:56 PM5/5/22
to Vladimir Botka, ansible...@googlegroups.com
I tested with another pb and it works fine on all 3 nodes

---
- name: test
  hosts: k8s
 
  tasks:
    - name: test
      lineinfile:
        line: "Hello World"
        path: /tmp/temp2.txt
        create: true

Vladimir Botka

unread,
May 6, 2022, 12:44:42 AM5/6/22
to Tony Wong, ansible...@googlegroups.com
On Thu, 5 May 2022 19:21:47 -0700
Tony Wong <tdub...@gmail.com> wrote:

> it only works for first node. When i run the playbook against 3 nodes the
> 2nd and 3rd node have this
>
> image: graylog/graylog:4.2.5
> #image: graylog/graylog4.2.5
> image: graylog/graylog4.2.8


Quoting from *lineinfile* parameter *regexp*
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html#parameter-regexp

For state=present, the pattern to replace if found. Only the last
line found will be replaced.
For state=absent, the pattern of the line(s) to remove.

Note the difference between the states *present/absent*. If *absent*
all matches are removed. If *present* only the last one is replaced.
The default state is *present*.

One of the scenarios on how to proceed might be removing all redundant
lines first. For example, given the file

shell> cat docker-compose
image: graylog/graylog4.2.5
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8


The playbook

shell> cat pb.yml
- hosts: localhost
vars:
versions:
4.2.5: false
4.2.8: true
tasks:
- name: Remove versions
lineinfile:
state: absent
path: docker-compose
regexp: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
loop: "{{ versions|dict2items }}"
when: force_remove_versions|d(false)|bool
- name: Add versions
lineinfile:
path: docker-compose
regexp: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
line: '{{ hash }}image: graylog/graylog{{ item.key }}'
loop: "{{ versions|dict2items }}"
vars:
hash: "{{ item.value|ternary('', '#') }}"


removes all matching lines and creates the specified ones

shell> ansible-playbook pb.yml -e force_remove_versions=true

PLAY [localhost]
***************************************************************

TASK [Remove versions]
***************************************************************
changed: [localhost] => (item={'key': '4.2.5', 'value': False})
changed: [localhost] => (item={'key': '4.2.8', 'value': True})

TASK [Add versions]
***************************************************************
changed: [localhost] => (item={'key': '4.2.5', 'value': False})
changed: [localhost] => (item={'key': '4.2.8', 'value': True})

PLAY RECAP
***************************************************************
localhost : ok=2 changed=2 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0


shell> cat docker-compose
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8


Set the variable *force_remove_versions* as appropriate (for the
scenario that will serve the purpose best).


--
Vladimir Botka

Vladimir Botka

unread,
May 6, 2022, 12:50:30 AM5/6/22
to Tony Wong, ansible...@googlegroups.com
> shell> cat pb.yml
> - hosts: localhost
> vars:
> versions:
> 4.2.5: false
> 4.2.8: true
> tasks:
> - name: Remove versions
> lineinfile:
> state: absent
> path: docker-compose
> regexp: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
> loop: "{{ versions|dict2items }}"
> when: force_remove_versions|d(false)|bool
> - name: Add versions
> lineinfile:
> path: docker-compose
> regexp: '^\s*#*\s*image: graylog/graylog{{ item.key }}\s*$'
> line: '{{ hash }}image: graylog/graylog{{ item.key }}'
> loop: "{{ versions|dict2items }}"
> vars:
> hash: "{{ item.value|ternary('', '#') }}"

The playbook is idempotent

shell> cat docker-compose
#image: graylog/graylog4.2.5
image: graylog/graylog4.2.8


shell> ansible-playbook pb.yml

PLAY [localhost]
****************************************************************

TASK [Remove versions]
****************************************************************
skipping: [localhost] => (item={'key': '4.2.5', 'value': False})
skipping: [localhost] => (item={'key': '4.2.8', 'value': True})

TASK [Add versions]
****************************************************************
ok: [localhost] => (item={'key': '4.2.5', 'value': False})
ok: [localhost] => (item={'key': '4.2.8', 'value': True})

PLAY RECAP
****************************************************************
localhost: ok=1 changed=0 unreachable=0
failed=0 skipped=1 rescued=0 ignored=0


--
Vladimir Botka

Tony Wong

unread,
May 6, 2022, 8:48:42 AM5/6/22
to Vladimir Botka, ansible...@googlegroups.com
i got it to work the simple way with multiple tasks

---
- name: test
  hosts: k8s
 
  tasks:
    - name: comment line
      lineinfile:
        line: "#image: graylog/graylog4.2.5"
        regexp: '^image:\sgraylog/graylog4.2.5'
        path: /tmp/temp2.txt
    - name: add line
      lineinfile:
        line: "image: graylog/graylog4.2.8"
        path: /tmp/temp2.txt
        create: true


probably not the most efficient. 

Tony Wong

unread,
May 6, 2022, 8:52:36 AM5/6/22
to Vladimir Botka, ansible...@googlegroups.com
I have another requirement to down the container on node01 first

docker-compose down
then run the pb, 
then docker-compose up -d

wait 30secs or so

repeat with node02
repeat with node03

is there docker module or I should just use shell module?

dulh...@mailbox.org

unread,
May 6, 2022, 9:58:19 AM5/6/22
to ansible...@googlegroups.com


On 06.05.22 14:52, Tony Wong wrote:
is there docker module or I should just use shell module?
I believe it's always better to use designated Modules over shell or command

that said ... you may want to get familiar (or at least be aware of this list) where you can find any modules.
that said ... here is the docker module (from that list)

you can study it online or with the built-in help like ansible-doc [module.name]

one last comment ... just like using designated modules for designated tasks in Ansible it's always best to use designated Threads for different problems.
This may not make a difference for you just now, but others who may be following the list have a chance to benefit from the solution somebody is digging out.

Tony Wong

unread,
May 6, 2022, 4:36:29 PM5/6/22
to Vladimir Botka, ansible...@googlegroups.com
does this mean I cannot keep the old commented line?

#image: graylog/graylog4.2.5

requirement is I need to have this line commented

Todd Lewis

unread,
May 6, 2022, 4:54:20 PM5/6/22
to Ansible Project
Assuming you only have one line for each version, it will assure that the line for any version that's marked false will be commented, and any line for a version marked true will be uncommented.

Where it gets hairy is when you have more than one line for any version. In that case, the second task only manages the first of the lines for that version. That shouldn't happen, but you've already seen that it does sometimes. When it does, you can run the playbook with `force_remove_versions` set to true, and it will remove all the matching lines - both good and bad - before the second task puts the single entries back in the file, properly commented or not as the case may be.

Nico Kadel-Garcia

unread,
May 6, 2022, 5:27:58 PM5/6/22
to ansible...@googlegroups.com, Vladimir Botka
On Fri, May 6, 2022 at 4:36 PM Tony Wong <tdub...@gmail.com> wrote:
>
> does this mean I cannot keep the old commented line?
>
> #image: graylog/graylog4.2.5

It's tricky. You can write scripting to do anything you want to do,
but it's not necessarily built-in precisely the way you want it to
behave.

It's why many config files, such as those in /etc/sudoers.d/, deploy
files rather than editing lines of /etc/sudoers.
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/CALmkhkpKHPEZ7YjVKhS8EmnxyJVJJ%2BGggtKuHEqNXKasznDpDg%40mail.gmail.com.

Vladimir Botka

unread,
May 6, 2022, 11:34:53 PM5/6/22
to Todd Lewis, ansible...@googlegroups.com
Quoting from *lineinfile* parameter *regexp*
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html#parameter-regexp

For state=present, the pattern to replace if found. Only the last
line found will be replaced.

Thank you!

On Fri, 6 May 2022 13:54:20 -0700 (PDT)
Todd Lewis <uto...@gmail.com> wrote:

> Assuming you only have one line for each version, it will assure
> that the line for any version that's marked false will be
> commented, and any line for a version marked true will be
> uncommented.
> Where it gets hairy is when you have more than one line for any
> version. In that case, the second task only manages the first of
^^^^^
last
> the lines for that version. That shouldn't happen, but you've
> already seen that it does sometimes. When it does, you can run the
> playbook with `force_remove_versions` set to true, and it will
> remove all the matching lines - both good and bad - before the
> second task puts the single entries back in the file, properly
> commented or not as the case may be.

--
Vladimir Botka
Reply all
Reply to author
Forward
0 new messages