Solaris ボリュームマネージャの管理

cron ジョブによる Solaris ボリュームマネージャの監視

Procedureボリュームのエラーを自動的にチェックするには

手順

    Solaris ボリュームマネージャ構成のエラーを自動的にチェックするために、cron ユーティリティで定期的に実行できるスクリプトを作成します。

    次のスクリプト例は、必要に応じて変更することができます。


    このスクリプトは、Solaris ボリュームマネージャのエラーチェック機能を自動化するための基本的なスクリプトです。 独自の構成に合わせて変更する必要があります。


    #
    #ident "@(#)metacheck.sh   1.3     96/06/21 SMI"
    #!/bin/ksh
    #!/bin/ksh -x
    #!/bin/ksh -v
    # ident='%Z%%M%   %I%     %E% SMI'
    #
    # Copyright (c) 1999 by Sun Microsystems, Inc.
    #
    # metacheck
    #
    # メタデバイス構成の状態をチェックする。問題がある場合は、
    # ゼロ以外の終了コードを返す。オプションに応じて e メール通知を送信する。
    #
    # -h
    #	ヘルプ
    # -s setname
    #	チェックするセットを指定する。デフォルトでは「local」セットがチェックされる。
    # -m recipient [recipient...]
    #	指定された受信者に e メール通知を送信する。これは
    #	最後の引数でなければならない。この通知は簡単な e メールメッセージ
    #	として送信される。その件名は次のとおり。
    #		"Solaris Volume Manager Problem: metacheck.who.nodename.setname"
    #	これには、問題の要約と詳しい情報の入手方法が示されている。
    #	「setname」は -s オプションから、「who」は 
    #	-w オプションからそれぞれとられ、「nodename」は uname(1) によって報告される。
    #	e メール通知は次のオプションによっても影響される。
    #		-f	問題が検出された後の追加メッセージを抑制する
    #		-d	抑制を制御する
    #		-w	だれが e メールを生成したのかを示す
    #		-t	問題がないときでも e メールを強制的に送る
    # -w who
    #	だれがコマンドを実行しているのかを示す。デフォルトでは、これは
    #	id(1M) によって報告される user-name である。これは、
    #	e メール通知を送信する (-m) ときに使用される。
    # -f 
    #	フィルタ機能を有効にする。フィルタ機能は e メール通知 (-m) に適用される。
    #	フィルタ機能にはルート権限が必要。e メール通知を送信するときに、
    #	 /etc/lvm/metacheck.setname.pending ファイルを使って 
    #	フィルタを制御する。次のマトリクスは
    #	フィルタの動作を指定する。
    #
    #      問題の発見     ファイルあり
    #         yes             no                 ファイルを作成し、通知を送信する。
    #         yes             yes                現在の日付 (-d datefmt で指定された) が
    #                                            ファイルの日付と異なる場合は、
    #                                            通知を再び送信する。
    #         no              yes                ファイルを削除し、問題が解決したことを示す
    #                                            通知を送信する。
    #         no              no                 -t が指定されている場合は、通知を送信する。
    #	
    # -d datefmt
    #	フィルタ機能 (-f) の日付形式を指定する。このオプションは、
    #	e メールで通知を再送する頻度を制御する。 
    #	指定された形式 (strftime(3C)) に基づく現在の日付が
    #	/etc/lvm/metacheck.setname.pending ファイルに含まれている日付
    #	と同じなら、メッセージは抑制される。
    #	デフォルトの日付形式は「%D」で、通知を 1 日に 1 回再送する
    #	ことを意味する。
    # -t
    #	テストモード。問題がない場合でも、e メールの生成を有効にする。
    #	この機構や e メールアドレスを全体的に確認するときに使用する。
    #	
    #
    # 次のオプションは、メタチェックを crontab に組み込む。
    # たとえば、次の root crontab エントリがあるとする。
    #
    # 0,15,30,45 * * * * /usr/sbin/metacheck -f -w SVMcron \
    #   -d '\%D \%h' -m notice@example.com 2148357243.8333033@pager.example.com
    #
    # 15 分ごとに問題をチェックし、問題がある場合には、1 時間ごとに
    # e メールを notice@example.com 宛てに生成する (そして、e メール
    # ページャサービスに送信する)。crontab エントリの「%」文字の前にある \ に注意。
    # 戻ってくる e メールは root@nodename に返される。
    # 上の行によって生成される e メールメッセージの件名は次のようになる。
    # Solaris Volume Manager Problem: metacheck.SVMcron.nodename.local
    #
    
    # 制御端末にデバッグ行を表示する (一連のパイプとして動作)。
    decho()
    {
        if [ "$debug" = "yes" ] ; then
    	echo "DEBUG: $*"	 /dev/null> /dev/tty 2>1
        fi
    }
    
    # $1 文字列が $2-* に含まれる場合は $1 を返す。それ以外の場合は "" を返す。
    strstr()
    {
        typeset	look="$1"
        typeset	ret=""
    
        shift
    #   decho "strstr LOOK .$look. FIRST .$1."
        while [ $# -ne 0 ] ; do
    	if [ "$look" = "$1" ] ; then
    	    ret="$look"
    	fi
    	shift
        done
        echo "$ret"
    }
    
    # $1 文字列が $2-* に含まれる場合は、削除して結果を返す。
    strdstr()
    {
        typeset	look="$1"
        typeset	ret=""
    
        shift
    #   decho "strdstr LOOK .$look. FIRST .$1."
        while [ $# -ne 0 ] ; do
    	if [ "$look" != "$1" ] ; then
    	    ret="$ret $1"
    	fi
    	shift
        done
        echo "$ret"
    }
    
    merge_continued_lines()
    {
        awk -e '\
    	BEGIN { line = "";} \
    	$NF == "\\" { \
    	    $NF = ""; \
    	    line = line $0; \
    	    next; \
    	} \
    	$NF != "\\" { \
    	    if ( line != "" ) { \
    		print line $0; \
    		line = ""; \
    	    } else { \
    		print $0; \
    	    } \
    	}'
    }
    
    # メタデバイスと関係ない部分を破棄する。
    find_meta_devices()
    {
        typeset	devices=""
    
    #   decho "find_meta_devices .$*."
        while [ $# -ne 0 ] ; do
    	case $1 in
    	d+([0-9]) )	# メタデバイス名
    	    devices="$devices $1"
    	    ;;
    	esac
    	shift
        done
        echo "$devices"
    }
    
    # トップレベルのメタデバイスのリストを返す。
    toplevel()
    {
        typeset	comp_meta_devices=""
        typeset	top_meta_devices=""
        typeset	devices=""
        typeset	device=""
        typeset	comp=""
    
        metastat$setarg -p | merge_continued_lines | while read line ; do
    	echo "$line"
    	devices=find_meta_devices $line
    	set -- $devices
    	if [ $# -ne 0 ] ; then
    	    device=$1
    	    shift
    	    # デバイスがコンポーネントとしてすでに参照されているかチェックする。
    	    comp=strstr $device $comp_meta_devices
    	    if [ -z $comp ] ; then 
    		top_meta_devices="$top_meta_devices $device"
    	    fi
    	    # コンポーネントリストにコンポーネントを追加し、トップリストから削除する。
    	    while [ $# -ne 0 ] ; do
    		comp=$1
    		comp_meta_devices="$comp_meta_devices $comp"
    		top_meta_devices=strdstr $comp $top_meta_devices
    		shift
    	    done
    	fi
        done> /dev/null 2>1
        echo $top_meta_devices
    }
    
    #
    # - MAIN
    #
    METAPATH=/usr/sbin
    PATH=//usr/bin:$METAPATH
    USAGE="usage: metacheck [-s setname] [-h] [[-t] [-f [-d datefmt]] \
        [-w who] -m recipient [recipient...]]"
    
    datefmt="%D"
    debug="no"
    filter="no"
    mflag="no"
    set="local"
    setarg=""
    testarg="no"
    who=id | sed -e 's/^uid=[0-9][0-9]*(//' -e 's/).*//'
    
    while getopts d:Dfms:tw: flag
    do
        case $flag in
        d)	datefmt=$OPTARG;
    	;;
        D)	debug="yes"
    	;;
        f)	filter="yes"
    	;;
        m)	mflag="yes"
    	;;
        s)	set=$OPTARG;
    	if [ "$set" != "local" ] ; then
    		setarg=" -s $set";
    	fi
    	;;
        t)	testarg="yes";
    	;;
        w)	who=$OPTARG;
    	;;
        \?)	echo $USAGE
    	exit 1
    	;;
        esac
    done
    
    # mflag が指定されている場合は、他のすべての部分が受信者に属す。
    shift expr $OPTIND - 1
    if [ $mflag = "no" ] ; then
        if [ $# -ne 0 ] ; then 
    	echo $USAGE
    	exit 1
        fi
    else
        if [ $# -eq 0 ] ; then 
    	echo $USAGE
    	exit 1
        fi
    fi
    recipients="$*"
    
    curdate_filter=date +$datefmt
    curdate=date
    node=uname -n
    
    # ファイルを確立する。
    msg_f=/tmp/metacheck.msg.$$
    msgs_f=/tmp/metacheck.msgs.$$
    metastat_f=/tmp/metacheck.metastat.$$
    metadb_f=/tmp/metacheck.metadb.$$
    metahs_f=/tmp/metacheck.metahs.$$
    
    pending_f=/etc/lvm/metacheck.$set.pending 
    files="$metastat_f $metadb_f $metahs_f $msg_f $msgs_f"
    
    rm -f $files							> /dev/null 2>1
    trap "rm -f $files> /dev/null 2>1; exit 1" 1 2 3 15
    
    # metadb が動作可能かチェックする。
    have_metadb="yes"
    metadb$setarg 							> $metadb_f 2>1
    if [ $? -ne 0 ] ; then
        have_metadb="no"
    fi
    grep "there are no existing databases"  	 $metadb_f	> /dev/null 2>1
    if [ $? -eq 0 ] ; then
        have_metadb="no"
    fi
    grep "/dev/md/admin"				 $metadb_f	> /dev/null 2>1
    if [ $? -eq 0 ] ; then
        have_metadb="no"
    fi
    
    # metadb のアクセスに問題がないかチェックする。
    retval=0
    if [ "$have_metadb" = "no" ] ; then
        retval=1
        echo "metacheck: metadb problem, can't run '$METAPATH/metadb$setarg'" \
    								>> $msgs_f
    else
        # 状態のスナップショット
        metadb$setarg 2>1 | sed -e '1d' | merge_continued_lines	> $metadb_f
        metastat$setarg 2>1 | merge_continued_lines		> $metastat_f
        metahs$setarg -i 2>1 | merge_continued_lines		> $metahs_f
    
        #
        # 複製の問題をチェックする。フラグの中の大文字は
        # エラーを意味する。フィールドはタブで区切られる。
        #
        problem=awk  $metadb_f -F\t '{if ($1  /[A-Z]/) print $1;}'
        if [ -n "$problem" ] ; then
    	retval=expr $retval + 64
    	echo "\
    metacheck: metadb problem, for more detail run:\n\t$METAPATH/metadb$setarg -i" \
    								>> $msgs_f
        fi
    
        #
        # メタデバイスの状態をチェックする。
        #
        problem=awk  $metastat_f -e \
    		'/State:/ {if ($2 != "Okay"  $2 != "Resyncing") print $0;}'
        if [ -n "$problem" ] ; then
    	retval=expr $retval + 128
    	echo "\
    metacheck: metadevice problem, for more detail run:" \
    								>> $msgs_f
    
    	# 問題があるトップレベルメタデバイスへのメッセージの精度を高める。
    	top=toplevel
    	set -- $top
    	while [ $# -ne 0 ] ; do
    	    device=$1
    	    problem=metastat $device | awk -e \
    		'/State:/ {if ($2 != "Okay"  $2 != "Resyncing") print $0;}'
    	    if [ -n "$problem" ] ; then
    		echo "\t$METAPATH/metastat$setarg $device"	>> $msgs_f
    		# デバイスに何がマウントされているかを調べる。
    		mp=mount|awk -e '/\/dev\/md\/dsk\/'$device'[ \t]/{print $1;}'
    		if [ -n "$mp" ] ; then
    		    echo "\t\t$mp mounted on $device"		>> $msgs_f
    		fi
    	    fi
    	    shift
    	done
        fi
    
        #
        # ホットスペアが使用されているかチェックする。
        #
        problem=""
        grep "no hotspare pools found"	 $metahs_f		> /dev/null 2>1
        if [ $? -ne 0 ] ; then
    	problem=awk  $metahs_f -e \
    	    '/blocks/ { if ( $2 != "Available" ) print $0;}'
        fi
        if [ -n "$problem" ] ; then
    	retval=expr $retval + 256
    	echo "\
    metacheck: hot spare in use, for more detail run:\n\t$METAPATH/metahs$setarg -i" \
    								>> $msgs_f
        fi
    fi
    
    # エラーが発生している場合は、レポートを送信する。
    if [ $retval -ne 0 ] ; then
        if [ -n "$recipients" ] ; then 
    	re=""
    	if [ -f $pending_f ]  [ "$filter" = "yes" ] ; then
    	    re="Re:"
    	    # 保留された通知がある。日付をチェックして再送するか決める。
    	    penddate_filter=cat $pending_f | head -1
    	    if [ "$curdate_filter" != "$penddate_filter" ] ; then
    		rm -f $pending_f				> /dev/null 2>1
    	    else
    	 	if [ "$debug" = "yes" ] ; then
    		    echo "metacheck: email problem notification still pending"
    		    cat $pending_f
    		fi
    	    fi
    	fi
    	if [ ! -f $pending_f ] ; then
    	    if [ "$filter" = "yes" ] ; then
    		echo "$curdate_filter\n\tDate:$curdate\n\tTo:$recipients" \
    								> $pending_f
    	    fi
    	    echo "\
    Solaris Volume Manager: $node: metacheck$setarg: Report: $curdate"		>> $msg_f
    	    echo "\
    --------------------------------------------------------------">> $msg_f
    	    cat $msg_f $msgs_f | mailx -s \
    		"${re}Solaris Volume Manager Problem: metacheck.$who.$set.$node" $recipients
    	fi
        else
    	cat $msgs_f
        fi
    else
        # 問題は検出されていない。
        if [ -n "$recipients" ] ; then
    	# デフォルトでは、メールを送信しない。また、何も印刷しない。
    	echo "\
    Solaris Volume Manager: $node: metacheck$setarg: Report: $curdate"		>> $msg_f
    	echo "\
    --------------------------------------------------------------">> $msg_f
    	if [ -f $pending_f ]  [ "$filter" = "yes" ] ; then
    	    # 保留されたフィルタが存在する。削除し、OK を送信する。
    	    rm -f $pending_f					> /dev/null 2>1
    	    echo "Problem resolved"				>> $msg_f
    	    cat $msg_f | mailx -s \
    		"Re: Solaris Volume Manager Problem: metacheck.$who.$node.$set" $recipients
    	elif [ "$testarg" = "yes" ] ; then
    	    # テストのため、問題がなくても、毎回、メールを送信する。
    	    echo "Messaging test, no problems detected"		>> $msg_f
    	    cat $msg_f | mailx -s \
    		"Solaris Volume Manager Problem: metacheck.$who.$node.$set" $recipients
    	fi
        else
    	echo "metacheck: Okay"
        fi
    fi
    
    rm -f $files							> /dev/null 2>1

    cron ユーティリティを使ってスクリプトを起動する手順については、cron(1M) のマニュアルページを参照してください。