Reputation: 603
I'm learning ansible and can't figure this out in simple terms with asnible.
I have a file that contains:
net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc cgroup_memory=1 cgroup_enable=memory
This is one line and I would for example want to check if cgroup_memory is set to 1, if not set it to 1 and if the whole setting is missing append it to end of the line.
I know perfectly simple method how to do it with bash and sed, but I can't wrap my head around ansible "correct" way, without using lineinfile and replacing the whole line... as mentioned lineinfile is working with whole line so that would not be ideal I think.. next module I looked into is replace that could possibly work but I can't just look for "cgroup_memory=1" as it would look at "cgroup_memory=0" and evaluated as thats not "cgroup_memory=1" and I end up with cgroup_memory=1 cgroup_memory=0 in a file... somehow I need to extract the value, compare and replace the value ( keeping the whole line intact ) and if its not there append to the end of the line...
Here is bash version I want in ansible: https://pastebin.com/1TCz30Nq
This is where I got closest to what I need:
- name: "Check for cgroup_memory"
shell: grep -v '^[[:space:]]*#' /tmp/cmdline.txt_old | grep -icP "cgroup_memory=-?\d+[[:space:]]" || true
register: grep_value
changed_when: False
- debug:
var: grep_value
- name: "Variable Missing: Add cgroup_memory=1 to end of line"
become: true
replace: dest=/tmp/cmdline.txt_old regexp='(\s+)$' replace=' cgroup_memory=1'
when: grep_value.stdout == "0"
- name: "Variable Exist: Set cgroup_memory=1"
become: true
replace: dest=/tmp/cmdline.txt_old regexp='cgroup_memory=\d+' replace='cgroup_memory=1'
when: grep_value.stdout == "1"
How ever this does not ignore # lines so the replace will happily change the values in comments which is bad. Also this does not evaluate the value but I guess I could grep and split further after determining that its there.. I don't want to complain but ansible was hyped to me as perfect for configuration management and the first simple thing that I do a lot via shell scripts is not that simple... ( if I don't want to use shell module )
Upvotes: 0
Views: 321
Reputation: 68144
The best option, IMHO, is blockinfile. Given the configuration file below
shell> cat test.cfg
line1
line2
net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc cgroup_memory=1 cgroup_enable=memory
line4
line5
Mark the line first. blockinfile needs the markers to find the block (a line in this case). For example
- lineinfile:
path: test.cfg
insertbefore: "^net.ifnames(.*)$"
line: "# BEGIN ANSIBLE MANAGED BLOCK my_block_01"
- lineinfile:
path: test.cfg
insertafter: "^net.ifnames(.*)$"
line: "# END ANSIBLE MANAGED BLOCK my_block_01"
gives
shell> cat test.cfg
line1
line2
# BEGIN ANSIBLE MANAGED BLOCK my_block_01
net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait=fixrtc cgroup_memory=1 cgroup_enable=memory
# END ANSIBLE MANAGED BLOCK my_block_01
line4
line5
The lineinfile tasks above are idempotent. Then create a variable with the configuration. For example
shell> cat net_cfg.yml
net_cfg_01:
- {key: 'net.ifnames', val: 0}
- {key: 'dwc_otg.lpm_enable', val: 0}
- {key: 'console', val: 'serial0,115200'}
- {key: 'console', val: 'tty1'}
- {key: 'root', val: 'LABEL=writable'}
- {key: 'rootfstype', val: 'ext4'}
- {key: 'elevator', val: 'deadline'}
- {key: 'rootwait', val: 'fixrtc'}
- {key: 'cgroup_memory', val: 1}
- {key: 'cgroup_enable', val: 'memory'}
A list, instead of a simpler dictionary, must be used because the keys are not unique. Create a template. For example
shell> cat templates/net_cfg_01.j2
{% for i in net_cfg_01 %}{{i.key}}={{i.val}} {% endfor %}
Now you can include the variable and configure the line in the file
- include_vars: net_cfg.yml
- blockinfile:
path: test.cfg
block: "{{ lookup('template', 'net_cfg_01.j2') }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK my_block_01"
Notes
How to use it
There are many options on how to use the above framework. For example, put configuration variables into the list
shell> cat net_cfg.yml
net_cfg_01:
...
- {key: 'cgroup_memory', val: {{ my_cgroup_memory }}}
Then the command below will make sure the file is configured properly
shell> ansible-playbook playbook.yml -e 'my_cgroup_memory=1'
Upvotes: 1
Reputation: 7340
One way to ensure that cgroup_memory
will be set to 1 is to use the Ansible replace module. The replace module can match a regexp
and replace it with what we want.
Example:
tasks:
- name: set cgroup_memory to 1
replace:
path: /path/to/file
regexp: 'cgroup_memory=\d+'
replace: 'cgroup_memory=1'
If there are more than one lines having this expression, this will replace all occurrences. We can use before
or after
parameters in the above task to target specific ones.
Or we can ensure that an entire line is present using the lineinfile module.
tasks:
- name: ensure line with cgroup_memory is present in file
lineinfile:
path: /path/to/file
regexp: 'cgroup_memory=\d+'
line: "net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc cgroup_memory=1 cgroup_enable=memory"
Upvotes: 1