0

I have the following playbook, jinja template and yaml data. I am running this against a Cisco 9300 or 3850 switch. I just get the following error. If I run just the commands without the template the playbook runs fine. I have output the template to a yaml file and I don't see any issues with the output. The command in the error below is a valis command.

fatal: [3850-access-42]: FAILED! => {
    "changed": false,
    "module_stderr": "before: default interface GigabitEthernet2/0/1\r\nbefore: default interface GigabitEthernet2/0/1\r\n  ^\r\n% Invalid input detected at '^' marker.\r\n\r\n3850-Access-(config)#",
    "module_stdout": "",
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error"
}

Playbook

- name: Update edge switch
  hosts: all
  gather_facts: false
  vars:
    - template_path: "./templates/interfaces.j2"

  tasks:

    - name: include variables
      include_vars: "./files/vars/jinja-test-data.yml"

    - name: update config
      cisco.ios.ios_config:
        src: "{{ template_path }}"

jinja template

{% for item in ip_interfaces %}
  before: default interface {{ item.interface }}
  lines:
{% for line in item.int_attributes %}
  - {{ line }}
{% endfor %}
  parents: interface {{ item.interface }}
  match: strict
  after:
{% for cmd in item.shut_commands %}
  - {{ cmd }}
{% endfor %}
{% endfor %}

yaml data

---

ip_interfaces:
  - interface: GigabitEthernet2/0/1
    int_attributes:
      - switchport access vlan 20
      - switchport voice vlan 21
      - speed 100
      - duplex full
      - switchport mode access
      - switchport nonegotiate
      - no switchport port-security
      - spanning-tree portfast
      - spanning-tree bpduguard enable
      - device-tracking attach-policy IPDT_POLICY
      - source template WIRED_DOT1X_CLOSED
    shut_commands:
      - shutdown
      - no shutdown

If I run the playbook without the template using the same data it runs fine.

Working playbook

- name: Update edge switch
  hosts: all
  gather_facts: false
  vars:
    - template_path: "./templates/interfaces.j2"

  tasks:

    - name: include variables
      include_vars: "./files/vars/jinja-test-data.yml"

    # - name: update config
    #   cisco.ios.ios_config:
    #     src: "{{ template_path }}"




    - name: update config
      cisco.ios.ios_config:
        before: default interface TwoGigabitEthernet1/0/1
        lines:
        - switchport access vlan 10
        - switchport voice vlan 11
        - speed 100
        - duplex full
        - switchport mode access
        - switchport nonegotiate
        - no switchport port-security
        - spanning-tree portfast
        - spanning-tree bpduguard enable
        - device-tracking attach-policy IPDT_POLICY
        - source template WIRED_DOT1X_CLOSED
        parents: interface TwoGigabitEthernet1/0/1
        match: strict
        after:
        - shutdown
        - no shutdown
      vars:
        ansible_command_timeout: 480

Results from working playbook

TASK [update config] *************************************************************************************************** task path: redirecting (type: connection) ansible.builtin.network_cli to ansible.netcommon.network_cli redirecting (type: terminal) ansible.builtin.ios to cisco.ios.ios redirecting (type: cliconf) ansible.builtin.ios to cisco.ios.ios redirecting (type: action) cisco.ios.ios_config to cisco.ios.ios redirecting (type: action) cisco.ios.ios_config to cisco.ios.ios [WARNING]: To ensure idempotency and correct diff the input configuration lines should be similar to how they appear if present in the running configuration on device changed: [9300-access-240] => {"banners": {}, "changed": true, "commands": ["default interface TwoGigabitEthernet1/0/1", "interface TwoGigabitEthernet1/0/1", "switchport voice vlan 11", "speed 100", "duplex full", "switchport mode access", "switchport nonegotiate", "no switchport port-security", "spanning-tree portfast", "spanning-tree bpduguard enable", "device-tracking attach-policy IPDT_POLICY", "source template WIRED_DOT1X_CLOSED", "shutdown", "no shutdown"], "updates": ["default interface TwoGigabitEthernet1/0/1", "interface TwoGigabitEthernet1/0/1", "switchport voice vlan 11", "speed 100", "duplex full", "switchport mode access", "switchport nonegotiate", "no switchport port-security", "spanning-tree portfast", "spanning-tree bpduguard enable", "device-tracking attach-policy IPDT_POLICY", "source template WIRED_DOT1X_CLOSED", "shutdown", "no shutdown"]} META: ran handlers META: ran handlers

PLAY RECAP ************************************************************************************************************* hav-lab-9300-access-240 : ok=2 changed=1 unreachable=0
failed=0 skipped=0 rescued=0 ignored=0

  • Show how the playbook runs fine without the template. – Vladimir Botka Sep 26 '22 at 05:01
  • @VladimirBotka I added addtional information to the thread showing the working playbook and the successful result. – Paul in Colorado Sep 26 '22 at 13:32
  • 1
    The format of the file, created by the template, should be a Cisco configuration file. Not Ansible YAML format of the parameters, I think. See the last [example](https://docs.ansible.com/ansible/latest/collections/cisco/ios/ios_config_module.html#examples). – Vladimir Botka Sep 26 '22 at 14:28
  • @VladimirBotka Yep, that was it. I wish I had seen your reply sooner, but we ended up in the same place. Thank you. – Paul in Colorado Sep 26 '22 at 18:51

1 Answers1

0

I figured this out finally. It seems that the ios_config module assumes the lines: command so it is not needed in the template output. All of the lines do not need to be preceeded by the "- " as they would in a normal playbook call directly to the ios_config module. If there is a parent object the subsequent lines are indented by one space. This is plainly shown in the docs which I did not pick up as soon as I wished I had. I hope this helps someone else out or saves them some time. Now I just need to figure out if the before or after command can be used as well. It would be a shame to have to loop through three different templates and hit the interfaces three seperate times.

> # Example ios_template.j2
> # ip access-list extended test
> #  permit ip host 192.0.2.1 any log
> #  permit ip host 192.0.2.2 any log
> #  permit ip host 192.0.2.3 any log
> #  permit ip host 192.0.2.4 any log