NSOカスタムサービスパッケージでのデバイスへのコンフィグデプロイ

#初めに
[前回](https://qiita.com/masanobu48154/items/85cf7ed6e51c2d9ae5b8)、NSOにサービスパッケージを追加しYANGでデータのモデリングを行いましたが、そのモデルを使って実際にデバイスへのコンフィグ反映はしてなかったので、今回はXMLのコンフィグテンプレートにマッピングし、DevNet SandboxのCML2のコアルータに設定反映させるまでのデモを行いました。

YANGの作成デモは[こちら](https://qiita.com/masanobu48154/items/85cf7ed6e51c2d9ae5b8)です。

[YANGモデルの理解のためのNSOカスタムサービスパッケージの追加デモ(2/2)](https://qiita.com/masanobu48154/items/85cf7ed6e51c2d9ae5b8)

DevNetのLearning Moduleの「NSO Basics for Network Automation」を見ればもっと詳しく記載されてます。

[-NSO Basics for Network Automation](https://developer.cisco.com/learning/modules/nso-basics)

#前回定義したYANG
[前回](https://qiita.com/masanobu48154/items/85cf7ed6e51c2d9ae5b8)は、YANGモデルの構成を理解することを目的として、NSOにカスタムサービスパッケージを追加しYANGデータモデルを作成しました。

<dl>
  <dt>デモ環境</dt>
  <dd>DevNet Sandbox 『Cisco Network Services Orchestrator』</dd>
</dl>
<dl>
 <dt>内容</dt>
 <dd>Sandbox内のCML2で構築したL3VPN(SR-MPLS)に新たなサイトを追加するカスタムサービスパッケージを追加、サイト追加に必要なコンフィグデータのYANGモデリング</dd>
</dl>

```yang:maintainers-base.yang
module maintainers-base {
  namespace "http://example.com/us/yang/maintainers-base";
  prefix base;
  description "The Base Modele For The maintainers.";

  identity base-maintainers {
    description "Cutom identity for the base protocol";
  }
  identity IEYASU {
    base base-maintainers;
    description "The Member of Maintainers";
  }
  identity HIDETADA {
    base base-maintainers;
    description "The Member of Maintainers";
  }
  identity IEMITSU {
    base base-maintainers;
    description "The Member of Maintainers";
  }
}
```
> これは、add-vpn-service.yangにインポートされるidentityを定義したYANGファイルです。

```yang:add-vpn-service.yang
module add-vpn-service {
  namespace "http://example.com/ns/yang/add-vpn-service";
  prefix vpn;

  import ietf-inet-types {
    prefix inet;
  }

  import tailf-ncs {
    prefix ncs;
  }

  import maintainers-base {
    prefix maintainers;
  }

  organization
    "EXAMPLE SYSTEMS";

  contact
    "EXAMPLE SYSTEMS
     Customer Service
     E-mail: example@example.com";

  description
    "L3VPN YANG Model.";

  revision 2021-10-15 {
    description
      "Initial revision";
  }

  typedef rdrt-type {
    type union {
      type string {
        pattern "[0-9]{1,5}:[0-9]{1,5}";
      }
      type enumeration {
        enum "65432:111";
        enum "65432:222";
      }
    }
  }

  identity IETSUNA {
    base maintainers:base-maintainers;
    description "The Member of Maintainers";
  }
  identity TSUNATOSHI {
    base maintainers:base-maintainers;
    description "The Member of Maintainers";
  }

  container vpn {
    description "L3vpn vrf";

    list vpn-policy {
      key "policy-name";
      description "VRF Configured Policy";

      leaf policy-name {
        type string;
      }

      leaf device {
        type leafref {
          path "/ncs:devices/ncs:device/ncs:name";
        }
        description "Configured Device Name";
      }

      leaf-list maintainer-members {
        type identityref {
          base maintainers:base-maintainers;
        }
        description "Maintainers of Customer";
      }

      container vrf {
        description "Vrf container";

        leaf vrf-name {
          type string;
          description "VRF Name";
        }

        leaf rd {
          type rdrt-type;
          description "Route Distinguisher and Route target";
        }

        leaf route-target-export {
          type rdrt-type;
          description "Route Target Export";
        }

        leaf-list route-target-import {
          type rdrt-type;
          description "Route Target Export";
        }
      }

      container loopback {
        description "Loopback container";

        leaf loopback-number {
          type uint16;
          description "Loopback Interface Number";
        }

        leaf loopback-ip {
          type inet:ipv4-address;
          description "Loopback IPv4 Address.";
        }
      }
    }
  }
}
```
> 新たなサイトを追加するために、①設定を追加するデバイス、②VRFの追加、③VRFに所属するLoopbackアドレスの追加、を中心に定義しました。

#コンフィグテンプレートXML
NSOは全てのデバイスのコンフィグをXMLで管理します。NSOからダイナミックにデバイスに設定する場合は、YANGで定義したnode(変数)を、このXMLにマッピングする必要があります。
XMLへのマッピングはそんなに難しくはありません。NSOからncs_cli経由でデバイスに実際に必要なコンフィグを投入すれば、その内容をXMLでアウトプットすることができます。
例えば、core-rtr01にVRF、route-target-import、route-target-exportを設定するとします。

```shell
developer@ncs(config-config)# vrf TEST
developer@ncs(config-vrf)# address-family ipv4 unicast 
developer@ncs(config-vrf-af)# export route-target 65432:444
developer@ncs(config-vrf-export-rt)# exit
developer@ncs(config-vrf-af)# import route-target 65432:444
developer@ncs(config-vrf-import-rt)# top
```
`commit`せずに`show configuration | display xml`で設定内容をxmlで出力できます。

```xml
developer@ncs(config)# show configuration | display xml
<devices xmlns="http://tail-f.com/ns/ncs">
  <device>
    <name>core-rtr01</name>
    <config>
      <vrf xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <vrf-list>
          <name>TEST</name>
          <address-family>
            <ipv4>
              <unicast>
                <import>
                  <route-target>
                    <address-list>
                      <name>65432:444</name>
                    </address-list>
                  </route-target>
                </import>
                <export>
                  <route-target>
                    <address-list>
                      <name>65432:444</name>
                    </address-list>
                  </route-target>
                </export>
              </unicast>
            </ipv4>
          </address-family>
        </vrf-list>
      </vrf>
    </config>
  </device>
</devices>
developer@ncs(config)# 
```
このXMLに、VRF名や、route-target-import、route-target-importの値の部分にYANGで定義したnode(変数)をマッピングします。

> コンフィグテンプレートXMLは`ncs-make-package`コマンドでサービスパッケージを構成すれば、`templates/`ディレクトリ配下に自動的に作成されます。


#デモの目的、概要、手順
今回はXMLのコンフィグテンプレートにYANGで定義したnode(変数)をマッピングし、DevNet SandboxのCML2のコアルータに設定反映させるまでのデモを行います。

<dl>
  <dt>デモ環境</dt>
  <dd>DevNet Sandbox 『Cisco Network Services Orchestrator』</dd>
</dl>
<dl>
 <dt>内容</dt>
 <dd>Sandbox内のCML2で構築したL3VPN(SR-MPLS)に新たなサイトを追加するカスタムサービスパッケージを追加、デバイスに反映するためのコンフィグテンプレートXMLに、YANGモデルのnode(変数)をマッピング</dd>
</dl>
<dl>
 <dt>手順</dt>
 <dd>⓪事前準備<br>
①サービスパッケージの作成<br>
②YANGモデルの編集<br>
③コンフィグテンプレートXMLの編集<br>
④reload packages<br>
⑤設定反映<br>
⑥Re-deploying<br>
⑦Rollback<br>
 </dd>
</dl>

#事前準備

<dl>
  <dt>1. DevNet Sandbox を予約</dt>
  <dd>『Cisco Network Services Orchestrator』を予約します。Sandboxの予約の仕方については、下記の記事が大変参考になります。
　</dd>
</dl>

[- 『DevNet Sandbox を使って pyATS/XPRESSO を CML2 と始めよう』](https://qiita.com/tahigash/items/753cffdbf6380afa823f)

![スクリーンショット 2021-10-14 11.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1834983/caa103cc-1d82-9f3e-fb09-6e69d7b3dbd6.png)

Sandboxで『Cisco Network Services Orchestrator』がアクティブになれば環境の準備は完了です。

<dl>
  <dt>2. Sandbox内CML2で稼働しているコアルータに追加設定</dt>
  <dd>Sandboxがアクティブなったら、CML2のコアルータ（core-rtr01、core-rtr02）にL3VPN(SR-MPLS)のコンフィグを追加設定します。</dd>
</dl>

<details>
  <summary>core-rtr01 コンフィグ</summary>
  <div>

```shell:core-rtr01.cfg
vrf A
 address-family ipv4 unicast
  import route-target
   65432:111
  !
  export route-target
   65432:111
  !
 !
!
vrf B
 address-family ipv4 unicast
  import route-target
   65432:222
  !
  export route-target
   65432:222
  !
 !
!
interface loopback0
 ipv4 address 172.16.252.101 255.255.255.255
 no shutdown
!
interface Loopback111
 vrf A
 ipv4 address 1.1.1.1 255.255.255.255
 no shutdown
!
interface Loopback222
 vrf B
 ipv4 address 2.2.2.1 255.255.255.255
 no shutdown
!
router bgp 65432
 bgp router-id 172.16.252.101
 bgp log neighbor changes detail
 address-family vpnv4 unicast
 !
 neighbor 172.16.252.102
  remote-as 65432
  update-source Loopback0
  address-family vpnv4 unicast
  !
 !
 vrf A
  rd 65432:111
  address-family ipv4 unicast
   !
   redistribute connected
  !
 !
 vrf B
  rd 65432:222
  address-family ipv4 unicast
   !
   redistribute connected
  !
 !
!
segment-routing
 global-block 16000 18000
!
router ospf 1
 segment-routing mpls
 area 0
  segment-routing mpls
  interface Loopback0
   prefix-sid index 111
```

  </div>
</details>
<details>
  <summary>core-rtr02 コンフィグ</summary>
  <div>

```shell:core-rtr02.cfg
vrf A
 address-family ipv4 unicast
  import route-target
   65432:111
  !
  export route-target
   65432:111
  !
 !
!
vrf B
 address-family ipv4 unicast
  import route-target
   65432:222
  !
  export route-target
   65432:222
  !
 !
!
interface loopback0
 ipv4 address 172.16.252.102 255.255.255.255
 no shutdown
!
interface Loopback111
 vrf A
 ipv4 address 1.1.1.2 255.255.255.255
 no shutdown
!
interface Loopback222
 vrf B
 ipv4 address 2.2.2.2 255.255.255.255
 no shutdown
!
router bgp 65432
 bgp router-id 172.16.252.102
 bgp log neighbor changes detail
 address-family vpnv4 unicast
 !
 neighbor 172.16.252.101
  remote-as 65432
  update-source Loopback0
  address-family vpnv4 unicast
  !
 !
 vrf A
  rd 65432:111
  address-family ipv4 unicast
   !
   redistribute connected
  !
 !
 vrf B
  rd 65432:222
  address-family ipv4 unicast
   !
   redistribute connected
  !
 !
!
segment-routing
 global-block 16000 18000
!
router ospf 1
 segment-routing mpls
 area 0
  segment-routing mpls
  interface Loopback0
   prefix-sid index 222
```

  </div>
</details>

> コアルータにはtelnetで接続することができます。
username:cisco
password:cisco
core-rtr01:10.10.20.173
core-rtr02:10.10.20.174

core-rtr01のVRF A、VRF Bで、SR-MPLSでのL3VPNが確立されたか確認します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso ~]$ telnet 10.10.20.173
Trying 10.10.20.173...
Connected to 10.10.20.173.
Escape character is '^]'.



IMPORTANT:  READ CAREFULLY
Welcome to the Demo Version of Cisco IOS XRv (the "Software").
The Software is subject to and governed by the terms and conditions
of the End User License Agreement and the Supplemental End User
License Agreement accompanying the product, made available at the
time of your order, or posted on the Cisco website at
www.cisco.com/go/terms (collectively, the "Agreement").
As set forth more fully in the Agreement, use of the Software is
strictly limited to internal use in a non-production environment
solely for demonstration and evaluation purposes.  Downloading,
installing, or using the Software constitutes acceptance of the
Agreement, and you are binding yourself and the business entity
that you represent to the Agreement.  If you do not agree to all
of the terms of the Agreement, then Cisco is unwilling to license
the Software to you and (a) you may not download, install or use the
Software, and (b) you may return the Software as more fully set forth
in the Agreement.


Please login with any configured user/password, or cisco/cisco


User Access Verification

Username: cisco
Password:


RP/0/0/CPU0:core-rtr01#
RP/0/0/CPU0:core-rtr01#sh bgp vpnv4 unicast
Fri Oct 15 00:40:33.165 UTC
BGP router identifier 172.16.252.101, local AS number 65432
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0x0   RD version: 0
BGP main routing table version 15
BGP NSR Initial initsync version 9 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs

Status codes: s suppressed, d damped, h history, * valid, > best
              i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
   Network            Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65432:111 (default for vrf A)
*> 1.1.1.1/32         0.0.0.0                  0         32768 ?
*>i1.1.1.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:222 (default for vrf B)
*> 2.2.2.1/32         0.0.0.0                  0         32768 ?
*>i2.2.2.2/32         172.16.252.102           0    100      0 ?

Processed 4 prefixes, 4 paths
RP/0/0/CPU0:core-rtr01#
```
  </div>
</details>

> core-rtr02から、VRF Aでは1.1.1.2/32を、VRF Bからは2.2.2.2/32を受信してます。

VRFを VRF Aに指定したpingを試します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
RP/0/0/CPU0:core-rtr01#ping vrf A 1.1.1.2 source 1.1.1.1
Thu Oct 14 03:26:49.226 UTC
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 1.1.1.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 9/11/19 ms
RP/0/0/CPU0:core-rtr01#
```
> core-rtr01から、VRF Aでpingも通りました。

  </div>
</derails>

> core-rtr01のloopback111(1.1.1.1)から、core-rtr02のloopback111(1.1.1.2)へ通りました。

Sandboxで『Cisco Network Services Orchestrator』がアクティブになり、core-rtr01と、core-rtr02間でSR-MPLSでのL3VPNが確立されれば環境の準備完了です。

#サービスパッケージの作成
今回はNSOのインスタンスが起動済みで、CML2内の仮装デバイスを全て登録しコンフィグもsync済みのNSOを利用します。
NSO(10.10.20.49)にSSHで接続します。usernameは`developer`、passwordは`C1sco12345`でログインできます。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
(py3venv) [developer@devbox ~]$ ssh -l developer 10.10.20.49
Warning: Permanently added '10.10.20.49' (ECDSA) to the list of known hosts.
developer@10.10.20.49's password: 
Last login: Thu Oct 14 22:34:04 2021 from 192.168.254.11
[developer@nso ~]$ 
```

  </div>
</details>

NSOはYANGファイルをそのままの形式では使用できないため、最初にコンパイルする必要があります。コンパイルにはMakefileなどが必要になるので、YANGモデルを作成する前に、テンプレートとなるYANGファイルや、コンパイルに必要なファイルを含んだサービスパッケージを`ncs-make-package`コマンドで作成する必要があります。
サービスパッケージは所定のディレクトリに展開する必要があるので、コマンドは`/var/opt/ncs/packages/`に移動してから入力します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso ~]$ cd /var/opt/ncs/packages/
[developer@nso packages]$ ncs-make-package --service-skeleton template add-vpn-service
```

  </div>
</details>

> `ncs-make-package`コマンドによって、`add-vpn-service/`ディレクトリが作成されました。
`add-vpn-service/src/`ディレクトリにコンパイルが必要なすべてのファイルとMakefileが配置されています。 Makefileは、`make`コマンドによってソースファイルをビルドする時に必要となります。`./src/yang/`配下にあるすべてのYANGファイルを検索し、それらをNSO互換（バイナリ）形式にコンパイルされます。

重要なファイルは、__`add-vpn-service/src/yang/`__にあるYANGファイルと、__`add-vpn-service/templates/`__にあるXMLファイルです。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso packages]$ tree add-vpn-service/
add-vpn-service/
├── package-meta-data.xml
├── src
│   ├── Makefile
│   └── yang
│       └── add-vpn-service.yang
├── templates
│   └── add-vpn-service-template.xml
└── test
    ├── Makefile
    └── internal
        ├── Makefile
        └── lux
            ├── Makefile
            └── basic
                ├── Makefile
                └── run.lux
```
  </div>
</details>



`add-vpn-service/src/yang/`ディレクトリにテンプレートとなるYANGファイルが作成されます。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso packages]$ ls add-vpn-service/src/yang/
add-vpn-service.yang
```
  </div>
</details>

`add-vpn-service/templates/`ディレクトリにテンプレートとなるコンフィグテンプレートXMLファイルが作成されます。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso packages]$ ls add-vpn-service/templates/
add-vpn-service-template.xml
```
  </div>
</details>

#YANGモデルの編集
`add-vpn-service/src/yang/`ディレクトリにテンプレートとなるYANGファイルが作成されますが削除し、前回作成した2つのYANGファイルを`touch`と`vim`で同じディレクトリにコピーします。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:
[developer@nso packages]$ rm add-vpn-service/src/yang/add-vpn-service.yang
[developer@nso packages]$ touch add-vpn-service/src/yang/maintainers-base.yang
[developer@nso packages]$ vim add-vpn-service/src/yang/maintainers-base.yang
[developer@nso packages]$ touch add-vpn-service/src/yang/add-vpn-service.yang
[developer@nso packages]$ vim add-vpn-service/src/yang/add-vpn-service.yang
```
  </div>
</details>

`make`でコンパイルします。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ cd add-vpn-service/src/
[developer@nso src]$ YANGPATH="./yang" make
mkdir -p ../load-dir
/opt/ncs/current/bin/ncsc  `ls add-vpn-service-ann.yang  > /dev/null 2>&1 && echo "-a add-vpn-service-ann.yang"` \
             --yangpath ./yang -c -o ../load-dir/add-vpn-service.fxs yang/add-vpn-service.yang
/opt/ncs/current/bin/ncsc  `ls maintainers-base-ann.yang  > /dev/null 2>&1 && echo "-a maintainers-base-ann.yang"` \
             --yangpath ./yang -c -o ../load-dir/maintainers-base.fxs yang/maintainers-base.yang
[developer@nso src]$ 
```
  </div>
</details>

> YANGPATH = "./yang"の部分は、必要なモジュールがないかYANGフォルダーも検索するようにビルドシステムに指示します。これがないと、システムがモジュールmaintainers-baseを見つけられないというエラーが発生する場合があります。

NSO cliにdeveloperユーザーで接続します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso src]$ ncs_cli -C -u developer

User developer last logged in 2021-10-19T22:39:35.383339-00:00, to nso, from 10.10.20.49 using rest-https
developer connected from 192.168.254.11 using ssh on nso
developer@ncs# 
```

  </div>
</details>

一つのパッケージに変更を適用した後でも、オペレーションモードの`packages reload`コマンドですべてのパッケージをリロードする必要があります。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@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 add-vpn-service
    result false
    info add-vpn-service-template.xml:2 Unknown servicepoint: add-vpn-service
}
reload-result {
    package cisco-asa-cli-6.12
    result true
}
reload-result {
    package cisco-ios-cli-6.67
    result true
}
reload-result {
    package cisco-iosxr-cli-7.32
    result true
}
reload-result {
    package cisco-nx-cli-5.20
    result true
}
reload-result {
    package resource-manager
    result true
}
reload-result {
    package selftest
    result true
}
reload-result {
    package svi_verify_example
    result true
}
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem stopped: ncs-dp-2-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem stopped: ncs-dp-3-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem stopped: ncs-dp-4-resource-manager:AddressallocationIPvalidation
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem stopped: ncs-dp-1-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem started: ncs-dp-5-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem started: ncs-dp-6-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem started: ncs-dp-7-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-19 23:46:00...
    Subsystem started: ncs-dp-8-resource-manager:AddressallocationIPvalidation
developer@ncs# *** ALARM package-load-failure: add-vpn-service-template.xml:2 Unknown servicepoint: add-vpn-service
developer@ncs# 
```
  </div>
</details>
> `Unknown servicepoint: add-vpn-service`というエラーが出てます。これは、コンフィグテンプレートXMLに定義されている`servicepoint`が、同じサービスパッケージのYANGには定義されていないからです。

サイト追加のコンフィグについてデータモデリングした__add-vpn-service.yang__に同じ`servicepoint`を`list vpn-policy`の直下に追加します。

```yang:add-vpn-service.yang
module add-vpn-service {
  namespace "http://example.com/ns/yang/add-vpn-service";
  prefix vpn;

  import ietf-inet-types {
    prefix inet;
  }

  import tailf-ncs {
    prefix ncs;
  }

  import maintainers-base {
    prefix maintainers;
  }

  organization
    "EXAMPLE SYSTEMS";

  contact
    "EXAMPLE SYSTEMS
     Customer Service
     E-mail: example@example.com";

  description
    "L3VPN YANG Model.";

  revision 2021-10-15 {
    description
      "Initial revision";
  }

  typedef rdrt-type {
    type union {
      type string {
        pattern "[0-9]{1,5}:[0-9]{1,5}";
      }
      type enumeration {
        enum "65432:111";
        enum "65432:222";
      }
    }
  }

  identity IETSUNA {
    base maintainers:base-maintainers;
    description "The Member of Maintainers";
  }
  identity TSUNATOSHI {
    base maintainers:base-maintainers;
    description "The Member of Maintainers";
  }

  container vpn {
    description "L3vpn vrf";

    list vpn-policy {
      key "policy-name";
      description "VRF Configured Policy";

      uses ncs:service-data;
      ncs:servicepoint "add-vpn-service";

      leaf policy-name {
        type string;
      }

      leaf device {
        type leafref {
          path "/ncs:devices/ncs:device/ncs:name";
        }
        description "Configured Device Name";
      }

      leaf-list maintainer-members {
        type identityref {
          base maintainers:base-maintainers;
        }
        description "Maintainers of Customer";
      }

      container vrf {
        description "Vrf container";

        leaf vrf-name {
          type string;
          description "VRF Name";
        }

        leaf rd {
          type rdrt-type;
          description "Route Distinguisher and Route target";
        }

        leaf route-target-export {
          type rdrt-type;
          description "Route Target Export";
        }

        leaf-list route-target-import {
          type rdrt-type;
          description "Route Target Export";
        }
      }

      container loopback {
        description "Loopback container";

        leaf loopback-number {
          type uint16;
          description "Loopback Interface Number";
        }

        leaf loopback-ip {
          type inet:ipv4-address;
          description "Loopback IPv4 Address.";
        }
      }
    }
  }
}
```

YANGファイルを修正し、再度`make`、`packages reload`します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso src]$ vim ./yang/add-vpn-service.yang 
[developer@nso src]$ YANGPATH="./yang" make
/opt/ncs/current/bin/ncsc  `ls add-vpn-service-ann.yang  > /dev/null 2>&1 && echo "-a add-vpn-service-ann.yang"` \
             --yangpath ./yang -c -o ../load-dir/add-vpn-service.fxs yang/add-vpn-service.yang
[developer@nso src]$ ncs_cli -C -u developer

User developer last logged in 2021-10-19T23:43:34.017986-00:00, to nso, from 192.168.254.11 using cli-ssh
developer connected from 192.168.254.11 using ssh on nso
developer@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 add-vpn-service
    result true
}
reload-result {
    package cisco-asa-cli-6.12
    result true
}
reload-result {
    package cisco-ios-cli-6.67
    result true
}
reload-result {
    package cisco-iosxr-cli-7.32
    result true
}
reload-result {
    package cisco-nx-cli-5.20
    result true
}
reload-result {
    package resource-manager
    result true
}
reload-result {
    package selftest
    result true
}
reload-result {
    package svi_verify_example
    result true
}
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem stopped: ncs-dp-6-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem stopped: ncs-dp-7-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem stopped: ncs-dp-8-resource-manager:AddressallocationIPvalidation
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem stopped: ncs-dp-5-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem started: ncs-dp-9-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem started: ncs-dp-10-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem started: ncs-dp-11-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-20 00:00:16...
    Subsystem started: ncs-dp-12-resource-manager:AddressallocationIPvalidation
developer@ncs# 
```
  </div>
</details>

これでYANGモデルの編集は完了です。

#コンフィグテンプレートXMLの編集
`add-vpn-service/templates/`ディレクトリにテンプレートとなるXMLファイルが作成されますので、中身を確認してみます。

```xml:add-vpn-service-template.xml 
<config-template xmlns="http://tail-f.com/ns/config/1.0"
                 servicepoint="add-vpn-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>
```
> `<config>`と`</config>`の間に、実際にデバイスを設定する際にNSOが使用するXMLを挿入し、YANGのnode(変数)をマッピングしていきます。

 `<config>`と`</config>`間に挿入するXMLは、core-rtr01に実際にL3VPN(SR-MPLS)にサイトを追加するのに必要なコンフィグを投入してそれをXMLでアウトプットすることで得ることができます。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ ncs_cli -C -u developer

User developer last logged in 2021-10-19T23:58:14.013468-00:00, to nso, from 192.168.254.11 using cli-ssh
developer connected from 192.168.254.11 using ssh on nso
developer@ncs# config t
Entering configuration mode terminal
developer@ncs(config)# devices device core-rtr01 config
developer@ncs(config-config)# vrf C
developer@ncs(config-vrf)# address-family ipv4 unicast                     
developer@ncs(config-vrf-af)# export route-target 65432:333
developer@ncs(config-vrf-export-rt)# exit
developer@ncs(config-vrf-af)# import route-target 65432:333
developer@ncs(config-vrf-import-rt)# exit
developer@ncs(config-vrf-af)# exit
developer@ncs(config-vrf)# router bgp 65432
developer@ncs(config-bgp)# vrf C
developer@ncs(config-bgp-vrf)# rd 65432:333
developer@ncs(config-bgp-vrf)# address-family ipv4 uni
developer@ncs(config-bgp-af)# redistribute connected 
developer@ncs(config-bgp-af)# exit
developer@ncs(config-bgp-vrf)# exit
developer@ncs(config-bgp)# exit
developer@ncs(config-config)# interface Loopback 333
developer@ncs(config-if)# vrf C
developer@ncs(config-if)# ipv4 address 3.3.3.1 255.255.255.255
developer@ncs(config-if)# top         
developer@ncs(config)# show configuration 
devices device core-rtr01
 config
  vrf C
   address-family ipv4 unicast
    import route-target
     65432:333
    exit
    export route-target
     65432:333
    exit
   exit
  exit
  interface Loopback 333
   vrf C
   ipv4 address 3.3.3.1 255.255.255.255
   no shutdown
  exit
  router bgp 65432
   vrf C
    rd 65432:333
    address-family ipv4 unicast
     redistribute connected
    exit
   exit
  exit
 !
!
developer@ncs(config)# 
```
  </div>
</details>

`show configuration | display xml`でXMLでアウトプットすることができます。

<details>
  <summary>アウトプット</summary>
  <div>

```xml
developer@ncs(config)# show configuration | display xml
<devices xmlns="http://tail-f.com/ns/ncs">
  <device>
    <name>core-rtr01</name>
    <config>
      <vrf xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <vrf-list>
          <name>C</name>
          <address-family>
            <ipv4>
              <unicast>
                <import>
                  <route-target>
                    <address-list>
                      <name>65432:333</name>
                    </address-list>
                  </route-target>
                </import>
                <export>
                  <route-target>
                    <address-list>
                      <name>65432:333</name>
                    </address-list>
                  </route-target>
                </export>
              </unicast>
            </ipv4>
          </address-family>
        </vrf-list>
      </vrf>
      <interface xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <Loopback>
          <id>333</id>
          <vrf>C</vrf>
          <ipv4>
            <address>
              <ip>3.3.3.1</ip>
              <mask>255.255.255.255</mask>
            </address>
          </ipv4>
        </Loopback>
      </interface>
      <router xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <bgp>
          <bgp-no-instance>
            <id>65432</id>
            <vrf>
              <name>C</name>
              <rd>65432:333</rd>
              <address-family>
                <ipv4>
                  <unicast>
                    <redistribute>
                      <connected/>
                    </redistribute>
                  </unicast>
                </ipv4>
              </address-family>
            </vrf>
          </bgp-no-instance>
        </bgp>
      </router>
    </config>
  </device>
</devices>
developer@ncs(config)# 
```
  </div>
</details>

取得したXMLの`<config>`から`</config>`の部分を、__add-vpn-service-template.xml__の`<config>`と`</config>`間に挿入し、設定値の部分を{/変数}へ書き換えます。この変数には__add-vpn-service.yang__の設定値に対応するnode名を入力します。

```xml:add-vpn-service-template.xml 
<config-template xmlns="http://tail-f.com/ns/config/1.0"
                 servicepoint="add-vpn-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>
      <vrf xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <vrf-list>
          <name>{/vrf/vrf-name}</name>
          <address-family>
            <ipv4>
              <unicast>
                <import>
                  <route-target>
                    <address-list>
                      <name>{/vrf/route-target-import}</name>
                    </address-list>
                  </route-target>
                </import>
                <export>
                  <route-target>
                    <address-list>
                      <name>{/vrf/route-target-export}</name>
                    </address-list>
                  </route-target>
                </export>
              </unicast>
            </ipv4>
          </address-family>
        </vrf-list>
      </vrf>
      <interface xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <Loopback>
          <id>{/loopback/loopback-number}</id>
          <vrf>{/vrf/vrf-name}</vrf>
          <ipv4>
            <address>
              <ip>{/loopback/loopback-ip}</ip>
              <mask>255.255.255.255</mask>
            </address>
          </ipv4>
        </Loopback>
      </interface>
      <router xmlns="http://tail-f.com/ned/cisco-ios-xr">
        <bgp>
          <bgp-no-instance>
            <id>65432</id>
            <vrf>
              <name>{/vrf/vrf-name}</name>
              <rd>{/vrf/rd}</rd>
              <address-family>
                <ipv4>
                  <unicast>
                    <redistribute>
                      <connected/>
                    </redistribute>
                  </unicast>
                </ipv4>
              </address-family>
            </vrf>
          </bgp-no-instance>
        </bgp>
      </router>
      </config>
    </device>
  </devices>
</config-template>
```
> add-vpn-service.yangに追加した`servicepoint`は`list vpn-policy`直下に配置したので、その配下で`container`でまとめた`leaf`を指定する場合には、`/container/leaf`の順でパスを指定します。
__これでコンフィグテンプレートXMLが完成しました。__

#reload packages

`reload packages`をする前に、NSOとデバイスのコンフィグをシンクさせます。これは、事前準備でcore-rtr01と、core-rtr02へコンフィグを追加したのでNSOが保持するコンフィグと、実際のデバイスのコンフィグが異なっているからです。


<details>
  <summary>アウトプット</summary>
  <div>

```shell:
developer@ncs# config t
Entering configuration mode terminal
developer@ncs(config)# devices check-sync 
sync-result {
    device core-rtr01
    result out-of-sync
    info got: 1000000002+2000000001 expected: 1000000001+2000000001

}
sync-result {
    device core-rtr02
    result out-of-sync
    info got: 1000000002+2000000001 expected: 1000000001+2000000001

}
sync-result {
    device dist-rtr01
    result in-sync
}
sync-result {
    device dist-rtr02
    result in-sync
}
sync-result {
    device dist-sw01
    result in-sync
}
sync-result {
    device dist-sw02
    result in-sync
}
sync-result {
    device edge-firewall01
    result in-sync
}
sync-result {
    device edge-sw01
    result in-sync
}
sync-result {
    device internet-rtr01
    result in-sync
}
developer@ncs(config)# *** ALARM out-of-sync: got: 1000000002+2000000001 expected: 1000000001+2000000001
developer@ncs(config)# devices device-group XR-DEVICES sync-from 
sync-result {
    device core-rtr01
    result true
}
sync-result {
    device core-rtr02
    result true
}
```
  </div>
</details>
> 全てのデバイスのコンフィグがNSOと`in-sync`になりました。

`reload packages`します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell:

developer@ncs# packages reload 
reload-result {
    package add-vpn-service
    result true
}
reload-result {
    package cisco-asa-cli-6.12
    result true
}
reload-result {
    package cisco-ios-cli-6.67
    result true
}
reload-result {
    package cisco-iosxr-cli-7.32
    result true
}
reload-result {
    package cisco-nx-cli-5.20
    result true
}
reload-result {
    package resource-manager
    result true
}
reload-result {
    package selftest
    result true
}
reload-result {
    package svi_verify_example
    result true
}
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem stopped: ncs-dp-26-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem stopped: ncs-dp-27-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem stopped: ncs-dp-28-resource-manager:AddressallocationIPvalidation
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem stopped: ncs-dp-25-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem started: ncs-dp-29-cisco-asa-cli-6.12:ASADp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem started: ncs-dp-30-cisco-ios-cli-6.67:IOSDp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem started: ncs-dp-31-cisco-nx-cli-5.20:NexusDp
developer@ncs# 
System message at 2021-10-20 05:08:25...
    Subsystem started: ncs-dp-32-resource-manager:AddressallocationIPvalidation
developer@ncs# 
```
  </div>
</details>
> 準備完了です。

#設定反映

NSOを通してncs_cliでデバイスにサイト追加のコンフィグを反映させます。`commit`する前にNSOのCDBに保存するコンフィグを`show configuration`で参照します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs# config t
Entering configuration mode terminal
developer@ncs(config)# vpn vpn-policy CORE-RTR01_VRF_C  
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# device core-rtr01                
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# maintainer-members HIDETADA      
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# maintainer-members IEYASU        
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# vrf vrf-name C                   
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# vrf rd 65432:333                 
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# vrf route-target-export 65432:333
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# vrf route-target-import 65432:333
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# loopback loopback-number 333     
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# loopback loopback-ip 3.3.3.1     
developer@ncs(config-vpn-policy-CORE-RTR01_VRF_C)# top                              
developer@ncs(config)# show configuration 
vpn vpn-policy CORE-RTR01_VRF_C
 device             core-rtr01
 maintainer-members [ HIDETADA IEYASU ]
 vrf vrf-name        C
 vrf rd              65432:333
 vrf route-target-export 65432:333
 vrf route-target-import [ 65432:333 ]
 loopback loopback-number 333
 loopback loopback-ip 3.3.3.1
!
```
  </div>
</details>
> 設定を投入完了。

`commit dry-run outformat native`で`commit`することなく、デバイスへ設定する内容を参照することができます。問題なければ`commit`します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs(config)# commit dry-run outformat native 
native {
    device {
        name core-rtr01
        data vrf C
              address-family ipv4 unicast
               import route-target
                65432:333
               exit
               export route-target
                65432:333
               exit
              exit
             exit
             interface Loopback 333
              vrf C
              ipv4 address 3.3.3.1 255.255.255.255
              no shutdown
             exit
             router bgp 65432
              vrf C
               rd 65432:333
               address-family ipv4 unicast
                redistribute connected
               exit
              exit
             exit
    }
}
developer@ncs(config)# 
developer@ncs(config)# commit 
Commit complete.
developer@ncs(config)# 
```
  </div>
</details>
> これで、NSOのCDBへ設定が反映されるとともに、core-rtr01へも設定が反映されました。

NSOのCDBにコンフィグが反映されているか`show running-config vpn`で確認します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs(config)# exit
developer@ncs# show running-config vpn
vpn vpn-policy CORE-RTR01_VRF_C
 device             core-rtr01
 maintainer-members [ HIDETADA IEYASU ]
 vrf vrf-name        C
 vrf rd              65432:333
 vrf route-target-export 65432:333
 vrf route-target-import [ 65432:333 ]
 loopback loopback-number 333
 loopback loopback-ip 3.3.3.1
!
developer@ncs# 
```
  </div>
</details>
> NSOのCDBに設定が反映されているのが確認できます。

core-rtr01にコンフィグが反映されいるか`show running-config devices device core-rtr01 config`で確認します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs# show running-config devices device core-rtr01 config vrf C
devices device core-rtr01
 config
  vrf C
   address-family ipv4 unicast
    import route-target
     65432:333
    exit
    export route-target
     65432:333
    exit
   exit
  exit
 !
!
developer@ncs# show running-config devices device core-rtr01 config router bgp 65432 vrf C
devices device core-rtr01
 config
  router bgp 65432
   vrf C
    rd 65432:333
    address-family ipv4 unicast
     redistribute connected
    exit
   exit
  exit
 !
!
developer@ncs# show running-config devices device core-rtr01 config interface Loopback 
devices device core-rtr01
 config
  interface Loopback 0
   description to
   ipv4 address 172.16.252.101 255.255.255.255
   no shutdown
  exit
  interface Loopback 111
   vrf A
   ipv4 address 1.1.1.1 255.255.255.255
   no shutdown
  exit
  interface Loopback 222
   vrf B
   ipv4 address 2.2.2.1 255.255.255.255
   no shutdown
  exit
  interface Loopback 333
   vrf C
   ipv4 address 3.3.3.1 255.255.255.255
   no shutdown
  exit
 !
!
```

  </div>
</details>
> core-rtr01にも設定が反映されているのが確認できます。

同じようにcore-rtr02へも同じ手順でサイト追加し、確認します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs# config t
Entering configuration mode terminal
developer@ncs(config)# vpn vpn-policy CORE-RTR02_VRF_C
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# device core-rtr02 
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# maintainer-members HIDETADA
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# maintainer-members IETSUNA
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# maintainer-members TSUNATOSHI
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# vrf vrf-name C
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# vrf rd 65432:333
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# vrf route-target-export 65432:333
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# vrf route-target-import 65432:333
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# loopback loopback-number 333
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# loopback loopback-ip 3.3.3.2
developer@ncs(config-vpn-policy-CORE-RTR02_VRF_C)# top
developer@ncs(config)# show configuration 
vpn vpn-policy CORE-RTR02_VRF_C
 device             core-rtr02
 maintainer-members [ IETSUNA TSUNATOSHI HIDETADA ]
 vrf vrf-name        C
 vrf rd              65432:333
 vrf route-target-export 65432:333
 vrf route-target-import [ 65432:333 ]
 loopback loopback-number 333
 loopback loopback-ip 3.3.3.2
!
developer@ncs(config)# commit dry-run outformat native 
native {
    device {
        name core-rtr02
        data vrf C
              address-family ipv4 unicast
               import route-target
                65432:333
               exit
               export route-target
                65432:333
               exit
              exit
             exit
             interface Loopback 333
              vrf C
              ipv4 address 3.3.3.2 255.255.255.255
              no shutdown
             exit
             router bgp 65432
              vrf C
               rd 65432:333
               address-family ipv4 unicast
                redistribute connected
               exit
              exit
             exit
    }
}
developer@ncs(config)# commit
Commit complete.
developer@ncs(config)# exit 
developer@ncs# show running-config vpn
vpn vpn-policy CORE-RTR01_VRF_C
 device             core-rtr01
 maintainer-members [ HIDETADA IEYASU ]
 vrf vrf-name        C
 vrf rd              65432:333
 vrf route-target-export 65432:333
 vrf route-target-import [ 65432:333 ]
 loopback loopback-number 333
 loopback loopback-ip 3.3.3.1
!
vpn vpn-policy CORE-RTR02_VRF_C
 device             core-rtr02
 maintainer-members [ IETSUNA TSUNATOSHI HIDETADA ]
 vrf vrf-name        C
 vrf rd              65432:333
 vrf route-target-export 65432:333
 vrf route-target-import [ 65432:333 ]
 loopback loopback-number 333
 loopback loopback-ip 3.3.3.2
!
developer@ncs# show running-config devices device core-rtr02 config vrf C
devices device core-rtr02
 config
  vrf C
   address-family ipv4 unicast
    import route-target
     65432:333
    exit
    export route-target
     65432:333
    exit
   exit
  exit
 !
!
developer@ncs# show running-config devices device core-rtr02 config router bgp 65432 vrf C
devices device core-rtr02
 config
  router bgp 65432
   vrf C
    rd 65432:333
    address-family ipv4 unicast
     redistribute connected
    exit
   exit
  exit
 !
!
developer@ncs# show running-config devices device core-rtr02 config interface Loopback 
devices device core-rtr02
 config
  interface Loopback 0
   description to
   ipv4 address 172.16.252.102 255.255.255.255
   no shutdown
  exit
  interface Loopback 111
   vrf A
   ipv4 address 1.1.1.2 255.255.255.255
   no shutdown
  exit
  interface Loopback 222
   vrf B
   ipv4 address 2.2.2.2 255.255.255.255
   no shutdown
  exit
  interface Loopback 333
   vrf C
   ipv4 address 3.3.3.2 255.255.255.255
   no shutdown
  exit
 !
!
developer@ncs# 

```
  </div>
</details>
> core-rtr02への設定も完了しました。

#確認
core-rtr01のVRF Cで、SR-MPLSでのL3VPNが確立されたか確認します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso templates]$ telnet 10.10.20.173
Trying 10.10.20.173...
Connected to 10.10.20.173.
Escape character is '^]'.



IMPORTANT:  READ CAREFULLY
Welcome to the Demo Version of Cisco IOS XRv (the "Software").
The Software is subject to and governed by the terms and conditions
of the End User License Agreement and the Supplemental End User
License Agreement accompanying the product, made available at the
time of your order, or posted on the Cisco website at
www.cisco.com/go/terms (collectively, the "Agreement").
As set forth more fully in the Agreement, use of the Software is
strictly limited to internal use in a non-production environment
solely for demonstration and evaluation purposes.  Downloading,
installing, or using the Software constitutes acceptance of the
Agreement, and you are binding yourself and the business entity
that you represent to the Agreement.  If you do not agree to all
of the terms of the Agreement, then Cisco is unwilling to license
the Software to you and (a) you may not download, install or use the
Software, and (b) you may return the Software as more fully set forth
in the Agreement.


Please login with any configured user/password, or cisco/cisco


User Access Verification

Username: cisco
Password: 


RP/0/0/CPU0:core-rtr01#
RP/0/0/CPU0:core-rtr01#sh bgp vpnv4 unicast 
Wed Oct 20 13:38:45.662 UTC
BGP router identifier 172.16.252.101, local AS number 65432
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0x0   RD version: 0
BGP main routing table version 22
BGP NSR Initial initsync version 9 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs

Status codes: s suppressed, d damped, h history, * valid, > best
              i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
   Network            Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65432:111 (default for vrf A)
*> 1.1.1.1/32         0.0.0.0                  0         32768 ?
*>i1.1.1.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:222 (default for vrf B)
*> 2.2.2.1/32         0.0.0.0                  0         32768 ?
*>i2.2.2.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:333 (default for vrf C)
*> 3.3.3.1/32         0.0.0.0                  0         32768 ?
*>i3.3.3.2/32         172.16.252.102           0    100      0 ?

Processed 6 prefixes, 6 paths
RP/0/0/CPU0:core-rtr01#
```
  </div>
</details>
> core-rtr02から、VRF Cでは3.3.3.2/32を受信しています。

VRF Cに指定したpingを試します。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
RP/0/0/CPU0:core-rtr01#ping vrf C 3.3.3.2 source 3.3.3.1
Wed Oct 20 13:40:28.645 UTC
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/7/9 ms
RP/0/0/CPU0:core-rtr01#
```
  </div>
</details>
> core-rtr01から、VRF Cでpingも通りました。

#Re-deploying
NSOで作成したサービスパッケージでサイト追加をした後に、デバイスのサイトが直接削除されてしまった場合などは、サービスのRe-deployingが可能です。

core-rtr01のvrf、loopbackの設定を削除してみます。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ telnet 10.10.20.173
Trying 10.10.20.173...
Connected to 10.10.20.173.
Escape character is '^]'.



IMPORTANT:  READ CAREFULLY
Welcome to the Demo Version of Cisco IOS XRv (the "Software").
The Software is subject to and governed by the terms and conditions
of the End User License Agreement and the Supplemental End User
License Agreement accompanying the product, made available at the
time of your order, or posted on the Cisco website at
www.cisco.com/go/terms (collectively, the "Agreement").
As set forth more fully in the Agreement, use of the Software is
strictly limited to internal use in a non-production environment
solely for demonstration and evaluation purposes.  Downloading,
installing, or using the Software constitutes acceptance of the
Agreement, and you are binding yourself and the business entity
that you represent to the Agreement.  If you do not agree to all
of the terms of the Agreement, then Cisco is unwilling to license
the Software to you and (a) you may not download, install or use the
Software, and (b) you may return the Software as more fully set forth
in the Agreement.


Please login with any configured user/password, or cisco/cisco


User Access Verification

Username: cisco
Password: 



RP/0/0/CPU0:core-rtr01#conf t
Thu Oct 21 00:08:28.159 UTC
RP/0/0/CPU0:core-rtr01(config)#router bgp 65432
RP/0/0/CPU0:core-rtr01(config-bgp)#no vrf C
RP/0/0/CPU0:core-rtr01(config-bgp)#exit
RP/0/0/CPU0:core-rtr01(config)#no interface loopback 333
RP/0/0/CPU0:core-rtr01(config)#no vrf C
RP/0/0/CPU0:core-rtr01(config)#commit 
Thu Oct 21 00:09:28.494 UTC
RP/0/0/CPU0:core-rtr01(config)#end
RP/0/0/CPU0:core-rtr01#sh running-config vrf
Thu Oct 21 00:09:37.924 UTC
vrf A
 address-family ipv4 unicast
  import route-target
   65432:111
  !
  export route-target
   65432:111
  !
 !
!
vrf B
 address-family ipv4 unicast
  import route-target
   65432:222
  !
  export route-target
   65432:222
  !
 !
!
vrf Mgmt-intf
 address-family ipv4 unicast
 !
 address-family ipv6 unicast
 !
!

RP/0/0/CPU0:core-rtr01#sh running-config interface loopback 333
Thu Oct 21 00:09:57.213 UTC
% No such configuration item(s)

RP/0/0/CPU0:core-rtr01#sh running-config router bgp 65432 vrf C
Thu Oct 21 00:10:17.621 UTC
% No such configuration item(s)

RP/0/0/CPU0:core-rtr01#

```
  </div>
</details>
> vrf、loopbackの設定を削除が完了しました。

NSOで`check-sync`してみます。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ ncs_cli -C -u developer

User developer last logged in 2021-10-20T16:33:49.711905-07:00, to nso, from 192.168.254.11 using cli-ssh
developer connected from 192.168.254.11 using ssh on nso
developer@ncs# devices device-group XR-DEVICES check-sync 
sync-result {
    device core-rtr01
    result out-of-sync
    info got: 1000000004+2000000001 expected: 1000000003+2000000001

}
sync-result {
    device core-rtr02
    result in-sync
}
developer@ncs# *** ALARM out-of-sync: got: 1000000004+2000000001 expected: 1000000003+2000000001

developer@ncs# 
```
  </div>
</details>
> core-rtr01が`out-of-sync`になっています。

`devices device core-rtr01 sync-from`コマンドで、NSOとcore-rtr01を`in-sync`にします。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs# devices device core-rtr01 sync-from       
result true
developer@ncs# devices device core-rtr01 check-sync      
result in-sync
developer@ncs# 
```
  </div>
</details>
> core-rtr01が`in-sync`になりました。これでcore-rtr01でもNSOでもサイト追加は削除されました。

`vpn vpn-policy CORE-RTR01_VRF_C`はCDBに登録しているので、もう一度サービスを適用するには`vpn vpn-policy CORE-RTR01_VRF_C re-deploy`コマンドを投入します。適用する前に`dry-run`オプションで確認することができます。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs(config)# vpn vpn-policy CORE-RTR01_VRF_C re-deploy dry-run 
cli {
    local-node {
        data  devices {
                   device core-rtr01 {
                       config {
                           vrf {
              +                vrf-list C {
              +                    address-family {
              +                        ipv4 {
              +                            unicast {
              +                                import {
              +                                    route-target {
              +                                        address-list 65432:333;
              +                                    }
              +                                }
              +                                export {
              +                                    route-target {
              +                                        address-list 65432:333;
              +                                    }
              +                                }
              +                            }
              +                        }
              +                    }
              +                }
                           }
                           interface {
              +                Loopback 333 {
              +                    vrf C;
              +                    ipv4 {
              +                        address {
              +                            ip 3.3.3.1;
              +                            mask 255.255.255.255;
              +                        }
              +                    }
              +                }
                           }
                           router {
                               bgp {
                                   bgp-no-instance 65432 {
              +                        vrf C {
              +                            rd 65432:333;
              +                            address-family {
              +                                ipv4 {
              +                                    unicast {
              +                                        redistribute {
              +                                            connected {
              +                                            }
              +                                        }
              +                                    }
              +                                }
              +                            }
              +                        }
                                   }
                               }
                           }
                       }
                   }
               }
              
    }
}
developer@ncs(config)# vpn vpn-policy CORE-RTR01_VRF_C re-deploy         
developer@ncs(config)# 
System message at 2021-10-20 17:23:08...
Commit performed by developer via ssh using cli.
developer@ncs(config)# 
```
  </div>
</details>
> Re-deploying完了です。

core-rtr01で確認してみましょう。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ telnet 10.10.20.173
Trying 10.10.20.173...
Connected to 10.10.20.173.
Escape character is '^]'.



IMPORTANT:  READ CAREFULLY
Welcome to the Demo Version of Cisco IOS XRv (the "Software").
The Software is subject to and governed by the terms and conditions
of the End User License Agreement and the Supplemental End User
License Agreement accompanying the product, made available at the
time of your order, or posted on the Cisco website at
www.cisco.com/go/terms (collectively, the "Agreement").
As set forth more fully in the Agreement, use of the Software is
strictly limited to internal use in a non-production environment
solely for demonstration and evaluation purposes.  Downloading,
installing, or using the Software constitutes acceptance of the
Agreement, and you are binding yourself and the business entity
that you represent to the Agreement.  If you do not agree to all
of the terms of the Agreement, then Cisco is unwilling to license
the Software to you and (a) you may not download, install or use the
Software, and (b) you may return the Software as more fully set forth
in the Agreement.


Please login with any configured user/password, or cisco/cisco


User Access Verification

Username: cisco
Password: 


RP/0/0/CPU0:core-rtr01#sh bgp vpnv4 unicast 
Thu Oct 21 00:26:19.755 UTC
BGP router identifier 172.16.252.101, local AS number 65432
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0x0   RD version: 0
BGP main routing table version 29
BGP NSR Initial initsync version 9 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs

Status codes: s suppressed, d damped, h history, * valid, > best
              i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
   Network            Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65432:111 (default for vrf A)
*> 1.1.1.1/32         0.0.0.0                  0         32768 ?
*>i1.1.1.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:222 (default for vrf B)
*> 2.2.2.1/32         0.0.0.0                  0         32768 ?
*>i2.2.2.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:333 (default for vrf C)
*> 3.3.3.1/32         0.0.0.0                  0         32768 ?
*>i3.3.3.2/32         172.16.252.102           0    100      0 ?

Processed 6 prefixes, 6 paths
RP/0/0/CPU0:core-rtr01#ping vrf C 3.3.3.2 source 3.3.3.1
Thu Oct 21 00:26:35.724 UTC
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.2, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/11/19 ms
RP/0/0/CPU0:core-rtr01#
```
  </div>
</details>
> VRF Cが`re-deploy`によって復活しました。

#Rollback
NSOはcommitをトレースしているので、ロールバックができこれが非常に強力です。
NSOは、commitごとにロールバックファイルを保存します。変更のID番号を参照することで、特定の変更をロールバックすることができます。1回のコミットで10個のデバイスと各デバイスの30個の構成行が更新される場合でも、ロールバックによってそのすべての構成が取り消されます。

`show configuration rollback changes`でcore-rtr01、core-rtr02へサイト追加した際のroll backを見てみましょう。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
[developer@nso packages]$ ncs_cli -C -u developer

User developer last logged in 2021-10-20T17:33:35.144065-00:00, to nso, from 192.168.254.11 using cli-ssh
developer connected from 192.168.254.11 using ssh on nso
developer@ncs# show configuration rollback changes ?
Possible completions:
  10001   2021-01-15 13:44:03 by system via system
  10002   2021-10-20 16:06:48 by system via system
  10003   2021-10-20 16:06:58 by developer via rest
  10004   2021-10-20 16:06:59 by developer via rest
  10005   2021-10-20 16:06:59 by developer via rest
  10006   2021-10-20 16:06:59 by developer via rest
  10007   2021-10-20 16:07:00 by developer via rest
  10008   2021-10-20 16:07:00 by developer via rest
  10009   2021-10-20 16:07:00 by developer via rest
  10010   2021-10-20 16:07:01 by developer via rest
  10011   2021-10-20 16:07:01 by developer via rest
  10012   2021-10-20 16:36:55 by developer via cli
  10013   2021-10-20 16:36:57 by developer via cli
  10014   2021-10-20 16:37:05 by developer via cli
  10015   2021-10-20 16:39:16 by developer via cli
  10016   2021-10-20 17:17:09 by developer via cli
  |       Output modifiers
  <cr>    latest
developer@ncs# show configuration rollback changes 10016
% No configuration changes found.
developer@ncs# show configuration rollback changes 10015
no vpn vpn-policy CORE-RTR02_VRF_C
developer@ncs# show configuration rollback changes 10014
no vpn vpn-policy CORE-RTR01_VRF_C
no vpn vpn-policy CORE-RTR02_VRF_C
developer@ncs#
```
  </div>
</details>
> 10014でroll backすれば、core-rtr01、core-rtr02へのサイト追加が削除されることがわかります。

`rollback configuration`でroll backしてみましょう。

<details>
  <summary>アウトプット</summary>
  <div>

```shell
developer@ncs# config t
Entering configuration mode terminal
developer@ncs(config)# rollback configuration 10014
developer@ncs(config)# show configuration 
no vpn vpn-policy CORE-RTR01_VRF_C
no vpn vpn-policy CORE-RTR02_VRF_C
developer@ncs(config)# commit dry-run outformat native 
native {
    device {
        name core-rtr01
        data interface Loopback 333
              no vrf C
             exit
             no vrf C
             no interface Loopback 333
             router bgp 65432
              no vrf C
             exit
    }
    device {
        name core-rtr02
        data interface Loopback 333
              no vrf C
             exit
             no vrf C
             no interface Loopback 333
             router bgp 65432
              no vrf C
             exit
    }
}
developer@ncs(config)# commit 
Commit complete.
developer@ncs(config)# 

```
  </div>
</details>
> `commit dry-run outformat native`でcore-rtr01、core-rtr02へも設定が反映されることがわかります。

core-rtr01で確認してみましょう。
<details>
  <summary>アウトプット</summary>
  <div>

```shell
RP/0/0/CPU0:core-rtr01#sh bgp vpnv4 unicast 
Thu Oct 21 02:28:41.822 UTC
BGP router identifier 172.16.252.101, local AS number 65432
BGP generic scan interval 60 secs
Non-stop routing is enabled
BGP table state: Active
Table ID: 0x0   RD version: 0
BGP main routing table version 31
BGP NSR Initial initsync version 9 (Reached)
BGP NSR/ISSU Sync-Group versions 0/0
BGP scan interval 60 secs

Status codes: s suppressed, d damped, h history, * valid, > best
              i - internal, r RIB-failure, S stale, N Nexthop-discard
Origin codes: i - IGP, e - EGP, ? - incomplete
   Network            Next Hop            Metric LocPrf Weight Path
Route Distinguisher: 65432:111 (default for vrf A)
*> 1.1.1.1/32         0.0.0.0                  0         32768 ?
*>i1.1.1.2/32         172.16.252.102           0    100      0 ?
Route Distinguisher: 65432:222 (default for vrf B)
*> 2.2.2.1/32         0.0.0.0                  0         32768 ?
*>i2.2.2.2/32         172.16.252.102           0    100      0 ?

Processed 4 prefixes, 4 paths
RP/0/0/CPU0:core-rtr01#sh running-config vrf C
Thu Oct 21 02:29:16.730 UTC
% No such configuration item(s)

RP/0/0/CPU0:core-rtr01#sh running-config interface loopback 333
Thu Oct 21 02:29:23.199 UTC
% No such configuration item(s)

RP/0/0/CPU0:core-rtr01#sh running-config router bgp 65432 vrf C
Thu Oct 21 02:29:41.138 UTC
% No such configuration item(s)

RP/0/0/CPU0:core-rtr01#

```
  </div>
</details>
> サイトを追加する前の状態へ戻りました。

#まとめ
コンフィグテンプレートXMLを作成し、サービスからデバイスの設定変更ができました。今回はデバイスごとにpolicyを作成するようなデザインにしましたが、複数のデバイスに同時に設定を反映させるようなサービスインスタンスを作成することも可能です。このようにNSOのサービスを使用すれば、デバイスへの設定を抽象化したサービスインスタンスを管理デバイスへ提供するので、シンプルでフレキシブルなマネージメントを可能にします。マルチベンダーネットワークにとっては非常に有効なオーケストレータです。

#参考リンク

[-DevNet Learning Module 「NSO Basics for Network Automation」](https://developer.cisco.com/learning/modules/nso-basics)

[-YANGモデルの理解のためのNSOカスタムサービスパッケージの追加デモ(2/2)](https://qiita.com/masanobu48154/items/85cf7ed6e51c2d9ae5b8)

[-YANGモデルの理解のためのNSOカスタムサービスパッケージの追加デモ(1/2)](https://qiita.com/masanobu48154/items/8bdf6bbcecf4be93540f)