eye 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -17
- data/bin/eye +5 -0
- data/examples/notify.eye +18 -0
- data/examples/process_thin.rb +29 -0
- data/examples/sidekiq.eye +5 -1
- data/examples/test.eye +24 -17
- data/examples/thin-farm.eye +29 -0
- data/examples/unicorn.eye +2 -0
- data/eye.gemspec +1 -1
- data/lib/eye.rb +1 -1
- data/lib/eye/checker.rb +3 -5
- data/lib/eye/checker/http.rb +1 -2
- data/lib/eye/checker/socket.rb +2 -2
- data/lib/eye/controller/commands.rb +2 -0
- data/lib/eye/controller/send_command.rb +8 -2
- data/lib/eye/dsl.rb +1 -0
- data/lib/eye/dsl/opts.rb +36 -2
- data/lib/eye/dsl/pure_opts.rb +17 -39
- data/lib/eye/{checker → dsl}/validation.rb +15 -5
- data/lib/eye/group.rb +13 -4
- data/lib/eye/group/chain.rb +11 -0
- data/lib/eye/notify.rb +1 -1
- data/lib/eye/notify/mail.rb +1 -1
- data/lib/eye/process/child.rb +0 -2
- data/lib/eye/process/commands.rb +11 -14
- data/lib/eye/process/monitor.rb +10 -16
- data/lib/eye/process/scheduler.rb +8 -3
- data/lib/eye/process/states.rb +1 -2
- data/lib/eye/process/system.rb +38 -7
- data/lib/eye/process/watchers.rb +3 -3
- data/lib/eye/settings.rb +1 -1
- data/lib/eye/system.rb +33 -16
- data/lib/eye/trigger.rb +1 -1
- data/lib/eye/utils/celluloid_chain.rb +2 -0
- data/spec/checker/cpu_spec.rb +1 -1
- data/spec/checker/http_spec.rb +2 -2
- data/spec/checker/memory_spec.rb +2 -2
- data/spec/checker_spec.rb +1 -1
- data/spec/controller/controller_spec.rb +6 -0
- data/spec/controller/find_objects_spec.rb +6 -0
- data/spec/controller/intergration_spec.rb +24 -0
- data/spec/dsl/checks_spec.rb +2 -2
- data/spec/dsl/notify_spec.rb +12 -3
- data/spec/dsl/with_server_spec.rb +26 -2
- data/spec/process/checks/child_checks_spec.rb +1 -1
- data/spec/process/checks/memory_spec.rb +14 -0
- data/spec/process/scheduler_spec.rb +8 -0
- data/spec/process/system_spec.rb +27 -4
- data/spec/spec_helper.rb +3 -1
- data/spec/system_spec.rb +12 -5
- data/spec/utils/celluloid_chain_spec.rb +8 -0
- metadata +8 -5
data/lib/eye/process/watchers.rb
CHANGED
@@ -9,7 +9,6 @@ module Eye::Process::Watchers
|
|
9
9
|
# default watcher :check_alive
|
10
10
|
add_watcher(:check_alive, self[:check_alive_period]) do
|
11
11
|
check_alive
|
12
|
-
GC.start if rand(1000) == 0
|
13
12
|
end
|
14
13
|
|
15
14
|
# monitor childs pids
|
@@ -61,8 +60,9 @@ private
|
|
61
60
|
unless subject.check
|
62
61
|
return unless up?
|
63
62
|
|
64
|
-
|
65
|
-
|
63
|
+
action = subject.fire || :restart
|
64
|
+
notify :crit, "Bounded #{subject.check_name}: #{subject.last_human_values} send to :#{action}"
|
65
|
+
schedule action, "bounded #{subject.check_name}"
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
data/lib/eye/settings.rb
CHANGED
data/lib/eye/system.rb
CHANGED
@@ -3,13 +3,28 @@ require 'pathname'
|
|
3
3
|
|
4
4
|
module Eye::System
|
5
5
|
class << self
|
6
|
+
# Check that pid realy exits
|
7
|
+
# very fast
|
8
|
+
# return result hash
|
9
|
+
def check_pid_alive(pid)
|
10
|
+
res = if pid
|
11
|
+
::Process.kill(0, pid)
|
12
|
+
true
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
{:result => res}
|
18
|
+
rescue => ex
|
19
|
+
{:error => ex}
|
20
|
+
end
|
6
21
|
|
7
22
|
# Check that pid realy exits
|
8
23
|
# very fast
|
24
|
+
# return true/false
|
9
25
|
def pid_alive?(pid)
|
10
|
-
|
11
|
-
|
12
|
-
false
|
26
|
+
res = check_pid_alive(pid)
|
27
|
+
!!res[:result]
|
13
28
|
end
|
14
29
|
|
15
30
|
# Send signal to process (uses for kill)
|
@@ -22,17 +37,15 @@ module Eye::System
|
|
22
37
|
end
|
23
38
|
code = code.to_s.upcase if code.is_a?(String) || code.is_a?(Symbol)
|
24
39
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
rescue Errno::EPERM
|
32
|
-
{:status => :error, :message => 'wrong permissions to kill'}
|
40
|
+
if pid
|
41
|
+
::Process.kill(code, pid)
|
42
|
+
{:result => :ok}
|
43
|
+
else
|
44
|
+
{:error => Exception.new('no_pid')}
|
45
|
+
end
|
33
46
|
|
34
|
-
rescue =>
|
35
|
-
{:
|
47
|
+
rescue => ex
|
48
|
+
{:error => ex}
|
36
49
|
end
|
37
50
|
|
38
51
|
# Daemonize cmd, and detach
|
@@ -60,14 +73,18 @@ module Eye::System
|
|
60
73
|
opts = spawn_options(cfg)
|
61
74
|
pid = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)
|
62
75
|
|
63
|
-
|
76
|
+
timeout = cfg[:timeout] || 1.second
|
77
|
+
Timeout.timeout(timeout) do
|
64
78
|
Process.waitpid(pid)
|
65
79
|
end
|
66
80
|
|
67
81
|
{:pid => pid}
|
68
82
|
|
69
|
-
rescue Timeout::Error => ex
|
70
|
-
|
83
|
+
rescue Timeout::Error => ex
|
84
|
+
if pid
|
85
|
+
Eye.warn "[#{cfg[:name]}] send signal 9 to #{pid} (because of timeouted<#{timeout}> execution)"
|
86
|
+
send_signal(pid, 9)
|
87
|
+
end
|
71
88
|
{:error => ex}
|
72
89
|
|
73
90
|
rescue Errno::ENOENT, Errno::EACCES => ex
|
data/lib/eye/trigger.rb
CHANGED
data/spec/checker/cpu_spec.rb
CHANGED
@@ -51,7 +51,7 @@ describe "Eye::Checker::Cpu" do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it "bad param below" do
|
54
|
-
expect{ Eye::Checker.validate!({:type => :cpu, :every => 5.seconds, :times => 1, :below => {1 => 2}}) }.to raise_error(Eye::
|
54
|
+
expect{ Eye::Checker.validate!({:type => :cpu, :every => 5.seconds, :times => 1, :below => {1 => 2}}) }.to raise_error(Eye::Dsl::Validation::Error)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
data/spec/checker/http_spec.rb
CHANGED
@@ -101,13 +101,13 @@ describe "Eye::Checker::Http" do
|
|
101
101
|
it "without param url" do
|
102
102
|
expect{ Eye::Checker.validate!({:type => :http, :every => 5.seconds,
|
103
103
|
:times => 1, :kind => :success,
|
104
|
-
:pattern => /OK/, :timeout => 2}) }.to raise_error(Eye::
|
104
|
+
:pattern => /OK/, :timeout => 2}) }.to raise_error(Eye::Dsl::Validation::Error)
|
105
105
|
end
|
106
106
|
|
107
107
|
it "bad param timeout" do
|
108
108
|
expect{ Eye::Checker.validate!({:type => :http, :every => 5.seconds,
|
109
109
|
:times => 1, :kind => :success, :url => "http://localhost:3000/",
|
110
|
-
:pattern => /OK/, :timeout => :fix}) }.to raise_error(Eye::
|
110
|
+
:pattern => /OK/, :timeout => :fix}) }.to raise_error(Eye::Dsl::Validation::Error)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
data/spec/checker/memory_spec.rb
CHANGED
@@ -51,11 +51,11 @@ describe "Eye::Checker::Memory" do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
it "bad param below" do
|
54
|
-
expect{ Eye::Checker.validate!({:type => :memory, :every => 5.seconds, :times => 1, :below => {1 => 2}}) }.to raise_error(Eye::
|
54
|
+
expect{ Eye::Checker.validate!({:type => :memory, :every => 5.seconds, :times => 1, :below => {1 => 2}}) }.to raise_error(Eye::Dsl::Validation::Error)
|
55
55
|
end
|
56
56
|
|
57
57
|
it "unknown params" do
|
58
|
-
expect{ Eye::Checker.validate!({:hello => true, :type => :memory, :every => 5.seconds, :times => 1, :below => 10.0.bytes})}.to raise_error(Eye::
|
58
|
+
expect{ Eye::Checker.validate!({:hello => true, :type => :memory, :every => 5.seconds, :times => 1, :below => 10.0.bytes})}.to raise_error(Eye::Dsl::Validation::Error)
|
59
59
|
end
|
60
60
|
|
61
61
|
end
|
data/spec/checker_spec.rb
CHANGED
@@ -138,7 +138,7 @@ describe "Eye::Checker" do
|
|
138
138
|
end
|
139
139
|
|
140
140
|
it "validate by default" do
|
141
|
-
expect{ Checker1.validate({:times => "jopa"}) }.to raise_error(Eye::
|
141
|
+
expect{ Checker1.validate({:times => "jopa"}) }.to raise_error(Eye::Dsl::Validation::Error)
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
@@ -104,6 +104,12 @@ S
|
|
104
104
|
subject.info_string_short.split("\n").size.should == 2
|
105
105
|
end
|
106
106
|
|
107
|
+
it "should delete all apps" do
|
108
|
+
subject.load(fixture("dsl/load.eye")).should include(error: false)
|
109
|
+
subject.send_command(:delete, 'all')
|
110
|
+
subject.applications.should be_empty
|
111
|
+
end
|
112
|
+
|
107
113
|
describe "command" do
|
108
114
|
it "should send_command" do
|
109
115
|
mock(Eye::Control).send_command(:restart, 'samples')
|
@@ -67,6 +67,12 @@ describe "find_objects" do
|
|
67
67
|
objs.map{|c| c.name}.sort.should == %w{app1 app2}
|
68
68
|
end
|
69
69
|
|
70
|
+
it "'*', find all projects" do
|
71
|
+
objs = subject.find_objects("*")
|
72
|
+
objs.map{|c| c.class}.should == [Eye::Application, Eye::Application]
|
73
|
+
objs.map{|c| c.name}.sort.should == %w{app1 app2}
|
74
|
+
end
|
75
|
+
|
70
76
|
it "nothing" do
|
71
77
|
subject.find_objects("asdfasdf").should == []
|
72
78
|
end
|
@@ -166,6 +166,30 @@ describe "Intergration" do
|
|
166
166
|
# nothing happens
|
167
167
|
@samples.alive?.should == true
|
168
168
|
end
|
169
|
+
|
170
|
+
it "chain breaker breaks current chain and all pending requests" do
|
171
|
+
@samples.config.merge!(:chain => C.restart_async)
|
172
|
+
|
173
|
+
@c.send_command(:restart, "samples")
|
174
|
+
@c.send_command(:stop, "samples")
|
175
|
+
sleep 0.5
|
176
|
+
|
177
|
+
@samples.current_scheduled_command.should == :restart
|
178
|
+
@samples.scheduler_actions_list.should == [:stop]
|
179
|
+
|
180
|
+
@c.send_command(:break_chain, "samples")
|
181
|
+
sleep 3
|
182
|
+
@samples.current_scheduled_command.should == :restart
|
183
|
+
sleep 2
|
184
|
+
@samples.current_scheduled_command.should == nil
|
185
|
+
@samples.scheduler_actions_list.should == []
|
186
|
+
|
187
|
+
sleep 1
|
188
|
+
|
189
|
+
# only first process should be restarted
|
190
|
+
@p1.last_scheduled_command.should == :restart
|
191
|
+
@p2.last_scheduled_command.should == :monitor
|
192
|
+
end
|
169
193
|
end
|
170
194
|
|
171
195
|
it "stop group" do
|
data/spec/dsl/checks_spec.rb
CHANGED
@@ -73,7 +73,7 @@ describe "Eye::Dsl checks" do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
E
|
76
|
-
expect{Eye::Dsl.parse_apps(conf)}.to raise_error(Eye::
|
76
|
+
expect{Eye::Dsl.parse_apps(conf)}.to raise_error(Eye::Dsl::Validation::Error)
|
77
77
|
end
|
78
78
|
|
79
79
|
it "ok trigger" do
|
@@ -98,7 +98,7 @@ describe "Eye::Dsl checks" do
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
E
|
101
|
-
expect{Eye::Dsl.parse_apps(conf)}.to raise_error(Eye::
|
101
|
+
expect{Eye::Dsl.parse_apps(conf)}.to raise_error(Eye::Dsl::Validation::Error)
|
102
102
|
end
|
103
103
|
|
104
104
|
it "nochecks to remove inherit checks" do
|
data/spec/dsl/notify_spec.rb
CHANGED
@@ -56,7 +56,7 @@ describe "Eye::Dsl notify" do
|
|
56
56
|
it "raise on unknown contact type" do
|
57
57
|
conf = <<-E
|
58
58
|
Eye.config do
|
59
|
-
contact :vasya, :dddd, "vasya@mail.ru"
|
59
|
+
contact :vasya, :dddd, "vasya@mail.ru", :host => "localhost", :port => 12
|
60
60
|
end
|
61
61
|
E
|
62
62
|
expect{ Eye::Dsl.parse(conf) }.to raise_error(Eye::Dsl::Error)
|
@@ -65,10 +65,19 @@ describe "Eye::Dsl notify" do
|
|
65
65
|
it "raise on unknown additional_options" do
|
66
66
|
conf = <<-E
|
67
67
|
Eye.config do
|
68
|
-
contact :vasya, :mail, "vasya@mail.ru", :bla => 1
|
68
|
+
contact :vasya, :mail, "vasya@mail.ru", :host => "localhost", :port => 12, :bla => 1
|
69
69
|
end
|
70
70
|
E
|
71
|
-
expect{ Eye::Dsl.parse(conf) }.to raise_error(Eye::
|
71
|
+
expect{ Eye::Dsl.parse(conf) }.to raise_error(Eye::Dsl::Validation::Error)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "raise on not including on list of values" do
|
75
|
+
conf = <<-E
|
76
|
+
Eye.config do
|
77
|
+
contact :vasya, :mail, "vasya@mail.ru", :host => "localhost", :port => 12, :auth => :ply
|
78
|
+
end
|
79
|
+
E
|
80
|
+
expect{ Eye::Dsl.parse(conf) }.to raise_error(Eye::Dsl::Validation::Error)
|
72
81
|
end
|
73
82
|
|
74
83
|
it "set notify inherited" do
|
@@ -38,6 +38,28 @@ describe "with_server feature" do
|
|
38
38
|
Eye::Dsl.parse_apps(conf).should == {"bla"=>{:name => "bla", :groups=>{"__default__"=>{:name => "__default__", :application => "bla", :processes=>{"1"=>{:pid_file=>"1.pid", :application=>"bla", :group=>"__default__", :name=>"1"}}}}}}
|
39
39
|
end
|
40
40
|
|
41
|
+
it "should behaves like scoped" do
|
42
|
+
stub(Eye::System).host{ "server1" }
|
43
|
+
|
44
|
+
conf = <<-E
|
45
|
+
Eye.application("bla") do
|
46
|
+
env "A" => "B"
|
47
|
+
with_server /server1/ do
|
48
|
+
env "A" => "C"
|
49
|
+
group(:a){}
|
50
|
+
end
|
51
|
+
|
52
|
+
group(:b){}
|
53
|
+
end
|
54
|
+
E
|
55
|
+
|
56
|
+
Eye::Dsl.parse_apps(conf).should == {
|
57
|
+
"bla" => {:name=>"bla", :environment=>{"A"=>"B"},
|
58
|
+
:groups=>{
|
59
|
+
"a"=>{:name=>"a", :environment=>{"A"=>"C"}, :application=>"bla", :processes=>{}},
|
60
|
+
"b"=>{:name=>"b", :environment=>{"A"=>"B"}, :application=>"bla", :processes=>{}}}}}
|
61
|
+
end
|
62
|
+
|
41
63
|
describe "matches" do
|
42
64
|
subject{ Eye::Dsl::Opts.new }
|
43
65
|
|
@@ -80,11 +102,13 @@ describe "with_server feature" do
|
|
80
102
|
conf = <<-E
|
81
103
|
Eye.application("bla"){
|
82
104
|
with_server('mega_server') do
|
83
|
-
|
105
|
+
group :blo do
|
106
|
+
working_dir "/tmp"
|
107
|
+
end
|
84
108
|
end
|
85
109
|
}
|
86
110
|
E
|
87
|
-
Eye::Dsl.parse_apps(conf).should == {"bla" => {:
|
111
|
+
Eye::Dsl.parse_apps(conf).should == {"bla" => {:name=>"bla", :groups=>{"blo"=>{:name=>"blo", :application=>"bla", :working_dir=>"/tmp", :processes=>{}}}}}
|
88
112
|
end
|
89
113
|
|
90
114
|
it "hostname work" do
|
@@ -70,7 +70,7 @@ describe "ChildProcess" do
|
|
70
70
|
|
71
71
|
|
72
72
|
crazy.watchers.keys.should == [:check_memory, :check_cpu]
|
73
|
-
mock(crazy).notify(:crit, "Bounded cpu(50%): [*55%, *55%]")
|
73
|
+
mock(crazy).notify(:crit, "Bounded cpu(50%): [*55%, *55%] send to :restart")
|
74
74
|
mock(crazy).schedule :restart, anything
|
75
75
|
|
76
76
|
sleep 4
|
@@ -37,6 +37,20 @@ describe "Process Memory check" do
|
|
37
37
|
sleep 1
|
38
38
|
end
|
39
39
|
|
40
|
+
it "when memory exceed limit process should stop if fire==stop" do
|
41
|
+
@check = {:memory => {:every => 2, :below => 40.megabytes, :times => 1, :type => :memory, :fire => :stop}}
|
42
|
+
start_ok_process(@c.merge(:checks => @check))
|
43
|
+
stub(Eye::SystemResources).memory(@process.pid){ 20_000 }
|
44
|
+
|
45
|
+
sleep 3
|
46
|
+
|
47
|
+
stub(Eye::SystemResources).memory(@process.pid){ 50_000 }
|
48
|
+
mock(@process).notify(:crit, anything)
|
49
|
+
mock(@process).schedule(:stop, anything)
|
50
|
+
|
51
|
+
sleep 1
|
52
|
+
end
|
53
|
+
|
40
54
|
it "else should not restart" do
|
41
55
|
start_ok_process(@c.merge(:checks => @check))
|
42
56
|
|
@@ -122,6 +122,14 @@ describe "Scheduler" do
|
|
122
122
|
scheduler.alive?.should == false
|
123
123
|
end
|
124
124
|
|
125
|
+
it "schedule unexisted method should not raise and break anything" do
|
126
|
+
scheduler = @process.scheduler
|
127
|
+
@process.schedule :hahhaha
|
128
|
+
sleep 0.2
|
129
|
+
@process.alive?.should == true
|
130
|
+
scheduler.alive?.should == true
|
131
|
+
end
|
132
|
+
|
125
133
|
describe "reasons" do
|
126
134
|
it "1 param without reason" do
|
127
135
|
@process.schedule :scheduler_test3, 1
|
data/spec/process/system_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe "Eye::Process::System" do
|
|
4
4
|
before :each do
|
5
5
|
@process = Eye::Process.new(C.p1)
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
it "load_pid_from_file" do
|
9
9
|
File.open(@process[:pid_file_ex], 'w'){|f| f.write("asdf") }
|
10
10
|
@process.load_pid_from_file.should == nil
|
@@ -16,6 +16,17 @@ describe "Eye::Process::System" do
|
|
16
16
|
@process.load_pid_from_file.should == nil
|
17
17
|
end
|
18
18
|
|
19
|
+
it "failsafe_load_pid" do
|
20
|
+
File.open(@process[:pid_file_ex], 'w'){|f| f.write("asdf") }
|
21
|
+
@process.failsafe_load_pid.should == nil
|
22
|
+
|
23
|
+
File.open(@process[:pid_file_ex], 'w'){|f| f.write(12345) }
|
24
|
+
@process.failsafe_load_pid.should == 12345
|
25
|
+
|
26
|
+
FileUtils.rm(@process[:pid_file_ex]) rescue nil
|
27
|
+
@process.failsafe_load_pid.should == nil
|
28
|
+
end
|
29
|
+
|
19
30
|
it "set_pid_from_file" do
|
20
31
|
File.open(@process[:pid_file_ex], 'w'){|f| f.write(12345) }
|
21
32
|
@process.set_pid_from_file
|
@@ -29,6 +40,18 @@ describe "Eye::Process::System" do
|
|
29
40
|
File.read(@process[:pid_file_ex]).to_i.should == 123456789
|
30
41
|
end
|
31
42
|
|
43
|
+
it "failsafe_save_pid ok case" do
|
44
|
+
@process.pid = 123456789
|
45
|
+
@process.failsafe_save_pid.should == true
|
46
|
+
File.read(@process[:pid_file_ex]).to_i.should == 123456789
|
47
|
+
end
|
48
|
+
|
49
|
+
it "failsafe_save_pid bad case" do
|
50
|
+
@process.config[:pid_file_ex] = "/asdf/adf/asd/fs/dfs/das/df.1"
|
51
|
+
@process.pid = 123456789
|
52
|
+
@process.failsafe_save_pid.should == false
|
53
|
+
end
|
54
|
+
|
32
55
|
it "clear_pid_file" do
|
33
56
|
@process.pid = 123456789
|
34
57
|
@process.save_pid_to_file
|
@@ -46,16 +69,16 @@ describe "Eye::Process::System" do
|
|
46
69
|
@process.process_realy_running?.should == nil
|
47
70
|
|
48
71
|
@process.pid = -123434
|
49
|
-
@process.process_realy_running?.should ==
|
72
|
+
@process.process_realy_running?.should == nil
|
50
73
|
end
|
51
74
|
|
52
75
|
it "send_signal ok" do
|
53
|
-
mock(Eye::System).send_signal(@process.pid, :TERM){ {:
|
76
|
+
mock(Eye::System).send_signal(@process.pid, :TERM){ {:result => :ok} }
|
54
77
|
@process.send_signal(:TERM).should == true
|
55
78
|
end
|
56
79
|
|
57
80
|
it "send_signal not ok" do
|
58
|
-
mock(Eye::System).send_signal(@process.pid, :TERM){ {:
|
81
|
+
mock(Eye::System).send_signal(@process.pid, :TERM){ {:error => Exception.new('bla')} }
|
59
82
|
@process.send_signal(:TERM).should == false
|
60
83
|
end
|
61
84
|
|