cognizant 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +4 -1
  5. data/{LICENSE → License.md} +4 -2
  6. data/Rakefile +5 -0
  7. data/Readme.md +95 -0
  8. data/bin/cognizant +76 -122
  9. data/bin/cognizantd +28 -61
  10. data/cognizant.gemspec +8 -4
  11. data/examples/apps/redis-server.cz +42 -0
  12. data/examples/apps/redis-server.yml +29 -0
  13. data/examples/apps/redis-server_dsl.cz +54 -0
  14. data/examples/apps/resque.cz +17 -0
  15. data/examples/apps/thin.cz +32 -0
  16. data/examples/apps/thin.yml +48 -0
  17. data/examples/cognizantd.yml +18 -47
  18. data/features/child_process.feature +62 -0
  19. data/features/commands.feature +65 -0
  20. data/features/cpu_usage.feature +45 -0
  21. data/features/daemon.feature +12 -0
  22. data/features/flapping.feature +39 -0
  23. data/features/memory_usage.feature +45 -0
  24. data/features/shell.feature +30 -0
  25. data/features/step_definitions/common_steps.rb +14 -0
  26. data/features/step_definitions/daemon_steps.rb +25 -0
  27. data/features/step_definitions/shell_steps.rb +96 -0
  28. data/features/support/env.rb +54 -0
  29. data/lib/cognizant.rb +1 -5
  30. data/lib/cognizant/application.rb +122 -0
  31. data/lib/cognizant/application/dsl_proxy.rb +23 -0
  32. data/lib/cognizant/client.rb +61 -0
  33. data/lib/cognizant/commands.rb +164 -0
  34. data/lib/cognizant/commands/actions.rb +30 -0
  35. data/lib/cognizant/commands/help.rb +10 -0
  36. data/lib/cognizant/commands/load.rb +10 -0
  37. data/lib/cognizant/commands/shutdown.rb +7 -0
  38. data/lib/cognizant/commands/status.rb +11 -0
  39. data/lib/cognizant/commands/use.rb +15 -0
  40. data/lib/cognizant/controller.rb +17 -0
  41. data/lib/cognizant/daemon.rb +279 -0
  42. data/lib/cognizant/interface.rb +17 -0
  43. data/lib/cognizant/log.rb +25 -0
  44. data/lib/cognizant/process.rb +138 -94
  45. data/lib/cognizant/process/actions.rb +30 -41
  46. data/lib/cognizant/process/actions/restart.rb +73 -17
  47. data/lib/cognizant/process/actions/start.rb +35 -12
  48. data/lib/cognizant/process/actions/stop.rb +38 -17
  49. data/lib/cognizant/process/attributes.rb +41 -10
  50. data/lib/cognizant/process/children.rb +36 -0
  51. data/lib/cognizant/process/{condition_check.rb → condition_delegate.rb} +11 -13
  52. data/lib/cognizant/process/conditions.rb +7 -4
  53. data/lib/cognizant/process/conditions/cpu_usage.rb +5 -6
  54. data/lib/cognizant/process/conditions/memory_usage.rb +2 -6
  55. data/lib/cognizant/process/dsl_proxy.rb +23 -0
  56. data/lib/cognizant/process/execution.rb +16 -9
  57. data/lib/cognizant/process/pid.rb +16 -6
  58. data/lib/cognizant/process/status.rb +14 -2
  59. data/lib/cognizant/process/trigger_delegate.rb +57 -0
  60. data/lib/cognizant/process/triggers.rb +19 -0
  61. data/lib/cognizant/process/triggers/flapping.rb +68 -0
  62. data/lib/cognizant/process/triggers/transition.rb +22 -0
  63. data/lib/cognizant/process/triggers/trigger.rb +15 -0
  64. data/lib/cognizant/shell.rb +142 -0
  65. data/lib/cognizant/system.rb +16 -0
  66. data/lib/cognizant/system/ps.rb +1 -1
  67. data/lib/cognizant/system/signal.rb +2 -2
  68. data/lib/cognizant/util/dsl_proxy_methods_handler.rb +25 -0
  69. data/lib/cognizant/util/fixnum_percent.rb +5 -0
  70. data/lib/cognizant/util/transform_hash_keys.rb +33 -0
  71. data/lib/cognizant/validations.rb +142 -142
  72. data/lib/cognizant/version.rb +1 -1
  73. metadata +131 -71
  74. data/README.md +0 -221
  75. data/examples/redis-server.rb +0 -28
  76. data/examples/resque.rb +0 -10
  77. data/images/logo-small.png +0 -0
  78. data/images/logo.png +0 -0
  79. data/images/logo.pxm +0 -0
  80. data/lib/cognizant/logging.rb +0 -33
  81. data/lib/cognizant/process/conditions/flapping.rb +0 -57
  82. data/lib/cognizant/process/conditions/trigger_condition.rb +0 -52
  83. data/lib/cognizant/server.rb +0 -14
  84. data/lib/cognizant/server/commands.rb +0 -80
  85. data/lib/cognizant/server/daemon.rb +0 -277
  86. data/lib/cognizant/server/interface.rb +0 -86
  87. 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