eye 0.3.1 → 0.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c291e8ed14e7f8199676afd126f117dbc5a491ed
4
- data.tar.gz: be96f87f1d1f70d5666d8a1e63e60516317ec499
3
+ metadata.gz: f91b36c9b73d802f079d62a345bbf29fcb929768
4
+ data.tar.gz: 2953436d9e587ff52b0a2ee146c2ac52434e1662
5
5
  SHA512:
6
- metadata.gz: 33701932d6954c9c274e4f80ac87c1c21a257ab53d351b43c65a0d95eba98227e5ca9d889c2ee6a4857ef38df89d89d83bce90f647732fc85a87f8afde9b4f4d
7
- data.tar.gz: 9cfe4c03629ef7f28138caa6cf84e73fbc317c19e5d5712e39728fe58137b93fa9674385e9b78413e4f41926d0da7d608b1a13f37fc1d3eb349d72f6cf6336f9
6
+ metadata.gz: 1569dabc95b8e86f63eaf7b3d921758638cd2183ea403610400f437f6824fe0d18d0b763c3ce2752ab6d2a63641d2755affd51137d134f6cf3adf2e6caa10869
7
+ data.tar.gz: 1e9d50a96ae0cc44d2ab218d45933ec4b3a49ec5686875351de2f6b5be10deaaa2e1843431bb88b89eb783c59a0c1f76d1ccda46ad915d11fc4e5da2c27640f1
data/.gitignore CHANGED
@@ -29,4 +29,5 @@ experiments
29
29
  *sublime*
30
30
  examples/work*.eye
31
31
  script
32
- [0-9].rb
32
+ [0-9].rb
33
+ *.cache
@@ -1,3 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - "1.9.3"
4
+ script: COVA=1 bundle exec rake
@@ -0,0 +1,19 @@
1
+ 0.3.3.dev
2
+ ---------
3
+
4
+ 0.3.2
5
+ ---------
6
+ * improve matching targers
7
+ * possibility to add many checkers with the same type per process (ex: checks :http_2, ...)
8
+ * add uid,gid options (only for ruby 2.0)
9
+
10
+ 0.3.1
11
+ -----
12
+ * load multiple configs (folder,...) now not breaks on first error (each config loads separately)
13
+ * load ~/.eyeconfig with first eye load
14
+ * some concurrency fixes
15
+ * custom checker
16
+
17
+ 0.3
18
+ ---
19
+ * stable version
data/Gemfile CHANGED
@@ -2,3 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in eye.gemspec
4
4
  gemspec
5
+
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
- Eye [![Build Status](https://secure.travis-ci.org/kostya/eye.png?branch=master)](http://travis-ci.org/kostya/eye)
1
+ Eye
2
2
  ===
3
+ [![Gem Version](https://badge.fury.io/rb/eye.png)](http://rubygems.org/gems/eye)
4
+ [![Build Status](https://secure.travis-ci.org/kostya/eye.png?branch=master)](http://travis-ci.org/kostya/eye)
5
+ [![Coverage Status](https://coveralls.io/repos/kostya/eye/badge.png?branch=master)](https://coveralls.io/r/kostya/eye?branch=master)
3
6
 
4
7
  Process monitoring tool. An alternative to God and Bluepill. With Bluepill like config syntax. Requires MRI Ruby >= 1.9.3-p194. Uses Celluloid and Celluloid::IO.
5
8
 
@@ -150,6 +153,10 @@ Check config syntax:
150
153
 
151
154
  $ eye c(heck) examples/test.eye
152
155
 
156
+ Config explain (for debug):
157
+
158
+ $ eye e(xplain) examples/test.eye
159
+
153
160
  Log tracing:
154
161
 
155
162
  $ eye trace
@@ -160,11 +167,6 @@ Quit monitoring:
160
167
 
161
168
  $ eye q(uit)
162
169
 
163
- Config explain (for debug):
164
-
165
- $ eye explain examples/test.eye
166
-
167
-
168
- ### Config api:
170
+ ### Config options:
169
171
 
170
- Waiting for pull requests ..., until that you can read `examples` and `spec/dsl` folders.
172
+ Waiting for pull requests here..., until that you can read `examples` and `spec/dsl` folders.
data/bin/eye CHANGED
@@ -10,9 +10,7 @@ class Cli < Thor
10
10
 
11
11
  desc "info [MASK]", "show process statuses"
12
12
  def info(mask = nil)
13
- res = cmd(:info, mask)
14
- puts res if res && !res.empty?
15
- puts
13
+ print cmd(:info, mask)
16
14
  end
17
15
 
18
16
  desc "status ", "show process statuses"
@@ -25,31 +23,22 @@ class Cli < Thor
25
23
  method_option :config, :type => :boolean, :aliases => "-c"
26
24
  method_option :show_processes, :type => :boolean, :aliases => "-p"
27
25
  def xinfo
28
- res = cmd(:xinfo, options[:config], options[:show_processes])
29
- puts res if res && !res.empty?
30
- puts
26
+ print cmd(:xinfo, options[:config], options[:show_processes])
31
27
  end
32
28
 
33
29
  desc "oinfo", "onelined info"
34
30
  def oinfo
35
- res = cmd(:oinfo)
36
- puts res if res && !res.empty?
37
- puts
31
+ print cmd(:oinfo)
38
32
  end
39
33
 
40
34
  desc "load [CONF, ...]", "load config (and start server if needed) (-f for foregraund start)"
41
35
  method_option :foregraund, :type => :boolean, :aliases => "-f"
42
- method_option :logger, :type => :string, :aliases => "-l"
43
36
  def load(*configs)
44
37
  configs.map!{ |c| File.expand_path(c) } if !configs.empty?
45
38
 
46
39
  if options[:foregraund]
47
40
  # in foregraund we stop another server, and run just 1 current config version
48
- if configs.size != 1
49
- say "foregraund expected only one config", :red
50
- exit 1
51
- end
52
-
41
+ error!("foregraund expected only one config") if configs.size != 1
53
42
  server_start_foregraund(configs.first)
54
43
 
55
44
  elsif server_started?
@@ -90,9 +79,7 @@ class Cli < Thor
90
79
 
91
80
  desc "history TARGET[,...]", "show process states history"
92
81
  def history(*targets)
93
- res = cmd(:history, *targets)
94
- puts res if res && !res.empty?
95
- puts
82
+ print cmd(:history, *targets)
96
83
  end
97
84
 
98
85
  desc "trace [TARGET]", "tracing log for app,group or process"
@@ -146,6 +133,16 @@ class Cli < Thor
146
133
 
147
134
  private
148
135
 
136
+ def error!(msg)
137
+ say msg, :red
138
+ exit 1
139
+ end
140
+
141
+ def print(msg, new_line = true)
142
+ say msg if msg && !msg.empty?
143
+ say if new_line
144
+ end
145
+
149
146
  def client
150
147
  @client ||= Eye::Client.new(Eye::Settings.socket_path)
151
148
  end
@@ -160,11 +157,9 @@ private
160
157
  res = _cmd(cmd, *args)
161
158
 
162
159
  if res == :not_started
163
- say "eye monitoring not found, did you start it?", :red
164
- exit 1
160
+ error! "eye monitoring not found, did you start it?"
165
161
  elsif res == :timeouted
166
- say "eye does not answer, timeouted...", :red
167
- exit 1
162
+ error! "eye does not answer, timeouted..."
168
163
  end
169
164
 
170
165
  res
@@ -175,18 +170,12 @@ private
175
170
  end
176
171
 
177
172
  def say_load_result(res = {}, opts = {})
178
- say(res) unless res.is_a?(Hash)
179
-
180
- if res.has_key?(:error) # TODO: remove that case, outdated
181
- show_load_message(res, opts)
182
- exit 1 if res[:error]
183
- else
184
- say_filename = (res.size > 1)
185
- say "eye started!", :green if opts[:started]
186
- res.each do |filename, _res|
187
- say "#{filename}: ", nil, true if say_filename
188
- show_load_message(_res, opts)
189
- end
173
+ error!(res) unless res.is_a?(Hash)
174
+ say_filename = (res.size > 1)
175
+ say "eye started!", :green if opts[:started]
176
+ res.each do |filename, _res|
177
+ say "#{filename}: ", nil, true if say_filename
178
+ show_load_message(_res, opts)
190
179
  end
191
180
  end
192
181
 
@@ -212,11 +201,11 @@ private
212
201
  def send_command(_cmd, *args)
213
202
  res = cmd(_cmd, *args)
214
203
  if res == :unknown_command
215
- say "unknown command :#{_cmd}", :red
204
+ error! "unknown command :#{_cmd}"
216
205
  elsif res == :corrupred_marshal
217
- say "something crazy wrong, check eye logs!", :red
206
+ error! "something crazy wrong, check eye logs!"
218
207
  elsif res == []
219
- say "command :#{_cmd}, targets not found!", :red
208
+ error! "command :#{_cmd}, targets not found!"
220
209
  else
221
210
  say "command :#{_cmd} sended to [#{res * ", "}]"
222
211
  end
@@ -227,7 +216,7 @@ private
227
216
  if log_file && File.exists?(log_file)
228
217
  Process.exec "tail -n 100 -f #{log_file} | grep '#{tag}'"
229
218
  else
230
- say "log file not found #{log_file.inspect}", :red
219
+ error! "log file not found #{log_file.inspect}"
231
220
  end
232
221
  end
233
222
 
@@ -250,8 +239,7 @@ private
250
239
 
251
240
  def ensure_loader_path
252
241
  unless loader_path
253
- say "start monitoring needs to run under ruby with installed gem 'eye'", :red
254
- exit 1
242
+ error! "start monitoring needs to run under ruby with installed gem 'eye'"
255
243
  end
256
244
  end
257
245
 
@@ -275,18 +263,15 @@ private
275
263
  Eye::Settings.ensure_eye_dir
276
264
 
277
265
  ensure_stop_previous_server
278
-
279
- args = []
280
- args += ['-l', options[:logger]] if options[:logger]
281
266
 
267
+ args = []
282
268
  pid = Process.spawn(ruby_path, loader_path, *args, :out => '/dev/null', :err => '/dev/null', :in => '/dev/null',
283
269
  :chdir => '/', :pgroup => true)
284
270
  Process.detach(pid)
285
271
  File.open(Eye::Settings.pid_path, 'w'){|f| f.write(pid) }
286
272
 
287
273
  unless wait_server
288
- say "server not runned in 15 seconds, something crazy wrong", :red
289
- exit 1
274
+ error! "server not runned in 15 seconds, something crazy wrong"
290
275
  end
291
276
 
292
277
  configs.unshift(Eye::Settings.eyeconfig) if File.exists?(Eye::Settings.eyeconfig)
@@ -11,8 +11,9 @@ Eye.application :some do
11
11
 
12
12
  process :some_process do
13
13
  notify :dev, :info
14
+ pid_file "1.pid"
14
15
 
15
- ...
16
+ #...
16
17
  end
17
18
 
18
- end
19
+ end
@@ -1,6 +1,6 @@
1
1
  RUBY = '/usr/local/ruby/1.9.3-p392/bin/ruby'
2
2
  RAILS_ENV = 'production'
3
- ROOT = '/var/www/super_app'
3
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
4
4
  CURRENT = File.expand_path(File.join(ROOT, %w{current}))
5
5
  LOGS = File.expand_path(File.join(ROOT, %w{shared log}))
6
6
  PIDS = File.expand_path(File.join(ROOT, %w{shared pids}))
@@ -12,7 +12,7 @@ end
12
12
 
13
13
  Eye.application :super_app do
14
14
  env 'RAILS_ENV' => RAILS_ENV
15
- working_dir CURRENT
15
+ working_dir ROOT
16
16
  triggers :flapping, :times => 10, :within => 1.minute
17
17
 
18
18
  process :puma do
@@ -1,6 +1,6 @@
1
1
  Eye.application "rbenv_example" do
2
2
  env 'RBENV_ROOT' => '/usr/local/rbenv', 'PATH' => "/usr/local/rbenv/shims:/usr/local/rbenv/bin:#{ENV['PATH']}"
3
- working_dir "/projects/some_project"
3
+ working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
4
4
 
5
5
  process "some_process" do
6
6
  pid_file "some.pid"
@@ -8,4 +8,4 @@ Eye.application "rbenv_example" do
8
8
  daemonize true
9
9
  stdall "some.log"
10
10
  end
11
- end
11
+ end
@@ -16,8 +16,8 @@ def sidekiq_process(proxy, name)
16
16
  end
17
17
 
18
18
  Eye.application :sidekiq_test do
19
- working_dir '/some_dir'
19
+ working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
20
20
  env "RAILS_ENV" => 'production'
21
21
 
22
22
  sidekiq_process self, :sidekiq
23
- end
23
+ end
@@ -16,6 +16,7 @@ Eye.app 'thin-farm' do
16
16
 
17
17
  triggers :flapping, :times => 10, :within => 1.minute
18
18
  checks :memory, :below => 60.megabytes, :every => 30.seconds, :times => 5
19
+ start_timeout 30.seconds
19
20
 
20
21
  group :web do
21
22
  chain :action => :restart, :grace => 5.seconds
@@ -5,7 +5,7 @@ RAILS_ENV = 'production'
5
5
 
6
6
  Eye.application "rails_unicorn" do
7
7
  env "RAILS_ENV" => RAILS_ENV, "PATH" => "#{File.dirname(RUBY)}:#{ENV['PATH']}"
8
- working_dir "/projects/rails_unicorn"
8
+ working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
9
9
 
10
10
  process("unicorn") do
11
11
  pid_file "tmp/pids/unicorn.pid"
@@ -27,7 +27,6 @@ Gem::Specification.new do |gem|
27
27
 
28
28
  gem.add_development_dependency 'rake'
29
29
  gem.add_development_dependency 'rspec'
30
- gem.add_development_dependency 'simplecov'
31
30
  gem.add_development_dependency 'rr'
32
31
  gem.add_development_dependency 'ruby-graphviz'
33
32
  gem.add_development_dependency 'forking'
@@ -36,4 +35,5 @@ Gem::Specification.new do |gem|
36
35
  gem.add_development_dependency 'sinatra'
37
36
  gem.add_development_dependency 'thin'
38
37
  gem.add_development_dependency 'xmpp4r'
38
+ gem.add_development_dependency 'coveralls'
39
39
  end
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Eye
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  ABOUT = "Eye v#{VERSION} (c) 2012-2013 @kostya"
4
4
  PROCLINE = "eye monitoring v#{VERSION}"
5
5
 
@@ -50,7 +50,7 @@ class Eye::Application
50
50
  end
51
51
 
52
52
  def send_command(command, *args)
53
- debug "send_command #{command} #{args}"
53
+ info "send_command #{command}"
54
54
 
55
55
  @groups.each do |group|
56
56
  group.send_command(command, *args)
@@ -13,6 +13,16 @@ class Eye::Checker
13
13
 
14
14
  attr_accessor :value, :values, :options, :pid, :type, :check_count
15
15
 
16
+ def self.name_and_class(type)
17
+ type = type.to_sym
18
+ return {:name => type, :type => type} if TYPES[type]
19
+
20
+ if type =~ /\A(.*?)_?[0-9]+\z/
21
+ ctype = $1.to_sym
22
+ return {:name => type, :type => ctype} if TYPES[ctype]
23
+ end
24
+ end
25
+
16
26
  def self.get_class(type)
17
27
  klass = eval("Eye::Checker::#{TYPES[type]}") rescue nil
18
28
  raise "Unknown checker #{type}" unless klass
@@ -59,15 +59,10 @@ private
59
59
 
60
60
  def quit
61
61
  info 'exiting...'
62
- delete
63
62
  sleep 1
64
63
  Eye::System.send_signal($$) # soft terminate
65
64
  sleep 2
66
65
  Eye::System.send_signal($$, 9)
67
66
  end
68
67
 
69
- def delete
70
- send_command(:delete)
71
- end
72
-
73
68
  end
@@ -6,10 +6,24 @@ module Eye::Controller::Helpers
6
6
  $0 = str
7
7
  end
8
8
 
9
+ def save_cache
10
+ File.open(Eye::Settings.cache_path, 'w') { |f| f.write(cache_str) }
11
+ rescue => ex
12
+ warn "save cache crashed with #{ex.message}"
13
+ end
14
+
15
+ def cache_str
16
+ all_processes.map{ |p| "#{p.full_name}=#{p.state}" } * "\n"
17
+ end
18
+
9
19
  def process_by_name(name)
10
20
  all_processes.detect{|c| c.name == name}
11
21
  end
12
22
 
23
+ def process_by_full_name(name)
24
+ all_processes.detect{|c| c.full_name == name }
25
+ end
26
+
13
27
  def group_by_name(name)
14
28
  all_groups.detect{|c| c.name == name}
15
29
  end
@@ -58,4 +72,4 @@ module Eye::Controller::Helpers
58
72
  res
59
73
  end
60
74
 
61
- end
75
+ end
@@ -22,6 +22,7 @@ module Eye::Controller::Load
22
22
  end
23
23
 
24
24
  set_proc_line
25
+ save_cache
25
26
 
26
27
  res
27
28
  end
@@ -35,6 +36,8 @@ private
35
36
  { :error => false, :config => yield }
36
37
 
37
38
  rescue Eye::Dsl::Error, Exception, NoMethodError => ex
39
+ raise if ex.class.to_s.include?('RR') # skip RR exceptions
40
+
38
41
  error "load: config error <#{filename}>: #{ex.message}"
39
42
 
40
43
  # filter backtrace for user output
@@ -4,7 +4,9 @@ module Eye::Controller::SendCommand
4
4
  matched_objects(*obj_strs) do |obj|
5
5
  if command.to_sym == :delete
6
6
  remove_object_from_tree(obj)
7
- set_proc_line # to sync proc line if was delete application
7
+
8
+ set_proc_line
9
+ save_cache
8
10
  end
9
11
 
10
12
  obj.send_command(command)
@@ -61,32 +63,44 @@ private
61
63
  return [] if obj_strs.blank?
62
64
  return @applications.dup if obj_strs.size == 1 && (obj_strs[0].strip == 'all' || obj_strs[0].strip == '*')
63
65
 
64
- res = []
66
+ res = Eye::Utils::AliveArray.new
65
67
  obj_strs.map{|c| c.split(",")}.flatten.each do |mask|
66
- res += find_objects_by_mask(mask)
68
+ res += find_objects_by_mask(mask.to_s.strip)
67
69
  end
70
+ res
71
+ end
72
+
73
+ def find_objects_by_mask(mask)
74
+ res = find_all_objects_by_mask(mask)
68
75
 
69
76
  if res.size > 1
70
- # remove inherited targets
77
+ final = Eye::Utils::AliveArray.new
71
78
 
72
- final = []
79
+ if mask[-1] != '*'
80
+ # try to find exactly matched
81
+ r = right_regexp(mask)
82
+ res.each do |obj|
83
+ final << obj if obj.full_name =~ r
84
+ end
85
+ end
86
+
87
+ return final if final.present?
88
+
89
+ # remove inherited targets
73
90
  res.each do |obj|
74
91
  sub_object = res.any?{|a| a.sub_object?(obj) }
75
92
  final << obj unless sub_object
76
93
  end
77
94
 
78
95
  res = final
79
- end
96
+ end
80
97
 
81
- res.present? ? Eye::Utils::AliveArray.new(res) : []
98
+ res
82
99
  end
83
100
 
84
- def find_objects_by_mask(mask)
85
- mask.strip!
86
-
87
- res = []
88
- str = Regexp.escape(mask).gsub('\*', '.*?')
89
- r = %r{\A#{str}}
101
+ def find_all_objects_by_mask(mask)
102
+ res = Eye::Utils::AliveArray
103
+ r = left_regexp(mask)
90
104
 
91
105
  # find app
92
106
  res = @applications.select{|a| a.name =~ r || a.full_name =~ r }
@@ -102,9 +116,16 @@ private
102
116
  gr.processes.each do |p|
103
117
  res << p if p.name =~ r || p.full_name =~ r
104
118
 
119
+ # child matching
105
120
  if p.childs.present?
106
- res += p.childs.values.select{|ch| ch.alive? && (ch.name =~ r || ch.full_name =~ r) }
121
+ childs = p.childs.values
122
+ res += childs.select do |ch|
123
+ name = ch.name rescue ''
124
+ full_name = ch.full_name rescue ''
125
+ name =~ r || full_name =~ r
126
+ end
107
127
  end
128
+
108
129
  end
109
130
  end
110
131
  end
@@ -112,4 +133,13 @@ private
112
133
  res
113
134
  end
114
135
 
136
+ def left_regexp(mask)
137
+ str = Regexp.escape(mask).gsub('\*', '.*?')
138
+ %r|\A#{str}|
139
+ end
140
+
141
+ def right_regexp(mask)
142
+ str = Regexp.escape(mask).gsub('\*', '.*?')
143
+ %r|#{str}\z|
144
+ end
115
145
  end
@@ -28,7 +28,7 @@ module Eye::Controller::Status
28
28
 
29
29
  str = <<-S
30
30
  About: #{Eye::ABOUT}
31
- Info: #{resources_str(Eye::SystemResources.resources($$), false)}
31
+ Info: #{resources_str(Eye::SystemResources.resources($$))}
32
32
  Ruby: #{RUBY_DESCRIPTION}
33
33
  Logger: #{Eye::Logger.dev}
34
34
  Socket: #{Eye::Settings::socket_path}
@@ -98,16 +98,11 @@ private
98
98
  end
99
99
  end
100
100
 
101
- def resources_str(r, mb = true)
101
+ def resources_str(r)
102
102
  return '' if r.blank?
103
103
 
104
104
  res = "#{r[:start_time]}, #{r[:cpu]}%"
105
-
106
- if r[:memory]
107
- mem = mb ? "#{r[:memory] / 1024}Mb" : "#{r[:memory]}Kb"
108
- res += ", #{mem}"
109
- end
110
-
105
+ res += ", #{r[:memory] / 1024}Mb" if r[:memory]
111
106
  res += ", <#{r[:pid]}>"
112
107
 
113
108
  res
@@ -6,6 +6,10 @@ class Eye::Dsl::ApplicationOpts < Eye::Dsl::Opts
6
6
  [:pid_file, :start_command]
7
7
  end
8
8
 
9
+ def not_seed_options
10
+ [:groups]
11
+ end
12
+
9
13
  def group(name, &block)
10
14
  Eye::Dsl.debug "=> group #{name}"
11
15
 
@@ -28,6 +32,6 @@ class Eye::Dsl::ApplicationOpts < Eye::Dsl::Opts
28
32
  group("__default__"){ process(name.to_s, &block) }
29
33
  end
30
34
 
31
- def xgroup(name, &block); end
32
- def xprocess(name, &block); end
35
+ alias xgroup nop
36
+ alias xprocess nop
33
37
  end
@@ -6,6 +6,10 @@ class Eye::Dsl::GroupOpts < Eye::Dsl::Opts
6
6
  [:pid_file, :start_command]
7
7
  end
8
8
 
9
+ def not_seed_options
10
+ [:processes, :chain]
11
+ end
12
+
9
13
  def process(name, &block)
10
14
  Eye::Dsl.debug "=> process #{name}"
11
15
 
@@ -17,11 +21,8 @@ class Eye::Dsl::GroupOpts < Eye::Dsl::Opts
17
21
  Eye::Dsl.debug "<= process #{name}"
18
22
  end
19
23
 
20
- def xprocess(name, &block); end
21
-
22
- def application
23
- parent
24
- end
25
- alias :app :application
24
+ alias xprocess nop
25
+ alias application parent
26
+ alias app application
26
27
 
27
28
  end
@@ -11,7 +11,7 @@ module Eye::Dsl::Main
11
11
  Eye::Dsl.debug "<= app: #{name}"
12
12
  end
13
13
 
14
- alias :app :application
14
+ alias app application
15
15
 
16
16
  def load(glob = '')
17
17
  return if glob.blank?
@@ -1,7 +1,7 @@
1
1
  class Eye::Dsl::Opts < Eye::Dsl::PureOpts
2
2
 
3
3
  STR_OPTIONS = [ :pid_file, :working_dir, :stdout, :stderr, :stdall, :start_command,
4
- :stop_command, :restart_command ]
4
+ :stop_command, :restart_command, :uid, :gid ]
5
5
  create_options_methods(STR_OPTIONS, String)
6
6
 
7
7
  BOOL_OPTIONS = [ :daemonize, :keep_alive, :control_pid, :auto_start, :stop_on_delete]
@@ -11,17 +11,14 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
11
11
  :restart_grace, :stop_grace, :childs_update_period ]
12
12
  create_options_methods(INTERVAL_OPTIONS, [Fixnum, Float])
13
13
 
14
- OTHER_OPTIONS = [ :environment, :stop_signals ]
15
- create_options_methods(OTHER_OPTIONS)
14
+ create_options_methods([:environment], Hash)
15
+ create_options_methods([:stop_signals], Array)
16
+ create_options_methods([:umask], Fixnum)
16
17
 
17
18
 
18
19
  def initialize(name = nil, parent = nil)
19
20
  super(name, parent)
20
21
 
21
- # ensure delete subobjects which can appears from parent config
22
- @config.delete :groups
23
- @config.delete :processes
24
-
25
22
  @config[:application] = parent.name if parent.is_a?(Eye::Dsl::ApplicationOpts)
26
23
  @config[:group] = parent.name if parent.is_a?(Eye::Dsl::GroupOpts)
27
24
 
@@ -30,14 +27,14 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
30
27
  end
31
28
 
32
29
  def checks(type, opts = {})
33
- type = type.to_sym
34
- raise Eye::Dsl::Error, "unknown checker type #{type}" unless Eye::Checker::TYPES[type]
30
+ nac = Eye::Checker.name_and_class(type.to_sym)
31
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless nac
35
32
 
36
- opts.merge!(:type => type)
33
+ opts.merge!(:type => nac[:type])
37
34
  Eye::Checker.validate!(opts)
38
35
 
39
36
  @config[:checks] ||= {}
40
- @config[:checks][type] = opts
37
+ @config[:checks][nac[:name]] = opts
41
38
  end
42
39
 
43
40
  def triggers(type, opts = {})
@@ -53,9 +50,9 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
53
50
 
54
51
  # clear checks from parent
55
52
  def nochecks(type)
56
- type = type.to_sym
57
- raise Eye::Dsl::Error, "unknown checker type #{type}" unless Eye::Checker::TYPES[type]
58
- @config[:checks].try :delete, type
53
+ nac = Eye::Checker.name_and_class(type.to_sym)
54
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless nac
55
+ @config[:checks].try :delete, nac[:name]
59
56
  end
60
57
 
61
58
  # clear triggers from parent
@@ -85,7 +82,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
85
82
  @config[:environment].merge!(value)
86
83
  end
87
84
 
88
- alias :env :environment
85
+ alias env environment
89
86
 
90
87
  def set_stdall(value)
91
88
  super
@@ -94,6 +91,16 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
94
91
  set_stderr value
95
92
  end
96
93
 
94
+ def set_uid(value)
95
+ raise Eye::Dsl::Error, ":uid not supported by ruby (needed 2.0)" unless Eye::Settings.supported_setsid?
96
+ super
97
+ end
98
+
99
+ def set_gid(value)
100
+ raise Eye::Dsl::Error, ":gid not supported by ruby (needed 2.0)" unless Eye::Settings.supported_setsid?
101
+ super
102
+ end
103
+
97
104
  def scoped(&block)
98
105
  h = self.class.new(self.name, self)
99
106
  h.instance_eval(&block)
@@ -7,15 +7,12 @@ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
7
7
  @config[:monitor_children].merge!(opts.config)
8
8
  end
9
9
 
10
- def xmonitor_children(&block); end
10
+ alias xmonitor_children nop
11
11
 
12
12
  def application
13
13
  parent.try(:parent)
14
14
  end
15
- alias :app :application
16
-
17
- def group
18
- parent
19
- end
15
+ alias app application
16
+ alias group parent
20
17
 
21
18
  end
@@ -49,7 +49,12 @@ class Eye::Dsl::PureOpts
49
49
 
50
50
  if parent
51
51
  @parent = parent
52
- @config = merge_parent_config ? Eye::Utils::deep_clone(parent.config) : {}
52
+ if merge_parent_config
53
+ @config = Eye::Utils::deep_clone(parent.config)
54
+ parent.not_seed_options.each { |opt| @config.delete(opt) }
55
+ else
56
+ @config = {}
57
+ end
53
58
  @full_name = "#{parent.full_name}:#{@full_name}"
54
59
  else
55
60
  @config = {}
@@ -66,6 +71,10 @@ class Eye::Dsl::PureOpts
66
71
  []
67
72
  end
68
73
 
74
+ def not_seed_options
75
+ []
76
+ end
77
+
69
78
  def with_condition(cond = true, &block)
70
79
  self.instance_eval(&block) if cond && block
71
80
  end
@@ -90,6 +99,8 @@ class Eye::Dsl::PureOpts
90
99
  end
91
100
  end
92
101
 
102
+ def nop(*args, &block); end
103
+
93
104
  private
94
105
 
95
106
  def self.with_parsed_file(file_name)
@@ -109,7 +109,7 @@ class Eye::Group
109
109
 
110
110
  def break_chain
111
111
  info "break chain"
112
- scheduler.clear_pending_list
112
+ scheduler_clear_pending_list
113
113
  @chain_breaker = true
114
114
  end
115
115
 
@@ -42,11 +42,11 @@ class Eye::Logger
42
42
  attr_reader :dev, :log_level
43
43
 
44
44
  def link_logger(dev)
45
- @dev = dev ? dev.to_s.downcase : nil
45
+ @dev = dev ? dev.to_s : nil
46
46
  @dev_fd = @dev
47
47
 
48
- @dev_fd = STDOUT if @dev == 'stdout'
49
- @dev_fd = STDERR if @dev == 'stderr'
48
+ @dev_fd = STDOUT if @dev.to_s.downcase == 'stdout'
49
+ @dev_fd = STDERR if @dev.to_s.downcase == 'stderr'
50
50
 
51
51
  @inner_logger = InnerLogger.new(@dev_fd)
52
52
  @inner_logger.level = self.log_level || Logger::INFO
@@ -77,4 +77,4 @@ private
77
77
  end
78
78
  end
79
79
 
80
- end
80
+ end
@@ -53,6 +53,10 @@ module Eye::Process::Scheduler
53
53
  def scheduler_actions_list
54
54
  scheduler.list.map{|c| c[:args].first rescue nil }.compact
55
55
  end
56
+
57
+ def scheduler_clear_pending_list
58
+ scheduler.clear_pending_list
59
+ end
56
60
 
57
61
  def self.included(base)
58
62
  base.finalizer :remove_scheduler
@@ -1,4 +1,5 @@
1
1
  require 'shellwords'
2
+ require 'etc'
2
3
 
3
4
  module Eye::Process::Validate
4
5
 
@@ -18,6 +19,13 @@ module Eye::Process::Validate
18
19
 
19
20
  Shellwords.shellwords(config[:stop_command]) if config[:stop_command]
20
21
  Shellwords.shellwords(config[:restart_command]) if config[:restart_command]
22
+
23
+ Etc.getpwnam(config[:uid]) if config[:uid]
24
+ Etc.getpwnam(config[:gid]) if config[:gid]
25
+
26
+ if config[:working_dir]
27
+ raise Error, "working_dir '#{config[:working_dir]}' is invalid" unless File.directory?(config[:working_dir])
28
+ end
21
29
  end
22
30
 
23
- end
31
+ end
@@ -46,14 +46,14 @@ private
46
46
  end
47
47
 
48
48
  def start_checkers
49
- self[:checks].each{|type, cfg| start_checker(cfg) }
49
+ self[:checks].each{|name, cfg| start_checker(name, cfg) }
50
50
  end
51
51
 
52
- def start_checker(cfg)
52
+ def start_checker(name, cfg)
53
53
  subject = Eye::Checker.create(pid, cfg, logger.prefix)
54
54
 
55
55
  # ex: {:type => :memory, :every => 5.seconds, :below => 100.megabytes, :times => [3,5]}
56
- add_watcher("check_#{cfg[:type]}".to_sym, subject.every, subject, &method(:watcher_tick).to_proc)
56
+ add_watcher("check_#{name}".to_sym, subject.every, subject, &method(:watcher_tick).to_proc)
57
57
  end
58
58
 
59
59
  def watcher_tick(subject)
@@ -4,7 +4,7 @@ module Eye::Settings
4
4
  module_function
5
5
 
6
6
  def dir
7
- if Process::UID.eid == 0 # root
7
+ if root?
8
8
  '/var/run/eye'
9
9
  else
10
10
  File.expand_path(File.join(home, '.eye'))
@@ -12,13 +12,17 @@ module Eye::Settings
12
12
  end
13
13
 
14
14
  def eyeconfig
15
- if Process::UID.eid == 0 # root
15
+ if root?
16
16
  '/etc/eye.conf'
17
17
  else
18
18
  File.expand_path(File.join(home, '.eyeconfig'))
19
19
  end
20
20
  end
21
21
 
22
+ def root?
23
+ Process::UID.eid == 0
24
+ end
25
+
22
26
  def home
23
27
  ENV['EYE_HOME'] || ENV['HOME']
24
28
  end
@@ -32,15 +36,23 @@ module Eye::Settings
32
36
  end
33
37
 
34
38
  def socket_path
35
- path('sock')
39
+ path(ENV['EYE_SOCK'] || "sock#{ENV['EYE_V']}")
36
40
  end
37
41
 
38
42
  def pid_path
39
- path('pid')
43
+ path(ENV['EYE_PID'] || "pid#{ENV['EYE_V']}")
40
44
  end
41
45
 
46
+ def cache_path
47
+ path("processes#{ENV['EYE_V']}.cache")
48
+ end
49
+
42
50
  def client_timeout
43
51
  5
44
52
  end
45
53
 
46
- end
54
+ def supported_setsid?
55
+ RUBY_VERSION >= '2.0'
56
+ end
57
+
58
+ end
@@ -1,5 +1,6 @@
1
1
  require 'shellwords'
2
2
  require 'pathname'
3
+ require 'etc'
3
4
 
4
5
  module Eye::System
5
6
  class << self
@@ -134,6 +135,14 @@ module Eye::System
134
135
  o.update(out: [config[:stdout], 'a']) if config[:stdout]
135
136
  o.update(err: [config[:stderr], 'a']) if config[:stderr]
136
137
  o.update(in: config[:stdin]) if config[:stdin]
138
+
139
+ if Eye::Settings.root?
140
+ o.update(uid: Etc.getpwnam(config[:uid]).uid) if config[:uid]
141
+ o.update(gid: Etc.getpwnam(config[:gid]).gid) if config[:gid]
142
+ end
143
+
144
+ o.update(umask: config[:umask]) if config[:umask]
145
+
137
146
  o
138
147
  end
139
148
 
@@ -2,7 +2,8 @@ class Eye::Utils::AliveArray
2
2
  extend Forwardable
3
3
  include Enumerable
4
4
 
5
- def_delegators :@arr, :[], :<<, :clear, :delete, :size, :empty?, :push, :flatten
5
+ def_delegators :@arr, :[], :<<, :clear, :delete, :size, :empty?, :push,
6
+ :flatten, :present?, :uniq!
6
7
 
7
8
  def initialize(arr = [])
8
9
  @arr = arr
@@ -28,4 +29,25 @@ class Eye::Utils::AliveArray
28
29
  self.class.new super
29
30
  end
30
31
 
32
+ def +(other)
33
+ if other.is_a?(Eye::Utils::AliveArray)
34
+ @arr += other.pure
35
+ elsif other.is_a?(Array)
36
+ @arr += other
37
+ else
38
+ raise "Unexpected + #{other}"
39
+ end
40
+ self
41
+ end
42
+
43
+ def ==(other)
44
+ if other.is_a?(Eye::Utils::AliveArray)
45
+ @arr == other.pure
46
+ elsif other.is_a?(Array)
47
+ @arr == other
48
+ else
49
+ raise "Unexpected == #{other}"
50
+ end
51
+ end
52
+
31
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Makarchev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-15 00:00:00.000000000 Z
11
+ date: 2013-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: simplecov
112
+ name: rr
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - '>='
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: rr
126
+ name: ruby-graphviz
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - '>='
@@ -137,7 +137,7 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: ruby-graphviz
140
+ name: forking
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - '>='
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: forking
154
+ name: fakeweb
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - '>='
@@ -165,35 +165,35 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: fakeweb
168
+ name: eventmachine
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - '>='
172
172
  - !ruby/object:Gem::Version
173
- version: '0'
173
+ version: 1.0.3
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - '>='
179
179
  - !ruby/object:Gem::Version
180
- version: '0'
180
+ version: 1.0.3
181
181
  - !ruby/object:Gem::Dependency
182
- name: eventmachine
182
+ name: sinatra
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - '>='
186
186
  - !ruby/object:Gem::Version
187
- version: 1.0.3
187
+ version: '0'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - '>='
193
193
  - !ruby/object:Gem::Version
194
- version: 1.0.3
194
+ version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
- name: sinatra
196
+ name: thin
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - '>='
@@ -207,7 +207,7 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
- name: thin
210
+ name: xmpp4r
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
213
  - - '>='
@@ -221,7 +221,7 @@ dependencies:
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
223
  - !ruby/object:Gem::Dependency
224
- name: xmpp4r
224
+ name: coveralls
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - '>='
@@ -246,6 +246,7 @@ files:
246
246
  - .gitignore
247
247
  - .rspec
248
248
  - .travis.yml
249
+ - CHANGES.md
249
250
  - Gemfile
250
251
  - LICENSE
251
252
  - README.md