double with_items and loops

80 views
Skip to first unread message

John Harmon

unread,
Jan 25, 2018, 12:38:36 PM1/25/18
to Ansible Project
I have the following, and wish to combine them, but don't know how because my with_items is referencing a variable.  Wondering if someone can guide me (if possible) on how to combine these two stanzas:

- name: Add DNS1 to ifcfg-* files if missing
  lineinfile
:
    path
: "{{ net_path }}{{ item }}"
    state
: present
    regexp
: "^DNS1"
    line
: "DNS1={{ dns1 }}"
  with_items
: "{{ ifcfg_list.stdout_lines }}"
  ignore_errors
: yes
  notify
:
   
- Networking

- name: Add DNS2 to ifcfg-* files if missing
  lineinfile
:
    path
: "{{ net_path }}{{ item }}"
    state
: present
    regexp
: "^DNS2"
    line
: "DNS2={{ dns2 }}"
  with_items
: "{{ ifcfg_list.stdout_lines }}"
  ignore_errors
: yes
  notify
:
   
- Networking

Here is how far I get:

How do I incorporate:
"{{ ifcfg_list.stdout_lines }}"

That allows me to loop through all ifcfg-* files (except ifcfg-lo)

-
name: Add DNS to ifcfg-* files if missing
  lineinfile
:
    path
: "{{ net_path }}{{ item.nic }}" #<--- This item is no longer reference by ifcfg_list.stdout_lines
    state
: present
    regexp
: "{{ item.regexp }}"
    line
: "{{ item.line }}"
  with_items
:
    - {
regexp: "
^DNS1", line: "DNS1={{ dns1 }}", nic: "ifcfg_list.stdout_lines"} #<--- The nic section of these looks incorrect to me, and I doubt it would work
    -
{regexp: "^DNS2", line: "DNS2={{ dns2 }}", nic: "ifcfg_list.stdout_lines"}
  ignore_errors: yes
  notify
:
   
- Networking

Kai Stian Olstad

unread,
Jan 25, 2018, 2:26:40 PM1/25/18
to ansible...@googlegroups.com
On Thursday, 25 January 2018 18.38.36 CET John Harmon wrote:
> How do I incorporate:
> "{{ ifcfg_list.stdout_lines }}"
>
> That allows me to loop through all ifcfg-* files (except ifcfg-lo)
>
> - name: Add DNS to ifcfg-* files if missing
> lineinfile:
> path: "{{ net_path }}{{ item.nic }}" #<--- This item is no longer
> reference by ifcfg_list.stdout_lines
> state: present
> regexp: "{{ item.regexp }}"
> line: "{{ item.line }}"
> with_items:
> - {regexp: "^DNS1", line: "DNS1={{ dns1 }}", nic:
> "ifcfg_list.stdout_lines"} #<--- The nic section of these looks incorrect
> to me, and I doubt it would work
> - {regexp: "^DNS2", line: "DNS2={{ dns2 }}", nic:
> "ifcfg_list.stdout_lines"}
> ignore_errors: yes
> notify:
> - Networking

Use the find module to search for the files and exclude the ifcfg-lo and register the result.

Then you can use the with_nested in the lineinfile.


--
Kai Stian Olstad

John Harmon

unread,
Jan 25, 2018, 5:31:08 PM1/25/18
to Ansible Project
I tried the following, but it failed.  Likely some syntax issues (doesn't like my var).  I am having a hard time finding comprehensive docs on with_nested.  I will keep trying, but if you have some suggestions, I am all ears.

- name: Add DNS entries to ifcfg-* files if missing
  lineinfile
:
    path
: "{{ net_path }}{{ item[0] }}"
    state
: present
    regexp
: "{{ item[1] }}"
    line
: "{{ item[2] }}"
  with_nested
:
   
- ifcfg_list.stdout_lines
   
- [ '^DNS1', '^DNS2' ]
   
- [ 'DNS1={{ dns1 }}', 'DNS2={{ dns2 }}' ]

Failed message:
failed: [ansible-oel6] (item=[u'ifcfg_list.stdout_lines', u'^DNS1', u'DNS1=10.253.1.23']) => {"changed": false, "item": ["ifcfg_list.stdout_lines", "^DNS1", "DNS1=10.253.1.23"], "msg": "Destination /etc/sysconfig/network-scripts/ifcfg_list.stdout_lines does not exist !", "rc": 257}


John Harmon

unread,
Jan 25, 2018, 5:33:46 PM1/25/18
to Ansible Project
I may have fixed it... change - ifcfg_list.stdout_lines to - "{{ ifcfg_list.stdout_lines }}".  I need to go look at the results to see if they are what I expected.
Message has been deleted

John Harmon

unread,
Jan 25, 2018, 5:46:29 PM1/25/18
to Ansible Project
It ultimately does what I want, but changes stuff every time.  I can't figure out the logic that is doing that.  Any ideas?
TASK [dns_update : Add DNS entries to ifcfg-* files if missing] **************************************************************************************************************************************************************************
ok
: [ansible-oel7] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS1=10.1.1.10'])
ok
: [ansible-oel6] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS1=10.1.1.10'])
ok
: [ansible-rhel6] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS1=10.1.1.10'])
ok
: [ansible-rhel7] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS1=10.1.1.10'])
changed
: [ansible-rhel6] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS2=10.1.1.11'])
changed
: [ansible-oel7] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS2=10.1.1.11'])
changed
: [ansible-oel6] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS2=10.1.1.11'])
changed
: [ansible-rhel7] => (item=[u'ifcfg-eth0', u'^DNS1.*', u'DNS2=10.1.1.11'])
changed
: [ansible-oel7] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS1=10.1.1.10'])
changed
: [ansible-rhel6] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS1=10.1.1.10'])
changed
: [ansible-oel6] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS1=10.1.1.10'])
changed
: [ansible-rhel7] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS1=10.1.1.10'])
ok
: [ansible-oel7] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS2=10.1.1.11'])
ok
: [ansible-oel6] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS2=10.1.1.11'])
ok
: [ansible-rhel6] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS2=10.1.1.11'])
ok
: [ansible-rhel7] => (item=[u'ifcfg-eth0', u'^DNS2.*', u'DNS2=10.1.1.11'])


John Harmon

unread,
Jan 25, 2018, 6:53:57 PM1/25/18
to Ansible Project
The more I read about this, the more I think it is working out of luck.  In fact, I don't understand how it is working now based on the output previously mentioned.  According to that both DNS1 and DNS2 should be pointing to dns2 or 10.1.1.11.  Thoughts?

Kai Stian Olstad

unread,
Jan 26, 2018, 2:34:49 AM1/26/18
to ansible...@googlegroups.com
Your nested has 3 levels and that gets you in trouble since you get this
four combinations
ifcfg-eth0 , ^DNS1.* , DNS1=10.1.1.10
ifcfg-eth0 , ^DNS1.* , DNS2=10.1.1.11
ifcfg-eth0 , ^DNS2.* , DNS1=10.1.1.10
ifcfg-eth0 , ^DNS2.* , DNS2=10.1.1.11

But you only want these two
ifcfg-eth0 , ^DNS1.* , DNS1=10.1.1.10
ifcfg-eth0 , ^DNS2.* , DNS2=10.1.1.11

So try this

- name: Add DNS entries to ifcfg-* files if missing
lineinfile:
path: "{{ net_path }}{{ item[0] }}"
state: present
regexp: "^{{ item[1] }}"
line: "{{ item[1] }}={{ vars[item[1] | lower] }}"
with_nested:
- '{{ ifcfg_list.stdout_lines }}'
- [ 'DNS1', 'DNS2' ]


--
Kai Stian Olstad

--
Kai Stian Olstad

John Harmon

unread,
Jan 26, 2018, 11:43:13 AM1/26/18
to Ansible Project
Kai, thank you.  That is awesome.  I wouldn't have thought of that.  I do have some follow-up questions, just to understand.

line: "{{ item[1] }}={{ vars[item[1] | lower] }}"
What does the = sign do here?  Is it overriding the with_nested item[1]?
What is vars specifying?  If I came close to ever doing this on my own I wouldn't have added vars.... so I am curious.
I know what the rest of it is doing, but am a little fuzzy in regards to the two things above.
 

Kai Stian Olstad

unread,
Jan 26, 2018, 12:32:53 PM1/26/18
to ansible...@googlegroups.com
On Friday, 26 January 2018 17.43.12 CET John Harmon wrote:
>
> On Friday, January 26, 2018 at 12:34:49 AM UTC-7, Kai Stian Olstad wrote:
> >
> > So try this
> >
> > - name: Add DNS entries to ifcfg-* files if missing
> > lineinfile:
> > path: "{{ net_path }}{{ item[0] }}"
> > state: present
> > regexp: "^{{ item[1] }}"
> > line: "{{ item[1] }}={{ vars[item[1] | lower] }}"
> > with_nested:
> > - '{{ ifcfg_list.stdout_lines }}'
> > - [ 'DNS1', 'DNS2' ]
> >
> >
> >
>
> Kai, thank you. That is awesome. I wouldn't have thought of that. I do
> have some follow-up questions, just to understand.

I'll try to explain.


> line: "{{ item[1] }}={{ vars[item[1] | lower] }}"
> What does the = sign do here? Is it overriding the with_nested item[1]?

The = sign is just the = sign.
In the first iteration the "item[1] = DNS1".
You need you the line in the file to be DNS1=10.1.1.10

So {{ item[0] }} would be replaced by the content, so it becomes DNS1, we need the character = to get DNS=


> What is vars specifying? If I came close to ever doing this on my own I
> wouldn't have added vars.... so I am curious.

Your DNS IP is in the variable named dns, to use the content of a variable as a variable name you need to use vars or hostvars.
vars if the same as hostvars[inventory_hostname].

item[1] is DNS (upper case) but the variable name is dns (lower case) so "vars[item[1] | lower]" becomes vars['dns'] that is the same {{ dns }} and you get 10.1.1.10.


> I know what the rest of it is doing, but am a little fuzzy in regards to
> the two things above.

Hopefully my explanation is understandable.


--
Kai Stian Olstad

Malcolm Hussain-Gambles

unread,
Jan 26, 2018, 3:18:36 PM1/26/18
to Ansible Project
If you are editing these files the inifile module is much better btw. Take a look

John Harmon

unread,
Jan 26, 2018, 3:22:48 PM1/26/18
to Ansible Project
Kai, perfect, thank you.  It can get confusing looking at the various variables and {{items}}.  Your explanation makes sense.


John Harmon

unread,
Jan 26, 2018, 3:23:03 PM1/26/18
to Ansible Project


On Friday, January 26, 2018 at 1:18:36 PM UTC-7, Malcolm Hussain-Gambles wrote:
If you are editing these files the inifile module is much better btw. Take a look

Thanks, I will.

John Harmon

unread,
Jan 26, 2018, 3:42:51 PM1/26/18
to Ansible Project
Malcom!  Thanks for info on the ini_file module!  That will be much better to use.....now I can cut back on the horribly complicated regexp stuff!


On Friday, January 26, 2018 at 1:18:36 PM UTC-7, Malcolm Hussain-Gambles wrote:

Malcolm Hussain-Gambles

unread,
Jan 27, 2018, 2:34:03 PM1/27/18
to Ansible Project
Another one to look at is the newly added xml module, if you have to suffer the pain of xml config files.
Reply all
Reply to author
Forward
0 new messages