meepo 1.5.2
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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +10 -0
- data/Dockerfile +7 -0
- data/Gemfile +13 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +15 -0
- data/TODO +5 -0
- data/bin/invoker +7 -0
- data/contrib/completion/invoker-completion.bash +70 -0
- data/contrib/completion/invoker-completion.zsh +62 -0
- data/examples/hello_sinatra.rb +26 -0
- data/examples/sample.ini +3 -0
- data/invoker.gemspec +43 -0
- data/lib/invoker.rb +152 -0
- data/lib/invoker/cli.rb +159 -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 +60 -0
- data/lib/invoker/commander.rb +95 -0
- data/lib/invoker/daemon.rb +126 -0
- data/lib/invoker/dns_cache.rb +23 -0
- data/lib/invoker/errors.rb +17 -0
- data/lib/invoker/event/manager.rb +79 -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 +17 -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 +35 -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/ipc/server.rb +26 -0
- data/lib/invoker/ipc/tail_command.rb +11 -0
- data/lib/invoker/ipc/unix_client.rb +60 -0
- data/lib/invoker/logger.rb +13 -0
- data/lib/invoker/parsers/config.rb +184 -0
- data/lib/invoker/parsers/procfile.rb +86 -0
- data/lib/invoker/power/balancer.rb +131 -0
- data/lib/invoker/power/config.rb +77 -0
- data/lib/invoker/power/dns.rb +38 -0
- data/lib/invoker/power/http_parser.rb +68 -0
- data/lib/invoker/power/http_response.rb +81 -0
- data/lib/invoker/power/pf_migrate.rb +64 -0
- data/lib/invoker/power/port_finder.rb +49 -0
- data/lib/invoker/power/power.rb +3 -0
- data/lib/invoker/power/powerup.rb +29 -0
- data/lib/invoker/power/setup.rb +90 -0
- data/lib/invoker/power/setup/distro/arch.rb +15 -0
- data/lib/invoker/power/setup/distro/base.rb +57 -0
- data/lib/invoker/power/setup/distro/debian.rb +11 -0
- data/lib/invoker/power/setup/distro/mint.rb +10 -0
- data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
- data/lib/invoker/power/setup/distro/redhat.rb +11 -0
- data/lib/invoker/power/setup/distro/ubuntu.rb +10 -0
- data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
- data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
- data/lib/invoker/power/setup/linux_setup.rb +105 -0
- data/lib/invoker/power/setup/osx_setup.rb +137 -0
- data/lib/invoker/power/templates/400.html +40 -0
- data/lib/invoker/power/templates/404.html +40 -0
- data/lib/invoker/power/templates/503.html +40 -0
- data/lib/invoker/power/url_rewriter.rb +40 -0
- data/lib/invoker/process_manager.rb +198 -0
- data/lib/invoker/process_printer.rb +43 -0
- data/lib/invoker/reactor.rb +37 -0
- data/lib/invoker/reactor/reader.rb +54 -0
- data/lib/invoker/version.rb +47 -0
- data/readme.md +25 -0
- 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 +45 -0
- data/spec/invoker/commander_spec.rb +152 -0
- data/spec/invoker/config_spec.rb +361 -0
- data/spec/invoker/daemon_spec.rb +34 -0
- data/spec/invoker/event/manager_spec.rb +67 -0
- data/spec/invoker/invoker_spec.rb +71 -0
- data/spec/invoker/ipc/client_handler_spec.rb +54 -0
- data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
- data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
- data/spec/invoker/ipc/message_spec.rb +49 -0
- data/spec/invoker/ipc/unix_client_spec.rb +29 -0
- data/spec/invoker/power/balancer_spec.rb +22 -0
- data/spec/invoker/power/config_spec.rb +18 -0
- data/spec/invoker/power/http_parser_spec.rb +32 -0
- data/spec/invoker/power/http_response_spec.rb +34 -0
- data/spec/invoker/power/pf_migrate_spec.rb +87 -0
- data/spec/invoker/power/port_finder_spec.rb +16 -0
- data/spec/invoker/power/setup/linux_setup_spec.rb +103 -0
- data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
- data/spec/invoker/power/setup_spec.rb +4 -0
- data/spec/invoker/power/url_rewriter_spec.rb +70 -0
- data/spec/invoker/power/web_sockets_spec.rb +61 -0
- data/spec/invoker/process_manager_spec.rb +130 -0
- data/spec/invoker/reactor_spec.rb +6 -0
- data/spec/spec_helper.rb +43 -0
- metadata +389 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
module Power
|
|
3
|
+
class PortFinder
|
|
4
|
+
STARTING_PORT = 23400
|
|
5
|
+
attr_accessor :dns_port, :http_port, :starting_port, :https_port
|
|
6
|
+
def initialize
|
|
7
|
+
@starting_port = STARTING_PORT
|
|
8
|
+
@ports = []
|
|
9
|
+
@dns_port = nil
|
|
10
|
+
@http_port = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def find_ports
|
|
14
|
+
STARTING_PORT.upto(STARTING_PORT + 100) do |port|
|
|
15
|
+
break if @ports.size > 3
|
|
16
|
+
if check_if_port_is_open(port)
|
|
17
|
+
@ports << port
|
|
18
|
+
else
|
|
19
|
+
next
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
@dns_port = @ports[0]
|
|
23
|
+
@http_port = @ports[1]
|
|
24
|
+
@https_port = @ports[2]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def check_if_port_is_open(port)
|
|
30
|
+
socket_flag = true
|
|
31
|
+
sockets = nil
|
|
32
|
+
begin
|
|
33
|
+
sockets = Socket.tcp_server_sockets(port)
|
|
34
|
+
socket_flag = false if sockets.size <= 1
|
|
35
|
+
rescue Errno::EADDRINUSE
|
|
36
|
+
socket_flag = false
|
|
37
|
+
end
|
|
38
|
+
sockets && close_socket_pairs(sockets)
|
|
39
|
+
socket_flag
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def close_socket_pairs(sockets)
|
|
43
|
+
sockets.each { |s| s.close }
|
|
44
|
+
rescue
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
# power is really a stupid pun on pow.
|
|
3
|
+
module Power
|
|
4
|
+
class Powerup
|
|
5
|
+
def self.fork_and_start
|
|
6
|
+
powerup = new()
|
|
7
|
+
fork { powerup.run }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
require "invoker/power/power"
|
|
12
|
+
EM.epoll
|
|
13
|
+
EM.run {
|
|
14
|
+
trap("TERM") { stop }
|
|
15
|
+
trap("INT") { stop }
|
|
16
|
+
if Invoker.darwin?
|
|
17
|
+
DNS.new.run(listen: DNS.server_ports)
|
|
18
|
+
end
|
|
19
|
+
Balancer.run
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stop
|
|
24
|
+
Invoker::Logger.puts "Terminating Proxy/Server"
|
|
25
|
+
EventMachine.stop
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "eventmachine"
|
|
2
|
+
|
|
3
|
+
module Invoker
|
|
4
|
+
module Power
|
|
5
|
+
class Setup
|
|
6
|
+
attr_accessor :port_finder, :tld
|
|
7
|
+
|
|
8
|
+
def self.install(tld)
|
|
9
|
+
selected_installer_klass = installer_klass
|
|
10
|
+
selected_installer_klass.new(tld).install
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.uninstall
|
|
14
|
+
power_config = Invoker::Power::Config.load_config
|
|
15
|
+
selected_installer_klass = installer_klass
|
|
16
|
+
selected_installer_klass.new(power_config.tld).uninstall_invoker
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.installer_klass
|
|
20
|
+
if Invoker.darwin?
|
|
21
|
+
Invoker::Power::OsxSetup
|
|
22
|
+
else
|
|
23
|
+
Invoker::Power::LinuxSetup
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize(tld)
|
|
28
|
+
if tld !~ /^[a-z]+$/
|
|
29
|
+
Invoker::Logger.puts("Please specify valid tld".color(:red))
|
|
30
|
+
exit(1)
|
|
31
|
+
end
|
|
32
|
+
self.tld = tld
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def install
|
|
36
|
+
if check_if_setup_can_run?
|
|
37
|
+
setup_invoker
|
|
38
|
+
else
|
|
39
|
+
Invoker::Logger.puts("The setup has been already run.".color(:red))
|
|
40
|
+
end
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def drop_to_normal_user
|
|
45
|
+
EventMachine.set_effective_user(ENV["SUDO_USER"])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def find_open_ports
|
|
49
|
+
port_finder.find_ports()
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def port_finder
|
|
53
|
+
@port_finder ||= Invoker::Power::PortFinder.new()
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def check_if_setup_can_run?
|
|
57
|
+
!File.exists?(Invoker::Power::Config.config_file)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def create_config_file
|
|
61
|
+
Invoker.setup_config_location
|
|
62
|
+
config = build_power_config
|
|
63
|
+
Invoker::Power::Config.create(config)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Builds and returns power config hash. Override this method in subclasses if necessary.
|
|
67
|
+
def build_power_config
|
|
68
|
+
config = {
|
|
69
|
+
http_port: port_finder.http_port,
|
|
70
|
+
https_port: port_finder.https_port,
|
|
71
|
+
tld: tld
|
|
72
|
+
}
|
|
73
|
+
config
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def remove_resolver_file
|
|
77
|
+
begin
|
|
78
|
+
safe_remove_file(resolver_file)
|
|
79
|
+
rescue Errno::EACCES
|
|
80
|
+
Invoker::Logger.puts("Running uninstall requires root access, please rerun it with sudo".color(:red))
|
|
81
|
+
raise
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def safe_remove_file(file)
|
|
86
|
+
File.delete(file) if File.exists?(file)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
module Power
|
|
3
|
+
module Distro
|
|
4
|
+
class Arch < Base
|
|
5
|
+
def install_required_software
|
|
6
|
+
system("pacman -S --needed --noconfirm dnsmasq socat")
|
|
7
|
+
system("mkdir -p /etc/dnsmasq.d")
|
|
8
|
+
unless File.open("/etc/dnsmasq.conf").each_line.any? { |line| line.chomp == "conf-dir=/etc/dnsmasq.d" }
|
|
9
|
+
File.open("/etc/dnsmasq.conf", "a") {|f| f.write("conf-dir=/etc/dnsmasq.d") }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
module Power
|
|
3
|
+
module Distro
|
|
4
|
+
class Base
|
|
5
|
+
SOCAT_SHELLSCRIPT = "/usr/bin/invoker_forwarder.sh"
|
|
6
|
+
SOCAT_SYSTEMD = "/etc/systemd/system/socat_invoker.service"
|
|
7
|
+
RESOLVER_DIR = "/etc/dnsmasq.d"
|
|
8
|
+
attr_accessor :tld
|
|
9
|
+
|
|
10
|
+
def resolver_file
|
|
11
|
+
File.join(RESOLVER_DIR, "#{tld}-tld")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.distro_installer(tld)
|
|
15
|
+
case Facter[:operatingsystem].value
|
|
16
|
+
when "Ubuntu"
|
|
17
|
+
require "invoker/power/setup/distro/ubuntu"
|
|
18
|
+
Ubuntu.new(tld)
|
|
19
|
+
when "Fedora"
|
|
20
|
+
require "invoker/power/setup/distro/redhat"
|
|
21
|
+
Redhat.new(tld)
|
|
22
|
+
when "Archlinux"
|
|
23
|
+
require "invoker/power/setup/distro/arch"
|
|
24
|
+
Arch.new(tld)
|
|
25
|
+
when "Debian"
|
|
26
|
+
require "invoker/power/setup/distro/debian"
|
|
27
|
+
Debian.new(tld)
|
|
28
|
+
when "LinuxMint"
|
|
29
|
+
require "invoker/power/setup/distro/mint"
|
|
30
|
+
Mint.new(tld)
|
|
31
|
+
when "OpenSuSE"
|
|
32
|
+
require "invoker/power/setup/distro/opensuse"
|
|
33
|
+
Opensuse.new(tld)
|
|
34
|
+
else
|
|
35
|
+
raise "Your selected distro is not supported by Invoker"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(tld)
|
|
40
|
+
self.tld = tld
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Install required software
|
|
44
|
+
def install_required_software
|
|
45
|
+
raise "Unimplemented"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def restart_services
|
|
49
|
+
system("systemctl enable socat_invoker.service")
|
|
50
|
+
system("systemctl enable dnsmasq")
|
|
51
|
+
system("systemctl start socat_invoker.service")
|
|
52
|
+
system("systemctl restart dnsmasq")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
KillJobs() {
|
|
4
|
+
for job in $(jobs -p); do
|
|
5
|
+
kill -s SIGTERM $job > /dev/null 2>&1 || (sleep 10 && kill -9 $job > /dev/null 2>&1 &)
|
|
6
|
+
done
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# Whatever you need to clean here
|
|
10
|
+
trap KillJobs SIGINT SIGTERM EXIT
|
|
11
|
+
|
|
12
|
+
/usr/bin/socat TCP-LISTEN:80,reuseaddr,fork TCP:0.0.0.0:<%= http_port %>&
|
|
13
|
+
pid1=$!
|
|
14
|
+
/usr/bin/socat TCP-LISTEN:443,reuseaddr,fork TCP:0.0.0.0:<%= https_port %>&
|
|
15
|
+
pid2=$!
|
|
16
|
+
wait $pid1 $pid2
|
|
17
|
+
wait $pid1 $pid2
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "invoker/power/setup/distro/base"
|
|
2
|
+
require "facter"
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module Invoker
|
|
7
|
+
module Power
|
|
8
|
+
class LinuxSetup < Setup
|
|
9
|
+
attr_accessor :distro_installer
|
|
10
|
+
|
|
11
|
+
def setup_invoker
|
|
12
|
+
if get_user_confirmation?
|
|
13
|
+
initialize_distro_installer
|
|
14
|
+
find_open_ports
|
|
15
|
+
distro_installer.install_required_software
|
|
16
|
+
install_resolver
|
|
17
|
+
install_port_forwarder
|
|
18
|
+
distro_installer.restart_services
|
|
19
|
+
drop_to_normal_user
|
|
20
|
+
create_config_file
|
|
21
|
+
else
|
|
22
|
+
Invoker::Logger.puts("Invoker is not configured to serve from subdomains".color(:red))
|
|
23
|
+
end
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def uninstall_invoker
|
|
28
|
+
system("systemctl disable socat_invoker.service")
|
|
29
|
+
system("systemctl stop socat_invoker.service")
|
|
30
|
+
system("rm #{Invoker::Power::Distro::Base::SOCAT_SYSTEMD}")
|
|
31
|
+
system("rm #{Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT}")
|
|
32
|
+
initialize_distro_installer
|
|
33
|
+
remove_resolver_file
|
|
34
|
+
drop_to_normal_user
|
|
35
|
+
Invoker::Power::Config.delete
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def resolver_file
|
|
39
|
+
distro_installer.resolver_file
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def forwarder_script
|
|
43
|
+
File.join(File.dirname(__FILE__), "files/invoker_forwarder.sh.erb")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def socat_unit
|
|
47
|
+
File.join(File.dirname(__FILE__), "files/socat_invoker.service")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def initialize_distro_installer
|
|
53
|
+
# Create a new facter check for systemctl (in systemd)
|
|
54
|
+
Facter.add(:systemctl) do
|
|
55
|
+
setcode do
|
|
56
|
+
Facter::Util::Resolution.exec("[ -e /usr/bin/systemctl ] && echo 'true' || echo 'false'")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
@distro_installer = Invoker::Power::Distro::Base.distro_installer(tld)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def install_resolver
|
|
63
|
+
File.open(resolver_file, "w") do |fl|
|
|
64
|
+
fl.write(resolver_file_content)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def install_port_forwarder
|
|
69
|
+
install_forwarder_script(port_finder.http_port, port_finder.https_port)
|
|
70
|
+
install_systemd_unit
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def resolver_file_content
|
|
74
|
+
content =<<-EOD
|
|
75
|
+
local=/#{tld}/
|
|
76
|
+
address=/#{tld}/127.0.0.1
|
|
77
|
+
EOD
|
|
78
|
+
content
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def install_forwarder_script(http_port, https_port)
|
|
82
|
+
script_template = File.read(forwarder_script)
|
|
83
|
+
renderer = ERB.new(script_template)
|
|
84
|
+
script_output = renderer.result(binding)
|
|
85
|
+
File.open(Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT, "w") do |fl|
|
|
86
|
+
fl.write(script_output)
|
|
87
|
+
end
|
|
88
|
+
system("chmod +x #{Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def install_systemd_unit
|
|
92
|
+
FileUtils.cp(socat_unit, Invoker::Power::Distro::Base::SOCAT_SYSTEMD)
|
|
93
|
+
system("chmod 644 #{Invoker::Power::Distro::Base::SOCAT_SYSTEMD}")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def get_user_confirmation?
|
|
97
|
+
Invoker::Logger.puts("Invoker is going to install dnsmasq and socat on this machine."\
|
|
98
|
+
" It is also going to install a local resolver for .#{tld} domain and a socat service"\
|
|
99
|
+
" which will forward all local requests on port 80 and 443 to another port")
|
|
100
|
+
Invoker::Logger.puts("If you still want to proceed with installation, press y.")
|
|
101
|
+
Invoker::CLI::Question.agree("Proceed with installation (y/n) : ")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|