ace-eye 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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