eye 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -17
  3. data/bin/eye +5 -0
  4. data/examples/notify.eye +18 -0
  5. data/examples/process_thin.rb +29 -0
  6. data/examples/sidekiq.eye +5 -1
  7. data/examples/test.eye +24 -17
  8. data/examples/thin-farm.eye +29 -0
  9. data/examples/unicorn.eye +2 -0
  10. data/eye.gemspec +1 -1
  11. data/lib/eye.rb +1 -1
  12. data/lib/eye/checker.rb +3 -5
  13. data/lib/eye/checker/http.rb +1 -2
  14. data/lib/eye/checker/socket.rb +2 -2
  15. data/lib/eye/controller/commands.rb +2 -0
  16. data/lib/eye/controller/send_command.rb +8 -2
  17. data/lib/eye/dsl.rb +1 -0
  18. data/lib/eye/dsl/opts.rb +36 -2
  19. data/lib/eye/dsl/pure_opts.rb +17 -39
  20. data/lib/eye/{checker → dsl}/validation.rb +15 -5
  21. data/lib/eye/group.rb +13 -4
  22. data/lib/eye/group/chain.rb +11 -0
  23. data/lib/eye/notify.rb +1 -1
  24. data/lib/eye/notify/mail.rb +1 -1
  25. data/lib/eye/process/child.rb +0 -2
  26. data/lib/eye/process/commands.rb +11 -14
  27. data/lib/eye/process/monitor.rb +10 -16
  28. data/lib/eye/process/scheduler.rb +8 -3
  29. data/lib/eye/process/states.rb +1 -2
  30. data/lib/eye/process/system.rb +38 -7
  31. data/lib/eye/process/watchers.rb +3 -3
  32. data/lib/eye/settings.rb +1 -1
  33. data/lib/eye/system.rb +33 -16
  34. data/lib/eye/trigger.rb +1 -1
  35. data/lib/eye/utils/celluloid_chain.rb +2 -0
  36. data/spec/checker/cpu_spec.rb +1 -1
  37. data/spec/checker/http_spec.rb +2 -2
  38. data/spec/checker/memory_spec.rb +2 -2
  39. data/spec/checker_spec.rb +1 -1
  40. data/spec/controller/controller_spec.rb +6 -0
  41. data/spec/controller/find_objects_spec.rb +6 -0
  42. data/spec/controller/intergration_spec.rb +24 -0
  43. data/spec/dsl/checks_spec.rb +2 -2
  44. data/spec/dsl/notify_spec.rb +12 -3
  45. data/spec/dsl/with_server_spec.rb +26 -2
  46. data/spec/process/checks/child_checks_spec.rb +1 -1
  47. data/spec/process/checks/memory_spec.rb +14 -0
  48. data/spec/process/scheduler_spec.rb +8 -0
  49. data/spec/process/system_spec.rb +27 -4
  50. data/spec/spec_helper.rb +3 -1
  51. data/spec/system_spec.rb +12 -5
  52. data/spec/utils/celluloid_chain_spec.rb +8 -0
  53. metadata +8 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1592106a2ce3c26da8ad55f6b0036b10e5932fc
4
- data.tar.gz: ff73a4ae40c4eeef57e9c50df0e50e8220eb187f
3
+ metadata.gz: ec5135b6c531e9451f98ec8b9d36a54d2e57e3f9
4
+ data.tar.gz: fd8011e705ee96d0d24dffbe03be598a18b285c4
5
5
  SHA512:
6
- metadata.gz: b81127c859a0e48c6a08b7109582cddcdb12731b93eca191ae3fe65289703075e32c53f3552db24fcca3d693e61ada93ca7bfcae1bed4488724c54918ed6c880
7
- data.tar.gz: 22e769a89a91343374045e502404f2fa26002f9a641807d4f772354774a3f88837cf486afb18da4880738548d9b8522f0c865e2b9c8ed2ae6cc9757d3da1ea78
6
+ metadata.gz: 59237be9adb524bdc90ddb9203d3246e7e6fc03f4b9c7398df2380fba2423e68592a996ac720ff04cd8a813b34ed8a27a1c259421907dd1103b18ad508c9decd
7
+ data.tar.gz: b741a332f8888e3f5a2dd50af91e0dbafebed8f8dcc406f9f8cab270b565f3ce2624adef2e4b9c2b3be0a01ff18dcbaf28159d4ba55b6d532e37711b8c9fa5cd
data/README.md CHANGED
@@ -14,26 +14,31 @@ Config example, shows some typical processes and most of the options (see in exa
14
14
 
15
15
  examples/test.eye
16
16
  ```ruby
17
- Eye.load("./eye/*.rb") # load submodules
17
+ # load submodules, here just for example
18
+ Eye.load("./eye/*.rb")
18
19
 
20
+ # Eye self-configuration section
19
21
  Eye.config do
20
- logger "/tmp/eye.log" # eye logger
21
- logger_level Logger::DEBUG
22
+ logger "/tmp/eye.log"
22
23
  end
23
24
 
25
+ # Adding application
24
26
  Eye.application "test" do
27
+ # All options inherits down to the config leafs.
28
+ # except `env`, which merging down
29
+
25
30
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
26
31
  stdall "trash.log" # stdout,err logs for processes by default
27
32
  env "APP_ENV" => "production" # global env for each processes
28
- triggers :flapping, :times => 10, :within => 1.minute
33
+ triggers :flapping, :times => 10, :within => 1.minute #
34
+ checks :cpu, :below => 100, :times => 3 # global check for all processes
29
35
 
30
36
  group "samples" do
31
- env "A" => "1" # merging to app env
32
- chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
37
+ chain :grace => 5.seconds # chained start-restart with 5s interval, one by one.
33
38
 
34
39
  # eye daemonized process
35
- process("sample1") do
36
- pid_file "1.pid" # will be expanded with working_dir
40
+ process :sample1 do
41
+ pid_file "1.pid" # pid_path will be expanded with the working_dir
37
42
  start_command "ruby ./sample.rb"
38
43
  daemonize true
39
44
  stdall "sample1.log"
@@ -42,7 +47,7 @@ Eye.application "test" do
42
47
  end
43
48
 
44
49
  # self daemonized process
45
- process("sample2") do
50
+ process :sample2 do
46
51
  pid_file "2.pid"
47
52
  start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
48
53
  stop_command "kill -9 {PID}"
@@ -52,7 +57,7 @@ Eye.application "test" do
52
57
  end
53
58
 
54
59
  # daemon with 3 childs
55
- process("forking") do
60
+ process :forking do
56
61
  pid_file "forking.pid"
57
62
  start_command "ruby ./forking.rb start"
58
63
  stop_command "ruby forking.rb stop"
@@ -67,17 +72,19 @@ Eye.application "test" do
67
72
  end
68
73
  end
69
74
 
75
+ # eventmachine process, daemonized with eye
70
76
  process :event_machine do |p|
71
- p.pid_file = 'em.pid'
72
- p.start_command = 'ruby em.rb'
73
- p.stdout = 'em.log'
74
- p.daemonize = true
75
- p.stop_signals = [:QUIT, 2.seconds, :KILL]
77
+ pid_file 'em.pid'
78
+ start_command 'ruby em.rb'
79
+ stdout 'em.log'
80
+ daemonize true
81
+ stop_signals [:QUIT, 2.seconds, :KILL]
76
82
 
77
- p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
78
- :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
83
+ checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
84
+ :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
79
85
  end
80
86
 
87
+ # thin process, self daemonized
81
88
  process :thin do
82
89
  pid_file "thin.pid"
83
90
  start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
data/bin/eye CHANGED
@@ -78,6 +78,11 @@ class Cli < Thor
78
78
  send_command(:signal, sig, *targets)
79
79
  end
80
80
 
81
+ desc "break TARGET[,...]", "break group chain executing"
82
+ def break(*targets)
83
+ send_command(:break_chain, *targets)
84
+ end
85
+
81
86
  desc "trace [TARGET]", "tracing log for app,group or process"
82
87
  def trace(target = "")
83
88
  log_trace(target)
@@ -0,0 +1,18 @@
1
+ # Notify example
2
+
3
+ Eye.config do
4
+ mail :host => "mx.some.host", :port => 25, :domain => "some.host"
5
+ contact :errors, :mail, 'error@some.host'
6
+ contact :dev, :mail, 'dev@some.host'
7
+ end
8
+
9
+ Eye.application :some do
10
+ notify :errors
11
+
12
+ process :some_process do
13
+ notify :dev, :warn
14
+
15
+ ...
16
+ end
17
+
18
+ end
@@ -0,0 +1,29 @@
1
+
2
+ def thin(proxy, port)
3
+ name = "thin-#{port}"
4
+
5
+ opts = [
6
+ "-l thins.log",
7
+ "-p #{port}",
8
+ "-P #{name}.pid",
9
+ "-d",
10
+ "-R thin.ru",
11
+ "--tag #{proxy.app.name}.#{proxy.name}",
12
+ "-t 60",
13
+ "-e #{proxy.env["RAILS_ENV"]}",
14
+ "-c #{proxy.working_dir}",
15
+ "-a 127.0.0.1"
16
+ ]
17
+
18
+ proxy.process(name) do
19
+ pid_file "#{name}.pid"
20
+
21
+ start_command "#{BUNDLE} exec thin start #{opts * ' '}"
22
+ stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
23
+
24
+ stdall "thin.stdall.log"
25
+
26
+ checks :http, :url => "http://127.0.0.1:#{port}/hello", :pattern => /World/,
27
+ :every => 5.seconds, :times => [2, 3], :timeout => 1.second
28
+ end
29
+ end
@@ -1,6 +1,10 @@
1
+ # Example: how to run sidekiq daemon
2
+
1
3
  def sidekiq_process(proxy, name)
4
+ rails_env = proxy.env['RAILS_ENV']
5
+
2
6
  proxy.process(name) do
3
- start_command "ruby ./bin/sidekiq -e #{proxy.env['RAILS_ENV']} -C ./config/sidekiq.#{proxy.env['RAILS_ENV']}.yml"
7
+ start_command "ruby ./bin/sidekiq -e #{rails_env} -C ./config/sidekiq.#{rails_env}.yml"
4
8
  pid_file "tmp/pids/#{name}.pid"
5
9
  stdall "log/#{name}.log"
6
10
  daemonize true
@@ -1,23 +1,28 @@
1
- Eye.load("./eye/*.rb") # load submodules
1
+ # load submodules, here just for example
2
+ Eye.load("./eye/*.rb")
2
3
 
4
+ # Eye self-configuration section
3
5
  Eye.config do
4
- logger "/tmp/eye.log" # eye logger
5
- logger_level Logger::DEBUG
6
+ logger "/tmp/eye.log"
6
7
  end
7
8
 
9
+ # Adding application
8
10
  Eye.application "test" do
11
+ # All options inherits down to the config leafs.
12
+ # except `env`, which merging down
13
+
9
14
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
10
15
  stdall "trash.log" # stdout,err logs for processes by default
11
16
  env "APP_ENV" => "production" # global env for each processes
12
- triggers :flapping, :times => 10, :within => 1.minute
17
+ triggers :flapping, :times => 10, :within => 1.minute #
18
+ checks :cpu, :below => 100, :times => 3 # global check for all processes
13
19
 
14
20
  group "samples" do
15
- env "A" => "1" # merging to app env
16
- chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
21
+ chain :grace => 5.seconds # chained start-restart with 5s interval, one by one.
17
22
 
18
23
  # eye daemonized process
19
- process("sample1") do
20
- pid_file "1.pid" # will be expanded with working_dir
24
+ process :sample1 do
25
+ pid_file "1.pid" # pid_path will be expanded with the working_dir
21
26
  start_command "ruby ./sample.rb"
22
27
  daemonize true
23
28
  stdall "sample1.log"
@@ -26,7 +31,7 @@ Eye.application "test" do
26
31
  end
27
32
 
28
33
  # self daemonized process
29
- process("sample2") do
34
+ process :sample2 do
30
35
  pid_file "2.pid"
31
36
  start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
32
37
  stop_command "kill -9 {PID}"
@@ -36,7 +41,7 @@ Eye.application "test" do
36
41
  end
37
42
 
38
43
  # daemon with 3 childs
39
- process("forking") do
44
+ process :forking do
40
45
  pid_file "forking.pid"
41
46
  start_command "ruby ./forking.rb start"
42
47
  stop_command "ruby forking.rb stop"
@@ -51,17 +56,19 @@ Eye.application "test" do
51
56
  end
52
57
  end
53
58
 
59
+ # eventmachine process, daemonized with eye
54
60
  process :event_machine do |p|
55
- p.pid_file = 'em.pid'
56
- p.start_command = 'ruby em.rb'
57
- p.stdout = 'em.log'
58
- p.daemonize = true
59
- p.stop_signals = [:QUIT, 2.seconds, :KILL]
61
+ pid_file 'em.pid'
62
+ start_command 'ruby em.rb'
63
+ stdout 'em.log'
64
+ daemonize true
65
+ stop_signals [:QUIT, 2.seconds, :KILL]
60
66
 
61
- p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
62
- :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
67
+ checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
68
+ :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
63
69
  end
64
70
 
71
+ # thin process, self daemonized
65
72
  process :thin do
66
73
  pid_file "thin.pid"
67
74
  start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
@@ -0,0 +1,29 @@
1
+ RUBY = 'ruby'
2
+ BUNDLE = 'bundle'
3
+
4
+ Eye.load("process_thin.rb")
5
+
6
+ Eye.config do
7
+ logger "/tmp/eye.log"
8
+ end
9
+
10
+ Eye.app 'thin-farm' do
11
+ working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
12
+ env "RAILS_ENV" => "production"
13
+
14
+ stop_on_delete true # this option means, when we change pids and load config,
15
+ # deleted processes will be stops
16
+
17
+ triggers :flapping, :times => 10, :within => 1.minute
18
+ checks :memory, :below => 60.megabytes, :every => 30.seconds, :times => 5
19
+
20
+ group :web do
21
+ chain :action => :restart, :grace => 5.seconds
22
+ chain :action => :start, :grace => 0.2.seconds
23
+
24
+ (5555..5560).each do |port|
25
+ thin self, port
26
+ end
27
+ end
28
+
29
+ end
@@ -1,3 +1,5 @@
1
+ # Example: now to run unicorn, and monitor its childs processes
2
+
1
3
  RUBY = '/usr/local/ruby/1.9.3/bin/ruby' # ruby on the server
2
4
  RAILS_ENV = 'production'
3
5
 
@@ -32,7 +32,7 @@ Gem::Specification.new do |gem|
32
32
  gem.add_development_dependency 'ruby-graphviz'
33
33
  gem.add_development_dependency 'forking'
34
34
  gem.add_development_dependency 'fakeweb'
35
- gem.add_development_dependency 'eventmachine'
35
+ gem.add_development_dependency 'eventmachine', ">= 1.0.3"
36
36
  gem.add_development_dependency 'sinatra'
37
37
  gem.add_development_dependency 'thin'
38
38
  gem.add_development_dependency 'xmpp4r'
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Eye
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  ABOUT = "Eye v#{VERSION} (c) 2012-2013 @kostya"
4
4
 
5
5
  autoload :Process, 'eye/process'
@@ -1,8 +1,6 @@
1
1
  class Eye::Checker
2
2
  include Eye::Logger::Helpers
3
3
 
4
- autoload :Validation, 'eye/checker/validation'
5
-
6
4
  autoload :Memory, 'eye/checker/memory'
7
5
  autoload :Cpu, 'eye/checker/cpu'
8
6
  autoload :Http, 'eye/checker/http'
@@ -51,7 +49,6 @@ class Eye::Checker
51
49
  end
52
50
 
53
51
  def check
54
- tm1 = Time.now
55
52
  @value = get_value
56
53
  @values << {:value => @value, :good => good?(value)}
57
54
 
@@ -62,7 +59,7 @@ class Eye::Checker
62
59
  result = false if bad_count >= min_tries
63
60
  end
64
61
 
65
- info "#{last_human_values} => #{result ? 'OK' : 'Fail'} (#{Time.now - tm1}s)"
62
+ info "#{last_human_values} => #{result ? 'OK' : 'Fail'}"
66
63
  result
67
64
  end
68
65
 
@@ -112,8 +109,9 @@ class Eye::Checker
112
109
  @values[-1][:value] if @values.present?
113
110
  end
114
111
 
115
- extend Eye::Checker::Validation
112
+ extend Eye::Dsl::Validation
116
113
  param :every, [Fixnum, Float], false, 5
117
114
  param :times, [Fixnum, Array]
115
+ param :fire, Symbol, nil, nil, [:stop, :restart, :unmonitor, :nothing]
118
116
 
119
117
  end
@@ -38,8 +38,7 @@ class Eye::Checker::Http < Eye::Checker
38
38
  end
39
39
 
40
40
  def get_value_sync
41
- _session = session
42
- res = _session.start{ |http| http.get(@uri.path) }
41
+ res = session.start{ |http| http.get(@uri.request_uri) }
43
42
  {:result => res}
44
43
 
45
44
  rescue Timeout::Error => ex
@@ -5,7 +5,7 @@ class Eye::Checker::Socket < Eye::Checker
5
5
  #
6
6
  # Available parameters:
7
7
  # :addr the socket addr to open. The format is tcp://<host>:<port> or unix:<path>
8
- # :timeout generic timeout for opening the socket or reading data
8
+ # :timeout generic timeout for reading data from socket
9
9
  # :open_timeout override generic timeout for the connection
10
10
  # :read_timeout override generic timeout for data read/write
11
11
  # :send_data after connection send this data
@@ -18,7 +18,7 @@ class Eye::Checker::Socket < Eye::Checker
18
18
  param :read_timeout, [Fixnum, Float]
19
19
  param :send_data
20
20
  param :expect_data, [String, Regexp, Proc]
21
- param :protocol, [Symbol]
21
+ param :protocol, [Symbol], nil, nil, [:default, :em_object]
22
22
 
23
23
  def check_name
24
24
  'socket'
@@ -14,6 +14,8 @@ module Eye::Controller::Commands
14
14
  exclusive{ send_command(cmd, *args) }
15
15
  when :signal
16
16
  signal(*args)
17
+ when :break_chain
18
+ break_chain(*args)
17
19
  when :load
18
20
  exclusive{ load(*args) }
19
21
  when :info
@@ -21,6 +21,12 @@ module Eye::Controller::SendCommand
21
21
  end
22
22
  end
23
23
 
24
+ def break_chain(*obj_strs)
25
+ matched_objects(*obj_strs) do |obj|
26
+ obj.send_command(:break_chain)
27
+ end
28
+ end
29
+
24
30
  private
25
31
 
26
32
  def matched_objects(*obj_strs, &block)
@@ -60,7 +66,7 @@ private
60
66
  # nil if not found
61
67
  def find_objects(*obj_strs)
62
68
  return [] if obj_strs.blank?
63
- return @applications if obj_strs.size == 1 && obj_strs[0].strip == 'all'
69
+ return @applications.dup if obj_strs.size == 1 && (obj_strs[0].strip == 'all' || obj_strs[0].strip == '*')
64
70
 
65
71
  res = obj_strs.map{|c| c.split(",").map{|mask| find_objects_by_mask(mask) }}.flatten
66
72
 
@@ -76,7 +82,7 @@ private
76
82
  res = final
77
83
  end
78
84
 
79
- res.present? ? Eye::Utils::AliveArray.new(res) : res
85
+ res.present? ? Eye::Utils::AliveArray.new(res) : []
80
86
  end
81
87
 
82
88
  def find_objects_by_mask(mask)
@@ -14,6 +14,7 @@ class Eye::Dsl
14
14
  autoload :Validate, 'eye/dsl/validate'
15
15
  autoload :Chain, 'eye/dsl/chain'
16
16
  autoload :ConfigOpts, 'eye/dsl/config_opts'
17
+ autoload :Validation, 'eye/dsl/validation'
17
18
 
18
19
  class Error < Exception; end
19
20
  extend Eye::Dsl::Validate
@@ -97,8 +97,42 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
97
97
  h.instance_eval(&block)
98
98
  groups = h.config.delete :groups
99
99
  processes = h.config.delete :processes
100
- self.config[:groups].merge!(groups) if groups.present?
101
- self.config[:processes].merge!(processes) if processes.present?
100
+
101
+ if groups.present?
102
+ config[:groups] ||= {}
103
+ config[:groups].merge!(groups)
104
+ end
105
+
106
+ if processes.present?
107
+ config[:processes] ||= {}
108
+ config[:processes].merge!(processes)
109
+ end
110
+ end
111
+
112
+ # execute part of config on particular server
113
+ # array of strings
114
+ # regexp
115
+ # string
116
+ def with_server(glob = nil, &block)
117
+ on_server = true
118
+
119
+ if glob.present?
120
+ host = Eye::System.host
121
+
122
+ if glob.is_a?(Array)
123
+ on_server = !!glob.any?{|elem| elem == host}
124
+ elsif glob.is_a?(Regexp)
125
+ on_server = !!host.match(glob)
126
+ elsif glob.is_a?(String) || glob.is_a?(Symbol)
127
+ on_server = (host == glob.to_s)
128
+ end
129
+ end
130
+
131
+ scoped do
132
+ with_condition(on_server, &block)
133
+ end
134
+
135
+ on_server
102
136
  end
103
137
 
104
138
  end