eye 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
|