Help with Jinja2 template error

I am trying to render a Jinja2 template from data I have added to the task.host object, but getting a traceback… The end of the traceback I’m getting is:

  File "templates/junos/vc_interfaces.j2", line 2, in template
    {{ for interface in host.data['front_ports'] }}
  File "/Users/will/PycharmProjects/nornir_learning/venv/lib/python3.7/site-packages/jinja2/environment.py", line 497, in _parse
    return Parser(self, source, name, encode_filename(filename)).parse()
  File "/Users/will/PycharmProjects/nornir_learning/venv/lib/python3.7/site-packages/jinja2/parser.py", line 901, in parse
    result = nodes.Template(self.subparse(), lineno=1)
  File "/Users/will/PycharmProjects/nornir_learning/venv/lib/python3.7/site-packages/jinja2/parser.py", line 876, in subparse
    self.stream.expect('variable_end')
  File "/Users/will/PycharmProjects/nornir_learning/venv/lib/python3.7/site-packages/jinja2/lexer.py", line 384, in expect
    self.name, self.filename)
jinja2.exceptions.TemplateSyntaxError: expected token 'end of print statement', got 'interface'

My code currently stands as:

import re
from nornir import InitNornir
from nornir.plugins.tasks import networking, text
from nornir.plugins.functions.text import print_result

nr = InitNornir(config_file="config.yaml", core={'num_workers': 1}, dry_run=True)

target = nr.filter(hostname="192.168.1.170")


def do_stuff(task):
    resobj = task.run(task=networking.napalm_get,
                      getters=['facts'])

    # obtain list of all interfaces from the result facts
    intlist = resobj[0].result['facts']['interface_list']

    # Create list of front ports
    front_ports = []
    p = re.compile('ge-\d+')
    for int in intlist:
        mch = p.match(int)
        if mch:
            front_ports.append(int)

    task.host['front_ports'] = front_ports
    print(task.host.data['front_ports'])  # FOR DEBUGGING

    rt = task.run(task=text.template_file,
                  name="Generate Front Port Config",
                  template="vc_interfaces.j2",
                  path=f"templates/{task.host.platform}")

    print_result(rt)


target.run(task=do_stuff)

And the template as:

interfaces {
    {{ for interface in host.data['front_ports'] }}
    {{ interface }} {
        unit 0 {
            family ethernet-switching {
                port-mode access;
            }
        }
    }
    {{ endfor }}
}

I determined that the interface list I generated is stored in task.host.data['front_ports'] and so am using host.data['front_ports'] in the j2 template; is that correct syntax to call the list? Or do I have some sort of other issue with the .j2 template?

One obvious error here is that your for loop uses two curly brackets when they should use {% and %}

interfaces {
    {% for interface in host.data['front_ports'] %}
    {{ interface }} {
        unit 0 {
            family ethernet-switching {
                port-mode access;
            }
        }
    }
    {% endfor %}
}

hangs head in shame

There’s always a syn tax.

Modified template to:

interfaces {
{% for interface in host.data['front_ports'] %}
    {{ interface }} {
        unit 0 {
            family ethernet-switching {
                port-mode access;
            }
        }
    }
{% endfor %}
}

and now working :slight_smile:

Thanks!