invoker 1.0.4 → 1.1.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.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rubocop.yml +30 -0
- data/.travis.yml +1 -0
- data/Gemfile +1 -0
- data/bin/invoker +4 -8
- data/invoker.gemspec +10 -11
- data/lib/invoker.rb +95 -21
- data/lib/invoker/cli.rb +126 -0
- data/lib/invoker/cli/pinger.rb +23 -0
- data/lib/invoker/cli/question.rb +15 -0
- data/lib/invoker/cli/tail.rb +34 -0
- data/lib/invoker/cli/tail_watcher.rb +34 -0
- data/lib/invoker/command_worker.rb +28 -2
- data/lib/invoker/commander.rb +34 -236
- data/lib/invoker/config.rb +5 -0
- data/lib/invoker/daemon.rb +126 -0
- data/lib/invoker/dns_cache.rb +23 -0
- data/lib/invoker/errors.rb +1 -0
- data/lib/invoker/ipc.rb +45 -0
- data/lib/invoker/ipc/add_command.rb +12 -0
- data/lib/invoker/ipc/add_http_command.rb +10 -0
- data/lib/invoker/ipc/base_command.rb +24 -0
- data/lib/invoker/ipc/client_handler.rb +26 -0
- data/lib/invoker/ipc/dns_check_command.rb +16 -0
- data/lib/invoker/ipc/list_command.rb +11 -0
- data/lib/invoker/ipc/message.rb +170 -0
- data/lib/invoker/ipc/message/list_response.rb +33 -0
- data/lib/invoker/ipc/message/tail_response.rb +10 -0
- data/lib/invoker/ipc/ping_command.rb +10 -0
- data/lib/invoker/ipc/reload_command.rb +12 -0
- data/lib/invoker/ipc/remove_command.rb +12 -0
- data/lib/invoker/{command_listener → ipc}/server.rb +6 -11
- data/lib/invoker/ipc/tail_command.rb +11 -0
- data/lib/invoker/ipc/unix_client.rb +60 -0
- data/lib/invoker/parsers/config.rb +1 -0
- data/lib/invoker/power/balancer.rb +17 -7
- data/lib/invoker/power/config.rb +6 -3
- data/lib/invoker/power/dns.rb +22 -21
- data/lib/invoker/power/http_response.rb +1 -1
- data/lib/invoker/power/power.rb +3 -0
- data/lib/invoker/power/powerup.rb +3 -2
- data/lib/invoker/power/setup.rb +6 -4
- data/lib/invoker/process_manager.rb +187 -0
- data/lib/invoker/process_printer.rb +27 -38
- data/lib/invoker/reactor.rb +19 -38
- data/lib/invoker/reactor/reader.rb +53 -0
- data/lib/invoker/version.rb +1 -1
- data/readme.md +1 -1
- data/spec/invoker/cli/pinger_spec.rb +22 -0
- data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
- data/spec/invoker/cli_spec.rb +27 -0
- data/spec/invoker/command_worker_spec.rb +30 -0
- data/spec/invoker/commander_spec.rb +57 -127
- data/spec/invoker/config_spec.rb +21 -0
- data/spec/invoker/daemon_spec.rb +34 -0
- data/spec/invoker/invoker_spec.rb +31 -0
- data/spec/invoker/ipc/client_handler_spec.rb +44 -0
- data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
- data/spec/invoker/ipc/message/list_response_spec.rb +22 -0
- data/spec/invoker/ipc/message_spec.rb +45 -0
- data/spec/invoker/ipc/unix_client_spec.rb +29 -0
- data/spec/invoker/power/setup_spec.rb +1 -1
- data/spec/invoker/process_manager_spec.rb +98 -0
- data/spec/invoker/reactor_spec.rb +6 -0
- data/spec/spec_helper.rb +15 -24
- metadata +107 -77
- data/lib/invoker/command_listener/client.rb +0 -45
- data/lib/invoker/parsers/option_parser.rb +0 -106
- data/lib/invoker/power.rb +0 -7
- data/lib/invoker/runner.rb +0 -98
- data/spec/invoker/command_listener/client_spec.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17e01fb0ade988c21a62f385d51e3b07e58f9016
|
4
|
+
data.tar.gz: 2e4e0c36f2df111493b7c05dea7e0ae99244de2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7601b89cd0db7b1cc0e780885d14f27ec652739702b5c2a59cf961b677db347bfd9e764ada4a53057de80a418ca3d486949c1a6909ee414505a8b5323593708
|
7
|
+
data.tar.gz: 552b15ffb14c384d02f3ec972ccd8f3a2191afedab5bfa899f19c9fb1ecf0e4df86c65cdbfa475df8babfc746401bc6d914bcb26f0abda2f6fd04283dab092c3
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
AllCops:
|
2
|
+
RunRailsCops: false
|
3
|
+
Excludes:
|
4
|
+
- db/**
|
5
|
+
|
6
|
+
HashSyntax:
|
7
|
+
Description: 'Use either hash rocket or 1.9 styled hashes.'
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
LineLength:
|
11
|
+
Max: 100
|
12
|
+
|
13
|
+
# Disable Certain Tests
|
14
|
+
|
15
|
+
Documentation:
|
16
|
+
Description: 'Document classes and non-namespace modules.'
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
StringLiterals:
|
20
|
+
Description: 'Checks if uses of quotes match the configured preference.'
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Encoding:
|
24
|
+
Description: 'Use UTF-8 as the source file encoding.'
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
SignalException:
|
28
|
+
Description: 'Do not enforce use of fail when raising exceptions.'
|
29
|
+
# Valid values are: semantic, only_raise and only_fail
|
30
|
+
EnforcedStyle: only_raise
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/bin/invoker
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
invoker_lib_path = File.expand_path('../../lib', __FILE__)
|
7
|
-
$:.unshift(invoker_lib_path)
|
8
|
-
require "invoker"
|
9
|
-
end
|
3
|
+
invoker_lib_path = File.expand_path('../../lib', __FILE__)
|
4
|
+
$:.unshift(invoker_lib_path)
|
5
|
+
require "invoker"
|
10
6
|
|
11
|
-
Invoker::
|
7
|
+
Invoker::CLI.start(ARGV)
|
data/invoker.gemspec
CHANGED
@@ -25,17 +25,16 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.licenses = ["MIT"]
|
26
26
|
s.require_paths = ["lib"]
|
27
27
|
s.summary = %q{Something small for Process management}
|
28
|
-
s.add_dependency("
|
29
|
-
s.add_dependency("rainbow", "~>
|
30
|
-
s.add_dependency("iniparse", "~> 1.1
|
31
|
-
s.add_dependency("formatador", "~> 0.2
|
32
|
-
s.add_dependency("eventmachine", "~> 1.0
|
33
|
-
s.add_dependency("em-proxy", "~> 0.1
|
34
|
-
s.add_dependency("rubydns", "~> 0.
|
35
|
-
s.add_dependency("uuid", "~> 2.3
|
36
|
-
s.add_dependency("
|
37
|
-
s.add_dependency("
|
38
|
-
s.add_dependency("dotenv", "~> 0.9.0")
|
28
|
+
s.add_dependency("thor", "~> 0.19")
|
29
|
+
s.add_dependency("rainbow", "~> 2.0")
|
30
|
+
s.add_dependency("iniparse", "~> 1.1")
|
31
|
+
s.add_dependency("formatador", "~> 0.2")
|
32
|
+
s.add_dependency("eventmachine", "~> 1.0")
|
33
|
+
s.add_dependency("em-proxy", "~> 0.1")
|
34
|
+
s.add_dependency("rubydns", "~> 0.7")
|
35
|
+
s.add_dependency("uuid", "~> 2.3")
|
36
|
+
s.add_dependency("http-parser-lite", "~> 0.6")
|
37
|
+
s.add_dependency("dotenv", "~> 0.9")
|
39
38
|
s.add_development_dependency("rspec")
|
40
39
|
s.add_development_dependency("mocha")
|
41
40
|
s.add_development_dependency("rake")
|
data/lib/invoker.rb
CHANGED
@@ -2,44 +2,118 @@ $: << File.dirname(__FILE__) unless $:.include?(File.expand_path(File.dirname(__
|
|
2
2
|
|
3
3
|
require "fileutils"
|
4
4
|
require "formatador"
|
5
|
-
|
6
|
-
require 'em-proxy'
|
7
|
-
require 'http-parser'
|
5
|
+
|
8
6
|
require "ostruct"
|
9
7
|
require "uuid"
|
10
|
-
require "
|
8
|
+
require "json"
|
9
|
+
require "rainbow"
|
10
|
+
require "rainbow/ext/string"
|
11
|
+
|
11
12
|
require "invoker/version"
|
12
13
|
require "invoker/logger"
|
13
|
-
require "invoker/
|
14
|
-
require "invoker/
|
15
|
-
require "invoker/
|
16
|
-
require "invoker/
|
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/powerup"
|
17
22
|
require "invoker/errors"
|
18
23
|
require "invoker/parsers/procfile"
|
19
24
|
require "invoker/parsers/config"
|
20
|
-
require "invoker/parsers/option_parser"
|
21
25
|
require "invoker/commander"
|
26
|
+
require "invoker/process_manager"
|
22
27
|
require "invoker/command_worker"
|
23
28
|
require "invoker/reactor"
|
24
29
|
require "invoker/event/manager"
|
25
30
|
require "invoker/process_printer"
|
26
31
|
|
27
32
|
module Invoker
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
class << self
|
34
|
+
attr_accessor :config, :tail_watchers, :commander
|
35
|
+
attr_accessor :dns_cache, :daemonize
|
31
36
|
|
32
|
-
|
33
|
-
|
34
|
-
|
37
|
+
alias_method :daemonize?, :daemonize
|
38
|
+
|
39
|
+
def darwin?
|
40
|
+
ruby_platform.downcase.include?("darwin")
|
41
|
+
end
|
42
|
+
|
43
|
+
def ruby_platform
|
44
|
+
RUBY_PLATFORM
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_invoker_config(file, port)
|
48
|
+
@config = Invoker::Parsers::Config.new(file, port)
|
49
|
+
@dns_cache = Invoker::DNSCache.new(@invoker_config)
|
50
|
+
@tail_watchers = Invoker::CLI::TailWatcher.new
|
51
|
+
@commander = Invoker::Commander.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def close_socket(socket)
|
55
|
+
socket.close
|
56
|
+
rescue StandardError => error
|
57
|
+
Invoker::Logger.puts "Error removing socket #{error}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def daemon
|
61
|
+
@daemon ||= Invoker::Daemon.new
|
62
|
+
end
|
35
63
|
|
36
|
-
|
37
|
-
|
38
|
-
|
64
|
+
def can_run_balancer?(throw_warning = true)
|
65
|
+
return false unless darwin?
|
66
|
+
return true if File.exist?(Invoker::Power::Config::CONFIG_LOCATION)
|
67
|
+
|
68
|
+
if throw_warning
|
69
|
+
Invoker::Logger.puts("Invoker has detected setup has not been run. Domain feature will not work without running setup command.".color(:red))
|
70
|
+
end
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
def setup_config_location
|
75
|
+
config_location = File.join(Dir.home, '.invoker')
|
76
|
+
return config_location if Dir.exist?(config_location)
|
77
|
+
|
78
|
+
if File.exist?(config_location)
|
79
|
+
old_config = File.read(config_location)
|
80
|
+
FileUtils.rm_f(config_location)
|
81
|
+
end
|
82
|
+
|
83
|
+
FileUtils.mkdir(config_location)
|
84
|
+
|
85
|
+
migrate_old_config(old_config, config_location) if old_config
|
86
|
+
config_location
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_without_bundler
|
90
|
+
if defined?(Bundler)
|
91
|
+
Bundler.with_clean_env do
|
92
|
+
yield
|
93
|
+
end
|
94
|
+
else
|
95
|
+
yield
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def notify_user(message)
|
100
|
+
run_without_bundler { check_and_notify_with_terminal_notifier(message) }
|
101
|
+
end
|
102
|
+
|
103
|
+
def check_and_notify_with_terminal_notifier(message)
|
104
|
+
return unless Invoker.darwin?
|
105
|
+
|
106
|
+
command_path = `which terminal-notifier`
|
107
|
+
if command_path && !command_path.empty?
|
108
|
+
system("terminal-notifier -message '#{message}' -title Invoker")
|
109
|
+
end
|
110
|
+
end
|
39
111
|
|
40
|
-
|
41
|
-
|
112
|
+
def migrate_old_config(old_config, config_location)
|
113
|
+
new_config = File.join(config_location, 'config')
|
114
|
+
File.open(new_config, 'w') do |file|
|
115
|
+
file.write(old_config)
|
116
|
+
end
|
42
117
|
end
|
43
|
-
false
|
44
118
|
end
|
45
119
|
end
|
data/lib/invoker/cli.rb
ADDED
@@ -0,0 +1,126 @@
|
|
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
|
+
def setup
|
17
|
+
Invoker::Power::Setup.install
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "version", "Print Invoker version"
|
21
|
+
def version
|
22
|
+
Invoker::Logger.puts Invoker::VERSION
|
23
|
+
end
|
24
|
+
map %w(-v --version) => :version
|
25
|
+
|
26
|
+
desc "uninstall", "Uninstall Invoker and all installed files"
|
27
|
+
def uninstall
|
28
|
+
Invoker::Power::Setup.uninstall
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "start CONFIG_FILE", "Start Invoker Server"
|
32
|
+
option :port, type: :numeric, banner: "Port series to be used for starting rack servers"
|
33
|
+
option :daemon,
|
34
|
+
type: :boolean,
|
35
|
+
banner: "Daemonize the server into the background",
|
36
|
+
aliases: [:d]
|
37
|
+
def start(file)
|
38
|
+
Invoker.setup_config_location
|
39
|
+
port = options[:port] || 9000
|
40
|
+
Invoker.daemonize = options[:daemon]
|
41
|
+
Invoker.load_invoker_config(file, port)
|
42
|
+
warn_about_terminal_notifier
|
43
|
+
pinger = Invoker::CLI::Pinger.new(unix_socket)
|
44
|
+
abort("Invoker is already running".color(:red)) if pinger.invoker_running?
|
45
|
+
Invoker.commander.start_manager
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "add process", "Add a program to Invoker server"
|
49
|
+
def add(name)
|
50
|
+
unix_socket.send_command('add', process_name: name)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "add_http process_name port", "Add an external http process to Invoker DNS server"
|
54
|
+
def add_http(name, port)
|
55
|
+
unix_socket.send_command('add_http', process_name: name, port: port)
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "tail process1 process2", "Tail a particular process"
|
59
|
+
def tail(*names)
|
60
|
+
tailer = Invoker::CLI::Tail.new(names)
|
61
|
+
tailer.run
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "reload process", "Reload a process managed by Invoker"
|
65
|
+
option :signal,
|
66
|
+
banner: "Signal to send for killing the process, default is SIGINT",
|
67
|
+
aliases: [:s]
|
68
|
+
def reload(name)
|
69
|
+
signal = options[:signal] || 'INT'
|
70
|
+
unix_socket.send_command('reload', process_name: name, signal: signal)
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "list", "List all running processes"
|
74
|
+
def list
|
75
|
+
unix_socket.send_command('list') do |response_object|
|
76
|
+
Invoker::ProcessPrinter.new(response_object).tap { |printer| printer.print_table }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "remove process", "Stop a process managed by Invoker"
|
81
|
+
option :signal,
|
82
|
+
banner: "Signal to send for killing the process, default is SIGINT",
|
83
|
+
aliases: [:s]
|
84
|
+
def remove(name)
|
85
|
+
signal = options[:signal] || 'INT'
|
86
|
+
unix_socket.send_command('remove', process_name: name, signal: signal)
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "stop", "Stop Invoker daemon"
|
90
|
+
def stop
|
91
|
+
Invoker.daemon.stop
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def self.default_start_command?(args)
|
97
|
+
command_name = args.first
|
98
|
+
command_name &&
|
99
|
+
!command_name.match(/^-/) &&
|
100
|
+
!valid_tasks.include?(command_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.valid_tasks
|
104
|
+
tasks.keys + ["help"]
|
105
|
+
end
|
106
|
+
|
107
|
+
def unix_socket
|
108
|
+
Invoker::IPC::UnixClient.new
|
109
|
+
end
|
110
|
+
|
111
|
+
def warn_about_terminal_notifier
|
112
|
+
if RUBY_PLATFORM.downcase.include?("darwin")
|
113
|
+
command_path = `which terminal-notifier`
|
114
|
+
if !command_path || command_path.empty?
|
115
|
+
Invoker::Logger.puts "You can enable OSX notification for processes "\
|
116
|
+
"by installing terminal-notifier gem".color(:red)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
require "invoker/cli/question"
|
124
|
+
require "invoker/cli/tail_watcher"
|
125
|
+
require "invoker/cli/tail"
|
126
|
+
require "invoker/cli/pinger"
|
@@ -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
|