My file structure is like below
[root@test exim]# cat exim.json
{
"general": {
"max_hourly_email": 0,
"max_notify_email": 0,
"enable_mail_retry": "1",
"mail_retry": 15,
"enable_roundcube": "1",
"default_quota_val": 32768,
"default_quota": "1",
"eximmailtrap": "1",
"no_local_emailing": "0",
"dkim_selector": "x",
"disable_ipv6": "0",
"custom_mailips": "0",
"message_linelength_limit": 2048
I want to change the value of "max_hourly_email" and "max_notify_email"
**I am trying to change the valued using following method:
**
- name: Set Max hourly emails per domain
lineinfile:
path: /var/webuzo/conf/exim/exim.json
regexp: 'max_hourly_email'
line: ' "max_hourly_email": 200,'
state: present
It is changing the value but breaking the file sturcture like below
[root@test exim]# cat exim.json
{
"general": {
**"max_hourly_email": 200,**
"max_notify_email": 0,
"enable_mail_retry": "1",
"mail_retry": 15,
"enable_roundcube": "1",
"default_quota_val": 32768,
"default_quota": "1",
"eximmailtrap": "1",
"no_local_emailing": "0",
"dkim_selector": "x",
"disable_ipv6": "0",
"custom_mailips": "0",
"message_linelength_limit": 2048
How may I change the values using ansible without breaking the structure. Thanks.
CodePudding user response:
Given the file with the sorted dictionary for simpler comparison
shell> cat exim.json
{
"general": {
"custom_mailips": "0",
"default_quota": "1",
"default_quota_val": 32768,
"disable_ipv6": "0",
"dkim_selector": "x",
"enable_mail_retry": "1",
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
"max_hourly_email": 0,
"max_notify_email": 0,
"message_linelength_limit": 2048,
"no_local_emailing": "0"
}
}
lineinfile
Create a dictionary with the updates. For example, if you want to keep the double quotes make them part of the string
update:
general:
max_hourly_email: 200
enable_mail_retry: '"3"'
test: 9
The task below will update existing keys, but won't add a new one
- lineinfile:
backrefs: true
path: "{{ my_file }}"
regexp: '^(.*){{ item.key }}(.*):\s (.*)$'
line: '\1{{ item.key }}\2: {{ item.value }},'
loop: "{{ update.general|dict2items }}"
gives when running with options --check --diff
TASK [lineinfile] ****************************************************************************
--- before: /export/scratch/tmp7/test-117/exim.json (content)
after: /export/scratch/tmp7/test-117/exim.json (content)
@@ -9,7 9,7 @@
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
- "max_hourly_email": 0,
"max_hourly_email": 200,
"max_notify_email": 0,
"message_linelength_limit": 2048,
"no_local_emailing": "0"
changed: [localhost] => (item={'key': 'max_hourly_email', 'value': 200})
--- before: /export/scratch/tmp7/test-117/exim.json (content)
after: /export/scratch/tmp7/test-117/exim.json (content)
@@ -5,7 5,7 @@
"default_quota_val": 32768,
"disable_ipv6": "0",
"dkim_selector": "x",
- "enable_mail_retry": "1",
"enable_mail_retry": "3",
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
changed: [localhost] => (item={'key': 'enable_mail_retry', 'value': '"3"'})
ok: [localhost] => (item={'key': 'test', 'value': 9})
template
There is a more flexible option of combining the dictionaries and using a template. Remove the extra quotation
update:
general:
max_hourly_email: 200
enable_mail_retry: "3"
test: 9
combine the dictionaries
- copy:
dest: "{{ playbook_dir }}/exim.json"
content: |
{{ orig|combine(update, recursive=true)|to_nice_json }}
vars:
orig: "{{ lookup('file', my_file)|from_yaml }}"
gives when running with options --check --diff
TASK [copy] **********************************************************************************
--- before: /export/scratch/tmp7/test-117/exim.json
after: /home/admin/.ansible/tmp/ansible-local-888558_ztunphb/tmp9b2vctgc
@@ -5,13 5,14 @@
"default_quota_val": 32768,
"disable_ipv6": "0",
"dkim_selector": "x",
- "enable_mail_retry": "1",
"enable_mail_retry": "3",
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
- "max_hourly_email": 0,
"max_hourly_email": 200,
"max_notify_email": 0,
"message_linelength_limit": 2048,
- "no_local_emailing": "0"
"no_local_emailing": "0",
"test": 9
}
}
changed: [localhost]
Notes
Example of a complete playbook for testing
- hosts: localhost
vars:
my_file: "{{ playbook_dir }}/exim.json"
tasks:
- lineinfile:
backrefs: true
path: "{{ my_file }}"
regexp: '^(.*){{ item.key }}(.*):\s (.*)$'
line: '\1{{ item.key }}\2: {{ item.value }},'
loop: "{{ update.general|dict2items }}"
when: iter|d(true)|bool
vars:
update:
general:
max_hourly_email: 200
enable_mail_retry: '"3"'
test: 9
- copy:
dest: "{{ my_file }}"
content: |
{{ orig|combine(update, recursive=true)|to_nice_json }}
when: not iter|d(true)|bool
vars:
orig: "{{ lookup('file', my_file)|from_yaml }}"
update:
general:
max_hourly_email: 200
enable_mail_retry: "3"
test: 9
CodePudding user response:
Above answer by Vladimir is quite comprehensive , adding to above I have written a simple playbook using jinja expression which is easy to understand.
exim.j2
{
"general": {
"custom_mailips": "0",
"default_quota": "1",
"default_quota_val": 32768,
"disable_ipv6": "0",
"dkim_selector": "x",
"enable_mail_retry": "1",
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
"max_hourly_email": "{{ max_hourly_email }}",
"max_notify_email": "{{ max_notify_email }}",
"message_linelength_limit": 2048,
"no_local_emailing": "0"
}
}
Using the above jinja file in the below playbook
---
- name: Set variable in jinja file
hosts: localhost
become: true
vars:
max_hourly_email: 200
max_notify_email: [email protected]
tasks:
- name: Deploy the file
template:
src: exim.j2
dest: final.txt
Below is the output final.txt that is produced as desired.
{
"general": {
"custom_mailips": "0",
"default_quota": "1",
"default_quota_val": 32768,
"disable_ipv6": "0",
"dkim_selector": "x",
"enable_mail_retry": "1",
"enable_roundcube": "1",
"eximmailtrap": "1",
"mail_retry": 15,
"max_hourly_email": "200",
"max_notify_email": "[email protected]",
"message_linelength_limit": 2048,
"no_local_emailing": "0"
}
}