Zabbix4.0のインポートファイルで設定出来ない項目を一括変更する方法

この記事は下記アドベントカレンダー 15日目の記事となります。
[エーピーコミュニケーションズ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ap-com)

皆さん、Zabbix使ってますか。
2018年10月にLTSのバージョン 4.0がリリースされました。
多くの新機能が追加され、グラフやダッシュボードの見た目も今風になり、
これからまた利用する方も増えて行く監視ソフトウェアなのではないでしょうか。

このリリースされて間もない Zabbix4.0に、
他のZabbixサーバからエクスポートしたネットワークマップ設定を
インポートしようとしたところ、一部の設定がXMLファイルに含まれておらず、
大量のネットワークマップ設定を手動で編集する危機に見舞われました。

何百もある設定を、一つ一つWEBGUIからポチポチ変更していくのは辛いので、
どうにか、その設定を一括変更することが出来ないかと考えました。

その手段について調査しましたので、その方法をまとめたいと思います。

###ネットワークマップ設定について
　Zabbixのネットワークマップ設定は、
　監視している装置やネットワークの結線状態を絵図で管理することが出来る機能です。
　障害が起き、アラートが発報されている時は、アイコンを赤くしたりすることで、
　障害がどの装置で起きているのか分かりやすく表示することも出来ます。

###エクスポートファイルに含まれない設定情報
　Zabbixのネットワークマップ設定はXMLファイルの形式で、
　設定内容をエクスポート・インポートすることが出来ます。
　ですが、ネットワークマップの共有設定はエクスポートファイルに含まれません。

###ネットワークマップの共有設定
　この設定は特定のマップに対して、
　特定のユーザ、またはユーザグループが閲覧・編集することを許可する設定となります。

　通常、管理者ユーザで作成したマップを、
　オペレータユーザは閲覧することが出来ませんが、
　共有設定によりオペレータユーザに閲覧許可することで、
　オペレータユーザでもマップを見る事が出来るようになります。

###一括変更の方法
　ホストの設定や、アイテムの設定ではWEBGUI上から一括変更する手段が用意されているのですが、
　ネットワークマップの設定にはWEBGUI上から一括変更する手段がありませんでした。

　そこで他に一括変更の手段が無いか、
　調査したところ、2つの手段があると分かりました。

###APIから一括で変更する方法
　1つ目はAPI経由で一括変更する方法です。
　APIの仕様を調査したところ、
　ネットワークマップの設定に共有設定の項目がありました。
　https://www.zabbix.com/documentation/current/manual/api/reference/map/object

　APIアクセスであれば、ネットワークマップの共有設定を変更できそうです。

　ネットワークマップ設定の各IDを取得し、
　全てのIDに対して共有設定を投入するプログラムを書けば、
　それを実行するだけで共有設定の一括変更が実現できます。

###DBから一括で変更する方法
　2つ目の方法はDBから一括変更する方法です。
　DBの構造を調べてみると、マップの共有設定は
　以下のテーブルに書き込まれることが分かりました。

共有設定ユーザの場合：sysmap_user
　https://zabbix.org/wiki/Docs/DB_schema/4.0/sysmap_user

共有設定ユーザグループの場合：sysmap_usrgrp
　https://zabbix.org/wiki/Docs/DB_schema/4.0/sysmap_usrgrp

　これらのテーブルにレコードを追加するSQLコマンドを投入すれば、
　一括変更が実現できます。

###【例】APIを使って一括変更する方法
　APIアクセスには色々な方法があると思いますが、
　今回はPHPのライブラリを使用して、ZabbixAPIへアクセスするプログラムを書いてみました。

####API経由でマップ設定を表示するプログラムの例
　[使用したライブラリ]
　https://github.com/confirm/PhpZabbixApi

　ライブラリの公式ページに記載されていた、サンプルコードを元に、
　マップ設定を全て表示するようにプログラムを書きました。

```php

<?php
require_once 'lib/ZabbixApi.class.php';
use ZabbixApi\ZabbixApi;

try
{
//APIアクセス先URLと、ID/PWを設定し、ログインする
    $api = new ZabbixApi('http://[IPアドレス or FQDN]/zabbix/api_jsonrpc.php', 'UserID', 'password');
//mapGetメソッドを実行して、結果を$resに格納する
    $res = $api->mapGet();
//$resに格納されたレスポンスを表示する
    var_dump($res);
}
catch(Exception $e)
{
    echo $e->getMessage();
}
?>
```
　このプログラムを実行すると、下記のような出力が得られます。

```
array(1) {
  [0]=>
  object(stdClass)#6 (31) {
    ["sysmapid"]=>
    string(1) "1"
    ["name"]=>
    string(13) "Local network"
    ["width"]=>
    string(3) "680"
    ["height"]=>
    string(3) "200"
    ["backgroundid"]=>
    string(1) "0"
    ["label_type"]=>
    string(1) "0"
    ["label_location"]=>
    string(1) "0"
    ["highlight"]=>
    string(1) "0"
    ["expandproblem"]=>
    string(1) "0"
    ["markelements"]=>
    string(1) "1"
    ["show_unack"]=>
    string(1) "0"
    ["grid_size"]=>
    string(2) "50"
    ["grid_show"]=>
    string(1) "1"
    ["grid_align"]=>
    string(1) "1"
    ["label_format"]=>
    string(1) "0"
    ["label_type_host"]=>
    string(1) "2"
    ["label_type_hostgroup"]=>
    string(1) "2"
    ["label_type_trigger"]=>
    string(1) "2"
    ["label_type_map"]=>
    string(1) "2"
    ["label_type_image"]=>
    string(1) "2"
    ["label_string_host"]=>
    string(0) ""
    ["label_string_hostgroup"]=>
    string(0) ""
    ["label_string_trigger"]=>
    string(0) ""
    ["label_string_map"]=>
    string(0) ""
    ["label_string_image"]=>
    string(0) ""
    ["iconmapid"]=>
    string(1) "0"
    ["expand_macros"]=>
    string(1) "1"
    ["severity_min"]=>
    string(1) "0"
    ["userid"]=>
    string(1) "1"
    ["private"]=>
    string(1) "1"
    ["show_suppressed"]=>
    string(1) "0"
  }
```
　この応答に含まれている各マップ設定のIDを取得し、
　マップID毎に、map.update APIを使って共有設定を投入する。
　こちらが1つ目の方法となります。

###【例】DBを使って一括変更する方法
　ネットワークマップの共有設定には下記の項目があります。
　1. タイプ：ネットワークマップの公開・非公開設定
　2. 共有するユーザ：ネットワークマップを共有するユーザ設定
　3. 共有するユーザグループ：ネットワークマップを共有するユーザグループ設定

　これらの設定は、DBの中ではそれぞれ別のテーブルで管理されています。

**タイプ：**
　この設定は「sysmaps」テーブルの「private」カラムで管理されています。
　デフォルトでは「非公開」となっており、「公開」に設定すると、
　共有するユーザ・ユーザグループとは関係なく、どのユーザからも閲覧が可能になります。
　[参考URL]
　https://zabbix.org/wiki/Docs/DB_schema/4.0/sysmaps

**共有するユーザ：**
　この設定は「sysmap_user」テーブルに格納されています。
　共有する対象のユーザと、権限を設定することが出来ます。
　[参考URL]
　https://zabbix.org/wiki/Docs/DB_schema/4.0/sysmap_user

**共有するユーザグループ：**
　この設定は「sysmap_usrgrp」テーブルに格納されています。
　共有する対象のユーザグループと、権限を設定することが出来ます。
　[参考URL]
　https://zabbix.org/wiki/Docs/DB_schema/4.0/sysmap_usrgrp

**下図：デフォルト状態のネットワークマップ共有設定**
![ネットワークマップの共有設定.png](https://qiita-image-store.s3.amazonaws.com/0/45111/fea76128-1722-78cf-1cd3-9192f8258c3b.png)

####SQLコマンド投入例
例として、下記のように設定する場合
　タイプ：非公開
　共有グループ：Guestグループ
　権限：表示

「sysmap_usrgrp」テーブルにレコードを追加することで設定出来ます。

```
MariaDB [zabbix]> INSERT INTO sysmap_usrgrp (sysmapusrgrpid,sysmapid,usrgrpid,permission) VALUES (1,1,8,2);
Query OK, 1 row affected (0.01 sec)
MariaDB [zabbix]> select * from sysmap_usrgrp;
+----------------+----------+----------+------------+
| sysmapusrgrpid | sysmapid | usrgrpid | permission |
+----------------+----------+----------+------------+
|              1 |        1 |        8 |          2 |
+----------------+----------+----------+------------+
1 row in set (0.00 sec)
```
あとは下記コマンド例のように、VALUESに続く値を
変更が必要なマップIDのぶんだけ、書いて実行すれば一括変更も可能です。

```
INSERT INTO sysmap_usrgrp (sysmapusrgrpid,sysmapid,usrgrpid,permission) VALUES (1,1,8,2), (2,2,8,2);
```

###まとめ
　Zabbixは監視対象の装置や、監視したいサービスなど、対象が増えると、
　大量の設定を管理しなければなりません。

　大量の設定が入ると予想がつく「ホスト」の設定や、「アイテム」などの設定は、
　一括変更や、XMLでのエクスポート・インポートなど一括で設定する手段がありますが、
　ネットワークマップや、ユーザなどの設定では、一括変更の手段が無かったりします。

　API経由での一括変更や、設定投入などの操作は応用が効く手段だと分かりましたので、
　他にもどういった操作が出来るか調査しておき、
　大量の設定変更があっても平気なように備えたいですね。