ruby-cute 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.yardopts +2 -0
- data/Gemfile +6 -0
- data/README.md +137 -6
- data/Rakefile +48 -0
- data/bin/cute +22 -0
- data/debian/changelog +5 -0
- data/debian/compat +1 -0
- data/debian/control +15 -0
- data/debian/copyright +33 -0
- data/debian/ruby-cute.docs +2 -0
- data/debian/ruby-tests.rb +2 -0
- data/debian/rules +19 -0
- data/debian/source/format +1 -0
- data/debian/watch +2 -0
- data/examples/distem-bootstrap +516 -0
- data/examples/g5k_exp1.rb +41 -0
- data/examples/g5k_exp_virt.rb +129 -0
- data/lib/cute.rb +7 -2
- data/lib/cute/bash.rb +337 -0
- data/lib/cute/configparser.rb +404 -0
- data/lib/cute/execute.rb +272 -0
- data/lib/cute/extensions.rb +38 -0
- data/lib/cute/g5k_api.rb +1190 -0
- data/lib/cute/net-ssh.rb +144 -0
- data/lib/cute/net.rb +29 -0
- data/lib/cute/synchronization.rb +89 -0
- data/lib/cute/taktuk.rb +554 -0
- data/lib/cute/version.rb +3 -0
- data/ruby-cute.gemspec +32 -0
- data/spec/extensions_spec.rb +17 -0
- data/spec/g5k_api_spec.rb +192 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/taktuk_spec.rb +129 -0
- data/test/test_bash.rb +71 -0
- metadata +204 -47
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 134cb9d25b87efcffb16969273bc4485b79a6086
|
4
|
+
data.tar.gz: b2454f6b7878e1e7339bcfd412dd52e431e17f08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e73cc26463f9eafe501ba6b01f9439dcb7cb6874ee35c8ea3692797dcb75f1a73fbef9adce8df8d2ea410267a6be34a3852f968d84db9ae19b5cf3c58a444f5
|
7
|
+
data.tar.gz: d5d5bf2fa5c5d0d99944bbe010fa6456356571487be772b4f9246213a5ade9d21f60ae29b3b4813091b94529c9ef1b5c44de948512c15fac2a7bdf086339ba79
|
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
Ruby-Cute
|
2
|
-
=========
|
1
|
+
# Ruby-Cute
|
3
2
|
|
4
3
|
Ruby-Cute is a set of *Commonly Used Tools for Experiments*, or *Critically
|
5
4
|
Useful Tools for Experiments*, depending on who you ask. It is a library
|
@@ -7,14 +6,146 @@ aggregating various Ruby snippets useful in the context of (but not limited to)
|
|
7
6
|
development of experiment software on distributed systems testbeds such as
|
8
7
|
Grid'5000.
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
From sources:
|
12
|
+
|
13
|
+
```bash
|
14
|
+
$ git clone https://github.com/ruby-cute/ruby-cute
|
15
|
+
$ cd ruby-cute
|
16
|
+
$ gem build ruby-cute.gemspec
|
17
|
+
$ gem install ruby-cute-*.gem
|
18
|
+
```
|
19
|
+
|
20
|
+
In Grid'5000 the installation procedure goes as follows:
|
21
|
+
|
22
|
+
```bash
|
23
|
+
$ gem install --user-install ruby-cute
|
24
|
+
```
|
25
|
+
|
26
|
+
Then, type the following for having ruby cute in your path (this is only necessary if you want to use interactive mode).
|
27
|
+
|
28
|
+
```bash
|
29
|
+
$ export PATH=$PATH:$(ruby -e 'puts "#{Gem.user_dir}/bin"')
|
30
|
+
```
|
31
|
+
|
32
|
+
## Overview
|
33
|
+
|
34
|
+
Ruby-Cute is structured in different modules that allows you to:
|
35
|
+
|
36
|
+
- communicate with Grid'5000 through the G5K Module. For more details please refer to
|
37
|
+
[G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API).
|
38
|
+
|
39
|
+
- execute commands in several remote machines in parallel. Two modules are available for that:
|
40
|
+
|
41
|
+
- [Net::SSH::Multi](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Net/SSH/Multi) that uses the SSH protocol.
|
42
|
+
- [TakTuk](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/TakTuk)
|
43
|
+
which is a wrapper of [taktuk](http://taktuk.gforge.inria.fr) parallel command executor.
|
44
|
+
|
45
|
+
An example of use of Ruby-Cute in a real use case is available in
|
46
|
+
[Virtualization on Grid'5000](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/file/examples/g5k_exp_virt.rb)
|
47
|
+
|
48
|
+
## Using pry -- an interactive ruby shell
|
49
|
+
|
50
|
+
Sometimes it may be useful to work in interactive mode. For this we can use an interactive ruby shell such as irb that is shipped by default with
|
51
|
+
Ruby, however, we highly recommend to use [pry](http://pryrepl.org/), it features syntax highlighting, method auto completion and command shell integration.
|
52
|
+
For installing pry type the following:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
$ gem install pry
|
56
|
+
```
|
57
|
+
|
58
|
+
or, for installing in the user home directory:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
$ gem install --user-install pry
|
62
|
+
```
|
63
|
+
|
64
|
+
When Ruby-Cute is installed, it provides a wrapper for an interactive shell that will
|
65
|
+
automatically load the necessary libraries. The following will get a *pry* prompt (if installed).
|
66
|
+
|
67
|
+
```bash
|
68
|
+
$ cute
|
69
|
+
[1] pry(main)>
|
70
|
+
```
|
71
|
+
|
72
|
+
The variable *$g5k* is available which can be used to access the Grid'5000 API through the
|
73
|
+
[G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API). For example,
|
74
|
+
let's request the name of the sites available in Grid'5000.
|
75
|
+
|
76
|
+
```bash
|
77
|
+
[2] pry(main)> $g5k.site_uids()
|
78
|
+
=> ["grenoble", "lille", "luxembourg", "lyon", "nancy", "nantes", "reims", "rennes", "sophia", "toulouse"]
|
79
|
+
```
|
80
|
+
|
81
|
+
We can get the status of nodes in a given site by using:
|
82
|
+
|
83
|
+
```bash
|
84
|
+
[8] pry(main)> $g5k.nodes_status("lyon")
|
85
|
+
=> {"taurus-2.lyon.grid5000.fr"=>"besteffort", "taurus-16.lyon.grid5000.fr"=>"besteffort", "taurus-15.lyon.grid5000.fr"=>"besteffort", ...}
|
86
|
+
```
|
87
|
+
|
88
|
+
Within this shell you have preloaded [G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API),
|
89
|
+
[Taktuk](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/TakTuk) and
|
90
|
+
[Net::SSH::Multi](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Net/SSH/Multi),
|
91
|
+
you can go directly to their respective documentation to know how to take advantage of them.
|
92
|
+
|
93
|
+
### Experiment example
|
94
|
+
|
95
|
+
The following example shows how to use the [G5K Module](http://www.rubydoc.info/github/ruby-cute/ruby-cute/master/Cute/G5K/API) in an experiment.
|
96
|
+
This example implements the experiment described in
|
97
|
+
[MPI on Grid5000](https://www.grid5000.fr/mediawiki/index.php/Run_MPI_On_Grid%275000#Setting_up_and_starting_Open_MPI_to_use_high_performance_interconnect).
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
require 'cute'
|
101
|
+
require 'net/scp'
|
102
|
+
|
103
|
+
g5k = Cute::G5K::API.new()
|
104
|
+
# We reuse a job if there is one available.
|
105
|
+
G5K_SITE = "nancy" # the chosen site has to have Infiniband 20G (e.g nancy, grenoble)
|
106
|
+
if g5k.get_my_jobs(G5K_SITE).empty?
|
107
|
+
job = g5k.reserve(:site => G5K_SITE, :resources => "{ib20g='YES'}/nodes=2/core=1",:walltime => '00:30:00', :keys => "~/my_ssh_jobkey" )
|
108
|
+
else
|
109
|
+
job = g5k.get_my_jobs(G5K_SITE).first
|
110
|
+
end
|
111
|
+
|
112
|
+
nodes = job["assigned_nodes"]
|
113
|
+
|
114
|
+
grid5000_opt = {:user => "oar", :keys => ["~/my_ssh_jobkey"], :port => 6667 }
|
115
|
+
|
116
|
+
machine_file = Tempfile.open('machine_file')
|
117
|
+
|
118
|
+
nodes.each{ |node| machine_file.puts node }
|
119
|
+
|
120
|
+
machine_file.close
|
121
|
+
|
122
|
+
netpipe ="http://pkgs.fedoraproject.org/repo/pkgs/NetPIPE/NetPIPE-3.7.1.tar.gz/5f720541387be065afdefc81d438b712/NetPIPE-3.7.1.tar.gz"
|
123
|
+
|
124
|
+
# We use the first node reserved.
|
125
|
+
Net::SCP.start(nodes.first, "oar", grid5000_opt) do |scp|
|
126
|
+
scp.upload! machine_file.path, "/tmp/machine_file"
|
127
|
+
end
|
128
|
+
|
129
|
+
Net::SSH.start(nodes.first, "oar", grid5000_opt) do |ssh|
|
130
|
+
ssh.exec!("mkdir -p netpipe_exp")
|
131
|
+
ssh.exec!("export http_proxy=\"http://proxy:3128\"; wget -O ~/netpipe_exp/NetPIPE.tar.gz #{netpipe}")
|
132
|
+
ssh.exec!("cd netpipe_exp && tar -zvxf NetPIPE.tar.gz")
|
133
|
+
ssh.exec!("cd netpipe_exp/NetPIPE-3.7.1 && make mpi")
|
134
|
+
ssh.exec("mpirun --mca plm_rsh_agent \"oarsh\" -machinefile /tmp/machine_file ~/netpipe_exp/NetPIPE-3.7.1/NPmpi")
|
135
|
+
end
|
136
|
+
|
137
|
+
g5k.release(job) # Frees resources.
|
138
|
+
```
|
139
|
+
|
140
|
+
## Contact information
|
141
|
+
|
142
|
+
Ruby-Cute is maintained by the Algorille team at LORIA/Inria Nancy - Grand Est, and specifically by:
|
143
|
+
|
14
144
|
* Sébastien Badia <sebastien.badia@inria.fr>
|
15
145
|
* Tomasz Buchert <tomasz.buchert@inria.fr>
|
16
146
|
* Emmanuel Jeanvoine <emmanuel.jeanvoine@inria.fr>
|
17
147
|
* Lucas Nussbaum <lucas.nussbaum@loria.fr>
|
18
148
|
* Luc Sarzyniec <luc.sarzyniec@inria.fr>
|
149
|
+
* Cristian Ruiz <cristian.ruiz@inria.fr>
|
19
150
|
|
20
151
|
Questions/comments should be directed to Lucas Nussbaum and Emmanuel Jeanvoine.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rake/packagetask'
|
2
|
+
require 'rubygems/package_task'
|
3
|
+
require 'yard'
|
4
|
+
require 'rake'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'bundler/gem_tasks'
|
7
|
+
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
|
+
|
10
|
+
GEM='ruby-cute'
|
11
|
+
|
12
|
+
def get_version
|
13
|
+
Cute::VERSION
|
14
|
+
end # def:: get_version
|
15
|
+
|
16
|
+
desc "Run spec tests"
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
19
|
+
spec.ruby_opts = "-I lib:spec -w"
|
20
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Generate source tgz package"
|
24
|
+
Rake::PackageTask::new("ruby-cute",get_version) do |p|
|
25
|
+
p.need_tar_gz = true
|
26
|
+
p.package_files.include('lib/**/*')
|
27
|
+
p.package_files.include('ext/**/*')
|
28
|
+
p.package_files.include('bin/**/*')
|
29
|
+
p.package_files.include('test/**/*')
|
30
|
+
p.package_files.include('Rakefile', 'COPYING','README', 'README.md')
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Builds a Debian package"
|
34
|
+
task :debian do
|
35
|
+
sh 'dpkg-buildpackage -us -uc'
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Builds a git snapshot package"
|
39
|
+
task :snapshot do
|
40
|
+
sh 'cp debian/changelog debian/changelog.git'
|
41
|
+
date = `date --iso=seconds |sed 's/+.*//' |sed 's/[-T:]//g'`.chomp
|
42
|
+
sh "sed -i '1 s/)/+git#{date})/' debian/changelog"
|
43
|
+
sh 'dpkg-buildpackage -us -uc'
|
44
|
+
sh 'mv debian/changelog.git debian/changelog'
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
task :default => :spec
|
data/bin/cute
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
ROOT_DIR= File.expand_path('../..',__FILE__)
|
5
|
+
BIN_DIR= File.join(ROOT_DIR,"bin")
|
6
|
+
|
7
|
+
if `which pry` && $?.success? then
|
8
|
+
PRY_BIN="pry"
|
9
|
+
elsif File.exist?("~/.gem/bin/pry")
|
10
|
+
PRY_BIN="~/.gem/bin/pry"
|
11
|
+
else
|
12
|
+
# We use the default ruby interactive shell
|
13
|
+
PRY_BIN="irb"
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
cute_init_file = File.open("#{Dir.mktmpdir}/cute_init.rb",'w+')
|
18
|
+
cute_init_file.puts "require 'cute'\n$g5k = Cute::G5K::API.new()"
|
19
|
+
cute_init_file.close
|
20
|
+
|
21
|
+
|
22
|
+
exec("#{PRY_BIN} -r #{cute_init_file.path}")
|
data/debian/changelog
ADDED
data/debian/compat
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
8
|
data/debian/control
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Source: ruby-cute
|
2
|
+
Section: ruby
|
3
|
+
Priority: optional
|
4
|
+
Maintainer: Lucas Nussbaum <lucas@debian.org>
|
5
|
+
Build-Depends: debhelper (>= 8~), gem2deb (>= 0.3.0~), rake, yard, ruby-redcloth, bc
|
6
|
+
Standards-Version: 3.9.3
|
7
|
+
Homepage: http://ruby-cute.gforge.inria.fr/
|
8
|
+
XS-Ruby-Versions: all
|
9
|
+
|
10
|
+
Package: ruby-cute
|
11
|
+
Architecture: all
|
12
|
+
XB-Ruby-Versions: ${ruby:Versions}
|
13
|
+
Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter
|
14
|
+
Description: Critically Useful Tools for Experiments
|
15
|
+
|
data/debian/copyright
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
2
|
+
Upstream-Name: ruby-cute
|
3
|
+
Source: FIXME <http://example.com/>
|
4
|
+
|
5
|
+
Files: *
|
6
|
+
Copyright: <years> <put author's name and email here>
|
7
|
+
<years> <likewise for another author>
|
8
|
+
License: GPL-2+ (FIXME)
|
9
|
+
This program is free software; you can redistribute it
|
10
|
+
and/or modify it under the terms of the GNU General Public
|
11
|
+
License as published by the Free Software Foundation; either
|
12
|
+
version 2 of the License, or (at your option) any later
|
13
|
+
version.
|
14
|
+
.
|
15
|
+
This program is distributed in the hope that it will be
|
16
|
+
useful, but WITHOUT ANY WARRANTY; without even the implied
|
17
|
+
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
18
|
+
PURPOSE. See the GNU General Public License for more
|
19
|
+
details.
|
20
|
+
.
|
21
|
+
You should have received a copy of the GNU General Public
|
22
|
+
License along with this package; if not, write to the Free
|
23
|
+
Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
24
|
+
Boston, MA 02110-1301 USA
|
25
|
+
.
|
26
|
+
On Debian systems, the full text of the GNU General Public
|
27
|
+
License version 2 can be found in the file
|
28
|
+
`/usr/share/common-licenses/GPL-2'.
|
29
|
+
|
30
|
+
Files: debian/*
|
31
|
+
Copyright: 2013 Lucas Nussbaum <lucas@debian.org>
|
32
|
+
License:
|
33
|
+
[LICENSE TEXT]
|
data/debian/rules
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/make -f
|
2
|
+
#export DH_VERBOSE=1
|
3
|
+
#
|
4
|
+
# Uncomment to ignore all test failures (but the tests will run anyway)
|
5
|
+
#export DH_RUBY_IGNORE_TESTS=all
|
6
|
+
#
|
7
|
+
# Uncomment to ignore some test failures (but the tests will run anyway).
|
8
|
+
# Valid values:
|
9
|
+
#export DH_RUBY_IGNORE_TESTS=ruby1.8 ruby1.9.1 require-rubygems
|
10
|
+
#
|
11
|
+
# If you need to specify the .gemspec (eg there is more than one)
|
12
|
+
#export DH_RUBY_GEMSPEC=gem.gemspec
|
13
|
+
|
14
|
+
%:
|
15
|
+
dh $@ --buildsystem=ruby --with ruby
|
16
|
+
|
17
|
+
override_dh_auto_build:
|
18
|
+
dh_auto_build
|
19
|
+
yard
|
@@ -0,0 +1 @@
|
|
1
|
+
3.0 (native)
|
data/debian/watch
ADDED
@@ -0,0 +1,516 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# distem-bootstrap is a script to configure a set of nodes as distem nodes
|
4
|
+
#
|
5
|
+
####
|
6
|
+
# distem-bootstrap is Copyright (C) 2011 Luc Sarzyniec <luc.sarzyniec@inria.fr>
|
7
|
+
# Secondary contact: Lucas Nussbaum <lucas.nussbaum@loria.fr>
|
8
|
+
#
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This program is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
######
|
22
|
+
require 'rubygems'
|
23
|
+
require 'socket'
|
24
|
+
require 'tmpdir'
|
25
|
+
require 'net/scp'
|
26
|
+
require 'etc'
|
27
|
+
require 'yaml'
|
28
|
+
require 'optparse'
|
29
|
+
require 'timeout'
|
30
|
+
require 'logger'
|
31
|
+
require 'cute'
|
32
|
+
|
33
|
+
logger = Logger.new(STDOUT)
|
34
|
+
|
35
|
+
def g5k?
|
36
|
+
`hostname --fqdn`.chomp =~ /grid5000\.fr$/
|
37
|
+
end
|
38
|
+
|
39
|
+
PKG_NAME = 'distem'
|
40
|
+
DEB_REPOSITORY = 'http://distem.gforge.inria.fr/deb'
|
41
|
+
HTTP_PROXY = 'proxy:3128'
|
42
|
+
SSH_KEYS_PATH = File.join(ENV['HOME'],'.ssh')
|
43
|
+
PATH_DISTEMD_LOGS = '/var/log/distem'
|
44
|
+
TMP_DIR = '/tmp/distem'
|
45
|
+
VAR_DISTEM_NODES = 'DISTEM_NODES'
|
46
|
+
VAR_DISTEM_COORD = 'DISTEM_COORDINATOR'
|
47
|
+
STATS_PORT = 12345
|
48
|
+
if g5k?
|
49
|
+
GIT_REPOSITORY = "https://gforge.inria.fr/git/distem/distem.git"
|
50
|
+
GERRIT_REPOSITORY = "http://gerrit.nancy.grid5000.fr:8080/gerrit/p/distem"
|
51
|
+
STATS_SERV = "carol.nancy.grid5000.fr"
|
52
|
+
else
|
53
|
+
GIT_REPOSITORY = "https://gforge.inria.fr/git/distem/distem.git"
|
54
|
+
GERRIT_REPOSITORY = "https://intranet.grid5000.fr/gerrit/p/distem"
|
55
|
+
STATS_SERV = ""
|
56
|
+
end
|
57
|
+
|
58
|
+
ULIMIT_OPEN_FILES = 65535 # to be removed
|
59
|
+
|
60
|
+
pkg_utils=[
|
61
|
+
'htop'
|
62
|
+
]
|
63
|
+
|
64
|
+
pkg_tmp_dependencies=[]
|
65
|
+
|
66
|
+
pkg_build=[
|
67
|
+
'git',
|
68
|
+
'rake'
|
69
|
+
]
|
70
|
+
|
71
|
+
pkg_build_gem=[
|
72
|
+
#'rake-compiler'
|
73
|
+
]
|
74
|
+
|
75
|
+
options = {}
|
76
|
+
@options = options
|
77
|
+
|
78
|
+
|
79
|
+
$startt = Time::now
|
80
|
+
|
81
|
+
options[:init_pnodes] = true
|
82
|
+
options[:coordinator] = nil
|
83
|
+
options[:node_list] = nil
|
84
|
+
options[:debpackages] = []
|
85
|
+
options[:gempackages] = []
|
86
|
+
options[:git] = nil
|
87
|
+
options[:gerrit] = nil
|
88
|
+
options[:ssh_key] = nil
|
89
|
+
options[:debug] = false
|
90
|
+
options[:distem_version] = nil
|
91
|
+
options[:debug_distem] = false
|
92
|
+
options[:stats] = true
|
93
|
+
options[:git_url] = GIT_REPOSITORY
|
94
|
+
options[:verbose] = false
|
95
|
+
options[:max_vifaces] = nil
|
96
|
+
options[:cow] = nil
|
97
|
+
options[:ci] = nil
|
98
|
+
options[:network_mode] = 'classical'
|
99
|
+
options[:network_interface] = nil
|
100
|
+
options[:num_nodes] = 2
|
101
|
+
options[:walltime] = "2:00:00"
|
102
|
+
|
103
|
+
args = ARGV.dup
|
104
|
+
|
105
|
+
optparse = OptionParser.new do |opts|
|
106
|
+
opts.banner = "Usage: #{$0} [options] [<script_to_execute>]"
|
107
|
+
opts.separator ""
|
108
|
+
opts.separator "distem-bootstrap automatically sets up a distem environment."
|
109
|
+
opts.separator "When run without options, it will create a distem environment with the latest"
|
110
|
+
opts.separator "released version of distem. It will perform a reservation as follows:"
|
111
|
+
opts.separator "slash_22=1+/nodes=2,walltime=02:00 --name=distem --type=deploy"
|
112
|
+
opts.separator "and deploy the environment: \"wheezy-x64-nfs\""
|
113
|
+
opts.separator ""
|
114
|
+
opts.separator "Options:"
|
115
|
+
|
116
|
+
opts.on( '--nodes <number of nodes>', Integer,'Number of nodes to reserve on Grid5000') do |n|
|
117
|
+
options[:num_nodes] = n.to_i
|
118
|
+
end
|
119
|
+
opts.on( '-t', '--time <walltime>', 'Walltime for the reservation on Grid5000') do |n|
|
120
|
+
options[:walltime] = n
|
121
|
+
end
|
122
|
+
opts.on( '-c', '--coordinator <coordinator_address>', 'Address of the coordinator (default: first node)' ) do |c|
|
123
|
+
options[:coordinator] = c || nil
|
124
|
+
end
|
125
|
+
opts.on( '-x', '--no-init-pnodes', 'Do not initialize all pnodes' ) do |c|
|
126
|
+
options[:init_pnodes] = false
|
127
|
+
end
|
128
|
+
opts.on( '--max-vifaces <nb>', 'Set the maximum number of vifaces on a physical node (used only without --no-init-pnodes)' ) do |n|
|
129
|
+
options[:max_vifaces] = n
|
130
|
+
end
|
131
|
+
opts.on( '-d', '--debug', 'Debug mode (display commands executed on nodes)' ) do
|
132
|
+
options[:debug] = true
|
133
|
+
end
|
134
|
+
opts.on( '-D', '--distem-debug', 'Show distem output when executing distem commands (script, node init)' ) do
|
135
|
+
options[:debug_distem] = true
|
136
|
+
end
|
137
|
+
opts.on( '-k', '--ssh-key [<ssh_key_file>]', 'Path of the ssh private key to use' ) do |k|
|
138
|
+
options[:ssh_key] = k
|
139
|
+
end
|
140
|
+
opts.on( '-p', '--debpackages <package1>,<package2>,<...>', Array, 'Additional debian packages to install on coordinator' ) do |p|
|
141
|
+
options[:debpackages] = p
|
142
|
+
end
|
143
|
+
opts.on( '-r', '--gempackages <package1>,<package2>,<...>', Array, 'Additional gem packages to install on coordinator' ) do |p|
|
144
|
+
options[:gempackages] = p
|
145
|
+
end
|
146
|
+
opts.on( '--distem-version <distem_version>', 'Version of distem to install (default: latest)' ) do |v|
|
147
|
+
options[:distem_version] = v
|
148
|
+
end
|
149
|
+
opts.on( '-g', '--git [<git_hash|git_tag>]', "Install a git snapshot of distem (default: master). Additional packages are installed on the coordinator to rebuild the Debian package" ) do |n|
|
150
|
+
options[:git] = n || :git_last
|
151
|
+
end
|
152
|
+
opts.on( '-U', '--git-url <git_repository>', "Overwrite the default distem git repository" ) do |repo|
|
153
|
+
options[:git_url] = repo
|
154
|
+
end
|
155
|
+
opts.on( '-G', '--gerrit <gerrit_ref>', "Checkout a gerrit ref (e.g refs/changes/94/94/1) and rebuild a Debian package" ) do |n|
|
156
|
+
options[:gerrit] = n
|
157
|
+
end
|
158
|
+
opts.on( '-S', '--stealth-mode', 'Do not report usage statistics (Grid\'5000 only)' ) do |c|
|
159
|
+
options[:stats] = false
|
160
|
+
end
|
161
|
+
opts.on( '--btrfs-format <tmp_device>', 'Format the device with btrfs support to allow COW on Vnodes (experimental)' ) do |d|
|
162
|
+
options[:cow] = d
|
163
|
+
end
|
164
|
+
opts.on( '--ci <path>', 'Path to the distem source directory (used only for CI purpose)' ) do |path|
|
165
|
+
options[:ci] = path
|
166
|
+
end
|
167
|
+
opts.on( '-n', '--network-mode <mode>', 'Define the network mode (classical or vxlan)') do |mode|
|
168
|
+
case mode
|
169
|
+
when 'classical'
|
170
|
+
when 'vxlan'
|
171
|
+
else
|
172
|
+
puts 'Invalid network mode'
|
173
|
+
exit 1
|
174
|
+
end
|
175
|
+
options[:network_mode] = mode
|
176
|
+
end
|
177
|
+
opts.on( '-i', '--network-interface <iface>', 'Define the root network interface for inter-pnode communication (use only with vxlan network mode)') do |iface|
|
178
|
+
options[:network_interface] = iface
|
179
|
+
end
|
180
|
+
opts.on( '--verbose', 'Activate the verbose mode on Distem servers' ) do
|
181
|
+
options[:verbose] = true
|
182
|
+
end
|
183
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
184
|
+
puts opts
|
185
|
+
exit
|
186
|
+
end
|
187
|
+
opts.separator ""
|
188
|
+
opts.separator "When executing a script, the file containing the list of nodes is available in the #{VAR_DISTEM_NODES}"
|
189
|
+
opts.separator "environment variable, while the address of the coordinator is in #{VAR_DISTEM_COORD}."
|
190
|
+
opts.separator ""
|
191
|
+
opts.separator "Examples:"
|
192
|
+
opts.separator "# run script.rb against the latest git snapshot of distem"
|
193
|
+
opts.separator "distem-bootstrap --nodes=4 --no-init-pnodes --git -- script.rb"
|
194
|
+
opts.separator "# setup distem, installing additional packages"
|
195
|
+
opts.separator "distem-bootstrap --nodes=10 -t \"04:00:00\" -p htop -r restfully -f nodes"
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
begin
|
200
|
+
optparse.parse!
|
201
|
+
rescue OptionParser::InvalidOption => e
|
202
|
+
logger.error(e.to_s)
|
203
|
+
end
|
204
|
+
|
205
|
+
logger.level = Logger::INFO
|
206
|
+
logger.level = Logger::DEBUG if options[:debug]
|
207
|
+
|
208
|
+
g5k = Cute::G5K::API.new()
|
209
|
+
g5k.logger = logger
|
210
|
+
## performing reservation with ruby-cute
|
211
|
+
|
212
|
+
reserv_param = {:site => g5k.site, :nodes => options[:num_nodes], :name => 'distem',
|
213
|
+
:walltime => options[:walltime], :env =>'wheezy-x64-nfs', :subnets => [22,1]}
|
214
|
+
|
215
|
+
reserv_param[:keys] = options[:ssh_key] unless options[:ssh_key].nil?
|
216
|
+
|
217
|
+
|
218
|
+
# we verify if we have already submit a job
|
219
|
+
old_jobs = g5k.get_my_jobs(g5k.site).select{ |j| j["name"] == "distem"}
|
220
|
+
|
221
|
+
job = old_jobs.empty? ? g5k.reserve(reserv_param) : old_jobs.first
|
222
|
+
|
223
|
+
nodelist = job.resources["cores"].uniq
|
224
|
+
## wait for the deploy
|
225
|
+
|
226
|
+
g5k.wait_for_deploy(job)
|
227
|
+
|
228
|
+
allnodes = nodelist.dup
|
229
|
+
|
230
|
+
# Generating ssh keys"
|
231
|
+
|
232
|
+
key_dir = Dir.mktmpdir("keys")
|
233
|
+
system "ssh-keygen -P \'\' -f #{key_dir}/keys"
|
234
|
+
logger.info "Keys generated in #{key_dir}"
|
235
|
+
|
236
|
+
nodelist.each do |node|
|
237
|
+
|
238
|
+
Net::SCP.start(node, "root") do |scp|
|
239
|
+
logger.debug "Transfering key to #{node}"
|
240
|
+
scp.upload! "#{key_dir}/keys.pub", "/root/.ssh/id_rsa.pub"
|
241
|
+
scp.upload! "#{key_dir}/keys", "/root/.ssh/id_rsa"
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
# Deletating keys
|
247
|
+
FileUtils.rm_rf(key_dir)
|
248
|
+
|
249
|
+
if options[:coordinator]
|
250
|
+
coordinator = options[:coordinator]
|
251
|
+
else
|
252
|
+
coordinator = nodelist[0]
|
253
|
+
end
|
254
|
+
|
255
|
+
if nodelist.include?(coordinator)
|
256
|
+
nodelist.delete(coordinator)
|
257
|
+
else
|
258
|
+
tmp = nodelist.select { |node| node =~ /^#{coordinator}/ }
|
259
|
+
if tmp.empty?
|
260
|
+
logger.warn("Coordinator not present in <nodes_file>")
|
261
|
+
else
|
262
|
+
logger.warn("Coordinator '#{coordinator}' assumed to be '#{tmp[0]}' (which is present in <nodes_file>)")
|
263
|
+
coordinator = tmp[0]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
logger.info("Establishing SSH connections to all nodes")
|
269
|
+
|
270
|
+
Net::SSH::Multi.logger = logger # setting the default logger.
|
271
|
+
|
272
|
+
Net::SSH::Multi.start do |session|
|
273
|
+
nodeobjlist = {}
|
274
|
+
begin
|
275
|
+
session.group :coord do
|
276
|
+
nodeobjlist[coordinator] = session.use("root@#{coordinator}")
|
277
|
+
end
|
278
|
+
#test connection
|
279
|
+
session.with(:coord).exec! "hostname"
|
280
|
+
rescue SocketError
|
281
|
+
logger.error("can't connect to #{coordinator}")
|
282
|
+
end
|
283
|
+
|
284
|
+
begin
|
285
|
+
session.group :nodes do
|
286
|
+
nodelist.each{ |node| session.use("root@#{node}")}
|
287
|
+
end
|
288
|
+
#test connection
|
289
|
+
session.with(:nodes).exec! "hostname"
|
290
|
+
rescue SocketError
|
291
|
+
logger.error("can't connect to #{node}")
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
# Check nfs paths ## comment: this is probably unnecessary given that now we are controlling the deployment with rubycute.
|
296
|
+
tmp = session.exec! "ls -a #{ENV['HOME']}"
|
297
|
+
nopath = allnodes - tmp.keys
|
298
|
+
nopath.each do |node|
|
299
|
+
logger.warn("NFS do not seems to be mounted on #{node} (check that you have deployed with NFS env")
|
300
|
+
end
|
301
|
+
|
302
|
+
# generating ssh password less connection
|
303
|
+
session.exec! "cat .ssh/id_rsa.pub >> .ssh/authorized_keys"
|
304
|
+
|
305
|
+
if options[:cow]
|
306
|
+
logger.infor("Format #{options[:cow]} to Btrfs")
|
307
|
+
session.exec! "(umount /tmp || true) && mkfs.btrfs #{options[:cow]} && mount -o compress=lzo #{options[:cow]} /tmp && chmod 1777 /tmp"
|
308
|
+
end
|
309
|
+
|
310
|
+
#setting up ulimit-open_files, to be removed
|
311
|
+
rule="root hard nofile"
|
312
|
+
session.exec! "grep -q '#{rule}' /etc/security/limits.conf; true || echo '#{rule} #{ULIMIT_OPEN_FILES}' >> /etc/security/limits.conf"
|
313
|
+
rule="root soft nofile"
|
314
|
+
session.exec! "grep -q '#{rule}' /etc/security/limits.conf; true || echo '#{rule} #{ULIMIT_OPEN_FILES}' >> /etc/security/limits.conf"
|
315
|
+
|
316
|
+
# setup Debian repo
|
317
|
+
session.exec! "grep -q '#{DEB_REPOSITORY}' /etc/apt/sources.list || echo 'deb #{DEB_REPOSITORY} ./\ndeb-src #{DEB_REPOSITORY} ./' >> /etc/apt/sources.list"
|
318
|
+
|
319
|
+
logger.info "Updating debian packages list"
|
320
|
+
session.exec! "apt-get update -q"
|
321
|
+
|
322
|
+
if options[:git] or options[:gerrit]
|
323
|
+
logger.info("Installing debian build packages on #{coordinator}")
|
324
|
+
session.with(:coord).exec! "apt-get build-dep -y --force-yes distem"
|
325
|
+
session.with(:coord).exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y #{pkg_build * ' '}" unless pkg_build.empty?
|
326
|
+
unless pkg_build_gem.empty?
|
327
|
+
logger.info("Installing gems build packages on #{coordinator}")
|
328
|
+
session.with(:corrd).exec! "export http_proxy=#{HTTP_PROXY}; gem install #{pkg_build_gem * ' '}"
|
329
|
+
end
|
330
|
+
|
331
|
+
gitdir = "#{TMP_DIR}/git"
|
332
|
+
session.exec! "mkdir -p #{TMP_DIR}"
|
333
|
+
session.with(:coord).exec! "rm -Rf #{gitdir}"
|
334
|
+
|
335
|
+
if options[:git]
|
336
|
+
if options[:ci] != nil
|
337
|
+
logger.info("Syncing source repository on #{coordinator} with the current Gerrit repository")
|
338
|
+
system("rsync -rlut --delete #{options[:ci]}/* root@#{options[:coordinator]}:#{gitdir}")
|
339
|
+
else
|
340
|
+
logger.info("Retrieving '#{options[:git_url]}' repository on #{coordinator}")
|
341
|
+
if g5k?
|
342
|
+
session.with(:coord).exec! "https_proxy=#{HTTP_PROXY} GIT_SSL_NO_VERIFY=1 git clone #{options[:git_url]} #{gitdir}"
|
343
|
+
else
|
344
|
+
session.with(:coord).exec! "GIT_SSL_NO_VERIFY=1 git clone #{options[:git_url]} #{gitdir}"
|
345
|
+
end
|
346
|
+
unless options[:git] == :git_last
|
347
|
+
logger.info("Setting up git repository ref:#{options[:git]} on #{coordinator}")
|
348
|
+
session.with(:corrd).exec! "git --git-dir=#{gitdir}/.git reset --hard #{options[:git]}"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
else # gerrit
|
352
|
+
logger.info("Setting up git repository from gerrit ref:#{options[:gerrit]} on #{coordinator}")
|
353
|
+
session.with(:coord).exec! "git clone #{GERRIT_REPOSITORY} #{gitdir}"
|
354
|
+
session.with(:coord).exec! "cd #{gitdir} && git fetch #{GERRIT_REPOSITORY} #{options[:gerrit]} && git checkout FETCH_HEAD"
|
355
|
+
end
|
356
|
+
logger.info("Building debian package of distem on #{coordinator}")
|
357
|
+
session.with(:coord).exec! "rm -f #{TMP_DIR}/*.deb #{TMP_DIR}/*.changes #{TMP_DIR}/*.dsc #{TMP_DIR}/*.tar.gz"
|
358
|
+
session.with(:coord).exec! "cd #{gitdir}; rake snapshot"
|
359
|
+
|
360
|
+
debarchivefile = session.with(:coord).exec! "find #{TMP_DIR} -maxdepth 1 -name *.deb"
|
361
|
+
|
362
|
+
session.with(:coord).exec! "Copying generated debian package #{File.basename(debarchivefile)}"
|
363
|
+
|
364
|
+
#exec(session,"cp #{debarchivefile} #{TMP_DIR}",:coord,true)
|
365
|
+
nodelist.each {|node| session.with(:coord).exec! "scp -o StrictHostKeyChecking=no #{debarchivefile} root@#{node}:#{TMP_DIR}"}
|
366
|
+
logger.info("Installing generated debian package #{File.basename(debarchivefile)}")
|
367
|
+
depends = session.with(:coord).exec! "dpkg -I #{debarchivefile} | grep 'Depends:'"
|
368
|
+
|
369
|
+
depends = depends.split("|").last.gsub!(' ','')
|
370
|
+
session.exec! "dpkg --ignore-depends #{depends} -i #{TMP_DIR}/#{File.basename(debarchivefile)}"
|
371
|
+
|
372
|
+
session.exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y --force-yes -f"
|
373
|
+
logger.info("Cleaning installation files on #{coordinator}")
|
374
|
+
session.with(:coord).exec! "rm -Rf #{gitdir}"
|
375
|
+
session.with(:coord).exec! "rm -f #{TMP_DIR}/*.deb #{TMP_DIR}/*.changes #{TMP_DIR}/*.dsc #{TMP_DIR}/*.tar.gz"
|
376
|
+
else
|
377
|
+
logger.info("Installing debian distem packages")
|
378
|
+
distempkg = options[:distem_version] ? "#{PKG_NAME}=#{options[:distem_version]}":PKG_NAME
|
379
|
+
session.exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y --allow-unauthenticated #{distempkg}"
|
380
|
+
end
|
381
|
+
|
382
|
+
logger.info("Installing debian misc packages")
|
383
|
+
session.exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y #{pkg_tmp_dependencies * ' '}" unless pkg_tmp_dependencies.empty?
|
384
|
+
session.exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y #{pkg_utils * ' '}" unless pkg_utils.empty?
|
385
|
+
options[:debpackages].each do |debpkg|
|
386
|
+
logger.info("Installing additional debian package '#{debpkg}'")
|
387
|
+
session.exec! "DEBIAN_FRONTEND=noninteractive apt-get install -q -y #{debpkg}"
|
388
|
+
end
|
389
|
+
options[:gempackages].each do |gempkg|
|
390
|
+
logger.info "Installing additional gem package '#{gempkg}'"
|
391
|
+
session.with(:coord).exec! "export http_proxy=#{HTTP_PROXY}; gem install #{gempkg}"
|
392
|
+
end
|
393
|
+
|
394
|
+
if options[:init_pnodes] or ARGV[0]
|
395
|
+
|
396
|
+
launched = session.exec! "lsof -Pnl -i4 | egrep ':4567 |:4568'"
|
397
|
+
launched_stdout = launched.values.select{ |x| x[:stdout] }
|
398
|
+
|
399
|
+
unless launched_stdout.empty?
|
400
|
+
tokill = launched.keys
|
401
|
+
|
402
|
+
session.group :tokill do
|
403
|
+
tokill.each{ |node| session.use "root@#{node}"
|
404
|
+
logger.debug("Distem detected on #{node}")
|
405
|
+
}
|
406
|
+
end
|
407
|
+
tokill.collect!{ |node| nodeobjlist[node] }
|
408
|
+
tokill.each { |node|
|
409
|
+
logger.info("Killing previous run of distem on #{node}")
|
410
|
+
}
|
411
|
+
session.with(:tokill).exec! "killall distemd"
|
412
|
+
time_start = Time.now
|
413
|
+
until !launched_stdout or launched_stdout.empty?
|
414
|
+
session.with(:tokill).exec! 'kill -9 `ps aux|grep "distemd"|grep -v grep|sed "s/ \{1,\}/ /g"|cut -f 2 -d" "`' if (Time.now - time_start) > 2
|
415
|
+
launched = session.with(:tokill).exec! "lsof -Pnl -i4 | egrep ':4567 |:4568 '"
|
416
|
+
launched_stdout = launched.values.select{ |x| x[:stdout] }
|
417
|
+
|
418
|
+
if launched_stdout and !launched_stdout.empty?
|
419
|
+
tokill = launched.keys
|
420
|
+
tokill.collect!{ |node| nodeobjlist[node] }
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
logger.info("Starting coordinator daemon on #{coordinator}")
|
425
|
+
session.with(:coord).exec! "mkdir -p #{PATH_DISTEMD_LOGS}"
|
426
|
+
begin
|
427
|
+
Timeout.timeout(10) do
|
428
|
+
root_iface_opt = options[:network_interface] ? "--network-interface #{options[:network_interface]}" : ''
|
429
|
+
distem_cmd = "LANG=C distemd #{options[:verbose] ? '--verbose' : ''} --network-mode "+
|
430
|
+
"#{options[:network_mode]} #{root_iface_opt} -d &>#{File.join(PATH_DISTEMD_LOGS,'distemd.log')}&"
|
431
|
+
|
432
|
+
session.with(:coord).exec! distem_cmd
|
433
|
+
|
434
|
+
[ '4567', '4568' ].each do |port|
|
435
|
+
launched = []
|
436
|
+
until launched and !launched.empty?
|
437
|
+
launched = session.with(:coord).exec! "lsof -Pnl -i4 | grep ':#{port} '"
|
438
|
+
launched[coordinator][:stdout]
|
439
|
+
sleep(1)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
rescue Timeout::Error
|
444
|
+
logger.error("Timeout reached")
|
445
|
+
end
|
446
|
+
|
447
|
+
if options[:init_pnodes]
|
448
|
+
begin
|
449
|
+
Timeout.timeout(180) do
|
450
|
+
logger.info("Initializing node #{coordinator}")
|
451
|
+
if options[:max_vifaces]
|
452
|
+
session.with(:coord).exec! "distem --coordinator host=#{coordinator} --init-pnode #{coordinator} --max-vifaces #{options[:max_vifaces]}"
|
453
|
+
# options[:debug_distem],options[:debug_distem]) this would be controlled using the logger.
|
454
|
+
else
|
455
|
+
session.with(:coord).exec! "distem --coordinator host=#{coordinator} --init-pnode #{coordinator}" # the same for this I have to add debug
|
456
|
+
end
|
457
|
+
if nodelist.length > 0
|
458
|
+
logger.info("Initializing nodes #{nodelist.join(',')}")
|
459
|
+
if options[:max_vifaces]
|
460
|
+
session.with(:coord).exec! "distem --coordinator host=#{coordinator} --init-pnode #{nodelist.join(',')} --max-vifaces #{options[:max_vifaces]}"
|
461
|
+
else
|
462
|
+
session.with(:coord).exec! "distem --coordinator host=#{coordinator} --init-pnode #{nodelist.join(',')}"
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
rescue Timeout::Error
|
467
|
+
logger.error("Timeout reached")
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
logger.info('Install done')
|
474
|
+
|
475
|
+
if ARGV[0]
|
476
|
+
begin
|
477
|
+
File.open(ARGV[0], 'r') do |f|
|
478
|
+
filename = session.with(:coord).exec!('tempfile')[coordinator][0]
|
479
|
+
logger.info("Copying script file in '#{filename}' on #{coordinator}")
|
480
|
+
`scp #{ARGV[0]} root@#{coordinator}:#{filename}`
|
481
|
+
session.with(:coord).exec! "chmod +x #{filename}"
|
482
|
+
logger.info("Executing script file '#{filename}' on #{coordinator}")
|
483
|
+
|
484
|
+
argv_dup = ARGV.dup
|
485
|
+
argv_dup.shift
|
486
|
+
script_args = (argv_dup.length > 0 ? argv_dup.join(" ") : "")
|
487
|
+
session.with(:coord).exec! "export #{VAR_DISTEM_NODES}='#{(nodelist + [coordinator]) * "\n"}'; export #{VAR_DISTEM_COORD}='#{coordinator}';#{filename} #{script_args}"
|
488
|
+
session.with(:coord).exec! "rm #{filename}"
|
489
|
+
end
|
490
|
+
logger.info 'Script execution done'
|
491
|
+
rescue Errno::ENOENT
|
492
|
+
logger.error "script file '#{ARGV[0]}' not found"
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
logger.info("Coordinator: #{coordinator}") if options[:init_pnodes] or ARGV[0]
|
497
|
+
|
498
|
+
# Send stats record to stats server
|
499
|
+
if g5k? and options[:stats]
|
500
|
+
begin
|
501
|
+
stats = {
|
502
|
+
:time => Time.now.to_i,
|
503
|
+
:site => Socket.gethostname,
|
504
|
+
:user => ENV['USER'],
|
505
|
+
:oar => ENV['OAR_JOB_ID'].to_i,
|
506
|
+
:nodes => allnodes,
|
507
|
+
:params => args * ' ',
|
508
|
+
:length => (Time.now - $startt).to_i
|
509
|
+
}
|
510
|
+
sock = TCPSocket.open(STATS_SERV, STATS_PORT)
|
511
|
+
sock.send(stats.to_yaml,0)
|
512
|
+
sock.close
|
513
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EHOSTUNREACH
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|