comana 0.0.10 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8203f79238f204d50f1e79f7e29bea90f20f4613
4
+ data.tar.gz: 8b3fe89b37f61a5f8f5bf0df6a346d2a0614c072
5
+ SHA512:
6
+ metadata.gz: 291a9ab5f01fa4641a40d2c917f3a6d63861777dba484a1a065f8342b5f9d2416c66f0d87d273163d2b2a02f3040346f8333210a61813e7a605d1c765e549416
7
+ data.tar.gz: 0794a0a6e80a3556e3fb7b7cb4b49a46d78746c59597e6ea194a8fe852bfaa4588431383edacc5c2a5a3225fc87385af8874d585313e11b910993f8431b9219b
data/CHANGES CHANGED
@@ -1,6 +1,13 @@
1
1
  = comana changelog
2
2
 
3
- == Master (for 0.0.11)
3
+ == Master (for 0.1.1)
4
+
5
+ == Version 0.1.0 [2016-03-04] released
6
+ - Comana::ComputationManager#start() rename to exec().
7
+ - Comana::ComputationManager.exec is added.
8
+ - Add Comana::HostInspector
9
+ - Add bin/hostinfo
10
+ - Add bin/genqsub
4
11
 
5
12
  == Version 0.0.10 [2014-08-28] released
6
13
  - Provide namespace 'Comana' for classes.
data/Gemfile CHANGED
@@ -4,17 +4,12 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
6
  # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
7
+ # Include everything needed to exec rake, tests, features, etc.
8
8
  group :development do
9
- #gem "rspec", ">= 2.10.0"
10
- gem "rdoc", "~> 4.0.1"
11
- gem "bundler", "~> 1.7.2"
12
- gem "jeweler", ">= 2.0.1"
13
- gem "simplecov", ">= 0"
14
- #gem "builder", "~> 3.2.2"
15
- #gem "nokogiri", ">= 1.5.9"
16
- #
17
- gem "tefil", ">= 0.0.3"
18
- #gem "psych", ">= 1.3.4"
19
-
9
+ gem "test-unit", "~> 3.1"
10
+ gem "rdoc", "~> 4.2"
11
+ gem "bundler", "~> 1.11"
12
+ gem "jeweler", "~> 2.0"
13
+ gem "simplecov", "~> 0.11"
14
+ gem "tefil", ">= 0.1"
20
15
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.10
1
+ 0.1.0
data/bin/genqsub ADDED
@@ -0,0 +1,45 @@
1
+ #! /usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require "pp"
5
+ require "comana"
6
+ require "optparse"
7
+
8
+ ## option analysis
9
+ OPTIONS = {}
10
+ op = OptionParser.new
11
+ op.banner = [
12
+ "Usage: #{File.basename("#{__FILE__}")} [options] host_series command",
13
+ ].join("\n")
14
+ op.on("-s" , "--submit" , "Submit at the same time."){OPTIONS[:submit] = true}
15
+ op.on("-o file", "--outfile=file", "Output in file."){|v| OPTIONS[:outfile] = v}
16
+ op.parse!(ARGV)
17
+
18
+ io = STDOUT
19
+ io = File.open( OPTIONS[:outfile], "w") if OPTIONS[:outfile]
20
+
21
+ series = ARGV.shift
22
+
23
+ cluster_setting = Comana::ClusterSetting.load_file
24
+ settings = cluster_setting.groups[series]
25
+
26
+ unless settings
27
+ puts "Not found '#{series}' in #{cluster_setting.data_file}"
28
+ puts op.banner
29
+ exit
30
+ end
31
+ ppn = settings["ppn"]
32
+
33
+ command = ARGV.join(' ')
34
+
35
+ GridEngineScript.generate(io, series, ppn, command)
36
+ io.close
37
+
38
+ if OPTIONS[:submit]
39
+ unless OPTIONS[:outfile]
40
+ puts "'--submit' option must use with '--outfile' option."
41
+ exit
42
+ end
43
+
44
+ GridEngineScript.write_submit(series, ppn, command, OPTIONS[:outfile])
45
+ end
data/bin/hostinfo ADDED
@@ -0,0 +1,182 @@
1
+ #! /usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require "comana"
5
+ require "optparse"
6
+ require "pp"
7
+
8
+ ##Analyze options
9
+ COMMAND_NAME = File.basename("#{__FILE__}")
10
+ OPTIONS = {}
11
+ op = OptionParser.new
12
+ op.banner = <<HERE
13
+ Usage: #{COMMAND_NAME} subcommand [options] [hosts]
14
+ Subcommands:
15
+ ping # Ping: o and x indicate OK and N/A, respectively.
16
+ alive # Ping only alive: show alive hostname
17
+ cwd # cwd of processes owned by ssh login user.
18
+ ps # Info from ps.
19
+ cpuinfo # CPU information from /proc/cpuinfo.
20
+ meminfo # memory information from /proc/meminfo.
21
+ load # the highest process
22
+ For example,
23
+ #{COMMAND_NAME} ping # for all hosts
24
+ #{COMMAND_NAME} ping host01 host02
25
+ #{COMMAND_NAME} ping -g host_series
26
+ #{COMMAND_NAME} ping -u # update cached data
27
+ HERE
28
+
29
+ op.on("-u", "--update" , "Update cache"){OPTIONS[:update] = true}
30
+ op.on("-g", "--group" , "Indicate group of hosts" ){OPTIONS[:group] = true}
31
+ op.on("-q", "--quiet" , "No output 'Wainting for...'"){OPTIONS[:quiet] = true}
32
+ op.parse!(ARGV)
33
+
34
+ ## Analyze subcommand
35
+ subcommand = ARGV.shift
36
+ requirement = {}
37
+ case subcommand
38
+ when "ping"
39
+ requirement[:ping] = true
40
+ when "alive"
41
+ requirement[:ping] = true
42
+ when "cwd"
43
+ requirement[:cwd] = true
44
+ when "ps"
45
+ requirement[:ps] = true
46
+ when "cpuinfo"
47
+ requirement[:cpuinfo] = true
48
+ when "meminfo"
49
+ requirement[:meminfo] = true
50
+ when "load"
51
+ requirement[:ps] = true
52
+ requirement[:cwd] = true
53
+ else
54
+ puts op.help
55
+ exit
56
+ end
57
+
58
+ ## Return selected hosts
59
+ def target_hosts
60
+ cs = Comana::ClusterSetting.load_file
61
+ groups = {}
62
+ cs.groups.each do |key, val|
63
+ cluster = key
64
+ groups[key] = val["members"]
65
+ end
66
+ hs = Comana::HostSelector.new groups
67
+ if OPTIONS[:group]
68
+ hosts = []
69
+ ARGV.each do |group|
70
+ begin
71
+ hosts << hs.select_group(group)
72
+ rescue Comana::HostSelector::NoEntryError
73
+ $stderr.puts "Unknown group: #{group}"
74
+ end
75
+ end
76
+ hosts.flatten!
77
+ else
78
+ hosts = ARGV
79
+ end
80
+ hosts = hs.select_all if ARGV.empty?
81
+ hosts
82
+ end
83
+
84
+ def time_ago(uptime)
85
+ if uptime
86
+ second = (Time.now - uptime).to_i
87
+ if second >= 86400
88
+ result = sprintf("%2s days ago", second / 86400)
89
+ elsif second >= 3600
90
+ result = sprintf("%2s hours ago", second / 3600)
91
+ elsif second >= 60
92
+ result = sprintf("%2s min ago", second / 60)
93
+ else
94
+ result = sprintf("%2s sec ago", second)
95
+ end
96
+ else #e.g., not exist cache file
97
+ result = "need_update"
98
+ end
99
+ return result
100
+ end
101
+
102
+ ## Collect information
103
+ hostinspectors = target_hosts.map { |host| Comana::HostInspector.new(host) }
104
+ if OPTIONS[:update]
105
+ Thread.abort_on_exception = true
106
+ threads = {}
107
+ hostinspectors.each do |hi|
108
+ threads[hi] = Thread.start do
109
+ hi.update_ping if requirement[:ping]
110
+ hi.update_cwd if requirement[:cwd]
111
+ hi.update_ps if requirement[:ps]
112
+ hi.update_cpuinfo if requirement[:cpuinfo]
113
+ hi.update_meminfo if requirement[:meminfo]
114
+ end
115
+ end
116
+ threads.each do |hi, thread|
117
+ print "Waiting for #{hi.hostname}...\n" unless OPTIONS[:quiet]
118
+ thread.join # wait until all processes are completed
119
+ end
120
+ end
121
+
122
+ ## Output
123
+ hostinspectors.each do |hi|
124
+ # oldest update
125
+ oldest_key, val = requirement.min_by {|key,val| hi.time_updated(key.to_s)}
126
+ hostname = hi.hostname
127
+ timeago = time_ago( hi.time_updated(oldest_key.to_s))
128
+ hosttime = sprintf("%-10s (%12s) ",
129
+ hi.hostname, time_ago( hi.time_updated(oldest_key.to_s)))
130
+ begin
131
+ case subcommand
132
+ when "ping"
133
+ if hi.fetch('ping')
134
+ hosttime += "o"
135
+ else
136
+ hosttime += "x"
137
+ end
138
+ puts hosttime
139
+ when "alive"
140
+ puts hostname if hi.fetch('ping')
141
+ when "cwd"
142
+ puts hosttime
143
+ hi.fetch('cwd').each do |pid, cwd|
144
+ printf(" %5s %s\n", pid, cwd)
145
+ end
146
+ when "ps"
147
+ puts hosttime
148
+ hi.fetch('ps').each do |pid, ps|
149
+ printf(" %-10s %5s\n", hi.hostname, pid)
150
+ end
151
+ when "cpuinfo"
152
+ result = hosttime
153
+ begin
154
+ cpuinfo = hi.fetch('cpuinfo')
155
+ result += sprintf("%2d_cores %s\n",
156
+ cpuinfo.size, cpuinfo[0]["model name"].gsub(/ +/, '_'))
157
+ rescue
158
+ result += sprintf("not_obtained\n")
159
+ end
160
+ puts result
161
+ when "meminfo"
162
+ result = hosttime
163
+ meminfo = hi.fetch('meminfo')
164
+ result += sprintf("%s\n", meminfo['MemTotal'])
165
+ puts result
166
+ when "load"
167
+ result = hosttime
168
+ ps = hi.fetch("ps")
169
+ cwd = hi.fetch("cwd")
170
+ pid, process = ps.max_by {|key, val| val['cpu'].to_f}
171
+ command = File.basename(process['command'].split[0])
172
+ result += sprintf("%5s %8s %5.1f %5.1f %20s %s\n",
173
+ pid, process['user'], process['cpu'], process['mem'],
174
+ command, cwd[pid])
175
+ puts result
176
+ end
177
+ rescue Comana::HostInspector::NoUpdateFile
178
+ puts hosttime + "------------"
179
+ rescue NoMethodError # 主にデータを取れなかった時用
180
+ puts hosttime + "------------"
181
+ end
182
+ end
data/bin/machinestatus CHANGED
@@ -1,6 +1,10 @@
1
1
  #! /usr/bin/env ruby
2
2
  # coding: utf-8
3
3
 
4
+
5
+ puts "machinestatus is obsoleted. use 'hostinfo'"
6
+ exit
7
+
4
8
  USAGE = <<HERE
5
9
  machinestatus HostA HostB
6
10
  machinestatus -g GroupA GroupB #-g option interprets as group name
@@ -57,8 +61,6 @@ else
57
61
  end
58
62
  hosts = hs.select_all if ARGV.empty?
59
63
 
60
- #pp hosts;exit
61
-
62
64
  ##Collect information
63
65
  Thread.abort_on_exception = true
64
66
  results = {}
@@ -186,4 +188,5 @@ end
186
188
 
187
189
  data = data.unshift(titles)
188
190
  #pp data
189
- Tefil::ColumnFormer.form(data, $stdout, "|")
191
+ t = Tefil::ColumnFormer.new
192
+ t.form(data, $stdout, "|")
data/bin/queueinfo ADDED
@@ -0,0 +1,28 @@
1
+ #! /usr/bin/env ruby
2
+
3
+
4
+ require 'thor'
5
+ require 'comana'
6
+ require 'pp'
7
+
8
+ ### Command template
9
+ class Queueinfo < Thor
10
+ desc "light", "Detect the lightest queue."
11
+
12
+ def lightqueue
13
+ qinfo = Comana::QueueManager.new
14
+ qinfo.light_queue
15
+ end
16
+
17
+ #def job
18
+ #end
19
+
20
+ def show
21
+
22
+ end
23
+
24
+ end
25
+
26
+ Queueinfo.start(ARGV)
27
+
28
+
data/comana.gemspec ADDED
@@ -0,0 +1,110 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: comana 0.1.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "comana"
9
+ s.version = "0.1.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["ippei94da"]
14
+ s.date = "2016-03-04"
15
+ s.description = "Comana, COmputation MANAger,\n is a software to provide a framework of\n managing scientific computing.\n Researchers on computing have to check calculation and\n generate new calculation and execute, repeatedly.\n The abstract class that this gem provide would help the work.\n "
16
+ s.email = "ippei94da@gmail.com"
17
+ s.executables = ["genqsub", "hostinfo", "machinestatus", "queueinfo", "scpall", "sshall"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".rspec",
25
+ "CHANGES",
26
+ "Gemfile",
27
+ "LICENSE.txt",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "bin/genqsub",
32
+ "bin/hostinfo",
33
+ "bin/machinestatus",
34
+ "bin/queueinfo",
35
+ "bin/scpall",
36
+ "bin/sshall",
37
+ "comana.gemspec",
38
+ "example/dot.clustersetting",
39
+ "lib/comana.rb",
40
+ "lib/comana/clustersetting.rb",
41
+ "lib/comana/computationmanager.rb",
42
+ "lib/comana/gridenginescript.rb",
43
+ "lib/comana/hostinspector.rb",
44
+ "lib/comana/hostselector.rb",
45
+ "lib/comana/queuemanager.rb",
46
+ "lib/comana/queuesubmitter.rb",
47
+ "memo.txt",
48
+ "test/helper.rb",
49
+ "test/hostinspector/.gitignore",
50
+ "test/locked/input_a",
51
+ "test/locked/input_b",
52
+ "test/locked/lock_comana/dummy",
53
+ "test/locked_outputted/input_a",
54
+ "test/locked_outputted/input_b",
55
+ "test/locked_outputted/lock_comana/dummy",
56
+ "test/locked_outputted/output",
57
+ "test/not_executable/dummy",
58
+ "test/not_started/input_a",
59
+ "test/not_started/input_b",
60
+ "test/outputted/input_a",
61
+ "test/outputted/input_b",
62
+ "test/outputted/output",
63
+ "test/pbsnodes/Br09.xml",
64
+ "test/pbsnodes/Br10.xml",
65
+ "test/pbsnodes/Ge00.xml",
66
+ "test/pbsnodes/Ge08.xml",
67
+ "test/pbsnodes/all.xml",
68
+ "test/queuesubmitter/locked/lock_queuesubmitter/dummy",
69
+ "test/queuesubmitter/unlocked/dummy",
70
+ "test/test_clustersetting.rb",
71
+ "test/test_computationmanager.rb",
72
+ "test/test_gridenginescript.rb",
73
+ "test/test_hostinspector.rb",
74
+ "test/test_hostselector.rb",
75
+ "test/test_queuemanager.rb",
76
+ "test/test_queuesubmitter.rb"
77
+ ]
78
+ s.homepage = "http://github.com/ippei94da/comana"
79
+ s.licenses = ["MIT"]
80
+ s.rubygems_version = "2.2.3"
81
+ s.summary = "Manager for scientific computing"
82
+
83
+ if s.respond_to? :specification_version then
84
+ s.specification_version = 4
85
+
86
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
87
+ s.add_development_dependency(%q<test-unit>, ["~> 3.1"])
88
+ s.add_development_dependency(%q<rdoc>, ["~> 4.2"])
89
+ s.add_development_dependency(%q<bundler>, ["~> 1.11"])
90
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0"])
91
+ s.add_development_dependency(%q<simplecov>, ["~> 0.11"])
92
+ s.add_development_dependency(%q<tefil>, [">= 0.1"])
93
+ else
94
+ s.add_dependency(%q<test-unit>, ["~> 3.1"])
95
+ s.add_dependency(%q<rdoc>, ["~> 4.2"])
96
+ s.add_dependency(%q<bundler>, ["~> 1.11"])
97
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
98
+ s.add_dependency(%q<simplecov>, ["~> 0.11"])
99
+ s.add_dependency(%q<tefil>, [">= 0.1"])
100
+ end
101
+ else
102
+ s.add_dependency(%q<test-unit>, ["~> 3.1"])
103
+ s.add_dependency(%q<rdoc>, ["~> 4.2"])
104
+ s.add_dependency(%q<bundler>, ["~> 1.11"])
105
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
106
+ s.add_dependency(%q<simplecov>, ["~> 0.11"])
107
+ s.add_dependency(%q<tefil>, [">= 0.1"])
108
+ end
109
+ end
110
+
@@ -8,21 +8,22 @@ require "yaml"
8
8
  # E.g.,
9
9
  # "Fe", "Fe00", "Fe01" are of series "Fe" and not "F"
10
10
  class Comana::ClusterSetting
11
- attr_reader :groups, :pbs_server
11
+ attr_reader :data_file, :groups, :pbs_server
12
12
 
13
13
  DEFAULT_DATA_FILE = ENV["HOME"] + "/.clustersetting"
14
14
 
15
15
  class NoEntryError < Exception; end
16
16
 
17
17
  #
18
- def initialize(settings)
18
+ def initialize(settings, data_file = nil)
19
19
  @pbs_server = settings["pbs_server"]
20
20
  @groups = settings["groups"]
21
+ @data_file = data_file
21
22
  end
22
23
 
23
24
  def self.load_file(data_file = DEFAULT_DATA_FILE)
24
25
  settings = YAML.load_file(data_file)
25
- self.new settings
26
+ self.new(settings, data_file)
26
27
  end
27
28
 
28
29
  #Return belonged cluster of the host.
@@ -1,7 +1,7 @@
1
1
  #! /usr/bin/env ruby
2
2
  # coding: utf-8
3
3
 
4
- # This class profides a framework of scientific computation.
4
+ # This class provides a framework of scientific computation.
5
5
  # Users have to redefine some methods in subclasses for various computation.
6
6
  #
7
7
  class Comana::ComputationManager
@@ -18,6 +18,28 @@ class Comana::ComputationManager
18
18
  @alive_time = 3600
19
19
  end
20
20
 
21
+ def self.exec(args)
22
+ targets = args
23
+ targets = [ENV['PWD']] if targets.size == 0
24
+
25
+ targets.each do |dir|
26
+ print "#{dir}..."
27
+ begin
28
+ calc_dir = self.new(dir)
29
+ rescue => exc
30
+ puts "Not suitable directory, due of an exception: #{exc}"
31
+ next
32
+ end
33
+
34
+ begin
35
+ calc_dir.start
36
+ rescue Comana::ComputationManager::AlreadyStartedError
37
+ puts "Already started."
38
+ next
39
+ end
40
+ end
41
+ end
42
+
21
43
  # Return a symbol which indicate state of calculation.
22
44
  # :yet not started
23
45
  # :started started, but not ended, including short time from last output
@@ -33,7 +55,7 @@ class Comana::ComputationManager
33
55
  # Execute calculation.
34
56
  # If log of ComputationManager exist, raise ComputationManager::AlreadyStartedError,
35
57
  # because the calculation has been done by other process already.
36
- def start
58
+ def exec
37
59
  begin
38
60
  Dir.mkdir "#{@dir}/#{@lockdir}"
39
61
  rescue Errno::EEXIST
@@ -46,6 +68,7 @@ class Comana::ComputationManager
46
68
  prepare_next
47
69
  end
48
70
  end
71
+ alias start exec
49
72
 
50
73
  # Return latest modified time of files in calc dir recursively.
51
74
  # require "find"
@@ -0,0 +1,68 @@
1
+ #! /usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ #
5
+ #
6
+ #
7
+ class GridEngineScript
8
+ #DEFAULT_QSUB_FILE = 'qsub.sh'
9
+ QSUB_PATH = '/usr/bin/qsub'
10
+
11
+ #
12
+ def initialize()
13
+ end
14
+
15
+ # series: name of computers' series
16
+ # ppn: number of using cores
17
+ def self.generate(io, series, ppn, command)
18
+ io.puts self.string(series, ppn, command)
19
+ end
20
+
21
+ def self.string(series, ppn, command)
22
+ string = <<HERE
23
+ \#! /bin/sh
24
+ \#$ -S /bin/sh
25
+ \#$ -cwd
26
+ \#$ -o stdout
27
+ \#$ -e stderr
28
+ \#$ -q #{series}.q
29
+ \#$ -pe #{series}.openmpi #{ppn}
30
+
31
+ MACHINE_FILE="machines"
32
+ ENV_FILE="printenv.log"
33
+
34
+ LD_LIBRARY_PATH=/usr/lib:/usr/local/lib:/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64:/opt/intel/lib:/opt/openmpi-intel/lib
35
+ export LD_LIBRARY_PATH
36
+
37
+ cd $SGE_O_WORKDIR
38
+ if [ -e $ENV_FILE ]; then
39
+ echo "$ENV_FILE already exist. Exit."
40
+ exit
41
+ fi
42
+ printenv | sort > printenv.log
43
+ cut -d " " -f 1,2 $PE_HOSTFILE | sed 's/ / cpu=/' > $MACHINE_FILE
44
+
45
+ #{command}
46
+ HERE
47
+ string
48
+ end
49
+
50
+ def self.write(series, ppn, command, io)
51
+ io.puts self.string(series, ppn, command)
52
+ end
53
+
54
+ def self.write_submit(series, ppn, command, filename)
55
+ #qsub_file = DEFAULT_QSUB_FILE
56
+ io = File.open(filename, 'w')
57
+ self.write(series, ppn, command, io)
58
+ io.close
59
+
60
+ logfile = filename.sub(/#{File.extname filename}$/, '.log')
61
+ command = "#{QSUB_PATH} #{filename} > #{logfile}"
62
+ #command = "qsub #{filename}"
63
+ puts command
64
+ system command
65
+ end
66
+
67
+ end
68
+