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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae0406a7f4bd886b167c02a54f60eed9c31c1f50
4
- data.tar.gz: 37f991e3ab296e74f568ea84c40e6b57d9240ccb
3
+ metadata.gz: c291e8ed14e7f8199676afd126f117dbc5a491ed
4
+ data.tar.gz: be96f87f1d1f70d5666d8a1e63e60516317ec499
5
5
  SHA512:
6
- metadata.gz: d0fca55046216067bc3a924a3526d1e483f8aceef3a72bac53462978f35df794fd2a4bbfe0e776f989273abb5f8709b7c676302caeffe098c1b6dd07955ccd65
7
- data.tar.gz: 5311297341068796e16ae6e13035fbbde98b71891caa3738229bafa7f3762a88c97839b71ecae890f4fb114ef6d60b5aec6f8dfa119e4c7b2ac80f104154ea82
6
+ metadata.gz: 33701932d6954c9c274e4f80ac87c1c21a257ab53d351b43c65a0d95eba98227e5ca9d889c2ee6a4857ef38df89d89d83bce90f647732fc85a87f8afde9b4f4d
7
+ data.tar.gz: 9cfe4c03629ef7f28138caa6cf84e73fbc317c19e5d5712e39728fe58137b93fa9674385e9b78413e4f41926d0da7d608b1a13f37fc1d3eb349d72f6cf6336f9
data/.gitignore CHANGED
@@ -29,3 +29,4 @@ experiments
29
29
  *sublime*
30
30
  examples/work*.eye
31
31
  script
32
+ [0-9].rb
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
1
  --color
2
2
  --profile
3
-
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.2. Uses Celluloid and Celluloid::IO.
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
@@ -3,7 +3,9 @@ require "bundler/gem_tasks"
3
3
 
4
4
  require 'rspec/core/rake_task'
5
5
  task :default => :spec
6
- RSpec::Core::RakeTask.new(:spec)
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.verbose = false
8
+ end
7
9
 
8
10
  task :env do
9
11
  require 'bundler/setup'
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(conf = "")
44
- conf = File.expand_path(conf) if !conf.empty?
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
- server_start_foregraund(conf)
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, conf)
56
+ say_load_result cmd(:load, *configs)
52
57
 
53
58
  else
54
- server_start(conf)
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
- if res[:error]
174
- say "config error: ", :red
175
- say res[:message]
178
+ say(res) unless res.is_a?(Hash)
176
179
 
177
- res[:backtrace].to_a.each{|line| say line}
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
- exit 1
180
- else
181
- if opts[:started]
182
- say "started and loaded!", :yellow if !res[:empty]
183
- elsif opts[:syntax]
184
- say "config ok!", :yellow if !res[:empty]
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!", :yellow if !res[:empty]
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
- Gem.bin_path('eye', 'loader_eye')
220
- rescue Gem::GemNotFoundException, Gem::Exception
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(conf = nil)
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 conf && !conf.empty?
272
- say_load_result cmd(:load, conf), :started => true
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!", :yellow
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 = get_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 get_value
119
- Celluloid::Future.new{ get_value_deferred }.value
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
@@ -29,7 +29,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
29
29
  @read_timeout = (read_timeout || timeout || 15).to_f
30
30
  end
31
31
 
32
- def get_value_deferred
32
+ def get_value
33
33
  res = session.start{ |http| http.get(@uri.request_uri) }
34
34
  {:result => res}
35
35
 
@@ -35,7 +35,7 @@ class Eye::Checker::Socket < Eye::Checker::Defer
35
35
  end
36
36
  end
37
37
 
38
- def get_value_deferred
38
+ def get_value
39
39
  sock = begin
40
40
  Timeout::timeout(@open_timeout){ open_socket }
41
41
  rescue Timeout::Error
@@ -55,7 +55,7 @@ class Eye::ChildProcess
55
55
  end
56
56
 
57
57
  def send_command(command, *args)
58
- schedule command, *args, "#{command} by user"
58
+ schedule command, *args, Eye::Reason::User.new(command)
59
59
  end
60
60
 
61
61
  def start
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
@@ -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::Dsl.initial_config
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 self_config
48
- current_config[:config]
49
+ def settings
50
+ current_config.settings
49
51
  end
50
52
 
51
53
  end
@@ -1,7 +1,7 @@
1
1
  module Eye::Controller::Helpers
2
2
 
3
3
  def set_proc_line
4
- str = "eye monitoring v#{Eye::VERSION}"
4
+ str = Eye::PROCLINE
5
5
  str += " (#{@applications.map(&:name) * ', '})" if @applications.present?
6
6
  $0 = str
7
7
  end
@@ -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) do
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) do
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
- # filename is a path, or folder, or mask
17
- def load(filename = '')
18
- catch_load_error(filename) do
19
- _load(filename)
20
- set_proc_line
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
- # return: result, config
46
- def parse_config(filename = '', &block)
47
- raise Eye::Dsl::Error, "config file '#{filename}' not found!" unless File.exists?(filename)
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
- debug "load: globbing mask #{mask}"
63
- configs = []
64
-
65
- Dir[mask].each do |config_path|
66
- info "load: config #{config_path}"
67
- configs << parse_config(config_path)
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
- raise Eye::Dsl::Error, "config file '#{mask}' not found!" if configs.blank?
61
+ debug "load: globbing mask #{mask}"
71
62
 
72
- @loaded_config = Eye::Dsl.initial_config
73
- configs.each do |cfg|
74
- @loaded_config = merge_configs(@loaded_config, cfg)
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
- new_cfg = merge_configs(@current_config, @loaded_config)
78
- validate(new_cfg)
79
- new_cfg
72
+ res
80
73
  end
81
74
 
82
- def _load(filename)
83
- info "load: #{filename} in #{Eye::VERSION}"
84
- new_cfg = parse_set_of_configs(filename)
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
- def load_config(new_config, changed_apps = [])
91
- load_options(new_config[:config])
92
- create_objects(new_config[:applications], changed_apps)
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
- def merge_configs(old_config, new_config)
97
- {:config => old_config[:config].merge(new_config[:config]),
98
- :applications => old_config[:applications].merge(new_config[:applications])}
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
- if opts[:logger]
106
- # do not apply logger, if in stdout state
107
- if !%w{stdout stderr}.include?(Eye::Logger.dev)
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[:applications].delete(obj.name)
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[:applications].each do |app_name, app_cfg|
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 = obj_strs.map{|c| c.split(",").map{|mask| find_objects_by_mask(mask) }}.flatten
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
- PidPath: #{Eye::Settings::pid_path}
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 = initial_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
- validate(Eye.parsed_config)
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)[:applications] || {}
42
+ parse(*args).applications
50
43
  end
51
44
  end
52
45
  end
@@ -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[:config][contact_type] || {}
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[:config].merge!(opts.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
@@ -74,7 +74,7 @@ class Eye::Group
74
74
  when :break_chain
75
75
  break_chain *args
76
76
  else
77
- schedule command, *args, "#{command} by user"
77
+ schedule command, *args, Eye::Reason::User.new(command)
78
78
  end
79
79
  end
80
80
 
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
- self_config = Eye::Control.self_config
23
- needed_hash = (self_config[:contacts] || {})[contact.to_s]
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 = (self_config[type] || {}).merge(nh[:opts] || {}).merge(:contact => nh[:contact])
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, "#{command} by user"
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
@@ -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, '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, 'crashed'
81
+ schedule :restore, Eye::Reason.new(:crashed)
82
82
  else
83
83
  warn 'check crashed: process without keep_alive'
84
- schedule :unmonitor, 'crashed'
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? && [String, Symbol].include?(args[-1].class)
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
- scheduler.add_wo_dups(:scheduled_action, command, {:args => args, :reason => reason}, &block)
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
 
@@ -61,7 +61,7 @@ class Eye::Process
61
61
  end
62
62
 
63
63
  def on_crashed
64
- schedule :check_crash, 'crashed'
64
+ schedule :check_crash, Eye::Reason.new(:crashed)
65
65
  end
66
66
 
67
67
  def on_unmonitored
@@ -31,7 +31,7 @@ private
31
31
 
32
32
  def on_flapping(trigger)
33
33
  notify :error, 'flapping!'
34
- schedule :unmonitor, "flapping"
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, "retry start after flapping"
50
+ schedule :start, Eye::Reason.new(:'retry start after flapping')
51
51
  @retry_times += 1
52
52
  end
53
53
 
@@ -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
@@ -0,0 +1,20 @@
1
+ class Eye::Reason
2
+
3
+ def initialize(mes = nil)
4
+ @message = mes
5
+ end
6
+
7
+ def to_s
8
+ @message.to_s
9
+ end
10
+
11
+ def user?
12
+ self.class == User
13
+ end
14
+
15
+ class User < Eye::Reason
16
+ def to_s
17
+ "#{super} by user"
18
+ end
19
+ end
20
+ end
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(ENV['EYE_HOME'] || ENV['HOME'], '.eye'))
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
- async.process unless @running
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
- @calls << h if @calls[-1] != h
20
- async.process unless @running
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], *call[:args], &call[:block]) if @target.alive?
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: '0.3'
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-05-19 00:00:00.000000000 Z
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
@@ -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