eye 0.3 → 0.3.1
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 +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 [](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
|