scout_agent 3.0.6 → 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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}'.
|