[Nornir:将Python函数传递给Jinja2模板

问题描述 投票:1回答:1

我正在使用Nornir自动化网络设备的配置。在我的Jinja2模板中,我想调用Python函数为我做一个子网计算。我似乎无法弄清楚如何使Jinja2具有以Nornir作为驱动程序调用Python函数的功能。

错误输出:

**** Nornir Playbook to generate site configurations ***************************
device_config*******************************************************************
* router01 ** changed : False **************************************************
vvvv device_config ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ERROR
Subtask: <function template_file at 0x7f547c2418c8> (failed)

---- Device Configuration ** changed : False ----------------------------------- ERROR
Traceback (most recent call last):
  File "/home/user1234/venv/lib/python3.6/site-packages/nornir/core/task.py", line 85, in start
    r = self.task(self, **self.params)
  File "/home/user1234/venv/lib/python3.6/site-packages/nornir/plugins/tasks/text/template_file.py", 
  line 35, in template_file
    **kwargs
  File "/home/user1234/venv/lib/python3.6/site-packages/nornir/core/helpers/jinja_helper.py", line 
  18, in render_from_file
    return t.render(**kwargs)
  File "/home/user1234/venv/lib/python3.6/site-packages/jinja2/asyncsupport.py", line 76, in render
    return original_render(self, *args, **kwargs)
  File "/home/user1234/venv/lib/python3.6/site-packages/jinja2/environment.py", line 1008, in render
    return self.environment.handle_exception(exc_info, True)
  File "/home/user1234/venv/lib/python3.6/site-packages/jinja2/environment.py", line 780, in 
  handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/user1234/venv/lib/python3.6/site-packages/jinja2/_compat.py", line 37, in reraise
    raise value.with_traceback(tb)
  File "./templates/router_master_config.j2", line 52, in top-level template code
    {% include 'router01_interfaces.j2' %}
  File "./templates/router01_interfaces.j2", line 17, in top-level template code
    description VLAN 3000 - WAN Interlink {{ calculate_subnet() }}
jinja2.exceptions.UndefinedError: 'calculate_subnet' is undefined

^^^^ END device_config ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Process finished with exit code 0

Jinja2模板部分:

interface Port-channel10.1000
 description VLAN 1000 - WAN {{ calculate_subnet(host.interfaces[2]['ipv4_addr'], host.interfaces[2]['ipv4_mask'] ) }}
 encapsulation dot1Q 1000
 ip address {{ host.interfaces[2]['ipv4_addr'] }} {{ host.interfaces[2]['ipv4_mask']}}
 ip nbar protocol-discovery
 bfd interval 750 min_rx 750 multiplier 4
 no shutdown

Python脚本:

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


def device_config(task):
    # Transform inventory data to configuration via a template file
    var = task.run(task=text.template_file,
                   name="Device Configuration",
                   template="router_master_config.j2",
                   path=f"./templates/"
                   )

    # Save the compiled configuration into a host variable
    task.host["config"] = var.result


def calculate_subnet(ip,mask):
    # Hard coding subnet for testing
    subnet = "10.10.10.0/24"
    # Calculation will happen here
    return subnet


def main():
    nr = InitNornir(config_file="config.yaml", dry_run=False)
    print_title("Nornir Playbook to generate site configurations")
    routers = nr.filter(device_type="router")
    task = routers.run(task=device_config)
    print_result(task)


if __name__ == "__main__":
    main()
python jinja2
1个回答
0
投票

如果跟踪nornir.core.task.run的代码,您会发现它只是将关键字参数传递给插件,最终传递给t.render中的nornir.core.helpers.jinja_helper.render_from_file

因此,您可以简单地将函数对象作为附加关键字参数传递给task.run,以使其在模板的名称空间中可用:

var = task.run(task=text.template_file,
               name="Device Configuration",
               template="router_master_config.j2",
               path=f"./templates/",
               calculate_subnet=calculate_subnet
               )
© www.soinside.com 2019 - 2024. All rights reserved.