meepo 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +10 -0
  7. data/Dockerfile +7 -0
  8. data/Gemfile +13 -0
  9. data/MIT-LICENSE +20 -0
  10. data/Rakefile +15 -0
  11. data/TODO +5 -0
  12. data/bin/invoker +7 -0
  13. data/contrib/completion/invoker-completion.bash +70 -0
  14. data/contrib/completion/invoker-completion.zsh +62 -0
  15. data/examples/hello_sinatra.rb +26 -0
  16. data/examples/sample.ini +3 -0
  17. data/invoker.gemspec +43 -0
  18. data/lib/invoker.rb +152 -0
  19. data/lib/invoker/cli.rb +159 -0
  20. data/lib/invoker/cli/pinger.rb +23 -0
  21. data/lib/invoker/cli/question.rb +15 -0
  22. data/lib/invoker/cli/tail.rb +34 -0
  23. data/lib/invoker/cli/tail_watcher.rb +34 -0
  24. data/lib/invoker/command_worker.rb +60 -0
  25. data/lib/invoker/commander.rb +95 -0
  26. data/lib/invoker/daemon.rb +126 -0
  27. data/lib/invoker/dns_cache.rb +23 -0
  28. data/lib/invoker/errors.rb +17 -0
  29. data/lib/invoker/event/manager.rb +79 -0
  30. data/lib/invoker/ipc.rb +45 -0
  31. data/lib/invoker/ipc/add_command.rb +12 -0
  32. data/lib/invoker/ipc/add_http_command.rb +10 -0
  33. data/lib/invoker/ipc/base_command.rb +24 -0
  34. data/lib/invoker/ipc/client_handler.rb +26 -0
  35. data/lib/invoker/ipc/dns_check_command.rb +17 -0
  36. data/lib/invoker/ipc/list_command.rb +11 -0
  37. data/lib/invoker/ipc/message.rb +170 -0
  38. data/lib/invoker/ipc/message/list_response.rb +35 -0
  39. data/lib/invoker/ipc/message/tail_response.rb +10 -0
  40. data/lib/invoker/ipc/ping_command.rb +10 -0
  41. data/lib/invoker/ipc/reload_command.rb +12 -0
  42. data/lib/invoker/ipc/remove_command.rb +12 -0
  43. data/lib/invoker/ipc/server.rb +26 -0
  44. data/lib/invoker/ipc/tail_command.rb +11 -0
  45. data/lib/invoker/ipc/unix_client.rb +60 -0
  46. data/lib/invoker/logger.rb +13 -0
  47. data/lib/invoker/parsers/config.rb +184 -0
  48. data/lib/invoker/parsers/procfile.rb +86 -0
  49. data/lib/invoker/power/balancer.rb +131 -0
  50. data/lib/invoker/power/config.rb +77 -0
  51. data/lib/invoker/power/dns.rb +38 -0
  52. data/lib/invoker/power/http_parser.rb +68 -0
  53. data/lib/invoker/power/http_response.rb +81 -0
  54. data/lib/invoker/power/pf_migrate.rb +64 -0
  55. data/lib/invoker/power/port_finder.rb +49 -0
  56. data/lib/invoker/power/power.rb +3 -0
  57. data/lib/invoker/power/powerup.rb +29 -0
  58. data/lib/invoker/power/setup.rb +90 -0
  59. data/lib/invoker/power/setup/distro/arch.rb +15 -0
  60. data/lib/invoker/power/setup/distro/base.rb +57 -0
  61. data/lib/invoker/power/setup/distro/debian.rb +11 -0
  62. data/lib/invoker/power/setup/distro/mint.rb +10 -0
  63. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  64. data/lib/invoker/power/setup/distro/redhat.rb +11 -0
  65. data/lib/invoker/power/setup/distro/ubuntu.rb +10 -0
  66. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  67. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  68. data/lib/invoker/power/setup/linux_setup.rb +105 -0
  69. data/lib/invoker/power/setup/osx_setup.rb +137 -0
  70. data/lib/invoker/power/templates/400.html +40 -0
  71. data/lib/invoker/power/templates/404.html +40 -0
  72. data/lib/invoker/power/templates/503.html +40 -0
  73. data/lib/invoker/power/url_rewriter.rb +40 -0
  74. data/lib/invoker/process_manager.rb +198 -0
  75. data/lib/invoker/process_printer.rb +43 -0
  76. data/lib/invoker/reactor.rb +37 -0
  77. data/lib/invoker/reactor/reader.rb +54 -0
  78. data/lib/invoker/version.rb +47 -0
  79. data/readme.md +25 -0
  80. data/spec/invoker/cli/pinger_spec.rb +22 -0
  81. data/spec/invoker/cli/tail_watcher_spec.rb +39 -0
  82. data/spec/invoker/cli_spec.rb +27 -0
  83. data/spec/invoker/command_worker_spec.rb +45 -0
  84. data/spec/invoker/commander_spec.rb +152 -0
  85. data/spec/invoker/config_spec.rb +361 -0
  86. data/spec/invoker/daemon_spec.rb +34 -0
  87. data/spec/invoker/event/manager_spec.rb +67 -0
  88. data/spec/invoker/invoker_spec.rb +71 -0
  89. data/spec/invoker/ipc/client_handler_spec.rb +54 -0
  90. data/spec/invoker/ipc/dns_check_command_spec.rb +32 -0
  91. data/spec/invoker/ipc/message/list_response_spec.rb +24 -0
  92. data/spec/invoker/ipc/message_spec.rb +49 -0
  93. data/spec/invoker/ipc/unix_client_spec.rb +29 -0
  94. data/spec/invoker/power/balancer_spec.rb +22 -0
  95. data/spec/invoker/power/config_spec.rb +18 -0
  96. data/spec/invoker/power/http_parser_spec.rb +32 -0
  97. data/spec/invoker/power/http_response_spec.rb +34 -0
  98. data/spec/invoker/power/pf_migrate_spec.rb +87 -0
  99. data/spec/invoker/power/port_finder_spec.rb +16 -0
  100. data/spec/invoker/power/setup/linux_setup_spec.rb +103 -0
  101. data/spec/invoker/power/setup/osx_setup_spec.rb +105 -0
  102. data/spec/invoker/power/setup_spec.rb +4 -0
  103. data/spec/invoker/power/url_rewriter_spec.rb +70 -0
  104. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  105. data/spec/invoker/process_manager_spec.rb +130 -0
  106. data/spec/invoker/reactor_spec.rb +6 -0
  107. data/spec/spec_helper.rb +43 -0
  108. 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,3 @@
1
+ require "invoker/power/http_response"
2
+ require "invoker/power/dns"
3
+ require "invoker/power/balancer"
@@ -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,11 @@
1
+ module Invoker
2
+ module Power
3
+ module Distro
4
+ class Debian < Base
5
+ def install_required_software
6
+ system("apt-get --assume-yes install dnsmasq socat")
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require "invoker/power/setup/distro/ubuntu"
2
+
3
+ module Invoker
4
+ module Power
5
+ module Distro
6
+ class Mint < Ubuntu
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Invoker
2
+ module Power
3
+ module Distro
4
+ class Opensuse < Base
5
+ def install_required_software
6
+ system("zypper install -l dnsmasq socat")
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Invoker
2
+ module Power
3
+ module Distro
4
+ class Redhat < Base
5
+ def install_required_software
6
+ system("yum --assumeyes install dnsmasq socat")
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require "invoker/power/setup/distro/debian"
2
+
3
+ module Invoker
4
+ module Power
5
+ module Distro
6
+ class Ubuntu < Debian
7
+ end
8
+ end
9
+ end
10
+ 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,12 @@
1
+ [Unit]
2
+ Description=Socat port forwarding service
3
+ After=network.target
4
+ Documentation=man:socat(1)
5
+
6
+ [Service]
7
+ ExecStart=/usr/bin/invoker_forwarder.sh
8
+ Restart=on-success
9
+
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
@@ -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