cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1662
Views
5
Helpful
10
Replies

how to pass or inherit parameters between NSO stacked services

mastedarq
Level 1
Level 1

In advance I just want to explain that I'm NSO newbie, so please don't be offended by the meritoric quality of my questions.
I picked the L3VPN service case to present my questions as it should be good example of what I want to achieve.
I like the approach of stacked services so decided it should be nice to split whole L3 service configuration to smaller parts (which can be reused in other services). By doing that I encountered some obstacles and based on simplified example I'd like to get some more information how to proceed with it.

On attached draw there are three services: "L3VPN" (CFS, umbrella service), "GLOBAL_VRF_DEF" (RFS) and "BGP_VRF_DEF" (RFS).

IMG_0006.jpg
Both RFS services are using some common pieces of information to configure device: vrf_name and vrf_address_families.

What I want to achieve is:
- based on CFS level defined parameters (vrf_name, vrf_address_families) they should be inherited by both RFS services
- Yang models of RFS services shouldn't(?) contain objects of above mentioned parameters at all (just the CFS Yang model) (or more precisely the user shouldn't be asked of such again)

So basically my question is how to pass parameters between services, are there some kind of constrains, what is the best approach, is it even possible at all or I'm missing the intention of NSO "logic" completely?

All of the above services are python-and-template based.

I'll appreciate any advice.

 

YANG models

L3VPN
-----
list L3VPN {
	key name;

	leaf name {
		type string;
	}

	leaf device {
		type leafref {
			path "/ncs:devices/ncs:device/ncs:name";
		}
	}

	leaf vrf_name {
		type string;
	}

	leaf vrf_afi {
		type enumeration {
			enum "ipv4";
			enum "ipv6";
		}
	}

	leaf vrf_safi {
		type enumeration {
			enum "unicast";
			enum "multicast";
		}
	}
}

GLOBAL_VRF_DEF & BGP_VRF_DEF (common Yang model parts)
----------------------------
list GLOBAL_VRF_DEF {
	key name;

	leaf name {
		type string;
	}
// here object is leaf-list as this RFS service can be reused or executed as standalone to configure multiple devices at the same time leaf-list device { type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } // what about the rest of the parameters (vrf_name, vrf_afi, vrf_safi?) }

 XML templates

L3VPN
-----
<config-template>
	<services>
		<GLOBAL_VRF_DEF>
			<name>{/name}</name>
			<device>{/device}</device>
			<vrf_name>{/vrf_name}</vrf_name>
			<vrf_afi>{/vrf_afi}</vrf_afi>
			<vrf_safi>{/vrf_safi}</vrf_safi>
		</GLOBAL_VRF_DEF>
		<BGP_VRF_DEF>
			<name>{/name}</name>
			<device>{/device}</device>
			<vrf_name>{/vrf_name}</vrf_name>
			<vrf_afi>{/vrf_afi}</vrf_afi>
			<vrf_safi>{/vrf_safi}</vrf_safi>
		</BGP_VRF_DEF>
	</services>
</config-template>

GLOBAL_VRF_DEF & BGP_VRF_DEF (here just the first one presented, but BGP_VRF_DEF should use same parameters within its own configuration with similar exceptions)
----------------------------
<devices> 
 <device>
  <name>{/device}</name>
  <config>
    <vrf xmlns="http://tail-f.com/ned/cisco-ios-xr">
      <vrf-list>
        <name>{/vrf_name}</name>
        <address-family>
          <ipv4>
            <unicast> 
				<!-- ... some configuration here -->
            </unicast>
<multicast> <!-- it should only be send to device if CFS level "vrf_safi='multicast'" -->
<!-- ... some configuration here -->
</multicast> </ipv4> <ipv6> <!-- it should only be send to device if CFS level "vrf_afi='ipv6'" --> <unicast> <!-- ... some configuration here --> </unicast> </ipv6> </address-family> </vrf-list> </vrf> </config> </device> </devices>

 

1 Accepted Solution

Accepted Solutions

Right, you should not need to require more parameters from the northbound user. Whatever parameters are needed by the lower services to generate the device configuration will need to be provided by either:

1) the user providing them into the umbrella and passed into the lower service yang service instance params

2) generated by the umbrella service and passed into the lower service yang service instance params

3) generated by the lower services themselves for use in the eventual device config template.

The way to pass config between the umbrella service to its subordinate services is to provide it though the Service instance yang parameters of the subordinate services you are creating.

All these services have independent yang model, not requiring any linkage of yang models between the upper/lower service.

View solution in original post

10 Replies 10

omz
VIP Alumni
VIP Alumni

Hi 

any chance you could please share what software and hardware you used to draw the diagram?

thank you

Sure.

iPad + Apple Pencil + Apple Notes app

:)

wow nice .. thank you .. didnt realise ipad and apple pencil were that good :)

Blackboard and chalks?
😉

mastedarq
Level 1
Level 1

What I was thinking to do was to create a separate package with Yang only model file describing those common parameters and import this package into all services. When already filled within CFS service, I should be able to call them somehow from python of RFS services (don't know if that make sense, but at least I'll learn something... maybe).

Hello,

The general concept of a 'stacked service' is to provide an 'umbrella' service that is used create service instances of one or more distinct subordinate services - usually hierarchically defined - as you are doing here. 

Each of the subordinate services are defined as NSO services, each with service models containing the parameters required to create that services sub-set of the overall config. Instances of these services can manually or programmatically be created by writing the service parameters for the service into the CDB and committing as usual.

The umbrella service is used to create (modify,delete) service instances for one or more subordinate services. The umbrella service creates these service instances by setting the service instance parameters for each of the subordinate services in the CDB.  This can be done either by explicit sets to the CDB service yang elements with code or, more commonly, using templates to set the service instance parameters.  The create code/templates for each of these service instances will then be run automatically by NSO to generate the desired device config for each.  Device configuration generated by all subordinate services (as well as any device config generated by the umbrella config itself) will be written to the network as a single transaction.

To answer your question, the parameters get 'passed/inherited' by the subordinate services by the umbrella service explicitly using the params to create service instances of the lower services.

 

Please excuse me for my limited brain capability, but while I understood what You wrote, I don't think I'm getting it.

You described general idea of stacked services which (I thought) I kind of understood. I - more or less - have some issues with implementing this idea into working configuration.

First of all, I'd like to pass just few parameters, not complete list of all parameters required by the subordinate services to configure devices. I want to hide most of such parameters and generate them automagically (route-targets, route-distinguisher, etc. that's why python-based services). From what I understand from Your description is that I need to pass all of them in CFS service, which means the end user will need to define at least two times the same parameters (address-family id, sub-id) in my example for global vrf definition and for bgp vrf piece of configuration. I already built such a service based on just templates, but now I need to optimize it and upgrade with python. That's why I thought that once defined common parameters on umbrella service level should then be passed down to subordinate services. And - while I understood how this process should look like - I don't know how to implement this passing/inheritance process. In Yang model, I'm not able to reference objects outside subordinate service model. In python I've some issues with call of data from CFS service (didn't understood this root.device_template.template path or I need to spend more time on it).

 

Right, you should not need to require more parameters from the northbound user. Whatever parameters are needed by the lower services to generate the device configuration will need to be provided by either:

1) the user providing them into the umbrella and passed into the lower service yang service instance params

2) generated by the umbrella service and passed into the lower service yang service instance params

3) generated by the lower services themselves for use in the eventual device config template.

The way to pass config between the umbrella service to its subordinate services is to provide it though the Service instance yang parameters of the subordinate services you are creating.

All these services have independent yang model, not requiring any linkage of yang models between the upper/lower service.

I had to rethink it once again and I believe I understood it now. I've got this working template based solution, but in fact I didn't understood how it worked. I believe I do now because of Your and jordanmeador explanations. I simply messed up with Yang models and unnecessarily defined duplicated objects. I'm going back to workbench, but I believe I've got it now.

Thank You guys.

jordanmeador
Level 1
Level 1

So this has been the focus of our development for the past few months. We have a top level service that takes common customer information, and then have lists underneath that which will contain the extra information necessary to build each type of service. So something like:

 

list main {

  leaf customer_name {

  type string;

  }

  list internet {

    leaf ip_address {

    }

  }

  list vpn {

    leaf ip_address {

    }

    leaf vrf {

    }

And so on. Your child yang modules will contain the common information necessary and the extra variables that you will need to build out the service. So the internet yang would look like:

 

list internet {

  leaf customer_name {

  }

  leaf ip_address {

  }

 

After that, in the parent template, you pass the variables down to the child modules by calling the namespace in the template. 

 

<config-template xmlns="http://tail-f.com/ns/config/1.0">

  <internet xmlns="http://example.com/internet">

    <customer_name>{/customer_name}</customer_name>

    <ip_address>{/internet/ip_address}</ip_address>

 

That pushes the information to the child service and populates the yang model there, and will then push it through the service as normal.