1

I have a Jinja2 template I am using for Cisco IOS devices. Currently my playbook runs fine, but always shows "changed" despite there being no obvious changes... I ran with the verbose tag and received the output below, but didn't see anything obvious. Is this normal behavior, and if not does anyone know of a work around/better way to accomplish this?

Debug output:

changed: [Parakoopa891F] => {
    "banners": {},
    "changed": true,
    "commands": [
        "interface Vlan 200",
        "description DMZ created by Ansible",
        "ip address 10.200.200.254 255.255.255.0",
        "ip nat inside",
        "ip virtual-reassembly",
        "zone-member security INSIDE",
        "no shutdown",
        "interface Loopback 30",
        "description Loopback created by Ansible",
        "ip address 172.30.69.254 255.255.255.0",
        "ip nat inside",
        "ip virtual-reassembly",
        "zone-member security INSIDE",
        "no shutdown"
    ],
    "invocation": {
        "module_args": {
            "after": null,
            "backup": false,
            "backup_options": null,
            "before": null,
            "defaults": false,
            "diff_against": null,
            "diff_ignore_lines": null,
            "intended_config": null,
            "lines": null,
            "match": "line",
            "multiline_delimiter": "@",
            "parents": null,
            "provider": null,
            "replace": "line",
            "running_config": null,
            "save_when": "never",
            "src": "interface Vlan 200\n  description DMZ created by Ansible\n  ip address 10.200.200.254 255.255.255.0\n  ip nat inside\n  ip virtual-reassembly\n  zone-member security INSIDE\n    no shutdown\n  interface Loopback 30\n  description Loopback created by Ansible\n  ip address 172.30.69.254 255.255.255.0\n  ip nat inside\n  ip virtual-reassembly\n  zone-member security INSIDE\n    no shutdown\n  "
        }
    },
    "updates": [
        "interface Vlan 200",
        "description DMZ created by Ansible",
        "ip address 10.200.200.254 255.255.255.0",
        "ip nat inside",
        "ip virtual-reassembly",
        "zone-member security INSIDE",
        "no shutdown",
        "interface Loopback 30",
        "description Loopback created by Ansible",
        "ip address 172.30.69.254 255.255.255.0",
        "ip nat inside",
        "ip virtual-reassembly",
        "zone-member security INSIDE",
        "no shutdown"
    ]
}

playbook.yml

---
- name: "Set Router Configuration"
  hosts: routers
  connection: network_cli
  tasks:
    - name: "Apply router config"
      ios_config:
        src: "templates/{{ vendor }}_template.j2"
      when: "'{{ vendor }}' == 'cisco'"

Jinja2 template

interface Vlan 200
  description {{ interfaces.vlans.dmz.description }}
  ip address {{ interfaces.vlans.dmz.ip }}
  ip nat {{ interfaces.vlans.dmz.nat }}
  ip virtual-reassembly
  zone-member security {{ interfaces.vlans.dmz.zone }}
  {% if 'up' in interfaces.vlans.dmz.status %}
  no shutdown
  {% else %}
  shutdown
  {% endif %}
interface Loopback {{ interfaces.loopbacks.test.number}}
  description {{ interfaces.loopbacks.test.description }}
  ip address {{ interfaces.loopbacks.test.ip }}
  ip nat {{ interfaces.loopbacks.test.nat }}
  ip virtual-reassembly
  zone-member security {{ interfaces.loopbacks.test.zone }}
  {% if 'up' in interfaces.loopbacks.test.status %}
  no shutdown
  {% else %}
  shutdown
  {% endif %}
Parakoopa
  • 505
  • 1
  • 9
  • 22
  • I can't immediately tell if this applies to you, but there's a suspiciously relevant looking [FAQ entry about always changed tasks](https://docs.ansible.com/ansible/2.10/network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands) – mdaniel Dec 15 '20 at 02:59
  • 2
    Fix the condition `when: vendor == "cisco"` – Vladimir Botka Dec 15 '20 at 06:35
  • Tried changing the syntax, but the result is the same. The way it is listed in my question still functions. – Parakoopa Dec 15 '20 at 20:37

1 Answers1

0

Not sure if you got to the bottom of this, but I too had a similar issue with my Jinja templates. To resolve it you need to address the whitespace control. if and for statements can add undesirable whitespace, which may not be the same every time so ansible detects a change. To make it Idempotent you can add to the top of each of your templates:

#jinja2: lstrip_blocks: True, trim_blocks: True

Though I think ansible uses trim_blocks by default.

I recommend testing the template using the following online Jinja2 parser and renderer by TTL255: https://j2live.ttl255.com/

Some reading on the subject: https://blog.networktocode.com/post/whitespace-control-in-jinja-templates/ https://ttl255.com/jinja2-tutorial-part-3-whitespace-control/

CreepyRaccoon
  • 826
  • 1
  • 9
  • 19