Lineinfile - Skip/Update an item inside "with_items" using conditions

I have a question.

Can an item inside “with_items” or “loop” be skipped? using condition “when some_variable is not defined” ?

Here is my play.

- name: “Update text in the file”
lineinfile:
path: /path-to-the-file/
backrefs: yes
regexp: “{{ item.regexp }}”
line: “{{ item.line }}”
with_items:
- { regexp: ‘^text1’, line: “text1 = {{ VAR1 }}”, when: VAR1 is defined }
- { regexp: ‘^text2’, line: “text2 = {{ VAR2 }}” }
- { regexp: ‘^text3’, line: “text3 = {{ VAR3 }}” }

What I’m trying to achieve is, it should replace the line only when VAR1 value is defined, else it should skip this item and move on to 2nd item.

with_items:
  - { regexp: '^text1', line: "text1 = {{ VAR1 }}", when: VAR1 is defined }
  - { regexp: '^text2', line: "text2 = {{ VAR2 }}" }
  - { regexp: '^text3', line: "text3 = {{ VAR3 }}" }

Set *default* to avoid errors, add attribute *def*, and select lines.
For example,

Thanks for your reply Vladimir Botka.

This is my actual case:

defaults > main.yml

Thanks for your reply Vladimir Botka.

This is my actual case:

defaults > main.yml
---
# defaults file for redis_configs
redis_config_path: /etc/redis/redis.conf

# Default Params Values
MAX_MEM: 3000
TCP_KEEPALIVE: 0
TCP_BACKLOG: 511
MAX_CLIENTS: 15000
TIMEOUT: 1500

And this is:

Tasks > main.yml

---

- name: "Update Redis Parameters in {{ redis_config_path }}"
lineinfile:
path: "{{ redis_config_path }}"
backrefs: yes
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
with_items:
- { regexp: '^maxmemory', line: "maxmemory {{ MAX_MEM }}mb", when: {{ MAX_MEM }} is defined }
- { regexp: '^tcp-keepalive', line: "tcp-keepalive {{ TCP_KEEPALIVE }}", when: {{ TCP_KEEPALIVE }} is defined }
- { regexp: '^tcp-backlog', line: "tcp-backlog {{ TCP_BACKLOG }}", when: {{ TCP_BACKLOG }} is defined}
- { regexp: '^maxclients', line: "maxclients {{ MAX_CLIENTS }}", when: {{ MAX_CLIENTS }} is defined}
- { regexp: '^timeout', line: "timeout {{ TIMEOUT }}" }

I want this to check if each variable inside an item is defined then make the changes to the line in the file, otherwise skip only those items which variables is not defined.
For Instance, If I comment out the variable MAX_MEM from the defaults > main.yml. like below:

# Default Params Values
##MAX_MEM: 3000
TCP_KEEPALIVE: 0
TCP_BACKLOG: 511
MAX_CLIENTS: 15000
TIMEOUT: 1500

Then the execution should skip changes to the line where MAX_MEM is undefined, and the rest lines should be changed as they defined.

Is it possible?

Sorry, but it eludes me why you didn't come up with the actual case in the first place. I see no point in wasting everyone's time.

Regards

         Racke
    - name: "Update Redis Parameters in {{ redis_config_path }}"
      lineinfile:
        path: "{{ redis_config_path }}"
        backrefs: yes
        regexp: "{{ item.regexp }}"
        line: "{{ item.line }}"
      when: item.line is match(omit)
      with_items:
        - { regexp: '^maxmemory',     line: "maxmemory {{ MAX_MEM | d(omit) }}mb" }
        - { regexp: '^tcp-keepalive', line: "tcp-keepalive {{ TCP_KEEPALIVE | d(omit) }}" }
        - { regexp: '^tcp-backlog',   line: "tcp-backlog {{ TCP_BACKLOG | d(omit) }}" }
        - { regexp: '^maxclients',    line: "maxclients {{ MAX_CLIENTS | d(omit) }}" }
        - { regexp: '^timeout',       line: "timeout {{ TIMEOUT }}" }

That “when:” should be

when: item.line is not search(omit)

Thanks @utoddl for your time and reply.

when: item.line is not search(omit)

This solution actually worked for me.

Thanks & regards,

FARRUKH

Can we do the same with blockinfile?
For instance, if the variable is not found then omit only that item and move on to the next item and update it.

Here is my play

  • name: insert/update php configurations in App_config_file
    blockinfile:
    path: “/etc/php/7.4/fpm/php.ini_bak”
    marker: “;# {mark} ANSIBLE MANAGED BLOCK ###”
    block: |
    {% for items in item %}
    {{ items }}
    {% endfor %}
    when: item is not search(omit)
    with_items:
  • { “display_errors = {{service_configurations.display_errors | d(omit) }}” }
  • { “memory_limit = {{service_configurations.memory_limit | d(omit) }}M” }

Here is the output I’m getting:

root@aws-farrukhahmed-518:/etc/php/7.4/fpm# cat php.ini_bak

;# BEGIN ANSIBLE MANAGED BLOCK ###
memory_limit = {{service_configurations.memory_limit | d(omit) }}M
;# END ANSIBLE MANAGED BLOCK ###

root@aws-farrukhahmed-518:/etc/php/7.4/fpm#

Here is the command I’m using:
ansible-playbook -i hosts exec.yml -e ‘{“service_configurations”:{“display_errors”:“On”,“memory_limit”:“128”}}’ -vvv

The expected output should be:

;# BEGIN ANSIBLE MANAGED BLOCK ###
display_errors = On
memory_limit = 128M
;# END ANSIBLE MANAGED BLOCK ###

PS: It is mandatory for me to do this with the blockinfile module.

Hii

Can we do the same with blockinfile?

Maybe. But, what one can do, is not always what one should do - see below.

PS: It is mandatory for me to do this with the blockinfile module.

This is not correct - the file should not be edited at all, because it
is a package provided file.
So, any updates will overwrite your changes. Plus you need to resort
to kludges (imho) like blockinfile.
What you should do, is put your local changes in a properly named ini
file below /etc/php/7.4/fpm/conf.d, which won't be touched by anyone
else.

Dick

Hello Team,

I have progressed but still not achieved my target with blockinfile module.
It should be updated the both items, as I passed both variables but It just updated the last item only i.e (memory_limit)

Here is my play:

  • name: update php configurations
    blockinfile:
    path: “{{ini_file_path}}” # set in defaults
    marker: “;# {mark} ANSIBLE MANAGED BLOCK ###”
    block: “{{ item.param }}”
    loop:
  • { param: “display_errors = {{service_configurations.display_errors | d(omit) }}”}
  • { param: “memory_limit = {{service_configurations.memory_limit | d(omit) }}M”}
    when: item.param is not search(omit)

The output I’m getting:

;# BEGIN ANSIBLE MANAGED BLOCK ###
memory_limit = 128M
;# END ANSIBLE MANAGED BLOCK ###

The output should be like this, if I passed both variables from the command line.

;# BEGIN ANSIBLE MANAGED BLOCK ###
display_errors = On
memory_limit = 128M
;# END ANSIBLE MANAGED BLOCK ###

The Command I’m using:
ansible-playbook -i hosts exec.yml -e ‘{“service_configurations”:{“display_errors”:“On”,“memory_limit”:“128”}}’

I would be thankful for any help or ideas.

Thanks.
FARRUKH AHMED

blockinfile:
path: "{{ini_file_path}}" # set in defaults
marker: ";# {mark} ANSIBLE MANAGED BLOCK ###"
block: "{{ item.param }}"
loop:
- { param: "display_errors = {{service_configurations.display_errors |
d(omit) }}"}
- { param: "memory_limit = {{service_configurations.memory_limit | d(omit)
}}M"}
when: item.param is not search(omit)

The *marker* must be unique for each block. Otherwise the the blocks
will overwrite each other. For this purpose it would be practical to
change the structure of the iterated data. For example, the
simplified playbook below

  > cat pb.yml
  - hosts: localhost
    tasks:
      - blockinfile:
          path: /tmp/test.ini
          marker: "# {mark} {{ item.param }}"
          block: |
            {{ item.param }} = {{ item.value }}
        loop:
          - param: 'display_errors'
            value: "{{ conf.errors }}"
          - param: 'memory_limit'
            value: "{{ conf.limit }}"

ansible-playbook pb.yml -e '{"conf":{"errors":"On","limit":"128"}}'

works as expected and creates the file

  > cat /tmp/test.ini
  # BEGIN display_errors
  display_errors = On
  # END display_errors
  # BEGIN memory_limit
  memory_limit = 128
  # END memory_limit

Fit the data and *marker* to your needs.