OpenStack のネットワーク作成における内部サーバーエラーの対処法

# はじめに
OpenStack Bobcat 環境構築中、VXLAN ネットワークを作成しようと思ったら内部サーバエラーが出力された。
```bash
# openstack network create network01 --provider-network-type vxlan
Error while executing command: HttpException: 500, 要求が失敗しました。要求の処理中に内部サーバーエラーが発生しました。
```

# 状況の確認
まずは `verbose` オプションで詳しく見てみると Control ノードの `:9696` への API リクエスト、つまり Neutron サーバへのアクセス時、その内部処理の最中に起きている可能性が高そうだということが分かった。
```bash
# openstack -vv network create private --provider-network-type vxlan 
 :
Network client initialized using OpenStack SDK: <openstack.network.v2._proxy.Proxy object at 0x7faf24328ac0>
REQ: curl -g -i --insecure -X POST https://osp-control-01.myhomelab.test:9696/v2.0/networks -H "Content-Type: application/json" -H "User-Agent: openstacksf5a5d8750214a607a226cd12ff9632f569a011a67" -d '{"network": {"provider:network_type": "vxlan", "admin_state_up": true, "name": "network01"}}'
Starting new HTTPS connection (1): osp-control-01.myhomelab.test:9696
https://osp-control-01.myhomelab.test:9696 "POST /v2.0/networks HTTP/1.1" 500 286
RESP: [500] Connection: keep-alive Content-Length: 286 Content-Type: application/json Date: Sat, 24 Feb 2024 09:45:12 GMT X-Openstack-Request-Id: req-1a2c
RESP BODY: {"NeutronError": {"type": "HTTPInternalServerError", "message": "\u8981\u6c42\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u8981\u6c42\u306e05f\u3002", "detail": ""}}
POST call to network for https://osp-control-01.myhomelab.test:9696/v2.0/networks used request id req-1a2c6c6f-1809-4c96-a1d8-636934d8de65
Error while executing command: HttpException: 500, 要求が失敗しました。要求の処理中に内部サーバーエラーが発生しました。
clean_up CreateNetwork: Error while executing command: HttpException: 500, 要求が失敗しました。要求の処理中に内部サーバーエラーが発生しました。
END return value: 1 
```

詳しく確認するため Neutron のログファイルを確認すると、
```bash
# vim /var/log/neutron/server.log
 :

2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation   File "/usr/lib/python3.9/site-packages/neutron_lib/callbacks/manager.py", line 164, in publish
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation     raise exceptions.CallbackFailure(errors=errors)
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation neutron_lib.callbacks.exceptions.CallbackFailure: Callback neutron.plugins.ml2.plugin.SecurityGroupDbMixin._ensure_default_security_group_handler-1436323 failed with "(pymysql.err.DataError) (1366, "Incorrect string value: '\\xE3\\x83\\x87\\xE3\\x83\\x95...' for column `neutron_ml2`.`standardattributes`.`description` at row 1")
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation [SQL: INSERT INTO standardattributes (resource_type, description, created_at, updated_at) VALUES (%(resource_type)s, %(description)s, %(created_at)s, %(updated_at)s)]
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation [parameters: {'resource_type': 'securitygroups', 'description': 'デフォルトセキュリティグループ', 'created_at': datetime.datetime(2024, 2, 24, 9, 51, 50), 'updated_at': datetime.datetime(2024, 2, 24, 9, 51, 50)}]
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation (Background on this error at: https://sqlalche.me/e/14/9h9h)"
2024-02-24 18:51:50.182 2310 ERROR neutron.pecan_wsgi.hooks.translation
2024-02-24 18:51:50.190 2310 INFO neutron.wsgi [None req-a3497447-3798-4c5e-b937-bddc2c431b88 e0485099471a453d92c36931b4e61860 af0fe637b97f45d9853d4226014d1207 - - default default] 127.0.0.1 "POST /v2.0/networks HTTP/1.1" status: 500  len: 504 time: 0.1964591
```

ログ中の `Incorrect string value` という部分のエラーが怪しそう。Neutron の Python 処理で DB へ操作を行う際に内部エラーが起きていそうだ。
```bash
"(pymysql.err.DataError) (1366, "Incorrect string value: '\\xE3\\x83\\x87\\xE3\\x83\\x95...' for column `neutron_ml2`.`standardattributes`.`description` at row 1")
```

# 原因
上記を詳しく調べてみると、どうやらデータベースの文字コードが不適切である可能性が高そう。
今回使用している MariaDB ではデフォルトの文字コードが `latin1` になっており、特段変更していなかったため、`utf8mb4` に修正する必要がある。
```bash
# mysql
 :

MariaDB [(none)]> show variables like '%char%';
+--------------------------+------------------------------+
| Variable_name            | Value                        |
+--------------------------+------------------------------+
| character_set_client     | utf8mb3                      |
| character_set_connection | utf8mb3                      |
| character_set_database   | latin1                       | <---(*)
| character_set_filesystem | binary                       |
| character_set_results    | utf8mb3                      |
| character_set_server     | latin1                       | <---(*)
| character_set_system     | utf8mb3                      |
| character_sets_dir       | /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.001 sec)
```

# 対処法
### デフォルトの文字コードを変更
すでに諸々の構築が進んでしまっているが、取り急ぎデフォルトの文字コードを修正する。
```bash
# vim /etc/my.cnf.d/charset.cnf
[mysqld]
character-set-server = utf8mb4

[client]
default-character-set = utf8mb4

# systemctl restart mariadb
```

文字コードが変更されているか確認する。
```bash
# mysql
 :
 
MariaDB [(none)]> show variables like '%char%';
+--------------------------+------------------------------+
| Variable_name            | Value                        |
+--------------------------+------------------------------+
| character_set_client     | utf8mb4                      |
| character_set_connection | utf8mb4                      |
| character_set_database   | utf8mb4                      | <---(*) OK
| character_set_filesystem | binary                       |
| character_set_results    | utf8mb4                      |
| character_set_server     | utf8mb4                      | <---(*) OK
| character_set_system     | utf8mb3                      |
| character_sets_dir       | /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.001 sec)
```

### 既存のデータベース/テーブルの文字コード再設定
上記の処理によってデフォルトの文字コードは変更されたが、すでに作成済みの DB が自動変更されるわけではないので対処は別途必要になる。
すべての DB を再設定するのは大変なため、とりあえず問題が起きている Neutron 用に作成した DB をいったん削除して再作成する。
```bash
# mysql
 :
MariaDB [(none)]> drop database neutron_ml2; /* 削除 */
Query OK, 191 rows affected (0.578 sec)

MariaDB [(none)]> create database neutron_ml2; /* 再度作成 */
Query OK, 1 row affected (0.000 sec)

MariaDB [(none)]> grant all privileges on neutron_ml2.* to neutron@'localhost' identified by 'password';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> grant all privileges on neutron_ml2.* to neutron@'%' identified by 'password';
Query OK, 0 rows affected (0.001 sec)

/* 結果を確認する */
MariaDB [(none)]> use neutron_ml2;
Database changed
MariaDB [neutron_ml2]> show variables like "chara%";
+--------------------------+------------------------------+
| Variable_name            | Value                        |
+--------------------------+------------------------------+
| character_set_client     | utf8mb4                      |
| character_set_connection | utf8mb4                      |
| character_set_database   | utf8mb4                      | <---(*) OK
| character_set_filesystem | binary                       |
| character_set_results    | utf8mb4                      |
| character_set_server     | utf8mb4                      | <---(*) OK
| character_set_system     | utf8mb3                      |
| character_sets_dir       | /usr/share/mariadb/charsets/ |
+--------------------------+------------------------------+
8 rows in set (0.001 sec)
```

### データベース再設定
以下のコマンドでデータベースを展開し
```bash
# neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini upgrade head
```

router と network が作成できるようになっていれば OK。
```bash
# openstack router create router01
+-------------------------+--------------------------------------+
| Field                   | Value                                |
+-------------------------+--------------------------------------+
| admin_state_up          | UP                                   |
| availability_zone_hints |                                      |
| availability_zones      |                                      |
| created_at              | 2024-02-24T10:22:05Z                 |
| description             |                                      |
| distributed             | False                                |
| enable_ndp_proxy        | None                                 |
| external_gateway_info   | null                                 |
| flavor_id               | None                                 |
| ha                      | False                                |
| id                      | fb58d995-5223-4d08-a2a9-701ad67ce5f1 |
| name                    | router01                             |
| project_id              | af0fe637b97f45d9853d4226014d1207     |
| revision_number         | 1                                    |
| routes                  |                                      |
| status                  | ACTIVE                               |
| tags                    |                                      |
| tenant_id               | af0fe637b97f45d9853d4226014d1207     |
| updated_at              | 2024-02-24T10:22:05Z                 |
+-------------------------+--------------------------------------+

# openstack network create private --provider-network-type vxlan
+---------------------------+--------------------------------------+
| Field                     | Value                                |
+---------------------------+--------------------------------------+
| admin_state_up            | UP                                   |
| availability_zone_hints   |                                      |
| availability_zones        |                                      |
| created_at                | 2024-02-24T10:22:11Z                 |
| description               |                                      |
| dns_domain                | None                                 |
| id                        | 7d82a5ea-bac5-4d52-9e90-df71f8d98a94 |
| ipv4_address_scope        | None                                 |
| ipv6_address_scope        | None                                 |
| is_default                | False                                |
| is_vlan_transparent       | None                                 |
| mtu                       | 1450                                 |
| name                      | private                              |
| port_security_enabled     | False                                |
| project_id                | af0fe637b97f45d9853d4226014d1207     |
| provider:network_type     | vxlan                                |
| provider:physical_network | None                                 |
| provider:segmentation_id  | 952                                  |
| qos_policy_id             | None                                 |
| revision_number           | 1                                    |
| router:external           | Internal                             |
| segments                  | None                                 |
| shared                    | False                                |
| status                    | ACTIVE                               |
| subnets                   |                                      |
| tags                      |                                      |
| tenant_id                 | af0fe637b97f45d9853d4226014d1207     |
| updated_at                | 2024-02-24T10:22:11Z                 |
+---------------------------+--------------------------------------+
```

# まとめ
`nova` や `keystone` の構築時には何も問題が起きず `neutron` のネットワーク設定時に初めて表面化したためハマってしまった。
データベース構築の際には一番最初に文字コードを `UTF-8` に設定しておくのが望ましそう。