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
@@ -4,9 +4,10 @@ require File.expand_path('../lib/cognizant/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Gurpartap Singh"]
6
6
  gem.email = ["contact@gurpartap.com"]
7
- gem.description = "Cognizant is a process management system utility that supervises your processes, ensuring their state based on a flexible criteria."
8
- gem.summary = "Cognizant is a process management system utility that supervises your processes, ensuring their state based on a flexible criteria."
7
+ gem.description = "Cognizant is a process management framework inspired from God and Bluepill. It supervises your processes, ensuring their state based on a flexible criteria."
8
+ gem.summary = "Cognizant is a process management framework inspired from God and Bluepill. It supervises your processes, ensuring their state based on a flexible criteria."
9
9
  gem.homepage = "http://github.com/Gurpartap/cognizant"
10
+ gem.license = "MIT"
10
11
 
11
12
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
13
  gem.files = `git ls-files`.split("\n")
@@ -16,15 +17,18 @@ Gem::Specification.new do |gem|
16
17
  gem.version = Cognizant::VERSION
17
18
 
18
19
  gem.add_development_dependency "rake"
19
- gem.add_development_dependency "redcarpet"
20
+ gem.add_development_dependency "ruby-graphviz"
20
21
  gem.add_development_dependency "yard"
22
+ gem.add_development_dependency "kramdown"
23
+ gem.add_development_dependency "aruba"
21
24
 
22
25
  # cognizantd
23
26
  gem.add_dependency "eventmachine"
24
27
  gem.add_dependency "state_machine"
25
28
  gem.add_dependency "activesupport"
29
+ gem.add_dependency "logging"
26
30
 
27
31
  # cognizant
28
- gem.add_dependency "gli"
32
+ gem.add_dependency "commander"
29
33
  gem.add_dependency "formatador"
30
34
  end
@@ -0,0 +1,42 @@
1
+ Cognizant.application("redis-example") do |app|
2
+ app.pids_dir = "~/.cognizant/redis-example/pids/"
3
+ app.logs_dir = "~/.cognizant/redis-example/logs/"
4
+
5
+ # 2 slave instances to master at port 6000.
6
+ 3.times do |i|
7
+ app.monitor("redis-server-600#{i}") do |process|
8
+ process.autostart = true
9
+ # process.name = "redis-server-600#{i}" # Same thing as above.
10
+ process.group = "redis"
11
+ # process.uid = "redis"
12
+ # process.gid = "redis"
13
+ process.start_command = "redis-server -"
14
+ process.ping_command = "redis-cli -p 600#{i} PING"
15
+
16
+ process.daemonize!
17
+ slaveof = i == 0 ? "" : "slaveof 127.0.0.1 6000"
18
+ process.start_with_input = <<-heredoc
19
+ daemonize no
20
+ port 600#{i}
21
+ #{slaveof}
22
+ heredoc
23
+
24
+ # process.check(:always_true, :every => 2.seconds, :times => 3) do |p|
25
+ # `say "Boom!"`
26
+ # end
27
+
28
+ process.check(:transition, :from => :running, :to => :stopped) do |p|
29
+ `say --rate 250 "A process has stopped!"`
30
+ end
31
+
32
+ # :retry_after => 0 means do not retry.
33
+ process.check(:flapping, :times => 5, :within => 30.seconds, :retry_after => 7.seconds)
34
+
35
+ process.check(:cpu_usage, :every => 5.seconds, :above => 60.percent, :times => [3, 5], :do => :restart)
36
+ process.check(:memory_usage, :every => 5.seconds, :above => 100.megabytes, :times => [3, 5]) do |p|
37
+ # Send email or something.
38
+ p.restart # Restart is the default anyways.
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ defaults: &defaults
2
+ autostart: false
3
+ group: redis
4
+ start_command: /usr/local/bin/redis-server -
5
+ stop_signals: [TERM, INT]
6
+ checks:
7
+ cpu_usage:
8
+ every: 3
9
+ above: 60
10
+ times: 3
11
+ do: restart
12
+ memory_usage:
13
+ every: 5 # Seconds.
14
+ above: 1220608 # Bytes.
15
+ times: [3, 5] # Three out of five times.
16
+ do: stop # Defaults to restart.
17
+
18
+ applications:
19
+ example:
20
+ monitor:
21
+ redis-server-6666:
22
+ <<: *defaults
23
+ start_with_input: "daemonize no\nport 6666"
24
+ ping_command: redis-cli -p 6666 PING
25
+ redis-server-7777:
26
+ <<: *defaults
27
+ start_with_input: "daemonize no\nport 7777"
28
+ ping_command: redis-cli -p 7777 PING
29
+ stop_command: redis-cli -p 7777 SHUTDOWN
@@ -0,0 +1,54 @@
1
+ # Cognizant.application "redis-example-dsl" do
2
+ # pids_dir "~/.cognizant/redis-example-dsl/pids/"
3
+ # logs_dir "~/.cognizant/redis-example-dsl/logs/"
4
+ #
5
+ # monitor "redis-server-7000" do
6
+ # autostart!
7
+ # group "redis"
8
+ # start_command "/usr/local/bin/redis-server -"
9
+ # start_with_input "daemonize no\nport 6666"
10
+ # ping_command "redis-cli -p 6666 PING"
11
+ # end
12
+ # end
13
+
14
+ # Not using dsl for app to use some Ruby in the immediate block.
15
+ Cognizant.application "redis-example-dsl" do |app|
16
+ app.pids_dir = "~/.cognizant/redis-example-dsl/pids/"
17
+ app.logs_dir = "~/.cognizant/redis-example-dsl/logs/"
18
+
19
+ # 2 slave instances to master at port 7000.
20
+ 3.times do |i|
21
+ slaveof = i == 0 ? "" : "slaveof 127.0.0.1 7000" # Any custom code has to be outside the monitor block.
22
+
23
+ app.monitor do
24
+ autostart!
25
+ name "redis-server-700#{i}"
26
+ group "redis"
27
+ start_command "redis-server -"
28
+ ping_command "redis-cli -p 700#{i} PING"
29
+
30
+ daemonize!
31
+ start_with_input <<-heredoc
32
+ daemonize no
33
+ port 700#{i}
34
+ #{slaveof}
35
+ heredoc
36
+
37
+ # check :always_true, :every => 2.seconds, :times => 3 do |p|
38
+ # `say "Boom!"`
39
+ # end
40
+
41
+ check :transition, :from => :running, :to => :stopped do
42
+ `say --rate 250 "A process has stopped!"`
43
+ end
44
+
45
+ check :flapping, :times => 5, :within => 30.seconds, :retry_after => 7.seconds
46
+
47
+ check :cpu_usage, :every => 3.seconds, :above => 60.percent, :times => 3, :do => :restart
48
+ check :memory_usage, :every => 5.seconds, :above => 100.megabytes, :times => [3, 5] do |p|
49
+ # Send email or something.
50
+ p.restart # Restart is the default anyways.
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ Cognizant.application("my-web-app") do |app|
2
+ 5.times do |i|
3
+ app.monitor "resque-worker-#{i}" do |process|
4
+ process.group = "resque"
5
+ process.uid = "deploy"
6
+ process.gid = "deploy"
7
+ process.chdir = "/apps/example/current/"
8
+ process.env = { "QUEUE" => "*", "RACK_ENV" => "production" }
9
+ process.start_command = "bundle exec rake resque:work"
10
+
11
+ process.monitor_children do
12
+ check :memory_usage, :every => 5.seconds, :above => 100.megabytes, :times => [2, 3], :do => :stop
13
+ stop_signals ["TERM", "INT", "KILL"]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ app_root = "/apps/acmecorp.com"
2
+ servers = 5
3
+ port = 4000
4
+
5
+ Cognizant.application "acmecorp.com" do |app|
6
+ servers.times do |n|
7
+ app.monitor "thin-#{n}" do
8
+ # autostart!
9
+ group "thin"
10
+ uid "www-data"
11
+ gid "www-data"
12
+
13
+ env RACK_ENV: "production"
14
+ chdir "#{app_root}/current"
15
+
16
+ daemonize false
17
+ pidfile "#{app_root}/shared/tmp/pids/thin.400#{n}.pid"
18
+
19
+ start_command "bundle exec thin start --only #{n} --servers #{servers} --port #{port}"
20
+ stop_command "bundle exec thin stop --only #{n} --servers #{servers} --port #{port}"
21
+ restart_command "bundle exec thin restart --only #{n} --servers #{servers} --port #{port}"
22
+
23
+ check :flapping, times: 3, within: 1.minute, retry_after: 15.seconds, retries: 10
24
+ check :transition, from: :running, to: :stopped do |process|
25
+ `say a thin server has stopped` # send an email, etc.
26
+ end
27
+
28
+ check :cpu_usage, above: 50.percent, every: 5.seconds, times: 5, do: :restart
29
+ check :memory_usage, above: 300.megabytes, every: 5.seconds, times: [3, 5], do: :restart
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ thin: &thin
2
+ # autostart: true
3
+ group: thin
4
+ uid: www-data
5
+ gid: www-data
6
+ env:
7
+ RACK_ENV: production
8
+ chdir: /apps/acmecorp.com/current
9
+ daemonize: false
10
+ checks:
11
+ flapping:
12
+ times: 3
13
+ within: 1
14
+ retry_after: 15
15
+ retries: 10
16
+ # transition trigger is not useful in YAML config as blocks are not possible
17
+ cpu_usage:
18
+ above: 50
19
+ every: 5
20
+ times: 5
21
+ do: stop
22
+ memory_usage:
23
+ above: 314572800 # 300 megabytes in bytes
24
+ every: 5
25
+ times: [3, 5]
26
+ do: stop
27
+
28
+ applications:
29
+ acmecorp.com:
30
+ monitor:
31
+ thin-0:
32
+ <<: *thin
33
+ start_command: bundle exec thin start --only 0 --servers 3 --port 5000
34
+ stop_command: bundle exec thin stop --only 0 --servers 3 --port 5000
35
+ restart_command: bundle exec thin restart --only 0 --servers 3 --port 5000
36
+ pidfile: /apps/acmecorp.com/shared/tmp/pids/thin.5000.pid
37
+ thin-1:
38
+ <<: *thin
39
+ start_command: bundle exec thin start --only 1 --servers 3 --port 5000
40
+ stop_command: bundle exec thin stop --only 1 --servers 3 --port 5000
41
+ restart_command: bundle exec thin restart --only 1 --servers 3 --port 5000
42
+ pidfile: /apps/acmecorp.com/shared/tmp/pids/thin.5001.pid
43
+ thin-2:
44
+ <<: *thin
45
+ start_command: bundle exec thin start --only 2 --servers 3 --port 5000
46
+ stop_command: bundle exec thin stop --only 2 --servers 3 --port 5000
47
+ restart_command: bundle exec thin restart --only 2 --servers 3 --port 5000
48
+ pidfile: /apps/acmecorp.com/shared/tmp/pids/thin.5002.pid
@@ -1,50 +1,21 @@
1
1
  ---
2
2
  daemonize: false
3
- pidfile: ~/.cognizant/cognizantd.pid
4
- logfile: ~/.cognizant/cognizantd.log
5
- socket: ~/.cognizant/cognizantd.sock
6
- pids_dir: ~/.cognizant/pids/
7
- logs_dir: ~/.cognizant/logs/
3
+ loglevel: debug
8
4
 
9
- monitor: {
10
- redis-server-1: {
11
- autostart: false,
12
- group: redis,
13
- start_command: /usr/local/bin/redis-server -,
14
- start_with_input: "daemonize no\nport 6666",
15
- ping_command: redis-cli -p 6666 PING,
16
- stop_signals: [TERM, INT],
17
- checks: {
18
- cpu_usage: {
19
- every: 3,
20
- above: 60,
21
- times: 3,
22
- do: restart
23
- },
24
- memory_usage: {
25
- every: 5, # Seconds.
26
- above: 1220608, # Bytes.
27
- times: [3, 5], # Three out of five times.
28
- do: stop # Defaults to restart.
29
- }
30
- }
31
- },
32
- redis-server-2: {
33
- autostart: false,
34
- group: redis,
35
- start_command: /usr/local/bin/redis-server -,
36
- start_with_input: "daemonize no\nport 7777",
37
- ping_command: redis-cli -p 7777 PING,
38
- stop_command: redis-cli -p 7777 SHUTDOWN
39
- },
40
- sleep: {
41
- start_command: sleep 3,
42
- checks: {
43
- flapping: {
44
- times: 4,
45
- within: 15, # Seconds.
46
- retry_after: 30 # Seconds.
47
- }
48
- }
49
- }
50
- }
5
+ load:
6
+ - ./examples/apps/*.cz
7
+ - ./examples/apps/*.yml
8
+
9
+ applications:
10
+ sleep-example:
11
+ monitor:
12
+ sleep:
13
+ autostart: false
14
+ start_command: sleep 3
15
+ uid: nobody
16
+ gid: nobody
17
+ checks:
18
+ flapping:
19
+ times: 4
20
+ within: 15 # seconds.
21
+ retry_after: 30 # seconds.
@@ -0,0 +1,62 @@
1
+ Feature: Child Process
2
+
3
+ Forks (children) of a process can be checked for conditions and triggers
4
+ similar to their parent process.
5
+
6
+ Background:
7
+ Given a file named "fork_machine.rb" with:
8
+ """ruby
9
+ require 'timeout'
10
+ $0 = File.basename(__FILE__) # Useful identification when debugging.
11
+ children = []
12
+ Signal.trap('TERM') do
13
+ children.each do |child|
14
+ Process.kill('INT', child)
15
+ end
16
+ end
17
+ children << fork do
18
+ Signal.trap 'INT' do
19
+ exit
20
+ end
21
+ data = ''
22
+ Timeout::timeout(60) do
23
+ loop do
24
+ data += '*' * 100
25
+ end
26
+ end
27
+ data = nil
28
+ end
29
+ Process.waitall
30
+ """
31
+ Given a file named "monitor.cz" with:
32
+ """ruby
33
+ Cognizant.application 'child_process_app' do
34
+ pids_dir './cognizant/pids/'
35
+ logs_dir './cognizant/logs/'
36
+ monitor 'fork_machine' do
37
+ autostart false
38
+ daemonize!
39
+ start_command 'ruby ./fork_machine.rb'
40
+ stop_signals ['TERM']
41
+ monitor_children do
42
+ check :memory_usage, :every => 2.seconds, :above => 10.megabytes, :times => 3, :do => :stop
43
+ stop_signals ['INT']
44
+ end
45
+ end
46
+ end
47
+ """
48
+
49
+ @daemon
50
+ @shell
51
+ Scenario: Check child process memory usage
52
+ Given the daemon is running
53
+ And the shell is running
54
+
55
+ When I run "load monitor.cz" successfully in the shell
56
+ And I run "use child_process_app" successfully in the shell
57
+ Then the status of "fork_machine" should be "stopped"
58
+
59
+ When I run "start fork_machine" successfully in the shell
60
+ Then the status of "fork_machine" should be "running"
61
+
62
+ And the status of "fork_machine" should be "stopped"
@@ -0,0 +1,65 @@
1
+ Feature: Commands
2
+
3
+ Cognizant provides a number of commands to maually change the state of a
4
+ process as a part of its maintenance.
5
+
6
+ Background:
7
+ Given a file named "sleep_process.cz" with:
8
+ """ruby
9
+ Cognizant.application 'sleep_app' do
10
+ pids_dir './cognizant/pids/'
11
+ logs_dir './cognizant/logs/'
12
+ monitor 'sleep_process' do
13
+ autostart false
14
+ daemonize!
15
+ start_command 'sleep 60'
16
+ end
17
+ end
18
+ """
19
+
20
+ @daemon
21
+ @shell
22
+ Scenario: Run all maintenance commands for a sample sleep process
23
+ Given the daemon is running
24
+ And the shell is running
25
+
26
+ When I run "load sleep_process.cz" successfully in the shell
27
+ And I run "use sleep_app" successfully in the shell
28
+ Then the status of "sleep_process" is "stopped"
29
+
30
+ When I run "start sleep_process" successfully in the shell
31
+ Then the status of "sleep_process" should be "running"
32
+
33
+ When I run "stop sleep_process" successfully in the shell
34
+ Then the status of "sleep_process" should be "stopped"
35
+
36
+ When I run "restart sleep_process" successfully in the shell
37
+ Then the status of "sleep_process" should be "running"
38
+
39
+ When I run "unmonitor sleep_process" successfully in the shell
40
+ Then the status of "sleep_process" should be "unmonitored"
41
+
42
+ When I run "monitor sleep_process" successfully in the shell
43
+ Then the status of "sleep_process" should be "running"
44
+
45
+ When I run "stop sleep_process" successfully in the shell
46
+ Then the status of "sleep_process" should be "stopped"
47
+
48
+ @daemon
49
+ @shell
50
+ Scenario: Run the help command
51
+ Given the daemon is running
52
+ And the shell is running
53
+
54
+ When I run "help" in the shell
55
+ Then I should see "You can run the following commands" in the shell
56
+
57
+ @daemon
58
+ @shell
59
+ Scenario: Shut down the daemon via command
60
+ Given the daemon is running
61
+ And the shell is running
62
+
63
+ When I run "shutdown" in the shell
64
+ Then I should see "The daemon has been shutdown successfuly." in the shell
65
+ And a process named "cognizantd" should not be running