Bashの空き領域監視サービス

こんにちは 次の自転車産業についてお話ししたいと思います。 Habrを見ると、 Bash:子プロセスでデーモンを起動するというすばらしい記事に出会いました。 アイデアを読んだ後、それがなければどこにあるのでしょうか?



入門:


OS: Astra Linux 1.2(1.3)



序文から2つの結論が続きます。



  1. 認定されていないソフトウェアをインストールすることはできません。インストールしないと、2つの方向(顧客と管理)から猛烈な被害が発生します。
  2. なぜなら 私たちは真の先駆者であり、簡単な方法を探していません。その場合、dfコマンドの出力は興味を持ちません。


bashでデーモンを構築する主なポイントについては説明しません。これは上記の記事で完全に説明されているため、実際に作業を始めます:)。



最初に、使用する変数を示します。



#        PID_FILE="/run/ac_check_disk_space.pid" LOG_FILE="/var/log/ac_check_disk_space.log" #   #       : # s -  # m -  # h -  # d -  #    ,      CHECK_PERIOD="1m" #  : #  :      #    2 : # CHECK_DISKS=('/dev/sda1:10G' '/dev/sda3:10G') #       : # K -  # M -  # G -  #    ,      CHECK_DISKS=('/dev/sda1:10G' '/dev/sda3:10G') #  : # :host: -   # :disk: -   # :mount_point: -   # :disk_total: -    # :disk_avaiable: -     # :disk_checked_size: -    MAIL_SUBJECT_TEMPLATE="ACHTUNG: :host: low disk space on :disk: mounted to :mount_point:!" MAIL_BODY_TEMPLATE="Details: Total disk size :disk_total:, Avaiable size: :disk_avaiable:, Trigger size: :disk_checked_size:" MAIL_RCPT=('somebody@domain.ru')
      
      





なぜなら dfは私たちに興味がないので、 statを介してファイルシステムの状態に関する情報を取得できます。 ただし、このためには、このファイルシステムがマウントされているディレクトリを知る必要があります。 このデータは/ proc / mountsファイルに保存されますが、わずかな問題があります。ディスク名は、通常のデバイス名(/ dev / sda1など)とデバイスのUUID(ohm)(/ dev / disk / by-uuidなど)の両方で表すことができます/ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。 これらすべてを神の形にするために、 blkidユーティリティ(ロケール/印刷ブロックデバイス属性)が役立ちます。



したがって、 start()関数の入力を開始します。ルートからの起動の確認とプロセスの2番目のコピーの確認は省略し、デバイス名をマウントポイントに一致させるための辞書のコンパイルに直接進みます。



 #       UUID disks=$(blkid | grep -v swap | awk '{print $1}' | sed -es/://) uuids=$(blkid | grep -v swap | awk '{print $1}' | sed -es/UUID=// | sed -es/\*//g) #        mounts=() #      for (( i=0; i<${#disks[*]}; i++ )); do mount_point=( `cat /proc/mounts | grep ${disks[$i]} | awk '{print $2}'` ) if [[ ! -z $mount_point ]]; then mounts=("${mounts[@]}" "${disks[$i]}:$mount_point") fi done #    UUID for (( i=0; i<${#uuids[*]}; i++ )); do mount_point=( `cat /proc/mounts | grep ${uuids[$i]} | awk '{print $2}'` ) if [[ ! -z $mount_point ]]; then disk=`blkid -U ${uuids[$i]}` mounts=("${mounts[@]}" "$disk:$mount_point") fi done # ,              exists=0 checked_disks=() for mount in "${mounts[@]}"; do mount_disk="${mount%%:*}" for check in "${CHECK_DISKS[@]}"; do check_disk="${check%%:*}" if [ $check_disk == $mount_disk ]; then check_size="${check##*:}" size=$(calculate_space_prefix $check_size) checked_disks=("${checked_disks[@]}" "$check_disk:$size") exists=1 fi done done if [ $exists -eq 0 ]; then echo "Can not find disks, please check your configuration file" exit 1 fi
      
      





設定ファイルでわかるように、チェックされたディスクパーティションの配列である変数CHECK_DISKSがあります。 パニックが必要なサイズは、人間が理解できる形式で示されます 。転送には、関数compute_space_prefixを使用します。 関数はサイズとプレフィックスを受け取り、このエコノミーをバイトに変換します。



 function calculate_space_prefix() { local value=$1 local result=$2 local size=0 local prefix="" prefix="${value: -1}" len="${#value}" len=$(($len - 1)) size="${value:0:$len}" case $prefix in "K") size=$(($size * 1024)) ;; "M") size=$(($size * 1048576)) ;; "G") size=$(($size * 1073741824)) ;; *) #size=$(($size * 1073741824)) ;; esac echo $size }
      
      





次に、メインループについて考えます。 その中で、 checked_disks配列を調べます。この配列では、セクションが示され、必要な値よりも小さい空き領域のしきい値が激しくヒットします。 前述のように、セクションに関する情報を取得するにはstatコマンドを使用しますが、次の構文が必要です。



 stat -f < > -c "%b %a %s" # : # %b -        # %a -   ,     # %s -  
      
      





ユーザーがパーティション上のスペースを使い果たしているという幸福の手紙を受け取ったときに、電卓に座って読みやすい形式でバイトを再カウントすることを望まない場合は、別の関数を記述します。



 function calculate_return_space_prefix() { local value=$1 local space=$2 local size=0 prefix="${value: -1}" case $prefix in "K") size=$(($space / 1024)) ;; "M") size=$(($space / 1048576)) ;; "G") size=$(($space / 1073741824)) ;; *) ;; esac echo $size }
      
      





ご覧のとおり、これは同じ関数calculate_space_prefixであり、その反対です。



これで、すべてがメインサービスサイクルの準備ができました。 そこには十分なコメントはありませんが、それらがなければ基本的な原則は明確だと思います:チェック、チェック、もう一度チェックしてから、手紙を書きます。



 #   while [ 1 ]; do for checked in "${checked_disks[@]}"; do checked_disk="${checked%%:*}" checked_size="${checked##*:}" for mount in "${mounts[@]}"; do mount_disk="${mount%%:*}" mount_point="${mount##*:}" if [ $mount_disk == $checked_disk ]; then disk_all=( `stat -f $mount_point -c "%b"` ) disk_avaiable=( `stat -f $mount_point -c "%a"` ) disk_block_size=( `stat -f $mount_point -c "%s"` ) disk_all=$(($disk_all * $disk_block_size)) disk_avaiable=$(($disk_avaiable * $disk_block_size)) if [ $disk_avaiable -le $checked_size ]; then _log "Low disk size on $checked_disk mounted to $mount_point. Total size: $disk_all, avaiable size: $disk_avaiable, trigger size: $checked_size." #      for check in "${CHECK_DISKS[@]}"; do check_disk="${check%%:*}" check_size="${check##*:}" if [ $check_disk == $checked_disk ]; then disk_all=$(calculate_return_space_prefix $check_size $disk_all) disk_avaiable=$(calculate_return_space_prefix $check_size $disk_avaiable) checked_size=$(calculate_return_space_prefix $check_size $checked_size) prefix="${check_size: -1}" fi done subject=`echo -e ${MAIL_SUBJECT_TEMPLATE} | sed -e "s|:host:|$host|g" | sed -e "s|:disk:|$checked_disk|g" | sed -e "s|:mount_point:|$mount_point|g" | sed -e "s|:disk_total:|${disk_all}${prefix}|g" | sed -e "s|:disk_avaiable:|${disk_avaiable}${prefix}|g" | sed -e "s|:disk_checked_size:|${checked_size}${prefix}|g"` body=`echo -e ${MAIL_BODY_TEMPLATE} | sed -e "s|:host:|$host|g" | sed -e "s|:disk:|$checked_disk|g" | sed -e "s|:mount_point:|$mount_point|g" | sed -e "s|:disk_total:|${disk_all}${prefix}|g" | sed -e "s|:disk_avaiable:|${disk_avaiable}${prefix}|g" | sed -e "s|:disk_checked_size:|${checked_size}${prefix}|g"` for rcpt in "${MAIL_RCPT[@]}"; do echo "$body" | mail -s "$subject" "$rcpt" done fi fi done done sleep "${CHECK_PERIOD}" done
      
      





誰かが興味を持っている場合、ネタバレの下でサービスの完全なリスト

全リスト
 #!/usr/bin/env bash set -e set -m ### BEGIN INIT SCRIPT # Provides: ac_check_disk_space # Required-Start: $local_fs $syslog # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: ac_check_disk_space # Description: Service to monitoring disk space for Astra Linux ### END INIT SCRIPT usage() { echo -e "Usage:\n$0 (start|stop|restart)" } _log() { #     #shift ts=`date +"%b %d %Y %H:%M:%S"` hn=`cat /etc/hostname` echo "$ts $hn ac_check_disk_space[${BASHPID}]: $*" } check_conf_file() { if [ -e "/etc/ac/check_disk_space.conf" ]; then source "/etc/ac/check_disk_space.conf" else echo "Can not find configuration file (/etc/ac/check_disk_space.conf)" exit 0 fi } function calculate_space_prefix() { local value=$1 local result=$2 local size=0 local prefix="" prefix="${value: -1}" len="${#value}" len=$(($len - 1)) size="${value:0:$len}" case $prefix in "K") size=$(($size * 1024)) ;; "M") size=$(($size * 1048576)) ;; "G") size=$(($size * 1073741824)) ;; *) #size=$(($size * 1073741824)) ;; esac echo $size } function calculate_return_space_prefix() { local value=$1 local space=$2 local size=0 prefix="${value: -1}" case $prefix in "K") size=$(($space / 1024)) ;; "M") size=$(($space / 1048576)) ;; "G") size=$(($space / 1073741824)) ;; *) ;; esac echo $size } start() { #trap 'echo "1" >> /tmp/test' 1 2 3 15 #     if [ $UID -ne 0 ]; then echo "Root privileges required" exit 0 fi #    check_conf_file #     if [ -e ${PID_FILE} ]; then _pid=( `cat ${PID_FILE}` ) if [ -e "/proc/${_pid}" ]; then echo "Daemon already running with pid = $_pid" exit 0 fi fi touch ${LOG_FILE} #       UUID disks=( `blkid | grep -v swap | awk '{print $1}' | sed -es/://` ) uuids=( `blkid | grep -v swap | awk '{print $2}' | sed -es/UUID=// | sed -es/\"//g` ) #        mounts=() #      for (( i=0; i<${#disks[*]}; i++ )); do mount_point=( `cat /proc/mounts | grep ${disks[$i]} | awk '{print $2}'` ) if [[ ! -z $mount_point ]]; then mounts=("${mounts[@]}" "${disks[$i]}:$mount_point") fi done #    UUID for (( i=0; i<${#uuids[*]}; i++ )); do mount_point=( `cat /proc/mounts | grep ${uuids[$i]} | awk '{print $2}'` ) if [[ ! -z $mount_point ]]; then disk=`blkid -U ${uuids[$i]}` mounts=("${mounts[@]}" "$disk:$mount_point") fi done # ,              exists=0 checked_disks=() for mount in "${mounts[@]}"; do mount_disk="${mount%%:*}" for check in "${CHECK_DISKS[@]}"; do check_disk="${check%%:*}" if [ $check_disk == $mount_disk ]; then check_size="${check##*:}" size=$(calculate_space_prefix $check_size) checked_disks=("${checked_disks[@]}" "$check_disk:$size") exists=1 fi done done if [ $exists -eq 0 ]; then echo "Can not find disks, please check your configuration file" exit 1 fi #    cp -f ${LOG_FILE} ${LOG_FILE}.prev #   host=( `cat /etc/hostname` ) #   =) cd / exec > ${LOG_FILE} exec 2> /dev/null exec < /dev/null #  ( # ; rm -f ${PID_FILE}; exit 255; # SIGHUP SIGINT SIGQUIT SIGTERM #trap '_log "Daemon stop"; rm -f ${PID_FILE}; cp ${LOG_FILE} ${LOG_FILE}.prev; exit 0;' 1 2 3 15 _log "Daemon started" #   while [ 1 ]; do for checked in "${checked_disks[@]}"; do checked_disk="${checked%%:*}" checked_size="${checked##*:}" for mount in "${mounts[@]}"; do mount_disk="${mount%%:*}" mount_point="${mount##*:}" if [ $mount_disk == $checked_disk ]; then disk_all=( `stat -f $mount_point -c "%b"` ) disk_avaiable=( `stat -f $mount_point -c "%a"` ) disk_block_size=( `stat -f $mount_point -c "%s"` ) disk_all=$(($disk_all * $disk_block_size)) disk_avaiable=$(($disk_avaiable * $disk_block_size)) if [ $disk_avaiable -le $checked_size ]; then _log "Low disk size on $checked_disk mounted to $mount_point. Total size: $disk_all, avaiable size: $disk_avaiable, trigger size: $checked_size." #      for check in "${CHECK_DISKS[@]}"; do check_disk="${check%%:*}" check_size="${check##*:}" if [ $check_disk == $checked_disk ]; then disk_all=$(calculate_return_space_prefix $check_size $disk_all) disk_avaiable=$(calculate_return_space_prefix $check_size $disk_avaiable) checked_size=$(calculate_return_space_prefix $check_size $checked_size) prefix="${check_size: -1}" fi done subject=`echo -e ${MAIL_SUBJECT_TEMPLATE} | sed -e "s|:host:|$host|g" | sed -e "s|:disk:|$checked_disk|g" | sed -e "s|:mount_point:|$mount_point|g" | sed -e "s|:disk_total:|${disk_all}${prefix}|g" | sed -e "s|:disk_avaiable:|${disk_avaiable}${prefix}|g" | sed -e "s|:disk_checked_size:|${checked_size}${prefix}|g"` body=`echo -e ${MAIL_BODY_TEMPLATE} | sed -e "s|:host:|$host|g" | sed -e "s|:disk:|$checked_disk|g" | sed -e "s|:mount_point:|$mount_point|g" | sed -e "s|:disk_total:|${disk_all}${prefix}|g" | sed -e "s|:disk_avaiable:|${disk_avaiable}${prefix}|g" | sed -e "s|:disk_checked_size:|${checked_size}${prefix}|g"` for rcpt in "${MAIL_RCPT[@]}"; do echo "$body" | mail -s "$subject" "$rcpt" done fi fi done done sleep "${CHECK_PERIOD}" done )& #  pid    echo $! > ${PID_FILE} } stop() { check_conf_file if [ -e ${PID_FILE} ]; then _pid=( `cat ${PID_FILE}` ) if [ -e "/proc/${_pid}" ]; then kill -9 $_pid result=$? if [ $result -eq 0 ]; then echo "Daemon stop." else echo "Error stop daemon" fi else echo "Daemon is not run" fi else echo "Daemon is not run" fi } restart() { stop start } case $1 in "start") start ;; "stop") stop ;; "restart") restart ;; *) usage ;; esac exit 0
      
      







気づいた脇枠について(理解し修正するには面倒です):



  1. スクリプトは、変数CHECK_PERIODで指定された遅延で、即座にではなく、送信された信号を処理します。 残念ながら、それがどのように呼ばれるか思い出せませんが、それはサイクルに依存します。


私が伝えたかったのはそれだけです。 すべてビーバー!



All Articles