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.
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