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,53 @@
1
+ require_relative 'dsl/helpers'
2
+
3
+ Eye::BINDING = binding
4
+
5
+ class Eye::Dsl
6
+
7
+ autoload :Main, 'eye/dsl/main'
8
+ autoload :ApplicationOpts, 'eye/dsl/application_opts'
9
+ autoload :GroupOpts, 'eye/dsl/group_opts'
10
+ autoload :ProcessOpts, 'eye/dsl/process_opts'
11
+ autoload :ChildProcessOpts, 'eye/dsl/child_process_opts'
12
+ autoload :Opts, 'eye/dsl/opts'
13
+ autoload :PureOpts, 'eye/dsl/pure_opts'
14
+ autoload :Chain, 'eye/dsl/chain'
15
+ autoload :ConfigOpts, 'eye/dsl/config_opts'
16
+ autoload :Validation, 'eye/dsl/validation'
17
+
18
+ class Error < Exception; end
19
+
20
+ class << self
21
+ attr_accessor :verbose
22
+
23
+ def debug(msg = '')
24
+ puts msg if verbose
25
+ end
26
+
27
+ def parse(content = nil, filename = nil)
28
+ Eye.parsed_config = Eye::Config.new
29
+ Eye.parsed_filename = filename
30
+ Eye.parsed_default_app = nil
31
+
32
+ content = File.read(filename) if content.blank?
33
+
34
+ silence_warnings do
35
+ Kernel.eval(content, Eye::BINDING, filename.to_s)
36
+ end
37
+
38
+ Eye.parsed_config.validate!(false)
39
+ Eye.parsed_config
40
+ end
41
+
42
+ def parse_apps(*args)
43
+ parse(*args).applications
44
+ end
45
+
46
+ def check_name(name)
47
+ raise Error, "':' is not allowed in name '#{name}'" if name.to_s.include?(':')
48
+ end
49
+ end
50
+ end
51
+
52
+ # extend here global module
53
+ Eye.send(:extend, Eye::Dsl::Main)
@@ -0,0 +1,39 @@
1
+ class Eye::Dsl::ApplicationOpts < Eye::Dsl::Opts
2
+
3
+ include Eye::Dsl::Chain
4
+
5
+ def disallow_options
6
+ [:pid_file, :start_command, :daemonize]
7
+ end
8
+
9
+ def not_seed_options
10
+ [:groups]
11
+ end
12
+
13
+ def group(name, &block)
14
+ Eye::Dsl.check_name(name)
15
+ Eye::Dsl.debug "=> group #{name}"
16
+
17
+ opts = Eye::Dsl::GroupOpts.new(name, self)
18
+ opts.instance_eval(&block)
19
+
20
+ @config[:groups] ||= {}
21
+ @config[:groups][name.to_s] ||= {}
22
+
23
+ if cfg = opts.config
24
+ Eye::Utils.deep_merge!(@config[:groups][name.to_s], cfg)
25
+ end
26
+
27
+ Eye::Dsl.debug "<= group #{name}"
28
+ opts
29
+ end
30
+
31
+ def process(name, &block)
32
+ res = nil
33
+ group('__default__'){ res = process(name.to_s, &block) }
34
+ res
35
+ end
36
+
37
+ alias xgroup nop
38
+ alias xprocess nop
39
+ end
@@ -0,0 +1,12 @@
1
+ module Eye::Dsl::Chain
2
+
3
+ def chain(opts = {})
4
+ acts = Array(opts[:action] || opts[:actions] || [:start, :restart])
5
+
6
+ acts.each do |act|
7
+ @config[:chain] ||= {}
8
+ @config[:chain][act] = opts.merge(:action => act)
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,13 @@
1
+ class Eye::Dsl::ChildProcessOpts < Eye::Dsl::Opts
2
+
3
+ def allow_options
4
+ [:stop_command, :restart_command, :children_update_period,
5
+ :stop_signals, :stop_grace, :stop_timeout, :restart_timeout]
6
+ end
7
+
8
+ def triggers(*args)
9
+ raise Eye::Dsl::Error, 'triggers not allowed in monitor_children'
10
+ end
11
+ alias trigger triggers
12
+
13
+ end
@@ -0,0 +1,55 @@
1
+ class Eye::Dsl::ConfigOpts < Eye::Dsl::PureOpts
2
+
3
+ create_options_methods([:logger_level], Fixnum)
4
+ create_options_methods([:http], Hash)
5
+
6
+ def logger(*args)
7
+ if args.empty?
8
+ @config[:logger]
9
+ else
10
+ str = args[0]
11
+ raise Eye::Dsl::Error, "logger should be a String #{str.inspect}" if !(str.is_a?(String) || str == nil)
12
+ @config[:logger] = args
13
+ end
14
+ end
15
+ alias logger= logger
16
+
17
+ # ==== contact options ==============================
18
+ def self.add_notify(type)
19
+ create_options_methods([type], Hash)
20
+
21
+ define_method("set_#{type}") do |value|
22
+ value = value.merge(:type => type)
23
+ super(value)
24
+ Eye::Notify.validate!(value)
25
+ end
26
+ end
27
+
28
+ Eye::Notify::TYPES.keys.each { |name| add_notify(name) }
29
+
30
+ def contact(contact_name, contact_type, contact, contact_opts = {})
31
+ raise Eye::Dsl::Error, "unknown contact_type #{contact_type}" unless Eye::Notify::TYPES[contact_type]
32
+ raise Eye::Dsl::Error, 'contact should be a String' unless contact.is_a?(String)
33
+
34
+ notify_hash = @config[contact_type] || (@parent && @parent.config[contact_type]) || Eye::parsed_config.settings[contact_type] || {}
35
+ validate_hash = notify_hash.merge(contact_opts).merge(:type => contact_type)
36
+
37
+ Eye::Notify.validate!(validate_hash)
38
+
39
+ @config[:contacts] ||= {}
40
+ @config[:contacts][contact_name.to_s] = {name: contact_name.to_s, type: contact_type,
41
+ contact: contact, opts: contact_opts}
42
+ end
43
+
44
+ def contact_group(contact_group_name, &block)
45
+ c = Eye::Dsl::ConfigOpts.new nil, self, false
46
+ c.instance_eval(&block)
47
+ cfg = c.config
48
+ @config[:contacts] ||= {}
49
+ if cfg[:contacts].present?
50
+ @config[:contacts][contact_group_name.to_s] = cfg[:contacts].values
51
+ @config[:contacts].merge!(cfg[:contacts])
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,32 @@
1
+ class Eye::Dsl::GroupOpts < Eye::Dsl::Opts
2
+
3
+ include Eye::Dsl::Chain
4
+
5
+ def disallow_options
6
+ [:pid_file, :start_command, :daemonize]
7
+ end
8
+
9
+ def not_seed_options
10
+ [:processes, :chain]
11
+ end
12
+
13
+ def process(name, &block)
14
+ Eye::Dsl.check_name(name)
15
+
16
+ Eye::Dsl.debug "=> process #{name}"
17
+
18
+ opts = Eye::Dsl::ProcessOpts.new(name, self)
19
+ opts.instance_eval(&block)
20
+ @config[:processes] ||= {}
21
+ @config[:processes][name.to_s] ||= {}
22
+ Eye::Utils.deep_merge!(@config[:processes][name.to_s], opts.config) if opts.config
23
+
24
+ Eye::Dsl.debug "<= process #{name}"
25
+ opts
26
+ end
27
+
28
+ alias xprocess nop
29
+ alias application parent
30
+ alias app application
31
+
32
+ end
@@ -0,0 +1,20 @@
1
+
2
+ # Dsl Helpers
3
+
4
+ # current eye parsed config path
5
+ def current_config_path
6
+ Eye.parsed_filename && File.symlink?(Eye.parsed_filename) ? File.readlink(Eye.parsed_filename) : Eye.parsed_filename
7
+ end
8
+
9
+ # host name
10
+ def hostname
11
+ Eye::Local.host
12
+ end
13
+
14
+ def example_process(proxy, name)
15
+ proxy.process(name) do
16
+ pid_file "/tmp/#{name}.pid"
17
+ start_command "sleep 100"
18
+ daemonize true
19
+ end
20
+ end
@@ -0,0 +1,51 @@
1
+ module Eye::Dsl::Main
2
+ attr_accessor :parsed_config, :parsed_filename, :parsed_default_app
3
+
4
+ def application(name, &block)
5
+ Eye::Dsl.check_name(name)
6
+ name = name.to_s
7
+
8
+ Eye::Dsl.debug "=> app: #{name}"
9
+
10
+ if name == '__default__'
11
+ @parsed_default_app ||= Eye::Dsl::ApplicationOpts.new(name)
12
+ @parsed_default_app.instance_eval(&block)
13
+ else
14
+ opts = Eye::Dsl::ApplicationOpts.new(name, @parsed_default_app)
15
+ opts.instance_eval(&block)
16
+ @parsed_config.applications[name] = opts.config if opts.config
17
+ end
18
+
19
+ Eye::Dsl.debug "<= app: #{name}"
20
+ end
21
+
22
+ alias project application
23
+ alias app application
24
+
25
+ def load(glob = '')
26
+ return if glob.blank?
27
+
28
+ Eye::Dsl::Opts.with_parsed_file(glob) do |mask|
29
+ Dir[mask].each do |path|
30
+ Eye::Dsl.debug "=> load #{path}"
31
+ Eye.parsed_filename = path
32
+ res = Kernel.load(path)
33
+ Eye.info "load: subload #{path} (#{res})"
34
+ Eye::Dsl.debug "<= load #{path}"
35
+ end
36
+ end
37
+ end
38
+
39
+ def config(&block)
40
+ Eye::Dsl.debug '=> config'
41
+
42
+ opts = Eye::Dsl::ConfigOpts.new
43
+ opts.instance_eval(&block)
44
+ Eye::Utils.deep_merge!(@parsed_config.settings, opts.config)
45
+
46
+ Eye::Dsl.debug '<= config'
47
+ end
48
+
49
+ alias settings config
50
+
51
+ end
@@ -0,0 +1,151 @@
1
+ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
2
+
3
+ STR_OPTIONS = [ :pid_file, :working_dir, :stdout, :stderr, :stdall, :stdin, :start_command,
4
+ :stop_command, :restart_command, :uid, :gid ]
5
+ create_options_methods(STR_OPTIONS, String)
6
+
7
+ BOOL_OPTIONS = [ :daemonize, :keep_alive, :auto_start, :stop_on_delete, :clear_pid, :preserve_fds, :use_leaf_child, :clear_env ]
8
+ create_options_methods(BOOL_OPTIONS, [TrueClass, FalseClass])
9
+
10
+ INTERVAL_OPTIONS = [ :check_alive_period, :start_timeout, :restart_timeout, :stop_timeout, :start_grace,
11
+ :restart_grace, :stop_grace, :children_update_period, :restore_in,
12
+ :auto_update_pidfile_grace, :revert_fuckup_pidfile_grace ]
13
+ create_options_methods(INTERVAL_OPTIONS, [Fixnum, Float])
14
+
15
+ create_options_methods([:environment], Hash)
16
+ create_options_methods([:stop_signals], Array)
17
+ create_options_methods([:umask], Fixnum)
18
+
19
+
20
+ def initialize(name = nil, parent = nil)
21
+ super(name, parent)
22
+
23
+ @config[:application] = parent.name if parent.is_a?(Eye::Dsl::ApplicationOpts)
24
+ @config[:group] = parent.name if parent.is_a?(Eye::Dsl::GroupOpts)
25
+
26
+ # hack for full name
27
+ @full_name = parent.full_name if @name == '__default__' && parent.respond_to?(:full_name)
28
+ end
29
+
30
+ def checks(type, opts = {})
31
+ nac = Eye::Checker.name_and_class(type.to_sym)
32
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless nac
33
+
34
+ opts.merge!(:type => nac[:type])
35
+ Eye::Checker.validate!(opts)
36
+
37
+ @config[:checks] ||= {}
38
+ @config[:checks][nac[:name]] = opts
39
+ end
40
+
41
+ def triggers(type, opts = {})
42
+ nac = Eye::Trigger.name_and_class(type.to_sym)
43
+ raise Eye::Dsl::Error, "unknown trigger type #{type}" unless nac
44
+
45
+ opts.merge!(:type => nac[:type])
46
+ Eye::Trigger.validate!(opts)
47
+
48
+ @config[:triggers] ||= {}
49
+ @config[:triggers][nac[:name]] = opts
50
+ end
51
+
52
+ # clear checks from parent
53
+ def nochecks(type)
54
+ nac = Eye::Checker.name_and_class(type.to_sym)
55
+ raise Eye::Dsl::Error, "unknown checker type #{type}" unless nac
56
+ @config[:checks].try :delete, nac[:name]
57
+ end
58
+
59
+ # clear triggers from parent
60
+ def notriggers(type)
61
+ nac = Eye::Trigger.name_and_class(type.to_sym)
62
+ raise Eye::Dsl::Error, "unknown trigger type #{type}" unless nac
63
+ @config[:triggers].try :delete, nac[:name]
64
+ end
65
+
66
+ alias check checks
67
+ alias nocheck nochecks
68
+ alias trigger triggers
69
+ alias notrigger notriggers
70
+
71
+ def notify(contact, level = :warn)
72
+ unless Eye::Process::Notify::LEVELS[level]
73
+ raise Eye::Dsl::Error, "level should be in #{Eye::Process::Notify::LEVELS.keys}"
74
+ end
75
+
76
+ @config[:notify] ||= {}
77
+ @config[:notify][contact.to_s] = level
78
+ end
79
+
80
+ def nonotify(contact)
81
+ @config[:notify] ||= {}
82
+ @config[:notify].delete(contact.to_s)
83
+ end
84
+
85
+ def set_environment(value)
86
+ raise Eye::Dsl::Error, "environment should be a hash, but not #{value.inspect}" unless value.is_a?(Hash)
87
+ @config[:environment] ||= {}
88
+ @config[:environment].merge!(value)
89
+ end
90
+
91
+ alias dir working_dir
92
+ alias env environment
93
+
94
+ def set_stdall(value)
95
+ super
96
+
97
+ set_stdout value
98
+ set_stderr value
99
+ end
100
+
101
+ def set_uid(value)
102
+ raise Eye::Dsl::Error, ':uid not supported (use ruby >= 2.0)' unless Eye::Local.supported_setsid?
103
+ super
104
+ end
105
+
106
+ def set_gid(value)
107
+ raise Eye::Dsl::Error, ':gid not supported (use ruby >= 2.0)' unless Eye::Local.supported_setsid?
108
+ super
109
+ end
110
+
111
+ def daemonize!
112
+ set_daemonize true
113
+ end
114
+
115
+ def clear_bundler_env
116
+ env('GEM_PATH' => nil, 'GEM_HOME' => nil, 'RUBYOPT' => nil, 'BUNDLE_BIN_PATH' => nil, 'BUNDLE_GEMFILE' => nil)
117
+ end
118
+
119
+ def scoped(&block)
120
+ h = self.class.new(self.name, self)
121
+ h.instance_eval(&block)
122
+ Eye::Utils.deep_merge!(config, h.config, [:groups, :processes])
123
+ end
124
+
125
+ # execute part of config on particular server
126
+ # array of strings
127
+ # regexp
128
+ # string
129
+ def with_server(glob = nil, &block)
130
+ on_server = true
131
+
132
+ if glob.present?
133
+ host = Eye::Local.host
134
+
135
+ if glob.is_a?(Array)
136
+ on_server = !!glob.any?{|elem| elem == host}
137
+ elsif glob.is_a?(Regexp)
138
+ on_server = !!host.match(glob)
139
+ elsif glob.is_a?(String) || glob.is_a?(Symbol)
140
+ on_server = (host == glob.to_s)
141
+ end
142
+ end
143
+
144
+ scoped do
145
+ with_condition(on_server, &block)
146
+ end
147
+
148
+ on_server
149
+ end
150
+
151
+ end
@@ -0,0 +1,36 @@
1
+ class Eye::Dsl::ProcessOpts < Eye::Dsl::Opts
2
+
3
+ def monitor_children(&block)
4
+ opts = Eye::Dsl::ChildProcessOpts.new
5
+ opts.instance_eval(&block) if block
6
+ @config[:monitor_children] ||= {}
7
+ Eye::Utils.deep_merge!(@config[:monitor_children], opts.config)
8
+ end
9
+
10
+ alias xmonitor_children nop
11
+
12
+ def application
13
+ parent.try(:parent)
14
+ end
15
+ alias app application
16
+ alias group parent
17
+
18
+ def depend_on(names, opts = {})
19
+ names = Array(names).map(&:to_s)
20
+ trigger("wait_dependency_#{unique_num}", {:names => names}.merge(opts))
21
+ nm = @config[:name]
22
+ names.each do |name|
23
+ parent.process(name) do
24
+ trigger("check_dependency_#{unique_num}", :names => [ nm ] )
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def unique_num
32
+ $unique_num ||= 0
33
+ $unique_num += 1
34
+ end
35
+
36
+ end