This is a machine translation based on the English version of the article. It might or might not have already been subject to text preparation. If you find errors, please file a GitHub issue that states the paragraph that has to be improved. |
1. 導入
Checkmk には、考えられるあらゆるハードウェアおよびソフトウェアに対応した 2000 以上の既製のチェックプラグインが含まれています。 これらのプラグインは Checkmk チームによって管理されており、毎週新しいプラグインが追加されています。 さらに、Checkmk Exchangeには、ユーザーによって提供されたプラグインも追加されています。
しかし、お客様にとって重要なデバイス、アプリケーション、あるいは特定のメトリックが、既存のプラグインではまだ対応されていない場合もあります。これは、そのデバイスやアプリケーション、メトリックがお客様の組織で独自に開発されたものであり、他の誰もそれを持っていないためです。 Checkmk の拡張機能の開発入門の記事では、ご利用いただけるオプションについてご紹介しています。
この記事では、Checkmk エージェント用の実際のチェックプラグインの開発方法、およびそれに伴うすべてについて説明します。 SNMP ベースのチェックプラグインについては、別の記事があります。
エージェントベースのチェックプラグインを開発する場合、通常、2 つのプラグインが必要です。 データを提供する、監視対象のホスト上のエージェントプラグインと、このデータを評価する Checkmk サーバー上のチェックプラグインです。 両者は一緒に作成し、相互に最適化する必要があります。 そうして初めて、その後スムーズに動作するようになります。 |
1.1. チェック API のドキュメント
Checkmk バージョン2.0.0 以降、チェックプラグインをプログラミングするためのCheck APIが新たに開発されました。 Checkmk バージョン 2.4.0 では、Check API V2 が最新バージョンです。 この記事では、プラグインのプログラミングに Check API バージョン 2 を使用する方法について説明します。 Check API バージョン 2 への移行については、この記事の最後にある「移行」の章をご覧ください。
Check API のドキュメントは、Checkmk ユーザーインターフェースからいつでもアクセスできます:Help > Developer resources > Plugin API references 。 新しいブラウザウィンドウで、左側のナビゲーションバーから「Agent based ("Check API") > Version 2 」を選択してください。

1.2. 事前準備
チェックプラグインのプログラミングに興味のある方は、以下のものが必要です。
Python プログラミング言語の知識。
Checkmk の使用経験、特にエージェントおよびチェックに関する知識。
コマンドラインからの Linux の使用経験。
2. エージェントプラグインの記述
Checkmk のプラグインのプログラミングに興味をお持ちの方は、すでに Checkmk サーバーを設定されている可能性が高いと思います。 その場合は、おそらく Checkmk サーバー自体をホストとして監視されているでしょう。
ここでは、Checkmk サーバーと監視対象のホストが同一である場合に便利なシナリオを作成します。 これにより、ホストからのライブステータスクエリを使用して、Checkmk サーバーが提供するホストグループに関する情報を取得することができます。
この例では、複数の拠点を持つ組織を想定しています。
各拠点は、Checkmk ではホストグループとして表されます。
各拠点には、独自のサービスチームがあります。
問題が発生した場合に正しいサービスチームに確実に通知できるように、各ホストは場所、つまりホストグループにも割り当てられる必要があります。 この例の目的は、ホストグループを割り当てることを忘れたホストがないことを確認するためのチェックを設定することです。
このプロセスは 2 つのステップで構成されています。
ホストから監視に関する情報を読み込みます。 この章では、この手順について説明します。
このデータを評価するチェックプラグインを Checkmk サイトに作成します。 これについては、次の章で説明します。
では、始めましょう …
2.1. 情報の取得とフィルタリング
プラグインプログラムを作成する前に、まず調査を行う必要があります。 つまり、監視に必要な情報を取得する方法を見つける必要があります。
この例では、Checkmk サーバーがホストでもあるという事実を利用します。 つまり、最初は、ライブステータス、つまり Checkmk が監視対象のホストおよびサービスについて、揮発性メモリにテーブル形式で保持しているデータを取得するだけで十分です。
サイトユーザーとしてログインし、次のコマンドでホストグループに関する情報を照会します。
OMD[mysite]:~$ lq "GET hostgroups"
action_url;alias;members;members_with_state;name;notes;notes_url;num_hosts;num_hosts_down;num_hosts_handled_problems;num_hosts_pending;num_hosts_unhandled_problems;num_hosts_unreach;num_hosts_up;num_services;num_services_crit;num_services_handled_problems;num_services_hard_crit;num_services_hard_ok;num_services_hard_unknown;num_services_hard_warn;num_services_ok;num_services_pending;num_services_unhandled_problems;num_services_unknown;num_services_warn;worst_host_state;worst_service_hard_state;worst_service_state
;Hamburg;myhost11,myhost22,myhost33;myhost11|0|1,myhost22|0|1,myhost33|0|1;Hamburg;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;Munich;myhost1,myhost2,myhost3;myhost1|0|1,myhost2|0|1,myhost3|0|1;Munich;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;check_mk;localhost;localhost|0|1;check_mk;;;1;0;0;0;0;0;1;66;0;0;0;4;0;1;4;61;1;0;1;0;1;1出力の最初の行には、クエリしたhostgroups テーブルの列名が含まれます。
セミコロンが区切り文字として機能します。
以降の行には、すべての列の内容がセミコロンで区切られて表示されます。
この小さな例でも、出力はすでにかなり複雑で、この例には関係のない情報も含まれています。
一般的には、データの解釈は Checkmk に任せるべきです。
ただし、実際に必要なデータだけが転送されるように、ホストで事前にフィルタリングを行うと、転送するデータ量を減らすことができます。
この場合、クエリを、関連する列 (Columns)、ホストグループの名前 (name)、およびそれらのグループ内のホスト (members) に制限します。
OMD[mysite]:~$ lq "GET hostgroups\nColumns: name members"
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhostライブステータスインターフェースは、すべてのコマンドとヘッダーが別々の行で送信されることを想定しています。
必要な改行は、\n で示されています。
この例では、現在 3 つのホストグループがあります。2 つは場所用、1 つはcheck_mk グループ用です。
これには、localhost というホストが含まれています。
check_mk ホストグループは、ホストグループ内の特別な機能です。
これは、ご自身で作成したものではありません。
また、このグループにホストをアクティブに追加することもできません。
では、このホストグループはどこから来たのでしょうか?
Checkmk では、定義上、すべてのホストはグループに属している必要があるため、ユーザーがグループに特に割り当てていないホストは、デフォルトで「特別な」check_mk グループに割り当てられます。
ホストを独自のホストグループのいずれかに割り当てると、そのホストは Checkmk によってcheck_mk グループから削除されます。
また、ホストをcheck_mk ホストグループに再割り当てる方法はありません。
この例では、check_mk グループのまさにこれらのプロパティを使用します。
各ホストは場所に割り当てる必要があるため、ホストグループcheck_mk は空である必要があります。
空でない場合は、その中のホストをホストグループ、つまり適切な場所に割り当てる必要があります。
2.2. コマンドをエージェントに組み込む
これまで、サイトユーザーは、lq コマンドを使用して情報を表示していました。
これは、データを理解するのに役立ちます。
しかし、Checkmk サーバーからこのデータを取得するには、新しいコマンドを監視対象ホストの Checkmk エージェントに追加する必要があります。
理論的には、/usr/bin/check_mk_agent ファイルで Checkmk エージェントを直接編集して、この部分を含めることもできます。
ただし、この方法では、エージェントソフトウェアが更新されると、このファイルが上書きされるため、新しいコマンドが再び消えてしまうという欠点があります。
そのため、エージェントプラグインを作成することをお勧めします。
これに必要なのは、コマンドを含む実行ファイルで、/usr/lib/check_mk_agent/plugins/ ディレクトリに保存されているものです。
さらに、もう 1 つ重要な点があります。 データは単に出力するだけではいけません。 セクションヘッダーも必要です。 これは、新しいエージェントプラグインの名前を含む、特別な形式の行です。 このセクションヘッダーにより、Checkmk は、新しいエージェントプラグインからのデータがどこから始まり、前のプラグインからのデータがどこで終わるかを後で認識することができます。 エージェントプラグイン、セクションヘッダー、およびチェックプラグインに同じ名前を付けると最も簡単です。ただし、これは必須ではありません。
したがって、まず、新しいチェックプラグインに意味のある名前を付ける必要があります。
この名前には、小文字(a~z、ウムラウト、アクセント記号は使用不可)、アンダースコア、数字のみを使用でき、一意である必要があります。
既存のチェックプラグインと名前が衝突しないようにしてください。
既存の名前を確認したい場合は、コマンドラインで Checkmk サイトにアクセスし、cmk -L でリストを表示できます。
OMD[mysite]:~$ cmk -L
3par_capacity agent HPE 3PAR: Capacity
3par_cpgs agent HPE 3PAR: CPGs
3par_cpgs_usage agent HPE 3PAR: CPGs Usage
3par_hosts agent HPE 3PAR: Hosts
3par_ports agent HPE 3PAR: Ports
3par_remotecopy agent HPE 3PAR: Remote Copy
3par_system agent HPE 3PAR: System
3par_volumes agent HPE 3PAR: Volumes
3ware_disks agent 3ware ATA RAID Controller: State of Disks
3ware_info agent 3ware ATA RAID Controller: General Information
3ware_units agent 3ware ATA RAID Controller: State of Units
acme_agent_sessions snmp ACME Devices: Agent Sessions
acme_certificates snmp ACME Devices: Certificatesこの出力には、非常に長いリストの最初の行のみが表示されます。プレフィックスを使用することで、多くのチェックプラグインの割り当てをここで簡単に認識することができます。 したがって、独自のチェックプラグインにもプレフィックスの使用をお勧めします。 ちなみに、2 列目には、それぞれのチェックプラグインがデータを取得する方法が表示されています。
この例の場合、新しいチェックプラグインの適切な名前はmyhostgroups です。
これで、エージェントプラグインのスクリプトを作成するために必要な情報はすべて揃いました。root ユーザーとして、/usr/lib/check_mk_agent/plugins/ ディレクトリに新しいファイルmyhostgroups を作成します。
#!/bin/bash
columns="name members"
site="mysite"
echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"これは具体的に何を意味するのでしょうか?
最初の行には「shebang」が含まれています (これは、シャープと バングの省略形で、後者は感嘆符の省略形です)。これにより、Linux は、指定されたシェルでスクリプトを実行すべきであることを認識します。
スクリプトの適応性を維持するために、次に 2 つの変数が導入されています。
columns変数には、現在グループ名と関連するメンバーが含まれています。site変数には、Checkmk サイトの名前が含まれます。
セクションヘッダーを出力するには、echo コマンドを使用します。
テーブルの列はセミコロンで区切られているため、sep(59) を追加して、エージェント出力のデータではセミコロンを区切り文字として使用することを指定します。
59 はASCII文字コード 59、セミコロンを表します。
この追加がない場合、デフォルトではスペース文字 (ASCII 文字 32) が区切り文字として使用されます。
サイトユーザーとして利用できるlq コマンドを、root ユーザーによって実行されるスクリプトで使用するには、その前にsu を付けます。
|
ファイルを作成したら、もう 1 つ重要な点があります。ファイルを実行可能にしてください:
root@linux# chmod +x /usr/lib/check_mk_agent/plugins/myhostgroupsエージェントプラグインは、完全なパスをコマンドとして入力することで、手動で直接試すことができます。
root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhostホストが含まれていないホストグループは、ここにリストされません。
2.3. エージェントのテスト
機能するエージェントプラグインを作成するには、テストとトラブルシューティングが最も重要な作業です。 3 つのステップで進めることをお勧めします。
エージェントプラグインを「スタンドアロン」で試します。 これは、前のセクションで実行しました。
エージェント全体をローカルでテストします。
Checkmk サーバーからエージェントを取得します。
エージェントをローカルでテストするのは非常に簡単です。root として、check_mk_agent コマンドを呼び出します。
root@linux# check_mk_agent非常に長い出力のどこかに、新しいセクションが表示されます。 エージェントプラグインは、プロセスの最後にエージェントによって出力されます。
出力にless を追加してスクロールできます(スペースバーでスクロール、/ で検索、q で終了):
root@linux# check_mk_agent | lessまたは、出力から興味のある行を検索することもできます。
たとえば、grep と-A を使用すると、ヒットするたびに数行ずつ出力するオプションがあります。
これにより、セクションを簡単に検索して出力することができます。
root@linux# check_mk_agent | grep -A3 '^<<<myhostgroups'
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost3 つ目の、そして最後のテストは、Checkmk サイトから直接行います。
ホストを監視対象に含め(たとえば、localhost のように)、サイトユーザーとしてログインし、cmk -d でエージェントデータを取得します。
OMD[mysite]:~$ cmk -d localhost | grep -A3 '^<<<myhostgroups'これにより、前のコマンドと同じ出力が表示されます。
これが機能すれば、エージェントの準備は完了です。
このために何を行ったか?
パス/usr/lib/check_mk_agent/plugins/myhostgroups に短いスクリプトを作成し、それを実行可能にしただけです。
以下は、Checkmk サーバーでのみ実行されます。 そこで、チェックプラグインを作成します。
3. 簡単なチェックプラグインの記述
エージェントの準備は、作業全体の半分にすぎません。 次に、新しいエージェントセクションからの情報をどのようにハンドルするか、どのサービスを生成するか、WARN またはCRIT に送信するかなどを Checkmk に教える必要があります。 これは、Python を使用してチェックプラグインをプログラミングすることで実行できます。
3.1. ファイルの準備
独自のチェックプラグイン用に、サイトディレクトリの local 階層には、ベースディレクトリがすでに用意されています。
これは~/local/lib/python3/cmk_addons/plugins/ です。
このディレクトリはサイトユーザーに属しているため、書き込みが可能です。
このディレクトリでは、プラグインはプラグインファミリーごとに整理されており、ディレクトリ名は自由に定義できます。
たとえば、Cisco デバイスに関連するすべてのプラグインはcisco フォルダに、ホストグループに関連するすべてのプラグインはmyhostgroups フォルダに保存されます。
この規則により、同じファミリーに属するすべてのプラグインがコードを共有できるようになります。この規則は、Checkmk に付属のプラグインでもまったく同じように使用されています。
このサブディレクトリ<plug-in_family> には、さまざまな API に応じて、定義済みの名前を持つサブディレクトリがさらに必要に応じて作成されます。たとえば、エージェントベースのチェックプラグインのチェック API には、agent_based が作成されます。
その後、ルールセット APIおよびグラフ API用のサブディレクトリも追加します。
新しいエージェントベースのチェックプラグイン用の 2 つのサブディレクトリを作成し、それらに切り替えて作業を開始します。
OMD[mysite]:~$ mkdir -p local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based
OMD[mysite]:~$ cd local/lib/python3/cmk_addons/plugins/myhostgroups/agent_basedLinux システムにインストールされている任意のテキストエディタを使用して、チェックプラグインを編集できます。
ここに、チェックプラグイン用のファイルmyhostgroups.py を作成します。
ファイル名は、エージェントセクションの名前と同じにするのが慣例です。
Checkmk バージョン2.0.0 以降、チェックプラグインは常に実際のPythonモジュールであるため、ファイル名は.py で終わる必要があります。
実行可能な基本フレームワーク(GitHub からダウンロード)は、以下の通りです。このフレームワークを段階的に展開していきます:
#!/usr/bin/env python3
from cmk.agent_based.v2 import AgentSection, CheckPlugin, Service, Result, State, Metric, check_levels
def parse_myhostgroups(string_table):
parsed = {}
return parsed
def discover_myhostgroups(section):
yield Service()
def check_myhostgroups(section):
yield Result(state=State.OK, summary="Everything is fine")
agent_section_myhostgroups = AgentSection(
name = "myhostgroups",
parse_function = parse_myhostgroups,
)
check_plugin_myhostgroups = CheckPlugin(
name = "myhostgroups",
service_name = "Host group check_mk",
discovery_function = discover_myhostgroups,
check_function = check_myhostgroups,
)まず、チェックプラグインに必要な関数とクラスを Python モジュールからインポートする必要があります。
この例では、この記事の残りの部分で必要になる、または役立つと思われるものだけをインポートします。
ここでは、cmk.agent_based.v2 を使用して、Check APIV2のモジュールがインポートされることを指定しています。
from cmk.agent_based.v2 import AgentSection, CheckPlugin, Service, Result, State, Metric, check_levels3.2. parse関数の記述
parse 関数は、「生の」エージェントデータを「解析」する、つまり、分析して分割し、後続のすべてのステップで処理しやすい論理的な構造のフォームに変換するタスクがあります。
エージェントのテストに関するセクションで示したように、エージェントプラグインによって提供されるセクションは、次のような構造になっています。
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhostCheckmk は、エージェントプラグインによって提供されたセクションの行を、セクションヘッダーの区切り文字(この例では; )に基づいて行のリストに分割します。これらの行は、単語のリストです。
したがって、エージェントプラグインからの生データではなく、Checkmk では次のデータ構造が利用可能です。
[
['Hamburg', 'myhost11,myhost22,myhost33'],
['Munich', 'myhost1,myhost2,myhost3'],
['check_mk', 'localhost']
]内側のリストでは、最初のエレメントにはホストグループの名前、2 番目のエレメントにはそのグループに属するホストの名前が含まれます。
これらの情報すべてにアクセスすることは可能ですが、データセット内の位置によってのみアクセスできます。 そのため、各角括弧内の角括弧の数と、目的の内容の「シーケンス」番号を常に指定する必要があります。 データ量が多い場合、これはますます複雑になり、概要を把握することが難しくなります。
この時点で、解析関数は、その構造のおかげで明確な利点をもたらします。 コードが読みやすくなり、アクセス性能が向上し、概要の把握がはるかに容易になります。 この関数は、Checkmk が提供するデータ構造を変換し、各値を名前(またはキー)で自由に指定して参照できるようにします。これにより、探しているものを検索するために配列を繰り返し検索する必要がなくなります。
{
'Hamburg': {'members': 'myhost11,myhost22,myhost33'},
'Munich': {'members': 'myhost1,myhost2,myhost3'},
'check_mk': {'members': 'localhost'}
}慣例として、解析関数はエージェントセクションにちなんで命名され、parse_ で始まります。
この関数は、string_table を唯一の引数として受け取ります。
ここで引数は自由に選択できるわけではないことにご注意ください。
def parse_myhostgroups(string_table):
# print(string_table)
parsed = {}
for line in string_table:
parsed[line[0]] = {"members": line[1]}
# print(parsed)
return parseddef を使用して、Python でその下に関数を定義することを指定します。parsed = {} は、改良されたデータ構造を持つ辞書を作成します。
この例では、各行をエレメントごとに順番に処理します。
各行からホストグループとそのメンバーが取り出され、辞書のエントリとして組み立てられます。
辞書は、return parsed で返されます。
上記の例には、2 行のコメントアウトされた行があります。 後でチェックプラグインをテストする際に、これらの行をコメントアウトすると、parse 関数の実行前後のデータがコマンドラインに表示されます。 これにより、関数が本当に意図したとおりに動作しているかどうかをテストすることができます。 |
3.3. エージェントセクションの作成
この手順全体が有効になるには、新しい解析機能を含む新しいエージェントセクションを作成する必要があります。
そうしないと、Checkmk によって認識され、考慮されません。
これを行うには、AgentSection クラスのインスタンスとしてエージェントセクションを作成します。
agent_section_myhostgroups = AgentSection(
name = "myhostgroups",
parse_function = parse_myhostgroups,
)ここで重要なのは、セクションの名前がエージェント出力のセクションヘッダーと完全に一致していることです。
この時点から、myhostgroups セクションを使用するすべてのチェックプラグインは、parse 関数からの戻り値を受け取ります。
ルールとして、これは同じ名前のチェックプラグインになります。
しかし、チェックプラグインの拡張機能で示すように、他のチェックプラグインもこのセクションを購読することができます。
ちなみに、正確に知りたい場合は、この時点でCheck API のドキュメントをご覧ください。 このドキュメントには、このクラス、およびこの記事の後半で使用されるクラス、関数、オブジェクトについて詳しく説明されています。

3.4. チェックプラグインの作成
Checkmk が新しいチェックプラグインの存在を認識するには、そのプラグインを作成する必要があります。
これは、CheckPlugin クラスのインスタンスを作成することで行います。
必ず次の4つを指定する必要があります:
name: チェックプラグインの名前。 最も簡単な方法は、新しいエージェントセクションと同じ名前を使用することです。 こうすることで、後でチェック関数で定義されるチェックは、評価すべきセクションを自動的に認識します。service_name: 監視に表示されるサービスの名前。discovery_function: このタイプのサービスを検出するための関数 (これについては後で詳しく説明します)。check_function: 実際のチェックを実行する関数 (これについては後で詳しく説明します)。
インスタンスの名前は、check_plugin_ で始まる必要があります。
その結果、次のように表示されます。
check_plugin_myhostgroups = CheckPlugin(
name = "myhostgroups",
service_name = "Host group check_mk",
discovery_function = discover_myhostgroups,
check_function = check_myhostgroups,
)まず、discover_myhostgroups およびcheck_myhostgroups 関数を記述する必要があるため、まだこれを試さないことをお勧めします。
これらは、前述のようにエージェントセクションおよびチェックプラグインを作成する前に、ソースコードに記述する必要があります。
Nagios コアを使用する場合 (Checkmk Raw では常に使用されます)、サービス名には以下の特殊文字は使用できません。 |
3.5. ディスカバリー関数の記述
Checkmk の特別な機能として、監視対象のサービスを自動的に検出する機能があります。 この機能を使用するには、各チェックプラグインで、エージェントの出力を使用して、そのタイプのサービス、またはそのタイプのどのサービスを、対象のホストに作成すべきかを認識する機能を定義する必要があります。
ディスカバリー機能は、ホストに対してサービスディスカバリーが実行されると常に呼び出されます。
そして、どのサービスを作成すべきかを決定します。
通常の場合、この機能には、section という名前の引数が 1 つだけ渡されます。
この引数には、parse 機能によって準備された形式のエージェントセクションデータが含まれています。
したがって、次の単純なロジックを実装してください。myhostgroups エージェントセクションが存在する場合、適切なサービスも作成します。
これにより、エージェントプラグインがデプロイされているすべてのホストに自動的に表示されます。
ホストごとに 1 つのサービスしか作成しないチェックプラグインの場合、これ以上の情報は必要ありません。
def discover_myhostgroups(section):
yield Service()ディスカバリー機能は、yield (return ではない)を使用して、作成する各サービスに対してservice タイプのオブジェクトを返す必要があります。
Python では、yield はreturnと同じ機能を持ちます。どちらも呼び出し元関数に値を返します。
決定的な違いは、yield は、関数がデータ処理でどこまで進んだかを記憶していることです。
次の呼び出しは、最後のyield ステートメントの後に続き、最初からやり直すことはありません。
つまり、return の場合のように最初のヒットだけが読み出されるのではなく、すべてのヒットが順番に読み出されます (この利点は、後のサービスディスカバリーに関する例で明らかになります)。
3.6. チェック関数の記述
次に、実際のチェック関数に進みます。この関数は、現在のエージェント出力を使用して、サービスがどの状態になるかを決定し、さらに情報を出力することができます。
チェック関数の目的は、ホストグループにホストが割り当てられているかどうかを検証するためのチェックを設定することです。
これを行うために、check_mk ホストグループにホストが含まれているかどうかをチェックします。
含まれている場合、サービスはCRIT 状態になります。
含まれていない場合、すべてがOK になり、サービスの状態も になります。
以下に実装を示します:
def check_myhostgroups(section):
attr = section.get("check_mk")
hosts = attr["members"] if attr else ""
if hosts:
yield Result(state=State.CRIT, summary=f"Default group is not empty; Current member list: {hosts}")
else:
yield Result(state=State.OK, summary="Everything is fine")次に、その説明です。check_myhostgroups() 関数は、まず、check_mk キーに属する値をattr 変数に取得します。
次に、hosts 変数が、members 値に存在する場合、その値にリンクされます。members が存在しない場合、hosts は空のままになります。
実際の評価のため、if クエリが実行されます:
hosts変数に内容がある場合、つまりcheck_mkホストグループが空でない場合、サービスの状態はCRIT になり、アドバイステキストが出力されます。 このテキストには、check_mkホストグループに含まれるすべてのホストのホスト名のリストも含まれます。 PythonF-Stringは、式を含むテキストを出力するために使用されます。この名前は、文字列の前にfが付いていることから付けられました。hosts変数が空の場合、つまりcheck_mkホストグループにホストがない場合、サービスの状態はOK に変わります。 この場合、適切なメッセージテキストも出力されます。
チェック機能が作成されると、チェックプラグインの準備が完了します。
チェックプラグイン およびエージェントプラグイン は GitHub で入手できます。
3.7. チェックプラグインのテストと有効化
テストと有効化は、コマンドラインでcmk コマンドを使用して行います。
まず、オプション-I を使用してサービスディスカバリーを試してみてください。
オプションv (詳細表示)を追加すると、詳細な出力が要求されます。--detect-plugins は、コマンドの実行をこのチェックプラグインに制限し、localhost によってこのホストに制限します。
OMD[mysite]:~$ cmk -vI --detect-plugins=myhostgroups localhost
Discovering services and host labels on: localhost
localhost:
+ FETCHING DATA
No piggyback files for 'localhost'. Skip processing.
Get piggybacked data
+ ANALYSE DISCOVERED HOST LABELS
SUCCESS - Found no new host labels
+ ANALYSE DISCOVERED SERVICES
+ EXECUTING DISCOVERY PLUGINS (1)
1 myhostgroups
SUCCESS - Found 1 services
プランどおり、サービスディスカバリーは、myhostgroups チェックプラグインで新しいサービスを認識します。
これで、チェックプラグインに含まれるチェックを試すことができます。
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups -v localhost
+ FETCHING DATA
No piggyback files for 'localhost'. Skip processing.
Get piggybacked data
Host group check_mk Default group is not empty; Current member list: localhost
No piggyback files for 'localhost'. Skip processing.
[agent] Success, [piggyback] Success (but no data found for this host), execution time 1.8 sec | execution_time=1.800 user_time=0.030 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=1.780チェックを実行すると、以前に検出されたサービスの状態が判断されます。
すべてが予想どおりに進んだ場合は、変更をアクティブにすることができます。 そうでない場合は、トラブルシューティングの章で役立つ情報を見つけることができます。
最後に、監視コアを再起動して変更をアクティブにしてください。
OMD[mysite]:~$ cmk -R
Generating configuration for core (type nagios)...
Precompiling host checks...OK
Validating Nagios configuration...OK
Restarting monitoring core...OKCheckmk 監視では、ホストlocalhost に新しいサービスHost group check_mk が表示されます。

check_mk は空ではないため、サービスはCRIT
最初のチェックプラグインの作成が正常に完了しました。
4. チェックプラグインの拡張
4.1. 準備作業
先ほど完成した最初のチェックプラグインを、段階的に拡張していきます。 これまでのところ、エージェントプラグインは、ホストグループ内の名前とメンバーに関する情報のみを提供していました。 たとえば、ホストの状態や、ホストで実行されているサービスの状態を評価するには、さらに多くのデータが必要です。
エージェントプラグインの拡張
まず、エージェントプラグインを1 回拡張して、次のセクションでチェックプラグインを拡張するために必要なすべての情報を収集します。
Checkmk がホストグループについてどのような情報を提供しているかを確認するには サイトユーザーとして、次のコマンドを使用して、ホストグループテーブルのすべての利用可能な列をクエリします。
OMD[mysite]:~$ lq "GET columns\nFilter: table = hostgroups\nColumns: name"
action_url
alias
members
members_with_state
name
notes
notes_url
num_hosts
...出力はさらに詳細です。
このテーブルには 30 近くの列があり、そのほとんどは意味のある名前が付いています。
ここで注目すべきは、次の列です。
グループごとのホスト数 (列num_hosts)、UP 状態のホスト数 (num_hosts_up)、グループ内のすべてのホストのサービス数 (num_services)、OK 状態のサービス数 (num_services_ok)。
これで、これらの新しい列はエージェントから提供されるだけで済みます。 これは、前の章で作成したエージェントプラグインを拡張することで実現できます。
root ユーザーとして、エージェントプラグインのスクリプトを編集します。
スクリプトは、設定可能な値をすでに変数に格納しているので、columns で始まる行のみを変更し、そこで取得した 4 つの追加列を入力するだけで十分です。
#!/bin/bash
columns="name members num_hosts num_hosts_up num_services num_services_ok"
site="mysite"
echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"スクリプトを実行して、これを確認します。
root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Munich;myhost3,myhost2,myhost1;3;3;180;144
Hamburg;myhost22,myhost33,myhost11;3;2;132;105
check_mk;localhost;1;1;62;454つの新しい値(それぞれセミコロンで区切られています)が、各行の末尾に表示されます。
この変更により、エージェントプラグインは以前とは異なるデータを提供するようになりました。 この時点で、変更したデータでもチェックプラグインが正常に動作することを確認することが重要です。
parse 関数の拡張
チェックプラグインでは、parse 関数はエージェントプラグインから提供されたデータを変換する役割を担っています。 parse 関数の記述では、ホストグループテーブルの 2 列のみを考慮していました。 しかし、現在は 2 列ではなく 6 列が提供されています。 そのため、追加の 4 列を処理するように parse 関数をカスタマイズする必要があります。
サイトユーザーとして、チェックプラグインを含むmyhostgroups.py ファイルでparse関数を変更します。
def parse_myhostgroups(string_table):
parsed = {}
column_names = [
"name",
"members",
"num_hosts",
"num_hosts_up",
"num_services",
"num_services_ok",
]
for line in string_table:
parsed[line[0]] = {}
for n in range(1, len(column_names)):
parsed[line[0]][column_names[n]] = line[n]
return parsedparsed = {} とreturn parsed の間のすべてが変更されています。
まず、処理する列を、その名前でcolumn_names リストとして定義します。
次に、for ループで、各行から列名と読み込んだ値からキーと値のペアを生成して、辞書を作成します。
最初の 2 列のデータ構造は変更されていないため、この拡張は既存のチェック機能には重要ではありません。 追加されたのは、チェック関数では(まだ)評価されていない列だけです。
新しいデータを処理できるようになったので、このデータも使用します。
4.2. サービスディスカバリー
前の章では、ホストにサービスを作成する非常に単純なチェックを作成しました。 しかし、1 つのホストに 1 つのチェックから複数のサービスが存在することもよくあります。
この最も一般的な例は、ホスト上のファイルシステム用のサービスです。df という名前のチェックプラグインは、ホスト上のファイルシステムごとに 1 つのサービスを作成します。
これらのサービスを区別するために、ファイルシステムのマウントポイント(/var など)またはドライブ文字(C: など)がサービス名に含まれます。
その結果、Filesystem /var やFilesystem C: などのサービス名になります。
ここで、/var やC: は項目と呼ばれます。
したがって、ここでは項目を含むチェックについても説明します。
項目を含むチェックを構築する場合は、次の機能を実装する必要があります。
ディスカバリー機能は、ホストで監視すべき各項目についてサービスを生成しなければなりません。
項目は、プレースホルダー
%s(例:"Filesystem %s")を使用してサービス名に含める必要があります。チェック機能は、項目ごとに個別に 1 回呼び出され、これを引数として受け取ります。 次に、エージェントデータから、この項目に関連するデータを抽出する必要があります。
これを実際にテストするには、既存のホストグループごとに個別のサービスを作成します。
前の章で、標準のcheck_mk グループをチェックするために作成したmyhostgroups チェックプラグインは引き続き機能する必要があるため、このチェックプラグインはそのまま残します。
拡張機能として、既存のファイルmyhostgroups.py に新しいチェックプラグインmyhostgroups_advanced を作成します。— 最初のステップでは、以前と同様に、クラスCheckPlugin のインスタンスを作成します。
以下に、古いコードと新しいコードをハイライト表示したものを示します:
check_plugin_myhostgroups = CheckPlugin(
name = "myhostgroups",
service_name = "Host group check_mk",
discovery_function = discover_myhostgroups,
check_function = check_myhostgroups,
)
check_plugin_myhostgroups_advanced = CheckPlugin(
name = "myhostgroups_advanced",
sections = [ "myhostgroups" ],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
)
新しいチェックプラグインを古いプラグインと区別するために、myhostgroups_advanced という一意の名前が付けられています。sections パラメータは、チェックプラグインがエージェント出力のどのセクションを購読するかを決定します。
ここでは、myhostgroups を使用して、新しいチェックプラグインが古いプラグインと同じデータを使用するように指定しています。つまり、parse 関数によって準備されたエージェントプラグインのセクションを使用します。
サービス名には、プレースホルダー%s が含まれています。
項目の名前は、後で Checkmk によってこの位置に挿入されます。
最後の 2 行では、新しいディスカバリー機能と新しいチェック機能の名前が定義されています。
まず、ディスカバリー関数についてです。この関数は、監視する項目を決定する役割を担います。これは、既存の関数に加えて追加で入力します。
def discover_myhostgroups_advanced(section):
for group in section:
if group != "check_mk":
yield Service(item=group)これまでと同様に、ディスカバリー関数はsection 引数を受け取ります。
個々のホストグループはループで実行されます。
ここでは、check_mk を除くすべてのホストグループが対象となります。この特別なホストグループは、既存のmyhostgroups チェックプラグインによってすでに処理されています。
項目が見つかるたびに、yield で返され、Service 型のオブジェクトが作成されます。このオブジェクトは、ホストグループ名を項目として受け取ります。
ホストが後で監視されると、チェック機能はサービスごとに、つまり項目ごとに個別に呼び出されます。
これにより、新しいmyhostgroups_advanced チェックプラグインのチェック機能の定義に移動します。
チェック機能は、セクションに加えてitem 引数も受け取ります。
関数の最初の行は、次のように表示されます。
def check_myhostgroups_advanced(item, section):チェック関数のアルゴリズムは単純です。 ホストグループが存在する場合、サービスはOK に設定され、グループ内のホストの数と名前がリストされます。 このための完全な関数は次のとおりです。
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if attr:
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")チェック結果は、yield を通じて、Result クラスのオブジェクトを返すことで配信されます。
これには、state およびsummary パラメータが必要です。
ここで、state はサービスの状態(例:OK )を定義し、summary はサービスのSummary に表示されるテキストを定義します。
これは純粋に情報提供のためのものであり、Checkmk ではさらに評価されることはありません。
詳細については、次のセクションをご覧ください。
ここまでは問題ありません。 しかし、探している項目が見つからない場合はどうなりますか? これは、過去にホストグループに対してサービスがすでに作成されていたが、そのホストグループが現在存在していない場合に発生します。ホストグループは Checkmk にはまだ存在しますが、ホストが含まれていないか、完全に削除されているかのいずれかです。 どちらの場合も、このホストグループはエージェントの出力には表示されなくなります。
良いニュースがあります。
Checkmk はこの問題に対応しています。
検索した項目が見つからない場合、Checkmk は自動的にサービスに対して結果UNKNOWN - Item not found in monitoring data を生成します。
これは意図的な機能であり、良いことです。
検索した項目が見つからない場合は、関数から Python を実行するだけで、Checkmk にその作業を行わせることができます。
Checkmk は、以前そこにあった項目がなくなったことしか認識しません。 Checkmk はその理由を知りません — しかし、あなたは知っています。 したがって、そのような知識を自分だけに留めておかないで、チェック関数でこの条件をインターセプトし、役立つメッセージを表示することが適切です。
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if not attr:
yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
return
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")何が変わったのでしょうか?
エラー条件が最初にハンドルされるようになりました。
したがって、if ブランチで、項目が本当に存在しないかどうかをチェックし、状態をCRIT に設定して、return で関数を終了します。
それ以外の場合は、これまでどおりOK を返します。
これにより、ホストグループの消失の状況をチェック機能に反映させました。 UNKNOWN の代わりに、関連するサービスはCRIT となり、クリティカル状態の原因に関する情報が含まれます。
これで、古いプラグインの拡張機能としての新しいチェックプラグインが完成しました。
拡張エージェントプラグイン
およびチェックプラグイン用の拡張ファイル
は、GitHub で入手できます。
後者には、前の章で紹介した単純なチェックプラグイン「myhostgroups 」、高度な解析機能、およびチェックプラグインの作成、ディスカバリー機能、チェック機能を含む新しいチェックプラグイン「myhostgroups_advanced 」のコンポーネントが含まれています。
チェックプラグインまたはエージェントセクションの作成前に、必ず関数を定義してください。そうしないと、関数名が定義されていないためにエラーが発生します。
新しいmyhostgroups_advanced チェックプラグインは新しいサービスを提供するため、このチェックプラグインのサービスディスカバリーを実行し、変更をアクティブにして、監視にこれらのサービスが表示されるようにする必要があります。

単純なチェックプラグインの章で説明されているように進めてください。myhostgroups に対して最初の 2 つのコマンドは実行せず、新しいmyhostgroups_advanced チェックプラグインに対して実行してください。
4.3. 概要と詳細
Checkmk の監視では、各サービスには、OK 、WARN などの状態と、1 行のテキストが表示されます。 このテキストは、前のスクリーンショットにあるように、Summary 列にあり、サービスの状態を簡単に要約する役割があります。 このテキストは 60 文字以内に収めることが望ましいです。 これにより、改行が煩雑になることなく、表を簡潔に表示することができます。
また、サービスの状態に関するすべての詳細が表示される「Details 」フィールドもあり、ここには要約情報もすべて含まれます。 サービスをクリックすると、サービスページが開き、「Summary 」および「Details 」の 2 つのフィールドが、他の多くのフィールドとともに表示されます。
yield Result(...) を呼び出すと、要約に表示すべき重要な情報、および詳細に表示するだけで十分な情報を決定することができます。
この例では、常に次の形式の呼び出しを使用しています:
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")これは、summary として定義されたテキストが、Summary — およびDetails にも常に表示されることを意味します。
したがって、これは重要な情報のみに使用してください。
ホストグループに多くのホストが含まれている場合、概要リストが非常に長くなり、推奨される 60 文字を超えることがあります。
重要度の低い情報については、details を使用して、そのテキストを詳細にのみ表示するように指定することができます。
yield Result(
state = State.OK,
summary = f"{attr['num_hosts']} hosts in this group",
details = f"{attr['num_hosts']} hosts in this group: {attr['members']}",
)上記の例では、ホストのリストはDetails にのみ表示されます。Summary には、グループ内のホストの数のみが表示されます。

summary とdetails に加えて、3 つめのパラメータがあります。notice を使用すると、OK 内のサービスのテキストは、詳細にのみ表示され、他のすべての状態の要約には表示されません。
これにより、要約から、サービスがOK ではない理由がすぐにわかります。notice パラメータは、これまでの例のように、テキストが状態に永続的に結び付けられている場合には、特に有用ではありません。
要約すると、次のようにまとめられます:
OK のサービスの場合、概要のテキストの合計は 60 文字以内にしてください。
summaryまたはnoticeのいずれかを使用してください。少なくとも一方を使用し、両方を同時に使用しないでください。必要に応じて、詳細のテキストが代替となる場合、
detailsを追加してください。
4.4. サービスごとの複数の部分結果
ホスト上のサービスの数が過度に増加することを防ぐため、複数の部分的な結果を 1 つのサービスにまとめることがよくあります。 たとえば、Linux のMemory サービスは、RAM およびスワップの使用状況だけでなく、共有メモリ、ページテーブル、その他あらゆるものをチェックします。
Check API は、このための非常に便利なインターフェースを提供しています。
チェック関数は、yield を必要な回数だけ実行して結果を生成するだけです。
サービスの全体的な状態は、OK →WARN →UNKNOWN→CRIT の順で、最悪の部分結果に基づいて決定されます。
この例では、このオプションを使用して、既存の結果に加えて、ホストグループの各サービスについて 2 つの結果を追加で定義します。 これらは、UP 状態のホストの割合と、OK 状態のサービスの割合を評価します。 エージェント出力および解析関数で以前に定義したホストグループテーブルの追加列を使用します。
次に、チェック関数を上から下に向かって段階的に展開します。
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if not attr:
yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
return
members = attr["members"]
num_hosts = int(attr["num_hosts"])
num_hosts_up = int(attr["num_hosts_up"])
num_services = int(attr["num_services"])
num_services_ok = int(attr["num_services_ok"])if ブランチは変更されません。つまり、新しい部分結果は、既存のホストグループにのみ適用されます。
次に、セクションに含まれるホストグループテーブルの列用に 5 つの変数を定義します。
これにより、読みやすさが向上する一方で、計算にまだ使用する 4 つの列について、読み込んだ文字列をint() で数値に変換することができます。
既存の結果は(ほぼ)変更されません:
yield Result(
state = State.OK,
summary = f"{num_hosts} hosts in this group",
details = f"{num_hosts} hosts in this group: {members}",
)attr はすでに変数定義に含まれているため、Python の「F-String」で値を返す式へのアクセスだけが以前よりも簡単になりました。
それでは、拡張機能の実際のコアである、次のステートメントを実装する結果の定義に移りましょう。
「ホストグループのサービスは、ホストの 90% がUP の場合はWARN 、ホストの 80% がUP の場合はCRIT です。
ここでの規則は、閾値に達した時点で、それを超えた場合だけでなく、WARN またはCRIT にチェックが移るということです。
Check API は、決定された値と閾値と比較するための補助関数check_levels を提供しています。
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = ("fixed", (90.0, 80.0)),
label = "UP hosts",
notice_only = True,
)1 行目では、UP 状態のホストの総数と数から割合が計算され、hosts_up_perc 変数に格納されます。
単一のスラッシュ (/) は浮動小数点除算を実行し、結果が浮動小数点値になることを保証します。
これは、後で使用される一部の関数が浮動小数点値を入力として期待するため、便利です。
2 行目では、check_levels 関数の結果が、API ドキュメントに記載されているResult 型のオブジェクトとして返されます。
この関数には、先ほど計算したパーセンテージ(hosts_up_perc )、2 つの下限閾値(levels_lower )、出力の前に付加されるラベル(label )、そして最後にnotice_only=True が値として渡されます。
最後のパラメータは、前のセクションで Result() オブジェクトについて紹介したnotice パラメータを使用します。notice_only=True を使用すると、状態がOK でない場合にのみ、サービスのテキストがSummary に表示されるように指定できます。
ただし、WARN またはCRIT になる部分的な結果は、notice_only の値に関係なく、常に概要に表示されます。
最後に、2 番目の結果と同じ方法で 3 番目の結果を定義します。これは、OK 状態にあるサービスの割合を評価します。
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = ("fixed", (90.0, 80.0)),
label = "OK services",
notice_only = True,
)これでチェック関数の作成は完了です。
ホストグループのサービスは、3 つの結果を評価し、その中から最悪の状態を監視に表示します。

4.5. メトリック
チェックでは、必ずしもそうとは限りませんが、多くの場合、数値が扱われます。そして、これらの数値は、測定値や計算値であることがほとんどです。
この例では、ホストグループ内のホストの数 (num_hosts) およびUP 状態のホストの数 (num_hosts_up) が測定値です。UP 状態のホストの割合 (hosts_up_perc) は、これらの値から計算された値です。
このような値を時間範囲にわたって表示できる場合、その値はメトリックとも呼ばれます。
Checkmk には、ビルトインのグラフ作成システムにより、このような値を保存、評価、表示するためのコンポーネントがあります。 これは、OK 、WARN 、CRIT 状態の計算とはまったく独立しています。
この例では、2 つの計算値、hosts_up_perc とservices_ok_perc をメトリックとして定義します。
メトリックは、何も操作をしなくても、Checkmk のグラフィカルユーザーインターフェースにすぐに表示されます。
各メトリックに対して、グラフが自動的に生成されます。
メトリックはチェック関数によって決定され、追加の結果として返されます。
最も簡単な方法は、呼び出しのcheck_levels() 関数にメトリック情報を追加することです。
念のため、前のセクションの check_levels() 関数呼び出しの行を以下に示します。
yield from check_levels(
hosts_up_perc,
levels_lower = ("fixed", (90.0, 80.0)),
label = "UP hosts",
notice_only = True,
)メトリックの 2 つの新しい引数は、metric_name およびboundaries です。
yield from check_levels(
hosts_up_perc,
levels_lower = ("fixed", (90.0, 80.0)),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)わかりやすく、意味のある名前にするため、メトリックの名前には、パーセンテージが値として格納されている変数の名前を使用してください。
boundaries を使用して、グラフ作成システムに可能な値の範囲に関する情報を提供することができます。
これは、可能な最小値と最大値を指します。
パーセンテージの場合、0.0 と100.0 の制限はそれほど難しくはありません。
浮動小数点数と整数(内部では浮動小数点数に変換されます)は使用できますが、文字列は使用できません。
値の範囲の制限が 1 つだけ定義されている場合は、もう一方にはNone と入力してください(例:boundaries = (0.0, None) )。
この拡張機能により、check_levels 関数は、Result に加えて、yield 経由でMetric 型のオブジェクトも返すようになります。
同じ方法で、メトリックservices_ok_perc を定義できるようになりました。
チェック関数の最後の行は、次のように表示されます。
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = ("fixed", (90.0, 80.0)),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = ("fixed", (90.0, 80.0)),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)拡張チェック機能により、両方のグラフが監視に表示されます。 サービスリストでは、アイコンがサービスにグラフがあることを示します。 アイコンにマウスを置くと、グラフがプレビュー表示されます。

すべてのグラフの概要は、説明文などとともにサービス詳細で確認できます。
しかし、check_levels() 関数で目的のメトリックの値が定義されていない場合はどうすればよいでしょうか?
もちろん、関数呼び出しとは独立してメトリックを定義することができます。
この目的には、コンストラクタから直接作成できるMetric() オブジェクトを使用します。
値hosts_up_perc のメトリックの代替定義は、次のようになります。
yield Metric(
name = "hosts_up_perc",
value = hosts_up_perc,
levels = (80.0, 90.0),
boundaries = (0.0, 100.0),
)Metric() の引数は、上記の関数呼び出しの引数とよく似ています。
メトリック名と値を表す最初の 2 つの引数は必須です。
さらに、2 つのオプションの引数があります。levels は閾値WARN およびCRIT を表し、boundaries は値の範囲を表します。
|
ここで、2 つの計算値だけでなく、Metric()を使用して、すべての測定値をメトリックとして定義するオプションを使用します。この例では、ホストグループテーブルの 4 つの測定値です。
メトリック名と値の 2 つの必須の指定のみに制限してください。
4 行の新しい行で、メトリックのチェック機能の拡張が完了します。
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (90.0, 80.0),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)
yield Metric(name="num_hosts", value=num_hosts)
yield Metric(name="num_hosts_up", value=num_hosts_up)
yield Metric(name="num_services", value=num_services)
yield Metric(name="num_services_ok", value=num_services_ok)これにより、サービスあたりのグラフの数が増えますが、たとえば、複数のメトリックを 1 つのグラフに結合するなどのオプションも利用できるようになります。 これらのオプションやその他のオプションについては、以下の「メトリックの表示のカスタマイズ」セクションで説明します。
GitHub のサンプルファイル で、チェック関数の全体を確認できます。
5. チェックパラメータのルールセット
拡張myhostgroups_advanced チェックプラグインでは、ホストの90%がUP の場合にWARN ステート、80%の場合にCRIT ステートを生成します。
この場合、90 および80 という数値は、チェック関数で明示的に定義されています。
しかし、Checkmk では、ユーザーはルールを使用して、このような閾値やその他のチェックパラメータを設定できることに慣れています。
たとえば、ホストグループに 4 つのメンバーしかいない場合、90 % と 80 % の 2 つの閾値はあまり適切ではありません。
最初のホストが故障すると、その割合は 75 % に低下し、中間状態の「WARN 」を経ずに「CRIT」の状態になります。
そのため、Setup インターフェースから設定できるように、チェックプラグインを変更する必要があります。 そのためには、ルールセットが必要です。
チェックプラグインのルールセットを作成するには、チェックプラグインの開発を終了し、ディレクトリ、ファイル、および API を切り替えます。 Checkmk の2.3.0 から、Rulesets APIを使用して、チェックプラグイン用のルールセットを作成できます。 ルールセットに関する API ドキュメントは、Checkmk サイトのRulesets > Version 1 の「Check API」と同じページにあります。
5.1. 新しいルールセットの定義
新しいルールセットを作成するには、まず、プラグインファミリーのディレクトリ~/local/lib/python3/cmk_addons/plugins/myhostgroups/ に新しいサブディレクトリを作成します。
このサブディレクトリには、rulesets という名前が事前に定義されています。
OMD[mysite]:~$ mkdir -p local/lib/python3/cmk_addons/plugins/myhostgroups/rulesets
OMD[mysite]:~$ cd local/lib/python3/cmk_addons/plugins/myhostgroups/rulesetsこのディレクトリに、ルールセットを定義するファイルを作成します。
ファイル名は、チェックプラグインの名前に基づいて付け、他のプラグインファイルと同様、拡張子はpy にする必要があります。
この例では、ファイル名ruleset_myhostgroups.py が適しています。
このファイルの構造を順に見ていきましょう。 まず、いくつかのインポートコマンドがあります。
#!/usr/bin/env python3
from cmk.rulesets.v1 import Label, Title
from cmk.rulesets.v1.form_specs import BooleanChoice, DefaultValue, DictElement, Dictionary, Float, LevelDirection, SimpleLevels
from cmk.rulesets.v1.rule_specs import CheckParameters, HostAndItemCondition, Topicまず、テキスト用のクラスがインポートされます。
2 行目では、フォーム仕様、つまりルールセットで使用される GUI の基本エレメント(バイナリ選択(BooleanChoice )、複数選択(Dictionary 、DictElement )、閾値定義(SimpleLevel 、LevelDirection 、DefaultValue )、浮動小数点数の入力(Float )など)から選択を行います。
ここでは、論理フォームエレメントのみを要求し、GUI のデザインは Checkmk に任せておきます。
最後の行は、Checkmk におけるルールの適用領域、つまりここではチェックパラメータの定義、ホストおよび項目への割り当て、トピックの下での保存を決定するルール仕様をインポートします。
チェックプラグインmyhostgroups_advanced は複数のサービスを生成するため、ここでHostAndItemCondition をインポートします。
チェックがサービスを生成しない、つまり項目がない場合は、代わりにHostCondition をインポートします。
次に、チェックパラメータを入力するためのフォームの実際の定義を行います。 ユーザーは、UP 状態のホスト数とOK 状態のサービス数の両方について、WARN およびCRIT の 2 つの閾値を個別に定義できる必要があります。
def _parameter_form():
return Dictionary(
elements = {
"hosts_up_lower": DictElement(
parameter_form = SimpleLevels(
title = Title("Lower percentage threshold for host in UP status"),
form_spec_template = Float(),
level_direction = LevelDirection.LOWER,
prefill_fixed_levels = DefaultValue(value=(90.0, 80.0)),
),
required = True,
),
"services_ok_lower": DictElement(
parameter_form = SimpleLevels(
title = Title("Lower percentage threshold for services in OK status"),
form_spec_template = Float(),
level_direction = LevelDirection.LOWER,
prefill_fixed_levels = DefaultValue(value=(90.0, 80.0)),
),
required = True,
),
}
)これを行うには、辞書を生成する関数を作成します。 関数の名前は自由に選択できますが、以下のルールを作成する際に必要になります。 関数は、モジュール境界を越えて表示されないように、アンダースコアで始める必要があります。
return Dictionary() は必須です。
その中に、elements={} を使用して辞書のエレメントを作成します。この例では、hosts_up_lower およびservices_ok_lower です。SimpleLevels パラメータフォームは、固定の閾値を入力するために使用します。
フォームでは、まず、入力する値のtitle および浮動小数点数を定義します(form_spec_template )。
値がこのレベルを下回った場合にステータスが変化することを指定するには、LevelDirection.LOWER を使用します。
最後に、prefill_fixed_levels を使用して、ルールセットのユーザーに空の入力フィールドではなく値を提供することができます。
GUIに表示されるこれらの値は、check_default_parametersを使用してチェックプラグインの作成でさらに下部に設定されるデフォルト値ではないことに注意してください。
チェック機能にも適用される同じデフォルト値をGUIに表示したい場合は、両方の場所で値を一致させる必要があります。
最後に、インポートした項目と自己定義した項目を使用して、新しいルールセットを作成します。
これは、CheckParameters クラスの新しいインスタンスを作成することで実行します。
このインスタンスの名前は、rule_spec_ で始まる必要があります。
rule_spec_myhostgroups = CheckParameters(
name = "myhostgroups_advanced",
title = Title("Host group status"),
topic = Topic.GENERAL,
parameter_form = _parameter_form,
condition = HostAndItemCondition(item_title=Title("Host group name")),
)以下の説明が適用されます:
ルールセットの
nameは、チェックプラグインとの接続を確立します。 このルールセットを使用するチェックプラグインは、作成時にこの名前をcheck_ruleset_nameとして使用する必要があります。 新しいルールセットの数を把握するために、名前にプレフィックスを使用することをお勧めします。titleは、Checkmk GUI に表示されるルールセットのタイトルを定義します。topicは、Setup 内でルールセットを表示する場所を決定します。 この例で選択した値では、ルールセットは、Setup > Services > Service monitoring rules のボックスVarious に表示されます。通常、この場所は適切な場所です。parameter_formに、以前に作成した関数の名前を入力します。チェックで項目を使用しない場合、条件は、上記の例のように「
HostAndItemCondition」ではなく「HostCondition」になります。 項目のタイトル「"Host group name"」で、GUI でルールを特定のホストグループに制限するためのラベルを定義します。
5.2. ルールセットのテスト
ルールセットのファイルを作成したら、チェックプラグインに接続せずに、これまでの設定がすべて機能するかどうかをテストする必要があります。 そのためには、まずサイトの Apache を再起動して、新しいファイルが読み込まれるようにする必要があります。 これは、次のコマンドで実行します。
OMD[mysite]:~$ omd restart apacheルールセットは、上記のページのSetup にあります。 セットアップメニューの検索機能を使用してルールセットを見つけることもできますが、Redis を再起動する必要があります。
OMD[mysite]:~$ omd restart redisGUI では、定義したルールセットは次のようになります。

Conditions ボックスには、ホストグループに対するルールを制限するために、HostAndItemCondition で定義したHost group name 入力フィールドがあります。
上のスクリーンショットのように、ルールを作成し、さまざまな値を試してみてください。 エラーなく動作すれば、チェック機能でチェックパラメータを使用できるようになります。
5.3. ルールセットをチェックプラグインに接続する
新しく作成したルールセットは、前の章で暫定的に完成したチェックプラグインに接続されます。
ルールを有効にするには、チェックプラグインがチェックパラメータを受け入れるように設定し、使用するルールを指定する必要があります。
これを行うには、myhostgroups_advanced チェックプラグインの作成時に、チェックプラグインファイルに 2 行を追加します。
check_plugin_myhostgroups_advanced = CheckPlugin(
name = "myhostgroups_advanced",
sections = [ "myhostgroups" ],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
check_default_parameters = {},
check_ruleset_name = "myhostgroups_advanced",
)check_default_parameters エントリでは、実際にルールが作成されていない場合に適用されるデフォルト値を定義できます。
チェックパラメータ用にチェックプラグインを変換する場合、この行は存在する必要があります。
最も単純なケースでは、空の辞書{} を渡します。
次に、check_ruleset_name 、つまりルールセットの名前を入力します。
これにより、Checkmk は、どのルールセットからパラメータを決定すべきかを認識します。
これで、Checkmk はチェック関数にパラメータを渡そうとします。
これを機能させるには、チェック関数を拡張して、item とsection の間に挿入されるparams 引数を期待するようにする必要があります。
def check_myhostgroups_advanced(item, params, section):項目なしでチェックを構築する場合、item は省略され、params が先頭に置かれます。
最初のテストとして、変数params の内容をprint で出力することを強くお勧めします。
def check_myhostgroups_advanced(item, params, section):
print(params)チェックプラグインが実行されると、ルールで定義された値を含む行(サービスごとに 1 行)が次のように表示されます。
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced -v localhost
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})
Parameters({'hosts_up_lower': ('fixed', (75.0, 60.0)), 'services_ok_lower': ('fixed', (75.0, 60.0))})すべての準備が整い、正しく動作している場合は、 |
次に、渡されたパラメータが有効になるように、チェック関数をさらにカスタマイズします。 ルールで定義した 2 つの辞書エレメントを、そこで選択した名前でパラメータから取得します。
def check_myhostgroups_advanced(item, params, section):
hosts_up_lower = params["hosts_up_lower"]
services_ok_lower = params["services_ok_lower"]チェック関数のさらに下で、以前にハードコードされていた閾値"fixed", (90.0, 80.0) は、変数hosts_up_lower およびservices_ok_lower に置き換えられます。
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (hosts_up_lower),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (services_ok_lower),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)ルールが設定されている場合、GUI で設定された閾値を使用して、例のホストグループを監視することができます。
ただし、ルールが定義されていない場合、チェックプラグインのデフォルトパラメータが設定されていないため、このチェック機能はクラッシュし、ルールがない場合、プラグインはKeyError を生成します。
ただし、チェックプラグインの作成時にデフォルト値を定義しておけば、この問題は解決できます。
check_plugin_myhostgroups_advanced = CheckPlugin(
name = "myhostgroups_advanced",
sections = [ "myhostgroups" ],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
check_default_parameters = {"hosts_up_lower": ("fixed", (90, 80)), "services_ok_lower": ("fixed", (90, 80))},
check_ruleset_name = "myhostgroups_advanced",
)これらのデフォルト値は、Setup インターフェースにも表示されるため、常にこの方法でデフォルト値を渡す必要があります (チェックプラグインでパラメータの欠落をインターセプトしないでください)。 たとえば、ホストのサービスディスカバリー、Services of host ページ、Display メニューには、Show check parameters スイッチがあります。
6. メトリックの表示のカスタマイズ
上記の例では、チェックプラグインmyhostgroups_advanced によって、測定値および計算値すべてのメトリックが生成されていました。
これを行うには 2 つの方法があります。
1 つ目は、metric_name 引数を使用して、check_levels() 関数の一部として計算値のメトリックを作成する方法です。
yield from check_levels(
services_ok_perc,
levels_lower = ("fixed", (90.0, 80.0)),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)次に、Metric() オブジェクトを使用して、測定されたメトリックを直接生成しました。たとえば、OK 状態のサービス数の場合、次のようにします。
yield Metric(name="num_services_ok", value=num_services_ok)何も操作しなくても、メトリックは Checkmk グラフィカルユーザーインターフェースにすぐに表示されます。 ただし、いくつかの制限があります。
一致するメトリックはグラフで自動的に結合されず、それぞれ個別に表示されます。
メトリックには適切なタイトルは付けられず、メトリックの内部変数名が表示されます。
意味のある表現が可能な単位(例:GB ではなく個々のバイト)は使用されません。
色はランダムに選択されます。
パーフオメーター、つまりメトリックのバー形式のグラフィックプレビューは、サービスリスト(ホストのすべてのサービスを表示するビューなど)には自動的に表示されません。
このような詳細情報を含むメトリックの表示を完了するには、メトリックの定義が必要です。
ルールセットと同様に、Checkmk2.3.0 以降では、グラフ API により、メトリック、グラフ、およびパーフオメーター用の個別の API も用意されています。 グラフ API のドキュメントは、Checkmk サイトのCheck API と同じページ、Graphing > Version 1 にあります。
6.1. 新しいメトリック定義の作成
ルールセットとメトリック定義の作成手順は、非常に似ています。
まず、プラグインファミリディレクトリ~/local/lib/python3/cmk_addons/plugins/myhostgroups/ に、デフォルト名graphing の新しいサブディレクトリを作成します。
OMD[mysite]:~$ mkdir -p local/lib/python3/cmk_addons/plugins/myhostgroups/graphing
OMD[mysite]:~$ cd local/lib/python3/cmk_addons/plugins/myhostgroups/graphing次に、このディレクトリにグラフファイルを作成します。例えば、graphing_myhostgroups.py などです。
まず、いくつかのインポートコマンドを実行します。
#!/usr/bin/env python3
from cmk.graphing.v1 import Title
from cmk.graphing.v1.graphs import Graph, MinimalRange
from cmk.graphing.v1.metrics import Color, DecimalNotation, Metric, Unit
from cmk.graphing.v1.perfometers import Closed, FocusRange, Open, Perfometerこの例では、OK 状態のサービスの割合を表す独自のメトリックを定義します。
これは、Metric クラスのインスタンスを作成することで実現します。
このインスタンスの名前は、metric_
metric_myhostgroups_services_ok_perc = Metric(
name = "services_ok_perc",
title = Title("Percentage of services in OK state"),
unit = Unit(DecimalNotation("%")),
color = Color.ORANGE,
)以下に説明します:
グラフファイルにこの定義を記述することで、メトリックのタイトル、単位、および色が適切に表示されるようになります。
ルールセットファイルの作成と同様に、GUI で変更を反映するには、まずグラフファイルを読み込む必要があります。 これは、サイトの Apache を再起動することで実行できます。
OMD[mysite]:~$ omd restart apacheメトリックグラフは、Checkmk GUI で次のように表示されます。

6.2. 複数のメトリックを含むグラフ
複数のメトリックを 1 つのグラフに結合したい場合(これは非常に便利な場合が多いです)、前のセクションで作成したグラフファイルに追加できるグラフ定義が必要になります。
この例では、2 つのメトリックnum_services とnum_services_ok を 1 つのグラフに表示します。
このメトリックの定義は、前のセクションでservices_ok_perc に対して行ったのと同じ方法で作成し、次のようにします。
metric_myhostgroups_services = Metric(
name = "num_services",
title = Title("Number of services in group"),
unit = Unit(DecimalNotation("")),
color = Color.PINK,
)
metric_myhostgroups_services_ok = Metric(
name = "num_services_ok",
title = Title("Number of services in OK state"),
unit = Unit(DecimalNotation("")),
color = Color.BLUE,
)次に、これら 2 つのメトリックを線として描画するグラフを追加します。
これは、クラスGraph のインスタンスを使用して行います。このインスタンスの名前は、再び定義済みのプレフィックス (graph_) で始まる必要があります。
graph_myhostgroups_combined = Graph(
name = "services_ok_comparison",
title = Title("Services in OK state out of total"),
simple_lines=[ "num_services", "num_services_ok" ],
minimal_range=MinimalRange(0, 50),
)パラメータminimal_range は、メトリックの実際の値に関係なく、グラフの縦軸がカバーする最小範囲を表します。
値が最小範囲を超えた場合、縦軸は延長されますが、短くなることはありません。
その結果、Checkmk GUI に結合グラフが表示されます。

6.3. パーフオメーター内のメトリック
サービスリストの行に、メトリックのパーフオメーターを表示しますか? たとえば、次のように表示されます。

このようなパーフオメーターを作成するには、別のインスタンス、今回はPerfometer クラスで、名前がperfometer_ で始まるものが必要です。
perfometer_myhostgroups_advanced = Perfometer(
name = "myhostgroups_advanced",
focus_range = FocusRange(Closed(0), Closed(100)),
segments = [ "services_ok_perc" ],
)パーフオメーターは、凡例がないため、グラフよりも少し扱いが難しいです。 そのため、特に絶対値を表示する場合、値の範囲を表示するのが困難です。 パーセンテージを表示する方が簡単です。 上記の例も同様です。
メトリック名は
segmentsに入力します。この例では、OK 状態のサービスの割合です。下限値と上限値は、
focus_rangeに入力します。Closedの制限は、指定した制限 (ここでは0および100) の間の値しか受け付けないメトリック用です。
さらに、パーフオメーターでメトリックを実装するためのより高度なオプションは、Graphing API のドキュメントに記載されています。たとえば、Bidirectional およびStacked クラスを使用すると、複数のパーフオメーターを 1 つにまとめて表示することができます。
この章のグラフファイルはGitHub にあります。 このファイルには、4 つの測定値と 2 つの計算値のメトリック定義などが含まれています。
7. 数値のフォーマット
数値は、サービスのSummary およびDetails で出力されることがよくあります。
できるだけ簡単に、正確かつ見やすいフォーマットを行うため、
また、すべてのチェックプラグインの出力の標準化を図るため、さまざまなサイズの表示を行うヘルパー関数が用意されています。
これらはすべて、render モジュールのサブ関数であるため、render. で呼び出します。
たとえば、render.bytes(2000) と入力すると、1.95 KiB というテキストが表示されます。
これらの関数の共通点は、値が「標準単位」または「自然単位」で表示されることです。 これにより、変換時の混乱やエラーが発生しません。 例えば、時間は常に秒で表示され、ハードディスクやファイルのサイズは常にバイトで表示され、キロバイト、キビバイト、ブロックなどといった混乱を招く単位は使用されません。
表示があまり気に入らない場合でも、これらの関数を使用してください。 いずれにせよ、ユーザーにとっては標準化されます。 Checkmk の将来のバージョンでは、表示を変更したり、温度表示などと同様にユーザーが設定できるようにする機能も追加される可能性があります。 その場合は、チェックプラグインもこの機能を利用できるようになります。
チェックプラグインでrender 関数を使用するには、まずそれをインポートする必要があります。
from cmk.agent_based.v2 import renderすべての表示機能 (レンダリング機能) について詳しく説明した後、わかりやすい表形式で概要をまとめます。
7.1. 時間、時間範囲、頻度
絶対時間指定 (タイムスタンプ) は、render.date() またはrender.datetime() でフォーマットされます。
情報は常にUnix 時間、つまり 1970 年 1 月 1 日 00:00:00 UTC (Unix エポックの開始時刻) からの秒数で指定されます。
これは、Python 関数time.time() でも使用されるフォーマットです。
この表現の利点は、開始時間と終了時間がわかっている場合、時間範囲の計算など、計算が非常に簡単であることです。
式は、単にduration = end - start となります。
これらの計算は、タイムゾーン、夏時間、うるう年に関係なく機能します。
render.date() は日付のみを出力しますが、 は時刻も追加します。
出力は、チェックを実行している Checkmk サーバーが置かれている現在のタイムゾーンに従います。
例:render.datetime()
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
|
|
render.datetime(0) が時刻として00:00 ではなく01:00 を出力しても驚かないでください。
これは、このユーザーガイドがドイツのタイムゾーンで作成されているためです。ドイツのタイムゾーンは、標準の UTC 時刻より 1 時間進んでいます(少なくとも標準時刻はそうです。1 月 1 日は夏時間ではないため)。
時間範囲 (または時間間隔) には、render.timespan() 関数もあります。
この関数には、秒単位の継続時間が指定され、人間が読めるフォームで出力されます。
時間間隔が長い場合は、秒または分が省略されます。TimeDelta オブジェクトに時間間隔がある場合は、total_seconds() 関数を使用して、秒数を浮動小数点数として読み出してください。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
|
|
周波数は、事実上時間の逆数です。 標準単位はHz で、1 / 秒 (1 秒の逆数) と同じ意味です。 その使用例としては、CPU のクロックレートがあります。
| 呼び出し | 出力 |
|---|---|
|
|
7.2. バイト
ワーキングメモリー、ファイル、ハードディスク、ファイルシステムなどに関しては、標準的な単位はバイトです。 コンピュータは通常、このようなものを 2 のべき乗、たとえば 512、1024、65,536 バイト単位で整理するため、当初から 1 キロバイトは1000 ではなく、その 1000 倍である 1024 (2 の 10 乗) バイトと定義されました。 これは確かに非論理的ですが、通常は整数の数値になるため、非常に実用的です。 伝説的な Commodore C64 は、65,536 ではなく 64 キロバイトのメモリを搭載していました。
残念ながら、ある時点で、ハードディスクメーカーは、ディスクの容量を 1000 単位で指定するというアイデアを思いつきました。 1000と1024の差は各サイズで2.4%であり、これが乗算されるため、 1GB(1024×1024×1024)のディスクは突然1.07GBになります。 これが売れるからです。
この厄介な混乱は現在も続いており、エラーの原因となっています。 この問題を軽減するため、国際電気標準会議 (IEC) は、バイナリシステムに基づく新しい接頭辞を定義しました。 これによると、今日のキロバイトは正式には 1000 バイト、キビバイトは1024 バイト(2 の 10 乗)となります。 さらに、メビバイト、ギビバイト、テビバイトという表現も使用すべきです。 略語は、KiB、MiB、GiB、TiB となります。
Checkmk はこの規格に準拠しており、常に正しい出力を生成するための、さまざまなカスタマイズ可能なレンダリング機能を提供しています。
たとえば、ハードディスクおよびファイルシステム専用のrender.disksize() 関数では、出力を 1000 の累乗で生成します。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
ファイルのサイズに関しては、四捨五入せずに正確なサイズをバイト単位で指定するのが通例です。
この方法には、ファイルがわずかに変更された場合でも、2 つのファイルが(おそらく)同じであるかどうかをすぐに確認できるという利点があります。
この目的には、render.filesize() 関数を使用します。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
ハードディスクやファイルのサイズではない値を出力したい場合は、汎用のrender.bytes() を使用します。
これにより、公式表記の「クラシック」な1024の累乗形式で出力されます:
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
7.3. 帯域幅、データレート
ネットワーク技術者には、独自の用語や表現方法があります。 Checkmk は、常に各分野における従来の表現方法を採用するよう努めています。 そのため、データレートと速度には 3 種類のレンダリング関数があります。 これらに共通しているのは、実際の出力はビット単位であっても、レートは1 秒あたりのバイト数で渡されることです。
render.nicspeed() は、ネットワークカードまたはスイッチポートの最大速度を表します。
これらは測定値ではないため、四捨五入する必要はありません。
個々のビットを送信できるポートはありませんが、歴史的な理由から、データはビット単位で表示されます。
重要:ただし、ここでもバイト/秒を指定する必要があります!
| 呼び出し | Output |
|---|---|
|
|
|
|
render.networkbandwidth() は、ネットワークの実際の測定伝送速度用です。
入力値は、ここでも 1 秒あたりのバイト数です。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
ネットワークが関係せず、データレートが引き続き出力される場合、バイトが再び一般的になります。
最も顕著な例は、ハードディスクの IO レートです。
このためには、Checkmk で 1000 の累乗で機能するrender.iobandwidth() 関数を使用します。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
7.4. パーセンテージ
render.percent() 関数は、小数点以下 2 桁に四捨五入したパーセンテージを表します。
これは、実際の自然値(つまり比率)ではなく、実際のパーセンテージを渡すという点で、他の関数とは例外です。
たとえば、何かが半分いっぱいである場合は、0.5 ではなく、50 を渡す必要があります。
値がほぼゼロであるか、正確にゼロであるかを知ることは興味深い場合があるため、値が 0 より大きく 0.01% 未満の場合は、値に「<」文字を付加してマークします。
| 呼び出し | 出力 |
|---|---|
|
|
|
|
|
|
7.5. まとめ
最後に、すべてのレンダリング関数の概要を以下に示します。
| 関数 | 入力 | 説明 | 出力例 |
|---|---|---|---|
|
Unix時間 |
日付 |
|
|
Unix時間 |
日付と時刻 |
|
|
秒 |
期間 / 年数 |
|
|
Hz |
周波数(例:クロックレート) |
|
|
バイト |
ハードディスクのサイズ、1000を基数とする |
|
|
バイト |
ファイルのサイズ、完全精度 |
|
|
バイト |
サイズ、1024を基数とする |
|
|
秒あたりのバイト数 |
ネットワークカードの速度 |
|
|
バイト/秒 |
伝送速度 |
|
|
秒あたりのバイト数 |
IO 帯域幅 |
|
|
パーセンテージ |
パーセンテージ、意味のある丸め値 |
|
8. トラブルシューティング
エラーの正しい処理は(残念ながら)プログラミング作業の大部分を占めます。 幸い、Check API はエラー処理の多くの作業をすでに代行しています。 そのため、一部のエラータイプについては、自分で処理しないほうがよい場合もあります。
Python は、何らかの予期しない状況が発生すると、いわゆる例外で反応します。 以下に、その例をいくつか挙げます。
文字列を数値に変換する
int()を使用しますが、文字列に数値が含まれていない場合、例えばint("foo")の場合です。bar[4]を使用してbarの 5 番目のエレメントにアクセスしますが、このリストには 4 つのエレメントしか含まれていません。存在しない関数を呼び出しています。
エラーに対処する方法を決定するには、まず、エラーが発生したコードの正確な位置を知る必要があります。 これには、現在作業している場所に応じて、GUI またはコマンドラインのいずれかを使用できます。
8.1. GUI での例外とクラッシュレポート
Setup の監視またはサービスディスカバリー中に例外が発生した場合、Summary には、作成されたばかりのクラッシュレポートへの参照が含まれます。 たとえば、次のような表示になります。

アイコンをクリックすると、詳細ページが表示され、次の操作を行うことができます。
クラッシュが発生したファイルを確認できます。
プログラムで発生したエラーのリスト (トレースバック)、ローカル変数の現在の値、エージェントの出力など、クラッシュに関するすべての情報を受け取ることができます。
レポートをフィードバックとして弊社(Checkmk GmbH)に送信することができます。
トレースバックは、開発者として、プログラムにエラーがあるかどうか(たとえば、存在しない関数の呼び出しなど)、またはエージェントデータが予想どおりに処理できなかったかどうかを判断するのに役立ちます。 前者の場合はエラーを修正し、後者の場合は多くの場合、何もしないことが妥当です。
レポートの送信は、もちろん Checkmk の公式プラグインであるチェックプラグインにのみ有用です。 独自のプラグインをサードパーティに提供している場合は、ユーザーにデータの送信を依頼してください。
8.2. コマンドラインでの例外の表示
コマンドラインからチェックプラグインを実行した場合、生成されたクラッシュレポートの ID は表示されません。 要約されたエラーメッセージのみが表示されます。
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced localhost
Error in agent based plugin myhostgroups: invalid syntax (myhostgroups.py, line 11)--debug オプションを追加の呼び出しパラメータとして追加すると、Python インタープリタからのトレースバックが表示されます。
OMD[mysite]:~$ cmk --debug --detect-plugins=myhostgroups_advanced localhost
Traceback (most recent call last):
File "/omd/sites/mysite/lib/python3/cmk/discover_plugins/_python_plugins.py", line 195, in add_from_module
module = importer(mod_name, raise_errors=True)
^^^^^^^^^^^^^
File "/omd/sites/mysite/lib/python3/cmk/discover_plugins/_python_plugins.py", line 156, in _import_optionally
return importlib.import_module(module_name)
^^^^^^^^^^^^
File "/omd/sites/mysite/lib/python3.12/importlib/init.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 995, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "/omd/sites/mysite/local/lib/python3/cmk_addons/plugins/myhostgroups/agent_based/myhostgroups.py", line 110, in <module>
agent_section_myhostgroups == AgentSection(
^^^^^^^^^^
NameError: name 'agent_section_myhostgroups' is not definedたとえば、新しいエージェント出力が利用可能になったために、次回--debug を呼び出してもエラーが発生しない場合は、ファイルシステムで最後のクラッシュレポートを表示することもできます。
OMD[mysite]:~$ ls -lhtr ~/var/check_mk/crashes/check/ | tail -n 5
drwxrwxr-x 2 mysite mysite 4.0K Aug 6 17:56 7b59a49e-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug 6 17:56 7c8870c0-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug 6 17:56 7cf9626c-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug 6 17:56 7d192d68-540c-11ef-9595-7574c603ce8d/
drwxrwxr-x 2 mysite mysite 4.0K Aug 6 17:56 7e2d5ec2-540c-11ef-9595-7574c603ce8d/これらのフォルダにはそれぞれ 2 つのファイルがあります。
crash.infoには、トレースバックやその他の多くの情報を含む Python 辞書が含まれています。多くの場合、Pager でこのファイルを一目見れば十分です。agent_outputには、クラッシュ時のエージェントの出力全体が含まれています。
8.3. カスタムデバッグ出力
上記の例では、print() 関数を使用して、開発者であるユーザーの変数の内容やオブジェクトの構造を出力しています。
デバッグ出力用のこれらの関数は、完成したチェックプラグインから削除する必要があります。
削除の代わりに、チェックプラグインがデバッグモードでコンソールから呼び出された場合にのみ、デバッグ出力を表示することもできます。
これを行うには、Checkmk ツールボックスからデバッグオブジェクトをインポートし、必要に応じて、pprint() フォーマット補助機能をインポートします。
これで、デバッグオブジェクトの値に応じてデバッグ出力を生成することができます。
デバッグオブジェクトは、Checkmk2.3.0 と2.4.0 間でパスが変更されました。
以前の場所 |
try:
from cmk.ccc import debug
except ImportError:
from cmk.utils import debug
from pprint import pprint
def check_mystuff(section):
if debug.enabled():
pprint(section)残りのデバッグ出力は、後続のユーザーのデバッグに役立つヒントに限定して、控えめに使用してください。 明らかで予測可能なユーザーエラー(たとえば、エージェントセクションの内容が、エージェントプラグインが正しく設定されていないことを示している場合など)は、UNKNOWN状態で応答し、概要に説明文を含めてください。
8.4. 無効なエージェント出力
エージェントからの出力が、Checkmk エージェントからのものか、SNMP 経由で受信したものかに関わらず、実際に期待したフォームではない場合、どのように対応すべきかが問題になります。 1 行に 3 語が常に含まれると予想している場合、2 語しか含まれていない場合はどうすればよいでしょうか?
これは、エージェントによって許可され、既知の動作である場合は、もちろんこれをインターセプトして、ケースの区別を行って対応する必要があります。 しかし、実際には許可されていない場合は、たとえば次の解析関数を使用して、行は常に 3 つの単語で構成されているかのように動作するのが最善です。
def parse_foobar(string_table):
for foo, bar, baz in string_table:
# ...3 つの単語で構成されていない行がある場合、例外が発生し、前述の非常に役立つクラッシュレポートが送信されます。
辞書内で、時折欠落することが予想されるキーにアクセスする場合、当然、それに応じて対応することが理にかなっています。
これは、サービスを「CRIT 」または「UNKNOWN」に設定し、評価できないエージェント出力に関する注記を要約に記述することで実現できます。
いずれの場合も、KeyError 例外をキャッチするよりも、辞書のget() 関数を使用したほうがよいでしょう。
これは、get() は、キーが存在しない場合、None 型のオブジェクトまたは第2パラメーターとして渡すためのオプションの置換オブジェクトを返すためです:
def check_foobar(section):
foo = section.get("bar")
if not foo:
yield Result(state=State.CRIT, summary="Missing key in section: bar")
return
# ...8.5. 項目がない場合
エージェントが正しいデータを出力しても、チェックする項目が欠落している場合はどうなりますか? たとえば、次のような場合です。
def check_foobar(item, section):
# Try to access the item as key in the section:
foo = section.get(item)
if foo:
yield Result(state=State.OK, summary="Item found in monitoring data")
# If foo is None, nothing is yielded here探している項目が含まれていない場合、ループが実行され、Python はyield によって結果を返すことなく、関数の最後に単純に終了します。
これはまさに正しい動作です。
Checkmk は、監視対象の項目が欠落していることを認識し、UNKNOWN を使用して正しいステータスと適切な標準テキストを生成します。
8.6. スプールファイルを使用したテスト
特定のエージェント出力をシミュレートしたい場合は、スプールディレクトリ内のファイルが非常に役立ちます。 これを使用して、他の方法では再現が難しい境界例をテストすることができます。 または、クラッシュレポートの原因となったエージェント出力を直接使用して、チェックプラグインの変更をテストすることもできます。
まず、通常使用しているエージェントプラグインを、その実行認可を取り消すなどして無効にします。
次に、/var/lib/check_mk_agent/spool/ ディレクトリに、チェックプラグインが期待するエージェントセクション(または予想されるエージェントセクション)を含むファイルを作成します。このファイルには、セクションヘッダーを含め、改行で終了してください。
次回エージェントが呼び出されると、エージェントプラグインからの出力ではなく、スプールファイルの内容が転送されます。
8.7. 古いチェックプラグインが多くのサービスで遅くなる
項目を使用する一部のチェックプラグインでは、大規模なサーバーで数百のサービスが生成される可能性があります。 個別の解析関数を使用しない場合、数百行のリスト全体を、数百の項目それぞれについて実行する必要があります。 そのため、検索に必要な時間は、リストされた項目の数の 2 乗だけ増加し、数百のサービスでは数万回の比較が必要になります。 一方、ネストされたリストを辞書に転送すると、エレメントの検索に必要な時間は、辞書のサイズに比例して直線的に増加します。
Python wiki には、説明とO 表記を含む、さまざまなデータ型での検索のコストの概要が記載されています。 parse 関数を使用すると、検索の複雑さがO(n)からO(1) に減少します。
この記事の古いバージョンでは parse 関数を使用していなかったため、そのようなチェックプラグインを特定し、parse 関数を使用するように書き直してください。
9. 移行
Checkmk バージョン2.0.0 で導入された Check API V1 は、バージョン2.3.0 までサポートされていましたが、現在のバージョン2.4.0 ではサポートされなくなりました。 チェックプラグインを引き続き使用するには、2.3.0 のまま、新しい API に移行する必要があります。
チェックプラグインを Check API V1 から V2 へ移行するには、以下の情報が役立ちます。
すべてのプラグイン API のファイルを保存するための新しいディレクトリ構造および命名規則は、メインページCheckmk’s Plug-in APIs のAPI ドキュメントに記載されています。
Check API V2 の変更点の要約は、API ドキュメントのCheckmk’s Plug-in APIs > Agent based ('Check API') > Version 2 > New in this version にも記載されています。 また、既存のチェックプラグイン
aptを Check API V2 に移行する GitHub コミットへのリンクも記載されています。GitHubでは、Checkmk の
treasuresディレクトリに、新しい API への移行に役立つスクリプトがあります。
|
10. ファイルとディレクトリ
| ファイルパス | 説明 |
|---|---|
|
プラグインファイルを保存するためのベースディレクトリ。 |
|
Check API V2 に従って作成されたチェックプラグインの保存場所です。 |
|
Rulesets API に基づいて作成されたルールセットファイルの保存場所です。 |
|
Graphing API に基づいて作成されたグラフファイルの保存場所です。 |
|
このディレクトリは、監視対象の Linux ホスト上にあります。Linux 用の Checkmk エージェントは、このディレクトリにエージェントの拡張機能 (エージェントプラグイン) があります。 |
