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 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