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,50 @@
|
|
1
|
+
|
2
|
+
# just reuse existing thing
|
3
|
+
|
4
|
+
def __check_g5k_credentials_path__
|
5
|
+
home = Etc.getpwuid.dir
|
6
|
+
return File.join(home, '.g5k.yaml')
|
7
|
+
end
|
8
|
+
|
9
|
+
def __check_g5k_credentials__
|
10
|
+
path = __check_g5k_credentials_path__()
|
11
|
+
if File.exist?(path)
|
12
|
+
h = YAML.load_file(path)
|
13
|
+
mode = File::Stat.new(path).mode
|
14
|
+
raise "#{path} is accessible by other users" if (mode & 077 != 0)
|
15
|
+
else
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
if !h.is_a?(Hash) or h["user"].nil? or h["pass"].nil?
|
19
|
+
raise "bad credentials"
|
20
|
+
end
|
21
|
+
[ h["user"], h["pass"] ]
|
22
|
+
end
|
23
|
+
|
24
|
+
def __save_g5k_credentials__
|
25
|
+
path = __check_g5k_credentials_path__()
|
26
|
+
File.open(path, "w") do |f|
|
27
|
+
f.puts({
|
28
|
+
"user" => $g5k_user,
|
29
|
+
"pass" => $g5k_pass
|
30
|
+
}.to_yaml)
|
31
|
+
end
|
32
|
+
File.chmod(0600, path)
|
33
|
+
end
|
34
|
+
|
35
|
+
$g5k_creds = __check_g5k_credentials__()
|
36
|
+
|
37
|
+
if $g5k_creds.nil?
|
38
|
+
# no credentials
|
39
|
+
$g5k_user = var(:g5k_user, :str, :text => "Provide G5K username: ")
|
40
|
+
$g5k_pass = var(:g5k_pass, :pass, :text => "Provide G5K password: ")
|
41
|
+
$g5k_save = var(:g5k_save, :bool, :callback => proc { |x| __save_g5k_credentials__ if x }, :text => "Do you want to save these credentials?")
|
42
|
+
else
|
43
|
+
$g5k_user = set_var(:g5k_user, $g5k_creds.first)
|
44
|
+
$g5k_pass = set_var(:g5k_pass, $g5k_creds.last)
|
45
|
+
end
|
46
|
+
|
47
|
+
# hide the password
|
48
|
+
set_var(:g5k_pass, "*" * $g5k_pass.length)
|
49
|
+
|
50
|
+
require 'xpflow/with_g5k'
|
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class << Sinatra::Base
|
6
|
+
|
7
|
+
def quit!(server, handler_name)
|
8
|
+
server.respond_to?(:stop!) ? server.stop! : server.stop
|
9
|
+
end
|
10
|
+
|
11
|
+
# copy-pasted-adjusted from sinatra code (1.3.2-2 in Debian)
|
12
|
+
def _run_custom!(options={})
|
13
|
+
set options
|
14
|
+
set :logging, nil
|
15
|
+
handler = detect_rack_handler
|
16
|
+
handler_name = handler.name.gsub(/.*::/, '')
|
17
|
+
handler.run self, :Host => bind, :Port => port do |server|
|
18
|
+
@__quit__ = proc { || quit!(server, handler_name) }
|
19
|
+
server.threaded = settings.threaded if server.respond_to? :threaded=
|
20
|
+
set :running, true
|
21
|
+
yield server if block_given?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_custom!(options={})
|
26
|
+
# it may result in a race
|
27
|
+
# small note here:
|
28
|
+
# THERE MUST BE A SPECIAL PLACE
|
29
|
+
# IN HELL FOR PEOPLE DOING THINGS LIKE THIS!!!
|
30
|
+
handler = trap(:INT, 'DEFAULT') # take previous handler
|
31
|
+
trap(:INT, handler)
|
32
|
+
t = Thread.new(handler) do |h|
|
33
|
+
x = h
|
34
|
+
while x == h do
|
35
|
+
sleep 0.1
|
36
|
+
x = trap(:INT, &h)
|
37
|
+
end
|
38
|
+
# x is sinatra wicked handler
|
39
|
+
# let's overwrite it back
|
40
|
+
trap(:INT, &h)
|
41
|
+
end
|
42
|
+
_run_custom!(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def quit_custom!
|
46
|
+
return @__quit__.call()
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
|
51
|
+
# sets xpflow engine
|
52
|
+
def set_engine(engine)
|
53
|
+
$__gui_engine__ = engine
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
class Rest
|
60
|
+
|
61
|
+
attr_reader :engine
|
62
|
+
|
63
|
+
def initialize(engine)
|
64
|
+
@engine = engine
|
65
|
+
end
|
66
|
+
|
67
|
+
def activities
|
68
|
+
ns = @engine.get_global_namespace()
|
69
|
+
return ns.each.map do |name, o|
|
70
|
+
{ :name => name, :info => o.info }
|
71
|
+
end.to_a
|
72
|
+
end
|
73
|
+
|
74
|
+
def active
|
75
|
+
h = @engine.spectator.info
|
76
|
+
h2 = []
|
77
|
+
h.each_pair do |k, v|
|
78
|
+
h2.push({ :name => k, :info => v })
|
79
|
+
end
|
80
|
+
return h2
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
class Controller < Sinatra::Base
|
87
|
+
|
88
|
+
set :port, 8080
|
89
|
+
set :public_folder, File.join(File.dirname(__FILE__), 'gui-files')
|
90
|
+
|
91
|
+
def rest
|
92
|
+
return Rest.new($__gui_engine__)
|
93
|
+
end
|
94
|
+
|
95
|
+
def json(obj)
|
96
|
+
content_type 'application/json', :charset => 'utf-8'
|
97
|
+
return obj.to_json
|
98
|
+
end
|
99
|
+
|
100
|
+
get '/__rest__/:method' do |m|
|
101
|
+
x = rest.send(m.to_sym)
|
102
|
+
json x
|
103
|
+
end
|
104
|
+
|
105
|
+
get '/' do
|
106
|
+
erb :index
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
if $0 == __FILE__
|
112
|
+
|
113
|
+
require 'xpflow'
|
114
|
+
|
115
|
+
process :main do
|
116
|
+
run :whatever
|
117
|
+
run :whatever
|
118
|
+
end
|
119
|
+
|
120
|
+
activity :whatever do |x|
|
121
|
+
sleep 10
|
122
|
+
log "cze"
|
123
|
+
end
|
124
|
+
|
125
|
+
Controller.set_engine($engine)
|
126
|
+
|
127
|
+
trap(:INT) do
|
128
|
+
puts 'Shutting everything down...'
|
129
|
+
Controller.quit_custom!
|
130
|
+
end
|
131
|
+
|
132
|
+
t = Thread.new do
|
133
|
+
Controller.run_custom!
|
134
|
+
end
|
135
|
+
|
136
|
+
$engine.execute_from_argv :main
|
137
|
+
|
138
|
+
t.join
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
|
2
|
+
# this is pulled in by the main xpflow command line tool
|
3
|
+
|
4
|
+
# a standard model for an experiment
|
5
|
+
|
6
|
+
NODES_OPTS = { :doc => "Resource acquisition" }
|
7
|
+
DEPLOYMENT_OPTS = { :doc => "Deployment", :idempotent => true }
|
8
|
+
COLLECTION_OPTS = { :doc => "Collection of results" }
|
9
|
+
ANALYSIS_OPTS = { :doc => "Data analysis" }
|
10
|
+
EXPERIMENT_OPTS = { :doc => "Experiment" }
|
11
|
+
STANDARD_OPTS = { :doc => "Experiment model" }
|
12
|
+
|
13
|
+
$engine.process :__reservation__, NODES_OPTS do |nodes|
|
14
|
+
value(nodes)
|
15
|
+
end
|
16
|
+
|
17
|
+
$engine.process :__deployment__, DEPLOYMENT_OPTS do |nodes|
|
18
|
+
value(nodes)
|
19
|
+
end
|
20
|
+
|
21
|
+
$engine.process :__collection__, COLLECTION_OPTS do
|
22
|
+
debug "Collecting results from nodes..."
|
23
|
+
save_all_results
|
24
|
+
end
|
25
|
+
|
26
|
+
$engine.process :__analysis__, ANALYSIS_OPTS do |exp_result|
|
27
|
+
value(exp_result)
|
28
|
+
end
|
29
|
+
|
30
|
+
$engine.activity :__install_node__, :doc => "Install a given node", :log_level => :none do |node|
|
31
|
+
node.install()
|
32
|
+
end
|
33
|
+
|
34
|
+
$engine.process :__install_nodes__, :doc => "Initial node setup", :log_level => :none do |nodes|
|
35
|
+
foreach nodes do |node|
|
36
|
+
debug "Installing ", node
|
37
|
+
run :__install_node__, node
|
38
|
+
end
|
39
|
+
count = (length_of nodes)
|
40
|
+
on(count > 0) do
|
41
|
+
bootstrap_taktuk(nodes)
|
42
|
+
end
|
43
|
+
# TODO: more parallel and more scalable
|
44
|
+
forall nodes, :pool => 10 do |node|
|
45
|
+
debug "Bootstrapping ", node
|
46
|
+
code(node) { |node| node.bootstrap }
|
47
|
+
end
|
48
|
+
|
49
|
+
# checking nodes - run a simple command everywhere
|
50
|
+
# be idempotent - if some nodes fail, retry them
|
51
|
+
|
52
|
+
run :__check_nodes__, nodes
|
53
|
+
value(nodes)
|
54
|
+
end
|
55
|
+
|
56
|
+
$engine.process :__check_nodes__, :doc => "Checking all nodes", :log_level => :none do |nodes|
|
57
|
+
results = execute_many nodes, "true", :idempotent => true
|
58
|
+
length = length_of results
|
59
|
+
debug "All nodes (#{length}) checked"
|
60
|
+
end
|
61
|
+
|
62
|
+
$engine.activity :__fix_node_list__ do |list|
|
63
|
+
(list.nil?) ? [] : list
|
64
|
+
end
|
65
|
+
|
66
|
+
$engine.process :__standard__, STANDARD_OPTS do |node_list|
|
67
|
+
|
68
|
+
flattened_node_list = run :__fix_node_list__, node_list
|
69
|
+
|
70
|
+
nodes = cache :__reservation__ do
|
71
|
+
run :__reservation__, flattened_node_list
|
72
|
+
end
|
73
|
+
|
74
|
+
nodes_list = run :__install_nodes__, nodes
|
75
|
+
|
76
|
+
# replace __reservation__ with a new set
|
77
|
+
set_scope :__nodes__, nodes_list
|
78
|
+
|
79
|
+
deployed = cache :__deployment__ do
|
80
|
+
run :__deployment__, nodes
|
81
|
+
end
|
82
|
+
|
83
|
+
exp_result = run :__experiment__, deployed
|
84
|
+
run :__collection__
|
85
|
+
run :__analysis__, exp_result
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
# helpers
|
90
|
+
|
91
|
+
def nodes(&block)
|
92
|
+
return $engine.process(:__reservation__, NODES_OPTS, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def deployment(name = nil, &block)
|
96
|
+
if name.nil?
|
97
|
+
return $engine.process(:__deployment__, DEPLOYMENT_OPTS, &block)
|
98
|
+
else
|
99
|
+
return $engine.process(:__deployment__, DEPLOYMENT_OPTS) { |nodes| run(name, nodes) }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def body(&block)
|
104
|
+
return $engine.process(:__experiment__, EXPERIMENT_OPTS, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def analysis(&block)
|
108
|
+
return $engine.process(:__analysis__, ANALYSIS_OPTS, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# importer of subexperiments
|
113
|
+
# TODO: this is rather ugly!
|
114
|
+
|
115
|
+
def with_sublibrary()
|
116
|
+
exp = nil
|
117
|
+
begin
|
118
|
+
old_engine = $engine
|
119
|
+
exp = $engine = XPFlow::BasicLibrary.new
|
120
|
+
yield
|
121
|
+
ensure
|
122
|
+
$engine = old_engine
|
123
|
+
end
|
124
|
+
return exp
|
125
|
+
end
|
126
|
+
|
127
|
+
def import(name, path = nil, opts = {})
|
128
|
+
if path.nil?
|
129
|
+
return import_file(name)
|
130
|
+
end
|
131
|
+
lib = with_sublibrary do
|
132
|
+
Kernel.load(__FILE__, true)
|
133
|
+
Kernel.load(path)
|
134
|
+
end
|
135
|
+
$engine.import_library(name, lib)
|
136
|
+
return lib
|
137
|
+
end
|
138
|
+
|
139
|
+
def library(name, &block)
|
140
|
+
lib = with_sublibrary do
|
141
|
+
Kernel.load(__FILE__, true)
|
142
|
+
block.call
|
143
|
+
end
|
144
|
+
$engine.import_library(name, lib)
|
145
|
+
return lib
|
146
|
+
end
|
147
|
+
|
148
|
+
# includes the file as-it-is
|
149
|
+
def import_file(path)
|
150
|
+
return Kernel.load(path)
|
151
|
+
end
|
152
|
+
|
153
|
+
def experiment_entry(&block)
|
154
|
+
return $engine.process(:__standard__, &block)
|
155
|
+
end
|