ZabbixのUIからは検索できない条件をSQLで確認する

# はじめに
Zabbixのユーザインターフェースにおける検索フォームは基本的に**一致条件**しか指定できず、また同じ項目に対するOR条件による検索が出来ないなど、あまり自由度が高くありません。またUI画面の深いところにある設定の場合、他の同じような要素と比較することが困難です。
**除外条件**を含めた複雑な条件の検索をしたい場合は、RDB内を直接確認することで運用的に楽になる場合があり、良く使いそうな検索パターンを纏めてみました。

### 確認環境
・CentOS7
・Zabbix3.0
　　※ver2.0以上であれば基本的に記載した内容で検索できるはずです。但しver1.8に関してはカラム名が異なるものがあるためエラーになります。
・MariaDB

### アイテムの「例外の更新間隔」が設定されているものだけ検索
* 例外の更新間隔(=delay_flex)が「空以外(=設定が入っているもの)」のレコードを検索します。

```mysql
SELECT
  h.host,
  i.name,
  i.key_,
  i.delay_flex
FROM items i
  inner join hosts h on h.hostid = i.hostid
WHERE i.delay_flex <> ""
ORDER BY h.host;

+---------------------------+------------+------------+------------------------+
| host                      | name       | key_       | delay_flex             |
+---------------------------+------------+------------+------------------------+
| DB Server001              | Agent ping | agent.ping | wd1;30/1-7,09:00-10:00 |
| DB Server002              | Agent ping | agent.ping | wd1                    |
| Template App Zabbix Agent | Agent ping | agent.ping | wd1                    |
```
余談ですが、ZabbixUI上は一致条件しか指定ができないようになっていますが、APIでは一応「excludeSearch」パラメータで除外条件に変えることができます（内部的には多分NOT LIKE）。しかし合わせて使用するsearch、startSearchパラメータが、それぞれ内部的には「LIKE “%…%”」,「LIKE “…%”」となっており、どちらも強制的に「%」が入ってしまうためカラムが空またはNullのレコードを検索するのはAPIでは難しいようです。


### OR条件によるアイテムの検索
* 例としてサブクエリと同一項目に対するOR条件を使った方法を書いてみます。尚、カラムの情報は[APIマニュアル](https://www.zabbix.com/documentation/3.0/manual/api/reference/item/object)のオブジェクトの説明にとり得る値も含めて記載されています。

* ホスト「DB Server001」で、アイテムキーに「cpu」または「memory」を含むものを検索

```mysql
SELECT
  name,
  key_,
  status
FROM
  items
WHERE
  hostid = (select hostid from hosts where host = 'DB Server001')
  and (key_ like '%cpu%' or key_ like '%memory%')
  and (flags = '0' or flags = '4')
ORDER BY key_;

+------------------------------------------+-------------------------------+--------+
| name                                     | key_                          | status |
+------------------------------------------+-------------------------------+--------+
| Interrupts per second                    | system.cpu.intr               |      0 |
| Processor load (15 min average per core) | system.cpu.load[percpu,avg15] |      0 |
| Processor load (1 min average per core)  | system.cpu.load[percpu,avg1]  |      0 |
| Processor load (5 min average per core)  | system.cpu.load[percpu,avg5]  |      0 |
| Context switches per second              | system.cpu.switches           |      0 |
| CPU $2 time                              | system.cpu.util[,idle]        |      0 |
| CPU $2 time                              | system.cpu.util[,interrupt]   |      0 |
| CPU $2 time                              | system.cpu.util[,iowait]      |      0 |
| CPU $2 time                              | system.cpu.util[,nice]        |      0 |
| CPU $2 time                              | system.cpu.util[,softirq]     |      0 |
| CPU $2 time                              | system.cpu.util[,steal]       |      0 |
| CPU $2 time                              | system.cpu.util[,system]      |      0 |
| CPU $2 time                              | system.cpu.util[,user]        |      0 |
| Available memory                         | vm.memory.size[available]     |      0 |
| Total memory                             | vm.memory.size[total]         |      0 |
+------------------------------------------+-------------------------------+--------+
```
ところで上記の例ではflagsの値は「0と4だけ」を抽出しています。
これはItemsテーブルにはローレベルディスカバリ(LLD)の「ディスカバリの検出アイテム」と「ディスカバリのプロトアイテム」も含まれているからです。

```mysql
SELECT
  name,
  key_,
  status,
  flags
FROM
  items
WHERE
  hostid = (select hostid from hosts where host = 'DB Server001')
  and  key_ like 'net.if%'
ORDER BY flags;

+--------------------------------+-------------------------+--------+-------+
| name                           | key_                    | status | flags |
+--------------------------------+-------------------------+--------+-------+
| Network interface discovery    | net.if.discovery        |      0 |     1 |★ディスカバリの検出アイテム
| Outgoing network traffic on $1 | net.if.out[{#IFNAME}]   |      0 |     2 |★ディスカバリのプロトアイテム
| Incoming network traffic on $1 | net.if.in[{#IFNAME}]    |      0 |     2 |★ディスカバリのプロトアイテム
| Incoming network traffic on $1 | net.if.in[eno16777984]  |      0 |     4 | ディスカバリによって検出されたアイテム
| Outgoing network traffic on $1 | net.if.out[eno16777984] |      0 |     4 | ディスカバリによって検出されたアイテム
+--------------------------------+-------------------------+--------+-------+
```


### 条件に一致するトリガーだけ検索
* ver2.4まではグループとホストでしか絞り込むことができませんでしたが、ver3.0ではいくつかフィルタ項目が追加されました。しかし、トリガー名から検索することは依然できないためSQLでやってみます。

![image](https://qiita-image-store.s3.amazonaws.com/0/54952/7cb0162c-1c02-b052-994e-f9d08584ccb3.png)

* トリガー名に「Zabbix」または「Disk」を含み、かつトリガーステータスが「有効」のものを検索

```mysql
SELECT
  CASE 
    WHEN t.priority LIKE '0' THEN '未分類'
    WHEN t.priority LIKE '1' THEN '情報'
    WHEN t.priority LIKE '2' THEN '警告'
    WHEN t.priority LIKE '3' THEN '軽度の障害'
    WHEN t.priority LIKE '4' THEN '重度の障害'
    WHEN t.priority LIKE '5' THEN '致命的な障害'
  END "priority",
  h.host,
  t.description,
  t.expression,
  CASE
    WHEN t.status = '0' THEN '有効'
    WHEN t.status = '1' THEN '無効'
  END "status",
  t.error
FROM triggers t
  inner join functions f on t.triggerid = f.triggerid
  inner join items i on f.itemid = i.itemid
  inner join hosts h on i.hostid = h.hostid
WHERE
     t.description Like '%Zabbix%' 
  or t.description Like '%Disk%' 
  and t.status = '0'
ORDER BY t.priority;

+-----------------+----------------------------+----------------------------------------------------------+--------------------------------------------------------------------------+--------+------------------------------------------+
| priority        | host                       | description                                              | expression                                                               | status | error                                    |
+-----------------+----------------------------+----------------------------------------------------------+--------------------------------------------------------------------------+--------+------------------------------------------+
| 警告            | Zabbix server              | Disk I/O is overloaded on {HOST.NAME}                    | {13081}>20                                                               | 有効   |                                          |
| 軽度の障害      | Template App Zabbix Server | Zabbix ipmi poller processes more than 75% busy          | ({TRIGGER.VALUE}=0 and {13117}>75) or ({TRIGGER.VALUE}=1 and {13117}>65) | 有効   |                                          |
| 軽度の障害      | Template App Zabbix Proxy  | Zabbix unreachable poller processes more than 75% busy   | ({TRIGGER.VALUE}=0 and {13151}>75) or ({TRIGGER.VALUE}=1 and             | 有効   |                                          |

```

トリガー名やトリガーキーに使われているマクロやアイテムIDはプログラム側で展開処理しているため、SQLで直接取り出しただけではUIから見た時と同じになりません。APIを使うと展開処理を行ってくれますが、それは後日別のエントリとして投稿したいと思います。


### 正規表現の一覧を検索
* ZabbixUIの正規表現の一覧画面では、「区切り文字」と「大文字小文字の区別」の設定は表示されません。そのため、この二つに関しては一つずつ詳細画面まで移動しないと内容が分からず不便なため、一度に確認できるようにしてみます。

```mysql
SELECT
  r.name,
  e.expression,
  CASE 
    WHEN e.expression_type LIKE '0' THEN '文字列が含まれる'
    WHEN e.expression_type LIKE '1' THEN 'いずれかの文字列が含まれる (区切り文字= , )'
    WHEN e.expression_type LIKE '2' THEN '文字列が含まれない'
    WHEN e.expression_type LIKE '3' THEN '結果が真'
    WHEN e.expression_type LIKE '4' THEN '結果が偽'
  END "条件式の形式",
  e.exp_delimiter "区切り文字",
  CASE 
    WHEN e.case_sensitive LIKE '0' THEN 'しない'
    WHEN e.case_sensitive LIKE '1' THEN 'する'
  END "大文字小文字の区別"
FROM regexps r
  inner join expressions e on r.regexpid = e.regexpid
ORDER BY r.name;

+------------------------------------+---------------------------------------------------------------------------------------+--------------------+-----------------+-----------------------------+
| name                               | expression                                                                            | 条件式の形式       | 区切り文字      | 大文字小文字の区別          |
+------------------------------------+---------------------------------------------------------------------------------------+--------------------+-----------------+-----------------------------+
| File systems for discovery         | ^(btrfs|ext2|ext3|ext4|jfs|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|refs|ntfs|fat32|zfs)$ | 結果が真           | ,               | しない                      |
| Network interfaces for discovery   | ^Software Loopback Interface                                                          | 結果が偽           | ,               | する                        |
| Network interfaces for discovery   | ^lo$                                                                                  | 結果が偽           | ,               | する                        |
| Storage devices for SNMP discovery | ^(Physical memory|Virtual memory|Memory buffers|Cached memory|Swap space)$            | 結果が偽           | ,               | する                        |
```



### グローバルマクロを全検索
```mysql
select * from globalmacro;

+---------------+-------------------+--------+
| globalmacroid | macro             | value  |
+---------------+-------------------+--------+
|             2 | {$SNMP_COMMUNITY} | public |
```

### テンプレートマクロを全検索
* テンプレートに設定されたマクロはテンプレート毎に設定箇所が分かれているため、全体を一遍に把握することができません。テンプレートを跨いで一括検索できるようにしてみます。

```mysql
SELECT
  hs.host,
  hm.macro,
  hm.value
FROM hostmacro hm
  inner join hosts hs on hm.hostid = hs.hostid
WHERE
  hs.status = '3';

+--------------------+-------------+-------+
| host               | macro       | value |
+--------------------+-------------+-------+
| Template OS Linux  | {$CPU_LOAD} | 2     |
| Template OS Linux  | {$MEM_SIZE} | 2000  |
| Template ICMP Ping | {$TIMEOUT}  | 30    |

hs.status
  0 - monitored host;
  1 - unmonitored host.
  3 - template host.　←APIマニュアルには記載されていません
```


### ホストマクロを全検索
* テンプレートマクロと同様に画面が分かれているホストマクロの設定も、ホストを跨いで一括検索します。

```mysql
SELECT
  hs.host,
  hm.macro,
  hm.value
FROM hostmacro hm
  inner join hosts hs on hm.hostid = hs.hostid
WHERE
  hs.status = '0' or hs.status = '1'; 

+---------------+-------------+-------+
| host          | macro       | value |
+---------------+-------------+-------+
| DB Server001  | {$CPU_LOAD} | 10    |
| DB Server001  | {$MEM_SIZE} | 3000  |
| Web Server001 | {$CPU_LOAD} | 20    |
| Web Server001 | {$MEM_SIZE} | 5000  |

hs.status
  0 - monitored host;
  1 - unmonitored host.
  3 - template host.　←APIマニュアルには記載されていません
```

### ホストインターフェースを全検索
* ホストのデフォルトになっているインターフェースのアドレスはホスト一覧の画面に表示されますが、複数のインターフェースが設定されている場合、ホスト各々の詳細設定画面を確認する必要があります。全体を一度に確認できるようインターフェース情報のみ全検索してみます。

```mysql
SELECT
  h.host,
  h.name,
  CASE
    WHEN i.type LIKE '1' THEN 'ZabbixAgent'
    WHEN i.type LIKE '2' THEN 'SNMP'
    WHEN i.type LIKE '3' THEN 'IPMI'
    WHEN i.type LIKE '4' THEN 'JMX'
  END "interface type",
  i.ip,
  i.dns,
  CASE
    WHEN i.useip LIKE '0' THEN 'DNS'
    WHEN i.useip LIKE '1' THEN 'IP'
  END "接続方法",
  i.port "ポート",
  CASE
    WHEN i.main LIKE '0' THEN 'not default'
    WHEN i.main LIKE '1' THEN 'default'
  END "標準"
FROM hosts h
  inner join interface i on i.hostid = h.hostid
ORDER BY h.host , i.type;


+----------------+----------------+----------------+---------------+-----+--------------+-----------+-------------+
| host           | name           | interface type | ip            | dns | 接続方法     | ポート    | 標準        |
+----------------+----------------+----------------+---------------+-----+--------------+-----------+-------------+
| DB Server001   | DBサーバ       | ZabbixAgent    | 192.168.0.1   |     | IP           | 10050     | default     |
| DB Server001   | DBサーバ       | ZabbixAgent    | 192.168.0.100 |     | IP           | 10050     | not default |
| DB Server001   | DBサーバ       | SNMP           | 192.168.0.1   |     | IP           | 161       | default     |
| DB Server001   | DBサーバ       | IPMI           | 192.168.0.1   |     | IP           | 623       | default     |
| DB Server002   | DB Server002   | ZabbixAgent    | 192.168.0.2   |     | IP           | 10050     | default     |
| Web Server001  | Web Server001  | ZabbixAgent    | 192.168.0.3   |     | IP           | 10050     | default     |
```

### イベント履歴情報を検索

以前投稿した[Zabbix イベント履歴情報の一括エクスポート](http://qiita.com/usiusi360/items/e3d8b073a4e9f0d58217)を参考にしてください。

# さいごに

UIでは出来なくともSQLを使うと複雑な条件でも検索でき、本当に必要としている情報セットに近づけることが出来るようになります。UIを補完するようにうまく活用頂けたらと思います。