scout_agent 3.0.6 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +18 -0
- data/Rakefile +1 -1
- data/lib/scout_agent/agent/communication_agent.rb +5 -1
- data/lib/scout_agent/agent/master_agent.rb +6 -6
- data/lib/scout_agent/agent.rb +26 -5
- data/lib/scout_agent/api.rb +52 -12
- data/lib/scout_agent/assignment/configuration.rb +11 -0
- data/lib/scout_agent/assignment/identify.rb +26 -0
- data/lib/scout_agent/assignment/queue.rb +35 -0
- data/lib/scout_agent/assignment/reset.rb +30 -0
- data/lib/scout_agent/assignment/snapshot.rb +50 -4
- data/lib/scout_agent/assignment/start.rb +65 -2
- data/lib/scout_agent/assignment/status.rb +22 -3
- data/lib/scout_agent/assignment/stop.rb +42 -5
- data/lib/scout_agent/assignment/test.rb +366 -0
- data/lib/scout_agent/assignment/update.rb +20 -0
- data/lib/scout_agent/assignment/upload_log.rb +31 -1
- data/lib/scout_agent/assignment.rb +92 -13
- data/lib/scout_agent/core_extensions.rb +24 -5
- data/lib/scout_agent/dispatcher.rb +45 -1
- data/lib/scout_agent/lifeline.rb +7 -2
- data/lib/scout_agent/mission.rb +31 -11
- data/lib/scout_agent/order/check_in_order.rb +27 -1
- data/lib/scout_agent/order/snapshot_order.rb +16 -0
- data/lib/scout_agent/order.rb +57 -11
- data/lib/scout_agent/plan.rb +1 -1
- data/lib/scout_agent.rb +1 -1
- metadata +13 -5
data/CHANGELOG
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
== 3.0.7
|
2
|
+
|
3
|
+
* Added a log() method (with a logger() alias) plugins can access to add
|
4
|
+
messages to the log as needed
|
5
|
+
* Added JSON hooks for the Time class so they will be converted back to Ruby
|
6
|
+
objects when loaded
|
7
|
+
* Added a `scout_agent test` command for plugin developers
|
8
|
+
* Switched to the default URL of https://beta.scoutapp.com
|
9
|
+
* Improved the error handling in the communications agent for connection failure
|
10
|
+
scenarios like blocked ports (fixes a CPU pegging bug)
|
11
|
+
* Loosened error checking when killing processes to improve monitor stability
|
12
|
+
* Loosened the check-in timeout a touch as the monitor seemed to kill off
|
13
|
+
processes a little too quickly
|
14
|
+
* Enhanced the monitor to kill off mission processes after killing the mission
|
15
|
+
runner
|
16
|
+
* Made the stop command hunt for stray processes after stopping the monitor
|
17
|
+
process
|
18
|
+
|
1
19
|
== 3.0.6
|
2
20
|
|
3
21
|
* The new `sudo scout_agent update` command can be used to update your
|
data/Rakefile
CHANGED
@@ -81,7 +81,7 @@ end
|
|
81
81
|
|
82
82
|
Rake::RDocTask.new do |rdoc|
|
83
83
|
rdoc.main = "README"
|
84
|
-
rdoc.rdoc_dir = "doc
|
84
|
+
rdoc.rdoc_dir = "doc"
|
85
85
|
rdoc.title = "Scout Agent Documentation"
|
86
86
|
rdoc.rdoc_files.include( *%w[ README INSTALL TODO CHANGELOG
|
87
87
|
AUTHORS COPYING LICENSE lib/ ] )
|
@@ -18,6 +18,7 @@ module ScoutAgent
|
|
18
18
|
@agent_jid = nil
|
19
19
|
@jabber = nil
|
20
20
|
@roster = nil
|
21
|
+
@connecting = false
|
21
22
|
@shutdown_thread = nil
|
22
23
|
@trusted = Array(Plan.xmpp_trusted).map { |trusted|
|
23
24
|
trusted_with_server = trusted.sub(/@\*\z/, "@#{jabber_server}")
|
@@ -36,6 +37,7 @@ module ScoutAgent
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def finish
|
40
|
+
log.info("Shutting down.")
|
39
41
|
if @shutdown_thread
|
40
42
|
@shutdown_thread.run
|
41
43
|
else
|
@@ -51,17 +53,19 @@ module ScoutAgent
|
|
51
53
|
log.info("Connecting to XMPP: #{@agent_jid}")
|
52
54
|
@jabber = Jabber::Client.new(@agent_jid)
|
53
55
|
@jabber.on_exception do |error, stream, during|
|
54
|
-
try_connection
|
56
|
+
try_connection unless @connecting
|
55
57
|
end
|
56
58
|
try_connection
|
57
59
|
end
|
58
60
|
|
59
61
|
def try_connection
|
62
|
+
@connecting = true
|
60
63
|
until connect_and_authenticate?
|
61
64
|
log.info( "Waiting #{RECONNECT_WAIT} seconds before making another " +
|
62
65
|
"connection attempt." )
|
63
66
|
sleep RECONNECT_WAIT
|
64
67
|
end
|
68
|
+
@connecting = false
|
65
69
|
end
|
66
70
|
|
67
71
|
def connect_and_authenticate?
|
@@ -271,7 +271,7 @@ module ScoutAgent
|
|
271
271
|
rescue Exception => error # any compile error
|
272
272
|
raise if $!.is_a? SystemExit # don't catch exit() calls
|
273
273
|
log.error( "#{mission[:name]} could not be compiled: " +
|
274
|
-
|
274
|
+
"#{error.message} (#{error.class})." )
|
275
275
|
reported = @db.write_report(
|
276
276
|
mission[:id],
|
277
277
|
:error,
|
@@ -287,11 +287,11 @@ module ScoutAgent
|
|
287
287
|
if prepared = Mission.prepared
|
288
288
|
log.info("Starting #{mission[:name]} mission.")
|
289
289
|
status("Running")
|
290
|
-
prepared.new( *mission.values_at( :id,
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
290
|
+
prepared.new( *( mission.values_at( :id,
|
291
|
+
:name,
|
292
|
+
:last_run_at,
|
293
|
+
:memory,
|
294
|
+
:options ) + [@log] ) ).run
|
295
295
|
else # no mission loaded
|
296
296
|
log.error("#{mission[:name]} could not be prepared.")
|
297
297
|
reported = @db.write_report(
|
data/lib/scout_agent/agent.rb
CHANGED
@@ -2,9 +2,17 @@
|
|
2
2
|
# encoding: UTF-8
|
3
3
|
|
4
4
|
module ScoutAgent
|
5
|
+
#
|
6
|
+
# An Agent is a subprocess launched at startup and kept running by a Lifeline
|
7
|
+
# monitor. These subprocesses manage the major functions of the platform.
|
8
|
+
#
|
5
9
|
class Agent
|
6
10
|
include Tracked
|
7
11
|
|
12
|
+
#
|
13
|
+
# Prepares a new agent instance by building a log() and setting a
|
14
|
+
# <tt>"Loading"</tt> status message.
|
15
|
+
#
|
8
16
|
def initialize
|
9
17
|
@log = ScoutAgent.prepare_wire_tap(file_name)
|
10
18
|
log.info("Loading.")
|
@@ -15,27 +23,40 @@ module ScoutAgent
|
|
15
23
|
end
|
16
24
|
end
|
17
25
|
|
26
|
+
# The log file this agent will report to.
|
18
27
|
attr_reader :log
|
19
28
|
|
29
|
+
# Ensure we are the only process with this name running.
|
20
30
|
def authorize
|
21
31
|
IDCard.new(file_name).authorize
|
22
32
|
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
34
|
+
#
|
35
|
+
# This method will be called when the agent process receives an +ALRM+
|
36
|
+
# signal. By default, this method is a no-op, but subclasses can overrided
|
37
|
+
# it to add behavior.
|
38
|
+
#
|
29
39
|
def notice_changes
|
30
40
|
# do nothing: specific agents can override for their purposes
|
31
41
|
end
|
32
42
|
|
43
|
+
#
|
44
|
+
# This method will be called when the agent receives a +TERM+ signal. The
|
45
|
+
# default behavior is to exit(), but subclasses can override it to add more
|
46
|
+
# specific behavior.
|
47
|
+
#
|
33
48
|
def finish
|
34
49
|
exit
|
35
50
|
end
|
36
51
|
|
52
|
+
#######
|
37
53
|
private
|
54
|
+
#######
|
38
55
|
|
56
|
+
#
|
57
|
+
# Returns the file name to be used for this agent's PID files and status
|
58
|
+
# entries.
|
59
|
+
#
|
39
60
|
def file_name
|
40
61
|
self.class.short_name.sub(/Agent\z/, "").snake_case
|
41
62
|
end
|
data/lib/scout_agent/api.rb
CHANGED
@@ -18,8 +18,8 @@ end
|
|
18
18
|
module ScoutAgent
|
19
19
|
#
|
20
20
|
# This module contains methods used to communicate with the agent
|
21
|
-
# programmatically. These methods can be used to send data to the agent or
|
22
|
-
#
|
21
|
+
# programmatically. These methods can be used to send data to the agent or to
|
22
|
+
# make requests that the agent perform certain actions for you.
|
23
23
|
#
|
24
24
|
module API
|
25
25
|
#
|
@@ -29,6 +29,11 @@ module ScoutAgent
|
|
29
29
|
# or failure of your requests.
|
30
30
|
#
|
31
31
|
class Command
|
32
|
+
#
|
33
|
+
# Prepares and runs an API command by shelling out to +name+, optionally
|
34
|
+
# with +args+ or +input+. You can also set +options+ for the run, like
|
35
|
+
# <tt>:background => true</tt>.
|
36
|
+
#
|
32
37
|
def initialize(name, args, input, options) # :nodoc:
|
33
38
|
@name = name
|
34
39
|
@args = args
|
@@ -68,20 +73,26 @@ module ScoutAgent
|
|
68
73
|
@finished
|
69
74
|
end
|
70
75
|
|
76
|
+
#######
|
71
77
|
private
|
78
|
+
#######
|
72
79
|
|
80
|
+
#
|
81
|
+
# Runs the prepared command, setting +exit_status+, +error_message+, and
|
82
|
+
# +finished+ on completion with the results of the run.
|
83
|
+
#
|
73
84
|
def run
|
74
85
|
command = [ API.path_to_ruby, API.path_to_agent,
|
75
86
|
@name, *Array(@args) ].
|
76
87
|
map { |s| "'#{API.shell_escape(s)}'" }.join(" ")
|
77
88
|
begin
|
78
|
-
response = open("| #{command} 2>&1", "r+")
|
89
|
+
response = open("| #{command} 2>&1", "r+") { |agent|
|
79
90
|
agent.puts @input.to_json if @input
|
80
91
|
agent.close_write
|
81
92
|
agent.read
|
82
|
-
|
93
|
+
}
|
83
94
|
rescue Exception => error # we cannot shell out to the agent
|
84
|
-
@exit_status = ($? && $?.exitstatus) ||
|
95
|
+
@exit_status = ($? && $?.exitstatus) || 1
|
85
96
|
@error_message = "#{error.message} (#{error.class})"
|
86
97
|
@finished = true
|
87
98
|
return
|
@@ -91,19 +102,37 @@ module ScoutAgent
|
|
91
102
|
@finished = true
|
92
103
|
end
|
93
104
|
|
105
|
+
# Wraps run() in a background Thread.
|
94
106
|
def run_in_background
|
95
|
-
Thread.new
|
107
|
+
Thread.new do
|
108
|
+
run
|
109
|
+
end
|
96
110
|
end
|
97
111
|
end
|
98
112
|
|
113
|
+
#
|
114
|
+
# This is a private specialization of Command that adds some validation for
|
115
|
+
# queue commands in order to fail faster during API calls.
|
116
|
+
#
|
99
117
|
class QueueCommand < Command # :nodoc:
|
118
|
+
#
|
119
|
+
# Simplifies the needed parameters to be specific to queue commands.
|
120
|
+
# Validation is also invoked here before the command is run.
|
121
|
+
#
|
100
122
|
def initialize(mission_id_or_report_type, fields, options)
|
101
123
|
validate(mission_id_or_report_type, fields)
|
102
124
|
super(:queue, [mission_id_or_report_type], fields, options)
|
103
125
|
end
|
104
126
|
|
127
|
+
#######
|
105
128
|
private
|
129
|
+
#######
|
106
130
|
|
131
|
+
#
|
132
|
+
# Duplicates some error checking done by the queue command, so that
|
133
|
+
# bad calls can fail before we pay the penalty of shelling out to the
|
134
|
+
# agent.
|
135
|
+
#
|
107
136
|
def validate(mission_id_or_report_type, fields)
|
108
137
|
unless mission_id_or_report_type.to_s =~
|
109
138
|
/\A(?:report|hint|alert|error|\d*[1-9])\z/
|
@@ -125,7 +154,13 @@ module ScoutAgent
|
|
125
154
|
end
|
126
155
|
end
|
127
156
|
|
157
|
+
###############
|
128
158
|
module_function
|
159
|
+
###############
|
160
|
+
|
161
|
+
###############
|
162
|
+
### Helpers ###
|
163
|
+
###############
|
129
164
|
|
130
165
|
#
|
131
166
|
# This convience method will escape a single _word_ for use in a shell
|
@@ -161,6 +196,10 @@ module ScoutAgent
|
|
161
196
|
*%w[.. .. bin scout_agent] ) )
|
162
197
|
end
|
163
198
|
|
199
|
+
###############
|
200
|
+
### Queuing ###
|
201
|
+
###############
|
202
|
+
|
164
203
|
#
|
165
204
|
# Use this method to queue a +message+ for a mission to receive on it's next
|
166
205
|
# run.
|
@@ -177,7 +216,7 @@ module ScoutAgent
|
|
177
216
|
# end
|
178
217
|
#
|
179
218
|
# If you don't wish to wait, you can request that the send take place in the
|
180
|
-
# background. You can still use the
|
219
|
+
# background. You can still use the Command object to check the status of
|
181
220
|
# these requests, but you must first wait for them to be finished?(). Do
|
182
221
|
# not trust any other methods, like success?(), until finished?() returns
|
183
222
|
# +true+.
|
@@ -242,6 +281,10 @@ module ScoutAgent
|
|
242
281
|
QueueCommand.new(:error, fields, options)
|
243
282
|
end
|
244
283
|
|
284
|
+
#################
|
285
|
+
### Snapshots ###
|
286
|
+
#################
|
287
|
+
|
245
288
|
#
|
246
289
|
# :call-seq:
|
247
290
|
# take_snapshot(options = { })
|
@@ -253,16 +296,13 @@ module ScoutAgent
|
|
253
296
|
# during the next checkin. The returned object and background processing
|
254
297
|
# rules are the same as those described in queue_for_mission().
|
255
298
|
#
|
256
|
-
# Passing a
|
299
|
+
# Passing a +true+ value in +force+ clears the command times before running,
|
257
300
|
# forcing a full snapshot to be taken.
|
258
301
|
#
|
259
302
|
def take_snapshot(*args)
|
260
|
-
started = Time.now
|
261
303
|
force = args.shift ? %w[force] : nil unless args.first.is_a? Hash
|
262
|
-
options = args.shift ||
|
304
|
+
options = args.shift || Hash.new
|
263
305
|
Command.new(:snapshot, force, nil, options)
|
264
|
-
ensure
|
265
|
-
p Time.now - started
|
266
306
|
end
|
267
307
|
end
|
268
308
|
end
|
@@ -3,7 +3,18 @@
|
|
3
3
|
|
4
4
|
module ScoutAgent
|
5
5
|
class Assignment
|
6
|
+
#
|
7
|
+
# Invoke with:
|
8
|
+
#
|
9
|
+
# scout_agent config
|
10
|
+
#
|
11
|
+
# This command shows the current configuration of the agent mainly
|
12
|
+
# determined by reading the configuration file. However, you can pass
|
13
|
+
# command-line switches when running this command to see how they change
|
14
|
+
# things and help you find a good setup for other commands.
|
15
|
+
#
|
6
16
|
class Configuration < Assignment
|
17
|
+
# Runs the configuration command.
|
7
18
|
def execute
|
8
19
|
puts "Configuration"
|
9
20
|
puts "============="
|
@@ -3,15 +3,27 @@
|
|
3
3
|
|
4
4
|
module ScoutAgent
|
5
5
|
class Assignment
|
6
|
+
#
|
7
|
+
# Invoke with:
|
8
|
+
#
|
9
|
+
# sudo scout_agent id
|
10
|
+
#
|
11
|
+
# This command prepares the agent for use by recording your key and settings
|
12
|
+
# into a configuration file. This file is then loaded by all other commands
|
13
|
+
# to configure the agent for use. Have a look at <tt>scout_agent -h</tt>
|
14
|
+
# for other options you may wish to set, like +proxy+.
|
15
|
+
#
|
6
16
|
class Identify < Assignment
|
7
17
|
plan :switches_only
|
8
18
|
choose_group true
|
9
19
|
|
20
|
+
# Runs the identify command.
|
10
21
|
def execute
|
11
22
|
puts "Identifying Your Agent"
|
12
23
|
puts "======================"
|
13
24
|
puts
|
14
25
|
|
26
|
+
# make sure we can access the needed directories
|
15
27
|
%w[config_file db_dir log_dir].each do |path|
|
16
28
|
full = dir = Plan.send(path)
|
17
29
|
loop do
|
@@ -23,6 +35,7 @@ module ScoutAgent
|
|
23
35
|
end
|
24
36
|
end
|
25
37
|
|
38
|
+
# get a key and test the server connection with that key
|
26
39
|
unless Plan.config_file.exist?
|
27
40
|
print <<-END_KEY_DESCRIPTION.trim.to_question
|
28
41
|
I need your Agent Key displayed in the Agent Settings tab
|
@@ -42,6 +55,7 @@ module ScoutAgent
|
|
42
55
|
end
|
43
56
|
end
|
44
57
|
|
58
|
+
# write the configuration file
|
45
59
|
puts "Saving identification..."
|
46
60
|
if Plan.write_default_config_file
|
47
61
|
puts "Identification file '#{Plan.config_file}' created."
|
@@ -52,6 +66,7 @@ module ScoutAgent
|
|
52
66
|
abort_with_insufficient_permissions(Plan.config_file)
|
53
67
|
end
|
54
68
|
end
|
69
|
+
# create directories and global databases
|
55
70
|
%w[db_dir log_dir].each do |path|
|
56
71
|
dir = Plan.send(path)
|
57
72
|
if dir.exist?
|
@@ -77,6 +92,7 @@ module ScoutAgent
|
|
77
92
|
puts "Done."
|
78
93
|
puts
|
79
94
|
|
95
|
+
# show next steps
|
80
96
|
puts <<-END_START_INSTRUCTIONS.trim
|
81
97
|
You are now identified. You can start the agent with:
|
82
98
|
|
@@ -85,8 +101,14 @@ module ScoutAgent
|
|
85
101
|
END_START_INSTRUCTIONS
|
86
102
|
end
|
87
103
|
|
104
|
+
#######
|
88
105
|
private
|
106
|
+
#######
|
89
107
|
|
108
|
+
#
|
109
|
+
# Abort with an error message to the user that says we lack the
|
110
|
+
# permissions to configure their agent.
|
111
|
+
#
|
90
112
|
def abort_with_insufficient_permissions(path)
|
91
113
|
abort <<-END_PRIVILEGES.trim
|
92
114
|
I don't have enough privileges to create '#{path}'.
|
@@ -97,6 +119,10 @@ module ScoutAgent
|
|
97
119
|
END_PRIVILEGES
|
98
120
|
end
|
99
121
|
|
122
|
+
#
|
123
|
+
# Abort with an error message to the user that says tells them their key
|
124
|
+
# is probably not valid.
|
125
|
+
#
|
100
126
|
def abort_with_bad_key
|
101
127
|
abort <<-END_BAD_KEY.trim
|
102
128
|
Could not contact server. The key may be incorrect.
|
@@ -6,7 +6,27 @@ require "io/wait"
|
|
6
6
|
|
7
7
|
module ScoutAgent
|
8
8
|
class Assignment
|
9
|
+
#
|
10
|
+
# Invoke with:
|
11
|
+
#
|
12
|
+
# scout_agent q ID_OR_TYPE <<< '{"fields": "in JSON"}'
|
13
|
+
#
|
14
|
+
# This command queues some data from an external source for a plugin. The
|
15
|
+
# plugin to receive the message is given by ID in +ID_OR_TYPE+. That plugin
|
16
|
+
# will be able to collect this data during its next run.
|
17
|
+
#
|
18
|
+
# Alternately, this command can be used to send a complete report, alert,
|
19
|
+
# error, or hint directly to the server (with the next check-in). When
|
20
|
+
# using as such, +ID_OR_TYPE+ must be one of those types and the fields must
|
21
|
+
# be a Hash (object in JSON terminology) that includes the key "plugin_id"
|
22
|
+
# associated with an ID value for the reporting plugin.
|
23
|
+
#
|
9
24
|
class Queue < Assignment
|
25
|
+
#
|
26
|
+
# A list of errors that can be sent to the user when attempting to queue a
|
27
|
+
# message. The index of the message plus one is also the exit status for
|
28
|
+
# that error.
|
29
|
+
#
|
10
30
|
ERRORS = [ [ :missing_db,
|
11
31
|
"Queue database could not be loaded." ],
|
12
32
|
[ :missing_id,
|
@@ -27,19 +47,24 @@ module ScoutAgent
|
|
27
47
|
[ :failed_to_queue_message,
|
28
48
|
"Your message could not be queued at this time." ] ]
|
29
49
|
|
50
|
+
# Runs the queue command.
|
30
51
|
def execute
|
52
|
+
# prepare the log
|
31
53
|
log = ScoutAgent.prepare_wire_tap(:queue, :skip_stdout)
|
32
54
|
|
55
|
+
# record our status and set removal at_exit()
|
33
56
|
status_database(log)
|
34
57
|
status("Queuing message", :queue)
|
35
58
|
at_my_exit do
|
36
59
|
clear_status(:queue)
|
37
60
|
end
|
38
61
|
|
62
|
+
# load the queue database
|
39
63
|
unless db = Database.load(:queue, log)
|
40
64
|
abort_with_error(:missing_db)
|
41
65
|
end
|
42
66
|
|
67
|
+
# ensure id or type is valid
|
43
68
|
log.info("Validating message for queuing.")
|
44
69
|
unless id = Array(other_args).shift
|
45
70
|
abort_with_error(:missing_id)
|
@@ -48,6 +73,7 @@ module ScoutAgent
|
|
48
73
|
abort_with_error(:invalid_id)
|
49
74
|
end
|
50
75
|
|
76
|
+
# read field data and parse JSON
|
51
77
|
fields = ARGF.read unless ARGV.empty? and not $stdin.ready?
|
52
78
|
if fields.nil? or fields.empty?
|
53
79
|
abort_with_error(:missing_fields)
|
@@ -59,6 +85,7 @@ module ScoutAgent
|
|
59
85
|
abort_with_error(:invalid_fields)
|
60
86
|
end
|
61
87
|
|
88
|
+
# ensure we have a valid plugin_id, if needed
|
62
89
|
if %w[report hint alert error].include? id
|
63
90
|
unless fields.is_a? Hash
|
64
91
|
abort_with_error(:invalid_report_fields)
|
@@ -74,18 +101,26 @@ module ScoutAgent
|
|
74
101
|
log.info("Message is valid (#{bytes} bytes).")
|
75
102
|
end
|
76
103
|
|
104
|
+
# queue the message
|
77
105
|
log.info("Queuing message.")
|
78
106
|
unless db.enqueue(id, fields)
|
79
107
|
abort_with_error(:failed_to_queue_message)
|
80
108
|
end
|
81
109
|
|
110
|
+
# maintain the queue database
|
82
111
|
db.maintain
|
83
112
|
|
84
113
|
log.info("Messages queued successfully.")
|
85
114
|
end
|
86
115
|
|
116
|
+
#######
|
87
117
|
private
|
118
|
+
#######
|
88
119
|
|
120
|
+
#
|
121
|
+
# Abort with an error message and exit status that tells the user which
|
122
|
+
# part of the process failed.
|
123
|
+
#
|
89
124
|
def abort_with_error(error_name)
|
90
125
|
error = ERRORS.assoc(error_name)
|
91
126
|
warn error.last
|
@@ -3,8 +3,20 @@
|
|
3
3
|
|
4
4
|
module ScoutAgent
|
5
5
|
class Assignment
|
6
|
+
#
|
7
|
+
# Invoke with:
|
8
|
+
#
|
9
|
+
# sudo scout_agent reset
|
10
|
+
#
|
11
|
+
# This command removes all saved configuration and data from the agent.
|
12
|
+
# After this is run it's basically like the agent has been reset to the way
|
13
|
+
# it was after being intalled. This is a dangerous command that destroys
|
14
|
+
# data and cannot be undone.
|
15
|
+
#
|
6
16
|
class Reset < Assignment
|
17
|
+
# Runs the reset command.
|
7
18
|
def execute
|
19
|
+
# make sure the agent isn't running
|
8
20
|
agent = IDCard.new(:lifeline)
|
9
21
|
if agent.pid_file.exist?
|
10
22
|
abort_with_agent_running
|
@@ -14,6 +26,7 @@ module ScoutAgent
|
|
14
26
|
puts "================"
|
15
27
|
puts
|
16
28
|
|
29
|
+
# get confirmation from the user
|
17
30
|
print <<-END_WARNING.trim.to_question
|
18
31
|
This is a dangerous operation that will remove configuration
|
19
32
|
and data files. Are you absolutely sure you wish to remove
|
@@ -25,6 +38,7 @@ module ScoutAgent
|
|
25
38
|
|
26
39
|
puts
|
27
40
|
puts "Resetting..."
|
41
|
+
# remove configuration file
|
28
42
|
if not Plan.config_file.exist?
|
29
43
|
puts <<-END_CONFIG_FILE
|
30
44
|
Identification file '#{Plan.config_file}' doesn't exist. Skipped.
|
@@ -37,6 +51,7 @@ module ScoutAgent
|
|
37
51
|
abort_with_insufficient_permissions(Plan.config_file)
|
38
52
|
end
|
39
53
|
end
|
54
|
+
# remove directories and the data they contain
|
40
55
|
%w[db_dir pid_dir log_dir].each do |path|
|
41
56
|
dir = Plan.send(path)
|
42
57
|
if not dir.exist?
|
@@ -53,6 +68,7 @@ module ScoutAgent
|
|
53
68
|
puts "Done."
|
54
69
|
puts
|
55
70
|
|
71
|
+
# show next steps
|
56
72
|
puts <<-END_START_INSTRUCTIONS.trim
|
57
73
|
This agent is reset. You can prepare it for use again
|
58
74
|
at anytime with:
|
@@ -62,8 +78,14 @@ module ScoutAgent
|
|
62
78
|
END_START_INSTRUCTIONS
|
63
79
|
end
|
64
80
|
|
81
|
+
#######
|
65
82
|
private
|
83
|
+
#######
|
66
84
|
|
85
|
+
#
|
86
|
+
# Abort with an error message to the user that says we with a warning that
|
87
|
+
# the agent cannot be reset when it is running.
|
88
|
+
#
|
67
89
|
def abort_with_agent_running
|
68
90
|
abort <<-END_AGENT_RUNNING.trim
|
69
91
|
You cannot reset while the agent is running. Please stop
|
@@ -74,10 +96,18 @@ module ScoutAgent
|
|
74
96
|
END_AGENT_RUNNING
|
75
97
|
end
|
76
98
|
|
99
|
+
#
|
100
|
+
# Abort with an error message to the user that confirms their
|
101
|
+
# cancellation of the reset.
|
102
|
+
#
|
77
103
|
def abort_with_cancel
|
78
104
|
abort "Reset cancelled. No data was removed."
|
79
105
|
end
|
80
106
|
|
107
|
+
#
|
108
|
+
# Abort with an error message to the user that says we don't have
|
109
|
+
# permission to remove some configuration.
|
110
|
+
#
|
81
111
|
def abort_with_insufficient_permissions(path)
|
82
112
|
abort <<-END_PRIVILEGES.trim
|
83
113
|
I don't have enough privileges to remove '#{path}'.
|