omf_ec 6.0.0.pre.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +7 -0
- data/bin/omf_test +161 -0
- data/config/ec.yml +164 -0
- data/exp_repo/system/exp/eventlib.rb +96 -0
- data/exp_repo/system/exp/imageNode.rb +283 -0
- data/exp_repo/system/exp/reset.rb +21 -0
- data/exp_repo/system/exp/saveNode.rb +99 -0
- data/exp_repo/system/exp/stat.rb +49 -0
- data/exp_repo/system/exp/stdlib.rb +122 -0
- data/exp_repo/system/exp/tell.rb +53 -0
- data/exp_repo/system/exp/testlib.rb +12 -0
- data/exp_repo/system/exp/winlib.rb +154 -0
- data/exp_repo/system/topo/active.rb +9 -0
- data/exp_repo/system/topo/all.rb +10 -0
- data/exp_repo/system/topo/circle.rb +23 -0
- data/exp_repo/test/app/aodvd.rb +73 -0
- data/exp_repo/test/app/appDef1.rb +102 -0
- data/exp_repo/test/app/athstats.rb +76 -0
- data/exp_repo/test/app/echo.rb +36 -0
- data/exp_repo/test/app/gennyReceiverAppDef.rb +100 -0
- data/exp_repo/test/app/gennySenderAppDef.rb +106 -0
- data/exp_repo/test/app/itgdec.rb +79 -0
- data/exp_repo/test/app/itgr.rb +77 -0
- data/exp_repo/test/app/itgs.rb +105 -0
- data/exp_repo/test/app/nop.rb +36 -0
- data/exp_repo/test/app/otg2.rb +68 -0
- data/exp_repo/test/app/otg2_mp.rb +56 -0
- data/exp_repo/test/app/otr2.rb +56 -0
- data/exp_repo/test/app/otr2_mp.rb +51 -0
- data/exp_repo/test/app/trace_oml2.rb +62 -0
- data/exp_repo/test/app/wlanconfig_oml2.rb +42 -0
- data/exp_repo/test/exp/conf-room-demo.rb +118 -0
- data/exp_repo/test/exp/planetlab.rb +82 -0
- data/exp_repo/test/exp/test01.rb +42 -0
- data/exp_repo/test/exp/test02.rb +60 -0
- data/exp_repo/test/exp/test03.rb +95 -0
- data/exp_repo/test/exp/test04.rb +105 -0
- data/exp_repo/test/exp/test05.rb +87 -0
- data/exp_repo/test/exp/test06.rb +71 -0
- data/exp_repo/test/exp/tutorial/hello-world-wired.rb +79 -0
- data/exp_repo/test/exp/tutorial/hello-world-wireless.rb +87 -0
- data/exp_repo/test/exp/tutorial/using-filters.rb +69 -0
- data/exp_repo/test/exp/tutorial/using-groups.rb +64 -0
- data/exp_repo/test/exp/tutorial/using-properties.rb +93 -0
- data/exp_repo/test/exp/tutorial/using-prototypes.rb +111 -0
- data/exp_repo/test/proto/aodvrouter.rb +55 -0
- data/exp_repo/test/proto/driverqueryapp.rb +59 -0
- data/exp_repo/test/proto/forwarder.rb +73 -0
- data/exp_repo/test/proto/itgcbrsender.rb +70 -0
- data/exp_repo/test/proto/itgdecoder.rb +64 -0
- data/exp_repo/test/proto/itgreceiver.rb +55 -0
- data/exp_repo/test/proto/itgvoipsender.rb +64 -0
- data/exp_repo/test/proto/listener2.rb +62 -0
- data/exp_repo/test/proto/nop.rb +47 -0
- data/exp_repo/test/proto/probelink.rb +48 -0
- data/exp_repo/test/proto/raw_receiver.rb +64 -0
- data/exp_repo/test/proto/receiver2_mp.rb +48 -0
- data/exp_repo/test/proto/sender2_mp.rb +54 -0
- data/exp_repo/test/proto/udp_receiver.rb +55 -0
- data/exp_repo/test/proto/udp_sender.rb +61 -0
- data/lib/omf_ec/version.rb +3 -0
- data/lib/omf_ec.rb +5 -0
- data/omf_ec.gemspec +24 -0
- metadata +145 -0
@@ -0,0 +1,283 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2008 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Copyright (c) 2004-2008 WINLAB, Rutgers University, USA
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# = imageNode.rb
|
26
|
+
#
|
27
|
+
# == Description
|
28
|
+
#
|
29
|
+
# This file describes the Experiment that is used to image the nodes within OMF.
|
30
|
+
# (In OMF, loading a disk image on a node is treated as an 'experiment' itself)
|
31
|
+
#
|
32
|
+
|
33
|
+
# Define the experiment properties
|
34
|
+
Experiment.name = "imageNode"
|
35
|
+
Experiment.project = "Orbit::Admin"
|
36
|
+
defProperty('nodes', 'system:topo:all', "Nodes to image")
|
37
|
+
defProperty('image', 'baseline.ndz', "Image to load on nodes")
|
38
|
+
defProperty('domain', "#{OConfig.domain}", "Domain of the nodes to image")
|
39
|
+
defProperty('outpath', "/tmp", "Path where to place the topology files resulting from this image")
|
40
|
+
defProperty('outprefix', "#{Experiment.ID}", "Prefix to use for the topology files resulting from this image")
|
41
|
+
# The following value of 1200sec for timeout is based on trial imaging experiments
|
42
|
+
defProperty('timeout', 1200, "Stop the imaging process <timeout> sec after the last node has powered up")
|
43
|
+
|
44
|
+
# Define some constants
|
45
|
+
MSG_CHECKINFAILED = <<TEXT
|
46
|
+
# This creates a Topology with the resources which did not check in to the load experiment.
|
47
|
+
# These nodes may have failed to boot into the PXE image or start the RC from within.
|
48
|
+
#
|
49
|
+
TEXT
|
50
|
+
MSG_IMAGEFAILED = <<TEXT
|
51
|
+
# This creates a Topology with the resources for which the image loading failed.
|
52
|
+
# On these resources, the 'frisbee' client may have raised an error during its execution.
|
53
|
+
# Please check the EC log file for the 'frisbee' client error message.
|
54
|
+
#
|
55
|
+
TEXT
|
56
|
+
MSG_TIMEOUT = <<TEXT
|
57
|
+
# This creates a Topology with the resources for which the image loading timed out.
|
58
|
+
# These nodes did not finish imaging before the timeout limit.
|
59
|
+
# Most of the time this is caused by some disk or network problems.
|
60
|
+
#
|
61
|
+
TEXT
|
62
|
+
MSG_SUCCESS = <<TEXT
|
63
|
+
# This creates a Topology with the resources which have successfully been imaged.
|
64
|
+
#
|
65
|
+
TEXT
|
66
|
+
MESSAGES = {:checkinfailed => MSG_CHECKINFAILED, :imagefailed => MSG_IMAGEFAILED, :timeout => MSG_TIMEOUT, :success => MSG_SUCCESS}
|
67
|
+
|
68
|
+
|
69
|
+
#
|
70
|
+
# First of all, do some checks...
|
71
|
+
# - check if the requested image really exists on the Repository
|
72
|
+
#
|
73
|
+
#url = "#{OConfig[:ec_config][:frisbee][:url]}/checkImage?img=#{prop.image.value}&domain=#{prop.domain.value}"
|
74
|
+
#response = NodeHandler.service_call(url, "Image does not exist")
|
75
|
+
response = OMF::Services.frisbee.checkImage(:img => "#{prop.image.value}", :domain => "#{prop.domain.value}")
|
76
|
+
if response.elements[1].name != "OK"
|
77
|
+
MObject.error("Frisbee Service Call", response.root.text)
|
78
|
+
Experiment.done
|
79
|
+
exit
|
80
|
+
end
|
81
|
+
# - check if timeout value from command line is really an integer
|
82
|
+
if (prop.timeout.value.to_i == 0)
|
83
|
+
MObject.error("The timeout value '#{prop.timeout.value}' is not an integer!")
|
84
|
+
MObject.error("Check command line syntax.")
|
85
|
+
Experiment.done
|
86
|
+
exit -1
|
87
|
+
end
|
88
|
+
|
89
|
+
@allNodes = []
|
90
|
+
|
91
|
+
#
|
92
|
+
# Define the group of node to image and set them into PXE boot
|
93
|
+
#
|
94
|
+
defGroup('image', prop.nodes) {|ns|
|
95
|
+
ns.image = "pxe-5.4"
|
96
|
+
ns.each { |n| @allNodes << n }
|
97
|
+
}
|
98
|
+
|
99
|
+
OMF::Services.pxe.setBootImageNS(:ns => "#{@allNodes.map{|n| n.to_s }.join(',')}", :domain => "#{prop.domain.value}")
|
100
|
+
|
101
|
+
def clearPXE
|
102
|
+
OMF::Services.pxe.clearBootImageNS(:ns => "#{@allNodes.map{|n| n.to_s }.join(',')}", :domain => "#{prop.domain.value}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def outputTopologyFile(type, nset)
|
106
|
+
begin
|
107
|
+
filename = "#{prop.outpath.value}/#{prop.outprefix.value}-topo-#{type}.rb"
|
108
|
+
toponame = "#{prop.outprefix.value}-topo-#{type}"
|
109
|
+
|
110
|
+
# we need to put the array back into the original order
|
111
|
+
# since nodes were added in the order they signed in
|
112
|
+
sortedNodes = Array.new(@allNodes)
|
113
|
+
sortedNodes.delete_if {|n| !nset.include?(n) }
|
114
|
+
sortedNodes.map!{|n| n.to_s }
|
115
|
+
File.open(filename, "w") do |f|
|
116
|
+
f.puts("# Topology name: #{toponame}", "# ")
|
117
|
+
f.puts(MESSAGES[type])
|
118
|
+
f.print("defTopology('#{toponame}', '")
|
119
|
+
f.print(sortedNodes.join(","))
|
120
|
+
f.puts "')"
|
121
|
+
end
|
122
|
+
return filename
|
123
|
+
rescue Exception => err
|
124
|
+
MObject.warn("exp", "Could not write result topology file: '#{filename}' (#{err})")
|
125
|
+
MObject.warn("exp", "(Most probably imaging was OK, but result file could not be created)")
|
126
|
+
end
|
127
|
+
return nil
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Every 10s check the state of the imaging process and report accordingly
|
132
|
+
#
|
133
|
+
everyNS('image', 10) { |ns|
|
134
|
+
nodesUp = 0
|
135
|
+
nodesDone = 0
|
136
|
+
nodesWithError = 0
|
137
|
+
nodesWithErrorList = []
|
138
|
+
nodesWithSuccessList = []
|
139
|
+
nodesPendingList = []
|
140
|
+
nodeCnt = 0
|
141
|
+
progMax = 0
|
142
|
+
progMin = 100
|
143
|
+
nodeMin = nil
|
144
|
+
progSum = 0
|
145
|
+
startupDelayMax = 0
|
146
|
+
report = true
|
147
|
+
notDone = true
|
148
|
+
lastUpTime = 0
|
149
|
+
|
150
|
+
ns.each { |n|
|
151
|
+
nodeCnt += 1
|
152
|
+
if n.isUp
|
153
|
+
# nodesUp += 1
|
154
|
+
prog = n.match('apps/*/*/progress/text()')[-1].to_s.to_i
|
155
|
+
#puts n
|
156
|
+
#puts n.match('apps/*/*/progress')
|
157
|
+
progSum += prog
|
158
|
+
progMax = prog if prog > progMax
|
159
|
+
if prog < progMin
|
160
|
+
progMin = prog
|
161
|
+
nodeMin = n
|
162
|
+
end
|
163
|
+
startupDelay = n.checkedInAt.to_i - n.poweredAt.to_i
|
164
|
+
startupDelayMax = startupDelay if startupDelay > startupDelayMax
|
165
|
+
if n.poweredAt.to_i > lastUpTime
|
166
|
+
lastUpTime = n.poweredAt.to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
status = n.match('apps/*/status/')[0].to_s
|
170
|
+
nodesDone += 1 if status =~ /DONE/
|
171
|
+
if status =~ /DONE.ERR/
|
172
|
+
nodesWithError += 1
|
173
|
+
nodesWithErrorList << n
|
174
|
+
elsif status =~ /DONE.OK/
|
175
|
+
nodesWithSuccessList << n
|
176
|
+
else
|
177
|
+
nodesPendingList << n
|
178
|
+
end
|
179
|
+
else
|
180
|
+
# wait with reporting until everybody is up
|
181
|
+
report = false
|
182
|
+
end
|
183
|
+
}
|
184
|
+
if report
|
185
|
+
progAvg = nodeCnt > 0 ? progSum / nodeCnt : 0
|
186
|
+
stats = "#{progMin}/#{progAvg}/#{progMax}"
|
187
|
+
prog = "#{nodesDone}/#{nodesWithError}/#{nodeCnt}"
|
188
|
+
timeLeft = lastUpTime+prop.timeout.value-Time.now.to_i
|
189
|
+
info "Progress(#{prog}): #{stats} min(#{nodeMin})/avg/max (#{startupDelayMax}) - Timeout: #{timeLeft} sec."
|
190
|
+
|
191
|
+
if (nodesDone >= nodeCnt) || ((lastUpTime+prop.timeout.value) < Time.now.to_i)
|
192
|
+
# we are done
|
193
|
+
info " ----------------------------- "
|
194
|
+
info " Imaging Process Done "
|
195
|
+
nodesWhichNeverCheckedIn = @allNodes - nodesWithErrorList - nodesPendingList - nodesWithSuccessList
|
196
|
+
if (l = nodesWhichNeverCheckedIn.length) > 0
|
197
|
+
f = outputTopologyFile(:checkinfailed, nodesWhichNeverCheckedIn)
|
198
|
+
info " #{l} node#{"s" if l>1} failed to check in - Topology saved in '#{f}'"
|
199
|
+
end
|
200
|
+
if (l = nodesWithErrorList.length) > 0
|
201
|
+
f = outputTopologyFile(:imagefailed, nodesWithErrorList)
|
202
|
+
info " #{l} node#{"s" if l>1} failed to image the disk - Topology saved in '#{f}'"
|
203
|
+
end
|
204
|
+
if (l = nodesPendingList.length) > 0
|
205
|
+
f = outputTopologyFile(:timeout, nodesPendingList)
|
206
|
+
info " #{l} node#{"s" if l>1} timed out - Topology saved in '#{f}'"
|
207
|
+
end
|
208
|
+
if (l = nodesWithSuccessList.length) > 0
|
209
|
+
f = outputTopologyFile(:success, nodesWithSuccessList)
|
210
|
+
info " #{l} node#{"s" if l>1} successfully imaged - Topology saved in '#{f}'"
|
211
|
+
end
|
212
|
+
info " ----------------------------- "
|
213
|
+
ns.stopImageServer("#{prop.image.value}", "#{prop.domain.value}")
|
214
|
+
Experiment.done
|
215
|
+
notDone = false
|
216
|
+
end
|
217
|
+
end
|
218
|
+
notDone
|
219
|
+
}
|
220
|
+
|
221
|
+
onEvent(:INTERRUPT) {
|
222
|
+
clearPXE
|
223
|
+
}
|
224
|
+
|
225
|
+
#
|
226
|
+
# When all the nodes in the above group are Up, then start loading the image on them
|
227
|
+
#
|
228
|
+
onEvent(:ALL_UP) {
|
229
|
+
clearPXE
|
230
|
+
# Only execute imaging if node set is not empty!
|
231
|
+
# (e.g. in rare occasions no node managed to come up and register to EC, when this
|
232
|
+
# happens, we need to exit quietly from this 'onEvent(:ALL_UP)')
|
233
|
+
nodeCount = 0
|
234
|
+
group('image').each { |n|
|
235
|
+
nodeCount += 1
|
236
|
+
}
|
237
|
+
if (nodeCount != 0)
|
238
|
+
group('image').loadImage(Experiment.property('image'), "#{prop.domain.value}")
|
239
|
+
end
|
240
|
+
}
|
241
|
+
|
242
|
+
|
243
|
+
##defURL('/progress') {|req, res|
|
244
|
+
#OMF::Common::Web.mapProc('/progress') {|req, res|
|
245
|
+
# body = []
|
246
|
+
# body << %q{
|
247
|
+
#<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
248
|
+
#<html>
|
249
|
+
# <head>
|
250
|
+
# <meta http-equiv="refresh" content="10">
|
251
|
+
# <title>Imaging Progress :: Orbit</title>
|
252
|
+
# <link href="resource/stylesheet/grid.css" type="text/css" rel="stylesheet"/>
|
253
|
+
# </head>
|
254
|
+
#
|
255
|
+
# <body>
|
256
|
+
# <h1>Imaging Progress</h1>
|
257
|
+
# <table class="grid">
|
258
|
+
#}
|
259
|
+
# # TODO: port this to OMF 5.4
|
260
|
+
# # (1 .. OConfig[:tb_config][:default][:y_max]).each { |y|
|
261
|
+
# # body << "<tr class='row'>"
|
262
|
+
# # (1 .. OConfig[:tb_config][:default][:x_max]).each { |x|
|
263
|
+
# # n = Node[x,y]
|
264
|
+
# # if (n == nil)
|
265
|
+
# # body << "<td class='cell'></td>"
|
266
|
+
# # elsif (n.isUp)
|
267
|
+
# # body << "<td class='cell cell-up'>"
|
268
|
+
# # progress = n.match('apps/builtin[1]/properties/progress/text()').to_s
|
269
|
+
# # if (progress != nil)
|
270
|
+
# # body << "<div class='cell-progress' style='width: #{progress}%'></div>"
|
271
|
+
# # end
|
272
|
+
# # body << "</td>"
|
273
|
+
# # else
|
274
|
+
# # body << "<td class='cell cell-down'></td>"
|
275
|
+
# # end
|
276
|
+
# # }
|
277
|
+
# # body << "</tr>"
|
278
|
+
# # }
|
279
|
+
# body << "</table></body></html>"
|
280
|
+
# res.body = body.to_s
|
281
|
+
# res['Content-Type'] = "text/html"
|
282
|
+
#}
|
283
|
+
#
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# This experiment sends a reset to all the resources which are associated to it
|
3
|
+
# Typically, one would run this experiment with a specific Experiment ID, with
|
4
|
+
# the following command:
|
5
|
+
# omf-5.4 exec -e your_experiment_id system:exp:reset
|
6
|
+
#
|
7
|
+
property.resetDelay = 1
|
8
|
+
property.resetTries = 0
|
9
|
+
info "---------------"
|
10
|
+
info " "
|
11
|
+
info " This management experiment will send a RESET to all resources"
|
12
|
+
info " in the experiment with the ID: #{Experiment.ID}"
|
13
|
+
info " (Typically one would run this experiment with the following"
|
14
|
+
info " command: omf-5.4 exec -e your_experiment_id system:exp:reset)"
|
15
|
+
info " "
|
16
|
+
info " Please wait a few second now..."
|
17
|
+
info " "
|
18
|
+
info "---------------"
|
19
|
+
defGroup("reset", "")
|
20
|
+
ECCommunicator.instance.send_reset
|
21
|
+
Experiment.done
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2009 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# = saveNode.rb
|
26
|
+
#
|
27
|
+
# == Description
|
28
|
+
#
|
29
|
+
# This file describes the Experiment that is used to save the disk image of a node within OMF.
|
30
|
+
# (In OMF, saving the disk image of a node is treated as an 'experiment' itself)
|
31
|
+
#
|
32
|
+
#
|
33
|
+
|
34
|
+
Experiment.name = "imageNode"
|
35
|
+
Experiment.project = "Orbit::Admin"
|
36
|
+
|
37
|
+
defProperty('node', 'omf.nicta.node1', "Node to save image of")
|
38
|
+
defProperty('pxe', '1.1.6', "PXE version to use")
|
39
|
+
defProperty('domain', "#{OConfig.domain}", "Domain of the node to save")
|
40
|
+
defProperty('started', 'false', "internal flag")
|
41
|
+
|
42
|
+
OMF::Services.pxe.setBootImageNS(:ns => "#{prop.node.value}", :domain => "#{prop.domain.value}")
|
43
|
+
|
44
|
+
def clearPXE
|
45
|
+
OMF::Services.pxe.clearBootImageNS(:ns => "#{prop.node.value}", :domain => "#{prop.domain.value}")
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Define nodes used in experiment
|
50
|
+
#
|
51
|
+
defGroup('save', Experiment.property('node')) {|n|
|
52
|
+
#n.pxeImage("#{prop.domain.value}", setPXE=true)
|
53
|
+
n.image = "pxe-5.4"
|
54
|
+
}
|
55
|
+
|
56
|
+
everyNS('save', 10) { |ns|
|
57
|
+
notDone = true
|
58
|
+
ns.each { |n|
|
59
|
+
status = n.match('apps/*/status/')[0].to_s
|
60
|
+
if status =~ /DONE/
|
61
|
+
notDone = false
|
62
|
+
if status =~ /DONE.ERR/
|
63
|
+
info("- Saving disk image of '#{n}' finished with ERRORS!")
|
64
|
+
info(" Check the log file (probably disk read error on the node)")
|
65
|
+
else
|
66
|
+
info("- Saving disk image of '#{n}' finished with success.")
|
67
|
+
end
|
68
|
+
info("- Saving process completed at: #{Time.now}")
|
69
|
+
info " "
|
70
|
+
end
|
71
|
+
}
|
72
|
+
Experiment.done if notDone == false
|
73
|
+
notDone
|
74
|
+
}
|
75
|
+
|
76
|
+
everyNS('save', 10) { |ns|
|
77
|
+
ns.each { |n|
|
78
|
+
status = n.match('apps/*/status/')[0].to_s
|
79
|
+
if status =~ /STARTED/
|
80
|
+
if prop.started.value == "false"
|
81
|
+
prop.started = "true"
|
82
|
+
info " "
|
83
|
+
info "- Saving process started at: #{Time.now}"
|
84
|
+
info " (this may take a while depending on the size of your image)"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
onEvent(:INTERRUPT) {
|
91
|
+
clearPXE
|
92
|
+
}
|
93
|
+
|
94
|
+
onEvent(:ALL_UP) {
|
95
|
+
clearPXE
|
96
|
+
group('save').each { |n|
|
97
|
+
n.saveImage
|
98
|
+
}
|
99
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This experiment prints the CMC power state of each node in the given topology
|
2
|
+
|
3
|
+
# empty group to stop OMF from complaining
|
4
|
+
# & prevent it from powering on nodes
|
5
|
+
defGroup("stat","")
|
6
|
+
|
7
|
+
defProperty('nodes', 'system:topo:all', 'Nodes to query')
|
8
|
+
defProperty('summary', false, 'Show a summary instead of details')
|
9
|
+
|
10
|
+
topo = nil
|
11
|
+
begin
|
12
|
+
# if 'nodes' is a topology file, try to load it
|
13
|
+
topo = Topology["#{prop.nodes}"]
|
14
|
+
rescue
|
15
|
+
# if not create a new topology here
|
16
|
+
topo = Topology.create(nil, "#{prop.nodes}")
|
17
|
+
end
|
18
|
+
|
19
|
+
tuples = []
|
20
|
+
|
21
|
+
$stderr.print " Talking to the CMC service, please wait"
|
22
|
+
|
23
|
+
topo.eachNode {|n|
|
24
|
+
tuples << ["#{n.to_s}", "#{OMF::Services.cmc.status(n.to_s, OConfig.domain).
|
25
|
+
first_element("NODE_STATUS/detail/node").attributes['state']}"]
|
26
|
+
$stderr.print "."
|
27
|
+
}
|
28
|
+
|
29
|
+
puts
|
30
|
+
puts "-----------------------------------------------"
|
31
|
+
puts " Domain: #{OConfig.domain}"
|
32
|
+
if property.summary.value
|
33
|
+
on = off = unknown = 0
|
34
|
+
tuples.each {|t|
|
35
|
+
on += 1 if t[1] == "POWERON"
|
36
|
+
off += 1 if t[1] == "POWEROFF"
|
37
|
+
unknown += 1 if t[1] == "UNKNOWN"
|
38
|
+
}
|
39
|
+
puts " Number of nodes in 'Power ON' state:\t#{on}"
|
40
|
+
puts " Number of nodes in 'Power OFF' state:\t#{off}"
|
41
|
+
puts " Number of nodes in 'Unknown' state:\t#{unknown}"
|
42
|
+
else
|
43
|
+
tuples.each {|t|
|
44
|
+
puts " Node: #{t[0]} \t State: #{t[1]}"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
puts "-----------------------------------------------"
|
48
|
+
|
49
|
+
Experiment.done
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2009 National ICT Australia (NICTA), Australia
|
3
|
+
# Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#
|
23
|
+
#
|
24
|
+
# = stdlib.rb
|
25
|
+
#
|
26
|
+
# == Description
|
27
|
+
#
|
28
|
+
# This Ruby file contains various general declarations, which the EC will load
|
29
|
+
# before the user's experiment file
|
30
|
+
#
|
31
|
+
# These declarations implement the process that loop, check and wait that all
|
32
|
+
# the required nodes are UP, before proceeding with the remaining of the
|
33
|
+
# experiment
|
34
|
+
#
|
35
|
+
|
36
|
+
# Define some properties that we will use in this
|
37
|
+
defProperty('resetDelay', 210,
|
38
|
+
"Time to wait before assuming that node didn't boot")
|
39
|
+
defProperty('resetTries', 1,
|
40
|
+
"Number of reset tries before declaring node dead")
|
41
|
+
# keeps track of how many times a node has been reset
|
42
|
+
ResetCount = {}
|
43
|
+
|
44
|
+
#
|
45
|
+
# This declaration calls the 'everyNS' loop defined in handlerCommand.rb
|
46
|
+
# This declared bloc will be executed for all the existing node sets ('*')
|
47
|
+
# every 10sec. This loop will stop when the bloc returns 'false', which will
|
48
|
+
# happen when all the nodes are UP
|
49
|
+
#
|
50
|
+
everyNS('*', 10) { |ns|
|
51
|
+
|
52
|
+
# First check if the experiment has not been interrupted
|
53
|
+
#exp_status = Experiment.state("status/text()")
|
54
|
+
#return true if allEqual(exp_status, "INTERRUPTED")
|
55
|
+
|
56
|
+
|
57
|
+
# Now check if we are done with adding node in that experiment
|
58
|
+
# If not, we skip the checks and loop again in 10sec
|
59
|
+
if NodeSet.frozen?
|
60
|
+
# Yes, we are done adding nodes...
|
61
|
+
nodesDown = []
|
62
|
+
nodeCnt = 0
|
63
|
+
# For each node in this Node Set, check if it is UP
|
64
|
+
# Check that for 'resetDelay' time, if no sucess, reset the node
|
65
|
+
# Do only 'resetTries' number of resets before giving up on a node
|
66
|
+
ns.eachNode { |n|
|
67
|
+
nodeCnt += 1
|
68
|
+
if ! n.isUp
|
69
|
+
nodesDown << n
|
70
|
+
poweredAt = n.poweredAt
|
71
|
+
if (poweredAt.kind_of?(Time))
|
72
|
+
startupDelay = Time.now - poweredAt
|
73
|
+
if (startupDelay > Experiment.property('resetDelay').value)
|
74
|
+
count = ResetCount[n] = (ResetCount[n] || 0) + 1
|
75
|
+
if (count <= prop.resetTries.value)
|
76
|
+
MObject.info('stdlib', "Resetting node ", n)
|
77
|
+
n.reset()
|
78
|
+
else
|
79
|
+
MObject.warn('stdlib', "Giving up on node ", n)
|
80
|
+
if NodeHandler.ALLOWMISSING
|
81
|
+
Topology.removeNode(n)
|
82
|
+
if Topology.empty?
|
83
|
+
MObject.info("stdlib", " ")
|
84
|
+
MObject.info("stdlib", "No resources available for this "+
|
85
|
+
"experiment. Closing the experiment now!" )
|
86
|
+
MObject.info("stdlib", "Please wait and ignore remaining "+
|
87
|
+
"messages...")
|
88
|
+
MObject.info("stdlib", " ")
|
89
|
+
Experiment.close
|
90
|
+
end
|
91
|
+
else
|
92
|
+
MObject.error('stdlib', "One or more nodes failed to check in " +
|
93
|
+
"to your experiment. To ignore and continue, use the '-a'"+
|
94
|
+
" flag. Exiting now.")
|
95
|
+
Experiment.close
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
}
|
102
|
+
# Check the number of nodes still not UP...
|
103
|
+
nodesDownCnt = nodesDown.length
|
104
|
+
if nodesDownCnt > 0
|
105
|
+
MObject.info('stdlib', "Waiting for nodes (Up/Down/Total): "+
|
106
|
+
"#{nodeCnt-nodesDownCnt}/#{nodesDownCnt}/#{nodeCnt}",
|
107
|
+
" - (still down: ", nodesDown[0..2].join(','),")")
|
108
|
+
end
|
109
|
+
# Check if the experiment is not interrupted
|
110
|
+
exp_status = Experiment.state("status/text()")
|
111
|
+
if allEqual(exp_status, "INTERRUPTED")
|
112
|
+
false
|
113
|
+
else
|
114
|
+
# The experiment is running, stop looping if all the nodes are UP!
|
115
|
+
nodesDownCnt > 0
|
116
|
+
end
|
117
|
+
else
|
118
|
+
# We have not finished adding nodes to this experiment,
|
119
|
+
# loop and check again in 10sec
|
120
|
+
true
|
121
|
+
end
|
122
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# This experiment can be used to power on, off, reset or reboot nodes using the CMC
|
2
|
+
|
3
|
+
# empty group to stop OMF from complaining
|
4
|
+
# & prevent it from powering on nodes
|
5
|
+
defGroup("tell","")
|
6
|
+
|
7
|
+
defProperty('nodes', 'system:topo:all', 'Nodes to act on')
|
8
|
+
defProperty('command', false, 'Command as in on, offh, offs, reboot, reset')
|
9
|
+
|
10
|
+
topo = nil
|
11
|
+
begin
|
12
|
+
# if 'nodes' is a topology file, try to load it
|
13
|
+
topo = Topology["#{prop.nodes}"]
|
14
|
+
rescue
|
15
|
+
# if not create a new topology here
|
16
|
+
topo = Topology.create(nil, "#{prop.nodes}")
|
17
|
+
end
|
18
|
+
|
19
|
+
tuples = []
|
20
|
+
call = nil
|
21
|
+
|
22
|
+
case "#{prop.command}"
|
23
|
+
when "on"
|
24
|
+
call = "on"
|
25
|
+
when "offh"
|
26
|
+
call = "offHard"
|
27
|
+
when "offs"
|
28
|
+
call = "offSoft"
|
29
|
+
when "reboot"
|
30
|
+
call = "reboot"
|
31
|
+
when "reset"
|
32
|
+
call = "reset"
|
33
|
+
else
|
34
|
+
raise "Unknown command: '#{prop.command}'. Use 'help' to see usage information."
|
35
|
+
end
|
36
|
+
|
37
|
+
$stderr.print " Talking to the CMC service, please wait"
|
38
|
+
|
39
|
+
topo.eachNode {|n|
|
40
|
+
tuples << ["#{n.to_s}", eval("OMF::Services.cmc.#{call}"+
|
41
|
+
"(n.to_s, OConfig.domain).elements[1].name")]
|
42
|
+
$stderr.print "."
|
43
|
+
}
|
44
|
+
|
45
|
+
puts
|
46
|
+
puts "-----------------------------------------------"
|
47
|
+
puts " Domain: #{OConfig.domain} - Command: #{call}"
|
48
|
+
tuples.each {|t|
|
49
|
+
puts " Node: #{t[0]} \t Reply: #{t[1]}"
|
50
|
+
}
|
51
|
+
puts "-----------------------------------------------"
|
52
|
+
|
53
|
+
Experiment.done
|
@@ -0,0 +1,12 @@
|
|
1
|
+
defProperty('logpath', "unconfigured-logpath", "Path to experiment log")
|
2
|
+
defProperty('outpath', "unconfigured-outpath", "Path to experiment output")
|
3
|
+
|
4
|
+
onEvent(:EXPERIMENT_DONE) do |event|
|
5
|
+
begin
|
6
|
+
f = File.open("#{property.outpath}", 'w')
|
7
|
+
check_outcome ? f.puts("OK") : f.puts("FAILED")
|
8
|
+
f.close
|
9
|
+
rescue Exception => ex
|
10
|
+
puts "TEST - Failed to check the outcome of a test (Error: '#{ex}'"
|
11
|
+
end
|
12
|
+
end
|