cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2437
Views
5
Helpful
13
Replies

Python data for leaf-least

Fantolino
Level 1
Level 1

I need to populate a template with a list of data in teh XML-template. I know How to do when apply the yang to the XML as in this case

YANG DEFINTION

...

augment /ncs:services {
  list LF3 {
  description "Provo la lisa di policy";
  ...
  leaf-list nbarCat {
    type enumeration {

  ...

 

XML TEMPLATE

    <category>
         <category-type>{/nbarCat}</category-type>
    </category>

 

I'd like to use a variable to be manipulated in my Pyton code. I tried to use a list but it seems it does not work. How can I do?

2 Accepted Solutions

Accepted Solutions

yfherzog
Cisco Employee
Cisco Employee

Hi,

 

In most cases, if you want to manipulate the list elements in python, you'd then have to apply the template for each list element (the template engine doesn't process python objects in the same way it processes data model references)

 

Something like:

 

for entry in service.nbarCat:
  vars.add('FOO', foo(entry))
  template.apply('my-template', vars)
    <category>
         <category-type>{$FOO}</category-type>
    </category>

Hope that answers your question!

View solution in original post

You can use multiple templates.

Have your list-related configs in one template, which you apply iteratively, and have your other configs on a separate template which you apply only once.

 

(In most cases, applying the same configs over and over again as part of the same service should not generate any issues)

View solution in original post

13 Replies 13

yfherzog
Cisco Employee
Cisco Employee

Hi,

 

In most cases, if you want to manipulate the list elements in python, you'd then have to apply the template for each list element (the template engine doesn't process python objects in the same way it processes data model references)

 

Something like:

 

for entry in service.nbarCat:
  vars.add('FOO', foo(entry))
  template.apply('my-template', vars)
    <category>
         <category-type>{$FOO}</category-type>
    </category>

Hope that answers your question!

Hi,

 

Sorry for posting to such an old thread, but what I have a similar case to this one, but I think my question is quite related to this one.

 

Like the OP, I want to manipulate elements of a list in python, but in the same service I use variables that are not part of a list. Applying the template in each loop iteration, messes all my service.

 

What should I do in these cases?

You can use multiple templates.

Have your list-related configs in one template, which you apply iteratively, and have your other configs on a separate template which you apply only once.

 

(In most cases, applying the same configs over and over again as part of the same service should not generate any issues)

Thanks for your reply. After struggling for several hours I think the problem is not related to what I thought.

I have the following yang (simplified):

 

list cr-art {
  key DEVICE; 
  leaf DEVICE {
  ...  
  }
  list ROUTER_VECINO {

    key NOMBRE;
    leaf NOMBRE {
    ...
    }
    list INT_AGREGADO_CONEXION {
      key NOMBRE_INT_AGREGADO;
      leaf NOMBRE_INT_AGREGADO {
      ...
      }
      list PUERTO_LOCAL {
        key NOMBRE;
        leaf NOMBRE {
        ...
        }
        leaf PUERTO_REMOTO {
        ...
        }
      }
    }
  }
}

The template has a part where I have to fill the variable $MIN_LINKS with some python calculations.

 

<interface>
  <name>{/ROUTER_VECINO/INT_AGREGADO_CONEXION/NOMBRE_INT_AGREGADO}</name>
  <description>Conexion con {../NOMBRE} {INT_AGREGADO_REMOTO}</description>
  <minimum-links>{$MIN_LINKS}</minimum-links>

 

The python code is similar to this:

 

for rv in service.ROUTER_VECINO:
  for iac in rv.INT_AGREGADO_CONEXION:
    num_puertos=len(iac.PUERTO_LOCAL)
    vars.add('MIN_LINKS',min_links)
    template.apply('cr-art-template',vars)

 

 

But this always returns MIN_LINKS as the number of the last aggregated interface that the code processes. That is logical, since the 'for' statements go through all the aggregated interfaces, not the one that is being processed at that moment in the template. It would be easy if somehow I could access the value of the current aggregated interface being processed each time, but nothing like the following seem to work (I get errors like "Error: Python cb_create error. 'List' object has no attribute 'NOMBRE'"):

 

service.ROUTER_VECINO.NOMBRE

service.ROUTER_VECINO[NOMBRE]

...

 

Any hint?

 

Thanks.

Fran

 

So in the loop you can do rv.NOMBRE and iac.NOMBRE_INT_AGREGADO, since that points to the current instance.

I throws an error if I add the following print statement to the code:

 

 

 

 for rv in service.ROUTER_VECINO:
print(rv.NOMBRE)
for iac in rv.INT_AGREGADO_CONEXION:
...

admin@ncs(config-cr-art-artfran1-01)# re-deploy Error: Python cb_create error. 'List' object has no attribute 'NOMBRE'

I must be misunderstanding the model or the code, because rv shouldn't be a list. Try printing rv._path, and try making sure in the logs that it isn't some other line giving you the error.

Sorry, you are correct, it was another line which was triggering the error.

 

However, it looks like in the loop, rv.NOMBRE is not pointing to the current instance. Instead, the for loop goes through all instances of the service.

 

The service config looks like this:

cr-art artfran1-01
  ROUTER_VECINO Prueba
    INT_AGREGADO_CONEXION ae1
      PUERTO_LOCAL ge-0/0/2
      PUERTO_LOCAL ge-0/0/3

  ROUTER_VECINO artlaur1-01
    INT_AGREGADO_CONEXION ae3
      PUERTO_LOCAL ge-0/0/5

I have put some print statements in the code:

 

        for rv in service.ROUTER_VECINO:
          print(rv.NOMBRE)
          for iac in rv.INT_AGREGADO_CONEXION:
            num_puertos=len(iac.PUERTO_LOCAL)
            print(num_puertos)

What I get in the logs is:

 

<INFO> 2-Feb-2020::21:43:44.882 cisco ncs[3724]: cr-art :: Prueba
<INFO> 2-Feb-2020::21:43:44.883 cisco ncs[3724]: cr-art :: 2
<INFO> 2-Feb-2020::21:43:45.149 cisco ncs[3724]: cr-art :: artlaur1-01
<INFO> 2-Feb-2020::21:43:45.151 cisco ncs[3724]: cr-art :: 1

That is correct, but when I look at the config of the router artfran1-01, the value for MIN_LINKS is "1" for both aggregated interfaces.

 

What can I do to have "2" for ae1 and "1" fora ae3?

I'm still struggling with this. I have divided the original template into two different templates. The debug shows that the second template is being applied twice, but I do not quite understand the results. First calculation for MIN_LINKS results in "2" for both aggregate interfaces, even though the second aggregate only has one port. The second pass returns MIN_LINKS="1" for both aggregates, although the first aggregate only has one port.

 

 2020-02-03T15:12:58.070 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae3']/NOMBRE_INT_AGREGADO
 2020-02-03T15:12:58.070 xpath: template agregados-template: result: 2 nodes [0.001 sec]
 2020-02-03T15:12:58.070 xpath: template agregados-template: evaluating: ../NOMBRE
 2020-02-03T15:12:58.071 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='Prueba']/NOMBRE
 2020-02-03T15:12:58.071 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.071 xpath: template agregados-template: evaluating: INT_AGREGADO_REMOTO
 2020-02-03T15:12:58.071 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='Prueba']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae1']/INT_AGREGADO_REMOTO: ae2
 2020-02-03T15:12:58.071 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.072 xpath: template agregados-template: evaluating: string($MIN_LINKS)
 2020-02-03T15:12:58.072 xpath: template agregados-template: result: 2 [0.000 sec]
 2020-02-03T15:12:58.073 xpath: template agregados-template: evaluating: ../NOMBRE
 2020-02-03T15:12:58.073 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/NOMBRE
 2020-02-03T15:12:58.073 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.073 xpath: template agregados-template: evaluating: INT_AGREGADO_REMOTO
 2020-02-03T15:12:58.073 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae3']/INT_AGREGADO_REMOTO: ae1
 2020-02-03T15:12:58.074 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.074 xpath: template agregados-template: evaluating: string($MIN_LINKS)
 2020-02-03T15:12:58.074 xpath: template agregados-template: result: 2 [0.000 sec]
 2020-02-03T15:12:58.079 xpath: template agregados-template: evaluating: /DEVICE
 2020-02-03T15:12:58.079 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/DEVICE
 2020-02-03T15:12:58.080 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.081 xpath: template agregados-template: evaluating: ROUTER_VECINO/INT_AGREGADO_CONEXION/NOMBRE_INT_AGREGADO
 2020-02-03T15:12:58.081 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='Prueba']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae1']/NOMBRE_INT_AGREGADO
 2020-02-03T15:12:58.082 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae3']/NOMBRE_INT_AGREGADO
 2020-02-03T15:12:58.082 xpath: template agregados-template: result: 2 nodes [0.001 sec]
 2020-02-03T15:12:58.082 xpath: template agregados-template: evaluating: ../NOMBRE
 2020-02-03T15:12:58.082 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='Prueba']/NOMBRE
 2020-02-03T15:12:58.083 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.083 xpath: template agregados-template: evaluating: INT_AGREGADO_REMOTO
 2020-02-03T15:12:58.083 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='Prueba']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae1']/INT_AGREGADO_REMOTO: ae2
 2020-02-03T15:12:58.083 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.084 xpath: template agregados-template: evaluating: string($MIN_LINKS)
 2020-02-03T15:12:58.084 xpath: template agregados-template: result: 1 [0.000 sec]
 2020-02-03T15:12:58.084 xpath: template agregados-template: evaluating: ../NOMBRE
 2020-02-03T15:12:58.085 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/NOMBRE
 2020-02-03T15:12:58.085 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.085 xpath: template agregados-template: evaluating: INT_AGREGADO_REMOTO
 2020-02-03T15:12:58.085 xpath: template agregados-template: match: /cr-art[DEVICE='artfran1-01']/ROUTER_VECINO[NOMBRE='artlaur1-01']/INT_AGREGADO_CONEXION[NOMBRE_INT_AGREGADO='ae3']/INT_AGREGADO_REMOTO: ae1
 2020-02-03T15:12:58.085 xpath: template agregados-template: result: one node [0.000 sec]
 2020-02-03T15:12:58.086 xpath: template agregados-template: evaluating: string($MIN_LINKS)
 2020-02-03T15:12:58.086 xpath: template agregados-template: result: 1 [0.000 sec]

This is driving me crazy. Any hint would be greatly appreciated.

Can you post the template for which you see unexpected debug output?

One thing to have in mind is that the template engine supports some sort of iteration capability as well.

 

If your template contains path to lists in your service model, then NSO will iterate the list entries and apply the same structure of the XML for each entry. Looking at XML snippets you shared earlier, I suspect that might be happening.

This is the relevant piece of the template:

 

            <interface>
              <name>{/ROUTER_VECINO/INT_AGREGADO_CONEXION/NOMBRE_INT_AGREGADO}</name>
              <description>Conexion con {../NOMBRE} {INT_AGREGADO_REMOTO}</description>
              <aggregated-ether-options>
                <minimum-links>{$MIN_LINKS}</minimum-links>
              </aggregated-ether-options>
              <unit>
                <name>0</name>
                <family>
                    <inet>
                        <address>
                            <name>{IP-MASK}</name>
                        </address>
                    </inet>
                </family>
            </unit>
          </interface>

ok.

 

So, both ROUTER_VECINO and INT_AGREGADO_CONEXION, so your XML template is also doing some sort of iteration on those lists.

 

I'd say, try to limit your logic to iterate either on python or on XML.

Suppose that you go with python here, have your python code fetch the values of NOMBRE_INT_AGREGADO, NOMBRE, INT_AGREGADO_REMOTO and IP-MASK and populate them in template variables.

I have explored the other way, the template one, and it works!!

 

Just in case it might help someone, this is my template:

 

          <interfaces>
            <interface>
              <name>{/ROUTER_VECINO/INT_AGREGADO_CONEXION/NOMBRE_INT_AGREGADO}</name>
              <description>Conexion con {../NOMBRE} {INT_AGREGADO_REMOTO}</description>
              <aggregated-ether-options>
                <?if {contains(OPCIONES,'ROBUSTO')}?>
                  <minimum-links>{count(PUERTO_LOCAL)}</minimum-links>
                <?else?>
                  <minimum-links>{ceiling(count(PUERTO_LOCAL) div 2)}</minimum-links>
                <?end?>
              </aggregated-ether-options>
             </interface>
          </interfaces>

If I have time, I will also try the python approach later.

 

Thanks again for your help.

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: