ZabbixAPI投げて障害情報をSlackに投げるpythonプログラム書いた

# Zabbixサーバが乱立してしまった
諸事情によりZabbixサーバが数台立っており、それぞれ管理しないといけない事態になった。
日々のチェックが非常に面倒だったのでAPI使って一発で情報が受け取れるようなモノを作った。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/150591/57e82b89-5614-80f1-e8cf-a729197bbad1.png)
> 優先度に応じて赤-黄-緑に色分けされる。見やすい…！
> 黒塗r###この先は文字が掠れている###

## 前提
 * python3
 * SlackAPI使える

## やったこと

### ZabbixAPI叩く
[Zabbix API の仕組みを理解する](http://qiita.com/Trickey/items/d51d93d525443baa496f)
この記事のZabbixAPIクラスを使って各ZabbixのAPIを叩く。
> 先人のコードは偉大である。　ありがとうございます…！

trigger.getで `"filter": {"status": 0,"value": 1}`を指定することで現在起こっている障害だけを取得できる。
更に`"selectHosts": ["name"]`を指定することでホスト名も取得。

```py3
# http://qiita.com/Trickey/items/d51d93d525443baa496f
# のZabbixAPIクラスを利用。
 zabapi= ZabbixApi(url,"Admin","zabbix")
 zabapi.request('trigger.get', {
        "output": ["triggerid","description","priority","lastchange"],
        "selectHosts": ["name"],
        "monitored": "true",
        "filter": {
        "status": 0,
        "value": 1
        }})
    if 'result' in response:
        for alert in response['result']:
            if int(alert['lastchange']) < time.time()-(31*24*60*60):
                # 一ヶ月以上前のアラートを無視
                continue
            # 加工してリストに追加
            datetime_s = str(datetime.fromtimestamp(float(alert['lastchange'])))  # UNIXTIMEなので変換
            hostname = alert['hosts'][0]['name']                                  # ホスト名はlistの下にdictがぶら下がっているので[0]を噛ませる
            description = alert['description'].replace('{HOST.NAME}', hostname)
            uri = "http://{0}/".format(url)
            ret.append({"description": description, "hostname": hostname, "time":datetime_s, "priority":alert['priority'],"url":uri})
    return ret
```

### 優先度別に分類したかったのでソート関数自作。

```py3
from functools import cmp_to_key

## カスタムソート機構
def cmp(a,b):
    a = int(a)
    b = int(b)
    return (a>b)-(a<b)

def cmp_len(s1, s2):
    # 優先度順、同じならホスト名の頭一文字コード順
    ret = cmp(s1['priority'], s2['priority'])
    if ret == 0:
        return cmp(s1['hostname'].encode('utf-8')[0], s2['hostname'].encode('utf-8')[0])
    else:
        return ret

def main():
    <略>
    # 優先度順にソート
    errlist = sorted(errlist, key=cmp_to_key(cmp_len), reverse=True)
```

### SlackのAttachment機能を使って見やすくする。
[Attaching content and links to messages](https://api.slack.com/docs/message-attachments)
jsonで投げるだけで冒頭の画像みたいな表示になってくれる。
> dict形式で返す関数なので使う時はパースをお忘れなく

```py3
def createAttachment(hostname,description,time_s,priority,uri=""):
    """ Slackに投げるAttachmentを作成する """
    # 優先度別で色を付ける
    colorlist = {
        '5':"#FF2222",
        '4':"#FF9922",
        '3':"#FFFF22",
        '2':"#CCFF22",
        '1':"#22FF22"
    }
    color = colorlist[priority]

    # https://api.slack.com/docs/message-attachments
    return {
        "color": color,
        "author_name": hostname,
        "author_link": uri,
        "text": description,
        "fields": [
            {
                "title": "time",
                "value": time_s,
                "short": True
            },
            {
                "title": "Priority",
                "value": priority,
                "short": True
            }
        ]
    }
```

### 後は集計してSlackAPIへポン。

```py3
def main():
    # 調査するZabbixのURLリスト
    serverlist = [  "url/to/zabbix1",
                    "url/to/zabbix2"
                 ]
    errlist = []

    # 障害をリストして優先度順にソート
    for srv in serverlist:
        errlist.extend(getErrorSummary(srv))
    errlist = sorted(errlist, key=cmp_to_key(cmp_len), reverse=True)

    # Attachment作成ついでに優先度別に集計
    att = []
    priority_count = [0,0,0,0,0]
    for err in errlist:
        priority_count[int(err["priority"])-1] += 1
        att.append(createAttachment(err["hostname"],err["description"],err["time"],err["priority"],err["url"]))

    # メッセージ作成
    mes = "いまのZabbixアラートだよ！\n Summary : "
    for pcidx in range(4, -1, -1):
        if priority_count[pcidx] > 0:
            mes = mes + (str(pcidx+1)+':'+str(priority_count[pcidx])+' ')

    # SlackへPOST (自作関数)
    post_message(username="ZabbixSummary",message=mes,attachments=att)
```

### 定期的に確認する
linux機に突っ込んでcronに登録するだけ。

## おしまい。
Tips的に書いているので全コードは乗っけてません。
動いているコードから抜粋したりコメント追加したりして掲載しているので、
利用する際は各自で不足分補ってください(丸投げ)

# 最後に
Zabbixが乱立するなんてことになる前に一元管理ができないか計画をしよう！