SimControl 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +4 -0
- data/SimControl.gemspec +30 -0
- data/bin/simcontrol +4 -0
- data/lib/SimControl.rb +12 -0
- data/lib/SimControl/cli.rb +86 -0
- data/lib/SimControl/controller.rb +71 -0
- data/lib/SimControl/environments/base.rb +9 -0
- data/lib/SimControl/environments/python.rb +24 -0
- data/lib/SimControl/hosts.rb +37 -0
- data/lib/SimControl/version.rb +3 -0
- data/spec/acceptance/init_spec.rb +34 -0
- data/spec/acceptance/scenario_spec.rb +67 -0
- data/spec/cli/simulate_spec.rb +65 -0
- data/spec/controller_spec.rb +133 -0
- data/spec/environments/base_environment_spec.rb +31 -0
- data/spec/environments/python_environment_spec.rb +37 -0
- data/spec/hosts_spec.rb +67 -0
- data/spec/spec_helper.rb +40 -0
- data/templates/scaffolding/Controlfile +14 -0
- data/templates/scenario/scenario.rb +8 -0
- metadata +210 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
SimControl (0.1.0)
|
5
|
+
active_support
|
6
|
+
i18n
|
7
|
+
thor
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
active_support (3.0.0)
|
13
|
+
activesupport (= 3.0.0)
|
14
|
+
activesupport (3.0.0)
|
15
|
+
coderay (1.0.9)
|
16
|
+
diff-lcs (1.2.4)
|
17
|
+
fakefs (0.4.2)
|
18
|
+
i18n (0.6.4)
|
19
|
+
method_source (0.8.1)
|
20
|
+
pry (0.9.12.2)
|
21
|
+
coderay (~> 1.0.5)
|
22
|
+
method_source (~> 0.8)
|
23
|
+
slop (~> 3.4)
|
24
|
+
rake (10.1.0)
|
25
|
+
rspec (2.14.1)
|
26
|
+
rspec-core (~> 2.14.0)
|
27
|
+
rspec-expectations (~> 2.14.0)
|
28
|
+
rspec-mocks (~> 2.14.0)
|
29
|
+
rspec-core (2.14.4)
|
30
|
+
rspec-expectations (2.14.0)
|
31
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
32
|
+
rspec-mocks (2.14.1)
|
33
|
+
slop (3.4.6)
|
34
|
+
thor (0.18.1)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
SimControl!
|
41
|
+
bundler (~> 1.3)
|
42
|
+
fakefs
|
43
|
+
pry
|
44
|
+
rake
|
45
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 cschwartz
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
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, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 christian.schwartz@gmail.com
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
SimControl
|
2
|
+
==========
|
3
|
+
|
4
|
+
Usage Example
|
5
|
+
=============
|
6
|
+
|
7
|
+
* Create a new directory `control`, in the following assumed to be at
|
8
|
+
/home/simpy/control/, create a `Gemfile` with the
|
9
|
+
following content:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
source 'https://rubygems.org'
|
13
|
+
gem 'SimControl'
|
14
|
+
```
|
15
|
+
and run `bundle` to install the dependencies.
|
16
|
+
|
17
|
+
* Next, run `bundle exec simcontrol init` to create the basic directory structure:
|
18
|
+
|
19
|
+
```
|
20
|
+
├── Controlfile
|
21
|
+
├── Gemfile
|
22
|
+
├── Gemfile.lock
|
23
|
+
├── results
|
24
|
+
└── scenarios
|
25
|
+
```
|
26
|
+
|
27
|
+
The Controlfile describes both the hosts on which the simulation will run, as well as general information about the simulation program. The default Controlfile is given below
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
hosts do
|
31
|
+
#A host with name "hostname"
|
32
|
+
use "hostname"
|
33
|
+
|
34
|
+
#Another host, with 3 cores to be used for simulation
|
35
|
+
use "another-hostname", cores: 3
|
36
|
+
end
|
37
|
+
|
38
|
+
#currently only a python environment is implemented
|
39
|
+
simulation PythonEnvironment, "/home/simpy/simulation/simulation.py",
|
40
|
+
#use a virtualenv, not the global python
|
41
|
+
virtualenv: "/home/simpy/simpy-env",
|
42
|
+
#do not use the default system python but pypy
|
43
|
+
interpreter: "pypy"
|
44
|
+
```
|
45
|
+
|
46
|
+
* In order to create your first simulation scenario, run
|
47
|
+
|
48
|
+
```
|
49
|
+
bundle exec simcontrol scenario myScenario
|
50
|
+
```
|
51
|
+
|
52
|
+
which creates a results subfolder named myScenario as well as a scenario description file myScenario.rb in the scenarios folder, resulting in the following overall project structure:
|
53
|
+
|
54
|
+
```
|
55
|
+
.
|
56
|
+
├── Controlfile
|
57
|
+
├── Gemfile
|
58
|
+
├── Gemfile.lock
|
59
|
+
├── results
|
60
|
+
│ └── myScenario
|
61
|
+
└── scenarios
|
62
|
+
└── myScenario.rb
|
63
|
+
```
|
64
|
+
|
65
|
+
The default scenario description in myScenario.rb has the following content:
|
66
|
+
|
67
|
+
```
|
68
|
+
repetitions 10
|
69
|
+
numberOfServers = (1..100).step(10)
|
70
|
+
|
71
|
+
numberOfServers.each do |currentNumberOfServers|
|
72
|
+
simulate numberOfServers: currentNumberOfServers,
|
73
|
+
duration: 1.day + 1.hour,
|
74
|
+
transientPhaseDuration: 1.hour
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
This describes 10 scenarios, each with 10 repetitions are described. A system with a varying number of server components is simulated for a duration of 25 hours, the first hour is exempt from statistic collection to account for the transient phase.
|
79
|
+
|
80
|
+
* Next, we consider the execution of the simulation on one of the hosts specified in the Controlfile by running `bundle exec simulate myScenario`. First, all scenarios, i.e. calls to simulate, are enumerated. Then, they are assigned to the hosts specified via the host call, were each host is considered multiple times if multiple cores are specified. In our example, the 3 of the 10 scenarios will be assigned to hostname and the first core of another-hostname, while 2 scenarios will be assigned the remaining cores of another-hostname. Then, simcontrol obtains the local hostname and the assigned scenarios and one scenario group is started per core. The command to simulate a scenario is obtained as follows:
|
81
|
+
|
82
|
+
The class and options hash passed to the simulation method in Controlfile are used to construct a `PythonEnvironment` instance, which is able to start the simulation environment. Note, that the simulation method merges the options hash with computed options, e.g. the path to the scenarios results directory and the seed to use for the stimulation. The full set of parameters used to invoke the simulation are obtained from the parameters of the simulate method in myScenario.rb, were each of the options passed to the simulation as unix-style long parameters (i.e. foo: 4 is converted to --foo 4).
|
83
|
+
|
84
|
+
In our example this results in the following simulation scenarios. Note, that in our example each of the scenarios is executed with varying parameter values for SEED (seed generation is discussed later).
|
85
|
+
|
86
|
+
| Host | Core | Command |
|
87
|
+
|--------------|------|---------|
|
88
|
+
| host | % | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 1 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario/ |
|
89
|
+
| host | % | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 11 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
90
|
+
| host | % | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 21 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
91
|
+
| another-host | 1 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 1 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
92
|
+
| another-host | 1 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 11 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
93
|
+
| another-host | 1 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 21 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
94
|
+
| another-host | 2 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 1 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
95
|
+
| another-host | 2 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 11 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
96
|
+
| another-host | 3 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 1 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
97
|
+
| another-host | 3 | /home/simpy/simpy-env/bin/pypy /home/simpy/simulation/simulation.py --numberOfServers 11 --duration 90000 --transientPhaseDuration 3600 --seed SEED --results /home/simpy/control/results/myScenario |
|
98
|
+
|
data/Rakefile
ADDED
data/SimControl.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'SimControl/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "SimControl"
|
8
|
+
spec.version = SimControl::VERSION
|
9
|
+
spec.authors = ["Christian Schwartz"]
|
10
|
+
spec.email = ["christian.schwartz@gmail.com"]
|
11
|
+
spec.description = %q{A DSL for simpy based simulations on multiple hosts}
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = "https://github.com/cschwartz/SimControl"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "thor"
|
22
|
+
spec.add_dependency "active_support"
|
23
|
+
spec.add_dependency "i18n"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "fakefs"
|
30
|
+
end
|
data/bin/simcontrol
ADDED
data/lib/SimControl.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "SimControl/version"
|
2
|
+
require "SimControl/cli"
|
3
|
+
require "SimControl/controller"
|
4
|
+
require "SimControl/hosts"
|
5
|
+
require "SimControl/environments/base"
|
6
|
+
require "SimControl/environments/python"
|
7
|
+
|
8
|
+
module SimControl
|
9
|
+
def self.root
|
10
|
+
File.expand_path('../..',__FILE__)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
module SimControl
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
desc "init", "creates scaffolding for SimControl in this directory"
|
9
|
+
def init
|
10
|
+
base_dir = Dir.pwd
|
11
|
+
destination_root= base_dir
|
12
|
+
empty_directory "scenarios"
|
13
|
+
empty_directory "results"
|
14
|
+
copy_file "scaffolding/Controlfile", "Controlfile"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "newScenario SCENARIO", "creates a new scenario of name SCENARIO"
|
18
|
+
def newScenario(name)
|
19
|
+
SimControl::CLI.init_generated_files_exist?
|
20
|
+
|
21
|
+
copy_file "scenario/scenario.rb", File.join("scenarios", "#{ name }.rb")
|
22
|
+
empty_directory File.join("results", name)
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "simulate SCENARIO", "simulates a subsets of SCENARIO on the current HOSTNAME"
|
26
|
+
def simulate(scenario)
|
27
|
+
SimControl::CLI.init_generated_files_exist?
|
28
|
+
SimControl::CLI.scenario_files_exist?(scenario)
|
29
|
+
|
30
|
+
SimControl::Controller.execute(hostname,
|
31
|
+
simulation_description,
|
32
|
+
scenario_description(scenario),
|
33
|
+
results_directory(scenario))
|
34
|
+
end
|
35
|
+
|
36
|
+
no_commands {
|
37
|
+
def hostname
|
38
|
+
Socket.gethostname
|
39
|
+
end
|
40
|
+
|
41
|
+
def simulation_description
|
42
|
+
File.open(control_file_name).read
|
43
|
+
end
|
44
|
+
|
45
|
+
def scenario_description(scenario)
|
46
|
+
File.open(scenario_file_name(scenario)).read
|
47
|
+
end
|
48
|
+
|
49
|
+
def results_directory(scenario)
|
50
|
+
File.join("results", scenario)
|
51
|
+
end
|
52
|
+
|
53
|
+
def control_file_name
|
54
|
+
File.join(Dir.pwd, "Controlfile")
|
55
|
+
end
|
56
|
+
|
57
|
+
def scenario_file_name(scenario)
|
58
|
+
File.join(Dir.pwd, "scenarios", "#{ scenario }.rb")
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.scenario_files_exist?(scenario)
|
62
|
+
raise Thor::Error.new "#{ CLI::scenario_path(scenario) } missing, run newScenario # scenario }" unless File.exists?(CLI::scenario_path(scenario))
|
63
|
+
raise Thor::Error.new "#{ CLI::results_path(scenario) } missing, run newScenario # scenario }" unless File.directory?(CLI::results_path(scenario))
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.results_path(scenario_name)
|
67
|
+
results_path = File.join("results", scenario_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.scenario_path(scenario_name)
|
71
|
+
scenario_path = File.join("scenarios", "#{scenario_name}.rb")
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.init_generated_files_exist?
|
75
|
+
raise Thor::Error.new "scenarios missing, run init" unless File.directory?("scenarios")
|
76
|
+
raise Thor::Error.new "results missing, run init" unless File.directory?("results")
|
77
|
+
raise Thor::Error.new "Controlfile missing, run init" unless File.exists?("Controlfile")
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.source_root
|
81
|
+
File.join(SimControl.root, 'templates')
|
82
|
+
end
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SimControl
|
2
|
+
class Controller
|
3
|
+
attr_reader :current_simulation
|
4
|
+
|
5
|
+
def initialize(hostname, simulation_description, scenario_description, results_directory, args = {})
|
6
|
+
@hosts = args.delete(:hosts) || SimControl::Hosts.new
|
7
|
+
|
8
|
+
@hostname = hostname
|
9
|
+
@simulation_description = simulation_description
|
10
|
+
@scenario_description = scenario_description
|
11
|
+
@results_directory = results_directory
|
12
|
+
|
13
|
+
@scenarios = []
|
14
|
+
|
15
|
+
@meta_seed = 13
|
16
|
+
@max_seed = 2**(32 - 1) - 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
instance_eval(@simulation_description)
|
21
|
+
instance_eval(@scenario_description)
|
22
|
+
|
23
|
+
host_scenarios = @hosts.partition(all_scenarios, @hostname)
|
24
|
+
|
25
|
+
host_scenarios.each do |scenarios_per_core|
|
26
|
+
threads = []
|
27
|
+
scenarios_per_core.each do |scenario|
|
28
|
+
threads << Thread.new do
|
29
|
+
current_simulation.simulate(scenario, seeds)
|
30
|
+
end
|
31
|
+
|
32
|
+
threads.each do |thread|
|
33
|
+
thread.join
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def repetitions(number_of_repetitions)
|
40
|
+
@number_of_repetitions = number_of_repetitions
|
41
|
+
end
|
42
|
+
|
43
|
+
def hosts(&hosts_block)
|
44
|
+
@hosts.process &hosts_block
|
45
|
+
end
|
46
|
+
|
47
|
+
def simulation(klass, script, arguments)
|
48
|
+
@current_simulation = klass.new script, arguments
|
49
|
+
end
|
50
|
+
|
51
|
+
def seeds
|
52
|
+
@rng = Random.new(@meta_seed)
|
53
|
+
(1..@number_of_repetitions).map { @rng.rand(@max_seed) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def simulate(scenario)
|
57
|
+
@scenarios << scenario
|
58
|
+
end
|
59
|
+
|
60
|
+
def all_scenarios
|
61
|
+
@scenarios
|
62
|
+
end
|
63
|
+
|
64
|
+
class << self
|
65
|
+
def execute(hostname, simulation_description, scenario_description, results_directory)
|
66
|
+
controller = SimControl::Controller.new(hostname, simulation_description, scenario_description, results_directory)
|
67
|
+
controller.run
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SimControl
|
2
|
+
class PythonEnvironment < BaseEnvironment
|
3
|
+
def initialize(script, args = {})
|
4
|
+
@script = script
|
5
|
+
@interpreter = args.delete(:interpreter)
|
6
|
+
@virtualenv = args.delete(:virtualenv)
|
7
|
+
raise "passing a virtualenv requires an interpreter" if @virtualenv and not @interpreter
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(scenario)
|
11
|
+
args = scenario.map { |k, v| "--#{ k } #{ v }" }.join " "
|
12
|
+
command = [interpreter, @script, args].reject(&:nil?).reject(&:empty?).join " "
|
13
|
+
`#{ command }`
|
14
|
+
end
|
15
|
+
|
16
|
+
def interpreter
|
17
|
+
if @virtualenv
|
18
|
+
File.join(@virtualenv, "bin", @interpreter)
|
19
|
+
else
|
20
|
+
@interpreter
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "active_support/all"
|
2
|
+
|
3
|
+
class SimControl::Hosts
|
4
|
+
def initialize
|
5
|
+
@hosts = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def use(host, args = {})
|
9
|
+
args[:cores] = args[:cores] || 1
|
10
|
+
@hosts[host] = args
|
11
|
+
end
|
12
|
+
|
13
|
+
def number_of_cores
|
14
|
+
@hosts.map { |k, v| v[:cores] }.reduce(0, :+)
|
15
|
+
end
|
16
|
+
|
17
|
+
def partition(all_scenarios, hostname)
|
18
|
+
return [] if number_of_cores == 0
|
19
|
+
scenario_groups = all_scenarios.in_groups_of(number_of_cores, false)
|
20
|
+
scenario_groups[host_indices hostname]
|
21
|
+
end
|
22
|
+
|
23
|
+
def host_indices(hostname)
|
24
|
+
return 0..0 unless @hosts.include? hostname
|
25
|
+
start_index = 0
|
26
|
+
@hosts.each do |current_hostname, options|
|
27
|
+
cores = options[:cores]
|
28
|
+
return (start_index ... (start_index + cores)) if current_hostname == hostname
|
29
|
+
start_index += cores
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def process(&block)
|
34
|
+
instance_eval(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "SimControl"
|
4
|
+
|
5
|
+
require "fakefs/spec_helpers"
|
6
|
+
|
7
|
+
describe SimControl::CLI do
|
8
|
+
let(:cli) { SimControl::CLI.new }
|
9
|
+
|
10
|
+
include FakeFS::SpecHelpers
|
11
|
+
describe "#init creates the control structure" do
|
12
|
+
let(:controlfile) { "Content" }
|
13
|
+
before(:each) do
|
14
|
+
FileUtils.mkdir_p("templates/scaffolding")
|
15
|
+
File.open("templates/scaffolding/Controlfile", "w") { |f| f.write(controlfile) }
|
16
|
+
end
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
cli.invoke :init
|
20
|
+
end
|
21
|
+
|
22
|
+
it "creates the scenarios folder" do
|
23
|
+
expect(File.directory?("scenarios")).to be(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "creates the results folder" do
|
27
|
+
expect(File.directory?("results")).to be(true)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "creates the Controlfile with appropriate content" do
|
31
|
+
expect(File.open("Controlfile", "r").read).to eq(controlfile)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "SimControl"
|
4
|
+
|
5
|
+
require "fakefs/spec_helpers"
|
6
|
+
|
7
|
+
describe SimControl::CLI do
|
8
|
+
let(:cli) { SimControl::CLI.new }
|
9
|
+
|
10
|
+
include FakeFS::SpecHelpers
|
11
|
+
describe "#newScenario" do
|
12
|
+
describe "with scenario name" do
|
13
|
+
let(:scenario) { "scenario" }
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
FileUtils.mkdir("scenarios")
|
17
|
+
FileUtils.mkdir("results")
|
18
|
+
FileUtils.touch("Controlfile")
|
19
|
+
FileUtils.mkdir_p("templates/scenario")
|
20
|
+
File.open("templates/scenario/scenario.rb", "w") { |f| f.write(scenario) }
|
21
|
+
cli.invoke :newScenario, ["myScenario"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "creates scenarios/myScenario.rb" do
|
25
|
+
expect(File.open("scenarios/myScenario.rb", "r").read).to eq(scenario)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "creates results/myScenario/" do
|
29
|
+
expect(File.directory?("results/myScenario")).to be_true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "without scenario name" do
|
34
|
+
it "fails" do
|
35
|
+
expect do
|
36
|
+
cli.invoke :newScenario
|
37
|
+
end.to raise_error(Thor::InvocationError, /with no arguments/)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "without init having been run" do
|
42
|
+
it "fails if no scenarios folder exists" do
|
43
|
+
FileUtils.mkdir("results")
|
44
|
+
FileUtils.touch("Controlfile")
|
45
|
+
expect do
|
46
|
+
cli.invoke :newScenario, ["myScenario"]
|
47
|
+
end.to raise_error(Thor::Error, /scenarios missing/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "fails if no results folder exists" do
|
51
|
+
FileUtils.mkdir("scenarios")
|
52
|
+
FileUtils.touch("Controlfile")
|
53
|
+
expect do
|
54
|
+
cli.invoke :newScenario, ["myScenario"]
|
55
|
+
end.to raise_error(Thor::Error, /results missing/)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "fails if no Controlfile exists" do
|
59
|
+
FileUtils.mkdir("scenarios")
|
60
|
+
FileUtils.mkdir("results")
|
61
|
+
expect do
|
62
|
+
cli.invoke :newScenario, ["myScenario"]
|
63
|
+
end.to raise_error(Thor::Error, /Controlfile missing/)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "simcontrol"
|
3
|
+
|
4
|
+
require "fakefs/spec_helpers"
|
5
|
+
|
6
|
+
describe SimControl::CLI do
|
7
|
+
include FakeFS::SpecHelpers
|
8
|
+
describe "simulate" do
|
9
|
+
before(:each) do
|
10
|
+
scenario = "hosts {}"
|
11
|
+
FileUtils.mkdir("scenarios")
|
12
|
+
FileUtils.mkdir("results")
|
13
|
+
FileUtils.touch("Controlfile")
|
14
|
+
FileUtils.touch("scenarios/myScenario.rb")
|
15
|
+
FileUtils.mkdir_p("results/myScenario")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "calls SimControl::Controller.execute()" do
|
19
|
+
scenario_description = "scenario"
|
20
|
+
simulation_description = "simulation"
|
21
|
+
results_path = File.join("results", "myScenario")
|
22
|
+
hostname = "a-hostname"
|
23
|
+
File.open("scenarios/myScenario.rb", "w") { |f| f.write(scenario_description) }
|
24
|
+
File.open("Controlfile", "w") { |f| f.write(simulation_description) }
|
25
|
+
Socket.stub(:gethostname).and_return { hostname }
|
26
|
+
SimControl::Controller.should_receive(:execute).with(hostname, simulation_description, scenario_description, results_path)
|
27
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "fails if no results directory exists" do
|
31
|
+
FileUtils.rm_rf("results")
|
32
|
+
expect do
|
33
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
34
|
+
end.to raise_error(Thor::Error, /results missing/)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "fails if no results directory exists for the scenario" do
|
38
|
+
FileUtils.rm_rf("results/myScenario")
|
39
|
+
expect do
|
40
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
41
|
+
end.to raise_error(Thor::Error, /results\/myScenario missing/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "fails if no scenarios directory exists" do
|
45
|
+
FileUtils.rm_rf("scenarios")
|
46
|
+
expect do
|
47
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
48
|
+
end.to raise_error(Thor::Error, /scenarios missing/)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "fails if the scenario description does not exist" do
|
52
|
+
FileUtils.rm("scenarios/myScenario.rb")
|
53
|
+
expect do
|
54
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
55
|
+
end.to raise_error(Thor::Error, /scenarios\/myScenario.rb missing/)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "fails if the Controlfile does not exist" do
|
59
|
+
FileUtils.rm("Controlfile")
|
60
|
+
expect do
|
61
|
+
SimControl::CLI.new.invoke :simulate, ["myScenario"]
|
62
|
+
end.to raise_error(Thor::Error, /Controlfile missing/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SimControl::Controller do
|
4
|
+
describe "#execute" do
|
5
|
+
it "creates a new controller instance and runs it with the called arguments" do
|
6
|
+
hostname = "a-hostname"
|
7
|
+
simulation_description = double("simulation_description")
|
8
|
+
scenario_description = double("scenario_description")
|
9
|
+
results_directory = double("results_directory")
|
10
|
+
instance = double(SimControl::Controller)
|
11
|
+
SimControl::Controller.should_receive(:new).with(hostname, simulation_description, scenario_description, results_directory).and_return(instance)
|
12
|
+
instance.should_receive(:run)
|
13
|
+
SimControl::Controller.execute(hostname, simulation_description, scenario_description, results_directory)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "calls methods called from the simulation description on the controller instance" do
|
17
|
+
simulation_description = <<Controlfile
|
18
|
+
hosts
|
19
|
+
Controlfile
|
20
|
+
instance = SimControl::Controller.new("", simulation_description, "", "")
|
21
|
+
instance.should_receive(:hosts)
|
22
|
+
instance.run
|
23
|
+
end
|
24
|
+
|
25
|
+
it "calls methods called from the scenario description on the controller instance" do
|
26
|
+
scenario_description = <<scenario
|
27
|
+
simulate
|
28
|
+
scenario
|
29
|
+
instance = SimControl::Controller.new("", "", scenario_description, "")
|
30
|
+
instance.should_receive(:simulate)
|
31
|
+
instance.run
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#hosts" do
|
36
|
+
it "yields the given block" do
|
37
|
+
proc = Proc.new do
|
38
|
+
|
39
|
+
end
|
40
|
+
hosts = double("Hosts")
|
41
|
+
hosts.should_receive(:process).with(&proc)
|
42
|
+
instance = SimControl::Controller.new("", "", "", "", hosts: hosts)
|
43
|
+
instance.hosts &proc
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#repetitions" do
|
48
|
+
it "allows to specify the number of repetitions" do
|
49
|
+
instance = SimControl::Controller.new("", "", "", "")
|
50
|
+
instance.repetitions 10
|
51
|
+
expect(instance.seeds.length).to eq(10)
|
52
|
+
instance.run
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#simulation" do
|
57
|
+
let(:klass) { double("Klass") }
|
58
|
+
it "creates a new instance of the given class and passes the hash" do
|
59
|
+
script = "a-script"
|
60
|
+
hash = double("Hash")
|
61
|
+
instance = SimControl::Controller.new("", "", "", "")
|
62
|
+
klass.should_receive(:new).with(script, hash)
|
63
|
+
instance.simulation klass, script, hash
|
64
|
+
end
|
65
|
+
|
66
|
+
it "allows for the instance to be obtained as #current_simulation" do
|
67
|
+
simulation_instance = double("simulation_instance")
|
68
|
+
instance = SimControl::Controller.new("", "", "", "")
|
69
|
+
klass.stub(:new) { simulation_instance }
|
70
|
+
instance.simulation klass, "script", {}
|
71
|
+
expect(instance.current_simulation).to be(simulation_instance)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#scenario" do
|
76
|
+
it "stores all provided scenarios in all_scenarios" do
|
77
|
+
scenario_a = {foo: 1}
|
78
|
+
scenario_b = {foo: 2}
|
79
|
+
instance = SimControl::Controller.new("", "", "", "")
|
80
|
+
instance.simulate scenario_a
|
81
|
+
instance.simulate scenario_b
|
82
|
+
expect(instance.all_scenarios).to include(scenario_a)
|
83
|
+
expect(instance.all_scenarios).to include(scenario_b)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#run" do
|
88
|
+
let(:hostname) { "a-hostname" }
|
89
|
+
let(:scenario_a) { {setting: "a-value"} }
|
90
|
+
let(:scenario_b) { {setting: "another-value"} }
|
91
|
+
let(:seeds) { [1, 2] }
|
92
|
+
let(:simulation_instance) { double("simulation_instance") }
|
93
|
+
let(:hosts) { double("Hosts") }
|
94
|
+
subject { SimControl::Controller.new(hostname, "", "", "", hosts: hosts).tap do |c|
|
95
|
+
c.stub(:seeds).and_return(seeds)
|
96
|
+
c.stub(:current_simulation).and_return(simulation_instance)
|
97
|
+
end
|
98
|
+
}
|
99
|
+
|
100
|
+
it "calls execute on the simulation instance for each parameter combination for the given host" do
|
101
|
+
per_host_scenarios = [[scenario_a, scenario_b]]
|
102
|
+
|
103
|
+
hosts.should_receive(:partition).with(anything(), hostname).and_return(per_host_scenarios)
|
104
|
+
simulation_instance.should_receive(:simulate).ordered.with(scenario_a, seeds)
|
105
|
+
simulation_instance.should_receive(:simulate).ordered.with(scenario_b, seeds)
|
106
|
+
|
107
|
+
subject.run
|
108
|
+
end
|
109
|
+
|
110
|
+
it "passes all_scenarios to partition" do
|
111
|
+
scenarios = [scenario_a, scenario_b]
|
112
|
+
|
113
|
+
subject.should_receive(:all_scenarios).and_return(scenarios)
|
114
|
+
hosts.should_receive(:partition).with(scenarios, anything()).and_return([scenarios])
|
115
|
+
simulation_instance.stub(:simulate)
|
116
|
+
|
117
|
+
subject.run
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
it "spawns multiple threads if the hosts support it" do
|
122
|
+
per_host_scenarios = [[scenario_a], [ scenario_b]]
|
123
|
+
|
124
|
+
hosts.should_receive(:partition).with(anything(), hostname).and_return(per_host_scenarios)
|
125
|
+
thread = double("Thread")
|
126
|
+
Thread.should_receive(:new).twice.and_return(thread)
|
127
|
+
thread.should_receive(:join).twice
|
128
|
+
|
129
|
+
subject.run
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SimControl::BaseEnvironment do
|
4
|
+
describe "#simulate" do
|
5
|
+
it "calls #execute for each seed" do
|
6
|
+
subject.should_receive(:execute).twice
|
7
|
+
subject.simulate({}, [1, 2])
|
8
|
+
end
|
9
|
+
|
10
|
+
it "injects the seed in the arguments hash" do
|
11
|
+
subject.should_receive(:execute) do |args|
|
12
|
+
expect(args[:seed]).to eq(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
subject.should_receive(:execute) do |args|
|
16
|
+
expect(args[:seed]).to eq(2)
|
17
|
+
end
|
18
|
+
|
19
|
+
subject.simulate({}, [1, 2])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "keeps the arguments hash" do
|
23
|
+
subject.should_receive(:execute) do |args|
|
24
|
+
expect(args[:foo]).to eq("bar")
|
25
|
+
end
|
26
|
+
|
27
|
+
subject.simulate({foo: "bar"}, [1])
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SimControl::PythonEnvironment do
|
4
|
+
let(:script) { "a-script" }
|
5
|
+
describe "#simulate" do
|
6
|
+
it "calls the script if nothing is passed in args" do
|
7
|
+
simulation = SimControl::PythonEnvironment.new script
|
8
|
+
simulation.should_receive(:`).with(script)
|
9
|
+
simulation.execute({})
|
10
|
+
end
|
11
|
+
|
12
|
+
it "passes args to the script in -- syntax" do
|
13
|
+
simulation = SimControl::PythonEnvironment.new script
|
14
|
+
simulation.should_receive(:`).with("#{ script } --foo bar --baz 1")
|
15
|
+
simulation.execute({foo: "bar", baz: 1})
|
16
|
+
end
|
17
|
+
|
18
|
+
it "uses a given interpreter" do
|
19
|
+
simulation = SimControl::PythonEnvironment.new script, interpreter: "pypy"
|
20
|
+
simulation.should_receive(:`).with("pypy #{ script }")
|
21
|
+
simulation.execute({})
|
22
|
+
end
|
23
|
+
|
24
|
+
it "uses a given virtualenv and interpreter" do
|
25
|
+
simulation = SimControl::PythonEnvironment.new script, virtualenv: "foo/bar", interpreter: "pypy"
|
26
|
+
simulation.should_receive(:`).with("foo/bar/bin/pypy #{ script }")
|
27
|
+
simulation.execute({})
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raised an exception is a virtualenv is passed but no interpreter" do
|
31
|
+
expect do
|
32
|
+
SimControl::PythonEnvironment.new script, virtualenv: "foo/bar"
|
33
|
+
end.to raise_error /passing a virtualenv requires an interpreter/
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/spec/hosts_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SimControl::Hosts do
|
4
|
+
it "applies use directives in process" do
|
5
|
+
hosts = SimControl::Hosts.new
|
6
|
+
hosts.should_receive(:use).with("host-a")
|
7
|
+
hosts.process do
|
8
|
+
use "host-a"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#number_of_cores" do
|
13
|
+
it "provides the total number of cores" do
|
14
|
+
hosts = SimControl::Hosts.new
|
15
|
+
hosts.use "host-a"
|
16
|
+
hosts.use "host-b", cores: 2
|
17
|
+
expect(hosts.number_of_cores).to eq(3)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns 0 if no hosts exist" do
|
21
|
+
hosts = SimControl::Hosts.new
|
22
|
+
expect(hosts.number_of_cores).to eq(0)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "splits scenarios evenly if all hosts have 1 core" do
|
27
|
+
hosts = SimControl::Hosts.new
|
28
|
+
hosts.use "host-a"
|
29
|
+
hosts.use "host-b"
|
30
|
+
scenario_a = {foo: 1}
|
31
|
+
scenario_b = {foo: 2}
|
32
|
+
scenario_c = {foo: 3}
|
33
|
+
scenario_d = {foo: 4}
|
34
|
+
all_scenarios = [scenario_a, scenario_b, scenario_c, scenario_d]
|
35
|
+
host_a_scenarios = hosts.partition all_scenarios, "host-a"
|
36
|
+
expect(host_a_scenarios.first).to include(scenario_a)
|
37
|
+
expect(host_a_scenarios.first).to include(scenario_b)
|
38
|
+
host_b_scenarios = hosts.partition all_scenarios, "host-b"
|
39
|
+
expect(host_b_scenarios.first).to include(scenario_c)
|
40
|
+
expect(host_b_scenarios.first).to include(scenario_d)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns the empty list if no hosts exist" do
|
44
|
+
hosts = SimControl::Hosts.new
|
45
|
+
scenario_a = {foo: 1}
|
46
|
+
expect(hosts.partition [scenario_a], "a-host").to eq([])
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
describe "#host_indices" do
|
51
|
+
it "returns the indices of scenarios to use" do
|
52
|
+
hosts = SimControl::Hosts.new
|
53
|
+
hosts.use "host-a", cores: 2
|
54
|
+
hosts.use "host-b", cores: 3
|
55
|
+
hosts.use "host-c", cores: 2
|
56
|
+
hosts.use "host-d", cores: 4
|
57
|
+
hosts_range = hosts.host_indices "host-c"
|
58
|
+
expect(hosts_range).to include 5
|
59
|
+
expect(hosts_range).to include 6
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns the empty array if the host is not found" do
|
63
|
+
hosts = SimControl::Hosts.new
|
64
|
+
expect(hosts.host_indices "host").to eq(0..0)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
14
|
+
# the seed, which is printed after each run.
|
15
|
+
# --seed 1234
|
16
|
+
config.order = 'random'
|
17
|
+
|
18
|
+
config.before do
|
19
|
+
#remove this as soon as FakeFS is released > 0.4.2
|
20
|
+
class ::FakeFS::File
|
21
|
+
def self.binread(file)
|
22
|
+
File.open(file, 'rb') { |f| f.read }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#shamelessly copied from thor's spec
|
28
|
+
def capture(stream)
|
29
|
+
begin
|
30
|
+
stream = stream.to_s
|
31
|
+
eval "$#{stream} = StringIO.new"
|
32
|
+
yield
|
33
|
+
result = eval("$#{stream}").string
|
34
|
+
ensure
|
35
|
+
eval("$#{stream} = #{stream.upcase}")
|
36
|
+
end
|
37
|
+
|
38
|
+
result
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
hosts do
|
2
|
+
#A host with name "hostname"
|
3
|
+
use "hostname"
|
4
|
+
|
5
|
+
#Another host, with 3 cores to be used for simulation
|
6
|
+
use "another-hostname", cores: 3
|
7
|
+
end
|
8
|
+
|
9
|
+
#currently only a python environment is implemented
|
10
|
+
simulation PythonEnvironment, "/path/to/simulation.py",
|
11
|
+
#use a virtualenv, not the global python
|
12
|
+
virtualenv: "/path/to/virtualenv",
|
13
|
+
#do not use the default system python but pypy
|
14
|
+
interpreter: "pypy"
|
metadata
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: SimControl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christian Schwartz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: active_support
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: i18n
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bundler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.3'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.3'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: pry
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: fakefs
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: A DSL for simpy based simulations on multiple hosts
|
143
|
+
email:
|
144
|
+
- christian.schwartz@gmail.com
|
145
|
+
executables:
|
146
|
+
- simcontrol
|
147
|
+
extensions: []
|
148
|
+
extra_rdoc_files: []
|
149
|
+
files:
|
150
|
+
- .gitignore
|
151
|
+
- .rspec
|
152
|
+
- Gemfile
|
153
|
+
- Gemfile.lock
|
154
|
+
- LICENSE
|
155
|
+
- LICENSE.txt
|
156
|
+
- README.md
|
157
|
+
- Rakefile
|
158
|
+
- SimControl.gemspec
|
159
|
+
- bin/simcontrol
|
160
|
+
- lib/SimControl.rb
|
161
|
+
- lib/SimControl/cli.rb
|
162
|
+
- lib/SimControl/controller.rb
|
163
|
+
- lib/SimControl/environments/base.rb
|
164
|
+
- lib/SimControl/environments/python.rb
|
165
|
+
- lib/SimControl/hosts.rb
|
166
|
+
- lib/SimControl/version.rb
|
167
|
+
- spec/acceptance/init_spec.rb
|
168
|
+
- spec/acceptance/scenario_spec.rb
|
169
|
+
- spec/cli/simulate_spec.rb
|
170
|
+
- spec/controller_spec.rb
|
171
|
+
- spec/environments/base_environment_spec.rb
|
172
|
+
- spec/environments/python_environment_spec.rb
|
173
|
+
- spec/hosts_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
- templates/scaffolding/Controlfile
|
176
|
+
- templates/scenario/scenario.rb
|
177
|
+
homepage: https://github.com/cschwartz/SimControl
|
178
|
+
licenses:
|
179
|
+
- MIT
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
+
none: false
|
192
|
+
requirements:
|
193
|
+
- - ! '>='
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
requirements: []
|
197
|
+
rubyforge_project:
|
198
|
+
rubygems_version: 1.8.23
|
199
|
+
signing_key:
|
200
|
+
specification_version: 3
|
201
|
+
summary: A DSL for simpy based simulations on multiple hosts
|
202
|
+
test_files:
|
203
|
+
- spec/acceptance/init_spec.rb
|
204
|
+
- spec/acceptance/scenario_spec.rb
|
205
|
+
- spec/cli/simulate_spec.rb
|
206
|
+
- spec/controller_spec.rb
|
207
|
+
- spec/environments/base_environment_spec.rb
|
208
|
+
- spec/environments/python_environment_spec.rb
|
209
|
+
- spec/hosts_spec.rb
|
210
|
+
- spec/spec_helper.rb
|