nutella_framework 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/README.md +3 -4
- data/VERSION +1 -1
- data/data/startup +3 -3
- data/framework_components/example_framework_interface/dandelion-flowers-card.jpg +0 -0
- data/framework_components/example_framework_interface/index.html +18 -0
- data/framework_components/main_interface/main_interface_bot.rb +183 -0
- data/framework_components/main_interface/public/index.html +54 -0
- data/framework_components/main_interface/views/index.erb +63 -0
- data/framework_components/order.json.example +6 -0
- data/framework_components/runs_list_bot/app_runs_list_bot.rb +15 -0
- data/lib/{core/commands → commands}/broker.rb +2 -2
- data/lib/{core/commands → commands}/checkup.rb +2 -2
- data/lib/commands/compile.rb +13 -0
- data/lib/commands/dependencies.rb +13 -0
- data/lib/commands/help.rb +35 -0
- data/lib/{core/commands → commands}/install.rb +19 -15
- data/lib/commands/meta/command.rb +19 -0
- data/lib/commands/meta/run_command.rb +114 -0
- data/lib/{core → commands/meta}/template_command.rb +1 -1
- data/lib/commands/new.rb +60 -0
- data/lib/commands/runs.rb +54 -0
- data/lib/commands/start.rb +321 -0
- data/lib/commands/stop.rb +101 -0
- data/lib/{core/commands → commands}/template.rb +59 -39
- data/lib/config/current_app_utils.rb +51 -0
- data/lib/config/persisted_hash.rb +14 -12
- data/lib/config/runlist.rb +116 -16
- data/lib/{cli → core}/nutella_cli.rb +1 -1
- data/lib/core/nutella_core.rb +2 -6
- data/lib/nutella_framework.rb +5 -3
- data/lib/nutella_lib_framework/api.rb +333 -0
- data/lib/tmux/tmux.rb +76 -0
- data/nutella_framework.gemspec +42 -29
- data/test/commands/test_cmd_cli_params_parsing.rb +56 -0
- data/test/commands/test_command_template.rb +31 -0
- data/test/config/test_current_app_utils.rb +34 -0
- data/test/config/test_persisted_hash.rb +48 -0
- data/test/config/test_runlist.rb +15 -23
- data/test/framework_apis/test_framework_api.rb +74 -0
- metadata +74 -27
- data/actors/main_interface/main_interface_bot.rb +0 -163
- data/actors/main_interface/public/index.html +0 -51
- data/actors/main_interface/views/index.erb +0 -45
- data/lib/config/current_project.rb +0 -58
- data/lib/core/command.rb +0 -12
- data/lib/core/commands/compile.rb +0 -21
- data/lib/core/commands/dependencies.rb +0 -21
- data/lib/core/commands/help.rb +0 -28
- data/lib/core/commands/new.rb +0 -60
- data/lib/core/commands/runs.rb +0 -52
- data/lib/core/commands/start.rb +0 -271
- data/lib/core/commands/stop.rb +0 -100
- data/lib/core/run_command.rb +0 -106
- data/lib/core/tmux.rb +0 -38
- data/test/config/test_config.rb +0 -48
- data/test/config/test_project.rb +0 -34
- data/test/test_run_command.rb +0 -54
- /data/{actors → framework_components}/main_interface/startup +0 -0
- /data/{actors → framework_components}/main_interface/views/not_found_404.erb +0 -0
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'core/run_command'
|
2
|
-
require 'core/tmux'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class Compile < RunCommand
|
6
|
-
@description = 'Compiles all the actors that need compilation in the project'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
|
10
|
-
# If the current directory is not a nutella project, return
|
11
|
-
return unless Nutella.current_project.exist?
|
12
|
-
|
13
|
-
# Compile all actors
|
14
|
-
return unless prepare_bot( Nutella.current_project.dir, 'compile', 'Compiling' )
|
15
|
-
|
16
|
-
# Output success message
|
17
|
-
console.success "All actors compiled for #{Nutella.current_project.config['name']}"
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'core/run_command'
|
2
|
-
require 'core/tmux'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class Dependencies < RunCommand
|
6
|
-
@description = 'Installs the dependencies for all actors in the project'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
|
10
|
-
# If the current directory is not a nutella project, return
|
11
|
-
return unless Nutella.current_project.exist?
|
12
|
-
|
13
|
-
# Install all dependencies
|
14
|
-
return unless prepare_bot( Nutella.current_project.dir, 'dependencies', 'Installing dependencies for' )
|
15
|
-
|
16
|
-
# Output success message
|
17
|
-
console.success "All dependencies installed for #{Nutella.current_project.config['name']}"
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
data/lib/core/commands/help.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'core/command'
|
2
|
-
|
3
|
-
module Nutella
|
4
|
-
|
5
|
-
class Help < Command
|
6
|
-
@description = 'Displays what every command does and how to use it'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
message=''
|
10
|
-
Dir["#{File.dirname(__FILE__)}/*.rb"].each do |file|
|
11
|
-
command = File.basename(file, File.extname(file))
|
12
|
-
if command.length > 7
|
13
|
-
message += "#{command}\t"
|
14
|
-
else
|
15
|
-
message += "#{command}\t\t"
|
16
|
-
end
|
17
|
-
message += Object::const_get("Nutella::#{command.capitalize}").description
|
18
|
-
message += "\n"
|
19
|
-
end
|
20
|
-
console.info message
|
21
|
-
console.info 'For more details on individual commands, see https://github.com/nutella-framework/nutella_framework/wiki/Nutella-Command-Line-Interface'
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
|
data/lib/core/commands/new.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'core/command'
|
2
|
-
require 'fileutils'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class New < Command
|
6
|
-
@description = 'Creates a new project'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
cur_prj_dir = args[0]
|
10
|
-
|
11
|
-
# If no other arguments, show help and quit here
|
12
|
-
if args.empty?
|
13
|
-
console.warn 'You need to specify a name for your new project'
|
14
|
-
return
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check that a directory (i.e. project) with the same name doesn't already exist
|
18
|
-
# If it does it looks into it to see if there is a nutella.json file and displays
|
19
|
-
# the proper error message
|
20
|
-
if File.directory? cur_prj_dir
|
21
|
-
if File.exist? "#{cur_prj_dir}/nutella.json"
|
22
|
-
console.warn "A project named #{cur_prj_dir} already exists"
|
23
|
-
return
|
24
|
-
else
|
25
|
-
console.warn "A directory named #{cur_prj_dir} already exists"
|
26
|
-
return
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# If all seems good, generate the project structure
|
31
|
-
create_dir_structure cur_prj_dir
|
32
|
-
|
33
|
-
# Display a nice success message and return
|
34
|
-
console.success "Your new project #{cur_prj_dir} is ready!"
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
|
41
|
-
def create_dir_structure( cur_prj_dir )
|
42
|
-
# Create directories
|
43
|
-
FileUtils.mkdir_p("#{cur_prj_dir}/bots")
|
44
|
-
FileUtils.mkdir_p("#{cur_prj_dir}/interfaces")
|
45
|
-
# Create nutella.json hash
|
46
|
-
config_file_hash = {
|
47
|
-
:name => cur_prj_dir,
|
48
|
-
:version => '0.1.0',
|
49
|
-
:nutella_version => File.open("#{Nutella.config['nutella_home']}VERSION", 'rb').read,
|
50
|
-
:type => 'project',
|
51
|
-
:description => 'A quick description of your project'
|
52
|
-
}
|
53
|
-
# Write nutella.json hash
|
54
|
-
File.open("#{cur_prj_dir}/nutella.json", 'w') do |f|
|
55
|
-
f.write(JSON.pretty_generate(config_file_hash))
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
data/lib/core/commands/runs.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'core/command'
|
2
|
-
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class Runs < Command
|
6
|
-
@description = 'Displays list of runs for current project or all projects'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
|
10
|
-
# If invoked with "all" it will show all the runs under this instance of nutella
|
11
|
-
if args[0]=='--all' || args[0]=='-a'
|
12
|
-
display_all_runs
|
13
|
-
else
|
14
|
-
# If current dir is not a nutella project, return
|
15
|
-
return unless Nutella.current_project.exist?
|
16
|
-
# Display list of runs for current nutella project
|
17
|
-
display_project_runs
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
|
25
|
-
def display_all_runs
|
26
|
-
if Nutella.runlist.empty?
|
27
|
-
console.info 'You are not running any projects'
|
28
|
-
else
|
29
|
-
console.info 'Currently running:'
|
30
|
-
Nutella.runlist.runs_by_project.each { |run| console.info " #{run}" }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def display_project_runs
|
35
|
-
project_name = Nutella.current_project.config['name']
|
36
|
-
runs = Nutella.runlist.runs_by_project project_name
|
37
|
-
console.info "Currently running #{runs.length} instances of project #{project_name}:"
|
38
|
-
runs.each do |run|
|
39
|
-
run_id = run.dup
|
40
|
-
run_id.slice! "#{project_name}_"
|
41
|
-
if run==project_name
|
42
|
-
console.info " #{project_name} (default instance)"
|
43
|
-
else
|
44
|
-
console.info " #{run_id}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
data/lib/core/commands/start.rb
DELETED
@@ -1,271 +0,0 @@
|
|
1
|
-
require 'core/run_command'
|
2
|
-
require 'core/tmux'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class Start < RunCommand
|
6
|
-
@description = 'Starts all or some of the bots in the current project'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
|
10
|
-
# If the current directory is not a nutella project, return
|
11
|
-
return unless Nutella.current_project.exist?
|
12
|
-
|
13
|
-
# Extract run (passed run name) and run_id
|
14
|
-
run, run_id = extract_names args
|
15
|
-
|
16
|
-
# Check that the run name is different than the project name
|
17
|
-
if run==Nutella.current_project.config['name']
|
18
|
-
console.warn 'Your run name should be different than your project name'
|
19
|
-
return
|
20
|
-
end
|
21
|
-
|
22
|
-
# Extract parameters
|
23
|
-
begin
|
24
|
-
params = extract_parameters args
|
25
|
-
rescue
|
26
|
-
console.warn 'The only supported parameters are --with (-w) and --without (-wo)'
|
27
|
-
return
|
28
|
-
end
|
29
|
-
|
30
|
-
# Check that we are not using 'with' and 'without' options at the same time
|
31
|
-
unless params[:with].empty? || params[:without].empty?
|
32
|
-
console.warn 'You can\'t use both --with and --without at the same time'
|
33
|
-
return
|
34
|
-
end
|
35
|
-
|
36
|
-
# Extract project directory
|
37
|
-
cur_prj_dir = Nutella.current_project.dir
|
38
|
-
|
39
|
-
# Check that there is at least a regular bot that will be started,
|
40
|
-
# otherwise it makes no sense to create a run
|
41
|
-
if bots_list_wo_project(cur_prj_dir, params).empty? && project_bots_started?
|
42
|
-
console.warn "Run #{run} not created: your project bots are already started and you specified no regular bots exclusively for this run"
|
43
|
-
return
|
44
|
-
end
|
45
|
-
|
46
|
-
# Check that the run_id is unique and add it to the list of runs
|
47
|
-
# If it's not, return (without adding the run_id to the list of course)
|
48
|
-
return unless add_to_run_list( run_id, cur_prj_dir )
|
49
|
-
|
50
|
-
# If running on the internal broker, start it if needed
|
51
|
-
if running_on_internal_broker?
|
52
|
-
return unless start_internal_broker
|
53
|
-
end
|
54
|
-
|
55
|
-
# Start all nutella internal actors, if needed
|
56
|
-
return unless start_nutella_actors
|
57
|
-
|
58
|
-
# Start all project level actors, if any
|
59
|
-
return unless start_project_bots cur_prj_dir
|
60
|
-
|
61
|
-
# Start all bots
|
62
|
-
return unless start_bots( cur_prj_dir, run_id, params )
|
63
|
-
|
64
|
-
# Output success message
|
65
|
-
output_success_message( run_id, run, 'started' )
|
66
|
-
output_monitoring_details( run_id, cur_prj_dir, params)
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
|
73
|
-
def bots_list_wo_project( cur_prj_dir, params )
|
74
|
-
# Fetch the list of project bots
|
75
|
-
project_bots_list = Nutella.current_project.config['project_bots']
|
76
|
-
run_bots_list = run_actors_list("#{cur_prj_dir}/bots/")
|
77
|
-
# Depending on the mode we are in we want to start only some bots, exclude only some bots, start all bots
|
78
|
-
unless params[:with].empty?
|
79
|
-
return project_bots_list.nil? ? params[:with] : params[:with] - project_bots_list
|
80
|
-
end
|
81
|
-
unless params[:without].empty?
|
82
|
-
return project_bots_list.nil? ? run_bots_list - params[:without] : run_bots_list - params[:without] - project_bots_list
|
83
|
-
end
|
84
|
-
if params[:with].empty? && params[:without].empty?
|
85
|
-
return project_bots_list.nil? ? run_bots_list : run_bots_list - project_bots_list
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
|
-
def project_bots_started?
|
91
|
-
project_name = Nutella.current_project.config['name']
|
92
|
-
tmux_session_name = "#{project_name}-project-bots"
|
93
|
-
Tmux.session_exist? tmux_session_name
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
def add_to_run_list(run_id, prj_dir)
|
98
|
-
unless Nutella.runlist.add?( run_id, prj_dir )
|
99
|
-
# If the run_id is already in the list, check that it's actually live
|
100
|
-
if Tmux.session_exist? run_id
|
101
|
-
console.error 'Impossible to start project: an instance of this project with the same run_id is already running!'
|
102
|
-
console.error "You might want to kill it with 'nutella stop #{run_id}'"
|
103
|
-
return false
|
104
|
-
end
|
105
|
-
end
|
106
|
-
true
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
def start_internal_broker
|
111
|
-
pid_file_path = "#{Nutella.config['broker_dir']}bin/.pid"
|
112
|
-
return true if sanitize_pid_file pid_file_path
|
113
|
-
# Check that broker is not running unsupervised (check port)
|
114
|
-
unless broker_port_free?
|
115
|
-
console.error 'Impossible to start project: looks like a broker is already running on port 1883. Stop it before trying to start the project again'
|
116
|
-
return false
|
117
|
-
end
|
118
|
-
# Broker is not running and there is no file so we try to start
|
119
|
-
# and create a new pid file. Note that the pid file is created by
|
120
|
-
# the startup script!
|
121
|
-
pid = fork
|
122
|
-
exec("#{Nutella.config['broker_dir']}/startup") if pid.nil?
|
123
|
-
# Sleep a bit to give the chance to the broker to actually start up
|
124
|
-
sleep(1)
|
125
|
-
# All went well so we return true
|
126
|
-
true
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
# Cleans the pid file of a given process
|
131
|
-
# @param [String] pid_file_path the file storing the pid file of the process
|
132
|
-
# @return [Boolean] true if the pid file exists AND the process with that pid is still alive
|
133
|
-
def sanitize_pid_file( pid_file_path )
|
134
|
-
# Does the pid file exist?
|
135
|
-
# If it does we try to see if the process with that pid is still alive
|
136
|
-
if File.exist? pid_file_path
|
137
|
-
pid_file = File.open(pid_file_path, 'rb')
|
138
|
-
pid = pid_file.read.to_i
|
139
|
-
pid_file.close
|
140
|
-
begin
|
141
|
-
# If this statement doesn't throw an exception then a process with
|
142
|
-
# this pid is still alive so we do nothing and just return true
|
143
|
-
Process.getpgid pid
|
144
|
-
return true
|
145
|
-
rescue
|
146
|
-
# If there is an exception, there is no process with this pid
|
147
|
-
# so we have a stale pid file that we need to remove
|
148
|
-
File.delete pid_file_path
|
149
|
-
return false
|
150
|
-
end
|
151
|
-
end
|
152
|
-
# If there is no pid file, there is no process running
|
153
|
-
false
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
# Checks if port 1883 (MQTT broker port) is free
|
158
|
-
# or some other service is already listening on it
|
159
|
-
def broker_port_free?
|
160
|
-
begin
|
161
|
-
s = TCPServer.new('0.0.0.0', 1883)
|
162
|
-
s.close
|
163
|
-
rescue
|
164
|
-
return false
|
165
|
-
end
|
166
|
-
true
|
167
|
-
end
|
168
|
-
|
169
|
-
|
170
|
-
def start_nutella_actors
|
171
|
-
nutella_actors_dir = "#{Nutella.config['nutella_home']}actors"
|
172
|
-
for_each_actor_in_dir nutella_actors_dir do |actor|
|
173
|
-
if File.exist? "#{nutella_actors_dir}/#{actor}/startup"
|
174
|
-
unless start_nutella_actor "#{nutella_actors_dir}/#{actor}"
|
175
|
-
return false
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
true
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
def start_nutella_actor( actor_dir )
|
184
|
-
pid_file_path = "#{actor_dir}/.pid"
|
185
|
-
return true if sanitize_pid_file pid_file_path
|
186
|
-
# Actor is not running and there is no pid file so we try to start
|
187
|
-
# the actor and create a new pid file. Note that the pid file is created by
|
188
|
-
# the startup script!
|
189
|
-
nutella_config_file = "#{Nutella.config['config_dir']}config.json"
|
190
|
-
runs_list_file = "#{Nutella.config['config_dir']}runlist.json"
|
191
|
-
if nutella_config_file==nil || runs_list_file==nil
|
192
|
-
return false
|
193
|
-
end
|
194
|
-
command = "#{actor_dir}/startup #{nutella_config_file} #{runs_list_file}"
|
195
|
-
pid = fork
|
196
|
-
exec(command) if pid.nil?
|
197
|
-
# All went well so we return true
|
198
|
-
true
|
199
|
-
end
|
200
|
-
|
201
|
-
|
202
|
-
def start_project_bots( cur_prj_dir )
|
203
|
-
project_bots_list = Nutella.current_project.config['project_bots']
|
204
|
-
project_name = Nutella.current_project.config['name']
|
205
|
-
tmux_session_name = "#{project_name}-project-bots"
|
206
|
-
bots_dir = "#{cur_prj_dir}/bots/"
|
207
|
-
# If project bots have been started already, then do nothing
|
208
|
-
unless Tmux.session_exist? tmux_session_name
|
209
|
-
# Start all project bots in the list into a new tmux session
|
210
|
-
tmux = Tmux.new tmux_session_name
|
211
|
-
for_each_actor_in_dir bots_dir do |bot|
|
212
|
-
unless project_bots_list.nil? || !project_bots_list.include?( bot )
|
213
|
-
# If there is no 'startup' script output a warning (because
|
214
|
-
# startup is mandatory) and skip the bot
|
215
|
-
unless File.exist?("#{bots_dir}#{bot}/startup")
|
216
|
-
console.warn "Impossible to start bot #{bot}. Couldn't locate 'startup' script."
|
217
|
-
next
|
218
|
-
end
|
219
|
-
# Create a new window in the session for this run
|
220
|
-
tmux.new_bot_window bot
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
true
|
225
|
-
end
|
226
|
-
|
227
|
-
|
228
|
-
def start_bots( cur_prj_dir, run_id, params )
|
229
|
-
# Create a new tmux instance for this run
|
230
|
-
tmux = Tmux.new run_id
|
231
|
-
# Fetch bots dir
|
232
|
-
bots_dir = "#{cur_prj_dir}/bots/"
|
233
|
-
# Start the appropriate bots
|
234
|
-
bots_list_wo_project( cur_prj_dir, params ).each { |bot| start_bot(bots_dir, bot, tmux) }
|
235
|
-
true
|
236
|
-
end
|
237
|
-
|
238
|
-
|
239
|
-
def start_bot( bots_dir, bot, tmux )
|
240
|
-
# If there is no 'startup' script output a warning (because
|
241
|
-
# startup is mandatory) and skip the bot
|
242
|
-
unless File.exist?("#{bots_dir}#{bot}/startup")
|
243
|
-
console.warn "Impossible to start bot #{bot}. Couldn't locate 'startup' script."
|
244
|
-
return
|
245
|
-
end
|
246
|
-
# Create a new window in the session for this run
|
247
|
-
tmux.new_bot_window bot
|
248
|
-
end
|
249
|
-
|
250
|
-
|
251
|
-
def output_monitoring_details( run_id, cur_prj_dir, params )
|
252
|
-
project_bots_list = Nutella.current_project.config['project_bots']
|
253
|
-
project_name = Nutella.current_project.config['name']
|
254
|
-
tmux_session_name = "#{project_name}-project-bots"
|
255
|
-
unless project_bots_list.nil? || project_bots_list.empty?
|
256
|
-
console.success "Do `tmux attach-session -t #{tmux_session_name}` to monitor your project bots."
|
257
|
-
end
|
258
|
-
if bots_list_wo_project(cur_prj_dir, params).empty?
|
259
|
-
console.success 'No tmux session was created for this run because you specified no regular bots exclusively for this run'
|
260
|
-
else
|
261
|
-
console.success "Do `tmux attach-session -t #{run_id}` to monitor your bots."
|
262
|
-
end
|
263
|
-
console.success "Go to http://localhost:#{Nutella.config['main_interface_port']}/#{run_id} to access your interfaces"
|
264
|
-
|
265
|
-
end
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
end
|
271
|
-
|
data/lib/core/commands/stop.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'core/run_command'
|
2
|
-
require 'core/tmux'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
class Stop < RunCommand
|
6
|
-
@description = 'Stops all or some of the bots in the current project'
|
7
|
-
|
8
|
-
def run(args=nil)
|
9
|
-
|
10
|
-
# If the current directory is not a nutella project, return
|
11
|
-
return unless Nutella.current_project.exist?
|
12
|
-
|
13
|
-
# Extract run (passed run name) and run_id
|
14
|
-
run, run_id = extract_names args
|
15
|
-
|
16
|
-
# Check that the run_id exists in the list and, if it is not,
|
17
|
-
# return false
|
18
|
-
return unless remove_from_run_list run_id
|
19
|
-
|
20
|
-
# Stops all the bots
|
21
|
-
Tmux.kill_session run_id
|
22
|
-
|
23
|
-
# Stop all project level actors (if any) if needed
|
24
|
-
stop_project_bots
|
25
|
-
|
26
|
-
# Stop all nutella internal actors, if needed
|
27
|
-
if Nutella.runlist.empty?
|
28
|
-
stop_nutella_actors
|
29
|
-
end
|
30
|
-
|
31
|
-
# If running on the internal broker, stop it if needed
|
32
|
-
if Nutella.runlist.empty? and running_on_internal_broker?
|
33
|
-
stop_broker
|
34
|
-
end
|
35
|
-
|
36
|
-
# Output success message
|
37
|
-
output_success_message( run_id, run, 'stopped' )
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
|
44
|
-
def remove_from_run_list( run_id )
|
45
|
-
unless Nutella.runlist.delete? run_id
|
46
|
-
console.warn "Run #{run_id} doesn't exist. Impossible to stop it."
|
47
|
-
return false
|
48
|
-
end
|
49
|
-
true
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
def stop_project_bots
|
54
|
-
project_name = Nutella.current_project.config['name']
|
55
|
-
tmux_session_name = "#{project_name}-project-bots"
|
56
|
-
if Tmux.session_exist? tmux_session_name
|
57
|
-
# Are there any runs of this project hinging on the project bots?
|
58
|
-
if Nutella.runlist.runs_by_project(project_name).empty?
|
59
|
-
Tmux.kill_session tmux_session_name
|
60
|
-
end
|
61
|
-
end
|
62
|
-
true
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
def stop_nutella_actors
|
67
|
-
nutella_actors_dir = "#{Nutella.config['nutella_home']}actors"
|
68
|
-
for_each_actor_in_dir nutella_actors_dir do |actor|
|
69
|
-
pid_file_path = "#{nutella_actors_dir}/#{actor}/.pid"
|
70
|
-
kill_process_with_pid pid_file_path
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
def stop_broker
|
76
|
-
pid_file_path = "#{Nutella.config['broker_dir']}/bin/.pid"
|
77
|
-
kill_process_with_pid pid_file_path
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
# Does the process pid file exist?
|
82
|
-
# If it does we send a SIGKILL to the process with that pid
|
83
|
-
# to stop the process and delete the pid file
|
84
|
-
def kill_process_with_pid( pid_file_path )
|
85
|
-
if File.exist? pid_file_path
|
86
|
-
pid_file = File.open( pid_file_path, 'rb' )
|
87
|
-
pid = pid_file.read.to_i
|
88
|
-
pid_file.close
|
89
|
-
begin
|
90
|
-
Process.kill( 'SIGKILL', pid )
|
91
|
-
rescue
|
92
|
-
# Pid file exists but process is dead. Do nothing
|
93
|
-
end
|
94
|
-
File.delete pid_file_path
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
end
|
data/lib/core/run_command.rb
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
require 'core/command'
|
2
|
-
require 'slop'
|
3
|
-
|
4
|
-
module Nutella
|
5
|
-
# This class describes a run command which can be either start or stop.
|
6
|
-
# It is mostly a commodity class for code reuse.
|
7
|
-
class RunCommand < Command
|
8
|
-
|
9
|
-
def run (args=nil)
|
10
|
-
console.error 'Running generic RunCommand!!! WAT?'
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
# Extracts run name and run_id
|
15
|
-
# @param [Array<String>] args command line arguments passed to the command
|
16
|
-
# @return [String, String ] the run name (cleaned of nils) and the run_id
|
17
|
-
def extract_names( args )
|
18
|
-
|
19
|
-
# Simple `nutella start/stop`
|
20
|
-
if args.nil? || args.empty?
|
21
|
-
run = nil
|
22
|
-
run_id = Nutella.runlist.extract_run_id( '' )
|
23
|
-
return run, run_id
|
24
|
-
end
|
25
|
-
|
26
|
-
# Check if the first argument is a parameter or a run name
|
27
|
-
if args[0].start_with? '-'
|
28
|
-
run = nil
|
29
|
-
run_id = Nutella.runlist.extract_run_id( '' )
|
30
|
-
else
|
31
|
-
# If it's a run name, store the run name and shift so we are left with only
|
32
|
-
# the parameters in args
|
33
|
-
run = args[0]
|
34
|
-
run_id = Nutella.runlist.extract_run_id( args[0] )
|
35
|
-
args.shift
|
36
|
-
end
|
37
|
-
|
38
|
-
return run, run_id
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
# Extracts the command line parameters
|
43
|
-
# @param [Array<String>] args command line arguments passed to the command
|
44
|
-
# @return [Hash] an hash containing the parameters
|
45
|
-
def extract_parameters( args )
|
46
|
-
opts = Slop::Options.new
|
47
|
-
opts.array '-wo', '--without', 'A list of actors NOT to start'
|
48
|
-
opts.array '-w', '--with', 'A list of actors that needs to be started'
|
49
|
-
parser = Slop::Parser.new(opts)
|
50
|
-
result = parser.parse(args)
|
51
|
-
result.to_hash
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
# Returns all the actors in a certain directory
|
56
|
-
def run_actors_list( actors_dir )
|
57
|
-
Dir.entries(actors_dir).select {|entry| File.directory?(File.join(actors_dir, entry)) && !(entry =='.' || entry == '..') }
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
# Executes a code block for each actor in a certain directory
|
62
|
-
# @param [String] actors_dir directory where we are iterating
|
63
|
-
# @yield [actor_dir] Gives the actor directory to the block
|
64
|
-
def for_each_actor_in_dir( actors_dir, &block )
|
65
|
-
run_actors_list(actors_dir).each do |actor_dir|
|
66
|
-
block.call actor_dir
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
def output_success_message(run_id, run, action)
|
72
|
-
if run_id == Nutella.current_project.config['name']
|
73
|
-
console.success "Project #{Nutella.current_project.config['name']} #{action}!"
|
74
|
-
else
|
75
|
-
console.success "Project #{Nutella.current_project.config['name']}, run #{run} #{action}!"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
def prepare_bot( cur_prj_dir, script, message )
|
81
|
-
for_each_actor_in_dir cur_prj_dir do |bot|
|
82
|
-
# Skip bot if there is no script
|
83
|
-
next unless File.exist? "#{cur_prj_dir}/bots/#{bot}/#{script}"
|
84
|
-
# Output message
|
85
|
-
console.info "#{message} bot #{bot}."
|
86
|
-
# Execute 'script' script
|
87
|
-
cur_dir = Dir.pwd
|
88
|
-
Dir.chdir "#{cur_prj_dir}/bots/#{bot}"
|
89
|
-
system "./#{script}"
|
90
|
-
Dir.chdir cur_dir
|
91
|
-
end
|
92
|
-
true
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
# If the broker is set to one of the current ip addresses,
|
97
|
-
# localhost or 127.0.0.1 return true.
|
98
|
-
def running_on_internal_broker?
|
99
|
-
broker = Nutella.config['broker']
|
100
|
-
Socket.ip_address_list.find_all{|a| a.ipv4? }.map{|a| a.ip_address}.include?(broker) || broker == 'localhost' || broker == '127.0.0.1'
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|