eye 0.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/README.md +1 -1
- data/Rakefile +3 -1
- data/bin/eye +47 -24
- data/lib/eye.rb +4 -1
- data/lib/eye/checker.rb +20 -4
- data/lib/eye/checker/http.rb +1 -1
- data/lib/eye/checker/socket.rb +1 -1
- data/lib/eye/child_process.rb +1 -1
- data/lib/eye/config.rb +88 -0
- data/lib/eye/controller.rb +5 -3
- data/lib/eye/controller/helpers.rb +1 -1
- data/lib/eye/controller/load.rb +61 -73
- data/lib/eye/controller/options.rb +22 -0
- data/lib/eye/controller/send_command.rb +8 -12
- data/lib/eye/controller/show_history.rb +1 -1
- data/lib/eye/controller/status.rb +3 -2
- data/lib/eye/dsl.rb +3 -10
- data/lib/eye/dsl/config_opts.rb +1 -1
- data/lib/eye/dsl/main.rb +2 -7
- data/lib/eye/group.rb +1 -1
- data/lib/eye/notify.rb +3 -3
- data/lib/eye/process/controller.rb +2 -2
- data/lib/eye/process/monitor.rb +3 -3
- data/lib/eye/process/scheduler.rb +11 -2
- data/lib/eye/process/states.rb +1 -1
- data/lib/eye/process/trigger.rb +2 -2
- data/lib/eye/process/watchers.rb +1 -1
- data/lib/eye/reason.rb +20 -0
- data/lib/eye/settings.rb +14 -3
- data/lib/eye/utils/celluloid_chain.rb +22 -5
- metadata +5 -3
- data/lib/eye/dsl/validate.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c291e8ed14e7f8199676afd126f117dbc5a491ed
|
4
|
+
data.tar.gz: be96f87f1d1f70d5666d8a1e63e60516317ec499
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33701932d6954c9c274e4f80ac87c1c21a257ab53d351b43c65a0d95eba98227e5ca9d889c2ee6a4857ef38df89d89d83bce90f647732fc85a87f8afde9b4f4d
|
7
|
+
data.tar.gz: 9cfe4c03629ef7f28138caa6cf84e73fbc317c19e5d5712e39728fe58137b93fa9674385e9b78413e4f41926d0da7d608b1a13f37fc1d3eb349d72f6cf6336f9
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Eye [![Build Status](https://secure.travis-ci.org/kostya/eye.png?branch=master)](http://travis-ci.org/kostya/eye)
|
2
2
|
===
|
3
3
|
|
4
|
-
Process monitoring tool. An alternative to God and Bluepill. With Bluepill like config syntax. Requires MRI Ruby >= 1.9.
|
4
|
+
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
5
|
|
6
6
|
Little demo, shows general commands and how chain works:
|
7
7
|
|
data/Rakefile
CHANGED
data/bin/eye
CHANGED
@@ -37,21 +37,26 @@ class Cli < Thor
|
|
37
37
|
puts
|
38
38
|
end
|
39
39
|
|
40
|
-
desc "load [CONF]", "load config (and start server if needed) (-f for foregraund start)"
|
40
|
+
desc "load [CONF, ...]", "load config (and start server if needed) (-f for foregraund start)"
|
41
41
|
method_option :foregraund, :type => :boolean, :aliases => "-f"
|
42
42
|
method_option :logger, :type => :string, :aliases => "-l"
|
43
|
-
def load(
|
44
|
-
|
43
|
+
def load(*configs)
|
44
|
+
configs.map!{ |c| File.expand_path(c) } if !configs.empty?
|
45
45
|
|
46
46
|
if options[:foregraund]
|
47
47
|
# in foregraund we stop another server, and run just 1 current config version
|
48
|
-
|
48
|
+
if configs.size != 1
|
49
|
+
say "foregraund expected only one config", :red
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
|
53
|
+
server_start_foregraund(configs.first)
|
49
54
|
|
50
55
|
elsif server_started?
|
51
|
-
say_load_result cmd(:load,
|
56
|
+
say_load_result cmd(:load, *configs)
|
52
57
|
|
53
58
|
else
|
54
|
-
server_start(
|
59
|
+
server_start(configs)
|
55
60
|
|
56
61
|
end
|
57
62
|
end
|
@@ -170,20 +175,31 @@ private
|
|
170
175
|
end
|
171
176
|
|
172
177
|
def say_load_result(res = {}, opts = {})
|
173
|
-
|
174
|
-
say "config error: ", :red
|
175
|
-
say res[:message]
|
178
|
+
say(res) unless res.is_a?(Hash)
|
176
179
|
|
177
|
-
|
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
|
190
|
+
end
|
191
|
+
end
|
178
192
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
193
|
+
def show_load_message(res, opts = {})
|
194
|
+
if res[:error]
|
195
|
+
say res[:message], :red
|
196
|
+
res[:backtrace].to_a.each{|line| say line, :red }
|
197
|
+
else
|
198
|
+
all_error = false
|
199
|
+
if opts[:syntax]
|
200
|
+
say "config ok!", :green if !res[:empty]
|
185
201
|
else
|
186
|
-
say "config loaded!", :
|
202
|
+
say "config loaded!", :green if !res[:empty]
|
187
203
|
end
|
188
204
|
|
189
205
|
if opts[:print_config]
|
@@ -192,7 +208,7 @@ private
|
|
192
208
|
end
|
193
209
|
end
|
194
210
|
end
|
195
|
-
|
211
|
+
|
196
212
|
def send_command(_cmd, *args)
|
197
213
|
res = cmd(_cmd, *args)
|
198
214
|
if res == :unknown_command
|
@@ -216,8 +232,13 @@ private
|
|
216
232
|
end
|
217
233
|
|
218
234
|
def loader_path
|
219
|
-
|
220
|
-
|
235
|
+
if RUBY_VERSION < '1.9'
|
236
|
+
begin
|
237
|
+
return Gem.bin_path('eye', 'loader_eye')
|
238
|
+
rescue Gem::GemNotFoundException, Gem::Exception
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
221
242
|
filename = File.expand_path(File.join(File.dirname(__FILE__), %w[loader_eye]))
|
222
243
|
File.exists?(filename) ? filename : nil
|
223
244
|
end
|
@@ -249,7 +270,7 @@ private
|
|
249
270
|
Process.exec(ruby_path, loader_path, *args)
|
250
271
|
end
|
251
272
|
|
252
|
-
def server_start(
|
273
|
+
def server_start(configs)
|
253
274
|
ensure_loader_path
|
254
275
|
Eye::Settings.ensure_eye_dir
|
255
276
|
|
@@ -268,10 +289,12 @@ private
|
|
268
289
|
exit 1
|
269
290
|
end
|
270
291
|
|
271
|
-
if
|
272
|
-
|
292
|
+
configs.unshift(Eye::Settings.eyeconfig) if File.exists?(Eye::Settings.eyeconfig)
|
293
|
+
|
294
|
+
if !configs.empty?
|
295
|
+
say_load_result cmd(:load, *configs), :started => true
|
273
296
|
else
|
274
|
-
say "started!", :
|
297
|
+
say "started!", :green
|
275
298
|
end
|
276
299
|
end
|
277
300
|
|
data/lib/eye.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Eye
|
2
|
-
VERSION = "0.3"
|
2
|
+
VERSION = "0.3.1"
|
3
3
|
ABOUT = "Eye v#{VERSION} (c) 2012-2013 @kostya"
|
4
|
+
PROCLINE = "eye monitoring v#{VERSION}"
|
4
5
|
|
5
6
|
autoload :Process, 'eye/process'
|
6
7
|
autoload :ChildProcess, 'eye/child_process'
|
@@ -17,6 +18,8 @@ module Eye
|
|
17
18
|
autoload :Client, 'eye/client'
|
18
19
|
autoload :Utils, 'eye/utils'
|
19
20
|
autoload :Notify, 'eye/notify'
|
21
|
+
autoload :Config, 'eye/config'
|
22
|
+
autoload :Reason, 'eye/reason'
|
20
23
|
|
21
24
|
autoload :Controller, 'eye/controller'
|
22
25
|
autoload :Control, 'eye/control'
|
data/lib/eye/checker.rb
CHANGED
@@ -11,7 +11,7 @@ class Eye::Checker
|
|
11
11
|
TYPES = {:memory => "Memory", :cpu => "Cpu", :http => "Http",
|
12
12
|
:ctime => "FileCTime", :fsize => "FileSize", :socket => "Socket"}
|
13
13
|
|
14
|
-
attr_accessor :value, :values, :options, :pid, :type
|
14
|
+
attr_accessor :value, :values, :options, :pid, :type, :check_count
|
15
15
|
|
16
16
|
def self.get_class(type)
|
17
17
|
klass = eval("Eye::Checker::#{TYPES[type]}") rescue nil
|
@@ -37,6 +37,7 @@ class Eye::Checker
|
|
37
37
|
|
38
38
|
@value = nil
|
39
39
|
@values = Eye::Utils::Tail.new(max_tries)
|
40
|
+
@check_count = 0
|
40
41
|
end
|
41
42
|
|
42
43
|
def last_human_values
|
@@ -49,10 +50,11 @@ class Eye::Checker
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def check
|
52
|
-
@value =
|
53
|
+
@value = get_value_safe
|
53
54
|
@values << {:value => @value, :good => good?(value)}
|
54
55
|
|
55
56
|
result = true
|
57
|
+
@check_count += 1
|
56
58
|
|
57
59
|
if @values.size == max_tries
|
58
60
|
bad_count = @values.count{|v| !v[:good] }
|
@@ -63,6 +65,10 @@ class Eye::Checker
|
|
63
65
|
result
|
64
66
|
end
|
65
67
|
|
68
|
+
def get_value_safe
|
69
|
+
get_value
|
70
|
+
end
|
71
|
+
|
66
72
|
def get_value
|
67
73
|
raise 'Realize me'
|
68
74
|
end
|
@@ -115,8 +121,18 @@ class Eye::Checker
|
|
115
121
|
param :fire, Symbol, nil, nil, [:stop, :restart, :unmonitor, :nothing]
|
116
122
|
|
117
123
|
class Defer < Eye::Checker
|
118
|
-
def
|
119
|
-
Celluloid::Future.new{
|
124
|
+
def get_value_safe
|
125
|
+
Celluloid::Future.new{ get_value }.value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class Custom < Defer
|
130
|
+
def self.inherited(base)
|
131
|
+
super
|
132
|
+
name = base.to_s
|
133
|
+
type = name.underscore.to_sym
|
134
|
+
Eye::Checker::TYPES[type] = name
|
135
|
+
Eye::Checker.const_set(name, base)
|
120
136
|
end
|
121
137
|
end
|
122
138
|
end
|
data/lib/eye/checker/http.rb
CHANGED
data/lib/eye/checker/socket.rb
CHANGED
data/lib/eye/child_process.rb
CHANGED
data/lib/eye/config.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
class Eye::Config
|
2
|
+
|
3
|
+
attr_reader :settings, :applications
|
4
|
+
|
5
|
+
def initialize(settings = {}, applications = {})
|
6
|
+
@settings = settings
|
7
|
+
@applications = applications
|
8
|
+
end
|
9
|
+
|
10
|
+
def merge(other_config)
|
11
|
+
Eye::Config.new(@settings.merge(other_config.settings), @applications.merge(other_config.applications))
|
12
|
+
end
|
13
|
+
|
14
|
+
def merge!(other_config)
|
15
|
+
@settings.merge!(other_config.settings)
|
16
|
+
@applications.merge!(other_config.applications)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
{:settings => @settings, :applications => @applications}
|
21
|
+
end
|
22
|
+
|
23
|
+
# raise an error if config wrong
|
24
|
+
def validate!
|
25
|
+
all_processes = processes
|
26
|
+
|
27
|
+
# Check blank pid_files
|
28
|
+
no_pid_file = all_processes.select{|c| c[:pid_file].blank? }
|
29
|
+
if no_pid_file.present?
|
30
|
+
raise Eye::Dsl::Error, "blank pid_file for: #{no_pid_file.map{|c| c[:name]} * ', '}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check dublicates of the full pid_file
|
34
|
+
|
35
|
+
dubl_pids = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
36
|
+
ex_pid_file = Eye::System.normalized_file(o[:pid_file], o[:working_dir])
|
37
|
+
h[ex_pid_file] += 1
|
38
|
+
end
|
39
|
+
dubl_pids = dubl_pids.select{|k,v| v>1}
|
40
|
+
|
41
|
+
if dubl_pids.present?
|
42
|
+
raise Eye::Dsl::Error, "dublicate pid_files: #{dubl_pids.inspect}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check dublicates of the full_name
|
46
|
+
dubl_names = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
47
|
+
full_name = "#{o[:application]}:#{o[:group]}:#{o[:name]}"
|
48
|
+
h[full_name] += 1
|
49
|
+
end
|
50
|
+
dubl_names = dubl_names.select{|k,v| v>1}
|
51
|
+
|
52
|
+
if dubl_names.present?
|
53
|
+
raise Eye::Dsl::Error, "dublicate names: #{dubl_names.inspect}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# validate processes with their own validate
|
57
|
+
all_processes.each do |process_cfg|
|
58
|
+
Eye::Process.validate process_cfg
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def processes
|
63
|
+
applications.values.map{|e| (e[:groups] || {}).values.map{|c| (c[:processes] || {}).values} }.flatten
|
64
|
+
end
|
65
|
+
|
66
|
+
def application_names
|
67
|
+
applications.keys
|
68
|
+
end
|
69
|
+
|
70
|
+
def delete_app(name)
|
71
|
+
applications.delete(name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete_group(name)
|
75
|
+
applications.each do |app_name, app_cfg|
|
76
|
+
app_cfg[:groups].delete(name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete_process(name)
|
81
|
+
applications.each do |app_name, app_cfg|
|
82
|
+
app_cfg[:groups].each do |gr_name, gr_cfg|
|
83
|
+
gr_cfg[:processes].delete(name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
data/lib/eye/controller.rb
CHANGED
@@ -20,6 +20,7 @@ class Eye::Controller
|
|
20
20
|
autoload :Status, 'eye/controller/status'
|
21
21
|
autoload :SendCommand, 'eye/controller/send_command'
|
22
22
|
autoload :ShowHistory, 'eye/controller/show_history'
|
23
|
+
autoload :Options, 'eye/controller/options'
|
23
24
|
|
24
25
|
include Eye::Logger::Helpers
|
25
26
|
include Eye::Controller::Load
|
@@ -28,12 +29,13 @@ class Eye::Controller
|
|
28
29
|
include Eye::Controller::Status
|
29
30
|
include Eye::Controller::SendCommand
|
30
31
|
include Eye::Controller::ShowHistory
|
32
|
+
include Eye::Controller::Options
|
31
33
|
|
32
34
|
attr_reader :applications, :current_config
|
33
35
|
|
34
36
|
def initialize
|
35
37
|
@applications = []
|
36
|
-
@current_config = Eye::
|
38
|
+
@current_config = Eye::Config.new
|
37
39
|
|
38
40
|
Eye.instance_variable_set(:@logger, Eye::Logger.new('eye'))
|
39
41
|
@logger = Eye.logger
|
@@ -44,8 +46,8 @@ class Eye::Controller
|
|
44
46
|
info "starting #{Eye::ABOUT} (#{$$})"
|
45
47
|
end
|
46
48
|
|
47
|
-
def
|
48
|
-
current_config
|
49
|
+
def settings
|
50
|
+
current_config.settings
|
49
51
|
end
|
50
52
|
|
51
53
|
end
|
data/lib/eye/controller/load.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
module Eye::Controller::Load
|
2
|
-
include Eye::Dsl::Validate
|
3
2
|
|
4
|
-
def check(filename
|
5
|
-
catch_load_error(filename)
|
6
|
-
parse_config(filename)
|
7
|
-
end
|
3
|
+
def check(filename)
|
4
|
+
{ filename => catch_load_error(filename) { parse_config(filename).to_h } }
|
8
5
|
end
|
9
6
|
|
10
7
|
def explain(filename)
|
11
|
-
catch_load_error(filename)
|
12
|
-
parse_set_of_configs(filename)
|
13
|
-
end
|
8
|
+
{ filename => catch_load_error(filename) { parse_config(filename).to_h } }
|
14
9
|
end
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
def load(*obj_strs)
|
12
|
+
info "load: #{obj_strs}"
|
13
|
+
|
14
|
+
res = Hash.new
|
15
|
+
|
16
|
+
globbing(*obj_strs).each do |filename|
|
17
|
+
res[filename] = catch_load_error(filename) do
|
18
|
+
cfg = parse_config(filename)
|
19
|
+
load_config(filename, cfg)
|
20
|
+
nil
|
21
|
+
end
|
21
22
|
end
|
23
|
+
|
24
|
+
set_proc_line
|
25
|
+
|
26
|
+
res
|
22
27
|
end
|
23
28
|
|
24
29
|
private
|
@@ -26,8 +31,8 @@ private
|
|
26
31
|
# regexp for clean backtrace to show for user
|
27
32
|
BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb].freeze
|
28
33
|
|
29
|
-
def catch_load_error(filename, &block)
|
30
|
-
{:error => false, :config => yield }
|
34
|
+
def catch_load_error(filename = nil, &block)
|
35
|
+
{ :error => false, :config => yield }
|
31
36
|
|
32
37
|
rescue Eye::Dsl::Error, Exception, NoMethodError => ex
|
33
38
|
error "load: config error <#{filename}>: #{ex.message}"
|
@@ -37,88 +42,71 @@ private
|
|
37
42
|
bt = bt.reject{|line| line.to_s =~ BT_REGX }
|
38
43
|
error bt.join("\n")
|
39
44
|
|
40
|
-
res = {:error => true, :message => ex.message}
|
45
|
+
res = { :error => true, :message => ex.message }
|
41
46
|
res.merge!(:backtrace => bt) if bt.present?
|
42
47
|
res
|
43
48
|
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
cfg = Eye::Dsl.parse(nil, filename)
|
50
|
-
validate( merge_configs(@current_config, cfg) )
|
51
|
-
|
52
|
-
cfg
|
53
|
-
end
|
54
|
-
|
55
|
-
def parse_set_of_configs(filename)
|
56
|
-
mask = if File.directory?(filename)
|
57
|
-
File.join filename, '{*.eye}'
|
58
|
-
else
|
59
|
-
filename
|
60
|
-
end
|
50
|
+
def globbing(*obj_strs)
|
51
|
+
res = []
|
52
|
+
return res if obj_strs.empty?
|
61
53
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
54
|
+
obj_strs.each do |filename|
|
55
|
+
mask = if File.directory?(filename)
|
56
|
+
File.join filename, '{*.eye}'
|
57
|
+
else
|
58
|
+
filename
|
59
|
+
end
|
69
60
|
|
70
|
-
|
61
|
+
debug "load: globbing mask #{mask}"
|
71
62
|
|
72
|
-
|
73
|
-
|
74
|
-
|
63
|
+
sub = []
|
64
|
+
Dir[mask].each do |config_path|
|
65
|
+
sub << config_path
|
66
|
+
end
|
67
|
+
sub = [mask] if sub.empty?
|
68
|
+
|
69
|
+
res += sub
|
75
70
|
end
|
76
71
|
|
77
|
-
|
78
|
-
validate(new_cfg)
|
79
|
-
new_cfg
|
72
|
+
res
|
80
73
|
end
|
81
74
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
load_config(new_cfg, @loaded_config[:applications].keys)
|
87
|
-
@loaded_config = nil
|
88
|
-
end
|
75
|
+
# return: result, config
|
76
|
+
def parse_config(filename)
|
77
|
+
raise Eye::Dsl::Error, "config file '#{filename}' not found!" unless File.exists?(filename)
|
78
|
+
debug "parse #{filename}"
|
89
79
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
@current_config = new_config
|
80
|
+
cfg = Eye::Dsl.parse(nil, filename)
|
81
|
+
@current_config.merge(cfg).validate! # just validate summary config here
|
82
|
+
cfg
|
94
83
|
end
|
95
84
|
|
96
|
-
|
97
|
-
|
98
|
-
|
85
|
+
# !!! exclusive operation
|
86
|
+
def load_config(filename, config)
|
87
|
+
info "load #{filename}"
|
88
|
+
new_cfg = @current_config.merge(config)
|
89
|
+
new_cfg.validate!
|
90
|
+
|
91
|
+
load_options(new_cfg.settings)
|
92
|
+
create_objects(new_cfg.applications, config.application_names)
|
93
|
+
@current_config = new_cfg
|
99
94
|
end
|
100
95
|
|
101
96
|
# load global config options
|
102
97
|
def load_options(opts)
|
103
98
|
return if opts.blank?
|
104
99
|
|
105
|
-
|
106
|
-
|
107
|
-
if
|
108
|
-
if opts[:logger].blank?
|
109
|
-
Eye::Logger.link_logger(nil)
|
110
|
-
else
|
111
|
-
Eye::Logger.link_logger(opts[:logger])
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
Eye::Logger.log_level = opts[:logger_level] if opts[:logger_level]
|
100
|
+
opts.each do |key, value|
|
101
|
+
method = "set_opt_#{key}"
|
102
|
+
send(method, value) if value && respond_to?(method)
|
116
103
|
end
|
117
104
|
end
|
118
105
|
|
119
106
|
# create objects as diff, from configs
|
120
107
|
def create_objects(apps_config, changed_apps = [])
|
121
108
|
debug 'create objects'
|
109
|
+
|
122
110
|
apps_config.each do |app_name, app_cfg|
|
123
111
|
update_or_create_application(app_name, app_cfg.clone) if changed_apps.include?(app_name)
|
124
112
|
end
|
@@ -190,7 +178,7 @@ private
|
|
190
178
|
group = if @old_groups[group_name]
|
191
179
|
debug "update group #{group_name}"
|
192
180
|
group = @old_groups.delete(group_name)
|
193
|
-
group.schedule :update_config, group_config, 'load config'
|
181
|
+
group.schedule :update_config, group_config, Eye::Reason::User.new(:'load config')
|
194
182
|
group.clear
|
195
183
|
group
|
196
184
|
else
|
@@ -213,7 +201,7 @@ private
|
|
213
201
|
if @old_processes[process_name]
|
214
202
|
debug "update process #{process_name}"
|
215
203
|
process = @old_processes.delete(process_name)
|
216
|
-
process.schedule :update_config, process_cfg, 'load config'
|
204
|
+
process.schedule :update_config, process_cfg, Eye::Reason::User.new(:'load config')
|
217
205
|
process
|
218
206
|
else
|
219
207
|
debug "create process #{process_name}"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Eye::Controller::Options
|
2
|
+
|
3
|
+
def set_opt_logger(logger)
|
4
|
+
# do not apply logger, if in stdout state
|
5
|
+
if !%w{stdout stderr}.include?(Eye::Logger.dev)
|
6
|
+
if logger.blank?
|
7
|
+
Eye::Logger.link_logger(nil)
|
8
|
+
else
|
9
|
+
Eye::Logger.link_logger(logger)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_opt_logger_level(level)
|
15
|
+
Eye::Logger.log_level = level
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_opt_http(opts = {})
|
19
|
+
# stub!
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -41,24 +41,17 @@ private
|
|
41
41
|
|
42
42
|
if klass == Eye::Application
|
43
43
|
@applications.delete(obj)
|
44
|
-
@current_config
|
44
|
+
@current_config.delete_app(obj.name)
|
45
45
|
end
|
46
46
|
|
47
47
|
if klass == Eye::Group
|
48
48
|
@applications.each{|app| app.groups.delete(obj) }
|
49
|
-
@current_config
|
50
|
-
app_cfg[:groups].delete(obj.name)
|
51
|
-
end
|
49
|
+
@current_config.delete_group(obj.name)
|
52
50
|
end
|
53
51
|
|
54
52
|
if klass == Eye::Process
|
55
53
|
@applications.each{|app| app.groups.each{|gr| gr.processes.delete(obj) }}
|
56
|
-
|
57
|
-
@current_config[:applications].each do |app_name, app_cfg|
|
58
|
-
app_cfg[:groups].each do |gr_name, gr_cfg|
|
59
|
-
gr_cfg[:processes].delete(obj.name)
|
60
|
-
end
|
61
|
-
end
|
54
|
+
@current_config.delete_process(obj.name)
|
62
55
|
end
|
63
56
|
end
|
64
57
|
|
@@ -68,7 +61,10 @@ private
|
|
68
61
|
return [] if obj_strs.blank?
|
69
62
|
return @applications.dup if obj_strs.size == 1 && (obj_strs[0].strip == 'all' || obj_strs[0].strip == '*')
|
70
63
|
|
71
|
-
res =
|
64
|
+
res = []
|
65
|
+
obj_strs.map{|c| c.split(",")}.flatten.each do |mask|
|
66
|
+
res += find_objects_by_mask(mask)
|
67
|
+
end
|
72
68
|
|
73
69
|
if res.size > 1
|
74
70
|
# remove inherited targets
|
@@ -107,7 +103,7 @@ private
|
|
107
103
|
res << p if p.name =~ r || p.full_name =~ r
|
108
104
|
|
109
105
|
if p.childs.present?
|
110
|
-
res += p.childs.values.select{|ch| ch.name =~ r || ch.full_name =~ r }
|
106
|
+
res += p.childs.values.select{|ch| ch.alive? && (ch.name =~ r || ch.full_name =~ r) }
|
111
107
|
end
|
112
108
|
end
|
113
109
|
end
|
@@ -39,7 +39,7 @@ private
|
|
39
39
|
res = "\033[1m#{name}\033[0m:\n"
|
40
40
|
history = history.reverse
|
41
41
|
|
42
|
-
history.chunk{|h| [h[:state], h[:reason]] }.each do |_, hist|
|
42
|
+
history.chunk{|h| [h[:state], h[:reason].to_s] }.each do |_, hist|
|
43
43
|
if hist.size >= 3
|
44
44
|
res << detail_process_info_string(hist[0])
|
45
45
|
res << detail_process_info_string(:state => "... #{hist.size - 2} times", :reason => '...', :at => hist[-1][:at])
|
@@ -29,9 +29,10 @@ module Eye::Controller::Status
|
|
29
29
|
str = <<-S
|
30
30
|
About: #{Eye::ABOUT}
|
31
31
|
Info: #{resources_str(Eye::SystemResources.resources($$), false)}
|
32
|
+
Ruby: #{RUBY_DESCRIPTION}
|
32
33
|
Logger: #{Eye::Logger.dev}
|
33
34
|
Socket: #{Eye::Settings::socket_path}
|
34
|
-
|
35
|
+
Pid: #{Eye::Settings::pid_path}
|
35
36
|
Actors: #{actors.inspect}
|
36
37
|
|
37
38
|
S
|
@@ -40,7 +41,7 @@ Actors: #{actors.inspect}
|
|
40
41
|
|
41
42
|
if show_config.present?
|
42
43
|
str += "\nCurrent config: \n"
|
43
|
-
str += YAML.dump(current_config)
|
44
|
+
str += YAML.dump(current_config.to_h)
|
44
45
|
end
|
45
46
|
|
46
47
|
GC.start
|
data/lib/eye/dsl.rb
CHANGED
@@ -11,13 +11,11 @@ class Eye::Dsl
|
|
11
11
|
autoload :ChildProcessOpts, 'eye/dsl/child_process_opts'
|
12
12
|
autoload :Opts, 'eye/dsl/opts'
|
13
13
|
autoload :PureOpts, 'eye/dsl/pure_opts'
|
14
|
-
autoload :Validate, 'eye/dsl/validate'
|
15
14
|
autoload :Chain, 'eye/dsl/chain'
|
16
15
|
autoload :ConfigOpts, 'eye/dsl/config_opts'
|
17
16
|
autoload :Validation, 'eye/dsl/validation'
|
18
17
|
|
19
18
|
class Error < Exception; end
|
20
|
-
extend Eye::Dsl::Validate
|
21
19
|
|
22
20
|
class << self
|
23
21
|
attr_accessor :verbose
|
@@ -26,12 +24,8 @@ class Eye::Dsl
|
|
26
24
|
puts msg if verbose
|
27
25
|
end
|
28
26
|
|
29
|
-
def initial_config
|
30
|
-
{:config => {}, :applications => {}}
|
31
|
-
end
|
32
|
-
|
33
27
|
def parse(content = nil, filename = nil)
|
34
|
-
Eye.parsed_config =
|
28
|
+
Eye.parsed_config = Eye::Config.new
|
35
29
|
Eye.parsed_filename = filename
|
36
30
|
|
37
31
|
content = File.read(filename) if content.blank?
|
@@ -40,13 +34,12 @@ class Eye::Dsl
|
|
40
34
|
Kernel.eval(content, Eye::BINDING, filename.to_s)
|
41
35
|
end
|
42
36
|
|
43
|
-
|
44
|
-
|
37
|
+
Eye.parsed_config.validate!
|
45
38
|
Eye.parsed_config
|
46
39
|
end
|
47
40
|
|
48
41
|
def parse_apps(*args)
|
49
|
-
parse(*args)
|
42
|
+
parse(*args).applications
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
data/lib/eye/dsl/config_opts.rb
CHANGED
@@ -24,7 +24,7 @@ class Eye::Dsl::ConfigOpts < Eye::Dsl::PureOpts
|
|
24
24
|
raise Eye::Dsl::Error, "unknown contact_type #{contact_type}" unless Eye::Notify::TYPES[contact_type]
|
25
25
|
raise Eye::Dsl::Error, "contact should be a String" unless contact.is_a?(String)
|
26
26
|
|
27
|
-
notify_hash = @config[contact_type] || (@parent && @parent.config[contact_type]) || Eye::parsed_config[
|
27
|
+
notify_hash = @config[contact_type] || (@parent && @parent.config[contact_type]) || Eye::parsed_config.settings[contact_type] || {}
|
28
28
|
validate_hash = notify_hash.merge(contact_opts).merge(:type => contact_type)
|
29
29
|
|
30
30
|
Eye::Notify.validate!(validate_hash)
|
data/lib/eye/dsl/main.rb
CHANGED
@@ -6,9 +6,7 @@ module Eye::Dsl::Main
|
|
6
6
|
opts = Eye::Dsl::ApplicationOpts.new(name)
|
7
7
|
opts.instance_eval(&block)
|
8
8
|
|
9
|
-
@parsed_config
|
10
|
-
@parsed_config[:applications] ||= {}
|
11
|
-
@parsed_config[:applications][name.to_s] = opts.config if opts.config
|
9
|
+
@parsed_config.applications[name.to_s] = opts.config if opts.config
|
12
10
|
|
13
11
|
Eye::Dsl.debug "<= app: #{name}"
|
14
12
|
end
|
@@ -32,12 +30,9 @@ module Eye::Dsl::Main
|
|
32
30
|
def config(&block)
|
33
31
|
Eye::Dsl.debug "=> config"
|
34
32
|
|
35
|
-
@parsed_config ||= {}
|
36
|
-
@parsed_config[:config] ||= {}
|
37
|
-
|
38
33
|
opts = Eye::Dsl::ConfigOpts.new
|
39
34
|
opts.instance_eval(&block)
|
40
|
-
@parsed_config
|
35
|
+
@parsed_config.settings.merge!(opts.config)
|
41
36
|
|
42
37
|
Eye::Dsl.debug "<= config"
|
43
38
|
end
|
data/lib/eye/group.rb
CHANGED
data/lib/eye/notify.rb
CHANGED
@@ -19,14 +19,14 @@ class Eye::Notify
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.notify(contact, message_h)
|
22
|
-
|
23
|
-
needed_hash = (
|
22
|
+
settings = Eye::Control.settings
|
23
|
+
needed_hash = (settings[:contacts] || {})[contact.to_s]
|
24
24
|
|
25
25
|
return if needed_hash.blank?
|
26
26
|
|
27
27
|
create_proc = lambda do |nh|
|
28
28
|
type = nh[:type]
|
29
|
-
config = (
|
29
|
+
config = (settings[type] || {}).merge(nh[:opts] || {}).merge(:contact => nh[:contact])
|
30
30
|
klass = get_class(type)
|
31
31
|
notify = klass.new(config, message_h)
|
32
32
|
notify.async_notify if notify
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Eye::Process::Controller
|
2
2
|
|
3
3
|
def send_command(command, *args)
|
4
|
-
schedule command, *args,
|
4
|
+
schedule command, *args, Eye::Reason::User.new(command)
|
5
5
|
end
|
6
6
|
|
7
7
|
def start
|
@@ -44,7 +44,7 @@ module Eye::Process::Controller
|
|
44
44
|
switch :already_running
|
45
45
|
else
|
46
46
|
warn "process not found, so :unmonitor"
|
47
|
-
schedule :unmonitor, 'not found'
|
47
|
+
schedule :unmonitor, Eye::Reason.new(:'not found')
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/eye/process/monitor.rb
CHANGED
@@ -40,7 +40,7 @@ private
|
|
40
40
|
unless process_realy_running?
|
41
41
|
warn "check_alive: process(#{self.pid}) not found!"
|
42
42
|
notify :info, 'crashed!'
|
43
|
-
switch :crashed,
|
43
|
+
switch :crashed, Eye::Reason.new(:crashed)
|
44
44
|
else
|
45
45
|
# check that pid_file still here
|
46
46
|
ppid = failsafe_load_pid
|
@@ -78,10 +78,10 @@ private
|
|
78
78
|
if down?
|
79
79
|
if self[:keep_alive]
|
80
80
|
warn 'check crashed: process is down'
|
81
|
-
schedule :restore,
|
81
|
+
schedule :restore, Eye::Reason.new(:crashed)
|
82
82
|
else
|
83
83
|
warn 'check crashed: process without keep_alive'
|
84
|
-
schedule :unmonitor,
|
84
|
+
schedule :unmonitor, Eye::Reason.new(:crashed)
|
85
85
|
end
|
86
86
|
else
|
87
87
|
debug 'check crashed: skipped, process is not in down'
|
@@ -8,12 +8,21 @@ module Eye::Process::Scheduler
|
|
8
8
|
return
|
9
9
|
end
|
10
10
|
|
11
|
-
reason = if args.present? &&
|
11
|
+
reason = if args.present? && args[-1].kind_of?(Eye::Reason)
|
12
12
|
args.pop
|
13
13
|
end
|
14
14
|
|
15
15
|
info "schedule :#{command} #{reason ? "(reason: #{reason})" : nil}"
|
16
|
-
|
16
|
+
|
17
|
+
if reason.class == Eye::Reason
|
18
|
+
# for auto reasons
|
19
|
+
# skip already running commands and all in chain
|
20
|
+
scheduler.add_wo_dups_current(:scheduled_action, command, {:args => args, :reason => reason}, &block)
|
21
|
+
else
|
22
|
+
# for manual, or without reason
|
23
|
+
# skip only for last in chain
|
24
|
+
scheduler.add_wo_dups(:scheduled_action, command, {:args => args, :reason => reason}, &block)
|
25
|
+
end
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
data/lib/eye/process/states.rb
CHANGED
data/lib/eye/process/trigger.rb
CHANGED
@@ -31,7 +31,7 @@ private
|
|
31
31
|
|
32
32
|
def on_flapping(trigger)
|
33
33
|
notify :error, 'flapping!'
|
34
|
-
schedule :unmonitor,
|
34
|
+
schedule :unmonitor, Eye::Reason.new(:flapping)
|
35
35
|
|
36
36
|
@retry_times ||= 0
|
37
37
|
retry_in = trigger.retry_in
|
@@ -47,7 +47,7 @@ private
|
|
47
47
|
return unless unmonitored?
|
48
48
|
return unless state_reason.to_s.include?('flapping') # TODO: remove hackety
|
49
49
|
|
50
|
-
schedule :start,
|
50
|
+
schedule :start, Eye::Reason.new(:'retry start after flapping')
|
51
51
|
@retry_times += 1
|
52
52
|
end
|
53
53
|
|
data/lib/eye/process/watchers.rb
CHANGED
@@ -62,7 +62,7 @@ private
|
|
62
62
|
|
63
63
|
action = subject.fire || :restart
|
64
64
|
notify :warn, "Bounded #{subject.check_name}: #{subject.last_human_values} send to :#{action}"
|
65
|
-
schedule action, "bounded #{subject.check_name}"
|
65
|
+
schedule action, Eye::Reason.new("bounded #{subject.check_name}")
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
data/lib/eye/reason.rb
ADDED
data/lib/eye/settings.rb
CHANGED
@@ -1,15 +1,26 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
|
3
3
|
module Eye::Settings
|
4
|
-
|
5
4
|
module_function
|
6
5
|
|
7
6
|
def dir
|
8
7
|
if Process::UID.eid == 0 # root
|
9
8
|
'/var/run/eye'
|
10
9
|
else
|
11
|
-
File.expand_path(File.join(
|
12
|
-
end
|
10
|
+
File.expand_path(File.join(home, '.eye'))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def eyeconfig
|
15
|
+
if Process::UID.eid == 0 # root
|
16
|
+
'/etc/eye.conf'
|
17
|
+
else
|
18
|
+
File.expand_path(File.join(home, '.eyeconfig'))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def home
|
23
|
+
ENV['EYE_HOME'] || ENV['HOME']
|
13
24
|
end
|
14
25
|
|
15
26
|
def path(path)
|
@@ -11,13 +11,23 @@ class Eye::Utils::CelluloidChain
|
|
11
11
|
|
12
12
|
def add(method_name, *args, &block)
|
13
13
|
@calls << {:method_name => method_name, :args => args, :block => block}
|
14
|
-
|
14
|
+
ensure_process
|
15
15
|
end
|
16
16
|
|
17
17
|
def add_wo_dups(method_name, *args, &block)
|
18
18
|
h = {:method_name => method_name, :args => args, :block => block}
|
19
|
-
|
20
|
-
|
19
|
+
if @calls[-1] != h
|
20
|
+
@calls << h
|
21
|
+
ensure_process
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_wo_dups_current(method_name, *args, &block)
|
26
|
+
h = {:method_name => method_name, :args => args, :block => block}
|
27
|
+
if !@calls.include?(h) && @call != h
|
28
|
+
@calls << h
|
29
|
+
ensure_process
|
30
|
+
end
|
21
31
|
end
|
22
32
|
|
23
33
|
def list
|
@@ -43,10 +53,17 @@ class Eye::Utils::CelluloidChain
|
|
43
53
|
|
44
54
|
private
|
45
55
|
|
56
|
+
def ensure_process
|
57
|
+
unless @running
|
58
|
+
@running = true
|
59
|
+
async.process
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
46
63
|
def process
|
47
|
-
while call = @calls.shift
|
64
|
+
while @call = @calls.shift
|
48
65
|
@running = true
|
49
|
-
@target.send(call[:method_name],
|
66
|
+
@target.send(@call[:method_name], *@call[:args], &@call[:block]) if @target.alive?
|
50
67
|
end
|
51
68
|
@running = false
|
52
69
|
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:
|
4
|
+
version: 0.3.1
|
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-
|
11
|
+
date: 2013-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: celluloid
|
@@ -276,11 +276,13 @@ files:
|
|
276
276
|
- lib/eye/checker/socket.rb
|
277
277
|
- lib/eye/child_process.rb
|
278
278
|
- lib/eye/client.rb
|
279
|
+
- lib/eye/config.rb
|
279
280
|
- lib/eye/control.rb
|
280
281
|
- lib/eye/controller.rb
|
281
282
|
- lib/eye/controller/commands.rb
|
282
283
|
- lib/eye/controller/helpers.rb
|
283
284
|
- lib/eye/controller/load.rb
|
285
|
+
- lib/eye/controller/options.rb
|
284
286
|
- lib/eye/controller/send_command.rb
|
285
287
|
- lib/eye/controller/show_history.rb
|
286
288
|
- lib/eye/controller/status.rb
|
@@ -295,7 +297,6 @@ files:
|
|
295
297
|
- lib/eye/dsl/opts.rb
|
296
298
|
- lib/eye/dsl/process_opts.rb
|
297
299
|
- lib/eye/dsl/pure_opts.rb
|
298
|
-
- lib/eye/dsl/validate.rb
|
299
300
|
- lib/eye/dsl/validation.rb
|
300
301
|
- lib/eye/group.rb
|
301
302
|
- lib/eye/group/chain.rb
|
@@ -319,6 +320,7 @@ files:
|
|
319
320
|
- lib/eye/process/trigger.rb
|
320
321
|
- lib/eye/process/validate.rb
|
321
322
|
- lib/eye/process/watchers.rb
|
323
|
+
- lib/eye/reason.rb
|
322
324
|
- lib/eye/server.rb
|
323
325
|
- lib/eye/settings.rb
|
324
326
|
- lib/eye/system.rb
|
data/lib/eye/dsl/validate.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module Eye::Dsl::Validate
|
2
|
-
|
3
|
-
# validate global config rules
|
4
|
-
def validate(config)
|
5
|
-
cfg = config[:config]
|
6
|
-
config = config[:applications]
|
7
|
-
|
8
|
-
all_processes = config.values.map{|e| (e[:groups] || {}).values.map{|c| (c[:processes] || {}).values} }.flatten
|
9
|
-
|
10
|
-
# Check blank pid_files
|
11
|
-
|
12
|
-
no_pid_file = all_processes.select{|c| c[:pid_file].blank? }
|
13
|
-
if no_pid_file.present?
|
14
|
-
raise Eye::Dsl::Error, "blank pid_file for: #{no_pid_file.map{|c| c[:name]} * ', '}"
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check dublicates of the full pid_file
|
18
|
-
|
19
|
-
dubl_pids = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
20
|
-
ex_pid_file = Eye::System.normalized_file(o[:pid_file], o[:working_dir])
|
21
|
-
h[ex_pid_file] += 1
|
22
|
-
end
|
23
|
-
dubl_pids = dubl_pids.select{|k,v| v>1}
|
24
|
-
|
25
|
-
if dubl_pids.present?
|
26
|
-
raise Eye::Dsl::Error, "dublicate pid_files: #{dubl_pids.inspect}"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Check dublicates of the full_name
|
30
|
-
dubl_names = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
31
|
-
full_name = "#{o[:application]}:#{o[:group]}:#{o[:name]}"
|
32
|
-
h[full_name] += 1
|
33
|
-
end
|
34
|
-
dubl_names = dubl_names.select{|k,v| v>1}
|
35
|
-
|
36
|
-
if dubl_names.present?
|
37
|
-
raise Eye::Dsl::Error, "dublicate names: #{dubl_names.inspect}"
|
38
|
-
end
|
39
|
-
|
40
|
-
# validate processes with their own validate
|
41
|
-
all_processes.each do |process_cfg|
|
42
|
-
Eye::Process.validate process_cfg
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|