eye 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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