nutella_framework 0.3.1 → 0.4.0
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.
- 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
|