Cisco NSO300 Lab 3: Nano Services
Nano Services
In LAB 3: Nano Services, participants delve into the intricacies of Nano Services within the Cisco Network Services Orchestrator (NSO) environment. Nano Services represent a microservices-based architecture, allowing for the modular decomposition and composition of network services. This lab involves tasks such as creating, configuring, and orchestrating Nano Services to achieve specific network functionalities. Participants gain hands-on experience in harnessing the flexibility and scalability advantages offered by Nano Services, showcasing their ability to streamline and modularize network service design and deployment. Successful completion of NSO300 LAB 3 equips participants with practical skills in working with Nano Services, a pivotal aspect of modern network automation architectures, fostering agility and efficiency in service orchestration.
Lab:
Task 1: Modify Service Model
In this task, you will modify the existing service model in two steps. First, you will create a separate list for the vpn-id allocations for the network operator. Next, you will delete the existing vpn-id leaf.
The final solution for this lab is located in the ~/solutions/lab3/l3mplsvpn/nano
directory. You can use it for copying and pasting longer pieces of code and as a reference point for troubleshooting your packages.
Step 1: Connect to the VM server by clicking the NSO icon
Step 2: Open the terminal window using the Terminal icon on the bottom bar.
Step 3: Change directory to /home/rst/NSO/nso300
rst@rst:~$ **cd NSO/nso300**
rst@rst:~/NSO/nso300$
Step 4: From the Terminal window, copy the existing l3mplsvpn
package.
rst@rst:~/NSO/nso300$ **cp -r ../packages/l3mplsvpn/ packages/l3mplsvpn**
rst@rst:~/NSO/nso300$
Step 5: List the contents of the ../packages/l3mplsvpn
directory.
rst@rst:~/NSO/nso300$ **ls packages/l3mplsvpn/**
package-meta-data.xml python README src templates
rst@rst:~/NSO/nso300$
Step 6: Open the service model file using a text editor of your choice
rst@rst:~/NSO/nso300$ code packages/l3mplsvpn/src/yang/l3mplsvpn.yang
Step 7: Delete the existing vpn-id
leaf.
leaf vpn-id {
type uint16;
tailf:info "Unique VPN ID";
}
Step 8: Create a list vpn-allocations
with two leaves — vpn-name
and vpn-id
. Declare vpn-name
to be used as a key leaf and use a unique constraint for the vpn-id
. Make sure that vpn-name
refers to the name leaf located in the l3mplsvpn list.
\### OUTPUT OMITTED ###
revision 2020-06-04 {
description
"Initial revision.";
}
**list vpn-allocations {**
** key "vpn-name";**
** unique "vpn-id";**
** leaf vpn-name {**
** type leafref {**
** path /l3mplsvpn/name;**
** }**
** }**
** leaf vpn-id {**
** type uint16;**
** tailf:info "Unique VPN ID";**
** }**
**}**
list l3mplsvpn {
uses ncs:service-data;
ncs:servicepoint l3mplsvpn-servicepoint;
key name;
### OUTPUT OMITTED ###
Step 9: Save the file and exit the text editor.
Task 2: Change to Nano Services
In this task, you will change the service model from the previous task and implement nano service. This change will consist of three key steps.
First, the service must include the ncs:nano-plan-data
grouping which will change the execution model of your service.
Second, the service must define a nano plan declared with the ncs:plan-outline
statement. Nano plan definitions consist of plan components and plan state definitions.
Finally, you must define a service behavior tree declared with the ncs:service-behavior-tree
statement. The behavior tree is responsible for creating and removing plan components from instances of your service plan.
Step 1: Open the service model file using a text editor of your choice and study the service model.
rst@rst:~/NSO/nso300$ **code packages/l3mplsvpn/src/yang/l3mplsvpn.yang **
Step 2: Find the l3mplsvpn
list definition and declare the use of nano-plan-data
.
\### OUTPUT OMITTED ###
list l3mplsvpn {
uses ncs:service-data;
**uses ncs:nano-plan-data;**
ncs:servicepoint l3mplsvpn-servicepoint;
key name;
leaf name {
tailf:info "Service Instance Name";
type string;
}
### OUTPUT OMITTED ###
Step 3: Declare the plan component and plan state for later use in the plan outline.
\### OUTPUT OMITTED ###
revision 2020-06-04 {
description
"Initial revision.";
}
**identity l3mplsvpn {**
** base ncs:plan-component-type;**
**}**
**identity l3mplsvpn-configured {**
** base ncs:plan-state;**
**}**
list vpn-allocations {
key "vpn-name";
unique "vpn-id";
### OUTPUT OMITTED ###
Step 4: Define your service plan outline and add a mandatory self
component with two mandatory states — init
and ready
. init
and ready
states are primarily used as placeholders for timestamps.
\### OUTPUT OMITTED ###
identity l3mplsvpn-configured {
base ncs:plan-state;
}
**ncs:plan-outline l3mplsvpn-plan {**
** description "L3 MPLS VPN Plan";**
** ncs:component-type "ncs:self" {**
** ncs:state "ncs:init";**
** ncs:state "ncs:ready";**
** }**
**}**
list vpn-allocations {
key "vpn-name";
unique "vpn-id";
### OUTPUT OMITTED ###
Step 5: Define the l3mplsvpn
component type and define two possible states. However, this time, use the l3mplsvpn:l3mplsvpn-configured
for the second state declaration. You have formally declared these identities previously.
\### OUTPUT OMITTED ###
identity l3mplsvpn-configured {
base ncs:plan-state;
}
ncs:plan-outline l3mplsvpn-plan {
description "L3 MPLS VPN Plan";
ncs:component-type "ncs:self" {
ncs:state "ncs:init";
ncs:state "ncs:ready";
}
**ncs:component-type "l3mplsvpn:l3mplsvpn" {**
** ncs:state "ncs:init";**
** ncs:state "l3mplsvpn:l3mplsvpn-configured" {**
** }**
**}**
}
list vpn-allocations {
key "vpn-name";
unique "vpn-id";
### OUTPUT OMITTED ###
Step 6: Finally, add a create
nano callback and define a pre-condition inside the block. Write an XPath expression and pass it as an argument to the monitor statement. This will make sure that l3mplsvpn-configured
state can be reached only if the monitor condition is satisfied. Make sure you add a nano-callback
declaration right after the pre-condition block.
\### OUTPUT OMITTED ###
identity l3mplsvpn-configured {
base ncs:plan-state;
}
ncs:plan-outline l3mplsvpn-plan {
description "L3 MPLS VPN Plan";
ncs:component-type "ncs:self" {
ncs:state "ncs:init";
ncs:state "ncs:ready";
}
ncs:component-type "l3mplsvpn:l3mplsvpn" {
ncs:state "ncs:init";
ncs:state "l3mplsvpn:l3mplsvpn-configured" {
**ncs:create {**
** ncs:pre-condition {**
** ncs:monitor "/vpn-allocations\[vpn-name=$SERVICE/name\]/vpn-id";**
** }**
** ncs:nano-callback;**
**}**
}
}
}
list vpn-allocations {
key "vpn-name";
unique "vpn-id";
### OUTPUT OMITTED ###
Step 7: Write a behavior tree for your service by providing the name of your service point and the name of your plan outline. A behavior tree is responsible for creating components instantiated from your service plan.
\### OUTPUT OMITTED ###
identity l3mplsvpn {
base ncs:plan-component-type;
}
identity l3mplsvpn-configured {
base ncs:plan-state;
}
**ncs:service-behavior-tree l3mplsvpn-servicepoint {**
** description "L3 MPLS VPN behavior tree";**
** ncs:plan-outline-red "l3mplsvpn:l3mplsvpn-plan";**
** ncs:selector {**
** ncs:create-component "'self'" {**
** ncs:component-type-ref "ncs:self";**
** }**
** ncs:create-component "'l3mplsvpn'" {**
** ncs:component-type-ref "l3mplsvpn:l3mplsvpn";**
** }**
** }**
**}**
ncs:plan-outline l3mplsvpn-plan {
description "L3 MPLS VPN Plan";
### OUTPUT OMITTED ###
Step 8: Save changes and close the file.
Step 9: Open the l3mplsvpn.py
file using a text editor of your choice.
rst@rst:~/NSO/nso300$ `code packages/l3mplsvpn/python/l3mplsvpn/l3mplsvpn.py`
Step 10: Delete the highlighted ServiceCallbacks class declaration, @Service.create
decorator, and cb_create method declaration along with the call to the self.log.debug
method.
import ncs
import math
class ServiceCallbacks(ncs.application.Service):
@Service.create
def cb\_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service.\_path, ')')
### OUTPUT OMITTED ###
Step 11: Declare a class L3MPLSNanoService
, which inherits from the ncs.application
NanoService class. Use the @ncs.application.NanoService.create
decorator and define the cb_nano_create
method with a call to the self.log.debug
method.
Note: cb_nano_create
accepts additional parameters—plan
, component, state, and component_proplist
.
import ncs
import math
**class L3MPLSNanoService(ncs.application.NanoService):**
**@ncs.application.NanoService.create**
**def cb\_nano\_create(**
**self, tctx, root, service, plan, component, state, proplist, component\_proplist**
**):**
**self.log.debug("NanoService create ", state)**
### OUTPUT OMITTED ###
Step 12: Delete the line with the vpn_id
declaration. Remember that your service model no longer provides the vpn-id
.
\### OUTPUT OMITTED ###
vpn\_id = service.vpn\_id
### OUTPUT OMITTED ###
Step 13: Add lines to obtain vpn-id
from vpn-allocations
list, and a call to self.log.info
method. Make sure that you use underscores and not hyphen when declaring variables.
\### OUTPUT OMITTED ###
self.log.debug("NanoService create ", state)
**vpn\_id = root.vpn\_allocations\[service.name\].vpn\_id**
**self.log.info(f"Vpn ID read: {vpn\_id}")**
### OUTPUT OMITTED ###
Step 14: Scroll down to near the end of the file and add a return proplist
statement. Also, add a call to self.register_nano_service
with your service parameters.
\### OUTPUT OMITTED ###
template.apply("l3mplsvpn-template", tvars)
**return proplist**
# ---------------------------------------------
# COMPONENT THREAD THAT WILL BE STARTED BY NCS.
# ---------------------------------------------
class L3MplsVpn(ncs.application.Application):
def setup(self):
self.log.info("L3MplsVpn RUNNING")
**self.register\_nano\_service(**
** "l3mplsvpn-servicepoint",**
** "l3mplsvpn:l3mplsvpn",**
** "l3mplsvpn:l3mplsvpn-configured",**
** L3MPLSNanoService,**
**)**
def teardown(self):
self.log.info("L3MplsVpn FINISHED")
### OUTPUT OMITTED ###
Step 15: Save changes and exit the text editor.
Step 16: Compile and deploy your package.
rst@rst:~/NSO/nso300$ **make testenv-build**
### OUTPUT OMITTED ###
>>> System upgrade has completed successfully.
reload-result {
package cisco-asa-cli-6.7
result true
}
reload-result {
package cisco-ios-cli-6.42
result true
}
reload-result {
package cisco-iosxr-cli-7.18
result true
}
reload-result {
package cisco-nx-cli-5.13
result true
}
reload-result {
**package l3mplsvpn**
**result true**
}
rst@rst:~/NSO/nso300$
Task 3: Deploy Nano Services
In this task, you will deploy the newly created nano service.
Step 1: Enter the NSO CLI and switch to the Cisco mode.
rst@rst:~/NSO/nso300$ **make testenv-cli**
docker exec -it testenv-nso300-5.3-rst-nso bash -lc 'ncs\_cli -u admin'
admin connected from 127.0.0.1 using console on 83dc28b9733d
admin@ncs> **switch cli**
admin@ncs#
Step 2: Enter the configuration mode and create a new customer entry called ACME.
admin@ncs# **config**
Entering configuration mode terminal
admin@ncs(config)# **customers customer ACME**
admin@ncs(config-customer-ACME)#
Step 3: Commit the configuration and return to the top.
admin@ncs(config-customer-ACME)# **top**
admin@ncs(config)#
Step 4: Configure a new VPN service instance for the new customer and name it vpn512.
admin@ncs(config)# **l3mplsvpn vpn512 customer ACME**
admin@ncs(config-l3mplsvpn-vpn512)#
Step 5: Configure two links, each on a different device.
admin@ncs(config-l3mplsvpn-vpn512)# **link 1 device PE11 interface 0/1**
admin@ncs(config-link-1)# **exit**
admin@ncs(config-l3mplsvpn-vpn512)# **link 2 device PE21 interface 0/2**
admin@ncs(config-link-2)# **exit**
Step 6: Commit the configuration and exit configuration mode.
admin@ncs(config-l3mplsvpn-vpn512)# **commit**
Commit complete.
admin@ncs(config-l3mplsvpn-vpn512)# **end**
admin@ncs#
Step 7: Inspect the status of the newly configured service instance.
Plan component l3mplsvpn
has not reached the l3mplsvpn-configured
state because a pre-condition
exists, which requires the presence of a vpn-id value in the vpn-allocations
list.
The NSO CLI adapts the output to the width of your terminal window. In case your window is too narrow, you can use the <command> | tab
format, to force the NSO CLI to display the tabulated output.
admin@ncs# **show l3mplsvpn vpn512**
POST
BACK ACTION
TYPE NAME TRACK GOAL STATE STATUS WHEN ref STATUS
--------------------------------------------------------------------------------------------------------
self self false - init reached 2021-07-29T08:04:42 - -
ready reached 2021-07-29T08:04:42 - -
l3mplsvpn l3mplsvpn false - init reached 2021-07-29T08:04:42 - -
l3mplsvpn-configured not-reached - - -
admin@ncs#
Step 8: Enter the configuration mode.
admin@ncs# **config**
Entering configuration mode terminal
Step 9: Use the vpn-allocations
command to allocate a new vpn-id to the service instance. You are taking the role of a network operator that is acting upon a new VPN service request.
admin@ncs(config)# **vpn-allocations ?**
Possible completions:
vpn512
admin@ncs(config)# **vpn-allocations vpn512 vpn-id 512**
Step 10: Commit the configuration and exit the configuration mode.
admin@ncs(config-vpn-allocations-vpn512)# **commit**
Commit complete.
admin@ncs(config-vpn-allocations-vpn512)# **end**
admin@ncs#
Step 11: Display the status of the service instance vpn512
one more time. Notice that the plan component l3mplsvpn
has now reached the l3mplsvpn-configured
state after the pre-condition
was satisfied.
admin@ncs# **show l3mplsvpn vpn512**
l3mplsvpn vpn512
modified devices \[ PE11 PE21 \]
directly-modified devices \[ PE11 PE21 \]
device-list \[ PE11 PE21 \]
POST
BACK ACTION
TYPE NAME TRACK GOAL STATE STATUS WHEN ref STATUS
----------------------------------------------------------------------------------------------------
self self false - init reached 2021-07-29T08:04:42 - -
ready reached 2021-07-29T08:04:42 - -
l3mplsvpn l3mplsvpn false - init reached 2021-07-29T08:04:42 - -
l3mplsvpn-configured reached 2021-07-29T08:05:38 - -
admin@ncs#
You have successful configured service instance. Your plan component l3mplsvpn
has reached l3mplsvpn-configured
state.