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
@@ -0,0 +1,40 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Invoker</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ padding: 0;
10
+ background: #fff;
11
+ line-height: 18px;
12
+ }
13
+ div.page {
14
+ padding: 36px 90px;
15
+ }
16
+ h1, h2, p, li {
17
+ font-family: Helvetica, sans-serif;
18
+ font-size: 13px;
19
+ }
20
+ h1 {
21
+ line-height: 45px;
22
+ font-size: 36px;
23
+ margin: 0;
24
+ }
25
+ h2 {
26
+ line-height: 27px;
27
+ font-size: 18px;
28
+ font-weight: normal;
29
+ margin: 0;
30
+ }
31
+ </style>
32
+ </head>
33
+ <body class="">
34
+ <div class="page">
35
+ <h1>Application not found</h1>
36
+ <hr>
37
+ <h2>Invoker could not find the application. Please check the configuration file.<h2>
38
+ </div>
39
+ </body>
40
+ </html>
@@ -0,0 +1,40 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Invoker</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ padding: 0;
10
+ background: #fff;
11
+ line-height: 18px;
12
+ }
13
+ div.page {
14
+ padding: 36px 90px;
15
+ }
16
+ h1, h2, p, li {
17
+ font-family: Helvetica, sans-serif;
18
+ font-size: 13px;
19
+ }
20
+ h1 {
21
+ line-height: 45px;
22
+ font-size: 36px;
23
+ margin: 0;
24
+ }
25
+ h2 {
26
+ line-height: 27px;
27
+ font-size: 18px;
28
+ font-weight: normal;
29
+ margin: 0;
30
+ }
31
+ </style>
32
+ </head>
33
+ <body class="">
34
+ <div class="page">
35
+ <h1>Application not running</h1>
36
+ <hr>
37
+ <h2>Invoker did not get any response. Please check if the application is running.<h2>
38
+ </div>
39
+ </body>
40
+ </html>
@@ -0,0 +1,40 @@
1
+ module Invoker
2
+ module Power
3
+ class UrlRewriter
4
+ def select_backend_config(complete_path)
5
+ possible_matches = extract_host_from_domain(complete_path)
6
+ exact_match = nil
7
+ possible_matches.each do |match|
8
+ if match
9
+ exact_match = dns_check(process_name: match)
10
+ break if exact_match.port
11
+ end
12
+ end
13
+ exact_match
14
+ end
15
+
16
+ def extract_host_from_domain(complete_path)
17
+ matching_strings = []
18
+ tld_match_regex.map do |regexp|
19
+ if (match_result = complete_path.match(regexp))
20
+ matching_strings << match_result[1]
21
+ end
22
+ end
23
+ matching_strings.uniq
24
+ end
25
+
26
+ private
27
+
28
+ def tld_match_regex
29
+ tld = Invoker.config.tld
30
+ [/([\w.-]+)\.#{tld}(\:\d+)?$/, /([\w-]+)\.#{tld}(\:\d+)?$/]
31
+ end
32
+
33
+ def dns_check(dns_args)
34
+ Invoker::IPC::UnixClient.send_command("dns_check", dns_args) do |dns_response|
35
+ dns_response
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,201 @@
1
+ module Invoker
2
+ # Class is responsible for managing all the processes Invoker is supposed
3
+ # to manage. Takes care of starting, stopping and restarting processes.
4
+ class ProcessManager
5
+ LABEL_COLORS = [:green, :yellow, :blue, :magenta, :cyan]
6
+ attr_accessor :open_pipes, :workers
7
+
8
+ def initialize
9
+ @open_pipes = {}
10
+ @workers = {}
11
+ @worker_mutex = Mutex.new
12
+ @thread_group = ThreadGroup.new
13
+ end
14
+
15
+ def start_process(process_info)
16
+ m, s = PTY.open
17
+ s.raw! # disable newline conversion.
18
+
19
+ pid = run_command(process_info, s)
20
+
21
+ s.close
22
+
23
+ worker = CommandWorker.new(process_info.label, m, pid, select_color)
24
+
25
+ add_worker(worker)
26
+ wait_on_pid(process_info.label, pid)
27
+ end
28
+
29
+ # Start a process given their name
30
+ # @param process_name [String] Command label of process specified in config file.
31
+ def start_process_by_name(process_name)
32
+ if process_running?(process_name)
33
+ Invoker::Logger.puts "\nProcess '#{process_name}' is already running".colorize(:red)
34
+ return false
35
+ end
36
+
37
+ process_info = Invoker.config.process(process_name)
38
+ start_process(process_info) if process_info
39
+ end
40
+
41
+ # Remove a process from list of processes managed by invoker supervisor.It also
42
+ # kills the process before removing it from the list.
43
+ #
44
+ # @param remove_message [Invoker::IPC::Message::Remove]
45
+ # @return [Boolean] if process existed and was removed else false
46
+ def stop_process(remove_message)
47
+ worker = workers[remove_message.process_name]
48
+ command_label = remove_message.process_name
49
+ return false unless worker
50
+ signal_to_use = remove_message.signal || 'INT'
51
+
52
+ Invoker::Logger.puts("Removing #{command_label} with signal #{signal_to_use}".colorize(:red))
53
+ kill_or_remove_process(worker.pid, signal_to_use, command_label)
54
+ end
55
+
56
+ # Receive a message from user to restart a Process
57
+ # @param [Invoker::IPC::Message::Reload]
58
+ def restart_process(reload_message)
59
+ command_label = reload_message.process_name
60
+ if stop_process(reload_message.remove_message)
61
+ Invoker.commander.schedule_event(command_label, :worker_removed) do
62
+ start_process_by_name(command_label)
63
+ end
64
+ else
65
+ start_process_by_name(command_label)
66
+ end
67
+ end
68
+
69
+ def run_power_server
70
+ return unless Invoker.can_run_balancer?(false)
71
+
72
+ powerup_id = Invoker::Power::Powerup.fork_and_start
73
+ wait_on_pid("powerup_manager", powerup_id)
74
+ at_exit do
75
+ begin
76
+ Process.kill("INT", powerup_id)
77
+ rescue Errno::ESRCH; end
78
+ end
79
+ end
80
+
81
+ # Given a file descriptor returns the worker object
82
+ #
83
+ # @param fd [IO] an IO object with valid file descriptor
84
+ # @return [Invoker::CommandWorker] The worker object which is associated with this fd
85
+ def get_worker_from_fd(fd)
86
+ open_pipes[fd.fileno]
87
+ end
88
+
89
+ def load_env(directory = nil)
90
+ directory ||= ENV['PWD']
91
+
92
+ if !directory || directory.empty? || !Dir.exist?(directory)
93
+ return {}
94
+ end
95
+
96
+ default_env = File.join(directory, '.env')
97
+ local_env = File.join(directory, '.env.local')
98
+ env = {}
99
+
100
+ if File.exist?(default_env)
101
+ env.merge!(Dotenv::Environment.new(default_env))
102
+ end
103
+
104
+ if File.exist?(local_env)
105
+ env.merge!(Dotenv::Environment.new(local_env))
106
+ end
107
+
108
+ env
109
+ end
110
+
111
+ def kill_workers
112
+ @workers.each do |key, worker|
113
+ kill_or_remove_process(worker.pid, "INT", worker.command_label)
114
+ end
115
+ @workers = {}
116
+ end
117
+
118
+ # List currently running commands
119
+ def process_list
120
+ Invoker::IPC::Message::ListResponse.from_workers(workers)
121
+ end
122
+
123
+ private
124
+
125
+ def wait_on_pid(command_label, pid)
126
+ raise Invoker::Errors::ToomanyOpenConnections if @thread_group.enclosed?
127
+
128
+ thread = Thread.new do
129
+ Process.wait(pid)
130
+ message = "Process with command #{command_label} exited with status #{$?.exitstatus}"
131
+ Invoker::Logger.puts("\n#{message}".colorize(:red))
132
+ Invoker.notify_user(message)
133
+ Invoker.commander.trigger(command_label, :exit)
134
+ end
135
+ @thread_group.add(thread)
136
+ end
137
+
138
+ def select_color
139
+ selected_color = LABEL_COLORS.shift
140
+ LABEL_COLORS.push(selected_color)
141
+ selected_color
142
+ end
143
+
144
+ def process_running?(command_label)
145
+ !!workers[command_label]
146
+ end
147
+
148
+ def kill_or_remove_process(pid, signal_to_use, command_label)
149
+ process_kill(pid, signal_to_use)
150
+ true
151
+ rescue Errno::ESRCH
152
+ Invoker::Logger.puts("Killing process with #{pid} and name #{command_label} failed".colorize(:red))
153
+ remove_worker(command_label, false)
154
+ false
155
+ end
156
+
157
+ def process_kill(pid, signal_to_use)
158
+ if signal_to_use.to_i == 0
159
+ Process.kill(signal_to_use, -Process.getpgid(pid))
160
+ else
161
+ Process.kill(signal_to_use.to_i, -Process.getpgid(pid))
162
+ end
163
+ end
164
+
165
+ # Remove worker from all collections
166
+ def remove_worker(command_label, trigger_event = true)
167
+ worker = @workers[command_label]
168
+ if worker
169
+ @open_pipes.delete(worker.pipe_end.fileno)
170
+ @workers.delete(command_label)
171
+ # Move label color to front of array so it's reused first
172
+ LABEL_COLORS.delete(worker.color)
173
+ LABEL_COLORS.unshift(worker.color)
174
+ end
175
+ if trigger_event
176
+ Invoker.commander.trigger(command_label, :worker_removed)
177
+ end
178
+ end
179
+
180
+ # add worker to global collections
181
+ def add_worker(worker)
182
+ @open_pipes[worker.pipe_end.fileno] = worker
183
+ @workers[worker.command_label] = worker
184
+ Invoker.commander.watch_for_read(worker.pipe_end)
185
+ end
186
+
187
+ def run_command(process_info, write_pipe)
188
+ command_label = process_info.label
189
+
190
+ Invoker.commander.schedule_event(command_label, :exit) { remove_worker(command_label) }
191
+
192
+ env_options = load_env(process_info.dir)
193
+
194
+ spawn_options = {
195
+ :chdir => process_info.dir || ENV['PWD'], :out => write_pipe, :err => write_pipe,
196
+ :pgroup => true, :close_others => true, :in => :close
197
+ }
198
+ Invoker.run_without_bundler { spawn(env_options, process_info.cmd, spawn_options) }
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,59 @@
1
+ module Invoker
2
+ class ProcessPrinter
3
+ MAX_COLUMN_WIDTH = 40
4
+ attr_accessor :list_response
5
+
6
+ def initialize(list_response)
7
+ self.list_response = list_response
8
+ end
9
+
10
+ def print_table
11
+ hash_with_colors = []
12
+ list_response.processes.each do |process|
13
+ if process.pid
14
+ hash_with_colors << colorize_hash(process, "green")
15
+ else
16
+ hash_with_colors << colorize_hash(process, "light_black")
17
+ end
18
+ end
19
+ Formatador.display_compact_table(hash_with_colors)
20
+ end
21
+
22
+ def print_raw_text
23
+ list_response.processes.each do |process|
24
+ Formatador.display_line("[bold]Process Name : #{process.process_name}[/]")
25
+ Formatador.indent {
26
+ Formatador.display_line("Dir : #{process.dir}")
27
+ if process.pid
28
+ Formatador.display_line("PID : #{process.pid}")
29
+ else
30
+ Formatador.display_line("PID : Not Running")
31
+ end
32
+ Formatador.display_line("Port : #{process.port}")
33
+ Formatador.display_line("Command : #{process.shell_command}")
34
+ }
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def colorize_hash(process, color)
41
+ hash_with_colors = {}
42
+
43
+ hash_with_colors['dir'] = colored_string(process.dir, color)
44
+ hash_with_colors['pid'] = colored_string(process.pid || 'Not Running', color)
45
+ hash_with_colors['port'] = colored_string(process.port, color)
46
+ hash_with_colors['shell_command'] = colored_string(process.shell_command, color)
47
+ hash_with_colors['process_name'] = colored_string(process.process_name, color)
48
+ hash_with_colors
49
+ end
50
+
51
+ def colored_string(string, color)
52
+ string = string.to_s
53
+ if string.length > MAX_COLUMN_WIDTH
54
+ string = "#{string[0..MAX_COLUMN_WIDTH]}.."
55
+ end
56
+ "[#{color}]#{string}[/]"
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,65 @@
1
+ module Invoker
2
+ class Reactor::Reader
3
+ attr_accessor :read_array
4
+
5
+ def initialize
6
+ @read_array = []
7
+ end
8
+
9
+ def watch_for_read(socket)
10
+ @read_array << socket
11
+ end
12
+
13
+ def handle_read_event(read_ready_fds)
14
+ ready_fds = read_ready_fds.flatten.compact
15
+ ready_fds.each { |ready_fd| process_read(ready_fd) }
16
+ end
17
+
18
+ private
19
+
20
+ def process_read(ready_fd)
21
+ command_worker = Invoker.commander.get_worker_from_fd(ready_fd)
22
+ begin
23
+ data = read_data(ready_fd)
24
+ send_data_to_worker(data, command_worker)
25
+ rescue Invoker::Errors::ProcessTerminated
26
+ remove_from_read_monitoring(command_worker, ready_fd)
27
+ end
28
+ end
29
+
30
+ def send_data_to_worker(data, command_worker)
31
+ if command_worker
32
+ command_worker.receive_data(data)
33
+ else
34
+ Invoker::Logger.puts("No reader found for incoming data")
35
+ end
36
+ end
37
+
38
+ def remove_from_read_monitoring(command_worker, ready_fd)
39
+ if command_worker
40
+ read_array.delete(command_worker.pipe_end)
41
+ command_worker.unbind
42
+ else
43
+ read_array.delete(ready_fd)
44
+ end
45
+ rescue StandardError => error
46
+ Invoker::Logger.puts(error.message)
47
+ Invoker::Logger.puts(error.backtrace)
48
+ end
49
+
50
+ def read_data(ready_fd)
51
+ sock_data = []
52
+ begin
53
+ while(t_data = ready_fd.read_nonblock(64))
54
+ sock_data << t_data
55
+ end
56
+ rescue Errno::EAGAIN
57
+ return sock_data.join
58
+ rescue Errno::EWOULDBLOCK
59
+ return sock_data.join
60
+ rescue
61
+ raise Invoker::Errors::ProcessTerminated.new(ready_fd,sock_data.join)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,37 @@
1
+ module Invoker
2
+ class Reactor
3
+ attr_accessor :reader
4
+
5
+ def initialize
6
+ @reader = Invoker::Reactor::Reader.new
7
+ end
8
+
9
+ def watch_for_read(fd)
10
+ reader.watch_for_read(fd)
11
+ end
12
+
13
+ # Writes data to client socket and raises error if errors
14
+ # while writing
15
+ def send_data(socket, data)
16
+ socket.write(data)
17
+ rescue
18
+ raise Invoker::Errors::ClientDisconnected
19
+ end
20
+
21
+ def monitor_for_fd_events
22
+ ready_read_fds, _ , _ = select(*options_for_select)
23
+
24
+ if ready_read_fds && !ready_read_fds.empty?
25
+ reader.handle_read_event(ready_read_fds)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def options_for_select
32
+ [reader.read_array, [], [], 0.05]
33
+ end
34
+ end
35
+ end
36
+
37
+ require "invoker/reactor/reader"
@@ -0,0 +1,47 @@
1
+ module Invoker
2
+ class Version
3
+ include Comparable
4
+ attr_reader :major, :minor, :patch
5
+
6
+ def initialize(number)
7
+ t_major, t_minor, t_patch = number.split('.')
8
+ @major = t_major.to_i
9
+ @minor = t_minor.to_i
10
+ @patch = t_patch.to_i
11
+ end
12
+
13
+ def to_a
14
+ [major, minor, patch].compact
15
+ end
16
+
17
+ def <=>(version)
18
+ (major.to_i <=> version.major.to_i).nonzero? ||
19
+ (minor.to_i <=> version.minor.to_i).nonzero? ||
20
+ patch.to_i <=> version.patch.to_i
21
+ end
22
+
23
+ def matches?(operator, number)
24
+ version = Version.new(number)
25
+ self == version
26
+
27
+ return self == version if operator == '='
28
+ return self > version if operator == '>'
29
+ return self < version if operator == '<'
30
+ return version <= self && version.next > self if operator == '~>'
31
+ end
32
+
33
+ def next
34
+ next_splits = to_a
35
+
36
+ if next_splits.length == 1
37
+ next_splits[0] += 1
38
+ else
39
+ next_splits[-2] += 1
40
+ next_splits[-1] = 0
41
+ end
42
+
43
+ Version.new(next_splits.join('.'))
44
+ end
45
+ end
46
+ VERSION = "1.6.0"
47
+ end
data/lib/invoker.rb ADDED
@@ -0,0 +1,151 @@
1
+ $: << File.dirname(__FILE__) unless $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ require "fileutils"
4
+ require "formatador"
5
+
6
+ require "ostruct"
7
+ require "uuid"
8
+ require "json"
9
+ require "colorize"
10
+ require "etc"
11
+
12
+ require "invoker/version"
13
+ require "invoker/logger"
14
+ require "invoker/daemon"
15
+ require "invoker/cli"
16
+ require "invoker/dns_cache"
17
+ require "invoker/ipc"
18
+ require "invoker/power/config"
19
+ require "invoker/power/port_finder"
20
+ require "invoker/power/setup"
21
+ require "invoker/power/setup/linux_setup"
22
+ require "invoker/power/setup/osx_setup"
23
+ require "invoker/power/powerup"
24
+ require "invoker/errors"
25
+ require "invoker/parsers/procfile"
26
+ require "invoker/parsers/config"
27
+ require "invoker/commander"
28
+ require "invoker/process_manager"
29
+ require "invoker/command_worker"
30
+ require "invoker/reactor"
31
+ require "invoker/event/manager"
32
+ require "invoker/process_printer"
33
+
34
+ module Invoker
35
+ class << self
36
+ attr_accessor :config, :tail_watchers, :commander
37
+ attr_accessor :dns_cache, :daemonize, :nocolors, :certificate, :private_key
38
+
39
+ alias_method :daemonize?, :daemonize
40
+ alias_method :nocolors?, :nocolors
41
+
42
+ def darwin?
43
+ ruby_platform.downcase.include?("darwin")
44
+ end
45
+
46
+ def linux?
47
+ ruby_platform.downcase.include?("linux")
48
+ end
49
+
50
+ def ruby_platform
51
+ RUBY_PLATFORM
52
+ end
53
+
54
+ def load_invoker_config(file, port)
55
+ @config = Invoker::Parsers::Config.new(file, port)
56
+ @dns_cache = Invoker::DNSCache.new(@invoker_config)
57
+ @tail_watchers = Invoker::CLI::TailWatcher.new
58
+ @commander = Invoker::Commander.new
59
+ end
60
+
61
+ def close_socket(socket)
62
+ socket.close
63
+ rescue StandardError => error
64
+ Invoker::Logger.puts "Error removing socket #{error}"
65
+ end
66
+
67
+ def daemon
68
+ @daemon ||= Invoker::Daemon.new
69
+ end
70
+
71
+ def can_run_balancer?(throw_warning = true)
72
+ return true if File.exist?(Invoker::Power::Config.config_file)
73
+
74
+ if throw_warning
75
+ Invoker::Logger.puts("Invoker has detected setup has not been run. Domain feature will not work without running setup command.".colorize(:red))
76
+ end
77
+ false
78
+ end
79
+
80
+ def setup_config_location
81
+ config_dir = Invoker::Power::Config.config_dir
82
+ return config_dir if Dir.exist?(config_dir)
83
+
84
+ if File.exist?(config_dir)
85
+ old_config = File.read(config_dir)
86
+ FileUtils.rm_f(config_dir)
87
+ end
88
+
89
+ FileUtils.mkdir(config_dir)
90
+
91
+ migrate_old_config(old_config, config_dir) if old_config
92
+ config_dir
93
+ end
94
+
95
+ def run_without_bundler
96
+ if defined?(Bundler)
97
+ Bundler.with_clean_env do
98
+ yield
99
+ end
100
+ else
101
+ yield
102
+ end
103
+ end
104
+
105
+ def notify_user(message)
106
+ if Invoker.darwin?
107
+ run_without_bundler { check_and_notify_with_terminal_notifier(message) }
108
+ elsif Invoker.linux?
109
+ notify_with_libnotify(message)
110
+ end
111
+ end
112
+
113
+ def check_and_notify_with_terminal_notifier(message)
114
+ command_path = `which terminal-notifier`
115
+ if command_path && !command_path.empty?
116
+ system("terminal-notifier -message '#{message}' -title Invoker")
117
+ end
118
+ end
119
+
120
+ def notify_with_libnotify(message)
121
+ begin
122
+ require "libnotify"
123
+ Libnotify.show(body: message, summary: "Invoker", timeout: 2.5)
124
+ rescue LoadError; end
125
+ end
126
+
127
+ def migrate_old_config(old_config, config_location)
128
+ new_config = File.join(config_location, 'config')
129
+ File.open(new_config, 'w') do |file|
130
+ file.write(old_config)
131
+ end
132
+ end
133
+
134
+ # On some platforms `Dir.home` or `ENV['HOME']` does not return home directory of user.
135
+ # this is especially true, after effective and real user id of process
136
+ # has been changed.
137
+ #
138
+ # @return [String] home directory of the user
139
+ def home
140
+ if File.writable?(Dir.home)
141
+ Dir.home
142
+ else
143
+ Etc.getpwuid(Process.uid).dir
144
+ end
145
+ end
146
+
147
+ def default_tld
148
+ 'test'
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::CLI::Pinger do
4
+ let(:unix_client) { Invoker::IPC::UnixClient.new }
5
+ let(:pinger) { Invoker::CLI::Pinger.new(unix_client) }
6
+ let(:pong) { MM::Pong.new(status: 'pong') }
7
+
8
+ context "If Invoker is running" do
9
+ it "should return true" do
10
+ unix_client.expects(:send_and_receive).returns(pong)
11
+ expect(pinger.invoker_running?).to be_truthy
12
+ end
13
+ end
14
+
15
+ context "if Invoker is not running" do
16
+ it "should return false" do
17
+ unix_client.expects(:send_and_receive).returns(nil)
18
+ unix_client.expects(:abort).never
19
+ expect(pinger.invoker_running?).to be_falsey
20
+ end
21
+ end
22
+ end