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 +