xpflow 0.1b
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/bin/xpflow +96 -0
- data/lib/colorado.rb +198 -0
- data/lib/json/add/core.rb +243 -0
- data/lib/json/add/rails.rb +8 -0
- data/lib/json/common.rb +423 -0
- data/lib/json/editor.rb +1369 -0
- data/lib/json/ext.rb +28 -0
- data/lib/json/pure/generator.rb +442 -0
- data/lib/json/pure/parser.rb +320 -0
- data/lib/json/pure.rb +15 -0
- data/lib/json/version.rb +8 -0
- data/lib/json.rb +62 -0
- data/lib/mime/types.rb +881 -0
- data/lib/mime-types.rb +3 -0
- data/lib/restclient/abstract_response.rb +106 -0
- data/lib/restclient/exceptions.rb +193 -0
- data/lib/restclient/net_http_ext.rb +55 -0
- data/lib/restclient/payload.rb +235 -0
- data/lib/restclient/raw_response.rb +34 -0
- data/lib/restclient/request.rb +316 -0
- data/lib/restclient/resource.rb +169 -0
- data/lib/restclient/response.rb +24 -0
- data/lib/restclient.rb +174 -0
- data/lib/xpflow/bash.rb +341 -0
- data/lib/xpflow/bundle.rb +113 -0
- data/lib/xpflow/cmdline.rb +249 -0
- data/lib/xpflow/collection.rb +122 -0
- data/lib/xpflow/concurrency.rb +79 -0
- data/lib/xpflow/data.rb +393 -0
- data/lib/xpflow/dsl.rb +816 -0
- data/lib/xpflow/engine.rb +574 -0
- data/lib/xpflow/ensemble.rb +135 -0
- data/lib/xpflow/events.rb +56 -0
- data/lib/xpflow/experiment.rb +65 -0
- data/lib/xpflow/exts/facter.rb +30 -0
- data/lib/xpflow/exts/g5k.rb +931 -0
- data/lib/xpflow/exts/g5k_use.rb +50 -0
- data/lib/xpflow/exts/gui.rb +140 -0
- data/lib/xpflow/exts/model.rb +155 -0
- data/lib/xpflow/graph.rb +1603 -0
- data/lib/xpflow/graph_xpflow.rb +251 -0
- data/lib/xpflow/import.rb +196 -0
- data/lib/xpflow/library.rb +349 -0
- data/lib/xpflow/logging.rb +153 -0
- data/lib/xpflow/manager.rb +147 -0
- data/lib/xpflow/nodes.rb +1250 -0
- data/lib/xpflow/runs.rb +773 -0
- data/lib/xpflow/runtime.rb +125 -0
- data/lib/xpflow/scope.rb +168 -0
- data/lib/xpflow/ssh.rb +186 -0
- data/lib/xpflow/stat.rb +50 -0
- data/lib/xpflow/stdlib.rb +381 -0
- data/lib/xpflow/structs.rb +369 -0
- data/lib/xpflow/taktuk.rb +193 -0
- data/lib/xpflow/templates/ssh-config.basic +14 -0
- data/lib/xpflow/templates/ssh-config.inria +18 -0
- data/lib/xpflow/templates/ssh-config.proxy +13 -0
- data/lib/xpflow/templates/taktuk +6590 -0
- data/lib/xpflow/templates/utils/batch +4 -0
- data/lib/xpflow/templates/utils/bootstrap +12 -0
- data/lib/xpflow/templates/utils/hostname +3 -0
- data/lib/xpflow/templates/utils/ping +3 -0
- data/lib/xpflow/templates/utils/rsync +12 -0
- data/lib/xpflow/templates/utils/scp +17 -0
- data/lib/xpflow/templates/utils/scp_many +8 -0
- data/lib/xpflow/templates/utils/ssh +3 -0
- data/lib/xpflow/templates/utils/ssh-interactive +4 -0
- data/lib/xpflow/templates/utils/taktuk +19 -0
- data/lib/xpflow/threads.rb +187 -0
- data/lib/xpflow/utils.rb +569 -0
- data/lib/xpflow/visual.rb +230 -0
- data/lib/xpflow/with_g5k.rb +7 -0
- data/lib/xpflow.rb +349 -0
- metadata +135 -0
@@ -0,0 +1,381 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
#
|
4
|
+
# Implementation of core activities.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'erb'
|
8
|
+
require 'ostruct'
|
9
|
+
|
10
|
+
module XPFlow
|
11
|
+
|
12
|
+
class Erb < OpenStruct
|
13
|
+
|
14
|
+
def render(hash)
|
15
|
+
ERB.new(hash).result(binding)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.render(template, hash)
|
19
|
+
x = Erb.new(hash)
|
20
|
+
return x.render(template)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# SSH = Net::SSH
|
26
|
+
|
27
|
+
class CoreLibrary < HiddenActivityLibrary
|
28
|
+
|
29
|
+
activities :sleep, :value, :code, :log, :repr, :system, :range,
|
30
|
+
:render_file, :render, :render_inline, :assert, :debug,
|
31
|
+
:start, :set_scope, :get_scope, :fail, :new_experiment,
|
32
|
+
:arguments, :item_range, :shift,
|
33
|
+
:send => :send_method, :id => :value, :"λ" => :code
|
34
|
+
|
35
|
+
def render_inline(template, hash = {})
|
36
|
+
return Erb.render(template, hash)
|
37
|
+
end
|
38
|
+
|
39
|
+
def shift(array)
|
40
|
+
return [ array.first, array.tail ]
|
41
|
+
end
|
42
|
+
|
43
|
+
def render(name, hash = {})
|
44
|
+
tmpl = $files[name]
|
45
|
+
raise "Template does not exist!" if tmpl.nil?
|
46
|
+
template = IO.read(tmpl)
|
47
|
+
return render_inline(template, hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
def arguments(shift = 0)
|
51
|
+
tab = Scope.current.parent_activity[:__name__].arguments
|
52
|
+
return tab[shift ... tab.length]
|
53
|
+
end
|
54
|
+
|
55
|
+
def new_experiment
|
56
|
+
# inserts a new experiment in the +1 scope
|
57
|
+
scope = Scope.current.parent_activity
|
58
|
+
parent_experiment = scope[:__experiment__]
|
59
|
+
name = scope[:__name__].activity_full_name
|
60
|
+
scope[:__experiment__] = parent_experiment.create_subexperiment(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_file(name, out, hash = {})
|
64
|
+
s = render(name, hash)
|
65
|
+
File.open(out, "wb") do |f|
|
66
|
+
f.write(s)
|
67
|
+
end
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def sleep(time)
|
72
|
+
span = Timespan.to_secs(time)
|
73
|
+
if span.infinite?
|
74
|
+
loop do; Kernel.sleep(1) end
|
75
|
+
end
|
76
|
+
Kernel.sleep(span)
|
77
|
+
end
|
78
|
+
|
79
|
+
def system(cmd)
|
80
|
+
result = `#{cmd}`
|
81
|
+
status = $?
|
82
|
+
code = status.exitstatus
|
83
|
+
raise "'#{cmd}' returned with code = #{code}" if code != 0
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
|
87
|
+
def value(v)
|
88
|
+
return v
|
89
|
+
end
|
90
|
+
|
91
|
+
def code(*args)
|
92
|
+
raise 'No code given.' unless block_given?
|
93
|
+
return yield(*args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def flatten_msgs(msgs)
|
97
|
+
return msgs.map { |m| m.__repr__ }.join("")
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_scope(name)
|
101
|
+
return Scope.current[name]
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_name
|
105
|
+
return Scope.current.parent[:__name__].activity_full_name
|
106
|
+
end
|
107
|
+
|
108
|
+
def log(*msgs)
|
109
|
+
msg = "Process %s: %s" % [ process_name.green, flatten_msgs(msgs) ]
|
110
|
+
proxy.engine.log(msg)
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def debug(*msgs)
|
115
|
+
proxy.engine.debug(
|
116
|
+
"Process %s: %s" % [ process_name.green, flatten_msgs(msgs) ])
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
|
120
|
+
def fail(msg = "?", prob = 1.0)
|
121
|
+
raise "Failure (reason: #{msg})" if (Kernel.rand <= prob)
|
122
|
+
end
|
123
|
+
|
124
|
+
def send_method(o, method, *args)
|
125
|
+
return o.send(method.to_sym, *args) if o.respond_to?(method)
|
126
|
+
return o[method] if (o.is_a?(Hash) and o.key?(method))
|
127
|
+
return o[method.to_s] if (o.is_a?(Hash) and o.key?(method.to_s))
|
128
|
+
raise "No '#{method}' method for #{o.class}"
|
129
|
+
end
|
130
|
+
|
131
|
+
def repr(v)
|
132
|
+
return v.__repr__
|
133
|
+
end
|
134
|
+
|
135
|
+
def range(*args)
|
136
|
+
f = args.first
|
137
|
+
if args.length == 1 and f.is_a?(Range)
|
138
|
+
return f.to_a
|
139
|
+
elsif args.length == 1 and f.is_a?(Fixnum)
|
140
|
+
return range(0 ... f)
|
141
|
+
elsif args.length == 2
|
142
|
+
return range(f ... args.last)
|
143
|
+
elsif args.length == 3
|
144
|
+
return (args[0] .. args[1]).step(args[2]).to_a
|
145
|
+
end
|
146
|
+
raise "Wrong arguments to range: #{args}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def item_range(items, last)
|
150
|
+
return items[0 ... last]
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_scope(key, value)
|
154
|
+
Scope.current.parent.parent[key] = value # TODO: that's kind of weird
|
155
|
+
end
|
156
|
+
|
157
|
+
def assert(condition)
|
158
|
+
raise "Assertion failed." unless condition
|
159
|
+
end
|
160
|
+
|
161
|
+
# mapped from runtime library
|
162
|
+
|
163
|
+
def start(*args)
|
164
|
+
return proxy.engine.runtime.invoke(:start, args)
|
165
|
+
end
|
166
|
+
|
167
|
+
def finish(*args)
|
168
|
+
return proxy.engine.runtime.invoke(:finish, args)
|
169
|
+
end
|
170
|
+
|
171
|
+
def event(*args)
|
172
|
+
return proxy.engine.runtime.invoke(:event, args)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
class GetSetLibrary < SyncedActivityLibrary
|
178
|
+
|
179
|
+
activities :get, :set, :config, :config_full,
|
180
|
+
:entry_activity,
|
181
|
+
:conf => :config
|
182
|
+
|
183
|
+
attr_accessor :configuration
|
184
|
+
|
185
|
+
include SerializableLibrary
|
186
|
+
|
187
|
+
def setup
|
188
|
+
@storage = {}
|
189
|
+
@configuration = {}
|
190
|
+
end
|
191
|
+
|
192
|
+
def get(key)
|
193
|
+
raise "Unknown key: #{key}" unless @storage.key?(key)
|
194
|
+
return @storage[key]
|
195
|
+
end
|
196
|
+
|
197
|
+
def set(key, value)
|
198
|
+
@storage[key] = value
|
199
|
+
end
|
200
|
+
|
201
|
+
def config(key)
|
202
|
+
raise "Unknown config option: #{key}" unless @configuration.key?(key)
|
203
|
+
return @configuration[key]
|
204
|
+
end
|
205
|
+
|
206
|
+
def config_full
|
207
|
+
return @configuration
|
208
|
+
end
|
209
|
+
|
210
|
+
def update_config(hash)
|
211
|
+
h = {}
|
212
|
+
hash.each_pair do |k, v|
|
213
|
+
h[k.to_sym] = v
|
214
|
+
end
|
215
|
+
@configuration.merge!(h)
|
216
|
+
end
|
217
|
+
|
218
|
+
def set_entry_activity(name)
|
219
|
+
set(:__original_entry__, name)
|
220
|
+
end
|
221
|
+
|
222
|
+
def entry_activity
|
223
|
+
return get(:__original_entry__)
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
class RunLater
|
229
|
+
# runs an activity later
|
230
|
+
|
231
|
+
attr_reader :name
|
232
|
+
attr_reader :args
|
233
|
+
|
234
|
+
def initialize(name, args)
|
235
|
+
@name = name
|
236
|
+
@args = args
|
237
|
+
end
|
238
|
+
|
239
|
+
def to_s
|
240
|
+
return "RunLater of '#{@name}' with (#{@args.inspect})"
|
241
|
+
end
|
242
|
+
|
243
|
+
def extend(args)
|
244
|
+
return RunLater.new(@name, @args + args)
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
class DataLibrary < SyncedActivityLibrary
|
250
|
+
|
251
|
+
activities :store, :data, :avg, :sum, :stddev, :gauss,
|
252
|
+
:confidence_precision, :confidence_interval, :save_yaml,
|
253
|
+
:data_vector, :conf_precision, :data_append, :data_push,
|
254
|
+
:run_later, :get_of, :minimal_sample, :minimal_sample_enough
|
255
|
+
|
256
|
+
def data_vector(values = nil)
|
257
|
+
return ValueData.new(values)
|
258
|
+
end
|
259
|
+
|
260
|
+
def get_of(object, key, default = nil)
|
261
|
+
str = key.to_s
|
262
|
+
sym = key.to_sym
|
263
|
+
if object.is_a?(Hash)
|
264
|
+
return object[str] if object.key?(str)
|
265
|
+
return object[sym] if object.key?(sym)
|
266
|
+
return default unless default.nil?
|
267
|
+
raise "No such key as '#{key}' in #{object}"
|
268
|
+
end
|
269
|
+
|
270
|
+
if object.respond_to?(sym)
|
271
|
+
return object.__send__(sym)
|
272
|
+
end
|
273
|
+
|
274
|
+
return default unless default.nil?
|
275
|
+
raise "No such property as '#{key}' on #{object} of class #{object.class}"
|
276
|
+
end
|
277
|
+
|
278
|
+
def setup
|
279
|
+
@storage = {}
|
280
|
+
end
|
281
|
+
|
282
|
+
def store(name, value)
|
283
|
+
@storage[name] = ValueData.new unless @storage.key?(name)
|
284
|
+
@storage[name].push(value.to_f)
|
285
|
+
end
|
286
|
+
|
287
|
+
def data(name)
|
288
|
+
@storage[name] = ValueData.new unless @storage.key?(name)
|
289
|
+
return @storage[name]
|
290
|
+
end
|
291
|
+
|
292
|
+
def run_later(name, *args)
|
293
|
+
if name.is_a?(RunLater)
|
294
|
+
return name.extend(args)
|
295
|
+
end
|
296
|
+
return RunLater.new(name, args)
|
297
|
+
end
|
298
|
+
|
299
|
+
def _stddev(vector)
|
300
|
+
m = avg(vector)
|
301
|
+
disp = vector.map { |x| (x - m)**2 }.reduce(:+)
|
302
|
+
var = disp.to_f / (vector.length - 1)
|
303
|
+
return (var ** 0.5)
|
304
|
+
end
|
305
|
+
|
306
|
+
def _sum(vector)
|
307
|
+
return vector.reduce(:+)
|
308
|
+
end
|
309
|
+
|
310
|
+
def _avg(vector)
|
311
|
+
return sum(vector).to_f / (vector.length)
|
312
|
+
end
|
313
|
+
|
314
|
+
def gauss(m = 0.0, s = 1.0)
|
315
|
+
x = Kernel.rand
|
316
|
+
y = Kernel.rand
|
317
|
+
p = (-2 * Math.log(1 - y)) ** 0.5
|
318
|
+
return m + s * Math.cos(2*Math::PI*x) * p
|
319
|
+
end
|
320
|
+
|
321
|
+
def data_append(data, x)
|
322
|
+
return data.append(x)
|
323
|
+
end
|
324
|
+
|
325
|
+
def data_push(data, x)
|
326
|
+
data.push(x)
|
327
|
+
end
|
328
|
+
|
329
|
+
def confidence_precision(name)
|
330
|
+
return data(name).confidence_precision
|
331
|
+
end
|
332
|
+
|
333
|
+
def conf_precision(x)
|
334
|
+
return x.confidence_precision
|
335
|
+
end
|
336
|
+
|
337
|
+
def confidence_interval(name)
|
338
|
+
return data(name).confidence_interval
|
339
|
+
end
|
340
|
+
|
341
|
+
def stddev(name)
|
342
|
+
return data(name).stddev
|
343
|
+
end
|
344
|
+
|
345
|
+
def sum(name)
|
346
|
+
if name.is_a?(Array)
|
347
|
+
return name.reduce(:+)
|
348
|
+
else
|
349
|
+
return data(name).sum
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def save_yaml(filename, obj)
|
354
|
+
IO.write(filename, obj.to_yaml)
|
355
|
+
end
|
356
|
+
def minimal_sample_enough(name,opts={})
|
357
|
+
minimal_sample(name,opts)<name.size
|
358
|
+
end
|
359
|
+
def minimal_sample(name,opts={})
|
360
|
+
opts.merge({:conf=>0.95,:abs=>1})
|
361
|
+
name.minimal_sample_both(opts[:rel],opts[:abs],opts[:conf])
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
class TestLibrary < SyncedActivityLibrary
|
366
|
+
# used for testing
|
367
|
+
|
368
|
+
attr_reader :values
|
369
|
+
activities :collect
|
370
|
+
|
371
|
+
def setup
|
372
|
+
@values = []
|
373
|
+
end
|
374
|
+
|
375
|
+
def collect(value)
|
376
|
+
@values.push(value)
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
end
|