# Network config modules (eos\_config, ios\_config) fuzzy matching lines, and what is the "config" parameter?

**URL:** <https://forum.ansible.com/t/network-config-modules-eos-config-ios-config-fuzzy-matching-lines-and-what-is-the-config-parameter/23992>\
**Category:** Ansible Project\
**Created:** [March 17, 2017, 1:23am UTC](https://forum.ansible.com/t/network-config-modules-eos-config-ios-config-fuzzy-matching-lines-and-what-is-the-config-parameter/23992 "2017-03-17T01:23:09Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![bboudrias](https://avatars.discourse-cdn.com/v4/letter/b/d9b06d/32.png) [@bboudrias](https://forum.ansible.com/u/bboudrias)\
**Post date:** [March 17, 2017, 1:23am UTC](https://forum.ansible.com/t/network-config-modules-eos-config-ios-config-fuzzy-matching-lines-and-what-is-the-config-parameter/23992/1 "2017-03-17T01:23:09Z")

</div>

Heya,

**TLDR, the summary:** I’m trying to use Ansible 2.2’s network modules to manage configs on EOS/IOS switches. I’m trying to find a module invocation that adds a number of, say, radius-server commands, removes any that aren’t expected, and also diff properly before applying config so I can accurately measure which switches were already correctly configured and which weren’t. What follows is my series of attempts at making this work before I was out of options short of doing the config diffs manually.

So for example, I want to write a task that manages the radius-server lines on an EOS device. The existing config might be…

`  
radius-server host 1.1.1.1  
radius-server host 2.2.2.2  
radius-server host 3.3.3.3

`

…and I want to replace it with my good configuration:

`radius-server host 2.2.2.2 radius-server host 3.3.3.3`

BUT, I don’t know what the original two lines are for sure. Maybe they’re as above, or maybe one of them is actually 4.4.4.4 instead. So what I’m really trying to do is remove any lines that begin with “radius-server host …” and then add on the two good config lines. I can’t find a way to make this work that accurately diffs the running config and avoids pushing changes if the lines already match.

I found a couple ‘workarounds’ but they each suffer from this problem. One of them is to use ‘before’ and run ‘no radius-server host’, nuking the existing config and replacing it with my good config:

`

- name: Install new RADIUS server config.  
eos\_config:  
provider: “{{ cli\_connection\_info }}”  
lines:
- radius-server host 1.1.1.1 vrf mgmt
- radius-server host 2.2.2.2 vrf mgmt  
before: “no radius-server host”  
match: none  
replace: block  
save: yes

`

“match” has to be “none” because if both of my good config lines are on the device, but there’s a third “radius-server host …” configured, I want to remove it. The above task accomplishes that but it always detects a diff, which means I can’t dry-run the play and I don’t get any feedback on how many devices in the fleet were actually different from the intended configuration.

But an even bigger problem is that not all OSs/versions support a generic “no …” command as used above. IOS, for example, will not accept “no radius-server host”; an IP must be specified, so I must somehow know what “bad” IPs are already configured before running the config module. And, I’m trying to eliminate config drift so I don’t know what those IPs are off hand. So here’s another workaround:

`

- name: Get current RADIUS server config.  
ios\_command:  
provider: “{{ cli\_connection\_info }}”  
commands: “show running-config | include radius-server host”  
register: current\_config

- name: Build cleanup commands.  
set\_fact:  
ios\_radius\_commands\_to\_remove: |  
{% set output = %}  
{% for existing\_line in current\_config.stdout\_lines[0] %}  
{% if existing\_line %}  
{% set \_ = output.append('no ’ + existing\_line) %}  
{% endif %}  
{% endfor %}  
{{ output }}

- name: Cleanup old and install new config.  
ios\_config:  
provider: “{{ cli\_connection\_info }}”  
before: “{{ ios\_radius\_commands\_to\_remove }}”  
lines:

- radius-server host 1.1.1.1 vrf mgmt

- radius-server host 2.2.2.2 vrf mgmt  
match: none  
replace: block

`

This makes sure I catch all unknown, bad lines of config and works on pretty much every platform I care about but it too needs to be forced with ‘match: none’ to work; especially on platforms that don’t support config sessions or a similar diff mechanism.

So the last thing I tried was the ‘config’ parameter. From its documentation, I understand it to be a user-provided parameter to replace the auto-fetched running-config from a device. To illustrate this understanding, I would expect something like this to _never_ report a diff and not even connect to the device:

`

- name: Install RADIUS server config.  
ios\_config:  
provider: “{{ cli\_connection\_info }}”  
config:
- radius-server host 1.1.1.1 vrf mgmt
- radius-server host 2.2.2.2 vrf mgmt  
lines:
- radius-server host 1.1.1.1 vrf mgmt
- radius-server host 2.2.2.2 vrf mgmt  
match: line  
replace: line

`

But, it does. The module still reports a diff and pushes the content of ‘lines’ to the device. I can’t discern any difference in behavior when using the config parameter.

So, does anyone else have a good way of doing this? At this point I can only assume I went the wrong way on some really simple assumption or the module doesn’t support this behavior. But the ability to specify a class of config that could be unexpected and should be pruned is such a useful feature, a config management system is incomplete without it.

---

<div class="post-metadata">

**Author:** ![bill\_paxton](https://avatars.discourse-cdn.com/v4/letter/b/46a35a/32.png) [@bill\_paxton](https://forum.ansible.com/u/bill_paxton)\
**Post date:** [March 27, 2017, 11:36pm UTC](https://forum.ansible.com/t/network-config-modules-eos-config-ios-config-fuzzy-matching-lines-and-what-is-the-config-parameter/23992/2 "2017-03-27T23:36:47Z")

</div>

I did something similar for NTP on IOS, maybe this will help you:

1. Provide a list of NTP server addresses I want provisioned

`

- { role: ntp, state: present,  
ntp\_source\_interface: Vlan10,  
ntp\_servers:  
[[0.us.pool.ntp.org](http://0.us.pool.ntp.org),  
1.1.1.1,  
2.2.2.2,  
3.3.3.3,  
4.4.4.4 ] }

`

Later finding the NTP servers that may already be there on the IOS device. In a past role, I obviously collected “show running-config” and set\_fact “config” to hold that. The regex\_findall returns a list of all the ip address instances for ‘ntp server’ lines

`

- name: get current configured ntp servers  
set\_fact: old\_ntp\_servers=“{{ config | regex\_findall(‘ntp server (.+)\n’) }}”

- name: get current configured ntp source  
set\_fact: old\_ntp\_source=“{{ config | regex\_findall(‘ntp source (.+)\n’) }}”

- name: configure ios ntp parameters  
ios\_template:  
src: “{{ state }}/ios.j2”  
config: “{{ config }}”  
provider: “{{ provider }}”

`

And then the template “ios.j2”, basically I let Ansible’s idempotency handle whether or not to issue “ntp server” commands. And later I check for any ntp servers that were previously configured (remember I collected these in old\_ntp\_servers above) that are not in the list of ntp servers I want configured (ntp\_servers) and then issue the “no ntp server” for those.

`

!

# Let Ansible idempotency decide for each line if the command needs to be issued

{% if ntp\_source\_interface is defined %}  
ntp source {{ ntp\_source\_interface }}  
{% endif%}  
!

# Let Ansible idempotency decide for each line if the command needs to be issued

{% if ntp\_servers is defined %}  
{% for ntp\_item in ntp\_servers %}  
ntp server {{ ntp\_item }}  
{% endfor %}  
!

# If there are any ntp servers still listed that aren’t in the list provided by

# the user, remove them (compliance).

{% for old\_ntp\_item in old\_ntp\_servers %}  
{% if old\_ntp\_item | lower not in ntp\_servers | lower %}  
no ntp server {{ old\_ntp\_item }}  
{% endif %}  
{% endfor %}  
{% endif%}  
!

`

Hope this gives you some ideas
