cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2896
Views
26
Helpful
7
Replies

Loading config using jinja2 templates

vleijon
Cisco Employee
Cisco Employee

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.

7 Replies 7

nikos_skalis
Level 1
Level 1

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

 

That error (no mount id exists for) probably means you are not having a ned id. Either because the device name is completely new or because you are doing replace and not merge. Make sure to use the explicit merge flag in your load.

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?

 

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).

 

a w e s o m e ! thank you!

nikos_skalis
Level 1
Level 1

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


  1. the namespace ios: required in case of ios-based operating systems
  2. the mixing of native configurations statements between nso and other operating systems (see example with sros and insert _ before/after _)

I was wondering

  • Is there a programmatic way (through any api or library) to issue nso-specific configuration statements (for example, insert devices device nokia-lab03c-ra2 config conf:configure router Base bgp group abc export policy MARKET-X before REJECT-ALL) ? 

with kind regards,

Nikos

 

 

I think depends a bit on your NSO version actually, it should accept non ios:-prefix in the later versions.

But, you are right with the after/before thing, that will not work.

Luckily, there are other APIs that will work. Easiest is perhaps to use the move option on maagic list: https://developer.cisco.com/docs/nso/api/#ncs-maagic/ncs.maagic.List
Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the NSO Developer community: