claudius 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -1
- data/claudius.gemspec +1 -1
- data/examples/on_instance.rb +42 -11
- data/examples/simple_program.rb +15 -5
- data/examples/specify_instances.rb +11 -11
- data/lib/tree_building/claudius.rb +48 -53
- data/lib/tree_building/concurrent_node.rb +5 -31
- data/lib/tree_building/execution_node.rb +16 -12
- data/lib/tree_building/node.rb +24 -17
- data/lib/tree_building/on_node.rb +5 -35
- data/test/execution_test.rb +1 -2
- metadata +2 -4
- data/test/test.rb +0 -46
data/README.md
CHANGED
@@ -7,7 +7,9 @@ Claudius is a easy-to-use domain specific language for clouds experiments. Langu
|
|
7
7
|
|
8
8
|
Install it as:
|
9
9
|
|
10
|
-
$ sudo gem install claudius
|
10
|
+
$ sudo gem install claudius
|
11
|
+
|
12
|
+
If you want export execution tree to image you need [Graphivz](http://www.graphviz.org).
|
11
13
|
|
12
14
|
## Usage
|
13
15
|
|
data/claudius.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "claudius"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.2"
|
8
8
|
spec.authors = ["radk0s", "blost"]
|
9
9
|
spec.email = ["rachamot@gmail.com"]
|
10
10
|
spec.description = "Write a gem description"
|
data/examples/on_instance.rb
CHANGED
@@ -1,15 +1,46 @@
|
|
1
|
+
require 'claudius'
|
2
|
+
require "awesome_print"
|
1
3
|
|
2
|
-
|
3
|
-
|
4
|
-
#
|
4
|
+
experiment_tree = experiment 'sdsdf' do
|
5
|
+
define_providers do
|
6
|
+
# cloud('aws', :provider => config['provider'],
|
7
|
+
# :region=>config['region'],
|
8
|
+
# :aws_access_key_id => config['aws_access_key_id'],
|
9
|
+
# :aws_secret_access_key => config['aws_secret_access_key'])
|
10
|
+
# .create_instances(['t1.micro'], 'ubuntu', './Piotr-key-pair-irleand.pem',
|
11
|
+
# :key_name => 'Piotr-key-pair-irleand',
|
12
|
+
# :groups => 'Piotr-irleand')
|
13
|
+
manual('kali', '192.168.1.116', 'root', :password => 'toor', :port => 22)
|
14
|
+
end
|
5
15
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
foreach ['kali', 't1.micro'] do |instance|
|
17
|
+
foreach ['a', 'b'] do |param|
|
18
|
+
before do
|
19
|
+
end
|
20
|
+
on instance do
|
21
|
+
execute 'install prerequisites' do
|
22
|
+
ssh "curl -O http://pegasus.isi.edu/montage/Montage_v3.3_patched_4.tar.gz"
|
23
|
+
ssh "tar zxvf Montage_v3.3_patched_4.tar.gz"
|
24
|
+
ssh "cd Montage_v3.3_patched_4"
|
25
|
+
ssh "make"
|
26
|
+
ssh "cd .."
|
27
|
+
ssh "git clone https://github.com/dice-cyfronet/hyperflow.git --depth 1 -b develop"
|
28
|
+
ssh "cd hyperflow"
|
29
|
+
ssh "npm install"
|
30
|
+
ssh "curl -O https://dl.dropboxusercontent.com/u/81819/hyperflow-amqp-executor.gem"
|
31
|
+
ssh "echo toor | sudo -S gem2.0 install --no-ri --no-rdoc hyperflow-amqp-executor.gem"
|
32
|
+
end
|
33
|
+
execute do
|
34
|
+
ssh "date"
|
35
|
+
end
|
36
|
+
execute do
|
37
|
+
ssh "echo #{param}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
after do
|
41
|
+
end
|
42
|
+
end
|
14
43
|
end
|
15
44
|
end
|
45
|
+
|
46
|
+
experiment_tree.export_tree
|
data/examples/simple_program.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'awesome_print'
|
2
2
|
# Initiate experiment
|
3
3
|
# ---------
|
4
4
|
#
|
@@ -7,10 +7,20 @@
|
|
7
7
|
# To use the DSL in your code, please require the gem:
|
8
8
|
require 'claudius'
|
9
9
|
# We sepcified te __experiment__ with name "Hello". Tree which represents our experiment was returned after parse DSL.
|
10
|
-
execution_tree =
|
10
|
+
execution_tree =
|
11
|
+
experiment 'Hello Experiment' do
|
12
|
+
before do
|
13
|
+
ssh "echo $PATH"
|
14
|
+
end
|
15
|
+
|
11
16
|
# __execute__ is a block where we can specify particular commands.
|
12
|
-
execute do
|
17
|
+
execute do
|
13
18
|
# Each starts with __ssh__ following by string represets command.
|
14
|
-
|
15
|
-
|
19
|
+
ssh "echo Hello World! > TestFile"
|
20
|
+
end
|
16
21
|
end
|
22
|
+
|
23
|
+
# execute tree and print result time
|
24
|
+
ap execution_tree.run
|
25
|
+
# export tree to tree.png and tree.dot
|
26
|
+
execution_tree.export_tree('tree')
|
@@ -4,19 +4,19 @@
|
|
4
4
|
# To conduct an experiment remotely, You should define set of machines, which you would like to use. Claudius allows you to define 2 types of hosts - ones which are going to be created in clouds environment, and others which are already established (and you have access to them). To define machine and to maintain connection with them you should provide required parameters. For your convenience, you may store all yours parameters in json file, and recall them as it is presented in example.
|
5
5
|
#
|
6
6
|
require 'claudius'
|
7
|
-
config = load_config('./user_config.json')
|
7
|
+
# config = load_config('./user_config.json')
|
8
8
|
experiment 'Hello' do
|
9
9
|
define_providers do
|
10
|
-
cloud('aws', :provider => config['provider'],
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
.create_instances(['t1.micro=>in1'],
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
# cloud('aws', :provider => config['provider'],
|
11
|
+
# :region =>config['region'],
|
12
|
+
# :endpoint => 'https://ec2.eu-west-1.amazonaws.com/',
|
13
|
+
# :aws_access_key_id => config['aws_access_key_id'],
|
14
|
+
# :aws_secret_access_key => config['aws_secret_access_key'])
|
15
|
+
# .create_instances(['t1.micro=>in1'],
|
16
|
+
# :username => 'ubuntu',
|
17
|
+
# :private_key_path =>'./Piotr-key-pair-irleand.pem',
|
18
|
+
# :key_name => 'Piotr-key-pair-irleand',
|
19
|
+
# :groups => ['Piotr-irleand'])
|
20
20
|
manual('kali', '172.16.0.109', 'root', :password => 'toor')
|
21
21
|
end
|
22
22
|
foreach ['kali', 'in1'] do |instance|
|
@@ -7,31 +7,24 @@ def experiment(name, &block)
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class Experiment
|
10
|
-
#attr_accessor :child_node
|
11
|
-
|
12
|
-
$child_node
|
13
|
-
$current_node = nil
|
14
|
-
$tmp_asynchronously = false
|
15
|
-
$tmp_safely = false
|
16
|
-
$tmp_execution_place = 'localhost'
|
17
|
-
$in_after_scope = false
|
18
|
-
$in_before_scope = false
|
19
|
-
|
20
|
-
$root
|
21
|
-
|
22
10
|
def initialize(name, &block)
|
23
|
-
|
24
|
-
|
25
|
-
|
11
|
+
@child_node
|
12
|
+
@current_node = nil
|
13
|
+
@tmp_asynchronously = false
|
14
|
+
@tmp_safely = false
|
15
|
+
@tmp_execution_place = 'localhost'
|
16
|
+
@in_after_scope = false
|
17
|
+
@in_before_scope = false
|
18
|
+
@root = Node.new(nil,block)
|
19
|
+
@current_node = @root
|
20
|
+
@root.name = name
|
26
21
|
instance_eval(&block) if block
|
27
|
-
$root.print_tree
|
28
|
-
run_with_time
|
29
22
|
end
|
30
23
|
|
31
24
|
def asynchronously
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
@child_node = ConcurrentNode.new(@current_node, nil)
|
26
|
+
@current_node.node_list.push(@child_node)
|
27
|
+
@current_node = @child_node
|
35
28
|
end
|
36
29
|
|
37
30
|
def safely
|
@@ -39,71 +32,73 @@ class Experiment
|
|
39
32
|
end
|
40
33
|
|
41
34
|
def before(*args, &block)
|
42
|
-
|
35
|
+
@in_before_scope = true
|
43
36
|
yield
|
44
|
-
|
37
|
+
@in_before_scope = false
|
45
38
|
end
|
46
39
|
|
47
40
|
def after(*args, &block)
|
48
|
-
|
41
|
+
@in_after_scope = true
|
49
42
|
yield
|
50
|
-
|
43
|
+
@in_after_scope = false
|
51
44
|
end
|
52
45
|
|
53
46
|
def foreach(parameters, *args, &block)
|
54
|
-
puts
|
47
|
+
puts @current_node.name
|
55
48
|
parameters.each do |parameter|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
49
|
+
@child_node = Node.new(@current_node, block)
|
50
|
+
@child_node.is_safely = @tmp_safely
|
51
|
+
@child_node.is_asynchronously = @tmp_asynchronously
|
52
|
+
@current_node.node_list.push(@child_node)
|
53
|
+
@current_node = @child_node
|
61
54
|
block.call parameter
|
62
|
-
|
55
|
+
@current_node = @current_node.parent
|
63
56
|
end
|
64
57
|
end
|
65
58
|
|
66
59
|
def on(instance, *args, &block)
|
67
|
-
|
60
|
+
@child_node = OnNode.new(@current_node, instance, block)
|
68
61
|
|
69
|
-
|
70
|
-
|
62
|
+
@current_node.node_list.push(@child_node)
|
63
|
+
@current_node = @child_node
|
71
64
|
block.call
|
72
|
-
|
65
|
+
@current_node = @current_node.parent
|
73
66
|
end
|
74
67
|
|
75
68
|
def concurrent(*args, &block)
|
76
|
-
|
77
|
-
|
78
|
-
|
69
|
+
@child_node = ConcurrentNode.new(@current_node, block)
|
70
|
+
@current_node.node_list.push(@child_node)
|
71
|
+
@current_node = @child_node
|
79
72
|
block.call
|
80
|
-
|
73
|
+
@current_node = @current_node.parent
|
81
74
|
end
|
82
75
|
|
83
76
|
def execute(*args, &block)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
77
|
+
@child_node = ExecutionNode.new(@current_node, block)
|
78
|
+
@child_node.is_safely = @tmp_safely
|
79
|
+
@child_node.is_asynchronously = @tmp_asynchronously
|
80
|
+
@current_node.node_list.push(@child_node)
|
81
|
+
@current_node = @child_node
|
89
82
|
block.call
|
90
|
-
|
83
|
+
@current_node = @current_node.parent
|
91
84
|
end
|
92
85
|
|
93
86
|
def ssh(command)
|
94
|
-
if
|
95
|
-
|
87
|
+
if @in_before_scope
|
88
|
+
@current_node.before_list.push(command)
|
96
89
|
elsif $in_after_scope
|
97
|
-
|
90
|
+
@current_node.after_list.push(command)
|
98
91
|
else
|
99
|
-
|
92
|
+
@current_node.commands.push(command)
|
100
93
|
end
|
101
94
|
end
|
102
95
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
96
|
+
def run
|
97
|
+
@root.run(nil)
|
98
|
+
end
|
99
|
+
|
100
|
+
def export_tree(path = 'execution_tree')
|
101
|
+
@root.print_tree(path)
|
107
102
|
end
|
108
103
|
|
109
104
|
end
|
@@ -10,46 +10,20 @@ class ConcurrentNode < Node
|
|
10
10
|
|
11
11
|
def run(instance)
|
12
12
|
pids = []
|
13
|
-
|
14
|
-
{
|
15
|
-
:name => self.name,
|
16
|
-
:before => 0,
|
17
|
-
:exec => [],
|
18
|
-
:after => 0
|
19
|
-
}
|
20
|
-
|
21
|
-
start = Time.now
|
22
|
-
before_list.each do |before_command|
|
23
|
-
if instance.nil?
|
24
|
-
puts `"#{before_command}"`
|
25
|
-
else
|
26
|
-
$virtual_machines[instance].invoke [[before_command]]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
finish = Time.now
|
13
|
+
init_time
|
30
14
|
|
31
|
-
|
15
|
+
before_exec(instance, @total_time)
|
32
16
|
|
33
17
|
node_list.each do |node|
|
34
18
|
pids << fork do
|
35
|
-
|
19
|
+
@total_time[:exec].push(node.run(instance))
|
36
20
|
end
|
37
21
|
end
|
38
22
|
|
39
23
|
pids.each{|pid| Process.waitpid(pid)}
|
40
24
|
|
41
|
-
|
42
|
-
|
43
|
-
if instance.nil?
|
44
|
-
puts `"#{after_command}"`
|
45
|
-
else
|
46
|
-
$virtual_machines[instance].invoke [[after_command]]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
finish = Time.now
|
50
|
-
|
51
|
-
totalTime[:after] = finish - start
|
52
|
-
return totalTime
|
25
|
+
after_exec(instance, @total_time)
|
26
|
+
return @total_time
|
53
27
|
end
|
54
28
|
|
55
29
|
def draw_block(graph)
|
@@ -9,23 +9,27 @@ class ExecutionNode < Node
|
|
9
9
|
self.name = '[' + ExecutionNode.to_s + ']'
|
10
10
|
end
|
11
11
|
|
12
|
+
|
13
|
+
def init_time
|
14
|
+
@total_time =
|
15
|
+
{
|
16
|
+
:name => @name,
|
17
|
+
:before => 0,
|
18
|
+
:exec => [],
|
19
|
+
}
|
20
|
+
|
21
|
+
end
|
22
|
+
|
12
23
|
def draw_block(graph)
|
13
24
|
graph.rect << graph.node(id)
|
14
25
|
graph.node(id).label(name)
|
15
26
|
end
|
16
27
|
|
28
|
+
|
17
29
|
def run(instance)
|
18
|
-
|
19
|
-
{
|
20
|
-
:name => self.name,
|
21
|
-
:total => 0,
|
22
|
-
:before => 0,
|
23
|
-
:exec => {},
|
24
|
-
:after => 0
|
25
|
-
}
|
30
|
+
init_time
|
26
31
|
|
27
32
|
start = Time.now
|
28
|
-
|
29
33
|
commands.each_with_index do |command, index|
|
30
34
|
_start = Time.now
|
31
35
|
if instance.nil?
|
@@ -34,12 +38,12 @@ class ExecutionNode < Node
|
|
34
38
|
$virtual_machines[instance].invoke [[command]]
|
35
39
|
end
|
36
40
|
_finish = Time.now
|
37
|
-
|
41
|
+
@total_time[:exec].push( {:cmd => command, :time => _finish - _start})
|
38
42
|
end
|
39
43
|
finish = Time.now
|
40
44
|
|
41
|
-
|
42
|
-
return
|
45
|
+
@total_time[:total] = finish - start
|
46
|
+
return @total_time
|
43
47
|
end
|
44
48
|
|
45
49
|
end
|
data/lib/tree_building/node.rb
CHANGED
@@ -19,15 +19,27 @@ class Node
|
|
19
19
|
self.name = '[Node]'
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
22
|
+
def init_time
|
23
|
+
@total_time =
|
24
24
|
{
|
25
|
-
:name =>
|
26
|
-
:
|
27
|
-
:exec => [],
|
28
|
-
:after => 0
|
25
|
+
:name => @name,
|
26
|
+
:exec => []
|
29
27
|
}
|
30
28
|
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(instance)
|
32
|
+
init_time
|
33
|
+
before_exec(instance, @total_time)
|
34
|
+
node_list.each do |node|
|
35
|
+
@total_time[:exec].push(node.run(instance))
|
36
|
+
end
|
37
|
+
after_exec(instance, @total_time)
|
38
|
+
|
39
|
+
return @total_time
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_exec(instance, total_time)
|
31
43
|
start = Time.now
|
32
44
|
before_list.each do |before_command|
|
33
45
|
if instance.nil?
|
@@ -38,12 +50,10 @@ class Node
|
|
38
50
|
end
|
39
51
|
finish = Time.now
|
40
52
|
|
41
|
-
|
42
|
-
|
43
|
-
node_list.each do |node|
|
44
|
-
totalTime[:exec].push(node.run(instance))
|
45
|
-
end
|
53
|
+
total_time[:before] = finish - start
|
54
|
+
end
|
46
55
|
|
56
|
+
def after_exec(instance, total_time)
|
47
57
|
start = Time.now
|
48
58
|
after_list.each do |after_command|
|
49
59
|
if instance.nil?
|
@@ -53,10 +63,7 @@ class Node
|
|
53
63
|
end
|
54
64
|
end
|
55
65
|
finish = Time.now
|
56
|
-
|
57
|
-
totalTime[:after] = finish - start
|
58
|
-
|
59
|
-
return totalTime
|
66
|
+
total_time[:after] = finish - start
|
60
67
|
end
|
61
68
|
|
62
69
|
def draw_block(graph)
|
@@ -107,11 +114,11 @@ class Node
|
|
107
114
|
draw_after_blocks(node, graph)
|
108
115
|
end
|
109
116
|
|
110
|
-
def print_tree
|
117
|
+
def print_tree(path)
|
111
118
|
node = self
|
112
119
|
digraph do
|
113
120
|
node.paint(node, self)
|
114
|
-
save
|
121
|
+
save path, 'png'
|
115
122
|
end
|
116
123
|
end
|
117
124
|
|
@@ -9,47 +9,17 @@ class OnNode < Node
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def run(instance)
|
12
|
-
|
13
|
-
{
|
14
|
-
:name => self.name,
|
15
|
-
:before => 0,
|
16
|
-
:exec => [],
|
17
|
-
:after => 0
|
18
|
-
}
|
19
|
-
instance = @instance
|
20
|
-
|
21
|
-
start = Time.now
|
22
|
-
before_list.each do |before_command|
|
23
|
-
puts before_command
|
24
|
-
if instance.nil?
|
25
|
-
`#{before_command}`
|
26
|
-
else
|
27
|
-
$virtual_machines[instance].invoke [[before_command]]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
finish = Time.now
|
31
|
-
|
32
|
-
totalTime[:before] = finish - start
|
12
|
+
init_time
|
33
13
|
|
14
|
+
before_exec(@instance, @total_time)
|
34
15
|
node_list.each do |node|
|
35
16
|
puts @instance
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
start = Time.now
|
41
|
-
after_list.each do |after_command|
|
42
|
-
if instance.nil?
|
43
|
-
`#{after_command}`
|
44
|
-
else
|
45
|
-
$virtual_machines[instance].invoke [[after_command]]
|
46
|
-
end
|
17
|
+
@total_time[:exec].push(node.run(@instance))
|
47
18
|
end
|
48
|
-
finish = Time.now
|
49
19
|
|
50
|
-
|
20
|
+
after_exec(@instance, @total_time)
|
51
21
|
|
52
|
-
return
|
22
|
+
return @total_time
|
53
23
|
end
|
54
24
|
|
55
25
|
def draw_block(graph)
|
data/test/execution_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: claudius
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-06-
|
13
|
+
date: 2014-06-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -120,7 +120,6 @@ files:
|
|
120
120
|
- lib/tree_building/on_node.rb
|
121
121
|
- test/execution_test.rb
|
122
122
|
- test/gem_usage_test.rb
|
123
|
-
- test/test.rb
|
124
123
|
- test/test_local_execution.rb
|
125
124
|
homepage: https://github.com/blostic/claudius
|
126
125
|
licenses:
|
@@ -151,5 +150,4 @@ summary: Write a gem summary
|
|
151
150
|
test_files:
|
152
151
|
- test/execution_test.rb
|
153
152
|
- test/gem_usage_test.rb
|
154
|
-
- test/test.rb
|
155
153
|
- test/test_local_execution.rb
|
data/test/test.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'claudius'
|
2
|
-
require "awesome_print"
|
3
|
-
|
4
|
-
experiment_tree = experiment 'sdsdf' do
|
5
|
-
define_providers do
|
6
|
-
# cloud('aws', :provider => config['provider'],
|
7
|
-
# :region=>config['region'],
|
8
|
-
# :aws_access_key_id => config['aws_access_key_id'],
|
9
|
-
# :aws_secret_access_key => config['aws_secret_access_key'])
|
10
|
-
# .create_instances(['t1.micro'], 'ubuntu', './Piotr-key-pair-irleand.pem',
|
11
|
-
# :key_name => 'Piotr-key-pair-irleand',
|
12
|
-
# :groups => 'Piotr-irleand')
|
13
|
-
manual('kali', '192.168.1.116', 'root', :password => 'toor', :port => 22)
|
14
|
-
end
|
15
|
-
|
16
|
-
foreach ['kali'] do |instance|
|
17
|
-
foreach ['a'] do |param|
|
18
|
-
before do
|
19
|
-
end
|
20
|
-
on instance do
|
21
|
-
execute 'install prerequisites' do
|
22
|
-
ssh "curl -O http://pegasus.isi.edu/montage/Montage_v3.3_patched_4.tar.gz"
|
23
|
-
ssh "tar zxvf Montage_v3.3_patched_4.tar.gz"
|
24
|
-
ssh "cd Montage_v3.3_patched_4"
|
25
|
-
ssh "make"
|
26
|
-
ssh "cd .."
|
27
|
-
ssh "git clone https://github.com/dice-cyfronet/hyperflow.git --depth 1 -b develop"
|
28
|
-
ssh "cd hyperflow"
|
29
|
-
ssh "npm install"
|
30
|
-
ssh "curl -O https://dl.dropboxusercontent.com/u/81819/hyperflow-amqp-executor.gem"
|
31
|
-
ssh "echo toor | sudo -S gem2.0 install --no-ri --no-rdoc hyperflow-amqp-executor.gem"
|
32
|
-
end
|
33
|
-
execute do
|
34
|
-
ssh "date"
|
35
|
-
end
|
36
|
-
execute do
|
37
|
-
ssh "echo #{param}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
after do
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
experiment_tree.run_with_time
|