ace-eye 0.6.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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +38 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/CHANGES.md +77 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE +22 -0
  8. data/README.md +212 -0
  9. data/Rakefile +35 -0
  10. data/bin/eye +5 -0
  11. data/bin/loader_eye +72 -0
  12. data/bin/runner +16 -0
  13. data/examples/dependency.eye +17 -0
  14. data/examples/notify.eye +19 -0
  15. data/examples/plugin/README.md +15 -0
  16. data/examples/plugin/main.eye +15 -0
  17. data/examples/plugin/plugin.rb +63 -0
  18. data/examples/process_thin.rb +29 -0
  19. data/examples/processes/em.rb +57 -0
  20. data/examples/processes/forking.rb +20 -0
  21. data/examples/processes/sample.rb +144 -0
  22. data/examples/processes/thin.ru +12 -0
  23. data/examples/puma.eye +29 -0
  24. data/examples/rbenv.eye +11 -0
  25. data/examples/sidekiq.eye +23 -0
  26. data/examples/test.eye +87 -0
  27. data/examples/thin-farm.eye +30 -0
  28. data/examples/unicorn.eye +39 -0
  29. data/eye.gemspec +40 -0
  30. data/lib/eye.rb +28 -0
  31. data/lib/eye/application.rb +73 -0
  32. data/lib/eye/checker.rb +258 -0
  33. data/lib/eye/checker/children_count.rb +44 -0
  34. data/lib/eye/checker/children_memory.rb +12 -0
  35. data/lib/eye/checker/cpu.rb +17 -0
  36. data/lib/eye/checker/cputime.rb +13 -0
  37. data/lib/eye/checker/file_ctime.rb +24 -0
  38. data/lib/eye/checker/file_size.rb +34 -0
  39. data/lib/eye/checker/file_touched.rb +15 -0
  40. data/lib/eye/checker/http.rb +96 -0
  41. data/lib/eye/checker/memory.rb +17 -0
  42. data/lib/eye/checker/nop.rb +6 -0
  43. data/lib/eye/checker/runtime.rb +18 -0
  44. data/lib/eye/checker/socket.rb +159 -0
  45. data/lib/eye/child_process.rb +101 -0
  46. data/lib/eye/cli.rb +185 -0
  47. data/lib/eye/cli/commands.rb +78 -0
  48. data/lib/eye/cli/render.rb +130 -0
  49. data/lib/eye/cli/server.rb +93 -0
  50. data/lib/eye/client.rb +32 -0
  51. data/lib/eye/config.rb +91 -0
  52. data/lib/eye/control.rb +2 -0
  53. data/lib/eye/controller.rb +54 -0
  54. data/lib/eye/controller/commands.rb +88 -0
  55. data/lib/eye/controller/helpers.rb +101 -0
  56. data/lib/eye/controller/load.rb +224 -0
  57. data/lib/eye/controller/options.rb +18 -0
  58. data/lib/eye/controller/send_command.rb +177 -0
  59. data/lib/eye/controller/status.rb +72 -0
  60. data/lib/eye/dsl.rb +53 -0
  61. data/lib/eye/dsl/application_opts.rb +39 -0
  62. data/lib/eye/dsl/chain.rb +12 -0
  63. data/lib/eye/dsl/child_process_opts.rb +13 -0
  64. data/lib/eye/dsl/config_opts.rb +55 -0
  65. data/lib/eye/dsl/group_opts.rb +32 -0
  66. data/lib/eye/dsl/helpers.rb +20 -0
  67. data/lib/eye/dsl/main.rb +51 -0
  68. data/lib/eye/dsl/opts.rb +151 -0
  69. data/lib/eye/dsl/process_opts.rb +36 -0
  70. data/lib/eye/dsl/pure_opts.rb +121 -0
  71. data/lib/eye/dsl/validation.rb +88 -0
  72. data/lib/eye/group.rb +140 -0
  73. data/lib/eye/group/chain.rb +81 -0
  74. data/lib/eye/loader.rb +10 -0
  75. data/lib/eye/local.rb +100 -0
  76. data/lib/eye/logger.rb +104 -0
  77. data/lib/eye/notify.rb +118 -0
  78. data/lib/eye/notify/jabber.rb +30 -0
  79. data/lib/eye/notify/mail.rb +48 -0
  80. data/lib/eye/process.rb +85 -0
  81. data/lib/eye/process/children.rb +60 -0
  82. data/lib/eye/process/commands.rb +280 -0
  83. data/lib/eye/process/config.rb +81 -0
  84. data/lib/eye/process/controller.rb +73 -0
  85. data/lib/eye/process/data.rb +78 -0
  86. data/lib/eye/process/monitor.rb +108 -0
  87. data/lib/eye/process/notify.rb +32 -0
  88. data/lib/eye/process/scheduler.rb +82 -0
  89. data/lib/eye/process/states.rb +86 -0
  90. data/lib/eye/process/states_history.rb +66 -0
  91. data/lib/eye/process/system.rb +97 -0
  92. data/lib/eye/process/trigger.rb +34 -0
  93. data/lib/eye/process/validate.rb +33 -0
  94. data/lib/eye/process/watchers.rb +66 -0
  95. data/lib/eye/reason.rb +20 -0
  96. data/lib/eye/server.rb +60 -0
  97. data/lib/eye/sigar.rb +5 -0
  98. data/lib/eye/system.rb +139 -0
  99. data/lib/eye/system_resources.rb +99 -0
  100. data/lib/eye/trigger.rb +136 -0
  101. data/lib/eye/trigger/check_dependency.rb +30 -0
  102. data/lib/eye/trigger/flapping.rb +41 -0
  103. data/lib/eye/trigger/stop_children.rb +17 -0
  104. data/lib/eye/trigger/transition.rb +15 -0
  105. data/lib/eye/trigger/wait_dependency.rb +49 -0
  106. data/lib/eye/utils.rb +45 -0
  107. data/lib/eye/utils/alive_array.rb +57 -0
  108. data/lib/eye/utils/celluloid_chain.rb +71 -0
  109. data/lib/eye/utils/celluloid_klass.rb +5 -0
  110. data/lib/eye/utils/leak_19.rb +10 -0
  111. data/lib/eye/utils/mini_active_support.rb +111 -0
  112. data/lib/eye/utils/pmap.rb +7 -0
  113. data/lib/eye/utils/tail.rb +20 -0
  114. metadata +398 -0
@@ -0,0 +1,104 @@
1
+ require 'logger'
2
+
3
+ class Eye::Logger
4
+ attr_accessor :prefix, :subprefix
5
+
6
+ class InnerLogger < Logger
7
+ FORMAT = '%d.%m.%Y %H:%M:%S'
8
+
9
+ def initialize(*args)
10
+ super
11
+
12
+ self.formatter = Proc.new do |s, d, p, m|
13
+ "#{d.strftime(FORMAT)} #{s.ljust(5)} -- #{m}\n"
14
+ end
15
+ end
16
+ end
17
+
18
+ module ObjectExt
19
+ def logger_tag
20
+ [Class, Module].include?(self.class) ? to_s : "<#{self.class.to_s}>"
21
+ end
22
+
23
+ def logger_sub_tag
24
+ end
25
+
26
+ def logger
27
+ @logger ||= Eye::Logger.new(logger_tag, logger_sub_tag)
28
+ end
29
+
30
+ Logger::Severity.constants.each do |level|
31
+ method_name = level.to_s.downcase
32
+ define_method method_name do |msg|
33
+ logger.send(method_name, msg)
34
+ end
35
+ end
36
+
37
+ def log_ex(ex)
38
+ error "#{ex.message} #{ex.backtrace}"
39
+ # notify here?
40
+ end
41
+ end
42
+
43
+ Logger::Severity.constants.each do |level|
44
+ method_name = level.to_s.downcase
45
+ define_method method_name do |msg|
46
+ self.class.inner_logger.send(method_name, "#{prefix_str}#{msg}")
47
+ end
48
+ end
49
+
50
+ def initialize(prefix = nil, subprefix = nil)
51
+ @prefix = prefix
52
+ @subprefix = subprefix
53
+ end
54
+
55
+ class << self
56
+ attr_reader :dev, :log_level, :args
57
+
58
+ def link_logger(dev, *args)
59
+ old_dev = @dev
60
+ @dev = dev ? dev.to_s : nil
61
+ @dev_fd = @dev
62
+ @args = args
63
+
64
+ @dev_fd = STDOUT if @dev.to_s.downcase == 'stdout'
65
+ @dev_fd = STDERR if @dev.to_s.downcase == 'stderr'
66
+
67
+ @inner_logger = InnerLogger.new(@dev_fd, *args)
68
+ @inner_logger.level = self.log_level || Logger::INFO
69
+
70
+ rescue Errno::ENOENT, Errno::EACCES
71
+ @dev = old_dev
72
+ raise
73
+ end
74
+
75
+ def reopen
76
+ link_logger(dev, *args)
77
+ end
78
+
79
+ def log_level=(level)
80
+ @log_level = level
81
+ @inner_logger.level = self.log_level if @inner_logger
82
+ end
83
+
84
+ def inner_logger
85
+ @inner_logger ||= InnerLogger.new(nil)
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def prefix_str
92
+ @pref_string ||= begin
93
+ pref_string = ''
94
+
95
+ if @prefix
96
+ pref_string = "[#{@prefix}] "
97
+ pref_string += "#{@subprefix} " if @subprefix
98
+ end
99
+
100
+ pref_string
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,118 @@
1
+ require 'celluloid'
2
+
3
+ class Eye::Notify
4
+ include Celluloid
5
+ include Eye::Dsl::Validation
6
+
7
+ autoload :Mail, 'eye/notify/mail'
8
+ autoload :Jabber, 'eye/notify/jabber'
9
+
10
+ TYPES = {:mail => 'Mail', :jabber => 'Jabber'}
11
+
12
+ def self.get_class(type)
13
+ klass = eval("Eye::Notify::#{TYPES[type]}") rescue nil
14
+ raise "unknown notifier :#{type}" unless klass
15
+ if deps = klass.requires
16
+ Array(deps).each { |d| require d }
17
+ end
18
+ klass
19
+ end
20
+
21
+ def self.validate!(options)
22
+ get_class(options[:type]).validate(options)
23
+ end
24
+
25
+ def self.notify(contact, message_h)
26
+ contact = contact.to_s
27
+ settings = Eye::Control.settings
28
+ needed_hash = (settings[:contacts] || {})[contact]
29
+
30
+ if needed_hash.blank?
31
+ error "contact #{contact} not found; check your configuration"
32
+ return
33
+ end
34
+
35
+ create_proc = lambda do |nh|
36
+ type = nh[:type]
37
+ config = (settings[type] || {}).merge(nh[:opts] || {}).merge(:contact => nh[:contact])
38
+ klass = get_class(type)
39
+ notify = klass.new(config, message_h)
40
+ notify.async_notify if notify
41
+ end
42
+
43
+ if needed_hash.is_a?(Array)
44
+ needed_hash.each{|nh| create_proc[nh] }
45
+ else
46
+ create_proc[needed_hash]
47
+ end
48
+
49
+ rescue Exception, Timeout::Error => ex
50
+ log_ex(ex)
51
+ end
52
+
53
+ TIMEOUT = 1 * 60
54
+
55
+ def initialize(options = {}, message_h = {})
56
+ @message_h = message_h
57
+ @options = options
58
+
59
+ debug "created notifier #{options}"
60
+ end
61
+
62
+ def logger_sub_tag
63
+ @options[:contact]
64
+ end
65
+
66
+ def async_notify
67
+ async.notify
68
+ after(TIMEOUT){ terminate }
69
+ end
70
+
71
+ def notify
72
+ debug "start notify #{@message_h}"
73
+ execute
74
+ debug "end notify #{@message_h}"
75
+ terminate
76
+ end
77
+
78
+ def execute
79
+ raise NotImplementedError
80
+ end
81
+
82
+ param :contact, [String]
83
+
84
+ def message_subject
85
+ "[#{msg_host}] [#{msg_full_name}] #{msg_message}"
86
+ end
87
+
88
+ def message_body
89
+ "#{message_subject} at #{Eye::Utils.human_time2(msg_at)}"
90
+ end
91
+
92
+ def self.register(base)
93
+ name = base.to_s.gsub('Eye::Notify::', '')
94
+ type = name.underscore.to_sym
95
+ Eye::Notify::TYPES[type] = name
96
+ Eye::Notify.const_set(name, base)
97
+ Eye::Dsl::ConfigOpts.add_notify(type)
98
+ end
99
+
100
+ def self.requires
101
+ end
102
+
103
+ class Custom < Eye::Notify
104
+ def self.inherited(base)
105
+ super
106
+ register(base)
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ %w{at host message name full_name pid level}.each do |name|
113
+ define_method("msg_#{name}") do
114
+ @message_h[name.to_sym]
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,30 @@
1
+ require 'xmpp4r'
2
+
3
+ class Eye::Notify::Jabber < Eye::Notify
4
+
5
+ # Eye.config do
6
+ # jabber :host => "some.host", :port => 12345, :user => "eye@some.host", :password => "123456"
7
+ # contact :vasya, :jabber, "vasya@some.host"
8
+ # end
9
+
10
+ param :host, String, true
11
+ param :port, [String, Fixnum], true
12
+ param :user, String, true
13
+ param :password, String
14
+
15
+ def execute
16
+ debug "send jabber #{[host, port, user, password]} - #{[contact, message_body]}"
17
+
18
+ mes = ::Jabber::Message.new(contact, message_body)
19
+ mes.set_type(:normal)
20
+ mes.set_id('1')
21
+ mes.set_subject(message_subject)
22
+
23
+ client = ::Jabber::Client.new(::Jabber::JID.new("#{user}/Eye"))
24
+ client.connect(host, port)
25
+ client.auth(password)
26
+ client.send(mes)
27
+ client.close
28
+ end
29
+
30
+ end
@@ -0,0 +1,48 @@
1
+ require 'net/smtp'
2
+
3
+ class Eye::Notify::Mail < Eye::Notify
4
+
5
+ # Eye.config do
6
+ # mail :host => "some.host", :port => 12345, :user => "eye@some.host", :password => "123456", :domain => "some.host"
7
+ # contact :vasya, :mail, "vasya@some.host"
8
+ # end
9
+
10
+ param :host, String, true
11
+ param :port, [String, Fixnum], true
12
+
13
+ param :domain, String
14
+ param :user, String
15
+ param :password, String
16
+ param :auth, Symbol, nil, nil, [:plain, :login, :cram_md5]
17
+
18
+ param :starttls, [TrueClass, FalseClass]
19
+
20
+ param :from_mail, String
21
+ param :from_name, String, nil, 'eye'
22
+
23
+ def execute
24
+ smtp
25
+ end
26
+
27
+ def smtp
28
+ args = [host, port, domain, user, password, auth]
29
+ debug "called smtp with #{args}"
30
+ smtp = Net::SMTP.new host, port
31
+ smtp.enable_starttls if starttls
32
+
33
+ smtp.start(domain, user, password, auth) do |s|
34
+ s.send_message(message, from_mail || user, contact)
35
+ end
36
+ end
37
+
38
+ def message
39
+ h = []
40
+ h << "From: #{from_name} <#{from_mail || user}>" if from_mail || user
41
+ h << "To: <#{contact}>"
42
+ h << "Subject: #{message_subject}"
43
+ h << "Date: #{msg_at.httpdate}"
44
+ h << "Message-Id: <#{rand(1000000000).to_s(36)}.#{$$}.#{contact}>"
45
+ "#{h * "\n"}\n#{message_body}"
46
+ end
47
+
48
+ end
@@ -0,0 +1,85 @@
1
+ require 'celluloid'
2
+
3
+ class Eye::Process
4
+ include Celluloid
5
+
6
+ autoload :Config, 'eye/process/config'
7
+ autoload :Commands, 'eye/process/commands'
8
+ autoload :Data, 'eye/process/data'
9
+ autoload :Watchers, 'eye/process/watchers'
10
+ autoload :Monitor, 'eye/process/monitor'
11
+ autoload :System, 'eye/process/system'
12
+ autoload :Controller, 'eye/process/controller'
13
+ autoload :StatesHistory, 'eye/process/states_history'
14
+ autoload :Children, 'eye/process/children'
15
+ autoload :Trigger, 'eye/process/trigger'
16
+ autoload :Notify, 'eye/process/notify'
17
+ autoload :Scheduler, 'eye/process/scheduler'
18
+ autoload :Validate, 'eye/process/validate'
19
+
20
+ attr_accessor :pid, :watchers, :config, :states_history,
21
+ :children, :triggers, :name, :state_reason, :flapping_times,
22
+ :parent_pid
23
+
24
+ def initialize(config)
25
+ raise 'you must supply a pid_file location' unless config[:pid_file]
26
+
27
+ @config = prepare_config(config)
28
+
29
+ @watchers = {}
30
+ @children = {}
31
+ @triggers = []
32
+ @name = @config[:name]
33
+
34
+ @flapping_times = 0
35
+
36
+ @states_history = Eye::Process::StatesHistory.new(100)
37
+ @states_history << :unmonitored
38
+
39
+ debug "creating with config: #{@config.inspect}"
40
+
41
+ add_triggers
42
+
43
+ super() # for statemachine
44
+ end
45
+
46
+ # c(), self[]
47
+ include Eye::Process::Config
48
+
49
+ # full_name, status_data
50
+ include Eye::Process::Data
51
+
52
+ # commands:
53
+ # start_process, stop_process, restart_process
54
+ include Eye::Process::Commands
55
+
56
+ # start, stop, restart, monitor, unmonit, delete
57
+ include Eye::Process::Controller
58
+
59
+ # add_watchers, remove_watchers:
60
+ include Eye::Process::Watchers
61
+
62
+ # check alive, crash methods:
63
+ include Eye::Process::Monitor
64
+
65
+ # system methods:
66
+ include Eye::Process::System
67
+
68
+ # manage child methods
69
+ include Eye::Process::Children
70
+
71
+ # manage triggers methods
72
+ include Eye::Process::Trigger
73
+
74
+ # manage notify methods
75
+ include Eye::Process::Notify
76
+
77
+ # scheduler
78
+ include Eye::Process::Scheduler
79
+
80
+ # validate
81
+ extend Eye::Process::Validate
82
+ end
83
+
84
+ # include state_machine states
85
+ require_relative 'process/states'
@@ -0,0 +1,60 @@
1
+ module Eye::Process::Children
2
+
3
+ def add_children
4
+ add_or_update_children
5
+ end
6
+
7
+ def add_or_update_children
8
+ return unless self[:monitor_children]
9
+ return unless self.up?
10
+ return if @updating_children
11
+ @updating_children = true
12
+
13
+ unless self.pid
14
+ warn "can't add children; pid not set"
15
+ return
16
+ end
17
+
18
+ now_children = Eye::SystemResources.children(self.pid)
19
+ new_children = []
20
+ exist_children = []
21
+
22
+ now_children.each do |child_pid|
23
+ if self.children[child_pid]
24
+ exist_children << child_pid
25
+ else
26
+ new_children << child_pid
27
+ end
28
+ end
29
+
30
+ removed_children = self.children.keys - now_children
31
+
32
+ if new_children.present?
33
+ new_children.each do |child_pid|
34
+ self.children[child_pid] = Eye::ChildProcess.new(child_pid, self[:monitor_children], logger.prefix, self.pid)
35
+ end
36
+ end
37
+
38
+ if removed_children.present?
39
+ removed_children.each{|child_pid| remove_child(child_pid) }
40
+ end
41
+
42
+ h = {:new => new_children.size, :removed => removed_children.size, :exists => exist_children.size }
43
+ debug "children info: #{ h.inspect }"
44
+
45
+ @updating_children = false
46
+ h
47
+ end
48
+
49
+ def remove_children
50
+ if children.present?
51
+ children.keys.each{|child_pid| remove_child(child_pid) }
52
+ end
53
+ end
54
+
55
+ def remove_child(child_pid)
56
+ child = self.children.delete(child_pid)
57
+ child.destroy if child && child.alive?
58
+ end
59
+
60
+ end