Linux(yum/apt)のパッケージアップデートを検知する

# やりたいこと

* 稼働し続ける異なる構成のLinux環境でパッケージ管理ソフト(apt/yum)経由でアップデートされたパッケージ数を確認したい
    * 例えばDebian/Ubuntu 12.04LTS/Ubuntu 14.04LTS/CentOS6/Fedora 20を全部「飼ってる」とする
* いっそ一括でアップグレードもしたい
* Zabbixで監視したい

「どいつもこいつも設定が微妙に違う」という前提があります。
例えば1000台であっても、同じ構成だったらアップデートパッケージ数は同じだし配布サーバも立てるはずですので、こういうツールは要らないはずです。話題のDockerなインフラともあまりそりがありませんし、vagrantで一時的に立ち上げるものとも関係がありません。

自分で5台くらい環境を持ってるけど、Debian/Ubuntu/CentOSでバラバラだなぁ、という時に使います。

単にそういうチェックをOS跨いで管理するソフトが思いつかなかったのです。

# やったこと

https://github.com/dmiyakawa/check_linux_updates

## check_updates.py : 自分のターミナルから向こう側を観測

これはFabric(ssh)経由で各ホストのアップデートを見に行く実装です。デフォルトでは並列でチェックしに行きます。

```
例 (snip部分は本当はFQDN相当だったもの):
$ check_updates.py
hansode.(snip)     :   0(0) (REBOOT-REQUIRED)
gobusode.(snip)    :  40(0)
shichibusode.(snip):   1(0)
mowa-net.jp        :   3(2)
centos64.(snip)    :   2(?) (REBOOT_REQUIRED)
```

gobusodeはDebian sidです。放置しとくとすぐこうなります。
ただもうちょっと重要なのはmowa-net.jpで、セキュリティアップデート(括弧の中)が2あるのでこれはアップデートしたほうがよいです。
もちろんDebianには自動でセキュリティアップデートを当てる仕組みがあるので、これはそれを使っていない罰です。

```
$ check_updates.py --upgrade mowa-net
```

アップグレードされます。この場合1ホストでシリアルに実行されるのでパスワード聞かれても大丈夫です。

ホスト名はいろいろ変えてますが、大体そういう感じで動きます。
CentOS混ざってもいけます(上のcentos64が例)が、実装をサボっててCentOS上でセキュリティアップデートを見てません。
なので"?"です。(後述するツールでは見てたりします。あれー)

Paramiko(ssh接続)周りの自分側実装が適当すぎで、パラレルで走るときには公開鍵認証で入れないとパスワードプロンプト時に落ちます。
sudo必要なときにパスワードプロンプトでてもやっぱり死にます。

「自分所有のサーバ群」等のグループを設定できます。
以下の例では mine グループのホストを順番にたどって、インタラクティブにアップデートとリブートの決断を行ないます。
(パラレル実行するとFabricがインタラクティブなYes/Noを許してくれない)

```
$ check_updates.py --serial --ask-upgrade mine
```

実行する側がPython2.7であることを仮定してます。

```
$ check_updates.py -h
usage: check_updates.py [-h] [-s] [-q] [-n] [-v] [--ask-upgrade]
                        [--auto-upgrade] [--dist-upgrade]
                        [--auto-upgrade-restart] [--refresh] [--show-packages]
                        [--sanity-check]
                        [HOST [HOST ...]]

Checks if remote hosts need update or not.

positional arguments:
  HOST                  Host names or host groups. If not specified, default
                        hosts configuration will be used. This may allow
                        special command "all" "list", "groups" (=
                        "list_groups").

optional arguments:
  -h, --help            show this help message and exit
  -s, --serial          Executes check in serial manner
  -q, --quiet           Suppress unnecessary output.
  -n, --nonregistered   Allow host names that are not registered
  -v, --verbose         Show verbose outputs, including Fabric ones.
  --ask-upgrade         Asks if upgrade should be done when appropriate. Only
                        effective when --serial (-s) option is set
  --auto-upgrade        Requests hosts to upgrade itself when necessary.
  --dist-upgrade        Use "dist-upgrade" instead of "upgrade". Only
                        effective with debian-like systems. Meaningless on
                        redhat-like systems.
  --auto-upgrade-restart
                        Requests hosts to upgrade itself and restart when
                        upgrade is finished. With this option restart will be
                        executed regardless of necessity (with/without
                        "Reboot-Required" status). This will execute "dist-
                        upgrade" on debian(-like) OSes, not "upgrade.
  --refresh             Run "apt-get update" on debian-like systems.
  --show-packages       This will show names of packages to be upgraded.
  --sanity-check        First executes sanity check toward each host serially
                        (not in parallel). If some hosts show prompt in the
                        check phase, this command will abort itself
                        immediately. Might be useful for "debugging" new
                        hosts. If you are considering --serial option, This
                        "check" would be meaningless.
```

## check_update_local.py : 向こう側で実行

上のスクリプトだと、ssh接続しないといけないし認証認可の処理が微妙な上に
Zabbixで監視する上では不都合ありまくりです。


各ホストにスクリプト(Python)を配置してでもZabbix Agentから監視できるものを作ってみます。

```
$ check_update_local.py -h
usage: check_update_local.py [-h] [--log LOG] [-d] [-s] [-r] [-q]

Check if update is available. Returns num of updates

optional arguments:
  -h, --help            show this help message and exit
  --log LOG             Set Python log level. e.g. DEBUG, INFO, WARN
  -d, --debug           Shortcut for --log DEBUG
  -s, --security-updates
                        Instead of showing num of updates, show num of
                        security updates.
  -r, --reboot_required
                        Instead of showing num of updates, return 1 if reboot
                        is required
  -q, --quiet           Logging will be disabled entirely.
$ check_update_local.py 
0
$ check_update_local.py -s
0
$ check_update_local.py -r
1
```

Debianでは```apt-check```コマンドを使うためupdate-notifier-commonパッケージが必要です。
確かですがUbuntu系だと最初から入っている感じですが、詳細不明です。

ここまでは比較的楽だったんですが、
油断してCentOS 6にもこのスクリプトを対応させようとしたら
CentOS 6のデフォルトPythonが2.6 (2.7じゃなく)でびびりました。
いろいろ変なハックいれまして、pipでargparse入ってれば動くレベルまでにはしましたが、
もっとクリーンな方法を期待したいです。

残念ですがPython3対応は入ってません。14.04LTS的ではないかもしれません。

Zabbixで使う方法はREADME.mdに書いてあります。
apt-checkもyumも本当はAgentから叩くのは不安な程度には重いので、
多くの監視対象で使うと、Agentを叩くサーバ側プロセスがいっぱいいっぱいになるかもしれません。
さっき作ったので検証できてません。

# 欲しいもの

これよりましなツール

# 追記

 * localの方ですが、Zabbixで監視する際にはアクティブ監視を用いたしたほうが良いようです。