itrg-invoker 1.6.0

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/bin/invoker +7 -0
  3. data/lib/invoker/cli/pinger.rb +23 -0
  4. data/lib/invoker/cli/question.rb +15 -0
  5. data/lib/invoker/cli/tail.rb +34 -0
  6. data/lib/invoker/cli/tail_watcher.rb +34 -0
  7. data/lib/invoker/cli.rb +197 -0
  8. data/lib/invoker/command_worker.rb +64 -0
  9. data/lib/invoker/commander.rb +101 -0
  10. data/lib/invoker/daemon.rb +126 -0
  11. data/lib/invoker/dns_cache.rb +23 -0
  12. data/lib/invoker/errors.rb +17 -0
  13. data/lib/invoker/event/manager.rb +79 -0
  14. data/lib/invoker/ipc/add_command.rb +12 -0
  15. data/lib/invoker/ipc/add_http_command.rb +10 -0
  16. data/lib/invoker/ipc/base_command.rb +24 -0
  17. data/lib/invoker/ipc/client_handler.rb +26 -0
  18. data/lib/invoker/ipc/dns_check_command.rb +17 -0
  19. data/lib/invoker/ipc/list_command.rb +11 -0
  20. data/lib/invoker/ipc/message/list_response.rb +35 -0
  21. data/lib/invoker/ipc/message/tail_response.rb +10 -0
  22. data/lib/invoker/ipc/message.rb +170 -0
  23. data/lib/invoker/ipc/ping_command.rb +10 -0
  24. data/lib/invoker/ipc/reload_command.rb +12 -0
  25. data/lib/invoker/ipc/remove_command.rb +12 -0
  26. data/lib/invoker/ipc/server.rb +26 -0
  27. data/lib/invoker/ipc/tail_command.rb +11 -0
  28. data/lib/invoker/ipc/unix_client.rb +60 -0
  29. data/lib/invoker/ipc.rb +45 -0
  30. data/lib/invoker/logger.rb +13 -0
  31. data/lib/invoker/parsers/config.rb +184 -0
  32. data/lib/invoker/parsers/procfile.rb +86 -0
  33. data/lib/invoker/power/balancer.rb +133 -0
  34. data/lib/invoker/power/config.rb +77 -0
  35. data/lib/invoker/power/dns.rb +38 -0
  36. data/lib/invoker/power/http_parser.rb +68 -0
  37. data/lib/invoker/power/http_response.rb +81 -0
  38. data/lib/invoker/power/port_finder.rb +49 -0
  39. data/lib/invoker/power/power.rb +3 -0
  40. data/lib/invoker/power/powerup.rb +29 -0
  41. data/lib/invoker/power/setup/distro/arch.rb +15 -0
  42. data/lib/invoker/power/setup/distro/base.rb +80 -0
  43. data/lib/invoker/power/setup/distro/debian.rb +11 -0
  44. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  45. data/lib/invoker/power/setup/distro/redhat.rb +11 -0
  46. data/lib/invoker/power/setup/distro/ubuntu.rb +46 -0
  47. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  48. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  49. data/lib/invoker/power/setup/linux_setup.rb +97 -0
  50. data/lib/invoker/power/setup/osx_setup.rb +137 -0
  51. data/lib/invoker/power/setup.rb +93 -0
  52. data/lib/invoker/power/templates/400.html +40 -0
  53. data/lib/invoker/power/templates/404.html +40 -0
  54. data/lib/invoker/power/templates/503.html +40 -0
  55. data/lib/invoker/power/url_rewriter.rb +40 -0
  56. data/lib/invoker/process_manager.rb +201 -0
  57. data/lib/invoker/process_printer.rb +59 -0
  58. data/lib/invoker/reactor/reader.rb +65 -0
  59. data/lib/invoker/reactor.rb +37 -0
  60. data/lib/invoker/version.rb +47 -0
  61. data/lib/invoker.rb +151 -0
  62. data/spec/invoker/cli/pinger_spec.rb +22 -0
  63. data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
  64. data/spec/invoker/cli_spec.rb +27 -0
  65. data/spec/invoker/command_worker_spec.rb +45 -0
  66. data/spec/invoker/commander_spec.rb +152 -0
  67. data/spec/invoker/config_spec.rb +361 -0
  68. data/spec/invoker/daemon_spec.rb +34 -0
  69. data/spec/invoker/event/manager_spec.rb +67 -0
  70. data/spec/invoker/invoker_spec.rb +71 -0
  71. data/spec/invoker/ipc/client_handler_spec.rb +54 -0
  72. data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
  73. data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
  74. data/spec/invoker/ipc/message_spec.rb +49 -0
  75. data/spec/invoker/ipc/unix_client_spec.rb +29 -0
  76. data/spec/invoker/power/balancer_spec.rb +53 -0
  77. data/spec/invoker/power/config_spec.rb +18 -0
  78. data/spec/invoker/power/http_parser_spec.rb +32 -0
  79. data/spec/invoker/power/http_response_spec.rb +34 -0
  80. data/spec/invoker/power/port_finder_spec.rb +16 -0
  81. data/spec/invoker/power/setup/linux_setup_spec.rb +166 -0
  82. data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
  83. data/spec/invoker/power/setup_spec.rb +4 -0
  84. data/spec/invoker/power/url_rewriter_spec.rb +69 -0
  85. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  86. data/spec/invoker/process_manager_spec.rb +130 -0
  87. data/spec/invoker/reactor_spec.rb +6 -0
  88. data/spec/spec_helper.rb +43 -0
  89. metadata +376 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e3d5b0bdacd47a5980cbcda55ef7834f36dd5dd9865b0449629407fd73a781ff
4
+ data.tar.gz: 82fd4361283d887768faa4b2c3595cf3ce13286fc11bfc2f7ad5e74843992766
5
+ SHA512:
6
+ metadata.gz: 85741205e13f285db961c8ddaa02d9fea88aa98027a2a5a518683a56234209bfa850fd7a896457d14a0e2cc33d1b3ccd1c148eaf6318fc0d1b48cffa17bdb609
7
+ data.tar.gz: ce60237af156b87c220e86a8efe002127652f4b2417d549f370c526df1cb45d367ad71278038f27e3231a64007f75f19ae71b9a2dcc466f9ac0bf5aabb9b1367
data/bin/invoker ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ invoker_lib_path = File.expand_path('../../lib', __FILE__)
4
+ $:.unshift(invoker_lib_path)
5
+ require "invoker"
6
+
7
+ Invoker::CLI.start(ARGV)
@@ -0,0 +1,23 @@
1
+ require "timeout"
2
+
3
+ module Invoker
4
+ class CLI::Pinger
5
+ attr_accessor :unix_client
6
+ def initialize(unix_client)
7
+ @unix_client = unix_client
8
+ end
9
+
10
+ def invoker_running?
11
+ response = send_ping_and_read_response
12
+ response && response.status == 'pong'
13
+ end
14
+
15
+ private
16
+
17
+ def send_ping_and_read_response
18
+ Timeout.timeout(2) { unix_client.send_and_receive('ping') }
19
+ rescue Timeout::Error
20
+ nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Invoker
2
+ class CLI::Question
3
+ def self.agree(question_text)
4
+ $stdout.print(question_text)
5
+ answer = $stdin.gets
6
+ answer.strip!
7
+ if answer =~ /\Ay(?:es)?|no?\Z/i
8
+ answer =~ /\Ay(?:es)?\Z/i
9
+ else
10
+ $stdout.puts "Please enter 'yes' or 'no'."
11
+ agree(question_text)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ module Invoker
2
+ class CLI::Tail
3
+ attr_accessor :process_names
4
+ def initialize(process_names)
5
+ verify_process_name(process_names)
6
+ @process_names = process_names
7
+ @unix_socket = Invoker::IPC::UnixClient.new
8
+ end
9
+
10
+ def run
11
+ socket = @unix_socket.send_and_wait('tail', process_names: process_names)
12
+ trap('INT') { socket.close }
13
+ loop do
14
+ message = read_next_line(socket)
15
+ break unless message
16
+ puts message.tail_line
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def verify_process_name(process_names)
23
+ if process_names.empty?
24
+ abort("Tail command requires one or more process name")
25
+ end
26
+ end
27
+
28
+ def read_next_line(socket)
29
+ Invoker::IPC.message_from_io(socket)
30
+ rescue
31
+ nil
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ module Invoker
2
+ # This class defines sockets which are open for watching log files
3
+ class CLI::TailWatcher
4
+ attr_accessor :tail_watchers
5
+
6
+ def initialize
7
+ @tail_mutex = Mutex.new
8
+ @tail_watchers = Hash.new { |h, k| h[k] = [] }
9
+ end
10
+
11
+ def [](process_name)
12
+ @tail_mutex.synchronize { tail_watchers[process_name] }
13
+ end
14
+
15
+ def add(names, socket)
16
+ @tail_mutex.synchronize do
17
+ names.each { |name| tail_watchers[name] << socket }
18
+ end
19
+ end
20
+
21
+ def remove(name, socket)
22
+ @tail_mutex.synchronize do
23
+ client_list = tail_watchers[name]
24
+ client_list.delete(socket)
25
+ purge(name, socket) if client_list.empty?
26
+ end
27
+ end
28
+
29
+ def purge(name, socket)
30
+ tail_watchers.delete(name)
31
+ Invoker.close_socket(socket)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,197 @@
1
+ require "socket"
2
+ require "thor"
3
+
4
+ module Invoker
5
+ class CLI < Thor
6
+ def self.start(*args)
7
+ cli_args = args.flatten
8
+ # If it is not a valid task, it is probably file argument
9
+ if default_start_command?(cli_args)
10
+ args = [cli_args.unshift("start")]
11
+ end
12
+ super(*args)
13
+ end
14
+
15
+ desc "setup", "Run Invoker setup"
16
+ option :tld,
17
+ type: :string,
18
+ banner: 'Configure invoker to use a different top level domain'
19
+ def setup
20
+ Invoker::Power::Setup.install(get_tld(options))
21
+ end
22
+ map install: :setup
23
+
24
+ desc "version", "Print Invoker version"
25
+ def version
26
+ Invoker::Logger.puts Invoker::VERSION
27
+ end
28
+ map %w(-v --version) => :version
29
+
30
+ desc "uninstall", "Uninstall Invoker and all installed files"
31
+ def uninstall
32
+ Invoker::Power::Setup.uninstall
33
+ end
34
+
35
+ desc "start [CONFIG_FILE]", "Start Invoker Server"
36
+ option :port, type: :numeric, banner: "Port series to be used for starting rack servers"
37
+ option :daemon,
38
+ type: :boolean,
39
+ banner: "Daemonize the server into the background",
40
+ aliases: [:d]
41
+ option :nocolors,
42
+ type: :boolean,
43
+ banner: "Disable color in output",
44
+ aliases: [:nc]
45
+ option :certificate,
46
+ type: :string,
47
+ banner: "Path to certificate"
48
+ option :private_key,
49
+ type: :string,
50
+ banner: "Path to private key"
51
+ def start(file = nil)
52
+ Invoker.setup_config_location
53
+ port = options[:port] || 9000
54
+ Invoker.daemonize = options[:daemon]
55
+ Invoker.nocolors = options[:nocolors]
56
+ Invoker.certificate = options[:certificate]
57
+ Invoker.private_key = options[:private_key]
58
+ Invoker.load_invoker_config(file, port)
59
+ warn_about_notification
60
+ pinger = Invoker::CLI::Pinger.new(unix_socket)
61
+ abort("Invoker is already running".colorize(:red)) if pinger.invoker_running?
62
+ Invoker.commander.start_manager
63
+ end
64
+
65
+ desc "add process", "Add a program to Invoker server"
66
+ def add(name)
67
+ unix_socket.send_command('add', process_name: name)
68
+ end
69
+
70
+ desc "add_http process_name port [IP]", "Add an external http process to Invoker DNS server"
71
+ def add_http(name, port, ip = nil)
72
+ unix_socket.send_command('add_http', process_name: name, port: port, ip: ip)
73
+ end
74
+
75
+ desc "tail process1 process2", "Tail a particular process"
76
+ def tail(*names)
77
+ tailer = Invoker::CLI::Tail.new(names)
78
+ tailer.run
79
+ end
80
+
81
+ desc "log process1", "Get log of particular process"
82
+ def log(process_name)
83
+ system("egrep -a '^#{process_name}' #{Invoker.daemon.log_file}")
84
+ end
85
+
86
+ desc "reload process", "Reload a process managed by Invoker"
87
+ option :signal,
88
+ banner: "Signal to send for killing the process, default is SIGINT",
89
+ aliases: [:s]
90
+ def reload(name)
91
+ signal = options[:signal] || 'INT'
92
+ unix_socket.send_command('reload', process_name: name, signal: signal)
93
+ end
94
+ map restart: :reload
95
+
96
+ desc "list", "List all running processes"
97
+ option :raw,
98
+ type: :boolean,
99
+ banner: "Print process list in raw text format",
100
+ aliases: [:r]
101
+ option :wait,
102
+ type: :boolean,
103
+ banner: "wait for update",
104
+ aliases: [:w]
105
+ def list
106
+ if options[:wait]
107
+ Signal.trap("INT") { exit(0) }
108
+ loop do
109
+ puts "\e[H\e[2J"
110
+ unix_socket.send_command('list') do |response_object|
111
+ Invoker::ProcessPrinter.new(response_object).tap { |printer| printer.print_table }
112
+ end
113
+ sleep(5)
114
+ end
115
+ else
116
+ unix_socket.send_command('list') do |response_object|
117
+ if options[:raw]
118
+ Invoker::ProcessPrinter.new(response_object).tap { |printer| printer.print_raw_text }
119
+ else
120
+ Invoker::ProcessPrinter.new(response_object).tap { |printer| printer.print_table }
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ desc "remove process", "Stop a process managed by Invoker"
127
+ option :signal,
128
+ banner: "Signal to send for killing the process, default is SIGINT",
129
+ aliases: [:s]
130
+ def remove(name)
131
+ signal = options[:signal] || 'INT'
132
+ unix_socket.send_command('remove', process_name: name, signal: signal)
133
+ end
134
+
135
+ desc "stop", "Stop Invoker daemon"
136
+ def stop
137
+ Invoker.daemon.stop
138
+ end
139
+
140
+ private
141
+
142
+ def self.default_start_command?(args)
143
+ command_name = args.first
144
+ command_name &&
145
+ !command_name.match(/^-/) &&
146
+ !valid_tasks.include?(command_name)
147
+ end
148
+
149
+ def self.valid_tasks
150
+ tasks.keys + %w(help install restart)
151
+ end
152
+
153
+ # TODO(kgrz): the default TLD option is duplicated in both this file and
154
+ # lib/invoker.rb May be assign this to a constant?
155
+ def get_tld(options)
156
+ if options[:tld] && !options[:tld].empty?
157
+ options[:tld]
158
+ else
159
+ 'test'
160
+ end
161
+ end
162
+
163
+ def unix_socket
164
+ Invoker::IPC::UnixClient.new
165
+ end
166
+
167
+ def warn_about_notification
168
+ if Invoker.darwin?
169
+ warn_about_terminal_notifier
170
+ else
171
+ warn_about_libnotify
172
+ end
173
+ end
174
+
175
+ def warn_about_libnotify
176
+ require "libnotify"
177
+ rescue LoadError
178
+ Invoker::Logger.puts "You can install libnotify gem for Invoker notifications "\
179
+ "via system tray".colorize(:red)
180
+ end
181
+
182
+ def warn_about_terminal_notifier
183
+ if Invoker.darwin?
184
+ command_path = `which terminal-notifier`
185
+ if !command_path || command_path.empty?
186
+ Invoker::Logger.puts "You can enable OSX notification for processes "\
187
+ "by installing terminal-notifier gem".colorize(:red)
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ require "invoker/cli/question"
195
+ require "invoker/cli/tail_watcher"
196
+ require "invoker/cli/tail"
197
+ require "invoker/cli/pinger"
@@ -0,0 +1,64 @@
1
+ module Invoker
2
+ class CommandWorker
3
+ attr_accessor :command_label, :pipe_end, :pid, :color
4
+
5
+ def initialize(command_label, pipe_end, pid, color)
6
+ @command_label = command_label
7
+ @pipe_end = pipe_end
8
+ @pid = pid
9
+ @color = color
10
+ end
11
+
12
+ # Copied verbatim from Eventmachine code
13
+ def receive_data data
14
+ (@buf ||= '') << data
15
+
16
+ while @buf.slice!(/(.*?)\r?\n/)
17
+ receive_line($1)
18
+ end
19
+ end
20
+
21
+ def unbind
22
+ Invoker::Logger.print(".")
23
+ end
24
+
25
+ # Print the lines received over the network
26
+ def receive_line(line)
27
+ tail_watchers = Invoker.tail_watchers[@command_label]
28
+ color_line = "#{@command_label.colorize(color)} : #{line}"
29
+ plain_line = "#{@command_label} : #{line}"
30
+ if Invoker.nocolors?
31
+ Invoker::Logger.puts plain_line
32
+ else
33
+ Invoker::Logger.puts color_line
34
+ end
35
+ if tail_watchers && !tail_watchers.empty?
36
+ json_encoded_tail_response = tail_response(color_line)
37
+ if json_encoded_tail_response
38
+ tail_watchers.each { |tail_socket| send_data(tail_socket, json_encoded_tail_response) }
39
+ end
40
+ end
41
+ end
42
+
43
+ def to_h
44
+ { command_label: command_label, pid: pid.to_s }
45
+ end
46
+
47
+ def send_data(socket, data)
48
+ socket.write(data)
49
+ rescue
50
+ Invoker::Logger.puts "Removing #{@command_label} watcher #{socket} from list"
51
+ Invoker.tail_watchers.remove(@command_label, socket)
52
+ end
53
+
54
+ private
55
+
56
+ # Encode current line as json and send the response.
57
+ def tail_response(line)
58
+ tail_response = Invoker::IPC::Message::TailResponse.new(tail_line: line)
59
+ tail_response.encoded_message
60
+ rescue
61
+ nil
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,101 @@
1
+ require "io/console"
2
+ require 'pty'
3
+ require "json"
4
+ require "dotenv"
5
+ require "forwardable"
6
+
7
+ module Invoker
8
+ class Commander
9
+ attr_accessor :reactor, :process_manager
10
+ attr_accessor :event_manager, :runnables, :thread_group
11
+ extend Forwardable
12
+
13
+ def_delegators :@process_manager, :start_process_by_name, :stop_process
14
+ def_delegators :@process_manager, :restart_process, :get_worker_from_fd, :process_list
15
+
16
+ def_delegators :@event_manager, :schedule_event, :trigger
17
+ def_delegator :@reactor, :watch_for_read
18
+
19
+ def initialize
20
+ @thread_group = ThreadGroup.new
21
+ @runnable_mutex = Mutex.new
22
+
23
+ @event_manager = Invoker::Event::Manager.new
24
+ @runnables = []
25
+
26
+ @reactor = Invoker::Reactor.new
27
+ @process_manager = Invoker::ProcessManager.new
28
+ Thread.abort_on_exception = true
29
+ end
30
+
31
+ # Start the invoker process supervisor. This method starts a unix server
32
+ # in separate thread that listens for incoming commands.
33
+ def start_manager
34
+ verify_process_configuration
35
+ daemonize_app if Invoker.daemonize?
36
+ install_interrupt_handler
37
+ unix_server_thread = Thread.new { Invoker::IPC::Server.new }
38
+ @thread_group.add(unix_server_thread)
39
+ process_manager.run_power_server
40
+ Invoker.config.autorunnable_processes.each do |process_info|
41
+ process_manager.start_process(process_info)
42
+ Logger.puts("Starting process - #{process_info.label} waiting for #{process_info.sleep_duration} seconds...")
43
+ sleep(process_info.sleep_duration)
44
+ end
45
+ at_exit { process_manager.kill_workers }
46
+ start_event_loop
47
+ end
48
+
49
+ def on_next_tick(*args, &block)
50
+ @runnable_mutex.synchronize do
51
+ @runnables << OpenStruct.new(:args => args, :block => block)
52
+ end
53
+ end
54
+
55
+ def run_runnables
56
+ @runnables.each do |runnable|
57
+ instance_exec(*runnable.args, &runnable.block)
58
+ end
59
+ @runnables = []
60
+ end
61
+
62
+ private
63
+
64
+ def verify_process_configuration
65
+ if !Invoker.config.processes || Invoker.config.processes.empty?
66
+ raise Invoker::Errors::InvalidConfig.new("No processes configured in config file")
67
+ end
68
+ end
69
+
70
+ def start_event_loop
71
+ loop do
72
+ reactor.monitor_for_fd_events
73
+ run_runnables
74
+ run_scheduled_events
75
+ end
76
+ end
77
+
78
+ def run_scheduled_events
79
+ event_manager.run_scheduled_events do |event|
80
+ event.block.call
81
+ end
82
+ end
83
+
84
+ def install_interrupt_handler
85
+ Signal.trap("INT") {
86
+ Invoker::Logger.puts("Stopping invoker")
87
+ process_manager.kill_workers
88
+ exit(0)
89
+ }
90
+ Signal.trap("TERM") {
91
+ Invoker::Logger.puts("Stopping invoker")
92
+ process_manager.kill_workers
93
+ exit(0)
94
+ }
95
+ end
96
+
97
+ def daemonize_app
98
+ Invoker.daemon.start
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,126 @@
1
+ module Invoker
2
+ # rip off from borg
3
+ # https://github.com/code-mancers/borg/blob/master/lib/borg/borg_daemon.rb
4
+ class Daemon
5
+ attr_reader :process_name
6
+
7
+ def initialize
8
+ @process_name = 'invoker'
9
+ end
10
+
11
+ def start
12
+ if running?
13
+ Invoker::Logger.puts "Invoker daemon is already running"
14
+ exit(0)
15
+ elsif dead?
16
+ File.delete(pid_file) if File.exist?(pid_file)
17
+ end
18
+ Invoker::Logger.puts "Running Invoker daemon"
19
+ daemonize
20
+ end
21
+
22
+ def stop
23
+ kill_process
24
+ end
25
+
26
+ def pid_file
27
+ File.join(Invoker.home, ".invoker", "#{process_name}.pid")
28
+ end
29
+
30
+ def pid
31
+ File.read(pid_file).strip.to_i
32
+ end
33
+
34
+ def log_file
35
+ File.join(Invoker.home, ".invoker", "#{process_name}.log")
36
+ end
37
+
38
+ def daemonize
39
+ if fork
40
+ sleep(2)
41
+ exit(0)
42
+ else
43
+ Process.setsid
44
+ File.open(pid_file, "w") do |file|
45
+ file.write(Process.pid.to_s)
46
+ end
47
+ Invoker::Logger.puts "Invoker daemon log is available at #{log_file}"
48
+ redirect_io(log_file)
49
+ $0 = process_name
50
+ end
51
+ end
52
+
53
+ def kill_process
54
+ pgid = Process.getpgid(pid)
55
+ Process.kill('-TERM', pgid)
56
+ File.delete(pid_file) if File.exist?(pid_file)
57
+ Invoker::Logger.puts "Stopped Invoker daemon"
58
+ end
59
+
60
+ def process_running?
61
+ Process.kill(0, pid)
62
+ true
63
+ rescue Errno::ESRCH
64
+ false
65
+ end
66
+
67
+ def status
68
+ @status ||= check_process_status
69
+ end
70
+
71
+ def pidfile_exists?
72
+ File.exist?(pid_file)
73
+ end
74
+
75
+ def running?
76
+ status == 0
77
+ end
78
+
79
+ # pidfile exists but process isn't running
80
+ def dead?
81
+ status == 1
82
+ end
83
+
84
+ private
85
+
86
+ def check_process_status
87
+ if pidfile_exists? && process_running?
88
+ 0
89
+ elsif pidfile_exists? # but not process_running
90
+ 1
91
+ else
92
+ 3
93
+ end
94
+ end
95
+
96
+ def redirect_io(logfile_name = nil)
97
+ redirect_file_to_target($stdin)
98
+ redirect_stdout(logfile_name)
99
+ redirect_stderr
100
+ end
101
+
102
+ def redirect_stderr
103
+ redirect_file_to_target($stderr, $stdout)
104
+ $stderr.sync = true
105
+ end
106
+
107
+ def redirect_stdout(logfile_name)
108
+ if logfile_name
109
+ begin
110
+ $stdout.reopen logfile_name, "a"
111
+ $stdout.sync = true
112
+ rescue StandardError
113
+ redirect_file_to_target($stdout)
114
+ end
115
+ else
116
+ redirect_file_to_target($stdout)
117
+ end
118
+ end
119
+
120
+ def redirect_file_to_target(file, target = "/dev/null")
121
+ begin
122
+ file.reopen(target)
123
+ rescue; end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,23 @@
1
+ module Invoker
2
+ class DNSCache
3
+ attr_accessor :dns_data
4
+
5
+ def initialize(config)
6
+ self.dns_data = {}
7
+ @dns_mutex = Mutex.new
8
+ Invoker.config.processes.each do |process|
9
+ if process.port
10
+ dns_data[process.label] = { 'port' => process.port }
11
+ end
12
+ end
13
+ end
14
+
15
+ def [](process_name)
16
+ @dns_mutex.synchronize { dns_data[process_name] }
17
+ end
18
+
19
+ def add(name, port, ip = nil)
20
+ @dns_mutex.synchronize { dns_data[name] = { 'port' => port, 'ip' => ip } }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Invoker
2
+ module Errors
3
+ class ToomanyOpenConnections < StandardError; end
4
+ class ProcessTerminated < StandardError
5
+ attr_accessor :message, :ready_fd
6
+ def initialize(ready_fd, message)
7
+ @ready_fd = ready_fd
8
+ @message = message
9
+ end
10
+ end
11
+
12
+ class NoValidPortFound < StandardError; end
13
+ class InvalidConfig < StandardError; end
14
+ class InvalidFile < StandardError; end
15
+ class ClientDisconnected < StandardError; end
16
+ end
17
+ end