CCIE DevNet Reference Guide v1.3 | PDF | Integer (Computer Science) | Data Type
0% found this document useful (0 votes)
143 views

CCIE DevNet Reference Guide v1.3

This document provides an overview of sections covered in the CCIE DevNet Technology Reference Guide. Section 1 covers setting up the development environment, using Terraform to provision Docker containers, and introduces Cisco NSO and YANG. Section 2 is a Python crash course. Later sections discuss REST APIs, Python libraries, Git/GitLab, Cisco APIC, network automation, and service management.

Uploaded by

Saleem Ahmad
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
143 views

CCIE DevNet Reference Guide v1.3

This document provides an overview of sections covered in the CCIE DevNet Technology Reference Guide. Section 1 covers setting up the development environment, using Terraform to provision Docker containers, and introduces Cisco NSO and YANG. Section 2 is a Python crash course. Later sections discuss REST APIs, Python libraries, Git/GitLab, Cisco APIC, network automation, and service management.

Uploaded by

Saleem Ahmad
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 38

CCIE DevNet Technology Reference Guide

CCIE DevNet Technology Reference Guide


Section Overview
Section 1.0: Setting up and Getting Started
What would you need?
Section 1.1 - Terraform - Docker and ACI
What is Terraform
Installation
How does Terraform work?
Terraform workflow
Resource Blocks
Resource Syntax
Providers
Terraform Docker Config file example
Hands-On 1 - Provision Docker Container using Terraform
Input Variables
Hands-On 2 - Parametrize Terraform config script using variables
Section 1.2 - YANG, Cisco NSO (Network Services Orchestrator)
Refer
What is Cisco NSO?
How does Cisco NSO Work?
Install Cisco NSO
Getting Started
Managing the devices
Configuring the network
Creating Services
Modifying a service
NETCONF
YANG
What is a data model?
YANG Structure
Modules
Containers and Leaves
YANG Data Types
Common Data Types
Enumeration
Section 2.0: Python Crash Course
What is Program?
What is Python?
Why Python?
Install Python
Getting started
Data Types
Variables
Operators
Arithmetic Operators
Assignment Operators
Comparison Operators
Logical Operators
Special Operators
Getting Input from the user
Data Types - Deep Dive
Strings
Lists
Tuples
Dictionaries

Section Overview
Section 1.0: Setting up and Getting Started
Section 1.1: Terraform - Docker, ACI
Section 1.2: YANG, NSO
Section 2.1: REST APIs with Python, Click API
Section 2.2: Python NCCLIENT, YANG, NETCONF, RESTCONF
Section 2.3: Python Libraries Jinja2, Scrapli, Netmiko
Section 3.1: Git, Gitlab, CI/CD Pipelines
Section 3.2: Cisco APIC APIs
Section 3.3: Network Test Automation with PyATS
Section 3.4: Secret Management with Vault, Ansible
Section 3.5: NX-API, , GitLab Authentication, Secure REST APIs
Section 4.1: Zammad Python SDK
Section 4.2: YANG Model Driven Telemetry
Section 4.3: Docker, Docker Compose
Section 1.0: Setting up and Getting Started

What would you need?


● DevNet VM Image with the following pieces set up
○ Python
○ Ansible
○ Docker
○ Terraform
● VMWare Workstation Player
● Code Editor/ IDE (Integrated Development Environment)
○ VS Code (Recommended)
○ Pycharm
○ Any other editor of your choice
● Download Links
○ VM Image
■ Octa Image:
https://drive.google.com/file/d/1a_xfj2wI3Ezbi0ElstYebPxpUC5cMulO/vie
w
● Username: student
● Password: devnetstudent
■ Cisco Image
https://learningcontent.cisco.com/images/2022-04-09_DevNetExpert_CW
S_Example.ova
■ If you download the Cisco image, what you get is a zip file, which you
need to unzip into some folder and then open the OVA file with any
virtualization software like VMWare Workstation
○ VMWare Player
■ https://www.vmware.com/go/getplayer-win
○ Visual Studio Code (VS Code)
■ https://code.visualstudio.com/download

Section 1.1 - Terraform - Docker and ACI

What is Terraform
● Terraform is an infrastructure as code tool
● It lets you build, change, and version infrastructure, both on cloud and on-prem, safely
and efficiently
● Resources are defined in human-readable configuration files that can be versioned,
reused, and shared
● Can manage both
○ Low level resources like compute, storage and networking
○ High level resources like DNS entries, SaaS features etc.
Installation
● If you have downloaded the DevNet VMImage mentioned above, Terraform is already
installed.
● If you are using any other system, you can follow the below instructions to install
Terraform.
○ https://developer.hashicorp.com/terraform/downloads

How does Terraform work?


● Providers enable Terraform to work with virtually any platform or service with an
accessible API.
● HashiCorp and the Terraform community have already written thousands of providers
to manage many different types of resources and services
● You can find all publicly available providers on the Terraform Registry
○ Explore the following providers on Terraform Registry
■ Docker
■ Cisco ACI
■ Azure
■ AWS

Terraform workflow
● Write
○ Create a config file in HCL (Hashciorp Config Language) which defines the
infrastructure in a declarative way
● Plan
○ Terraform creates an execution plan describing the infrastructure it will create,
update, or destroy based on the existing infrastructure and your configuration.
● Apply
○ On approval, Terraform performs the proposed operations in the correct order,
respecting any resource dependencies

Resource Blocks
● Resources are the most important element in the Terraform language
● Each resource block describes one or more infrastructure objects, such as virtual
networks, compute instances, or higher-level components such as DNS records

Resource Syntax
● A resource block declares a resource of a given type ("docker_container") with a
given local name ("nginx_container")
● The local name can only be used to refer this resource from elsewhere in the same
module but has no significance outside
Providers
● Each resource type is implemented by a provider, which is a terraform plugin
● Providers are distributed separately from Terraform itself
● Terraform can automatically install most providers when initializing a working directory
● In order to manage resources, a Terraform module must specify which providers it
requires
● Terraform usually automatically determines which provider to use based on a resource
type's name
● By convention, resource type names start with their provider's preferred local name
● Every Terraform provider has its own documentation, describing its resource types and
their arguments
● Most publicly available providers are distributed on the Terraform Registry, which also
hosts their documentation

Terraform Docker Config file example

Unset
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.2"
}
}
}

provider "docker" {}

resource "docker_image" "nginx_image" {


name = "nginx:latest"
keep_locally = false
}

resource "docker_container" "nginx_container" {


image = docker_image.nginx_image.image_id
name = "tutorial"
ports {
internal = 80
external = 8000
}
}

# initialize terraform
$ terraforrm init

# check what is terraform going to create by generating a plan


$ terraform plan

# apply the plan to create resources


$ terraform apply

# destroy the resources created by terraform


$ terraform destroy

Hands-On 1 - Provision Docker Container using Terraform


● Create an nginx docker container using terraform
● Expose port 80 on the container via port 8888 on host
● Ensure that default page comes up

Input Variables
● Lets us customize aspects of Terraform modules without altering the module's source
code
● This functionality allows you to share modules across different Terraform configurations
● If you're familiar with traditional programming languages, it can be useful to compare
Terraform modules to function definitions
○ Input variables are like function arguments
○ Output values are like function return values
○ Local values are like a function's temporary local variables
● Each input variable accepted by a module must be declared using a variable block
● The label after the variable keyword is a name for the variable, which must be unique
among all variables in the same module

Hands-On 2 - Parametrize Terraform config script using variables

● Using Cisco ACI provider, create an ACI tenant and an application profile
● Names of the tenant and the application profile should be taken from variables file set as
default values

Hands-On 3 - Create multiple ACI tenants using for-each construct

● Declare a list variable with a list of tenant names


● Using for each construct, create multiple tenants with each name given in the list
variable

Hands-On 4 - Create multiple ACI tenants using for-each construct

● Declare a list variable with a list of tenant names


● Using for each construct, create multiple tenants with each name given in the list
variable

Section 1.2 - YANG, Cisco NSO (Network Services Orchestrator)

Refer
● https://developer.cisco.com/docs/nso/guides/#!start/start
● https://developer.cisco.com/learning/tracks/get_started_with_nso
● https://developer.cisco.com/docs/nso/guides/#!basic-operations/setup

What is Cisco NSO?


● A Linux application which orchestrates the configuration life cycle of physical and virtual
network devices
● NSO gathers, parses, and stores the configuration state of the network devices it
manages in a configuration database (CDB)
● Users and applications can then "ask" NSO to create, read, update, or delete
configuration in a programmatic way either ad hoc or through customizable network
services
How does Cisco NSO Work?
● NSO uses software packages called Network Element Drivers (NEDs)
● Using NEDs NSO facilitates telnet, SSH, or API interactions with the devices that it
manages
● NED provides an abstraction layer that reads in the device's running configuration and
parses it into a data-model-validated snapshot in the CDB
● NEDs can also do the reverse
○ creating network configuration from CDB data inputs
○ sending the configurations to the network devices

Install Cisco NSO


● https://developer.cisco.com/docs/nso/#!getting-and-installing-nso/installation
● Prerequisites
○ Java
■ apt install default-jdk (already installed on CWS)
○ Apache ANT
■ apt install ant (already installed on CWS)
○ Python
■ apt-get install python3 python3-pip python3-setuptools
(already installed on CWS)
○ Development Tools
■ apt install libxml2-utils (already installed on CWS)
● Download NSO suitable for your OS
○ https://software.cisco.com/download/home/286331591/type/286283941/release/6
.0
○ Locate the installer for your OS (e.g.: Cisco Network Services Orchestrator Linux
Installer) and click download button on the right
○ Once downloaded,
■ cd /home/expert/Downloads
■ sh nso-6.0-freetrial.linux.x86_64.signed.bin
○ Files are unpacked
○ Locate your installer
■ E.g. nso-6.0.linux.x86_64.installer.bin
○ Use the following command to get help with the installation
■ sh nso-6.0.linux.x86_64.installer.bin --help
○ Use the following command to perform the local installation (recommended for
installing NSO for development purpose on laptops)
■ nso-6.0.linux.x86_64.installer.bin [--local-install]
LocalInstallDir
○ Ensure that installation is successful as shown in the above screenshot
● Look at the contents of the nso/packages/neds directory:

● Go to NSO installation folder and execute the following command to add NSO
executable to the PATH
● Alternately you can also add it to the end of bash profile so that NSO executables are
available on system boot up
○ cd nso
○ source ncsrc
● Now we are ready to start using NSO commands that start with its earlier name nsc
○ ncs-setup --help
● If we don't see a command not found error, we are good

Getting Started
● Change to nso installation dir and source ncsrc file to set nso commands in path

$ cd nso
$ source ncsrc

● NSO supports keeping the installation separate from the runtime


● This enables us to create a project specific nso setup to keep the list of devices and their
corresponding configuration separate
● Go to any directory created for working on a project

(main) expert@devnet-lab:~/nso$ cd
(main) expert@devnet-lab:~$ cd work
(main) expert@devnet-lab:~/work$ ls
my_nso my_nso_new
(main) expert@devnet-lab:~/work$ cd my_nso
(main) expert@devnet-lab:~/work/my_nso$

● In this directory create a simple network with a couple of devices using netsim by
choosing some ned available with the installation

(main) expert@devnet-lab:~/work/my_nso$ ls
logs ncs-cdb ncs.conf packages README.ncs README.netsim
scripts state
(main) expert@devnet-lab:~/work/my_nso$ ncs-netsim create-network
cisco-ios-cli-3.8 2 ios
DEVICE ios0 CREATED
DEVICE ios1 CREATED
(main) expert@devnet-lab:~/work/my_nso$ ls
logs ncs-cdb ncs.conf netsim packages README.ncs
README.netsim scripts state
(main) expert@devnet-lab:~/work/my_nso$ ls netsim/ios/
ios0 ios1
(main) expert@devnet-lab:~/work/my_nso$

● Make this as NSO runtime by setting nso in this dir by pointing to netsim directory as
inventory of devices

(main) expert@devnet-lab:~/work/my_nso$ ncs-setup --dest .


--netsim-dir netsim
Using netsim dir netsim
(main) expert@devnet-lab:~/work/my_nso$
● Start the devices and then nso using the following commands

(main) expert@devnet-lab:~/work/my_nso$ ncs-netsim start


DEVICE ios0 OK STARTED
DEVICE ios1 OK STARTED
(main) expert@devnet-lab:~/work/my_nso$ ncs
(main) expert@devnet-lab:~/work/my_nso$ncs --status | grep status
status: started
db=running id=34 priority=1
path=/ncs:devices/device/live-status-protocol/device-type
(main) expert@devnet-lab:~/work/my_nso$

Managing the devices


● Connect to NSO CLI as admin using Cisco-Style
● Sync NSO with our simulated devices

(main) expert@devnet-lab:~/work/my_nso$ ncs_cli -u admin -C

admin connected from 192.168.110.1 using ssh on devnet-lab


admin@ncs# devices sync-from
sync-result {
device ios0
result true
}
sync-result {
device ios1
result true
}
admin@ncs#

● NSO always keeps a copy of the device configuration in CDB and you can easily check if
devices are in sync or not

admin@ncs# devices device ios1 check-sync


result in-sync
admin@ncs#

Configuring the network


● From NCS CLI, get into config mode using the below command

(main) expert@devnet-lab:~/work/my_nso$ ncs_cli -u admin -C


User admin last logged in 2023-06-09T12:37:09.88296+00:00, to
devnet-lab, from 192.168.110.1 using cli-ssh
admin connected from 192.168.110.1 using ssh on devnet-lab
admin@ncs# config
Entering configuration mode terminal
admin@ncs(config)#

● Examine the existing configuration as follows

admin@ncs(config)# show full-configuration devices device ios1


config
devices device ios1
config
tailfned device netsim
tailfned police cirmode
no service password-encryption
no cable admission-control preempt priority-voice
no cable qos permission create
no cable qos permission update
no cable qos permission modems
ip source-route
no ip cef
ip vrf my-forward
bgp next-hop Loopback1

● Configuration of a single device can be changes as follows


○ Get into device config mode using devices device ios0 config
○ Change hostname using ios:hostname nso.cisco.com
○ Move to parent prompt using top
○ Verify the config change using show configuration
○ Commit the configuration changes using commit

admin@ncs(config)# devices device ios0 config


admin@ncs(config-config)# ios:hostname nso.cisco.com
admin@ncs(config-config)# top
admin@ncs(config)# show configuration
devices device ios0
config
hostname nso.cisco.com
!
!
admin@ncs(config)# commit
Commit complete.
admin@ncs(config)#

● At any point if you wish to connect to any device directly, you can do it as follows
(main) expert@devnet-lab:~/work/my_nso$ ncs-netsim cli-c ios0

User admin last logged in 2023-06-09T14:24:30.838836+00:00, to


devnet-lab, from 192.168.110.1 using cli-ssh
admin connected from 192.168.110.1 using ssh on devnet-lab
ios0# show running-config | include hostname
hostname nso.cisco.com
ios0#

Creating Services
● Service is a way of simplifying device configuration by automating service provisioning in
NSO
● To add a service, you need to create a service package, which will have some pre-built
files and directories
● We will use the NSO built in command ncs-make-package with the option
service-skeleton to create a blank service

(main) expert@devnet-lab:~/work/my_nso$ cd packages/


(main) expert@devnet-lab:~/work/my_nso/packages$ ncs-make-package
--service-skeleton template simple-service
(main) expert@devnet-lab:~/work/my_nso/packages$ ls
cisco-ios-cli-3.8 simple-service
(main) expert@devnet-lab:~/work/my_nso/packages$ ls simple-service/
package-meta-data.xml src templates test

● You can see 2 folder created above src, templates


● Check their contents

(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$ ls
src/
Makefile yang
(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$ ls
src/yang/
simple-service.yang
(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$

● Open simple-service.yang
module simple-service {
namespace "http://com/example/simpleservice";
prefix simple-service;

import ietf-inet-types {
prefix inet;
}
import tailf-ncs {
prefix ncs;
}

list simple-service {
key name;

uses ncs:service-data;
ncs:servicepoint "simple-service";

leaf name {
type string;
}

// may replace this with other ways of referring to the


devices.
leaf-list device {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
// replace with your own stuff here
leaf dummy {
type inet:ipv4-address;
}
}
}

● Replace the part that says dummy as follows

// replace with your own stuff here


leaf dummy {
type inet:ipv4-address;
}
}

Replace above section with the below section

leaf secret {
type string;
tailf:info "Enable secret for this device";
}
● Basically we are trying to create a service to enable password on the devices
● Accordingly we are defining how the password should look in the yang data model
● We will now look at the xml template which specifies the configuration as defined in the
yang model

(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$ ls
templates/
simple-service-template.xml
(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$
nano templates/simple-service-template.xml

<config-template xmlns="http://tail-f.com/ns/config/1.0"
servicepoint="simple-service">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<!--
Select the devices from some data structure in the
service
model. In this skeleton the devices are specified in a
leaf-list.
Select all devices in that leaf-list:
-->
<name>{/device}</name>
<config>
<!--
Add device-specific parameters here.
In this skeleton the service has a leaf "dummy"; use that
to set something on the device e.g.:
<ip-address-on-device>{/dummy}</ip-address-on-device>
-->
</config>
</device>
</devices>
</config-template>

● We need to modify the above sample template as shown below

<config-template xmlns="http://tail-f.com/ns/config/1.0"
servicepoint="simple-service">
<devices xmlns="http://tail-f.com/ns/ncs">
<device>
<name>{./device}</name>
<config>
<enable xmlns="urn:ios">
<password>
<secret>{./secret}</secret>
</password>
</enable>
</config>
</device>
</devices>
</config-template>

● After we change yang model, we have to invoke the command make to check for any
errors and compile it
● For instance we made some mistake in yang file which is shown like below

(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$
make -C src
make: Entering directory
'/home/expert/work/my_nso/packages/simple-service/src'
mkdir -p ../load-dir
/home/expert/nso/bin/ncsc `ls simple-service-ann.yang > /dev/null
2>&1 && echo "-a simple-service-ann.yang"` \
--fail-on-warnings \
\
-c -o ../load-dir/simple-service.fxs yang/simple-service.yang
yang/simple-service.yang:34: error: premature end of file
make: *** [Makefile:26: ../load-dir/simple-service.fxs] Error 1
make: Leaving directory
'/home/expert/work/my_nso/packages/simple-service/src'

● After rectifying errors it should look like below

(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$
make -C src
make: Entering directory
'/home/expert/work/my_nso/packages/simple-service/src'
/home/expert/nso/bin/ncsc `ls simple-service-ann.yang > /dev/null
2>&1 && echo "-a simple-service-ann.yang"` \
--fail-on-warnings \
\
-c -o ../load-dir/simple-service.fxs yang/simple-service.yang
make: Leaving directory
'/home/expert/work/my_nso/packages/simple-service/src'

● We can also validate yang file correctness using python module for yang called pyang
● We will use to display yang file in tree format to better understand the hierarchy and
relations
(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$
pyang -f tree --tree-depth=2 src/yang/simple-service.yang
module: simple-service
+--rw simple-service* [name]
+---x check-sync
| ...
+---x deep-check-sync
| ...
+---x re-deploy
| ...
+---x reactive-re-deploy
| ...
+---x touch
| ...
+--ro modified
| ...
+--ro directly-modified
| ...
+---x get-modifications
| ...
+---x un-deploy
| ...
+--ro used-by-customer-service* ->
/ncs:services/customer-service/object-id
+--ro commit-queue
| ...
+--rw private
| ...
+--ro plan-location? instance-identifier
+--ro log
| ...
+--rw name string
+--rw device* -> /ncs:devices/device/name
+--rw secret? string

● We have now defined our service using yang data model and xml config template as a
package
● We now need to connect to nso cli and reload the packages for the changes to take
effect

(main) expert@devnet-lab:~/work/my_nso/packages/simple-service$
ncs_cli -u admin -C

User admin last logged in 2023-06-09T13:51:51.918629+00:00, to


devnet-lab, from 192.168.110.1 using cli-ssh
admin connected from 192.168.110.1 using ssh on devnet-lab
admin@ncs# packages reload

>>> System upgrade is starting.


>>> Sessions in configure mode must exit to operational mode.
>>> No configuration changes can be performed until upgrade has
completed.
>>> System upgrade has completed successfully.
reload-result {
package cisco-ios-cli-3.8
result true
}
reload-result {
package simple-service
result true
}
admin@ncs#
System message at 2023-06-09 16:58:29...
Subsystem stopped: ncs-dp-1-cisco-ios-cli-3.8:IOSDp2
admin@ncs#
System message at 2023-06-09 16:58:29...
Subsystem stopped: ncs-dp-2-cisco-ios-cli-3.8:IOSDp
admin@ncs#
System message at 2023-06-09 16:58:29...
Subsystem started: ncs-dp-3-cisco-ios-cli-3.8:IOSDp2
admin@ncs#
System message at 2023-06-09 16:58:29...
Subsystem started: ncs-dp-4-cisco-ios-cli-3.8:IOSDp

● We can verify the status of packages using the below command

admin@ncs# show packages package oper-status


packages package cisco-ios-cli-3.8
oper-status up
packages package simple-service
oper-status up
admin@ncs#

● Our service is now ready to start configuring the system


● NSO CLI now understand our service and starts offering auto complete hints

admin@ncs(config)# si
Possible completions:
side-effect-queue simple-service
admin@ncs(config)# simple-service ?
% No entries found
Possible completions:
<name:string>
admin@ncs(config)# simple-service
● Use the below command to set the password on the device ios0 to mypasswd
● Verify the config change by moving to parent prompt and using the command show
configuration
● Commit the config changes using the commit command

admin@ncs(config)# simple-service pwdchange device ios0 secret


mypasswd
admin@ncs(config-simple-service-pwdchange)# top
admin@ncs(config)# show configuration
simple-service pwdchange
device [ ios0 ]
secret mypasswd
!
admin@ncs(config)# commit
Commit complete.
admin@ncs(config)#

Modifying a service
● Once we have a service in place, making config modifications is very easy
● Just re invoke the service with the changed config
● For instance if we want to change the password, we can do it as below

admin@ncs(config)# simple-service test1 device ios0 secret


securepasswd
admin@ncs(config-simple-service-test1)# commit
Commit complete.

● Check the modification using the below command

admin@ncs(config-simple-service-test1)# top
admin@ncs(config)# simple-service test1 get-modifications
cli {
local-node {
data
}
}

● It is showing that what has been changed is the actual password, which is nothing but
data
● We can now apply the changed configuration by redeploying the changed service
admin@ncs(config)# simple-service test1 re-deploy
admin@ncs(config)#
System message at 2023-06-09 17:13:31...
Commit performed by admin via ssh using cli.
admin@ncs(config)#

● If the service is no longer needed, we can delete is as below

admin@ncs(config)# no simple-service test1


admin@ncs(config)# commit
Commit complete.
admin@ncs(config)#

NETCONF
● NETCONF is a configuration management protocol that defines a mechanism through
which:
○ A network device can be managed
○ configuration data can be retrieved
○ new configuration data can be uploaded and manipulated
● NETCONF uses SSH for secure communication and data is encoded in XML
● This data should be consistent, standardized and as per certain agreed upon rules, if the
sender and receiver have to be on the same page
● So it can be modeled using YANG

YANG

What is a data model?

● A data model is a well-understood and agreed-upon method to describe "something".


● E.g. Person:
○ First name: the name of the person.
○ Last name: the surname.
○ Date of birth: the day the person was born.
○ Job Role: such as admin, developer, or manager.
○ Email: the email address of the person.
● Sample YANG model to define a person would look like below
list person {
key email;

leaf first-name {
tailf:info "Person's first name";
mandatory true;
type string;
}

leaf last-name {
tailf:info "Person's last name";
mandatory true;
type string;
}

leaf date-of-birth {
tailf:info "Date of birth as dd/mm/yyyy";
type string {
pattern "[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]";
}
}

leaf email {
tailf:info "Contact email";
mandatory true;
type string;
}

leaf job-role {
tailf:info "Persons job role within organization";
type enumeration {
enum admin;
enum developer;
enum manager;
}
}
}

● Data models form the foundation for model-driven APIs and network programmability
● They define the syntax, semantics, and constraints of the data interchanged
● They define data attributes and answer questions, such as the following:
○ What is the range of a valid VLAN ID?
○ Can a VLAN name have spaces in it?
○ Should the values be enumerated and only support "up" or "down" for an admin
state?
○ Should the value be a string or an integer?
● Yet Another Next Generation (YANG) has become a widely used data modeling
language in the networking industry
● Although it can describe any data model, it was originally designed for networking data
models
● It is used to create models of configuration and state data
● It has a structured format that is also human-readable
● The below example shows how YANG defines a model of a network interface

module ietf-interfaces {
import ietf-yang-types {
prefix yang;
}
container interfaces {
list interface {
key "name";

leaf name {
type string;
description
"The name of the interface";
}

leaf description {
type string;
description
"A textual description of the interface";
}

leaf type {
type identityref {
base interface-type;
}
mandatory true;
description
"The type of the interface";
}

leaf enabled {
type boolean;
default true;
description
"The configured state of the interface";
}
}
}

● This YANG model describes ethernet interfaces


● Each individual attribute of the interface is represented by a leaf statement
● Every interface that is modeled with this YANG model has a name, type and description,
and can be enabled or disabled
● Interfaces are uniquely identified with the name. This is defined with the key attribute on
the leaf named "name".

YANG Structure

Modules
● In YANG, all data modeling definitions reside inside YANG modules
● Modules organize related items and place them in groups
● Often a single module describes a complete part of a functionality, such as the Border
Gateway Protocol (BGP) or interface IP configuration
● Other times, a device, especially a simpler one, could implement everything in a single
module
● Module can be defines as shown below

Unset
module ip-access-list {
namespace "http://example.com/ns/yang/ip-access-list";
prefix acl;

// ...
}

● We can add some additional information to this module as shown below

Unset
organization
"Example, Inc.";

contact
"Example, Inc.
Customer Service
E-mail: cs-yang@example.org";
description
"Access Control List (ACL) YANG model.";

revision 2021-07-06 {
description
"Initial revision";
}

● organization: Organization identifies the entity that created the module.


● contact: Contact identifies the contact responsible for the module.
● description: Description statement serves as an overview of the purpose of the
module.
● revision: Revision statement is used for version control, with sub statements detailing
the changes.

Containers and Leaves

● YANG uses different nodes to hold the actual data


● Think of a node as a data structure in a programming language
● The data inside a single node is also described using different data types
● To group several related nodes inside a single node, use a container node
● If you need a simple node for some basic data types, use a leaf node

Unset
container acl {

description

"Access Control Lists";

● A leaf node contains simple data such as an integer or a character string


● You can further restrict values of a particular type with the usage of the pattern,
range, and length restriction statements
● A pattern is defined with the regular expression (regex), range, and length are both
defined with integers

Unset
container acl {

...

leaf acl-description {

type string {

length "0..64";

pattern "[0-9a-zA-Z]*";

description "Purpose of ACL";

● The leaf-list statement defines an array of values, which have the same, specific
type

Unset
container acl {

...

leaf acl-description {

...

leaf-list maintainers {

type string;
description "Maintainers working on the ACL";

● The list node specifies a sequence of list entries and is similar to Python's dictionary
data structure

YANG Data Types

Common Data Types

Type Name Type Description

binary Text Any binary data

bits Text/Number A set of bits or flags

boolean Text "true" or "false"

decimal64 Number 64-bit fixed point real number

empty Empty A leaf that does not have any value

enumeration Text/Number Enumerated strings with associated numeric


values

identityref Text A reference to an abstract identity

instance-identifier Text References a data tree node

int8 Number 8-bit signed integer

int16 Number 16-bit signed integer

int32 Number 32-bit signed integer

int64 Number 64-bit signed integer

leafref Text/Number A reference to a leaf instance

string Text Human readable string


uint8 Number 8-bit unsigned integer

uint16 Number 16-bit unsigned integer

uint32 Number 32-bit unsigned integer

uint64 Number 64-bit unsigned integer

union Text/Number Choice of member types

Enumeration
● Used to define a finite set of values allowed
○ true/ false
○ enabled/ disabled
○ ipv4/ ipv6

Section 2.0: Python Crash Course

What is Program?
● A program is a set of instructions given to a computer to perform a specific operation
using some data
● When the program is executed, raw data is processed into a desired output format
● These programs are written in high-level programming languages which are close to
human languages
● They are then converted to machine understandable low level languages and
executed

What is Python?
● Python is an interpreted, object oriented, high-level, scripting language used for
general-purpose programming
● It has wide range of applications ranging from Web Development, Scientific and
Mathematical Computing to Desktop Graphical User Interfaces
● It was created by Guido van Rossum and first released in 1991

Why Python?
● Python interpreters are available for many operating systems including network
operating systems
● Cisco puts Python on many of its devices and releases many tools using Python
● This makes Python a great choice for network engineers looking to add programming
to their skillset
● For network and IT infrastructure engineers, there is a well-established online community
of infrastructure engineers using Python to deploy and maintain IT systems
Install Python
● If you are using Cisco CWS, Python is already installed and ready for use the moment
you connect to CWS as user expert
● If You want to set it up on any other VM or your laptop you can follow the steps below
● On Windows
○ Download the installer from https://www.python.org/downloads/
○ Invoke the installer executable and follow the steps in the installation wizard
● On Ubuntu
○ By default Ubuntu comes with Python older version that is python2
○ Now a days certain Ubuntu distributions come preinstalled with python3
○ Check which version is already installed using the below command
■ python -–version
○ If you get a message like command not found or you get the result showing
python version as 2.x, you can proceed further
○ If the result shows the version as 3.x, you are good to go, unless you want to
update to the latest version
○ To install latest version follow the link
https://www.makeuseof.com/install-python-ubuntu/
○ Or any other link of your choice

Getting started
● Check which version of python are you using

(main) expert@devnet-lab:~$ python -V


Python 3.9.10
(main) expert@devnet-lab:~$

● Python is an interpreted language (as opposed to being a compiled language)


● Check which interpreter you are using

(main) expert@devnet-lab:~$ which python


/home/expert/venvs/main/bin/python
(main) expert@devnet-lab:~$

● Start using interpreter in CLI mode

(main) expert@devnet-lab:~$ python


Python 3.9.10 (main, Jan 15 2022, 18:17:56)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more
information.
>>>

Data Types
● All we are doing as part of our work is using and manipulating data
● Data comes in various types like:
○ Names of network devices: Group of alphabets - Strings (str)
○ Number of interfaces: Number (Integers) (int)
○ Information like whether certain interface is enabled or not: True or False
(Boolean) (bool)
○ OS version of certain router or switch: Number (Decimals or Floating point
numbers) (float)
○ List of spine and leaf switches: Collection of names (List)
○ A switch with all its attributes like: Name of the attribute mapped to its value
■ Make or manufacturer: Cisco/ Juniper etc.
■ Model: Cisco CSR 1000
■ OS Version: 16.9
■ Name: brch_rtr_01
■ And so on
● Looking at a piece of data it is easy for humans to understand its type, but for machines
it is not
● So we need to explicitly let the systems know what is the type of data we are dealing
with
● To do this every programming language uses some data types
● Python has the following basic data types
○ Text Type : Strings (str)
○ Numeric Types : Numbers (int, float, complex)
○ Sequence Types : Lists, Tuples, Set (list, tuple, set)
○ Mapping Type : Dictionaries (dict)
○ Boolean Type : bool

Variables
● Now that we are talking about different types of data, we need a way to store this data
during the program (or code as we call it) execution
● We use variables for this purpose
● Variables are named locations used to store data in memory
● Think of them like containers that holds data
● Data held by the variable can change later
● When we create a variable, we are telling the system to keep some storage aside
● How much storage to keep aside depends on the type of data that is going to be stored
in that variable
● Let us create few variables and display them on the console using an inbuilt utility or
function called print()
● By the way, we can use Python Interpreter CLI to give any python commands and
perform some basic operations
● In CLI mode you do not need to use print() function. Directly type the name of the
variable and the value stored in it will be displayed
● Use suggestive names for the variables based on what they are used to store

(main) expert@devnet-lab:~$ python


Python 3.9.10 (main, Jan 15 2022, 18:17:56)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more
information.
>>> hostname = "brch_rtr_01"
>>> make = "Nexus"
>>> model = "9300v"
>>> os_version = 9.3
>>> num_intfcs = 4
>>> print(hostname)
brch_rtr_01
>>> print(make)
Nexus
>>> num_intfcs
4
>>>

● We can check the type of data stored in a variable using another built in function called
type()

>>> type(model)
<class 'str'>
>>> type(os_version)
<class 'float'>
>>> type(num_intfcs)
<class 'int'>
>>>

Operators
● Data manipulation requires that we are able to perform certain operations on the data
● We will use operators for this purpose
● Accordingly every programming language, including python has certain operators
defined
● Depending on the types of operations they are classified as follows
○ Arithmetic Operators
○ Assignment Operators
○ Comparison Operators
○ Logical Operators
○ Special Operators

Arithmetic Operators
● Used to perform arithmetic operations on variables

Operator Operation Example

+ Addition 5 + 2 = 7

- Subtraction 4 - 2 = 2

* Multiplication 2 * 3 = 6

/ Division 4 / 2 = 2

// Floor Division 10 // 3 = 3

% Modulo 5 % 2 = 1

** Power 4 ** 2 = 16

a = 7
b = 2

# addition
print ('Sum: ', a + b)

# subtraction
print ('Subtraction: ', a - b)

# multiplication
print ('Multiplication: ', a * b)

# division
print ('Division: ', a / b)

# floor division
print ('Floor Division: ', a // b)

# modulo
print ('Modulo: ', a % b)

# a to the power b
print ('Power: ', a ** b)

Assignment Operators
● Used to assign values to variables

Operator Name Example

= Assignment Operator a = 7

+= Addition Assignment a += 1 # a = a + 1

-= Subtraction Assignment a -= 3 # a = a - 3

*= Multiplication Assignment a *= 4 # a = a * 4

/= Division Assignment a /= 3 # a = a / 3

%= Remainder Assignment a %= 10 # a = a % 10

**= Exponent Assignment a **= 10 # a = a ** 10

# assign 10 to a
a = 10

# assign 5 to b
b = 5

# assign the sum of a and b to a


a += b # a = a + b

print(a)

# Output: 15

Comparison Operators
● Used to compare the value or variables
● Result of the comparison operators is always true or false (boolean)

Operator Meaning Example


== Is Equal To 3 == 5 gives us False

!= Not Equal To 3 != 5 gives us True

> Greater Than 3 > 5 gives us False

< Less Than 3 < 5 gives us True

>= Greater Than or Equal To 3 >= 5 give us False

<= Less Than or Equal To 3 <= 5 gives us True

a = 5

b = 2

# equal to operator
print('a == b =', a == b)

# not equal to operator


print('a != b =', a != b)

# greater than operator


print('a > b =', a > b)

# less than operator


print('a < b =', a < b)

# greater than or equal to operator


print('a >= b =', a >= b)

# less than or equal to operator


print('a <= b =', a <= b)

Logical Operators
● Used to check truthiness or falseness of expressions

Operator Example Meaning

and a and b Logical AND: True only if both the operands are True
or a or b Logical OR: True if at least one of the operands is True

not not a Logical NOT: True if the operand is False and


vice-versa.

# logical AND
print(True and True) # True
print(True and False) # False

# logical OR
print(True or False) # True

# logical NOT
print(not True) # False

Special Operators
● Used to verify identity or check membership

Operator Meaning Example

is True if the operands are identical (refer to the same object) x is True

is not True if the operands are not identical (do not refer to the same x is not
object) True

in True if value/variable is found in the sequence 5 in x

not in True if value/variable is not found in the 5 not in x


sequence

x = 'Hello world'

# check if 'H' is present in x string


print('H' in x) # prints True

# check if 'hello' is present in x string


print('hello' not in x) # prints True
Getting Input from the user
● We have seen how to print something to the console, which we normally call output
● We can also take something from the console as input
● We use a built in function called input() for this
● This is useful in taking input from the console and assigning it to variables using the
assignment operator
● By default the input from the console will be read as a string
● Let us read the following input from the console and store them in appropriate variables
○ Number of edge routers
○ Names of those edge routers
○ Their IP Addresses

>>> num_routers = input('Enter the number of edge routers:')


Enter the number of edge routers:2
>>> router1_name = input('Enter the name of the first router:')
Enter the name of the first router:edge_rtr_01
>>> router2_name = input('Enter the name of the second router:')
Enter the name of the second router:edge_rtr_02
>>> router1_ip = input('Enter the IP Address of the first router:')
Enter the IP Address of the first router:192.168.10.1
>>> router2_ip = input('Enter the IP Address of the second
router:')
Enter the IP Address of the second router:192.168.10.2
>>> print(router2_name)
edge_rtr_02
>>>

Data Types - Deep Dive

Strings
● Strings are sequence of characters enclosed by quotes
● Single or double quotes are accepted, but be consistent
● Create a variable called hostname and assign it the value of "ROUTER1"

>>> hostname = 'edge_rtr_01'


>>> type(hostname)
<class 'str'>
>>>

● Strings are very useful in Python as most of the time we end up working with strings
● Some of the built in methods on strings are shown below
Methods Description

upper() converts the string to uppercase

lower() converts the string to lowercase

partition() returns a tuple

replace() replaces substring inside

find() returns the index of first occurrence of substring

rstrip() removes trailing characters

split() splits string from left

startswith() checks if string starts with the specified string

isnumeric() checks numeric characters

index() returns index of substring

Lists
● Lists are sequence data type used to store multiple values or objects
● It's one of the most frequently used and versatile data type
● It is an ordered sequence, meaning elements of a list are indexed by integers starting at
0
● Similar to arrays in other programming languages
● But elements of a list can be of any data type
● An example is shown below

>>> commands = ["interface Etherent1/1", "switchport access vlan


10"]
>>> commands
['interface Etherent1/1', 'switchport access vlan 10']
>>> type(commands)
<class 'list'>
>>>

● List is an ordered collection, which means that the elements in the list are indexed
● We can retrieve elements of a list using an index
● Indexing in lists starts from 0
● Lists also support negative indexing which helps us to traverse the list in reverse
● Some useful methods on lists are shown below
Method Description

append() add an item to the end of the list

extend() add items of lists and other iterables to the end of the
list

insert() inserts an item at the specified index

remove() removes item present at the given index

pop() returns and removes item present at the given index

clear() removes all items from the list

index() returns the index of the first matched item

count() returns the count of the specified item in the list

sort() sort the list in ascending/descending order

reverse() reverses the item of the list

copy() returns the shallow copy of the list

Tuples
● A tuple in Python is similar to a list
● The difference between the two is that we cannot change the elements of a tuple once it
is assigned
● We call this property as immutability
● A tuple is created by placing all the items (elements) inside parentheses ‘(‘, ‘)’
● Similar to lists, tuples can have any number of elements and of any type
● From memory management point of view tuples are more efficient than lists
● Also tuples are used where we do not expect the variable to be changed accidentally
● There are not too many built in methods are available for Tuples as they cannot be
modified once created
● We just have count() and index() methods on tuples

Dictionaries
● Dictionaries are mapping data types where data is stored as combination of key, value
pairs
● We can think of them as unordered lists
● Unlike lists instead being indexed by a number, dictionaries are indexed by a name
known as key
● Also known with other names like hashes or associative arrays
● Let us create a simple dictionary to store the details of a network device

>>> dev_dict = {'vendor': 'cisco', 'hostname': 'csr2', 'ip':


'10.10.10.2'}
>>> dev_sub_dict = dev_dict["hostname"]
>>> dev_sub_dict
'csr2'
>>>

● But why do we need a new data type like a dictionary? Why can't we use one of the
existing ones like a list?
● Let us relook at a list which stores similar details

>>> dev = ['sw1', '10.1.100.1/24', '00:00:00:00:00:01']


>>> # hostname is stored at index 0
>>> # mac address is stored at index 2

● Looking at the values stored in the list, we have to guess what they stand for
● Instead we can associate them with appropriate keys in the dictionary

>>> dev = {'hostname':'sw1', 'mgmt_ip':'10.1.100.1/24',


'mac':'00:00:00:00:00:01'}
>>> type(dev)
<class 'dict'>
>>> dev
{'hostname': 'sw1', 'mgmt_ip': '10.1.100.1/24', 'mac':
'00:00:00:00:00:01'}
>>>

You might also like