新人が DevStack 上で LCM Operation User Data を使用して VNF を VM としてデプロイする話

# 目次

[1. はじめに](#はじめに)
[2. 環境](#環境)
[3. インストール手順](#インストール手順)
[4. 発生したエラー](#発生したエラー)
[5. まとめ](#まとめ)

# 参考 URL

- [ETSI NFV-SOL VNF Deployment as VM with LCM Operation User Data](https://docs.openstack.org/tacker/latest/user/etsi_vnf_deployment_as_vm_with_user_data.html)
- [LCM operation with user data](https://specs.openstack.org/openstack/tacker-specs/specs/ussuri/lcm-operation-with-lcm-operation-user-data.html)
- [VNF Package](https://docs.openstack.org/tacker/latest/user/vnf-package.html)
- [第2章 Heat テンプレートの理解](https://access.redhat.com/documentation/ja-jp/red_hat_openstack_platform/11/html/advanced_overcloud_customization/sect-understanding_heat_templates)

# はじめに

こんにちは。新入社員として約 3 か月目の新人です。

この記事では NFV という言葉すら知らなかった新人が [Install via Devstack]( https://docs.openstack.org/tacker/latest/install/devstack.html) を参考にして DevStack 環境をインストールし、VIM として OpenStack と Kubernetes を登録するまでの手順と発生したエラーを複数の章に分けて記載していきます。

- 第 1 章: [新人が DevStack 上で Tacker を動かそうとする話](https://qiita.com/yoshi_1010/items/c1db52099b5897e049d0)

[Install via Devstack]( https://docs.openstack.org/tacker/latest/install/devstack.html) を実際に試します。

- 第 2 章: [新人が DevStack 上で TOSCA を使用して VNF を VM としてデプロイする話](https://qiita.com/yoshi_1010/items/1dbe4fe3c11f2b743853)

[ETSI NFV-SOL VNF Deployment as VM with TOSCA](https://docs.openstack.org/tacker/latest/user/etsi_vnf_deployment_as_vm_with_tosca.html) を実際に試します。

- 第 3 章: この記事です。

[ETSI NFV-SOL VNF Deployment as VM with LCM Operation User Data](https://docs.openstack.org/tacker/latest/user/etsi_vnf_deployment_as_vm_with_user_data.html) を実際に試します。

- 第 4 章: 続く。。。

今回のインストールで自分が調べた用語は以下にまとめました。

## LCM Operation User Data

Base HOT に使用される Heat の入力パラメータとしてキー/値データを返却するスクリプトです。
Heat 入力パラメーターとして、VNFD で静的に定義されていない OpenStack パラメーターを割り当てることができます。

## Base HOT

ネイティブクラウドオーケストレーションテンプレートです。
LCM Operation User Data で取得したキー/値データとともに Heat がスタックを作成することに利用されます。

HOT は Heat Orchestration Template のことです。
Heat が作成するリソースのコレクションとスタックを定義します。

- リソース: コンピュートリソース、ネットワーク設定などの OpenStack のオブジェクトのこと。
- スタック: Heat によってテンプレートから作成されるシステム環境のこと。テンプレートにはネットワーク、仮想ルータ、インスタンスなどの設定が書かれている。

# 環境

ESXi 上に Devstack をインストールし、環境に対して一部設定を追加しています。
詳しくは [新人が DevStack 上で Tacker を動かそうとする話](https://qiita.com/yoshi_1010/items/c1db52099b5897e049d0) と [新人が DevStack 上で TOSCA を使用して VNF を VM としてデプロイする話](https://qiita.com/yoshi_1010/items/1dbe4fe3c11f2b743853) をお読みください。

# インストール手順

この手順は本環境でインストール完了までうまくいったものです。
手順完成までに発生したエラーは [4. 発生したエラー](#発生したエラー) にまとめます。

## 実行ユーザとディレクトリ

stack ユーザで実行します。

```
sudo -u stack -i
```

自分で作成したファイルを配置する work ディレクトリを作成します。

```
mkdir ~/work/
```

work ディレクトリに移動します。

```
cd ~/work
```

## VM としての VNF の展開

### VNF パッケージの作成

VNF パッケージを作成します。

```
$ openstack vnf package create
+-------------------+-------------------------------------------------------------------------------------------------+
| Field             | Value                                                                                           |
+-------------------+-------------------------------------------------------------------------------------------------+
| ID                | 266d96d7-6d1c-41dc-9ea5-2a42d139124d                                                            |
| Links             | {                                                                                               |
|                   |     "self": {                                                                                   |
|                   |         "href": "/vnfpkgm/v1/vnf_packages/266d96d7-6d1c-41dc-9ea5-2a42d139124d"                 |
|                   |     },                                                                                          |
|                   |     "packageContent": {                                                                         |
|                   |         "href": "/vnfpkgm/v1/vnf_packages/266d96d7-6d1c-41dc-9ea5-2a42d139124d/package_content" |
|                   |     }                                                                                           |
|                   | }                                                                                               |
| Onboarding State  | CREATED                                                                                         |
| Operational State | DISABLED                                                                                        |
| Usage State       | NOT_IN_USE                                                                                      |
| User Defined Data | {}                                                                                              |
+-------------------+-------------------------------------------------------------------------------------------------+
```

環境変数として VNF のパッケージ ID を定義しておきます。

```
export VNF_PACKAGE_ID=266d96d7-6d1c-41dc-9ea5-2a42d139124d
```

確認します。

```
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Onboarding State' -c 'Operational State' -c 'Usage State'

+-------------------+------------+
| Field             | Value      |
+-------------------+------------+
| Onboarding State  | CREATED    |
| Operational State | DISABLED   |
| Usage State       | NOT_IN_USE |
+-------------------+------------+
```

### VNF パッケージのアップロード

LCM 操作のユーザーデータを使用して VNF を展開するには、VNF パッケージのオプションである BaseHOT と UserData を VNF パッケージに含める必要があります。

アップロードするファイルは tacker リポジトリから取得します。
取得には zip コマンドが必要であるため、zip コマンドがインストールされていない場合はインストールします。

```
sudo apt install zip
```

この時、[新人が DevStack 上で TOSCA を使用して VNF を VM としてデプロイする話](https://qiita.com/yoshi_1010/items/1dbe4fe3c11f2b743853) の手順を踏み、すでにサンプルの VNF パッケージをアップロード済みである場合、下記の手順をそのまま実行することでエラーが発生する可能性があります。

発生する可能性が高いエラーは重複不可なパッケージ ID が重複してしまうというものです。
これはサンプルパッケージをそのまま利用していることが原因で発生してしまうエラーです。
そのため、場合によっては新たにアップデートする VNF パッケージに設定する ID を変更します。

VNF パッケージのサンプルファイルがあるディレクトリに移動します。

```
cd ../tacker/samples/etsi_getting_started/userdata/sample_vnf_package_csar
```

下記の手順は ID を変更するためのものです。
サンプルデータに存在している既存の値からどこかの数値を 1 増やした値にするとよいです。

```
# 下記 2 つのファイルで b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 の値を変更する
$ vim Definitions/sample_vnfd_types.yaml
node_types:
 company.provider.VNF:
   ...
   properties:
     ...
     descriptor_id:
       ...
       constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ]
       default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177

$ vim Definitions/sample_vnfd_top.yaml
 node_templates:
   VNF:
     ...
     properties:
       ...
       descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
```

zip コマンドで圧縮します。

```
zip -r sample_vnf_pkg_lcm.zip TOSCA-Metadata Definitions BaseHOT UserData Files
cd -
mv ../tacker/samples/etsi_getting_started/userdata/sample_vnf_package_csar/sample_vnf_pkg_lcm.zip .
 ```

VNF パッケージをアップロードします。

```
$ openstack vnf package upload --path sample_vnf_pkg_lcm.zip $VNF_PACKAGE_ID
Upload request for VNF package 266d96d7-6d1c-41dc-9ea5-2a42d139124d has been accepted.
```

確認します。

```
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Onboarding State' -c 'Operational State' -c 'Usage State' -c 'VNFD ID'

+-------------------+--------------------------------------+
| Field             | Value                                |
+-------------------+--------------------------------------+
| Onboarding State  | ONBOARDED                            |
| Operational State | ENABLED                              |
| Usage State       | NOT_IN_USE                           |
| VNFD ID           | b1bb0ce7-ebca-4fa7-95ed-4840d70a1181 |
+-------------------+--------------------------------------+
```

環境変数として VNFD ID を定義しておきます。

```
export VNFD_ID=b1bb0ce7-ebca-4fa7-95ed-4840d70a1181
```

### VNF Identifier の作成

VNF インスタンスを作成します。

```
$ openstack vnflcm create $VNFD_ID
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| Field                       | Value                                                                                                            |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| ID                          | a59a2761-d0fa-4b4c-a674-b2b9dea4110e                                                                             |
| Instantiation State         | NOT_INSTANTIATED                                                                                                 |
| Links                       | {                                                                                                                |
|                             |     "self": {                                                                                                    |
|                             |         "href": "http://localhost:9890/vnflcm/v1/vnf_instances/a59a2761-d0fa-4b4c-a674-b2b9dea4110e"             |
|                             |     },                                                                                                           |
|                             |     "instantiate": {                                                                                             |
|                             |         "href": "http://localhost:9890/vnflcm/v1/vnf_instances/a59a2761-d0fa-4b4c-a674-b2b9dea4110e/instantiate" |
|                             |     }                                                                                                            |
|                             | }                                                                                                                |
| VNF Configurable Properties |                                                                                                                  |
| VNF Instance Description    | None                                                                                                             |
| VNF Instance Name           | vnf-a59a2761-d0fa-4b4c-a674-b2b9dea4110e                                                                         |
| VNF Product Name            | Sample VNF                                                                                                       |
| VNF Provider                | Company                                                                                                          |
| VNF Software Version        | 1.0                                                                                                              |
| VNFD ID                     | b1bb0ce7-ebca-4fa7-95ed-4840d70a1181                                                                             |
| VNFD Version                | 1.0                                                                                                              |
| vnfPkgId                    |                                                                                                                  |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
```

環境変数として VNFD ID を定義しておきます。

```
export VNF_INSTANCE_ID=a59a2761-d0fa-4b4c-a674-b2b9dea4110e
```

確認します。

```
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Usage State'
+-------------+--------+
| Field       | Value  |
+-------------+--------+
| Usage State | IN_USE |
+-------------+--------+

$ openstack vnflcm show $VNF_INSTANCE_ID \
-c 'Instantiation State'
+---------------------+------------------+
| Field               | Value            |
+---------------------+------------------+
| Instantiation State | NOT_INSTANTIATED |
+---------------------+------------------+
```

### VNFのインスタンス化

次の形式で sample_param_file.json ファイルを作成します。
これは、インスタンス化リクエストのパラメータを定義するファイルです。
これらのパラメータは、インスタンス化リクエストの本文で設定されます。

必須パラメータ

- flavourID
- additionalParams

オプションのパラメータ

- instantiationLevelId
- extVirtualLinks
- extManagedVirtualLinks
- vimConnectionInfo

additionalParams は、KeyValuePairs で記述できるパラメーターです。
このパラメータに以下の 2 つのパラメータを設定することにより、LCM 操作のユーザデータを使用したインスタンス化が可能になります。
file_name.py と class_name には、アップロードしたパッケージ内の UserData ディレクトリにあるファイルのファイル名とクラス名を定義します。

```
lcm-operation-user-data: ./UserData/file_name.py
lcm-operation-user-data-class: class_name
```

インスタンス化するために使用する sample_param_file_LCM.json を取得します。

```
cp -ai ../tacker/samples/etsi_getting_started/userdata/lcm_instantiate_request/sample_param_file.json sample_param_file_LCM.json
```

インスタンス化するために使用する sample_param_file_LCM.json に必要な情報を収集します。

- extVirtualLinks.resourceId: 7539276f-fa1e-44f4-8ff3-f6fb44f2e7e9 
- extVirtualLinks.extCps.cpConfig.cpProtocolData.ipAddresses.subnetId: a94f82d5-2ecc-428d-97fc-2730c79b6170

今回は VNF インスタンスへのインバウンドパケットのためのネットワークである net0 を利用します。

```
$ openstack network list
+--------------------------------------+-----------------+----------------------------------------------------------------------------+
| ID                                   | Name            | Subnets                                                                    |
+--------------------------------------+-----------------+----------------------------------------------------------------------------+
| 02bb6ed5-bd90-423a-9b8e-2de58bd45329 | public          | 323e6649-5b29-4ff1-afe3-cac404325ce3, 5c234bb8-0372-494d-b701-94d5640b9067 |
| 0b83f650-5556-4d23-b72f-3767230e747b | net1            | c3810efb-c74b-41d9-8041-9d1e684e3f2d                                       |
| 1cbda5ce-a7b7-4798-81d5-f97019f7fbb7 | k8s-pod-net     | 140dfd97-deab-46f5-a6df-fea2a48f842b                                       |
| 45d5bdcc-a88a-4f23-84e7-570f9b1bc5ee | k8s-service-net | 45506c3b-441c-49d4-a9dd-4ba75eb0d86b                                       |
| 4b0c4d1f-9c01-4c80-be92-19e5c3b8dfaa | private         | 512581fc-601e-42ad-b26d-10d98c356088, 6d0ce67d-434a-45fd-bab6-898fc93386cc |
| 7539276f-fa1e-44f4-8ff3-f6fb44f2e7e9 | net0            | a94f82d5-2ecc-428d-97fc-2730c79b6170                                       |
| 7db2bc29-6625-40aa-bdf2-ab91e3d47143 | net_mgmt        | 75620ca9-00b9-4cb9-a01a-c8f67d841ba4                                       |
| fbd1da96-6631-41d0-a09d-6fca9b3edc0e | lb-mgmt-net     | db9b1b01-bde5-4e81-969a-013ac5181f7a                                       |
+--------------------------------------+-----------------+----------------------------------------------------------------------------+
```

- vimConnectionInfo.vimId: 03179d72-ac26-4ac2-bdd4-43cc2672dea8

VNF をインスタンス化する VIM の ID を `openstack vim list` コマンドで取得します。
このコマンドで複数の VIM が出力された場合は自身が使用したい VIM の ID を 1 つ選択してください。

```
$ openstack vim list
+--------------------------------------+-------------------+----------------------------------+-----------+------------+-----------+
| ID                                   | Name              | Tenant_id                        | Type      | Is Default | Status    |
+--------------------------------------+-------------------+----------------------------------+-----------+------------+-----------+
| 03179d72-ac26-4ac2-bdd4-43cc2672dea8 | openstack-nfv-vim | 7ef18f601b824be897934f6793130760 | openstack | True       | REACHABLE |
+--------------------------------------+-------------------+----------------------------------+-----------+------------+-----------+
```

取得した情報を用いて sample_param_file_LCM.json を作成します。

```
cat << _EOF_ > ~/work/sample_param_file_LCM.json
{
  "flavourId": "simple",
  "extVirtualLinks": [
    {
      "id": "net0",
      "resourceId": "7539276f-fa1e-44f4-8ff3-f6fb44f2e7e9",
      "extCps": [
        {
          "cpdId": "CP1",
          "cpConfig": [
            {
              "cpProtocolData": [
                {
                  "layerProtocol": "IP_OVER_ETHERNET",
                  "ipOverEthernet": {
                    "ipAddresses": [
                      {
                        "type": "IPV4",
                        "numDynamicAddresses": 1,
                        "subnetId": "a94f82d5-2ecc-428d-97fc-2730c79b6170"
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "vimConnectionInfo": [
    {
      "id": "e24f9796-a8e9-4cb0-85ce-5920dcddafa1",
      "vimId": "03179d72-ac26-4ac2-bdd4-43cc2672dea8",
      "vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2"
    }
  ],
  "additionalParams": {
    "lcm-operation-user-data": "./UserData/lcm_user_data.py",
    "lcm-operation-user-data-class": "SampleUserData"
  }
}
_EOF_
```

VNF インスタンスをインスタンス化します。

```
openstack vnflcm instantiate $VNF_INSTANCE_ID \
./sample_param_file_LCM.json
```

確認します。

```
$ openstack vnflcm show  $VNF_INSTANCE_ID -c 'Instantiation State'
+---------------------+--------------+
| Field               | Value        |
+---------------------+--------------+
| Instantiation State | INSTANTIATED |
+---------------------+--------------+
```

## VNF の終了

VNF インスタンスを終了させます。

```
$ openstack vnflcm terminate $VNF_INSTANCE_ID
Terminate request for VNF Instance 'a59a2761-d0fa-4b4c-a674-b2b9dea4110e' has been accepted.
```

確認します。

```
$ openstack vnflcm show $VNF_INSTANCE_ID \
-c 'Instantiation State'
+---------------------+------------------+
| Field               | Value            |
+---------------------+------------------+
| Instantiation State | NOT_INSTANTIATED |
+---------------------+------------------+
```

## VNF Identifier を削除

VNF Identifier を削除します.

```
$ openstack vnflcm delete $VNF_INSTANCE_ID
Vnf instance 'a59a2761-d0fa-4b4c-a674-b2b9dea4110e' deleted successfully
```

確認します。

```
$ openstack vnf package show $VNF_PACKAGE_ID \
-c 'Usage State'
+-------------+------------+
| Field       | Value      |
+-------------+------------+
| Usage State | NOT_IN_USE |
+-------------+------------+

$ openstack vnflcm show $VNF_INSTANCE_ID \
-c 'Instantiation State'
Can not find requested vnf instance: a59a2761-d0fa-4b4c-a674-b2b9dea4110e
```

# 発生したエラー

## VNF パッケージがアップロードされない

下記のコマンド実行時のエラーです。

```
$ openstack vnf package upload --path sample_vnf_pkg_lcm.zip $VNF_PACKAGE_ID
```

このエラー発生時のパッケージ作成に利用したディレクトリは `~/tacker/samples/vnf_packages` です。

```
$ journalctl -xe -u devstack@tacker-conductor.service -f   

...
TRACE oslo_messaging.rpc.server Traceback (most recent call last):
TRACE oslo_messaging.rpc.server   File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/server.py", line 165, in _process_incoming
TRACE oslo_messaging.rpc.server     res = self.dispatcher.dispatch(message)
TRACE oslo_messaging.rpc.server   File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 309, in dispatch
TRACE oslo_messaging.rpc.server     return self._do_dispatch(endpoint, method, ctxt, args)
TRACE oslo_messaging.rpc.server   File "/usr/local/lib/python3.8/dist-packages/oslo_messaging/rpc/dispatcher.py", line 229, in _do_dispatch
TRACE oslo_messaging.rpc.server     result = func(ctxt, **new_args)
TRACE oslo_messaging.rpc.server   File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 158, in decorated_function
TRACE oslo_messaging.rpc.server     vnf_package.save()
TRACE oslo_messaging.rpc.server   File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 227, in __exit__
TRACE oslo_messaging.rpc.server     self.force_reraise()
TRACE oslo_messaging.rpc.server   File "/usr/local/lib/python3.8/dist-packages/oslo_utils/excutils.py", line 200, in force_reraise
TRACE oslo_messaging.rpc.server     raise self.value
TRACE oslo_messaging.rpc.server   File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 131, in decorated_function
TRACE oslo_messaging.rpc.server     return function(self, context, *args, **kwargs)
TRACE oslo_messaging.rpc.server   File "/opt/stack/tacker/tacker/conductor/conductor_server.py", line 486, in upload_vnf_package_content
TRACE oslo_messaging.rpc.server     raise Exception(msg)
TRACE oslo_messaging.rpc.server Exception: Vnf package with vnfd id b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 already exists.
```

原因は内容が全く同じ VNF パッケージを新たにアップロードしようとしていたことでした。
`Exception: Vnf package with vnfd id b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 already exists.` となっているため、アップロードしている VNF パッケージを作成したディレクトリで `b1bb0ce7-ebca-4fa7-95ed-4840d70a1177` の値を確認すると下記のように id がセットされていることがわかりました。

```
$ grep -e "b1bb0ce7-ebca-4fa7-95ed-4840d70a1177" -rn ~/tacker/samples/vnf_packages
./Definitions/helloworld3_types.yaml:27:        constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ]
./Definitions/helloworld3_types.yaml:28:        default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
./Definitions/helloworld3_top.vnfd.yaml:22:        descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177

$ cat ./Definitions/helloworld3_top.vnfd.yaml

...

imports:
  - etsi_nfv_sol001_common_types.yaml
  - etsi_nfv_sol001_vnfd_types.yaml
  - helloworld3_types.yaml
  - helloworld3_df_simple.yaml
  
...

topology_template:
  inputs:
    ...

  node_templates:
    VNF:
      type: company.provider.VNF
      properties:
        flavour_id: { get_input: selected_flavour }
        descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
		


$ cat ./Definitions/helloworld3_types.yaml

...

node_types:
  company.provider.VNF:
    derived_from: tosca.nodes.nfv.VNF
    properties:
      ...
      descriptor_id:
        type: string
        constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ]
        default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
```

この id は重複が許されないためエラーが発生しました。
そのため、この id をすべて変更することで動作するようになります。
ちなみにですが、helloworld3_top.vnfd.yaml の方で import しているため、 helloworld3_top.vnfd.yaml のみを変更することで対処可能ですが、安全のためすべて変更するのがおすすめです。

設定している id は Tacker がパッケージを識別するために利用するものであり、重複しない限りユーザー側で自由に設定してよい値です。
今回は直接ファイルを変更し、サンプルデータ値である `b1bb0ce7-ebca-4fa7-95ed-4840d70a1177`のいずれかの値を 1 増やした値にするとよいです。

`uuidgen` コマンドで生成した UUID を設定しても良いです。

```
$ uuidgen
739d4288-c0b6-422b-9bc6-19fb085fea55
```

## VNF インスタンス化できない

下記のコマンド実行時のエラーです。

```
$ openstack vnflcm instantiate $VNF_INSTANCE_ID ./sample_param_file_LCM.json
```

###  failed to get Base HOT

このエラー発生時のパッケージ作成に利用したディレクトリは `~/tacker/samples/vnf_packages` です。

```
$ journalctl -xe -u devstack@tacker-conductor.service --no-pager -f

tacker-conductor[1171]: 2022-07-11 01:13:35.273 ERROR tacker.vnflcm.vnflcm_driver [req-e3384124-0443-4fc3-801d-b48923dbc498 admin admin] Unable to instantiate vnf instance 4f9c3d09-820c-43db-b369-b15c12423267 due to error : LCM user data failed to get Base HOT.: tacker.extensions.vnfm.LCMUserDataFailed: LCM user data failed to get Base HOT.
tacker-conductor[1171]: 2022-07-11 01:13:35.273 ERROR root [req-e3384124-0443-4fc3-801d-b48923dbc498 admin admin] Original exception being dropped: ['Traceback (most recent call last):\n', '  File "/opt/stack/tacker/tacker/vnflcm/vnflcm_driver.py", line 371, in _instantiate_vnf\n    instance_id = self._vnf_manager.invoke(\n', '  File "/opt/stack/tacker/tacker/common/driver_manager.py", line 71, in invoke\n    return getattr(driver, method_name)(**kwargs)\n', '  File "/opt/stack/tacker/tacker/vnfm/infra_drivers/openstack/openstack.py", line 1139, in instantiate_vnf\n    instance_id = self.create(plugin, context, vnfd_dict,\n', '  File "/opt/stack/tacker/tacker/common/log.py", line 35, in wrapper\n    return method(*args, **kwargs)\n', '  File "/opt/stack/tacker/tacker/vnfm/infra_drivers/openstack/openstack.py", line 180, in create\n    raise vnfm.LCMUserDataFailed(reason=error_reason)\n', 'tacker.extensions.vnfm.LCMUserDataFailed: LCM user data failed to get Base HOT.\n']: tacker.common.exceptions.VnfInstantiationFailed: Vnf instantiation failed for vnf 4f9c3d09-820c-43db-b369-b15c12423267, error: LCM user data failed to get Base HOT.
tacker-conductor[1171]: 2022-07-11 01:13:35.274 DEBUG tacker.common.log [req-e3384124-0443-4fc3-801d-b48923dbc498 admin admin] tacker.conductor.conductor_server.Conductor method _change_vnf_status called with arguments (<tacker.context.Context object at 0x7fb5d58f8190>, '4f9c3d09-820c-43db-b369-b15c12423267', ('ACTIVE', 'INACTIVE', 'ERROR', 'PENDING_INSTANTIATE', 'PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE', 'PENDING_SCALE_IN', 'PENDING_SCALE_OUT', 'PENDING_HEAL', 'PENDING_TERMINATE', 'PENDING_CHANGE_EXT_CONN'), 'ERROR') {} from (pid=1171) wrapper /opt/stack/tacker/tacker/common/log.py:34
```

`LCM user data failed to get Base HOT` が発生していました。
[VNF Package](https://docs.openstack.org/tacker/latest/user/vnf-package.html) にも書いてある通り、LCM では BaseHOT や USERDATE の情報がパッケージ内部に必要です。
これにより原因として、アップロードしたパッケージ情報の不足が考えられます。

そのため、tacker リポジトリの `samples/practical_vnf_package` のように BaseHOT や USERDATE が含まれているサンプルを利用する必要がありました。
[VNF Package](https://docs.openstack.org/tacker/latest/user/vnf-package.html) には必須のディレクトリとして `Files/images` が挙げられていますが、これは [ETSI NFV-SOL VNF Deployment as VM with TOSCA](https://docs.openstack.org/tacker/latest/user/etsi_vnf_deployment_as_vm_with_tosca.html)のように TOSCA ベースの手順を実行する場合のみ必要であり、オートスケールするためのイメージとして利用されます。
今回の LCM ベースの場合は Glance に保存されているイメージを利用するため、TOSCA ベースとは異なり、`Files/images` を zip ファイルにしてアップロードする必要がありません。

###  No flavour with id 'simple'

このエラー発生時のパッケージ作成に利用したディレクトリは `~/tacker/samples/practical_vnf_package` です。

```
$ openstack vnflcm instantiate $VNF_INSTANCE_ID ./sample_param_file_LCM.json
No flavour with id 'simple'.  

$ journalctl -xe -u devstack@tacker.service --no-pager

...

ERROR tacker.wsgi [req-35d65a4d-0738-471a-948b-e07754d11fa7 admin admin] HTTP exception thrown: No flavour with id 'simple'.: webob.exc.HTTPBadRequest: No flavour with id 'simple'.
INFO tacker.wsgi [req-35d65a4d-0738-471a-948b-e07754d11fa7 admin admin] http://10.100.2.220:9890/vnflcm/v1/vnf_instances/b0068512-be8c-4f1f-acc2-8111cfda2abf/instantiate returned with HTTP 400
DEBUG tacker.wsgi [req-35d65a4d-0738-471a-948b-e07754d11fa7 admin admin] Returning 400 to user: No flavour with id 'simple'. from (pid=1172) __call__ /opt/stack/tacker/tacker/wsgi.py:1057
INFO tacker.wsgi [req-35d65a4d-0738-471a-948b-e07754d11fa7 admin admin] 10.100.2.220 - - [11/Jul/2022 05:39:48] "POST /vnflcm/v1/vnf_instances/b0068512-be8c-4f1f-acc2-8111cfda2abf/instantiate HTTP/1.1" 400 311 0.058706
```

flavour id が違うと書かれています。
また、インスタンス化のリクエストに対するレスポンスで 400 Bad Request が発生しています。
パッケージとして作成した、flavour id を調べたところ、

```
# TOSCA ベースのパッケージ
~/tacker/samples/vnf_packages$ grep -e "flavour_id" -rn .
./Definitions/etsi_nfv_sol001_vnfd_types.yaml:1032:      flavour_id:
./Definitions/helloworld3_df_simple.yaml:32:    flavour_id:
./Definitions/helloworld3_df_simple.yaml:40:      flavour_id: simple
./Definitions/helloworld3_types.yaml:51:      flavour_id:
./Definitions/helloworld3_top.vnfd.yaml:21:        flavour_id: { get_input: selected_flavour }

# LCM ベースのパッケージ
~/tacker/samples/practical_vnf_package$ grep -e "flavour_id" -rn .
./Definitions/etsi_nfv_sol001_vnfd_types.yaml:1032:      flavour_id:
./Definitions/df_scalable.yaml:26:    flavour_id:
./Definitions/df_scalable.yaml:36:      flavour_id: scalable
./Definitions/Common.yaml:38:      flavour_id:
./Definitions/df_ha.yaml:26:    flavour_id:
./Definitions/df_ha.yaml:36:      flavour_id: ha
./Definitions/Node.yaml:22:        flavour_id: { get_input: selected_flavour }
```

となっており、flavour_id に今まで (~/tacker/samples/vnf_packages) とは違うものが設定されていました。
sample_param_file_LCM.json で指定する際の flavourId を scalable に変更して再度インスタンス化実行しました。

ただし、この時利用した ~/tacker/samples/vnf_packages のパッケージも [ETSI NFV-SOL VNF Deployment as VM with LCM Operation User Data](https://docs.openstack.org/tacker/latest/user/etsi_vnf_deployment_as_vm_with_user_data.html) を参考に利用するには不適切です。
手順のように ~/tacker/samples/etsi_getting_started/userdata/sample_vnf_package_csar のパッケージを利用することでこのあたりの値が異なるというエラーが発生しなくなるため、こちらのサンプルパッケージを利用することを推奨します。

### vnfd_simple のエラー

```
tacker-conductor[1171]: 2022-07-11 07:29:06.898 ERROR tacker.vnflcm.vnflcm_driver [req-b242887b-91fb-4868-b790-94887bec980e admin admin] Unable to instantiate vnf instance d921b648-2294-4268-8983-2c91c64b5502 due to error : 'vnfd_simple'
tacker-conductor[1171]: 2022-07-11 07:29:06.898 ERROR root [req-b242887b-91fb-4868-b790-94887bec980e admin admin] Original exception being dropped: ['Traceback (most recent call last):\n', '  File "/opt/stack/tacker/tacker/vnflcm/vnflcm_driver.py", line 371, in _instantiate_vnf\n    instance_id = self._vnf_manager.invoke(\n', '  File "/opt/stack/tacker/tacker/common/driver_manager.py", line 71, in invoke\n    return getattr(driver, method_name)(**kwargs)\n', '  File "/opt/stack/tacker/tacker/vnfm/infra_drivers/openstack/openstack.py", line 1139, in instantiate_vnf\n    instance_id = self.create(plugin, context, vnfd_dict,\n', '  File "/opt/stack/tacker/tacker/common/log.py", line 35, in wrapper\n    return method(*args, **kwargs)\n', '  File "/opt/stack/tacker/tacker/vnfm/infra_drivers/openstack/openstack.py", line 185, in create\n    vnfd_str = vnf[\'vnfd\'][\'attributes\'][\'vnfd_\' +\n', "KeyError: 'vnfd_simple'\n"]: tacker.common.exceptions.VnfInstantiationFailed: Vnf instantiation failed for vnf d921b648-2294-4268-8983-2c91c64b5502, error: 'vnfd_simple'
tacker-conductor[1171]: 2022-07-11 07:29:06.898 DEBUG tacker.common.log [req-b242887b-91fb-4868-b790-94887bec980e admin admin] tacker.conductor.conductor_server.Conductor method _change_vnf_status called with arguments (<tacker.context.Context object at 0x7fb5d4ce5940>, 'd921b648-2294-4268-8983-2c91c64b5502', ('ACTIVE', 'INACTIVE', 'ERROR', 'PENDING_INSTANTIATE', 'PENDING_CREATE', 'PENDING_UPDATE', 'PENDING_DELETE', 'PENDING_SCALE_IN', 'PENDING_SCALE_OUT', 'PENDING_HEAL', 'PENDING_TERMINATE', 'PENDING_CHANGE_EXT_CONN'), 'ERROR') {} from (pid=1171) wrapper /opt/stack/tacker/tacker/common/log.py:33
tacker-conductor[1171]: 2022-07-11 07:29:06.901 DEBUG tacker.conductor.conductor_server [req-b242887b-91fb-4868-b790-94887bec980e admin admin] Change status of vnf d921b648-2294-4268-8983-2c91c64b5502 from PENDING_CREATE to ERROR from (pid=1171) _change_vnf_status /opt/stack/tacker/tacker/conductor/conductor_server.py:643
tacker-conductor[1171]: 2022-07-11 07:29:06.904 DEBUG tacker.common.log [req-b242887b-91fb-4868-b790-94887bec980e admin admin] tacker.conductor.conductor_server.Conductor method _build_instantiated_vnf_info called with arguments (<tacker.context.Context object at 0x7fb5d4ce5940>, VnfInstance(created_at=2022-07-11T07:21:59Z,deleted=False,deleted_at=None,id=d921b648-2294-4268-8983-2c91c64b5502,instantiated_vnf_info=InstantiatedVnfInfo,instantiation_state='NOT_INSTANTIATED',task_state='INSTANTIATING',tenant_id='7ef18f601b824be897934f6793130760',updated_at=2022-07-11T07:29:05Z,vim_connection_info=[VimConnectionInfo(e24f9796-a8e9-4cb0-85ce-5920dcddafa1)],vnf_instance_description=None,vnf_instance_name='vnf-d921b648-2294-4268-8983-2c91c64b5502',vnf_metadata=None,vnf_pkg_id='98283a4e-5f8b-4209-95bf-ef1ab9ad333f',vnf_product_name='Sample VNF',vnf_provider='Company',vnf_software_version='1.0',vnfd_id='b1bb0ce7-ebca-4fa7-95ed-4840d70a1178',vnfd_version='1.0'), InstantiateVnfRequest(additional_params={lcm-operation-user-data=./UserData/lcm_user_data.py,lcm-operation-user-data-class=SampleUserData},ext_managed_virtual_links=[],ext_virtual_links=[ExtVirtualLinkData(net0)],flavour_id='simple',instantiation_level_id=None,vim_connection_info=[VimConnectionInfo(e24f9796-a8e9-4cb0-85ce-5920dcddafa1)])) {} from (pid=1171) wrapper /opt/stack/tacker/tacker/common/log.py:33
```

VNF パッケージのアップロードを繰り返した結果、アップロードしたものと `vnflcm create` で参照したものに不整合が発生してしまったために発生したエラーのようでした。

下記のコマンドの結果から VNF パッケージと vnflcm で参照しているパッケージの ID (VNFD ID) は末尾が 1178 となっていることがわかります。

```
$ openstack vnf package show $VNF_PACKAGE_ID
+----------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Field                | Value                                                                                                                                          |
+----------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Additional Artifacts |                                                                                                                                                |
~~~                                                                                                                              |
| VNFD ID              | b1bb0ce7-ebca-4fa7-95ed-4840d70a1178                                                                                                           |
| VNFD Version         | 1.0                                                                                                                                            |
+----------------------+------------------------------------------------------------------------------------------------------------------------------------------------+

$ openstack vnflcm show $VNF_INSTANCE_ID
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| Field                       | Value                                                                                                            |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
| ID                          | d921b648-2294-4268-8983-2c91c64b5502                                                                             |
| Instantiation State         | NOT_INSTANTIATED                                                                                                 |
~~~                                                                                                             |
| VNFD ID                     | b1bb0ce7-ebca-4fa7-95ed-4840d70a1178                                                                             |
| VNFD Version                | 1.0                                                                                                              |
| vnfPkgId                    |                                                                                                                  |
+-----------------------------+------------------------------------------------------------------------------------------------------------------+
```

しかし、実際にロードされているパッケージの VNFD ID の末尾は 1179 になってしまっています。

```
stack@yoshitest2:~/data/tacker/vnfpackage$ grep descriptor_id -r
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_top.yaml:       descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1179
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/etsi_nfv_sol001_vnfd_types.yaml:      descriptor_id: # instead of vnfd_id
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_types.yaml:     descriptor_id:
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_df_simple.yaml:   descriptor_id:

stack@yoshitest2:~/data/tacker/vnfpackage$ grep 1179 -r
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_top.yaml:       descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1179
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_types.yaml:       constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1179 ] ]
98283a4e-5f8b-4209-95bf-ef1ab9ad333f/Definitions/sample_vnfd_types.yaml:       default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1179
```

そのため、一度アップロードしたパッケージや作成した VNF インスタンスを削除し、新たに ID を変更したパッケージをアップロードし直した後、そちらのパッケージを利用するように新たにインスタンス化することによって対応することができます。

## VNF パッケージの削除できない

```
$ openstack vnf package delete 75d3bc97-b214-4238-8283-695c0ae08bf1
Unable to delete the below 'vnf_package'(s):
Cannot delete 75d3bc97-b214-4238-8283-695c0ae08bf1: VNF Package 75d3bc97-b214-4238-8283-695c0ae08bf1 cannot be deleted as it's operational state is ENABLED and usage state is NOT_IN_USE.
```

パッケージ削除のためには Operational State が下記のように ENABLE となっている場合、DISABLED に変更する必要がありました。

```
$ openstack vnf package show $VNF_PACKAGE_ID -c 'Onboarding State' -c 'Operational State' -c 'Usage State'
+-------------------+-----------+ 
| Field             | Value      |
+-------------------+------------+
| Onboarding State  | ONBOARDED  |
| Operational State | ENABLED    |
| Usage State       | NOT_IN_USE |
+-------------------+------------+   
```

`opesnstack vnf package update` コマンドの ` --operational-state` オプションを利用して無効化します。

```
$ openstack vnf package update --operational-state DISABLED 75d3bc97-b214-4238-8283-695c0ae08bf1
+-------------------+----------+
| Field             | Value    |
+-------------------+----------+
| Operational State | DISABLED |
+-------------------+----------+
```

削除します。

```
$ openstack vnf package delete 75d3bc97-b214-4238-8283-695c0ae08bf1
All specified vnf-package(s) deleted successfully                                      
```

# まとめ

今回で LCM Operation User Data を利用して VNF インスタンス化ができました。
次回は CNF をデプロイしていきます。

ここまでお読みいただき、ありがとうございました。