omf_ec 6.0.0.pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|