restfully-addons 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/bonfire/scenario1.rb +205 -0
- data/examples/bonfire/scenario2.rb +198 -0
- data/examples/bonfire/ssh.rb +107 -0
- data/lib/restfully/addons/bonfire/ssh.rb +17 -4
- data/lib/restfully/addons/version.rb +1 -1
- metadata +19 -16
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'restfully'
|
3
|
+
require 'restfully/addons/bonfire'
|
4
|
+
|
5
|
+
CLIENT_IMAGE_NAME = "VM-iperf"
|
6
|
+
SERVER_IMAGE_NAME = "VM-iperf"
|
7
|
+
AGGREGATOR_IMAGE_NAME = "BonFIRE Zabbix Aggregator v4"
|
8
|
+
WAN_NAME = "BonFIRE WAN"
|
9
|
+
|
10
|
+
session = Restfully::Session.new(
|
11
|
+
:configuration_file => "~/.restfully/api.bonfire-project.eu",
|
12
|
+
:cache => false,
|
13
|
+
:gateway => "ssh.bonfire.grid5000.fr",
|
14
|
+
:keys => ["~/.ssh/id_rsa"],
|
15
|
+
:require => ["http://bonfire-dev.gforge.inria.fr/public/restfully/http.rb"]
|
16
|
+
)
|
17
|
+
session.logger.level = Logger::INFO
|
18
|
+
|
19
|
+
experiment = nil
|
20
|
+
|
21
|
+
begin
|
22
|
+
# Find an existing running experiment with the same name or submit a new
|
23
|
+
# one. This allows re-using an experiment when developing a new script.
|
24
|
+
experiment = session.root.experiments.find{|e|
|
25
|
+
e['name'] == "Demo ONE" && e['status'] == "running"
|
26
|
+
} || session.root.experiments.submit(
|
27
|
+
:name => "Demo ONE",
|
28
|
+
:description => "ONE demo using Restfully - #{Time.now.to_s}",
|
29
|
+
:status => "waiting",
|
30
|
+
:walltime => 8*3600 # 8 hours
|
31
|
+
)
|
32
|
+
|
33
|
+
# Create shortcuts for location resources:
|
34
|
+
inria = session.root.locations[:'fr-inria']
|
35
|
+
fail "Can't select the fr-inria location" if inria.nil?
|
36
|
+
hlrs = session.root.locations[:'de-hlrs']
|
37
|
+
fail "Can't select the de-hlrs location" if hlrs.nil?
|
38
|
+
epcc = session.root.locations[:'uk-epcc']
|
39
|
+
fail "Can't select the uk-epcc location" if epcc.nil?
|
40
|
+
|
41
|
+
# In this array we'll store the clients launched at each site:
|
42
|
+
locations = [[epcc,[]], [hlrs,[]], [inria,[]]]
|
43
|
+
|
44
|
+
session.logger.info "Launching aggregator..."
|
45
|
+
# Find an existing server in the experiment, or set up a new one:
|
46
|
+
aggregator = experiment.computes.find{|vm|
|
47
|
+
vm['name'] == "BonFIRE-monitor-experiment#{experiment['id']}"
|
48
|
+
} || experiment.computes.submit(
|
49
|
+
:name => "BonFIRE-monitor-experiment#{experiment['id']}",
|
50
|
+
:instance_type => "small",
|
51
|
+
:disk => [{
|
52
|
+
:storage => inria.storages.find{|s|
|
53
|
+
s['name'] == AGGREGATOR_IMAGE_NAME
|
54
|
+
}, :type => "OS"
|
55
|
+
}],
|
56
|
+
:nic => [{
|
57
|
+
:network => inria.networks.find{|n|
|
58
|
+
n['name'] == WAN_NAME
|
59
|
+
}
|
60
|
+
}],
|
61
|
+
:location => inria
|
62
|
+
)
|
63
|
+
aggregator_ip = aggregator['nic'][0]['ip']
|
64
|
+
session.logger.info "AGGREGATOR IP=#{aggregator_ip}"
|
65
|
+
|
66
|
+
session.logger.info "Launching server..."
|
67
|
+
# Find an existing server in the experiment, or set up a new one:
|
68
|
+
server = experiment.computes.find{|vm|
|
69
|
+
vm['name'] == "server-experiment#{experiment['id']}"
|
70
|
+
} || experiment.computes.submit(
|
71
|
+
:name => "server-experiment#{experiment['id']}",
|
72
|
+
:instance_type => "small",
|
73
|
+
:disk => [{
|
74
|
+
:storage => hlrs.storages.find{|s|
|
75
|
+
s['name'] == SERVER_IMAGE_NAME
|
76
|
+
},
|
77
|
+
:type => "OS"
|
78
|
+
}],
|
79
|
+
:nic => [
|
80
|
+
{:network => hlrs.networks.find{|n| n['name'] == WAN_NAME}}
|
81
|
+
],
|
82
|
+
:location => hlrs,
|
83
|
+
:context => {
|
84
|
+
'aggregator_ip' => aggregator_ip,
|
85
|
+
# Register metric on the server
|
86
|
+
'metrics' => XML::Node.new_cdata('<metric>iperf.server-bw,fgrep ",-" /root/iperf_server_log.txt | cut -d "," -f9 | tail -1</metric>')
|
87
|
+
}
|
88
|
+
)
|
89
|
+
server_ip = server['nic'][0]['ip']
|
90
|
+
session.logger.info "SERVER IP=#{server_ip}"
|
91
|
+
|
92
|
+
# Procedure to create a client VM in a round-robin fashion on each location:
|
93
|
+
def create_client(session, experiment, locations, context = {})
|
94
|
+
# Sort locations by number of clients already running
|
95
|
+
placement = locations.sort{|loc1,loc2|
|
96
|
+
loc1[1].size <=> loc2[1].size
|
97
|
+
}.first
|
98
|
+
location, vms = placement
|
99
|
+
session.logger.info "Deploying client image on #{location['name']}..."
|
100
|
+
vms.push experiment.computes.submit(
|
101
|
+
:name => "#{location['name']}-#{vms.size}-client-e#{experiment['id']}",
|
102
|
+
:instance_type => "small",
|
103
|
+
:disk => [{
|
104
|
+
:storage => location.storages.find{|s|
|
105
|
+
s['name'] == CLIENT_IMAGE_NAME
|
106
|
+
}, :type => "OS"
|
107
|
+
}],
|
108
|
+
:nic => [
|
109
|
+
{:network => location.networks.find{|n| n['name'] == WAN_NAME}}
|
110
|
+
],
|
111
|
+
:location => location,
|
112
|
+
:context => context.merge(
|
113
|
+
'metrics' => XML::Node.new_cdata('<metric>iperf.client-bw,fgrep ",-" /root/iperf_clients_log.txt | cut -d "," -f9 | tail -1</metric>')
|
114
|
+
)
|
115
|
+
)
|
116
|
+
vms.last
|
117
|
+
end
|
118
|
+
|
119
|
+
# Select clients that were potentially already existing
|
120
|
+
# (in case of an experiment reuse).
|
121
|
+
locations.each do |(location,vms)|
|
122
|
+
vms.push(*location.computes.select{|vm|
|
123
|
+
vm['name'] =~ /client-e#{experiment['id']}$/
|
124
|
+
})
|
125
|
+
end
|
126
|
+
clients = locations.map{|(l,vms)| vms}.flatten
|
127
|
+
|
128
|
+
# Create two client if no existing clients:
|
129
|
+
clients = 2.times.map{ create_client(session, experiment, locations, {
|
130
|
+
'aggregator_ip' => aggregator_ip,
|
131
|
+
'iperf_server' => server_ip
|
132
|
+
})} if clients.empty?
|
133
|
+
|
134
|
+
# Pass the experiment status to running.
|
135
|
+
# If it was already running this has no effect.
|
136
|
+
experiment.update(:status => "running")
|
137
|
+
|
138
|
+
# Wait until all VMs are ACTIVE and ssh-able.
|
139
|
+
# Fail if one of them has FAILED.
|
140
|
+
until [aggregator, server, *clients].all?{|vm|
|
141
|
+
vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
|
142
|
+
} do
|
143
|
+
fail "One of the VM has failed" if [aggregator, server, *clients].any?{|vm| vm['state'] == 'FAILED'}
|
144
|
+
session.logger.info "One of the VMs is not ready. Waiting..."
|
145
|
+
sleep 20
|
146
|
+
end
|
147
|
+
|
148
|
+
session.logger.info "VMs are now READY!"
|
149
|
+
# Display VM IPs
|
150
|
+
session.logger.info "*** Aggregator IP: #{aggregator_ip}"
|
151
|
+
session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
|
152
|
+
session.logger.info "*** Client IPs: #{clients.map{|vm| vm['nic'][0]['ip']}.inspect}"
|
153
|
+
|
154
|
+
# Control loop, until the experiment is done.
|
155
|
+
until ['terminated', 'canceled'].include?(experiment.reload['status']) do
|
156
|
+
case experiment['status']
|
157
|
+
when 'running'
|
158
|
+
session.logger.info "Experiment is running. Monitoring elasticity rule..."
|
159
|
+
session.logger.info "Clients: #{locations.map{|(l,vms)| "#{l['name']}: #{vms.map{|vm| vm['name']}.inspect}"}.join("; ")}."
|
160
|
+
|
161
|
+
# Check a metric values:
|
162
|
+
values = experiment.zabbix.metric('system.cpu.util[,system,avg1]', :type => :numeric, :hosts => server).values
|
163
|
+
avg3, avg5 = [values[0..3].avg, values[0..5].avg]
|
164
|
+
|
165
|
+
session.logger.info "Metric: values=#{values.inspect}, avg3=#{avg3}, avg5=#{avg5}."
|
166
|
+
clients_count = locations.map{|(l,vms)| vms}.flatten.length
|
167
|
+
|
168
|
+
# Here if the CPU usage of the iperf server is too low, we'll spawn a
|
169
|
+
# new client. If it's too high, we'll shut a client down.
|
170
|
+
if clients_count <= 10 && values.length >= 3 && avg3 <= 20
|
171
|
+
session.logger.warn "Scaling UP (avg=#{avg3})!"
|
172
|
+
vm = create_client(session, experiment, locations, {
|
173
|
+
'aggregator_ip' => aggregator_ip,
|
174
|
+
'iperf_server' => server_ip
|
175
|
+
})
|
176
|
+
sleep(10) until vm.ssh.accessible?
|
177
|
+
elsif clients_count > 1 && values.length >= 5 && avg5 >= 22
|
178
|
+
session.logger.warn "Scaling DOWN (avg=#{avg5})!"
|
179
|
+
# Delete the first client of the location which has the most clients:
|
180
|
+
locations.sort{|loc1,loc2|
|
181
|
+
loc2[1].size <=> loc1[1].size
|
182
|
+
}.first[1].shift.delete
|
183
|
+
else
|
184
|
+
session.logger.info "Nothing to do."
|
185
|
+
end
|
186
|
+
|
187
|
+
sleep 60
|
188
|
+
when 'terminating'
|
189
|
+
session.logger.info "Experiment is terminating. Here you could save images, retrieve data, etc."
|
190
|
+
sleep 30
|
191
|
+
else
|
192
|
+
session.logger.info "Experiment is #{experiment['status']}. Nothing to do yet."
|
193
|
+
sleep 60
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
session.logger.warn "Experiment terminated!"
|
198
|
+
|
199
|
+
rescue Exception => e
|
200
|
+
session.logger.error "#{e.class.name}: #{e.message}"
|
201
|
+
session.logger.error e.backtrace.join("\n")
|
202
|
+
session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
|
203
|
+
sleep 30
|
204
|
+
experiment.delete unless experiment.nil?
|
205
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'restfully'
|
3
|
+
require 'restfully/addons/bonfire'
|
4
|
+
|
5
|
+
CLIENT_IMAGE_NAME = "BonFIRE Debian Squeeze 2G v2"
|
6
|
+
SERVER_IMAGE_NAME = "BonFIRE Debian Squeeze 2G v2"
|
7
|
+
AGGREGATOR_IMAGE_NAME = "BonFIRE Zabbix Aggregator v4"
|
8
|
+
WAN_NAME = "BonFIRE WAN"
|
9
|
+
|
10
|
+
session = Restfully::Session.new(
|
11
|
+
:configuration_file => "~/.restfully/api.bonfire-project.eu",
|
12
|
+
:cache => false,
|
13
|
+
:gateway => "ssh.bonfire.grid5000.fr",
|
14
|
+
:keys => ["~/.ssh/id_rsa"]
|
15
|
+
)
|
16
|
+
session.logger.level = Logger::INFO
|
17
|
+
|
18
|
+
experiment = nil
|
19
|
+
|
20
|
+
begin
|
21
|
+
# Find an existing running experiment with the same name or submit a new
|
22
|
+
# one. This allows re-using an experiment when developing a new script.
|
23
|
+
experiment = session.root.experiments.find{|e|
|
24
|
+
e['name'] == "Demo VW" && e['status'] == "running"
|
25
|
+
} || session.root.experiments.submit(
|
26
|
+
:name => "Demo VW",
|
27
|
+
:description => "VW demo using Restfully - #{Time.now.to_s}",
|
28
|
+
:status => "waiting",
|
29
|
+
:walltime => 8*3600 # 8 hours
|
30
|
+
)
|
31
|
+
|
32
|
+
# Create shortcuts for location resources:
|
33
|
+
inria = session.root.locations[:'fr-inria']
|
34
|
+
fail "Can't select the fr-inria location" if inria.nil?
|
35
|
+
ibbt = session.root.locations[:'be-ibbt']
|
36
|
+
fail "Can't select the de-hlrs location" if ibbt.nil?
|
37
|
+
|
38
|
+
# In this array we'll store the clients launched at each site:
|
39
|
+
locations = [[ibbt,[]]]
|
40
|
+
|
41
|
+
private_network = experiment.networks.submit(
|
42
|
+
:location => ibbt,
|
43
|
+
:name => "network-experiment#{experiment['id']}",
|
44
|
+
:bandwidth => 1000,
|
45
|
+
:latency => 0,
|
46
|
+
:size => 24,
|
47
|
+
:lossrate => 0,
|
48
|
+
# You MUST specify the address:
|
49
|
+
:address => "192.168.0.0"
|
50
|
+
)
|
51
|
+
|
52
|
+
session.logger.info "Launching aggregator..."
|
53
|
+
aggregator = experiment.computes.find{|vm|
|
54
|
+
vm['name'] == "BonFIRE-monitor-experiment#{experiment['id']}"
|
55
|
+
} || experiment.computes.submit(
|
56
|
+
:name => "BonFIRE-monitor-experiment#{experiment['id']}",
|
57
|
+
:instance_type => "small",
|
58
|
+
:disk => [
|
59
|
+
{
|
60
|
+
:storage => inria.storages.find{|s|
|
61
|
+
s['name'] == AGGREGATOR_IMAGE_NAME
|
62
|
+
},
|
63
|
+
:type => "OS"
|
64
|
+
}
|
65
|
+
],
|
66
|
+
:nic => [
|
67
|
+
{
|
68
|
+
:network => inria.networks.find{|n|
|
69
|
+
n['name'] == WAN_NAME
|
70
|
+
}
|
71
|
+
}
|
72
|
+
],
|
73
|
+
:location => inria
|
74
|
+
)
|
75
|
+
aggregator_ip = aggregator['nic'][0]['ip']
|
76
|
+
session.logger.info "AGGREGATOR IP=#{aggregator_ip}"
|
77
|
+
|
78
|
+
session.logger.info "Launching server..."
|
79
|
+
# Set up server
|
80
|
+
server = experiment.computes.find{|vm|
|
81
|
+
vm['name'] == "server-experiment#{experiment['id']}"
|
82
|
+
} || experiment.computes.submit(
|
83
|
+
:name => "server-experiment#{experiment['id']}",
|
84
|
+
:instance_type => "small",
|
85
|
+
:disk => [
|
86
|
+
{
|
87
|
+
:storage => ibbt.storages.find{|s|
|
88
|
+
s['name'] == SERVER_IMAGE_NAME
|
89
|
+
},
|
90
|
+
:type => "OS"
|
91
|
+
}
|
92
|
+
],
|
93
|
+
:nic => [
|
94
|
+
{:network => ibbt.networks.find{|n| n['name'] == WAN_NAME}},
|
95
|
+
{:network => private_network, :ip => '192.168.0.2'}
|
96
|
+
],
|
97
|
+
:location => ibbt,
|
98
|
+
:context => {
|
99
|
+
'aggregator_ip' => aggregator_ip,
|
100
|
+
# Register metric on the server
|
101
|
+
'metrics' => XML::Node.new_cdata('<metric>iperf.server-bw,fgrep ",-" /root/iperf_server_log.txt | cut -d "," -f9 | tail -1</metric>')
|
102
|
+
}
|
103
|
+
)
|
104
|
+
server_ip = server['nic'][0]['ip']
|
105
|
+
session.logger.info "SERVER IP=#{server_ip}"
|
106
|
+
|
107
|
+
# Procedure to create a client VM in a round-robin fashion on each location:
|
108
|
+
def create_client(session, experiment, locations, context = {})
|
109
|
+
# Sort locations by number of clients already running
|
110
|
+
placement = locations.sort{|loc1,loc2|
|
111
|
+
loc1[1].size <=> loc2[1].size
|
112
|
+
}.first
|
113
|
+
location, vms = placement
|
114
|
+
session.logger.info "Deploying client image on #{location['name']}..."
|
115
|
+
private_ip = "192.168.0.#{vms.size+3}"
|
116
|
+
vms.push experiment.computes.submit(
|
117
|
+
:name => "#{location['name']}-#{vms.size}-client-e#{experiment['id']}",
|
118
|
+
:instance_type => "small",
|
119
|
+
:disk => [
|
120
|
+
{
|
121
|
+
:storage => location.storages.find{|s|
|
122
|
+
s['name'] == CLIENT_IMAGE_NAME
|
123
|
+
},
|
124
|
+
:type => "OS"
|
125
|
+
}
|
126
|
+
],
|
127
|
+
:nic => [
|
128
|
+
{:network => location.networks.find{|n| n['name'] == WAN_NAME}},
|
129
|
+
{:network => context.delete(:private_network), :ip => private_ip}
|
130
|
+
],
|
131
|
+
:location => location,
|
132
|
+
:context => context.merge(
|
133
|
+
'metrics' => XML::Node.new_cdata('<metric>iperf.client-bw,fgrep ",-" /root/iperf_clients_log.txt | cut -d "," -f9 | tail -1</metric>')
|
134
|
+
)
|
135
|
+
)
|
136
|
+
vms.last
|
137
|
+
end
|
138
|
+
|
139
|
+
# Select clients that were potentially already existing
|
140
|
+
# (in case of an experiment reuse).
|
141
|
+
locations.each do |(location,vms)|
|
142
|
+
vms.push(*location.computes.select{|vm|
|
143
|
+
vm['name'] =~ /client-e#{experiment['id']}$/
|
144
|
+
})
|
145
|
+
end
|
146
|
+
clients = locations.map{|(l,vms)| vms}.flatten
|
147
|
+
|
148
|
+
# Create two client if no existing clients:
|
149
|
+
clients = 2.times.map{ create_client(session, experiment, locations, {
|
150
|
+
'aggregator_ip' => aggregator_ip,
|
151
|
+
'iperf_server' => '192.168.0.2',
|
152
|
+
:private_network => private_network
|
153
|
+
})} if clients.empty?
|
154
|
+
|
155
|
+
# Pass the experiment status to running.
|
156
|
+
# If it was already running this has no effect.
|
157
|
+
experiment.update(:status => "running")
|
158
|
+
|
159
|
+
# Wait until all VMs are ACTIVE and ssh-able.
|
160
|
+
# Fail if one of them has FAILED.
|
161
|
+
until [aggregator, server, *clients].all?{|vm|
|
162
|
+
vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
|
163
|
+
} do
|
164
|
+
fail "One of the VM has failed" if [aggregator, server, *clients].any?{|vm| vm['state'] == 'FAILED'}
|
165
|
+
session.logger.info "One of the VMs is not ready. Waiting..."
|
166
|
+
sleep 20
|
167
|
+
end
|
168
|
+
|
169
|
+
session.logger.info "VMs are now READY!"
|
170
|
+
# Display VM IPs
|
171
|
+
session.logger.info "*** Aggregator IP: #{aggregator_ip}"
|
172
|
+
session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
|
173
|
+
session.logger.info "*** Client IPs: #{clients.map{|vm| vm['nic'][0]['ip']}.inspect}"
|
174
|
+
|
175
|
+
# Control loop, until the experiment is done.
|
176
|
+
until ['terminated', 'canceled'].include?(experiment.reload['status']) do
|
177
|
+
case experiment['status']
|
178
|
+
when 'running'
|
179
|
+
session.logger.info "Experiment is running..."
|
180
|
+
sleep 60
|
181
|
+
when 'terminating'
|
182
|
+
session.logger.info "Experiment is terminating. Here you could save images, retrieve data, etc."
|
183
|
+
sleep 30
|
184
|
+
else
|
185
|
+
session.logger.info "Experiment is #{experiment['status']}. Nothing to do yet."
|
186
|
+
sleep 60
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
session.logger.warn "Experiment terminated!"
|
191
|
+
|
192
|
+
rescue Exception => e
|
193
|
+
session.logger.error "#{e.class.name}: #{e.message}"
|
194
|
+
session.logger.error e.backtrace.join("\n")
|
195
|
+
session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
|
196
|
+
sleep 30
|
197
|
+
experiment.delete unless experiment.nil?
|
198
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'restfully'
|
3
|
+
require 'restfully/addons/bonfire'
|
4
|
+
|
5
|
+
SERVER_IMAGE_NAME = "BonFIRE Debian Squeeze v2"
|
6
|
+
WAN_NAME = "BonFIRE WAN"
|
7
|
+
|
8
|
+
logger = Logger.new(STDOUT)
|
9
|
+
logger.level = Logger::INFO
|
10
|
+
|
11
|
+
session = Restfully::Session.new(
|
12
|
+
:configuration_file => "~/.restfully/api.bonfire-project.eu",
|
13
|
+
:gateway => "ssh.bonfire.grid5000.fr",
|
14
|
+
:keys => ["~/.ssh/id_rsa"],
|
15
|
+
:cache => false,
|
16
|
+
:logger => logger
|
17
|
+
)
|
18
|
+
|
19
|
+
experiment = nil
|
20
|
+
|
21
|
+
begin
|
22
|
+
# Find an existing running experiment with the same name or submit a new
|
23
|
+
# one. This allows re-using an experiment when developing a new script.
|
24
|
+
experiment = session.root.experiments.find{|e|
|
25
|
+
e['name'] == "Demo SSH" && e['status'] == "running"
|
26
|
+
} || session.root.experiments.submit(
|
27
|
+
:name => "Demo SSH",
|
28
|
+
:description => "SSH demo using Restfully - #{Time.now.to_s}",
|
29
|
+
:status => "waiting",
|
30
|
+
:walltime => 8*3600 # 8 hours
|
31
|
+
)
|
32
|
+
|
33
|
+
# Create shortcuts for location resources:
|
34
|
+
inria = session.root.locations[:'fr-inria']
|
35
|
+
fail "Can't select the fr-inria location" if inria.nil?
|
36
|
+
|
37
|
+
session.logger.info "Launching VM..."
|
38
|
+
# Find an existing server in the experiment, or set up a new one:
|
39
|
+
server = experiment.computes.find{|vm|
|
40
|
+
vm['name'] == "VM-experiment#{experiment['id']}"
|
41
|
+
} || experiment.computes.submit(
|
42
|
+
:name => "VM-experiment#{experiment['id']}",
|
43
|
+
:instance_type => "small",
|
44
|
+
:disk => [{
|
45
|
+
:storage => inria.storages.find{|s|
|
46
|
+
s['name'] == SERVER_IMAGE_NAME
|
47
|
+
},
|
48
|
+
:type => "OS"
|
49
|
+
}],
|
50
|
+
:nic => [
|
51
|
+
{:network => inria.networks.find{|n| n['name'] == WAN_NAME}}
|
52
|
+
],
|
53
|
+
:location => inria
|
54
|
+
)
|
55
|
+
server_ip = server['nic'][0]['ip']
|
56
|
+
session.logger.info "SERVER IP=#{server_ip}"
|
57
|
+
|
58
|
+
# Pass the experiment status to running.
|
59
|
+
# If it was already running this has no effect.
|
60
|
+
experiment.update(:status => "running")
|
61
|
+
|
62
|
+
# Wait until all VMs are ACTIVE and ssh-able.
|
63
|
+
# Fail if one of them has FAILED.
|
64
|
+
until [server].all?{|vm|
|
65
|
+
vm.reload['state'] == 'ACTIVE' && vm.ssh.accessible?
|
66
|
+
} do
|
67
|
+
fail "One of the VM has failed" if [server].any?{|vm|
|
68
|
+
vm['state'] == 'FAILED'
|
69
|
+
}
|
70
|
+
session.logger.info "One of the VMs is not ready. Waiting..."
|
71
|
+
sleep 20
|
72
|
+
end
|
73
|
+
|
74
|
+
session.logger.info "VMs are now READY!"
|
75
|
+
# Display VM IPs
|
76
|
+
session.logger.info "*** Server IP: #{server['nic'][0]['ip']}"
|
77
|
+
|
78
|
+
server.ssh do |ssh|
|
79
|
+
session.logger.info "Uploading content..."
|
80
|
+
# Here is how you would upload a file:
|
81
|
+
# ssh.scp.upload!("/path/to/file", '/tmp/file.log')
|
82
|
+
# Here is how you can upload some in-memory data:
|
83
|
+
ssh.scp.upload!(StringIO.new('some data'), '/tmp/file.log')
|
84
|
+
# See <http://net-ssh.github.com/scp/v1/api/index.html> for more details.
|
85
|
+
|
86
|
+
session.logger.info "Content of uploaded file:"
|
87
|
+
puts ssh.exec!("cat /tmp/file.log")
|
88
|
+
|
89
|
+
session.logger.info "Installing things..."
|
90
|
+
output = ssh.exec!("apt-get install curl -y")
|
91
|
+
session.logger.debug output
|
92
|
+
|
93
|
+
session.logger.info "Running query against API..."
|
94
|
+
puts ssh.exec!("source /etc/default/bonfire && curl -k $BONFIRE_URI/locations/$BONFIRE_PROVIDER/computes/$BONFIRE_RESOURCE_ID -u $BONFIRE_CREDENTIALS")
|
95
|
+
end
|
96
|
+
|
97
|
+
session.logger.warn "Success! Will delete experiment in 10 seconds. Hit CTRL-C now to keep your VMs..."
|
98
|
+
sleep 10
|
99
|
+
experiment.delete
|
100
|
+
|
101
|
+
rescue Exception => e
|
102
|
+
session.logger.error "#{e.class.name}: #{e.message}"
|
103
|
+
session.logger.error e.backtrace.join("\n")
|
104
|
+
session.logger.warn "Cleaning up in 30 seconds. Hit CTRL-C now to keep your VMs..."
|
105
|
+
sleep 30
|
106
|
+
experiment.delete unless experiment.nil?
|
107
|
+
end
|
@@ -4,11 +4,16 @@ require 'net/sftp'
|
|
4
4
|
|
5
5
|
module Restfully
|
6
6
|
class Resource
|
7
|
+
# Opens an SSH session on the resource's IP.
|
8
|
+
# Returns the result of the last statement of the given block.
|
7
9
|
def ssh(user = nil, opts = {}, &block)
|
8
10
|
raise NotImplementedError unless uri.to_s =~ /\/computes\/\w+$/
|
9
11
|
@ssh ||= SSH.new(session, self)
|
10
|
-
|
11
|
-
|
12
|
+
if block
|
13
|
+
@ssh.run(@ssh.ip, user, opts, &block)
|
14
|
+
else
|
15
|
+
@ssh
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
@@ -27,10 +32,18 @@ module Restfully
|
|
27
32
|
gateway = session.config[:gateway]
|
28
33
|
if gateway
|
29
34
|
gateway_handler = Net::SSH::Gateway.new(gateway, session.config[:username], options)
|
30
|
-
|
35
|
+
result = nil
|
36
|
+
gateway_handler.ssh(fqdn, user, options) {|handler|
|
37
|
+
result = block.call(handler)
|
38
|
+
}
|
31
39
|
gateway_handler.shutdown!
|
40
|
+
result
|
32
41
|
else
|
33
|
-
|
42
|
+
result = nil
|
43
|
+
Net::SSH.start(fqdn, user, options) {|handler|
|
44
|
+
result = block.call(handler)
|
45
|
+
}
|
46
|
+
result
|
34
47
|
end
|
35
48
|
end
|
36
49
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restfully-addons
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-09-21 00:00:00.000000000 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: restfully
|
17
|
-
requirement: &
|
17
|
+
requirement: &2153539680 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2153539680
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: net-ssh-gateway
|
28
|
-
requirement: &
|
28
|
+
requirement: &2153570680 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2153570680
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: net-scp
|
39
|
-
requirement: &
|
39
|
+
requirement: &2153570260 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2153570260
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: net-sftp
|
50
|
-
requirement: &
|
50
|
+
requirement: &2153569840 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *2153569840
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: net-ssh-multi
|
61
|
-
requirement: &
|
61
|
+
requirement: &2153569420 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *2153569420
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: libxml-ruby
|
72
|
-
requirement: &
|
72
|
+
requirement: &2153569000 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,10 +77,10 @@ dependencies:
|
|
77
77
|
version: '0'
|
78
78
|
type: :runtime
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *2153569000
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: rake
|
83
|
-
requirement: &
|
83
|
+
requirement: &2153568500 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
86
|
- - ~>
|
@@ -88,7 +88,7 @@ dependencies:
|
|
88
88
|
version: '0.8'
|
89
89
|
type: :development
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *2153568500
|
92
92
|
description: Addons for Restfully
|
93
93
|
email:
|
94
94
|
- cyril.rohr@inria.fr
|
@@ -103,6 +103,9 @@ files:
|
|
103
103
|
- lib/restfully/addons/bonfire.rb
|
104
104
|
- lib/restfully/addons/version.rb
|
105
105
|
- lib/restfully/addons.rb
|
106
|
+
- examples/bonfire/scenario1.rb
|
107
|
+
- examples/bonfire/scenario2.rb
|
108
|
+
- examples/bonfire/ssh.rb
|
106
109
|
- Rakefile
|
107
110
|
- LICENSE
|
108
111
|
- README.md
|