サーバ自動再起動スクリプト
自宅で運用しているサーバが最近NICの不調orチップ周りの埃のせいで、トラフィックが大量にやってくるとネットワークに繋がらなくなるという問題が続発してサービスが滞ってしまって、困ったのでRubyの勉強もかねて、NIC周りの不調が起こった時に鯖を自動的に再起動するスクリプトを書いてみた。
買い換えろと言われそうですが、NICを買い換えるのは直ぐには無理(鯖の体的な意味で
家庭内ネットにも繋がらなくなると、NASをマウントしているのでそれを使うようなデーモンが走った時にエラー続発。
復旧後のエラーメールで俺涙目という式が成立←結論
このスクリプトを投下したから少しはましになるかな。
でも、書き方変だし、何か起こりそうな予感・・・。
やってることは簡単だから、もう少し勉強しよう。
おかしいぞ!ってコメントはお気軽にして下さい。
やってることは簡単、/var/log/messagesを参照してネット周りがハングアップした時の特徴を抽出して、最終検出時間を記録して再起動。
再起動後に管理者へメール送信。
ただこれだけ。
このスクリプトをcronに設定して5分間隔で実行。
ログに現れずにハングされると終わり。
これを解決しないといけない←今ここ
Tmailを使っています。
gemでインストールしただけじゃ、使えなかったのでRubyのディレクトリにいるのをコピーした。
なぜだろう?
重大なバグがあったので2/17追記・訂正
ログロテート後に空行のみのlockファイルが出来るが、その処理が甘かったため再起動を繰り返す
lockファイルが無い場合の動作を安定させました。
require "tmail" require "net/smtp" require "date" require "time" #定数を定義 Logname = "/var/log/messages" Lockname = "./lock" MailFlag = "./mlock" Matchstring = "smb_add_request:" #ログを取得して、smb_add_request:が最後に出現した時間を取得 def readLogs() begin lastLog = "" tmp = "" findFlag = false open(Logname,"r"){|io| while line = io.gets logArry = line.split(/ /) if(logArry[5].index(Matchstring)) tmp = logArry findFlag = true end end if(findFlag) i = 0 3.times{ lastLog += tmp[i] i = i+1 } end io.close return lastLog.slice(0,lastLog.length-3) } rescue => ex print ex.message+"\n" exit end end #最終ヒット時間を記録 def writeLastLog(writeData) begin open(Lockname,"w"){|f| f.write(writeData) f.close } rescue => ex print ex.message+"\n" exit end end #時間の比較を実行 def cheackLog(lastData) begin open(Lockname,"r"){|io| while line = io.gets io.close return line == lastData end } return true #Lockファイルの中身がなかったら rescue return false #ファイルが無かったら end end #再起動を実行 def doReboot() #print IO.popen("ls").gets IO.popen("reboot") end def sendErrorMail() begin d = DateTime.now mail = TMail::Mail.new mail.to = "管理者のアドレス" mail.from = "送信元アドレス" mail.reply_to = "送信元アドレス" mail.subject = "Server was Rebooted" mail.body = "Server was Rebooted. "+d.strftime("%Y/%m/%d %H:%M:%S") mail.date = Time.now mail.mime_version = "1.0" mail.set_content_type 'text', 'plain', {'charset'=>'iso-2022-jp'} mail.write_back Net::SMTP.start("localhost") do |smtp| smtp.sendmail(mail.encoded,mail.from,mail.to) end rescue => ex print ex.message+"\n" exit end end #復帰後メール送信 def cheackMailLog() begin isDelete = File.exist?(MailFlag) if(isDelete) IO.popen("rm -f ./"+MailFlag) sendErrorMail() end rescue => ex print ex.message+"\n" exit end end #メール送信用フラグファイル作成 def makeMailFile() begin IO.popen("touch "+MailFlag) rescue => ex print ex.message+"\n" exit end end #nilか判定 def isNil(data) return data == nil end cheackMailLog() #メールを送信すべきか確認 lastDate = readLogs() #NIC異常を確認した最終ログ時間を取得 if(isNil(lastDate)) #該当ログがなかった場合は終了 exit end isReboot = cheackLog(lastDate) #既に確認済みのログエントリか確認 if(isNil(isReboot)) #エラー発生時は終了 exit end if(!isReboot) #Rebootが必要ならログに記録して実行 makeMailFile() #送信用フラグファイル作成 sleep(1) writeLastLog(lastDate) sleep(1) doReboot() end
lockファイルには Feb1501:24 のように書き出されます。
秒まで入れると、このスクリプトが走ってる途中でエラーが書き込まれると再起動後に、また再起動してしまうかも知れないのでということです。
メール送信するかどうかは、mlockというファイルの有無で判断しています。
適当にディレクトリを作って、その中で実行している場合はcronで実行する際に、そのディレクトリ内に移動してからじゃないと、あらぬところにファイルが生成されます。
ちなみに、cronの設定はこんな感じ。
0-59/5 * * * * cd /root/設置Dir/; /usr/bin/ruby reboot.rb
0-59/5 というのは、0-59分の間で5分間隔で実行という事です。