lib/comana/hostinspector.rb in comana-0.0.10 vs lib/comana/hostinspector.rb in comana-0.1.0
- old
+ new
@@ -1,4 +1,223 @@
-#! /usr/bin/env ruby
+#s! /usr/bin/env ruby
# coding: utf-8
+#
+require "yaml"
-module Comana::HostInspector; end
+class Comana::HostInspector
+ PING_MIN_INTERVAL = 1
+ CACHE_DIR = "#{ENV['HOME']}/var/comana"
+
+ class NoUpdateFile < Exception; end
+
+ attr_reader :hostname
+
+ #
+ def initialize(hostname)
+ @hostname = hostname
+ @cache_dir = "#{CACHE_DIR}/#{@hostname}"
+ end
+
+
+ ##ping
+ #Try ping three times.
+ #Return true if at least one time responds.
+ #def ping3
+ def update_ping
+ result = false
+ 3.times do
+ command =
+ "ping -c 1 -W #{PING_MIN_INTERVAL} #{@hostname} 2> /dev/null 1> /dev/null"
+ if system(command)
+ result = true
+ break
+ end
+ end
+
+ write_cache("ping", result)
+ end
+
+ ##cwd
+ ##readlink コマンドが使えるかとも思ったが、シムリンク自体の名前が不明瞭になる。
+ def update_cwd
+ #str = `ssh #{@hostname} 'ls -l /proc/*/cwd'`
+ str = ssh_str('ls -l /proc/\*/cwd 2> /dev/null')
+ results = {}
+ str.split("\n").each do |line|
+ #pp line
+ items = line.split
+ pid = items[8].sub(/^\/proc\//, '').sub(/\/cwd$/, '')
+ results[pid] = items[10]
+ end
+
+ write_cache('cwd', results)
+ end
+
+ ##processes
+ #%ps auxw
+ #USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+ #ippei 28971 0.0 0.0 103684 3764 ? S 15:19 0:00 sshd: ippei@pts/19
+ #root 1 0.0 0.0 33876 2280 ? Ss 5月17 0:22 /sbin/init
+ #0---------1---------2---------3---------4---------5---------6---------7
+ #0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0
+ #
+ #% ps -o 'user pid %cpu %mem command'
+ #USER PID %CPU %MEM COMMAND
+ #ippei 19991 0.0 0.2 zsh
+ #ippei 23217 0.0 0.0 ps -o user pid %cpu %mem command
+ #0---------1---------2---------3---------4---------5---------6---------7
+ #0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0-2-4-6-8-0
+ #auxw だと、
+ #ippei 2948 198 11.8 4495708 3884740 pts/3 Rl Apr01 173494:26 /opt/bin/vasp5212openmpi で桁が崩れることがある。
+ def update_ps
+ #str = ssh_str('ps -eo "user pid %cpu %mem command"')
+ #results = {}
+ #lines = str.split("\n")
+ #lines.shift # titles of items
+ #lines.each do |line|
+ # user = line[0..7]
+ # pid = line[9..13]
+ # cpu = line[15..18]
+ # mem = line[20..23]
+ # command = line[25..-1]
+ # results[pid] = {
+ # "user" => user,
+ # "cpu" => cpu,
+ # "mem" => mem,
+ # "command" => command
+ # }
+ #end
+ #write_cache('ps', results)
+
+ #str = `ssh #{@hostname} 'ps auxw'`
+ str = ssh_str('ps auxw')
+ results = {}
+ lines = str.split("\n")
+ lines.shift # titles of items
+ lines.each do |line|
+ items = line.split
+ user = items[0]
+ pid = items[1]
+ cpu = items[2]
+ mem = items[3]
+ command = items[10]
+
+ results[pid] = {
+ "user" => user,
+ "cpu" => cpu,
+ "mem" => mem,
+ "command" => command
+ }
+ end
+ write_cache('ps', results)
+
+ ##str = `ssh #{@hostname} 'ps auxw'`
+ #str = ssh_str('ps auxw')
+ #results = {}
+ #lines = str.split("\n")
+ #lines.shift # titles of items
+ #lines.each do |line|
+ # user = line[0..7]
+ # pid = line[9..13]
+ # cpu = line[15..18]
+ # mem = line[20..23]
+ # #vsz = line[25..30]
+ # #rss = line[32..36]
+ # #tty = line[38..45]
+ # #stat = line[47..50]
+ # #start = line[52..56]
+ # #time = line[58..63]
+ # command = line[65..-1]
+ # results[pid] = {
+ # "user" => user,
+ # "cpu" => cpu,
+ # "mem" => mem,
+ # "command" => command
+ # }
+ #end
+ #write_cache('ps', results)
+ end
+
+ # dmesg ログ形式でつらい。
+ # /proc/cpuinfo コアごとにでるのでパースめんどう。
+ # lscpu これだと思ったら、CPU MHz がずれてる。ハードウェアで想定される値ではなく、
+ # 実際の速度で書かれるらしい。
+ # 負荷の有無で値がかわる。
+ def update_cpuinfo
+ #str = `ssh #{@hostname} 'cat /proc/cpuinfo'`
+ str = ssh_str('cat /proc/cpuinfo')
+ results = []
+ cur_index = 0
+ results[cur_index] = {}
+ lines = str.split("\n")
+ lines.each do |line|
+ if line =~ /^\s*$/
+ cur_index += 1
+ results[cur_index] = {}
+ next
+ end
+ key, value = line.split(/\s*:\s*/)
+ results[cur_index][key] = value
+ end
+ write_cache('cpuinfo', results)
+ end
+
+ def update_meminfo
+ #str = `ssh #{@hostname} 'cat /proc/meminfo'`
+ str = ssh_str('cat /proc/meminfo')
+ results = {}
+ lines = str.split("\n")
+ lines.each do |line|
+ key, value = line.split(/\s*:\s*/)
+ results[key] = value
+ end
+ write_cache('meminfo', results)
+ end
+
+ ############################################################
+ ## common
+ #Return from cached ping data.
+ def fetch(name)
+ load_cache(name)
+ end
+
+ def time_updated(name)
+ ping_file = "#{@cache_dir}/#{name}.yaml"
+ if File.exist? ping_file
+ return File.mtime(ping_file)
+ else
+ return nil
+ end
+ end
+
+ private
+
+ # 先に ping を打ち、返事がなければ 空文字列 を返す。
+ def ssh_str(command)
+ #pp command
+ update_ping
+ if fetch('ping')
+ return `ssh #{@hostname} #{command}`
+ else
+ return ''
+ end
+ end
+
+ def write_cache(name, value)
+ FileUtils.mkdir_p @cache_dir
+ File.open("#{@cache_dir}/#{name}.yaml", "w") do |io|
+ YAML.dump(value, io)
+ end
+ end
+
+ def load_cache(name)
+ #return nil unless File.exist? "#{@cache_dir}/#{name}.yaml"
+ cache_file = "#{@cache_dir}/#{name}.yaml"
+ unless File.exist? cache_file
+ raise NoUpdateFile, "#{cache_file} not found."
+ end
+
+ YAML.load_file("#{@cache_dir}/#{name}.yaml")
+ end
+
+end
+