cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
367
Views
0
Helpful
1
Replies

Issue with NSO XML Template Variable Resolution

ndmitri
Level 1
Level 1

Hello Cisco Community,

I’m currently working on an NSO project where I’m trying to manage network fabrics and devices using a service package. The goal is to create a fabric and have the service point code automatically populate the devices within the model using static data initially, with plans to integrate with Nautobot for dynamic device retrieval later on.

Overview

Our design involves creating a top-level service for the fabric, which is supposed to automatically create and configure associated devices as part of the service instantiation process. When we create a fabric, we expect the service point code to populate the devices within the model, based on static data or retrieved from Nautobot.

However, during a commit dry-run, we encounter an “empty node” error, indicating that the template variables for the devices are not being resolved correctly. 

We are trying to determine if there is a way to implement this design effectively within NSO, or if there are limitations in the platform that prevent this approach.

Thank you for your support!

YANG Model

 

 

module nfaas-fabric {
  namespace "http://example.com/nfaas-fabric";
  prefix nfaas-fab;
  yang-version 1.1;

  import ietf-inet-types {
    prefix inet;
  }

  import tailf-ncs {
    prefix ncs;
  }

  description "Fabric management for NFaaS";

  revision 2024-07-29 {
    description "Fabric management service.";
  }

  augment "/ncs:services" {
    list fabric {
      key "name";
      leaf name {
        type string;
        description "Name of the fabric";
      }

      uses ncs:service-data;
      ncs:servicepoint nfaas-fabric-servicepoint;

      container devices {
        list device {
          key "name";
          leaf name {
            type string;
            description "Name of the device";
          }
          leaf address {
            type inet:ipv4-address;
            description "Management IP address of the device";
          }
          leaf ned-id {
            type string;
            description "NED ID of the device";
          }
        }
      }
    }
  }
}

 

 

Python Code

 

 

# -*- mode: python; python-indent: 4 -*-
import ncs
from ncs.application import Service

class NfaasFabricServiceCallbacks(Service):
    .create
    def cb_create(self, tctx, root, service, proplist):
        self.log.info(f"Creating fabric: {service.name}")

        # Static data for a single device
        devices = [
            {"name": "DLF03.FAB00.EWR00", "address": "10.0.0.10", "ned_id": "test"}
            # More devices can be added here
        ]

        # Iterate over each device and apply the template
        for device in devices:
            if device["name"] not in root.ncs__devices.device:
                self.log.info(f"Device: {device}")
                vars = ncs.template.Variables()
                vars.add('device-name', device["name"])
                vars.add('device-address', device["address"])
                vars.add('device-ned-id', device["ned_id"])

                self.log.info(f"Vars: {vars}")

                template = ncs.template.Template(service)
                template.apply('nfaas-fabric-template', vars)
                self.log.info(f"Device {device['name']} added to fabric {service.name}")
            else:
                self.log.info(f"Device {device['name']} already exists in NSO")

class NfaasFabric(ncs.application.Application):
    def setup(self):
        self.log.info('NFaaS Fabric Service RUNNING')
        self.register_service('nfaas-fabric-servicepoint', NfaasFabricServiceCallbacks)

    def teardown(self):
        self.log.info('NFaaS Fabric Service FINISHED')

 

 

XML Template

 

 

<config-template xmlns="http://tail-f.com/ns/config/1.0">
  <services xmlns="http://tail-f.com/ns/ncs">
    <fabric xmlns="http://example.com/nfaas-fabric">
      <name>{/name}</name> <!-- Ensure the context is set correctly for the 'name' -->
      <devices>
        <device tags="create">
          <name>{device-name}</name>
          <address>{device-address}</address>
          <ned-id>{device-ned-id}</ned-id>
        </device>
      </devices>
    </fabric>
  </services>
</config-template>

 

 

CLI Output

 

 

admin@ncs# config 
Entering configuration mode terminal
admin@ncs(config)# services fabric FAB00.EWR00                                        
admin@ncs(config-fabric-FAB00.EWR00)# commit dry-run outformat xml | debug template nfaas-fabric-template
Evaluating "/name" (from file "nfaas-fabric-template.xml", line 4)
Context node: /services/nfaas-fab:fabric[name='FAB00.EWR00']
Result:
For /services/nfaas-fab:fabric[name='FAB00.EWR00'], it evaluates to "FAB00.EWR00"
Operation 'merge' on existing node: /services/nfaas-fab:fabric[name='FAB00.EWR00'] (from file "nfaas-fabric-template.xml", line 4)
Evaluating "device-name" (from file "nfaas-fabric-template.xml", line 7)
Context node: /services/nfaas-fab:fabric[name='FAB00.EWR00']
Result: empty node - skipping siblings
result-xml {
    local-node {
        data <services xmlns="http://tail-f.com/ns/ncs">
               <fabric xmlns="http://example.com/nfaas-fabric">
                 <name>FAB00.EWR00</name>
               </fabric>
             </services>
    }
}
admin@ncs(config-fabric-FAB00.EWR00)#

 

 

 

1 Accepted Solution

Accepted Solutions

ndmitri
Level 1
Level 1
1 Reply 1

ndmitri
Level 1
Level 1

Resolved!