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.
- checksums.yaml +7 -0
- data/bin/invoker +7 -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/cli.rb +197 -0
- data/lib/invoker/command_worker.rb +64 -0
- data/lib/invoker/commander.rb +101 -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/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/list_response.rb +35 -0
- data/lib/invoker/ipc/message/tail_response.rb +10 -0
- data/lib/invoker/ipc/message.rb +170 -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/ipc.rb +45 -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 +133 -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/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/distro/arch.rb +15 -0
- data/lib/invoker/power/setup/distro/base.rb +80 -0
- data/lib/invoker/power/setup/distro/debian.rb +11 -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 +46 -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 +97 -0
- data/lib/invoker/power/setup/osx_setup.rb +137 -0
- data/lib/invoker/power/setup.rb +93 -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 +201 -0
- data/lib/invoker/process_printer.rb +59 -0
- data/lib/invoker/reactor/reader.rb +65 -0
- data/lib/invoker/reactor.rb +37 -0
- data/lib/invoker/version.rb +47 -0
- data/lib/invoker.rb +151 -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 +53 -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/port_finder_spec.rb +16 -0
- data/spec/invoker/power/setup/linux_setup_spec.rb +166 -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 +69 -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 +376 -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,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,80 @@
|
|
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
|
+
if distro.start_with? "Arch Linux", "Manjaro Linux"
|
16
|
+
require "invoker/power/setup/distro/arch"
|
17
|
+
Arch.new(tld)
|
18
|
+
elsif distro.start_with? "Debian"
|
19
|
+
require "invoker/power/setup/distro/debian"
|
20
|
+
Debian.new(tld)
|
21
|
+
elsif distro.start_with? "Fedora"
|
22
|
+
require "invoker/power/setup/distro/redhat"
|
23
|
+
Redhat.new(tld)
|
24
|
+
elsif distro.start_with? "Linux Mint", "Ubuntu"
|
25
|
+
require "invoker/power/setup/distro/ubuntu"
|
26
|
+
Ubuntu.new(tld)
|
27
|
+
elsif distro.start_with? "openSUSE"
|
28
|
+
require "invoker/power/setup/distro/opensuse"
|
29
|
+
Opensuse.new(tld)
|
30
|
+
else
|
31
|
+
raise "Your selected distro is not supported by Invoker"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.distro
|
36
|
+
@distro ||= if File.exist?('/etc/os-release')
|
37
|
+
File.read('/etc/os-release').each_line do |line|
|
38
|
+
parsed_line = line.chomp.tr('"', '').split('=')
|
39
|
+
break parsed_line[1] if parsed_line[0] == 'NAME'
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise "File /etc/os-release doesn't exist or not Linux"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(tld)
|
47
|
+
self.tld = tld
|
48
|
+
end
|
49
|
+
|
50
|
+
# Install required software
|
51
|
+
def install_required_software
|
52
|
+
raise "Unimplemented"
|
53
|
+
end
|
54
|
+
|
55
|
+
def restart_services
|
56
|
+
system("systemctl enable socat_invoker.service")
|
57
|
+
system("systemctl enable dnsmasq")
|
58
|
+
system("systemctl start socat_invoker.service")
|
59
|
+
system("systemctl restart dnsmasq")
|
60
|
+
end
|
61
|
+
|
62
|
+
def install_packages
|
63
|
+
"dnsmasq and socat"
|
64
|
+
end
|
65
|
+
|
66
|
+
def install_other
|
67
|
+
" a local resolver for .#{tld} domain and"
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_user_confirmation?
|
71
|
+
Invoker::Logger.puts("Invoker is going to install #{install_packages} on this machine."\
|
72
|
+
" It is also going to install#{install_other} a socat service"\
|
73
|
+
" which will forward all local requests on port 80 and 443 to another port")
|
74
|
+
Invoker::Logger.puts("If you still want to proceed with installation, press y.")
|
75
|
+
Invoker::CLI::Question.agree("Proceed with installation (y/n) : ")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "invoker/power/setup/distro/debian"
|
2
|
+
|
3
|
+
module Invoker
|
4
|
+
module Power
|
5
|
+
module Distro
|
6
|
+
class Ubuntu < Debian
|
7
|
+
def using_systemd_resolved?
|
8
|
+
return @_using_systemd_resolved if defined?(@_using_systemd_resolved)
|
9
|
+
@_using_systemd_resolved = system("systemctl is-active --quiet systemd-resolved")
|
10
|
+
end
|
11
|
+
|
12
|
+
def install_required_software
|
13
|
+
if using_systemd_resolved?
|
14
|
+
# Don't install dnsmasq if Ubuntu version uses systemd-resolved for DNS because they conflict
|
15
|
+
system("apt-get --assume-yes install socat")
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def install_packages
|
22
|
+
using_systemd_resolved? ? "socat" : super
|
23
|
+
end
|
24
|
+
|
25
|
+
def install_other
|
26
|
+
using_systemd_resolved? ? nil : super
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolver_file
|
30
|
+
using_systemd_resolved? ? nil : super
|
31
|
+
end
|
32
|
+
|
33
|
+
def tld
|
34
|
+
using_systemd_resolved? ? 'localhost' : @tld
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_user_confirmation?
|
38
|
+
if using_systemd_resolved? && tld != 'localhost'
|
39
|
+
Invoker::Logger.puts("Ubuntu installations using systemd-resolved (typically Ubuntu 17+) only support the .localhost domain, so your tld setting (or the default) will be ignored.".colorize(:yellow))
|
40
|
+
end
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
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,97 @@
|
|
1
|
+
require "invoker/power/setup/distro/base"
|
2
|
+
require 'erb'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Invoker
|
6
|
+
module Power
|
7
|
+
class LinuxSetup < Setup
|
8
|
+
attr_accessor :distro_installer
|
9
|
+
|
10
|
+
def setup_invoker
|
11
|
+
initialize_distro_installer
|
12
|
+
if distro_installer.get_user_confirmation?
|
13
|
+
find_open_ports
|
14
|
+
distro_installer.install_required_software
|
15
|
+
install_resolver
|
16
|
+
install_port_forwarder
|
17
|
+
distro_installer.restart_services
|
18
|
+
drop_to_normal_user
|
19
|
+
create_config_file
|
20
|
+
else
|
21
|
+
Invoker::Logger.puts("Invoker is not configured to serve from subdomains".colorize(:red))
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def uninstall_invoker
|
27
|
+
system("systemctl disable socat_invoker.service")
|
28
|
+
system("systemctl stop socat_invoker.service")
|
29
|
+
system("rm #{Invoker::Power::Distro::Base::SOCAT_SYSTEMD}")
|
30
|
+
system("rm #{Invoker::Power::Distro::Base::SOCAT_SHELLSCRIPT}")
|
31
|
+
initialize_distro_installer
|
32
|
+
remove_resolver_file
|
33
|
+
drop_to_normal_user
|
34
|
+
Invoker::Power::Config.delete
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_power_config
|
38
|
+
config = super
|
39
|
+
config[:tld] = distro_installer.tld
|
40
|
+
config
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolver_file
|
44
|
+
distro_installer.resolver_file
|
45
|
+
end
|
46
|
+
|
47
|
+
def forwarder_script
|
48
|
+
File.join(File.dirname(__FILE__), "files/invoker_forwarder.sh.erb")
|
49
|
+
end
|
50
|
+
|
51
|
+
def socat_unit
|
52
|
+
File.join(File.dirname(__FILE__), "files/socat_invoker.service")
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def initialize_distro_installer
|
58
|
+
@distro_installer ||= Invoker::Power::Distro::Base.distro_installer(tld)
|
59
|
+
end
|
60
|
+
|
61
|
+
def install_resolver
|
62
|
+
return if resolver_file.nil?
|
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
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Invoker
|
2
|
+
module Power
|
3
|
+
class OsxSetup < Setup
|
4
|
+
FIREWALL_PLIST_FILE = "/Library/LaunchDaemons/com.codemancers.invoker.firewall.plist"
|
5
|
+
RESOLVER_DIR = "/etc/resolver"
|
6
|
+
|
7
|
+
def resolver_file
|
8
|
+
File.join(RESOLVER_DIR, tld)
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup_invoker
|
12
|
+
if setup_resolver_file
|
13
|
+
find_open_ports
|
14
|
+
install_resolver(port_finder.dns_port)
|
15
|
+
install_firewall(port_finder.http_port, port_finder.https_port)
|
16
|
+
# Before writing the config file, drop down to a normal user
|
17
|
+
drop_to_normal_user
|
18
|
+
create_config_file
|
19
|
+
else
|
20
|
+
Invoker::Logger.puts("Invoker is not configured to serve from subdomains".colorize(:red))
|
21
|
+
end
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def uninstall_invoker
|
26
|
+
uninstall_invoker_flag = Invoker::CLI::Question.agree("Are you sure you want to uninstall firewall rules created by setup (y/n) : ")
|
27
|
+
|
28
|
+
if uninstall_invoker_flag
|
29
|
+
remove_resolver_file
|
30
|
+
unload_firewall_rule(true)
|
31
|
+
Invoker::Power::Config.delete
|
32
|
+
Invoker::Logger.puts("Firewall rules were removed")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_power_config
|
37
|
+
config = super
|
38
|
+
config[:dns_port] = port_finder.dns_port
|
39
|
+
config
|
40
|
+
end
|
41
|
+
|
42
|
+
def install_resolver(dns_port)
|
43
|
+
open_resolver_for_write { |fl| fl.write(resolve_string(dns_port)) }
|
44
|
+
rescue Errno::EACCES
|
45
|
+
Invoker::Logger.puts("Running setup requires root access, please rerun it with sudo".colorize(:red))
|
46
|
+
raise
|
47
|
+
end
|
48
|
+
|
49
|
+
def install_firewall(http_port, https_port)
|
50
|
+
File.open(FIREWALL_PLIST_FILE, "w") { |fl|
|
51
|
+
fl.write(plist_string(http_port, https_port))
|
52
|
+
}
|
53
|
+
unload_firewall_rule
|
54
|
+
load_firewall_rule
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_firewall_rule
|
58
|
+
system("launchctl load -Fw #{FIREWALL_PLIST_FILE} 2>/dev/null")
|
59
|
+
end
|
60
|
+
|
61
|
+
def unload_firewall_rule(remove = false)
|
62
|
+
system("pfctl -a com.apple/250.InvokerFirewall -F nat 2>/dev/null")
|
63
|
+
system("launchctl unload -w #{FIREWALL_PLIST_FILE} 2>/dev/null")
|
64
|
+
system("rm -rf #{FIREWALL_PLIST_FILE}") if remove
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ripped from POW code
|
68
|
+
def plist_string(http_port, https_port)
|
69
|
+
plist =<<-EOD
|
70
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
71
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
72
|
+
<plist version="1.0">
|
73
|
+
<dict>
|
74
|
+
<key>Label</key>
|
75
|
+
<string>com.codemancers.invoker</string>
|
76
|
+
<key>ProgramArguments</key>
|
77
|
+
<array>
|
78
|
+
<string>sh</string>
|
79
|
+
<string>-c</string>
|
80
|
+
<string>#{firewall_command(http_port, https_port)}</string>
|
81
|
+
</array>
|
82
|
+
<key>RunAtLoad</key>
|
83
|
+
<true/>
|
84
|
+
<key>UserName</key>
|
85
|
+
<string>root</string>
|
86
|
+
</dict>
|
87
|
+
</plist>
|
88
|
+
EOD
|
89
|
+
plist
|
90
|
+
end
|
91
|
+
|
92
|
+
def resolve_string(dns_port)
|
93
|
+
string =<<-EOD
|
94
|
+
nameserver 127.0.0.1
|
95
|
+
port #{dns_port}
|
96
|
+
EOD
|
97
|
+
string
|
98
|
+
end
|
99
|
+
|
100
|
+
# Ripped from Pow code
|
101
|
+
def firewall_command(http_port, https_port)
|
102
|
+
rules = [
|
103
|
+
"rdr pass on lo0 inet proto tcp from any to any port 80 -> 127.0.0.1 port #{http_port}",
|
104
|
+
"rdr pass on lo0 inet proto tcp from any to any port 443 -> 127.0.0.1 port #{https_port}"
|
105
|
+
].join("\n")
|
106
|
+
"echo \"#{rules}\" | pfctl -a 'com.apple/250.InvokerFirewall' -f - -E"
|
107
|
+
end
|
108
|
+
|
109
|
+
def setup_resolver_file
|
110
|
+
return true unless File.exist?(resolver_file)
|
111
|
+
|
112
|
+
Invoker::Logger.puts "Invoker has detected an existing Pow installation. We recommend "\
|
113
|
+
"that you uninstall pow and rerun this setup.".colorize(:red)
|
114
|
+
Invoker::Logger.puts "If you have already uninstalled Pow, proceed with installation"\
|
115
|
+
" by pressing y/n."
|
116
|
+
replace_resolver_flag = Invoker::CLI::Question.agree("Replace Pow configuration (y/n) : ")
|
117
|
+
|
118
|
+
if replace_resolver_flag
|
119
|
+
Invoker::Logger.puts "Invoker has overwritten one or more files created by Pow. "\
|
120
|
+
"If .#{tld} domains still don't resolve locally, try turning off the wi-fi"\
|
121
|
+
" and turning it on. It'll force OS X to reload network configuration".colorize(:green)
|
122
|
+
end
|
123
|
+
replace_resolver_flag
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def open_resolver_for_write
|
129
|
+
FileUtils.mkdir(RESOLVER_DIR) unless Dir.exist?(RESOLVER_DIR)
|
130
|
+
fl = File.open(resolver_file, "w")
|
131
|
+
yield fl
|
132
|
+
ensure
|
133
|
+
fl && fl.close
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,93 @@
|
|
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
|
+
if Invoker::Power::Config.has_config?
|
15
|
+
power_config = Invoker::Power::Config.load_config
|
16
|
+
selected_installer_klass = installer_klass
|
17
|
+
selected_installer_klass.new(power_config.tld).uninstall_invoker
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.installer_klass
|
22
|
+
if Invoker.darwin?
|
23
|
+
Invoker::Power::OsxSetup
|
24
|
+
else
|
25
|
+
Invoker::Power::LinuxSetup
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(tld)
|
30
|
+
if tld !~ /^[a-z]+$/
|
31
|
+
Invoker::Logger.puts("Please specify valid tld".colorize(:red))
|
32
|
+
exit(1)
|
33
|
+
end
|
34
|
+
self.tld = tld
|
35
|
+
end
|
36
|
+
|
37
|
+
def install
|
38
|
+
if check_if_setup_can_run?
|
39
|
+
setup_invoker
|
40
|
+
else
|
41
|
+
Invoker::Logger.puts("The setup has been already run.".colorize(:red))
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def drop_to_normal_user
|
47
|
+
EventMachine.set_effective_user(ENV["SUDO_USER"])
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_open_ports
|
51
|
+
port_finder.find_ports()
|
52
|
+
end
|
53
|
+
|
54
|
+
def port_finder
|
55
|
+
@port_finder ||= Invoker::Power::PortFinder.new()
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_if_setup_can_run?
|
59
|
+
!File.exist?(Invoker::Power::Config.config_file)
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_config_file
|
63
|
+
Invoker.setup_config_location
|
64
|
+
config = build_power_config
|
65
|
+
Invoker::Power::Config.create(config)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Builds and returns power config hash. Override this method in subclasses if necessary.
|
69
|
+
def build_power_config
|
70
|
+
config = {
|
71
|
+
http_port: port_finder.http_port,
|
72
|
+
https_port: port_finder.https_port,
|
73
|
+
tld: tld
|
74
|
+
}
|
75
|
+
config
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_resolver_file
|
79
|
+
return if resolver_file.nil?
|
80
|
+
begin
|
81
|
+
safe_remove_file(resolver_file)
|
82
|
+
rescue Errno::EACCES
|
83
|
+
Invoker::Logger.puts("Running uninstall requires root access, please rerun it with sudo".colorize(:red))
|
84
|
+
raise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def safe_remove_file(file)
|
89
|
+
File.delete(file) if File.exist?(file)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -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>Bad request</h1>
|
36
|
+
<hr>
|
37
|
+
<h2>Invoker couldn't understand the request</h2>
|
38
|
+
</div>
|
39
|
+
</body>
|
40
|
+
</html>
|