cognizant 0.0.2 → 0.0.3
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 +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -1
- data/{LICENSE → License.md} +4 -2
- data/Rakefile +5 -0
- data/Readme.md +95 -0
- data/bin/cognizant +76 -122
- data/bin/cognizantd +28 -61
- data/cognizant.gemspec +8 -4
- data/examples/apps/redis-server.cz +42 -0
- data/examples/apps/redis-server.yml +29 -0
- data/examples/apps/redis-server_dsl.cz +54 -0
- data/examples/apps/resque.cz +17 -0
- data/examples/apps/thin.cz +32 -0
- data/examples/apps/thin.yml +48 -0
- data/examples/cognizantd.yml +18 -47
- data/features/child_process.feature +62 -0
- data/features/commands.feature +65 -0
- data/features/cpu_usage.feature +45 -0
- data/features/daemon.feature +12 -0
- data/features/flapping.feature +39 -0
- data/features/memory_usage.feature +45 -0
- data/features/shell.feature +30 -0
- data/features/step_definitions/common_steps.rb +14 -0
- data/features/step_definitions/daemon_steps.rb +25 -0
- data/features/step_definitions/shell_steps.rb +96 -0
- data/features/support/env.rb +54 -0
- data/lib/cognizant.rb +1 -5
- data/lib/cognizant/application.rb +122 -0
- data/lib/cognizant/application/dsl_proxy.rb +23 -0
- data/lib/cognizant/client.rb +61 -0
- data/lib/cognizant/commands.rb +164 -0
- data/lib/cognizant/commands/actions.rb +30 -0
- data/lib/cognizant/commands/help.rb +10 -0
- data/lib/cognizant/commands/load.rb +10 -0
- data/lib/cognizant/commands/shutdown.rb +7 -0
- data/lib/cognizant/commands/status.rb +11 -0
- data/lib/cognizant/commands/use.rb +15 -0
- data/lib/cognizant/controller.rb +17 -0
- data/lib/cognizant/daemon.rb +279 -0
- data/lib/cognizant/interface.rb +17 -0
- data/lib/cognizant/log.rb +25 -0
- data/lib/cognizant/process.rb +138 -94
- data/lib/cognizant/process/actions.rb +30 -41
- data/lib/cognizant/process/actions/restart.rb +73 -17
- data/lib/cognizant/process/actions/start.rb +35 -12
- data/lib/cognizant/process/actions/stop.rb +38 -17
- data/lib/cognizant/process/attributes.rb +41 -10
- data/lib/cognizant/process/children.rb +36 -0
- data/lib/cognizant/process/{condition_check.rb → condition_delegate.rb} +11 -13
- data/lib/cognizant/process/conditions.rb +7 -4
- data/lib/cognizant/process/conditions/cpu_usage.rb +5 -6
- data/lib/cognizant/process/conditions/memory_usage.rb +2 -6
- data/lib/cognizant/process/dsl_proxy.rb +23 -0
- data/lib/cognizant/process/execution.rb +16 -9
- data/lib/cognizant/process/pid.rb +16 -6
- data/lib/cognizant/process/status.rb +14 -2
- data/lib/cognizant/process/trigger_delegate.rb +57 -0
- data/lib/cognizant/process/triggers.rb +19 -0
- data/lib/cognizant/process/triggers/flapping.rb +68 -0
- data/lib/cognizant/process/triggers/transition.rb +22 -0
- data/lib/cognizant/process/triggers/trigger.rb +15 -0
- data/lib/cognizant/shell.rb +142 -0
- data/lib/cognizant/system.rb +16 -0
- data/lib/cognizant/system/ps.rb +1 -1
- data/lib/cognizant/system/signal.rb +2 -2
- data/lib/cognizant/util/dsl_proxy_methods_handler.rb +25 -0
- data/lib/cognizant/util/fixnum_percent.rb +5 -0
- data/lib/cognizant/util/transform_hash_keys.rb +33 -0
- data/lib/cognizant/validations.rb +142 -142
- data/lib/cognizant/version.rb +1 -1
- metadata +131 -71
- data/README.md +0 -221
- data/examples/redis-server.rb +0 -28
- data/examples/resque.rb +0 -10
- data/images/logo-small.png +0 -0
- data/images/logo.png +0 -0
- data/images/logo.pxm +0 -0
- data/lib/cognizant/logging.rb +0 -33
- data/lib/cognizant/process/conditions/flapping.rb +0 -57
- data/lib/cognizant/process/conditions/trigger_condition.rb +0 -52
- data/lib/cognizant/server.rb +0 -14
- data/lib/cognizant/server/commands.rb +0 -80
- data/lib/cognizant/server/daemon.rb +0 -277
- data/lib/cognizant/server/interface.rb +0 -86
- data/lib/cognizant/util/symbolize_hash_keys.rb +0 -19
@@ -1,277 +0,0 @@
|
|
1
|
-
require "eventmachine"
|
2
|
-
|
3
|
-
require "cognizant"
|
4
|
-
require "cognizant/logging"
|
5
|
-
require "cognizant/process"
|
6
|
-
require "cognizant/server/interface"
|
7
|
-
require "cognizant/system"
|
8
|
-
|
9
|
-
module Cognizant
|
10
|
-
module Server
|
11
|
-
class Daemon
|
12
|
-
include Cognizant::Logging
|
13
|
-
|
14
|
-
# Whether or not to the daemon in the background.
|
15
|
-
# @return [true, false] Defaults to true
|
16
|
-
attr_accessor :daemonize
|
17
|
-
|
18
|
-
# The pid lock file for the daemon.
|
19
|
-
# e.g. /Users/Gurpartap/.cognizant/cognizantd.pid
|
20
|
-
# @return [String] Defaults to /var/run/cognizant/cognizantd.pid
|
21
|
-
attr_accessor :pidfile
|
22
|
-
|
23
|
-
# The file to log the daemon's operations information into.
|
24
|
-
# e.g. /Users/Gurpartap/.cognizant/cognizantd.log
|
25
|
-
# @return [String] Defaults to /var/log/cognizant/cognizantd.log
|
26
|
-
attr_accessor :logfile
|
27
|
-
|
28
|
-
# The level of information to log. This does not affect the log
|
29
|
-
# level of managed processes.
|
30
|
-
# @note The possible values must be one of the following:
|
31
|
-
# Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR and
|
32
|
-
# Logger::FATAL or 0, 1, 2, 3, 4 (respectively).
|
33
|
-
# @return [Logger::Severity] Defaults to Logger::INFO
|
34
|
-
attr_accessor :loglevel
|
35
|
-
|
36
|
-
# The socket lock file for the server. This file is ignored if valid
|
37
|
-
# bind address and port are given.
|
38
|
-
# e.g. /Users/Gurpartap/.cognizant/cognizant-server.sock
|
39
|
-
# @return [String] Defaults to /var/run/cognizant/cognizantd.sock
|
40
|
-
attr_accessor :socket
|
41
|
-
|
42
|
-
# The TCP address and port to start the server with. e.g. 8081,
|
43
|
-
# "127.0.0.1:8081", "0.0.0.0:8081".
|
44
|
-
# @return [String] Defaults to nil
|
45
|
-
attr_accessor :port
|
46
|
-
|
47
|
-
# Username for securing server access. e.g. "cognizant-user"
|
48
|
-
# @return [String] Defaults to nil
|
49
|
-
attr_accessor :username
|
50
|
-
|
51
|
-
# Password to accompany the username.
|
52
|
-
# e.g. "areallyverylongpasswordbecauseitmatters"
|
53
|
-
# @return [String] Defaults to nil
|
54
|
-
attr_accessor :password
|
55
|
-
|
56
|
-
# Directory to store the pid files of managed processes, when required.
|
57
|
-
# e.g. /Users/Gurpartap/.cognizant/pids/
|
58
|
-
# @return [String] Defaults to /var/run/cognizant/pids/
|
59
|
-
attr_accessor :pids_dir
|
60
|
-
|
61
|
-
# Directory to store the log files of managed processes, when required.
|
62
|
-
# e.g. /Users/Gurpartap/.cognizant/logs/
|
63
|
-
# @return [String] Defaults to /var/log/cognizant/logs/
|
64
|
-
attr_accessor :logs_dir
|
65
|
-
|
66
|
-
# Environment variables for managed processes to inherit.
|
67
|
-
# @return [Hash] Defaults to {}
|
68
|
-
attr_accessor :env
|
69
|
-
|
70
|
-
# The current working directory for the managed processes to start with.
|
71
|
-
# @return [String] Defaults to nil
|
72
|
-
attr_accessor :chdir
|
73
|
-
|
74
|
-
# Limit the permission modes for files and directories created by the
|
75
|
-
# daemon and the managed processes.
|
76
|
-
# @return [Integer] Defaults to nil
|
77
|
-
attr_accessor :umask
|
78
|
-
|
79
|
-
# Run the daemon and managed processes as the given user.
|
80
|
-
# e.g. "deploy", 1000
|
81
|
-
# @return [String] Defaults to nil
|
82
|
-
attr_accessor :user
|
83
|
-
|
84
|
-
# Run the daemon and managed processes as the given user group.
|
85
|
-
# e.g. "deploy"
|
86
|
-
# @return [String] Defaults to nil
|
87
|
-
attr_accessor :group
|
88
|
-
|
89
|
-
# Hash of processes being managed.
|
90
|
-
# @private
|
91
|
-
# @return [Hash]
|
92
|
-
attr_accessor :processes
|
93
|
-
|
94
|
-
# Initializes and starts the cognizant daemon with the given options
|
95
|
-
# as instance attributes.
|
96
|
-
# @param [Hash] options A hash of instance attributes and their values.
|
97
|
-
def initialize(options = {})
|
98
|
-
# Daemon config.
|
99
|
-
@daemonize = options.has_key?(:daemonize) ? options[:daemonize] : true
|
100
|
-
@pidfile = options[:pidfile] || "/var/run/cognizant/cognizantd.pid"
|
101
|
-
@logfile = options[:logfile] || "/var/log/cognizant/cognizantd.log"
|
102
|
-
@loglevel = options[:loglevel].to_i || Logger::INFO
|
103
|
-
@socket = options[:socket] || "/var/run/cognizant/cognizantd.sock"
|
104
|
-
@port = options[:port] || nil
|
105
|
-
@username = options[:username] || nil
|
106
|
-
@password = options[:password] || nil
|
107
|
-
@trace = options[:trace] || nil
|
108
|
-
|
109
|
-
# Processes config.
|
110
|
-
@pids_dir = options[:pids_dir] || "/var/run/cognizant/pids/"
|
111
|
-
@logs_dir = options[:logs_dir] || "/var/log/cognizant/logs/"
|
112
|
-
@env = options[:env] || {}
|
113
|
-
@chdir = options[:chdir] || nil
|
114
|
-
@umask = options[:umask] || nil
|
115
|
-
@user = options[:user] || nil
|
116
|
-
@group = options[:group] || nil
|
117
|
-
|
118
|
-
# Expand paths.
|
119
|
-
@socket = File.expand_path(@socket)
|
120
|
-
@pidfile = File.expand_path(@pidfile)
|
121
|
-
@logfile = File.expand_path(@logfile)
|
122
|
-
@pids_dir = File.expand_path(@pids_dir)
|
123
|
-
@logs_dir = File.expand_path(@logs_dir)
|
124
|
-
|
125
|
-
self.processes = Hash.new
|
126
|
-
|
127
|
-
# Only available through a config file/stdin.
|
128
|
-
load_processes(options[:monitor]) if options.has_key?(:monitor)
|
129
|
-
end
|
130
|
-
|
131
|
-
def bootup
|
132
|
-
setup_prerequisites
|
133
|
-
trap_signals
|
134
|
-
log.info "Booting up cognizantd..."
|
135
|
-
EventMachine.run do
|
136
|
-
start_interface_server
|
137
|
-
start_periodic_ticks
|
138
|
-
daemonize_process
|
139
|
-
write_pid
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def load(config_file)
|
144
|
-
config_file = File.expand_path(config_file)
|
145
|
-
log.info "Loading config from #{config_file}..."
|
146
|
-
# config = YAML.load_file(config_file)
|
147
|
-
# config = config.inject({}) { |c,(k,v)| c[k.gsub("-", "_").to_sym] = v; c }
|
148
|
-
# load_processes(config[:monitor]) if config.has_key?(:monitor)
|
149
|
-
Kernel.load(config_file)
|
150
|
-
end
|
151
|
-
|
152
|
-
def monitor(process_name = nil, attributes = {}, &block)
|
153
|
-
process = Cognizant::Process.new(process_name, attributes, &block)
|
154
|
-
self.processes[process.name] = process
|
155
|
-
process.monitor
|
156
|
-
end
|
157
|
-
|
158
|
-
# Stops the TCP server and the tick loop, and performs cleanup.
|
159
|
-
def shutdown
|
160
|
-
log.info "Shutting down cognizantd..."
|
161
|
-
EventMachine.next_tick do
|
162
|
-
EventMachine.stop
|
163
|
-
logger.close
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
private
|
168
|
-
|
169
|
-
def load_processes(processes_to_load)
|
170
|
-
if processes_to_load
|
171
|
-
processes_to_load.each do |name, attributes|
|
172
|
-
monitor(name, attributes)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Starts the TCP server with the set socket lock file or port.
|
178
|
-
def start_interface_server
|
179
|
-
stop_previous_server
|
180
|
-
if port = @port
|
181
|
-
log.info "Starting the TCP server at #{@port}..."
|
182
|
-
host = "127.0.0.1"
|
183
|
-
splitted = port.to_s.split(":")
|
184
|
-
host, port = splitted if splitted.size > 1
|
185
|
-
EventMachine.start_server(host, port, Server::Interface)
|
186
|
-
else
|
187
|
-
log.info "Starting the UNIX domain server with socket #{@socket}..."
|
188
|
-
EventMachine.start_unix_domain_server(@socket, Server::Interface)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
# Starts the loop that defines the time window for determining and acting upon process states.
|
193
|
-
def start_periodic_ticks
|
194
|
-
log.info "Starting the periodic tick..."
|
195
|
-
EventMachine.add_periodic_timer(1) do
|
196
|
-
System.reset_data
|
197
|
-
self.processes.values.map(&:tick)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def setup_prerequisites
|
202
|
-
# Create the require directories.
|
203
|
-
[File.dirname(@pidfile), File.dirname(@logfile), @pids_dir, @logs_dir, File.dirname(@socket)].each do |directory|
|
204
|
-
FileUtils.mkdir_p(directory)
|
205
|
-
end
|
206
|
-
|
207
|
-
# Setup logging.
|
208
|
-
add_log_adapter(File.open(@logfile, "a"))
|
209
|
-
add_log_adapter($stdout) unless @daemonize
|
210
|
-
log.level = if @trace then Logger::DEBUG else @loglevel end
|
211
|
-
end
|
212
|
-
|
213
|
-
def trap_signals
|
214
|
-
terminator = Proc.new do
|
215
|
-
log.info "Received signal to shutdown."
|
216
|
-
shutdown
|
217
|
-
end
|
218
|
-
|
219
|
-
Signal.trap('TERM', &terminator)
|
220
|
-
Signal.trap('INT', &terminator)
|
221
|
-
Signal.trap('QUIT', &terminator)
|
222
|
-
end
|
223
|
-
|
224
|
-
def stop_previous_server
|
225
|
-
if @pidfile and File.exists?(@pidfile)
|
226
|
-
if previous_daemon_pid = File.read(@pidfile).to_i
|
227
|
-
# Only attempt to stop automatically if the daemon will run in background.
|
228
|
-
if @daemonize and System.pid_running?(previous_daemon_pid)
|
229
|
-
# Ensure that the process stops within 5 seconds or force kill.
|
230
|
-
signals = ["TERM", "KILL"]
|
231
|
-
timeout = 2
|
232
|
-
catch :stopped do
|
233
|
-
signals.each do |stop_signal|
|
234
|
-
# Send the stop signal and wait for it to stop.
|
235
|
-
System.signal(stop_signal, previous_daemon_pid)
|
236
|
-
|
237
|
-
# Poll to see if it's stopped yet. Minimum 2 so that we check at least once again.
|
238
|
-
([timeout / signals.size, 2].max).times do
|
239
|
-
throw :stopped unless System.pid_running?(previous_daemon_pid)
|
240
|
-
sleep 1
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
# Alert the user to manually stop the previous daemon, if it is [still] alive.
|
248
|
-
if System.pid_running?(previous_daemon_pid)
|
249
|
-
raise "There is already a daemon running with pid #{previous_daemon_pid}."
|
250
|
-
else
|
251
|
-
begin
|
252
|
-
File.unlink(@pidfile) if @pidfile
|
253
|
-
rescue Errno::ENOENT
|
254
|
-
nil
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
# Daemonize the current process and save it pid in a file.
|
261
|
-
def daemonize_process
|
262
|
-
if @daemonize
|
263
|
-
log.info "Daemonizing into the background..."
|
264
|
-
::Process.daemon
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
def write_pid
|
269
|
-
pid = ::Process.pid
|
270
|
-
if @pidfile
|
271
|
-
log.info "Writing the daemon pid (#{pid}) to the pidfile..."
|
272
|
-
File.open(@pidfile, "w") { |f| f.write(pid) }
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require "eventmachine"
|
2
|
-
|
3
|
-
require "cognizant/server/commands"
|
4
|
-
|
5
|
-
module Cognizant
|
6
|
-
module Server
|
7
|
-
class Interface < EventMachine::Connection
|
8
|
-
|
9
|
-
attr_accessor :authenticated, :username, :password
|
10
|
-
|
11
|
-
def post_init
|
12
|
-
@authenticated = false
|
13
|
-
@username = nil
|
14
|
-
@password = nil
|
15
|
-
if Cognizant::Server.daemon.username and Cognizant::Server.daemon.password
|
16
|
-
post_authentication_challenge
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def receive_data(args)
|
21
|
-
if not @authenticated and (Cognizant::Server.daemon.username and Cognizant::Server.daemon.password)
|
22
|
-
return post_authentication_challenge(args.to_s)
|
23
|
-
end
|
24
|
-
|
25
|
-
args = [*args.split]
|
26
|
-
command = args.shift.to_s.strip.downcase
|
27
|
-
if command.size > 0
|
28
|
-
begin
|
29
|
-
Commands.send(command, *args) do |response|
|
30
|
-
send_data "#{response}"
|
31
|
-
end
|
32
|
-
rescue => e
|
33
|
-
send_data "#{e.message}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
close_connection_after_writing
|
37
|
-
end
|
38
|
-
|
39
|
-
def unbind
|
40
|
-
@authenticated = false
|
41
|
-
# puts "-- someone disconnected from the server!"
|
42
|
-
end
|
43
|
-
|
44
|
-
def post_authentication_challenge(data = nil)
|
45
|
-
data = data.to_s.strip
|
46
|
-
if data.to_s.size > 0
|
47
|
-
if @username
|
48
|
-
@password = data
|
49
|
-
else
|
50
|
-
@username = data
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
unless @username.to_s.size > 0
|
55
|
-
if Cognizant::Server.daemon.username and Cognizant::Server.daemon.username.size != nil
|
56
|
-
send_data "Username: "
|
57
|
-
return
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
unless @password.to_s.size > 0
|
62
|
-
if Cognizant::Server.daemon.password and Cognizant::Server.daemon.password.size != nil
|
63
|
-
send_data "Password: "
|
64
|
-
return
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
if @username and @password
|
69
|
-
validate
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def validate
|
74
|
-
@authenticated = @username == Cognizant::Server.daemon.username and @password == Cognizant::Server.daemon.password
|
75
|
-
@username = nil
|
76
|
-
@password = nil
|
77
|
-
if @authenticated
|
78
|
-
send_data "Authenticated. Welcome!\r\n\r\n"
|
79
|
-
else
|
80
|
-
send_data "Authentication failed.\r\n\r\n"
|
81
|
-
post_authentication_challenge
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Destructively convert all keys by using the block operation.
|
3
|
-
# This includes the keys from the root hash and from all
|
4
|
-
# nested hashes.
|
5
|
-
def deep_transform_keys!(&block)
|
6
|
-
keys.each do |key|
|
7
|
-
value = delete(key)
|
8
|
-
self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
|
9
|
-
end
|
10
|
-
self
|
11
|
-
end
|
12
|
-
|
13
|
-
# Destructively convert all keys to symbols, as long as they respond
|
14
|
-
# to +to_sym+. This includes the keys from the root hash and from all
|
15
|
-
# nested hashes.
|
16
|
-
def deep_symbolize_keys!
|
17
|
-
deep_transform_keys!{ |key| key.to_sym rescue key }
|
18
|
-
end
|
19
|
-
end
|