アクション設定したスクリプト実行が失敗

いつもお世話になってます。
ZETTONと申します。

アクション設定したスクリプトが失敗する現象が発生しており、
回避策が有りましたらご教授ください。

<現象>
(1)アクションからメール送信スクリプトを実行する際に引き渡す情報量が
大量になるとアクションに設定したメール送信スクリプトの起動が失敗する。
※運用要件でメール本文のカスタマイズが必要となるため、
独自のメール送信スクリプトを利用しています。

(2)Zabbixのイベント履歴ではアクションは正常と表示されている為、
メール送信の失敗が認識出来ない。

<原因>
zabbix_server.logで確認するとメール送信スクリプトをキックする際にエラーが発生しています。
メール送信スクリプトへ引き渡すデータ量が多すぎる場合、
途中でカットされてしまう為に文末クォーティングが欠落し、
書式エラーで失敗していると推測されます。
※ログ出力レベルは最高レベルの4に設定

■zabbix_server.log抜粋
-------------------------------------------------------------
29086:20111219:185113.630 zbx_popen(): executing script
30670:20111219:185113.630 End of zbx_popen():6
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 21: syntax error: unexpected end of file
30670:20111219:185113.631 In zbx_waitpid()
30670:20111219:185113.631 zbx_waitpid() exited, status:2
30670:20111219:185113.631 End of zbx_waitpid():29086
30670:20111219:185113.631 mail_sender.pl output:
-------------------------------------------------------------
※上記ログにはメール送信スクリプトをキックする際に引き渡す情報(大量のテキスト文字)が
実際には出力されていますが省略しています。
※メール送信スクリプトには、検知アイテムの現在値と過去値5世代分を引き渡している為、
特にログ監視では情報が多くなっています。

<環境>
■Zabbixサーバ
【OS】Red Hat Enterprise Linux Server release 5.5 (Tikanga)
【Zabbixバージョン】v1.9.6

■Zabbixエージェント
【OS】Red Hat Enterprise Linux ES release 4 (Nahant Update 6)
【Zabbixバージョン】v1.9.6

コメント表示オプション

お好みのコメント表示方法を選び「設定の保存」をクリックすると変更が反映されます。
ユーザー TNK の写真

ソースを確認してみましたが、

 src/zabbix_server/alerter/alerter.c

内のコマンド実行用の文字列を作成するところに手を入れないと
対応できなさそうです。

スクリプトの実行でメール送信をされているということでしたの
で、関数execute_action()の

 else if (MEDIA_TYPE_EXEC == mediatype->type)

条件内のfull_pathを生成するところで、MAX_STRING_LENの長さ以
下でクォーティングなどでも問題にならないような文字列を生成
するようにできればよいと思います。

マルチバイト文字列が含まれているような場合には、単純に最後
の文字に閉じるためのクォートを追加するような対応では結局エ
ラーが回避できないと思われますので注意が必要です。

現時点ではここまでしか調べられていません。

ユーザー ZETTON の写真

TNKさん。調査頂きありがとうございます。

根本解決にはソース改修が必要との事で簡単には解決できそうも無いですね。

理想は上限値を超えたものは自動的に切り捨てられ、
コマンドが失敗しない事とアクションの失敗を
システム上で検知出来ればと思います。
※ZABBIXの画面上ではアクションが正常なので認知できない

それでは以下の対策を実施してみます。
問題あればアドバイスをお願いします。

対策1:文字列の削減
アドバイスの通り、MAX_STRING_LENの長さ以下に文字列生成を行ってみます。
しかしログ監視では不定形メッセージを取得するので、
MAX_STRING_LENを超える懸念を対策2で対応。

対策2:MAX_STRING_LEN値を拡張
文字数超過の予防としてalerter.cソース内の
full_path[MAX_STRING_LEN]をfull_path[4096]に変更。
又は、MAX_STRING_LENを定義している、
include/common.hの値を4096に変更。

よろしくお願いします。

ユーザー kodai の写真

関連しそうなチケットがいくつか登録されていました。

https://support.zabbix.com/browse/ZBX-4527
https://support.zabbix.com/browse/ZBX-1298

ユーザー ZETTON の写真

kodaiさん。
TNKさん。

ご返答が遅くなりました。

リンク先でも当方と同様のエラーが発生しているようですが、
まだ、根本解決されていないようですね。

解決策としてTNKさんにご教授頂いた対策の実施と、
データベースから直接取得する方法を検証しました。
結果、双方とも当方の要件をクリア可能でした。
アドバイスありがとうございました。

<検証>
■実施内容
文字数超過の予防としてalerter.cソース内の
full_path[MAX_STRING_LEN]をfull_path[512000]に変更。

■結果
スクリプトに引き渡される上限値が増えました。
ただし65Kバイト以上のデータは切り捨てられて
スクリプトに渡されてしまいます。
何かの制限と思いますが調べていません。

<検証2>
■実施内容
SQLで”直近データ”、”過去データ”を直接取得する。
過去データは5件分。

■結果
取得可能でした。

これによりZabbixからメールスクリプトに渡されるデータ量を
自分で制御可能となります。
MAX_STRING_LENは制限も関係ありません。

ただし今後のzabbixのバージョンアップで、
テーブル構成に変更があると利用不可になる可能性もあります。

■参考
参考として実現方法を記載します。

【前提】
アクションのデフォルト/リカバリメッセージのフォームに
事象を検知した「トリガーID」が埋め込まれるようにマクロを記載しておく。
記載が必要なマクロ:{TRIGGER.KEY}

スクリプトに本文が渡された際に上記「トリガーID」を抽出し、
以下のSQLの対応した位置に抽出した値を埋め込む。

【スクリプト内で実行するSQL】
(1)事象検知したtriggeridよりトリガー条件式を取得。
"取得したトリガーID"
SELECT expression FROM triggers WHERE triggerid = "取得したトリガーID";

(2)トリガー条件式の最初の{}に入ったファンクションIDを抽出。
⇒使用しているスクリプトの関数などで抽出。

(3)(2)で取得したファンクションIDでアイテム情報を取得。
SELECT itemid, lastclock, valuemapid, units FROM items WHERE itemid = (SELECT itemid FROM functions WHERE functionid = "上記(2)で取得したID");

(4)(3)で取得したアイテムID、最終更新時間から最終取得値から6件分の格納データを抽出。

(SELECT clock, value FROM history WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_log WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_str WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_str_sync WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_sync WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_text WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_uint WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock")
UNION
(SELECT clock, value FROM history_uint_sync WHERE itemid = "(3)で取得したitemid" AND clock <= "(3)で取得したlastclock") ORDER BY clock DESC LIMIT 6;

(5)(3)で取得したvaluemapidがNULLじゃなければ、(4)で取得した値分、以下のSQLを実行し、(4)の取得値と紐づける。
SELECT newvalue FROM mappings WHERE valuemapid = "(3)で取得したvaluemapid" AND value = "(4)で取得したvalue";

※上記は(4)を実行した時点で値の取得は完了していますが、マッピング機能を使用していて、
メール文の見栄えを良くしたい場合などは(5)を実行する。

以上

ユーザー TNK の写真

情報をご提供頂きありがとうございます。

私も参考にさせて頂きます。

ユーザー kodai の写真

情報ありがとうございます!

<検証>
■実施内容
文字数超過の予防としてalerter.cソース内の
full_path[MAX_STRING_LEN]をfull_path[512000]に変更。

■結果
スクリプトに引き渡される上限値が増えました。
ただし65Kバイト以上のデータは切り捨てられて
スクリプトに渡されてしまいます。
何かの制限と思いますが調べていません。

すぐ下のzbx_execute()の中でbuf_sizeが65536(MAX_BUFFER_LENで定義)されているので、ここで削られているんじゃないかと思います。

使われているDBのスキーマはそれほど変更があるところではないと思います。