YANGモデルの理解のためのNSOカスタムサービスパッケージの追加デモ(1/2)

#初めに
YANGはネットワークデバイスのコンフィグをモデル化するのに適した言語とされてますが、CLIに慣れているので私には取っつきにくいものでした。NSOのサービスパッケージを作成する過程でYANGモデルを自作すれば理解しやすかったので、備忘録的に記事に残そうと思いました。

2部構成で2部(Sanbboxを使ったデモ)は[こちら](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とは
Yet Another Next Generation（YANG）とは、プログラムによるAPIアクセスを標準化するために設計された、ネットワークデバイスのコンフィグのフォーマットとルールを定義したデータモデリング言語。コンフィグのモデルを作成するために使用されます。CLIとは違い構造化された形式ですが、人が読みやすいようにも工夫されています。

[RFC 6020](https://datatracker.ietf.org/doc/rfc6020/)
[RFC 7950](https://datatracker.ietf.org/doc/rfc7950/)
[RFC 8342](https://datatracker.ietf.org/doc/rfc8342/) 

#YANGが活用される例
YANGは、もともとNETCONFで使用するために設計されました。しかし、RESTが普及するにつれて、RESTCONFも標準化されました。現在はgNMIなど、YANG言語に依存する他のプロトコルもあります。これらのプロトコルは、YANGを使用してデータを定義し、モデル駆動型のインターフェイスが提供されます。

#データモデルとは
「何か」を機能させるために必要な情報を定義するためのモデルです。
例えば、「連絡先」を機能させるモデルを考えると、少しわかりやすいかもしれません。

<dl>
  <dt>
    連絡先
    <dd>
      姓<br>
      名<br>
      生年月日<br>
      メールアドレス<br>
      電話番号<br>
      役職
    </dd>
  <d/t>
</dl>


#YANGの構造

###YANG module
YANGでは、__module__内でnodeを定義したり、nodeのグルーピングを定義したり、カスタムデータタイプを定義したり、他の__module__をインポートしたりなど、全てのデータモデルを定義します。多くの場合、単一のモジュールでBGPやインターフェースのIP設定などのそれぞれの機能を記述するので、ネットワークデバイスはサポートするさまざまな機能ごとにモジュールを実装します。

```yang:
module 連絡先モジュール {
}
```

> YANGでは、例えばこのように連絡先モジュールとして機能を定義します。今回はわかりやすい例として日本語の表現を使ってます。

###YANG nodes
実際のデータを保持するためにさまざまな__node__を使用します。__node__はkeyとvalueを持つPythonの「辞書型」に似ています。「辞書型」は一つのkeyであっても、str型、int型、list型など様々なデータ型を持つことができます。__node__も`container node`や`list node`などは、単一のノード内にさまざまなデータ型を含めることができます。

####container node
複数の子ノードをまとめるには、__container__を使用します。 __container__には、任意のnode(container、list、leaf、leaf-list)をいくつでも含めることができます。__container__自体は値を保持しません。

```yang:
module 連絡先モジュール {
  container 連絡先 {
  }
}
```

> 連絡先のデータを__container__にグルーピングします。


####leaf node
__leaf__は、整数や文字列などの単純なデータを保持します。 特定のtype(`string`、`uint16`、`boolean`など)の値が1つだけあり子ノードはありません。

```yang:
module 連絡先モジュール {
  container 連絡先 {
    leaf 姓 {
    }
    leaf 名 {
    }
    leaf 生年月日 {
    }
    leaf メールアドレス{
    }
  }
}
```

> 単一の値を持つものが__leaf__です。

####leaf-list node</dt>
leafは特定のtypeのデータを保持しますが、__leaf-list__は同じtypeの値を複数持つリストを保持します。

```yang:
module 連絡先モジュール {
  container 連絡先 {
    leaf 姓 {
    }
    leaf 名 {
    }
    leaf 生年月日 {
    }
    leaf メールアドレス {
    }
    leaf-list 電話番号 {
    }
  }
}
```

> 自宅、会社、携帯電話など、複数の値を持つものは__lear-list__で定義できます。

####list node
__list__はPythonの「辞書型」に似ています。一意の値を持つleafやleaf-listなどのnodeを複数含めることができます。__list__は異なる値を持つインスタンスが複数作成されるので、インスタンスを見分けるためにインスタンス間でユニークな値を持つ__key leaf nodes__を指定します。

```yang:
module 連絡先モジュール {
  container 連絡先 {
    list 連絡先エントリー {
      key "メールアドレス";
      leaf 姓 {
      }
      leaf 名 {
      }
      leaf 生年月日 {
      }
      leaf メールアドレス {
      }
      leaf-list 電話番号 {
      }
    }
  }
}
```

> 連絡先はたくさんのエントリーが存在するので、全ての連絡先間でユニークな値のメールアドレスleafをキーにして各連絡先をCDBに格納できます。

#YANGのデータタイプ
YANGには、Pythonなどプログラミング言語と同じように組み込み型のデータタイプがあります。leafや、leaf-listなどは含める値のデータタイプを`type`で指定します。

###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|

```yang:
module 連絡先モジュール {
  container 連絡先 {
    list 連絡先エントリー {
      key "メールアドレス";
      leaf 姓 {
        type string;
      }
      leaf 名 {
        type string;
      }
      leaf 生年月日 {
        type string {
          pattern "[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]";
        }
      }
      leaf メールアドレス {
        type string;
      }
      leaf-list 電話番号 {
        type string {
          pattern "[0-9]{2,4}-[0-9]{2,4}-[0-9]{2,4}";
        }
      }
    }
  }
}
```

> データタイプを指定し後、`pattern`、`range`、`length`などのステートメントを使用して、特定のtypeの値をさらに制限できます。 patternは正規表現（regex）で定義され、rangeとlengthは両方とも整数で定義されます。


###Enumeration
Enumerationを使用すれば、選択可能なオプションをあらかじめ定義してオプションの数を制限することができます。
Enumerationを適用するときは、`enum`を指定する必要があります。

```yang:
module 連絡先モジュール {
  container 連絡先 {
    list 連絡先エントリー {
      key "メールアドレス";
      leaf 姓 {
        type string;
      }
      leaf 名 {
        type string;
      }
      leaf 生年月日 {
        type string {
          pattern "[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]";
        }
      }
      leaf メールアドレス {
        type string;
      }
      leaf-list 電話番号 {
        type string {
          pattern "[0-9]{2,4}-[0-9]{2,4}-[0-9]{2,4}";
        }
      }
      leaf 役職 {
        type  enumeration {
          enum "社長";
          enum "部長";
          enum "課長";
        }
      }
    }
  }
}
```

> オプションを社長、部長、課長に限定することができます。
typeに`union`などを使用すれば、オプションを`enumeration`で選択可能にしつつ他のtypeのオプションを指定可能にすることもできます。

#まとめ
YANGの構造や、データタイプについてイメージできるように簡単にまとめてみました。
2部では__DevNet Sandbox__を使って実際にサービスパッケージを作るデモを実施していきたいと思います。

#参考リンク

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