02-21-2018 05:43 AM - edited 03-01-2019 04:06 AM
I got into a little discussion about jinja templates the other day and ended up putting together a little example that I thought might be of interest to others. Note that the approach demonstrated here is a little bit fragile, it depends on the way the NSO cli would interpret the template. But, as long as your template is in cisco ios format it should work fairly well.
Also, note that the xml templates are checked against the model at load time, and gives much more robustness than this approach. However especially for experiments in the development phase using templates looking more like dumps from the device can be attractive.
#!/usr/bin/env python
from jinja2 import Environment, FileSystemLoader
import ncs
import _ncs.maapi as maapi
import socket
# Make sure to set /ncs-config/cli/use-expose-ns-prefix to false in ncs.conf
def loadJinja(device, file, data,
sock=None, th=None, apply_trans=True):
# Load and apply jinja2 template
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template(file)
t = template.render(data)
print t
# If no socket is given
if sock is None:
sock = socket.socket()
maapi.connect(sock, '127.0.0.1', ncs.NCS_PORT)
trans = None
# Setup a maapi transaction as admin
if th is None:
maapi.start_user_session(sock, 'admin', 'foo', [],'127.0.0.1',ncs.PROTO_TCP)
th = maapi.start_trans(sock, ncs.RUNNING, ncs.READ_WRITE)
# Load config
maapi.load_config_cmds(sock, th, maapi.CONFIG_MERGE | maapi.CONFIG_C_IOS, t, "/devices/device{%s}/config" % (device))
# Apply trans
if apply_trans:
maapi.apply_trans(sock, th, False)
# Example usage
fn = "ios.j2"
device = "ios0"
data = { "ip_addr" : "192.168.1.3", "ip_mask" : "255.255.255.0",
"routes" : [ { "network" : "0.0.0.0", "mask" : "0.0.0.0", "gw" : "192.168.1.254"}]}
loadJinja(device, fn, data)
ios.j2 is:
interface GigabitEthernet0/1
ip address {{ ip_addr }} {{ ip_mask }}
exit
{% for route in routes %}
ip route {{ route.network }} {{ route.mask }} {{ route.gw }}
{% endfor %}
Also, note that if use-expose-ns-prefix is true, or if there are conflicts between different namespaces you would have to type ios:interface and ios:ip.
11-26-2021 02:12 PM - edited 11-29-2021 01:26 AM
Thank you @vleijon for this example. it is enlightening!
Would anyone be so kind to comment how the same can be accomplished, if possible using XML?
For example,
_ncs.maapi.load_config(mgmt.msock, trxn.th, _ncs.maapi.CONFIG_XML, "light.xml") trxn.apply()
where the contents of light.xml are
(after removing the element <config-template xmlns="http://tail-f.com/ns/config/1.0">)
<devices xmlns="http://tail-f.com/ns/ncs"> <device> <name>nokia-lab03c-ra2</name> <config> <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf"> <port> <port-id tags="replace">1/1/c30</port-id> <description tags="replace">* ip-spotlight * omega * note: proof-of-concept *</description> </port> </configure> </config> </device> </devices>
complains about
Error: Python cb_action error. external error (19): Error on line 6: no mount id exists for: /ncs:devices/ncs:device[ncs:name='nokia-lab03c-ra2']/ncs:config
What I am doing wrong? Will the tags xml attribute in the .xml file be recognised and acted upon?
PS. ncs_load is recognising the router, the following succeeds
$ ncs_load -P "/ncs:devices/ncs:device[ncs:name='nokia-lab03c-ra2']/ncs:config" -Fp
with kind regards,
Niko
11-26-2021 03:14 PM
11-27-2021 11:37 PM - edited 11-28-2021 01:34 AM
Thanks a lot @vleijon _ncs.maapi.CONFIG_MERGE did the trick
There is also _ncs.maapi.CONFIG_REPLACE (https://github.com/NSO-developer/ntool/blob/master/ntool/ntool_modules/ntool_template.py) with an inherent "delete" operation I guess, with a purpose which is not clear to me and not working either (same error), which is not important because
the flag _ncs.maapi.CONFIG_MERGE together with honouring the tags xml attribute would be the global solution supporting all operations (replace, delete, etc.)
but, when applying the above .xml document on the router it results in
@ncs> show configuration devices device nokia-lab03c-ra2 config conf:configure port 1/1/c30
/* Tags: delete */
description "* ip-spotlight * omega * note: proof-of-concept *";
which means the tags xml attribute is not respected, the interface description is still there.
Question: Is there a way for CiscoNSO to respect the tags xml attribute when loading xml-based configuration?
The method _ncs.maapi.apply_template respects the tags xml attribute. What is the extra call that it makes and honours the tags xml attribute?
11-29-2021 12:35 AM
The "tags" XML attribute is interpreted by NSO/ConfD as tag information that is intended to be used for data organization and filtering purposes.
You may use the "operation" XML attribute which is interpreted by NSO MAAPI load_config when merging the same way the "operation" attribute is used in a NETCONF <edit-config> operation as described in the NETCONF RFC 6241, https://datatracker.ietf.org/doc/html/rfc6241#page-38 and YANG RFC 7950, for example under https://datatracker.ietf.org/doc/html/rfc7950#section-7.6.7.
I.e. a CONFIG_MERGE with the below "operation" XML attribute will delete the description leaf data.
<description operation="delete">* ip-spotlight * omega * note: proof-of-concept *</description>
The "operation" attribute is briefly described in the ncs(1) man page for the "--mergexmlfiles" flag, and should be added to the MAAPI load_config documentation too. (Note taken).
11-29-2021 01:25 AM
a w e s o m e ! thank you!
12-28-2021 05:07 AM
Thank you @vleijon @cohult for your help so far.
I was exploring the above example around _ncs.maapi.load_config_cmds and I am not sure if I understand this correctly. More specifically,
In case of ios-based operating systems, nso does not accept the above template unless the ios: namespace is used. For example, this works
cmds = """ ios:interface Loopback 12 description "* ip-spotlight * omega * note: proof-of-concept * xxx *" exit """
In case of sros operating systems, nso requires the conf:configure part. The following works
cmds = """ conf:configure port 1/1/c30 description "* ip-spotlight * omega * note: proof-of-concept *" """
The problem with the above approaches is that it misses out additional capabilities present in junos- or sros- based operating systems, that nso supports though.
More specifically, the delete or insert __ before/after __ configuration statements. For example,
@ncs% insert devices device nokia-lab03c-ra2 config conf:configure router Base bgp group abc export policy MARKET-X before REJECT-ALL
in this case, the insert knob is placed before namespace conf:configure and the before is placed after the namespace conf:configure hence _ncs.maapi.load_config_cmds doesn't fit the purpose I think.
The native way looks like this:
insert router Base bgp group abc export policy MARKET-X before REJECT-ALL
Given
I was wondering
with kind regards,
Nikos
01-06-2022 11:45 AM
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide