見出し画像

TWSNMPのコマンド実行ポーリング機能

ポーリング機能の改善という目標の第二弾としてコマンドを実行した結果でノードの状態を判断するポーリング機能を付けた時の話です。この機能をつけることで監視する方法の自由度が格段に高くなります。誰でも好きな監視方法をTWSNMPに追加できるということです。猫は私を監視するためのスクリプトを書きたいのかもしれません。(自分が寝るため)

コマンド実行の落とし穴

GO言語からコマンドを実行するためには標準パッケージ

が使えます。

import (
	"fmt"
	"log"
	"os/exec"
)

func main() {
	cmd := exec.Command("実行したいコマンド", "パラメータ"...)
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", stdoutStderr)
}

のようにすればよいだけです。この方法で定期に設定したコマンドを実行すれば目的は達成できます。
ここまでは簡単に思いつくことで若い頃ならこれで完成と思っていたことでしょう。でも、安易な作り方で随分痛い目にあってきた経験があるのでもう少し考えました。昔より心配性なのです。実行したコマンドがいつまでも終わらないとどうなるか?まずいことに定期的に実行したコマンドがどんどん溜まっていってメモリ不足でTWSNMPだけでなく実行しているパソコンすら危うい状態にするかもしれません。
では、どうするか?
方法は2つ考えられます。

・前のコマンドを実行中は次のコマンドを実行しない。
・一定時間コマンドが終了しなければ諦める。

1つ目の方法は一見よさそうですが落とし穴があります。同じように終わらないコマンドを実行するポーリングが沢山あるとやっぱり実行中のコマンドが溜まっていく問題が発生します。ということでコマンドの実行は一定時間に制限する方法にしました。

タイムアウト付きのコマンド実行

コマンドの実行時間を制限する処理をどうするか?自分で作るのは最後の手段としてまずはGO言語のパッケージを探しました。Googleに聞いてみるキーワードは「golang  exec timeout」です。いくつかみつかります。

なるほど、作り方はわかりますがちょっと面倒そう。
よいものがありました。しかも日本語のページ

GO言語のパッケージは、

にあります。これを使えば

tio := &timeout.Timeout
{
	Cmd:            exec.Command("実行したいコマンド", "パラメータ"...),
	Duration:       10 * time.Second, // 実行の制限時間
	KillAfter:      5 * time.Second,  // プロセスを強制終了する時間
}
exitStatus, stdout, stderr, err := tio.Run() // 実行結果のコードと出力が取得できます。

のように作れます。すばらしい。私の要望にピッタリです。ありがとう。

ということで、この問題を解決しました。


開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。