invoker 1.1.0 → 1.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17e01fb0ade988c21a62f385d51e3b07e58f9016
4
- data.tar.gz: 2e4e0c36f2df111493b7c05dea7e0ae99244de2c
3
+ metadata.gz: 82fe57088b14eea68ff54c85fd7cb0d95ab005d2
4
+ data.tar.gz: 37b082192e6af1f57544055d9a3c65761b53dbfc
5
5
  SHA512:
6
- metadata.gz: a7601b89cd0db7b1cc0e780885d14f27ec652739702b5c2a59cf961b677db347bfd9e764ada4a53057de80a418ca3d486949c1a6909ee414505a8b5323593708
7
- data.tar.gz: 552b15ffb14c384d02f3ec972ccd8f3a2191afedab5bfa899f19c9fb1ecf0e4df86c65cdbfa475df8babfc746401bc6d914bcb26f0abda2f6fd04283dab092c3
6
+ metadata.gz: 9840525fee76d6639a1a138d3fa4a0b40f4a9f197acf73a47a79c02cc01a67c523bb21559457bd0ab32cbf9f604fb557a69e95c610d3c60b90d2bac09d8114ea
7
+ data.tar.gz: 75622356bdde370032362506609019947b439d0cfcb16ba70de758b4ada5797668f8abf1552afa9f37ecf6dec465e281d2b0fe54dc6f52d65f3c595db96b969c
data/.gitignore CHANGED
@@ -3,8 +3,7 @@ config/
3
3
  *.gem
4
4
  Gemfile.lock
5
5
  pkg/
6
- local.ini
7
- multi.ini
6
+ *.ini
8
7
  tags
9
8
  .rvmrc
10
9
  vendor/
@@ -13,3 +12,4 @@ _site
13
12
  coverage
14
13
  invoker_profile/
15
14
  *.pid
15
+ .ruby-version
@@ -18,6 +18,8 @@ require "invoker/ipc"
18
18
  require "invoker/power/config"
19
19
  require "invoker/power/port_finder"
20
20
  require "invoker/power/setup"
21
+ require "invoker/power/setup/linux_setup"
22
+ require "invoker/power/setup/osx_setup"
21
23
  require "invoker/power/powerup"
22
24
  require "invoker/errors"
23
25
  require "invoker/parsers/procfile"
@@ -62,7 +64,6 @@ module Invoker
62
64
  end
63
65
 
64
66
  def can_run_balancer?(throw_warning = true)
65
- return false unless darwin?
66
67
  return true if File.exist?(Invoker::Power::Config::CONFIG_LOCATION)
67
68
 
68
69
  if throw_warning
@@ -23,6 +23,10 @@ module Invoker
23
23
  power_config && power_config.dns_port
24
24
  end
25
25
 
26
+ def https_port
27
+ power_config && power_config.https_port
28
+ end
29
+
26
30
  def process(label)
27
31
  processes.detect { |pconfig| pconfig.label == label }
28
32
  end
@@ -3,7 +3,7 @@ require 'http-parser'
3
3
 
4
4
  module Invoker
5
5
  module Power
6
- class BalancerConnection < EventMachine::ProxyServer::Connection
6
+ class InvokerHttpProxy < EventMachine::ProxyServer::Connection
7
7
  attr_accessor :host, :ip, :port
8
8
  def set_host(host, selected_backend)
9
9
  self.host = host
@@ -12,6 +12,13 @@ module Invoker
12
12
  end
13
13
  end
14
14
 
15
+ class InvokerHttpsProxy < InvokerHttpProxy
16
+ def post_init
17
+ super
18
+ start_tls
19
+ end
20
+ end
21
+
15
22
  class BalancerParser
16
23
  attr_accessor :host, :parser
17
24
  def initialize
@@ -44,27 +51,44 @@ module Invoker
44
51
  end
45
52
 
46
53
  class Balancer
47
- attr_accessor :connection, :http_parser, :session
54
+ attr_accessor :connection, :http_parser, :session, :protocol
48
55
  DEV_MATCH_REGEX = /([\w-]+)\.dev(\:\d+)?$/
49
56
 
50
57
  def self.run(options = {})
51
- EventMachine.start_server('0.0.0.0', Invoker.config.http_port,
52
- BalancerConnection, options) do |connection|
53
- balancer = Balancer.new(connection)
58
+ start_http_proxy(InvokerHttpProxy, 'http', options)
59
+ start_http_proxy(InvokerHttpsProxy, 'https', options)
60
+ end
61
+
62
+ def self.start_http_proxy(proxy_class, protocol, options)
63
+ port = protocol == 'http' ? Invoker.config.http_port : Invoker.config.https_port
64
+ EventMachine.start_server('0.0.0.0', port,
65
+ proxy_class, options) do |connection|
66
+ balancer = Balancer.new(connection, protocol)
54
67
  balancer.install_callbacks
55
68
  end
56
69
  end
57
70
 
58
- def initialize(connection)
71
+ def initialize(connection, protocol)
59
72
  @connection = connection
73
+ @protocol = protocol
60
74
  @http_parser = BalancerParser.new()
61
75
  @session = nil
62
76
  @buffer = []
63
77
  end
64
78
 
79
+ # insert X_FORWARDED_PROTO_ so as rails can identify the request as coming from
80
+ # https
81
+ def insert_forwarded_proto_header(data)
82
+ if data =~ /\r\n\r\n/ && data !~ /X_FORWARDED_PROTO/i && protocol == 'https'
83
+ data.gsub(/\r\n\r\n/, "\r\nX_FORWARDED_PROTO: #{protocol}\r\n\r\n")
84
+ else
85
+ data
86
+ end
87
+ end
88
+
65
89
  def install_callbacks
66
90
  http_parser.on_headers_complete { |header| headers_received(header) }
67
- connection.on_data {|data| upstream_data(data) }
91
+ connection.on_data { |data| upstream_data(data) }
68
92
  connection.on_response { |backend, data| backend_data(backend, data) }
69
93
  connection.on_finish { |backend, name| frontend_disconnect(backend, name) }
70
94
  end
@@ -74,7 +98,7 @@ module Invoker
74
98
  dns_check_response = select_backend_config(header['Host'])
75
99
  if dns_check_response && dns_check_response.port
76
100
  connection.server(session, host: '0.0.0.0', port: dns_check_response.port)
77
- connection.relay_to_servers(@buffer.join)
101
+ connection.relay_to_servers(insert_forwarded_proto_header(@buffer.join))
78
102
  @buffer = []
79
103
  else
80
104
  return_error_page(404)
@@ -88,7 +112,7 @@ module Invoker
88
112
  append_for_http_parsing(data)
89
113
  nil
90
114
  else
91
- data
115
+ insert_forwarded_proto_header(data)
92
116
  end
93
117
  end
94
118
 
@@ -107,7 +131,7 @@ module Invoker
107
131
  def frontend_disconnect(backend, name)
108
132
  http_parser.reset
109
133
  unless @backend_data
110
- Invoker::Logger.puts("\nApplication not running. Returning error page.".color(:red))
134
+ Invoker::Logger.puts("\nApplication #{name} not running. Returning error page.".color(:red))
111
135
  return_error_page(503)
112
136
  end
113
137
  @backend_data = false
@@ -43,6 +43,10 @@ module Invoker
43
43
  @config[:http_port] = http_port
44
44
  end
45
45
 
46
+ def https_port=(https_port)
47
+ @config[:https_port] = https_port
48
+ end
49
+
46
50
  def ipfw_rule_number=(ipfw_rule_number)
47
51
  @config[:ipfw_rule_number] = ipfw_rule_number
48
52
  end
@@ -51,6 +55,10 @@ module Invoker
51
55
  def http_port; @config[:http_port]; end
52
56
  def ipfw_rule_number; @config[:ipfw_rule_number]; end
53
57
 
58
+ def https_port
59
+ @config[:https_port]
60
+ end
61
+
54
62
  def save
55
63
  File.open(CONFIG_LOCATION, "w") do |fl|
56
64
  YAML.dump(@config, fl)
@@ -2,7 +2,7 @@ module Invoker
2
2
  module Power
3
3
  class PortFinder
4
4
  STARTING_PORT = 23400
5
- attr_accessor :dns_port, :http_port, :starting_port
5
+ attr_accessor :dns_port, :http_port, :starting_port, :https_port
6
6
  def initialize
7
7
  @starting_port = STARTING_PORT
8
8
  @ports = []
@@ -12,7 +12,7 @@ module Invoker
12
12
 
13
13
  def find_ports
14
14
  STARTING_PORT.upto(STARTING_PORT + 100) do |port|
15
- break if @ports.size > 2
15
+ break if @ports.size > 3
16
16
  if check_if_port_is_open(port)
17
17
  @ports << port
18
18
  else
@@ -21,9 +21,11 @@ module Invoker
21
21
  end
22
22
  @dns_port = @ports[0]
23
23
  @http_port = @ports[1]
24
+ @https_port = @ports[2]
24
25
  end
25
26
 
26
27
  private
28
+
27
29
  def check_if_port_is_open(port)
28
30
  socket_flag = true
29
31
  sockets = nil
@@ -42,8 +44,6 @@ module Invoker
42
44
  rescue
43
45
  nil
44
46
  end
45
-
46
-
47
47
  end
48
48
  end
49
49
  end
@@ -13,7 +13,9 @@ module Invoker
13
13
  EM.run {
14
14
  trap("TERM") { stop }
15
15
  trap("INT") { stop }
16
- DNS.new.run(listen: DNS.server_ports)
16
+ if Invoker.darwin?
17
+ DNS.new.run(listen: DNS.server_ports)
18
+ end
17
19
  Balancer.run
18
20
  }
19
21
  end
@@ -3,72 +3,38 @@ require "eventmachine"
3
3
  module Invoker
4
4
  module Power
5
5
  class Setup
6
- RESOLVER_FILE = "/etc/resolver/dev"
7
- RESOLVER_DIR = "/etc/resolver"
8
-
9
- FIREWALL_PLIST_FILE = "/Library/LaunchDaemons/com.codemancers.invoker.firewall.plist"
6
+ attr_accessor :port_finder
10
7
  def self.install
11
- installer = new
12
- if Invoker.darwin?
13
- if installer.check_if_setup_can_run?
14
- installer.setup_invoker
15
- else
16
- Invoker::Logger.puts("The setup has been already run.".color(:red))
17
- end
18
- else
19
- Invoker::Logger.puts("Domain feature is currently not supported on systems other than OSX".color(:red))
20
- end
21
- installer
8
+ selected_installer_klass = installer_klass
9
+ selected_installer_klass.new.install
22
10
  end
23
11
 
24
12
  def self.uninstall
25
- installer = new
26
- installer.uninstall_invoker
13
+ selected_installer_klass = installer_klass
14
+ selected_installer_klass.new.uninstall_invoker
27
15
  end
28
16
 
29
- def setup_invoker
30
- if setup_resolver_file
31
- find_open_ports
32
- install_resolver(port_finder.dns_port)
33
- install_firewall(port_finder.http_port)
34
- flush_dns_rules()
35
- # Before writing the config file, drop down to a normal user
36
- drop_to_normal_user()
37
- create_config_file()
17
+ def self.installer_klass
18
+ if Invoker.darwin?
19
+ Invoker::Power::OsxSetup
38
20
  else
39
- Invoker::Logger.puts("Invoker is not configured to serve from subdomains".color(:red))
21
+ Invoker::Power::LinuxSetup
40
22
  end
41
- self
42
23
  end
43
24
 
44
- def uninstall_invoker
45
- uninstall_invoker_flag = Invoker::CLI::Question.agree("Are you sure you want to uninstall firewall rules created by setup (y/n) : ")
46
-
47
- if uninstall_invoker_flag
48
- remove_resolver_file
49
- unload_firewall_rule(true)
50
- flush_dns_rules
51
- Invoker::Power::Config.delete
52
- Invoker::Logger.puts("Firewall rules were removed")
25
+ def install
26
+ if check_if_setup_can_run?
27
+ setup_invoker
28
+ else
29
+ Invoker::Logger.puts("The setup has been already run.".color(:red))
53
30
  end
31
+ self
54
32
  end
55
33
 
56
34
  def drop_to_normal_user
57
35
  EventMachine.set_effective_user(ENV["SUDO_USER"])
58
36
  end
59
37
 
60
- def flush_dns_rules
61
- system("dscacheutil -flushcache")
62
- end
63
-
64
- def create_config_file
65
- Invoker.setup_config_location
66
- Invoker::Power::Config.create(
67
- dns_port: port_finder.dns_port,
68
- http_port: port_finder.http_port
69
- )
70
- end
71
-
72
38
  def find_open_ports
73
39
  port_finder.find_ports()
74
40
  end
@@ -77,112 +43,9 @@ module Invoker
77
43
  @port_finder ||= Invoker::Power::PortFinder.new()
78
44
  end
79
45
 
80
- def install_resolver(dns_port)
81
- open_resolver_for_write { |fl|
82
- fl.write(resolve_string(dns_port))
83
- }
84
- rescue Errno::EACCES
85
- Invoker::Logger.puts("Running setup requires root access, please rerun it with sudo".color(:red))
86
- raise
87
- end
88
-
89
- def remove_resolver_file
90
- if File.exists?(RESOLVER_FILE)
91
- File.delete(RESOLVER_FILE)
92
- end
93
- rescue Errno::EACCES
94
- Invoker::Logger.puts("Running uninstall requires root access, please rerun it with sudo".color(:red))
95
- raise
96
- end
97
-
98
46
  def check_if_setup_can_run?
99
47
  !File.exists?(Invoker::Power::Config::CONFIG_LOCATION)
100
48
  end
101
-
102
- def install_firewall(balancer_port)
103
- File.open(FIREWALL_PLIST_FILE, "w") { |fl|
104
- fl.write(plist_string(balancer_port))
105
- }
106
- unload_firewall_rule
107
- load_firewall_rule
108
- end
109
-
110
- def load_firewall_rule
111
- system("launchctl load -Fw #{FIREWALL_PLIST_FILE} 2>/dev/null")
112
- end
113
-
114
- def unload_firewall_rule(remove = false)
115
- system("launchctl unload -w #{FIREWALL_PLIST_FILE} 2>/dev/null")
116
- system("rm -rf #{FIREWALL_PLIST_FILE}") if remove
117
- end
118
-
119
- # Ripped from POW code
120
- def plist_string(balancer_port)
121
- plist =<<-EOD
122
- <?xml version="1.0" encoding="UTF-8"?>
123
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
124
- <plist version="1.0">
125
- <dict>
126
- <key>Label</key>
127
- <string>com.codemancers.invoker</string>
128
- <key>ProgramArguments</key>
129
- <array>
130
- <string>sh</string>
131
- <string>-c</string>
132
- <string>#{firewall_command(balancer_port)}</string>
133
- </array>
134
- <key>RunAtLoad</key>
135
- <true/>
136
- <key>UserName</key>
137
- <string>root</string>
138
- </dict>
139
- </plist>
140
- EOD
141
- plist
142
- end
143
-
144
- def resolve_string(dns_port)
145
- string =<<-EOD
146
- nameserver 127.0.0.1
147
- port #{dns_port}
148
- EOD
149
- string
150
- end
151
-
152
- # Ripped from Pow code
153
- def firewall_command(balancer_port)
154
- "ipfw add fwd 127.0.0.1,#{balancer_port} tcp from any to me dst-port 80 in"\
155
- "&amp;&amp; sysctl -w net.inet.ip.forwarding=1"
156
- end
157
-
158
- def setup_resolver_file
159
- return true unless File.exists?(RESOLVER_FILE)
160
- Invoker::Logger.puts "Invoker has detected an existing Pow installation. We recommend "\
161
- "that you uninstall pow and rerun this setup.".color(:red)
162
-
163
- Invoker::Logger.puts "If you have already uninstalled Pow, proceed with installation"\
164
- " by pressing y/n."
165
-
166
- replace_resolver_flag = Invoker::CLI::Question.agree("Replace Pow configuration (y/n) : ")
167
-
168
- if replace_resolver_flag
169
- Invoker::Logger.puts "Invoker has overwritten one or more files created by Pow. "\
170
- "If .dev domains still don't resolve locally. Try turning off the wi-fi"\
171
- " and turning it on. It will force OSX to reload network configuration".color(:green)
172
- end
173
- replace_resolver_flag
174
- end
175
-
176
- private
177
-
178
- def open_resolver_for_write
179
- FileUtils.mkdir(RESOLVER_DIR) unless Dir.exists?(RESOLVER_DIR)
180
- fl = File.open(RESOLVER_FILE, "w")
181
- yield fl
182
- ensure
183
- fl && fl.close
184
- end
185
-
186
49
  end
187
50
  end
188
51
  end
@@ -0,0 +1,84 @@
1
+ module Invoker
2
+ module Power
3
+ class LinuxSetup < Setup
4
+ RESOLVER_FILE = "/etc/dnsmasq.d/dev-tld"
5
+ RINETD_FILE = "/etc/rinetd.conf"
6
+
7
+ def setup_invoker
8
+ if get_user_confirmation?
9
+ find_open_ports
10
+ install_required_software
11
+ install_resolver
12
+ install_port_forwarder
13
+ restart_services
14
+ drop_to_normal_user
15
+ create_config_file
16
+ else
17
+ Invoker::Logger.puts("Invoker is not configured to serve from subdomains".color(:red))
18
+ end
19
+ self
20
+ end
21
+
22
+ def create_config_file
23
+ Invoker.setup_config_location
24
+ Invoker::Power::Config.create(
25
+ http_port: port_finder.http_port,
26
+ https_port: port_finder.https_port
27
+ )
28
+ end
29
+
30
+ def uninstall_invoker
31
+ Invoker::Logger.puts("Uninstall is not yet supported on Linux."\
32
+ " You can remove invoker changes by uninstalling dnsmasq and rinetd")
33
+ end
34
+
35
+ private
36
+
37
+ def restart_services
38
+ system("/etc/init.d/rinetd restart")
39
+ system("/etc/init.d/dnsmasq restart")
40
+ end
41
+
42
+ def install_required_software
43
+ system("apt-get --assume-yes install dnsmasq rinetd")
44
+ end
45
+
46
+ def install_resolver
47
+ File.open(RESOLVER_FILE, "w") do |fl|
48
+ fl.write(tld_setup)
49
+ end
50
+ end
51
+
52
+ def install_port_forwarder
53
+ File.open(RINETD_FILE, "a") do |fl|
54
+ fl << "\n"
55
+ fl << rinetd_setup(port_finder.http_port, port_finder.https_port)
56
+ end
57
+ end
58
+
59
+ def tld_setup
60
+ tld_string =<<-EOD
61
+ local=/dev/
62
+ address=/dev/127.0.0.1
63
+ EOD
64
+ tld_string
65
+ end
66
+
67
+ def rinetd_setup(http_port, https_port)
68
+ rinetd_string =<<-EOD
69
+ 0.0.0.0 80 0.0.0.0 #{http_port}
70
+ 0.0.0.0 443 0.0.0.0 #{https_port}
71
+ EOD
72
+ rinetd_string
73
+ end
74
+
75
+ def get_user_confirmation?
76
+ Invoker::Logger.puts("Invoker is going to install dnsmasq and rinetd on this machine."\
77
+ " It is also going to install a local resolver for .dev domain and a rinetd rule"\
78
+ " which will forward all local requests on port 80 and 443 to another port")
79
+ Invoker::Logger.puts("If you still want to proceed with installation, press y.")
80
+ Invoker::CLI::Question.agree("Proceed with installation (y/n) : ")
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,152 @@
1
+ module Invoker
2
+ module Power
3
+ class OsxSetup < Setup
4
+ RESOLVER_FILE = "/etc/resolver/dev"
5
+ RESOLVER_DIR = "/etc/resolver"
6
+ FIREWALL_PLIST_FILE = "/Library/LaunchDaemons/com.codemancers.invoker.firewall.plist"
7
+
8
+ def setup_invoker
9
+ if setup_resolver_file
10
+ find_open_ports
11
+ install_resolver(port_finder.dns_port)
12
+ install_firewall(port_finder.http_port, port_finder.https_port)
13
+ flush_dns_rules
14
+ # Before writing the config file, drop down to a normal user
15
+ drop_to_normal_user
16
+ create_config_file
17
+ else
18
+ Invoker::Logger.puts("Invoker is not configured to serve from subdomains".color(:red))
19
+ end
20
+ self
21
+ end
22
+
23
+ def uninstall_invoker
24
+ uninstall_invoker_flag = Invoker::CLI::Question.agree("Are you sure you want to uninstall firewall rules created by setup (y/n) : ")
25
+
26
+ if uninstall_invoker_flag
27
+ remove_resolver_file
28
+ unload_firewall_rule(true)
29
+ flush_dns_rules
30
+ Invoker::Power::Config.delete
31
+ Invoker::Logger.puts("Firewall rules were removed")
32
+ end
33
+ end
34
+
35
+ def flush_dns_rules
36
+ system("dscacheutil -flushcache")
37
+ end
38
+
39
+ def create_config_file
40
+ Invoker.setup_config_location
41
+ Invoker::Power::Config.create(
42
+ dns_port: port_finder.dns_port,
43
+ http_port: port_finder.http_port,
44
+ https_port: port_finder.https_port
45
+ )
46
+ end
47
+
48
+ def install_resolver(dns_port)
49
+ open_resolver_for_write { |fl|
50
+ fl.write(resolve_string(dns_port))
51
+ }
52
+ rescue Errno::EACCES
53
+ Invoker::Logger.puts("Running setup requires root access, please rerun it with sudo".color(:red))
54
+ raise
55
+ end
56
+
57
+ def remove_resolver_file
58
+ if File.exists?(RESOLVER_FILE)
59
+ File.delete(RESOLVER_FILE)
60
+ end
61
+ rescue Errno::EACCES
62
+ Invoker::Logger.puts("Running uninstall requires root access, please rerun it with sudo".color(:red))
63
+ raise
64
+ end
65
+
66
+ def install_firewall(http_port, https_port)
67
+ File.open(FIREWALL_PLIST_FILE, "w") { |fl|
68
+ fl.write(plist_string(http_port, https_port))
69
+ }
70
+ unload_firewall_rule
71
+ load_firewall_rule
72
+ end
73
+
74
+ def load_firewall_rule
75
+ system("launchctl load -Fw #{FIREWALL_PLIST_FILE} 2>/dev/null")
76
+ end
77
+
78
+ def unload_firewall_rule(remove = false)
79
+ system("launchctl unload -w #{FIREWALL_PLIST_FILE} 2>/dev/null")
80
+ system("rm -rf #{FIREWALL_PLIST_FILE}") if remove
81
+ end
82
+
83
+ # Ripped from POW code
84
+ def plist_string(http_port, https_port)
85
+ plist =<<-EOD
86
+ <?xml version="1.0" encoding="UTF-8"?>
87
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
88
+ <plist version="1.0">
89
+ <dict>
90
+ <key>Label</key>
91
+ <string>com.codemancers.invoker</string>
92
+ <key>ProgramArguments</key>
93
+ <array>
94
+ <string>sh</string>
95
+ <string>-c</string>
96
+ <string>#{firewall_command(http_port, https_port)}</string>
97
+ </array>
98
+ <key>RunAtLoad</key>
99
+ <true/>
100
+ <key>UserName</key>
101
+ <string>root</string>
102
+ </dict>
103
+ </plist>
104
+ EOD
105
+ plist
106
+ end
107
+
108
+ def resolve_string(dns_port)
109
+ string =<<-EOD
110
+ nameserver 127.0.0.1
111
+ port #{dns_port}
112
+ EOD
113
+ string
114
+ end
115
+
116
+ # Ripped from Pow code
117
+ def firewall_command(http_port, https_port)
118
+ "ipfw add fwd 127.0.0.1,#{http_port} tcp from any to me dst-port 80 in"\
119
+ "&amp;&amp; ipfw add fwd 127.0.0.1,#{https_port} tcp from any to me dst-port 443 in"\
120
+ "&amp;&amp; sysctl -w net.inet.ip.forwarding=1"
121
+ end
122
+
123
+ def setup_resolver_file
124
+ return true unless File.exists?(RESOLVER_FILE)
125
+ Invoker::Logger.puts "Invoker has detected an existing Pow installation. We recommend "\
126
+ "that you uninstall pow and rerun this setup.".color(:red)
127
+
128
+ Invoker::Logger.puts "If you have already uninstalled Pow, proceed with installation"\
129
+ " by pressing y/n."
130
+
131
+ replace_resolver_flag = Invoker::CLI::Question.agree("Replace Pow configuration (y/n) : ")
132
+
133
+ if replace_resolver_flag
134
+ Invoker::Logger.puts "Invoker has overwritten one or more files created by Pow. "\
135
+ "If .dev domains still don't resolve locally. Try turning off the wi-fi"\
136
+ " and turning it on. It will force OSX to reload network configuration".color(:green)
137
+ end
138
+ replace_resolver_flag
139
+ end
140
+
141
+ private
142
+
143
+ def open_resolver_for_write
144
+ FileUtils.mkdir(RESOLVER_DIR) unless Dir.exists?(RESOLVER_DIR)
145
+ fl = File.open(RESOLVER_FILE, "w")
146
+ yield fl
147
+ ensure
148
+ fl && fl.close
149
+ end
150
+ end
151
+ end
152
+ end
@@ -1,3 +1,3 @@
1
1
  module Invoker
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0.pre"
3
3
  end
@@ -108,20 +108,12 @@ command = ls
108
108
  @file = Tempfile.new(["config", ".ini"])
109
109
  end
110
110
 
111
- it "does not load config if platform is not darwin" do
112
- Invoker.expects(:darwin?).returns(false)
113
- Invoker::Power::Config.expects(:load_config).never
114
- Invoker::Parsers::Config.new(@file.path, 9000)
115
- end
116
-
117
111
  it "does not load config if platform is darwin but there is no power config file" do
118
- Invoker.expects(:darwin?).returns(true)
119
112
  Invoker::Power::Config.expects(:load_config).never
120
113
  Invoker::Parsers::Config.new(@file.path, 9000)
121
114
  end
122
115
 
123
116
  it "loads config if platform is darwin and power config file exists" do
124
- Invoker.expects(:darwin?).returns(true)
125
117
  File.open(Invoker::Power::Config::CONFIG_LOCATION, "w") { |fl| fl.puts "sample" }
126
118
  Invoker::Power::Config.expects(:load_config).once
127
119
  Invoker::Parsers::Config.new(@file.path, 9000)
@@ -14,37 +14,18 @@ describe "Invoker" do
14
14
  end
15
15
 
16
16
  describe "#can_run_balancer?" do
17
- before {
18
- File.exists?(Invoker::Power::Config::CONFIG_LOCATION) &&
19
- File.delete(Invoker::Power::Config::CONFIG_LOCATION)
20
- }
21
-
22
- after {
23
- File.exists?(Invoker::Power::Config::CONFIG_LOCATION) &&
24
- File.delete(Invoker::Power::Config::CONFIG_LOCATION)
25
- }
26
-
27
- it "should return false if setup command was not run on osx" do
28
- Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
29
- expect(Invoker.can_run_balancer?).to be_false
30
- end
31
-
32
- it "should return false if platform is not osx" do
33
- Invoker.expects(:ruby_platform).returns("i686-linux")
17
+ it "should return false if setup command was not run" do
34
18
  expect(Invoker.can_run_balancer?).to be_false
35
19
  end
36
20
 
37
21
  it "should return true if setup was run properly" do
38
- Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
39
22
  File.open(Invoker::Power::Config::CONFIG_LOCATION, "w") {|fl|
40
23
  fl.write("hello")
41
24
  }
42
-
43
25
  expect(Invoker.can_run_balancer?).to be_true
44
26
  end
45
27
 
46
28
  it "should not print warning if setup is not run when flag is false" do
47
- Invoker.expects(:ruby_platform).returns("x86_64-darwin12.4.0")
48
29
  Invoker::Logger.expects(:puts).never()
49
30
  Invoker.can_run_balancer?(false)
50
31
  end
@@ -81,4 +62,3 @@ describe "Invoker" do
81
62
  end
82
63
  end
83
64
  end
84
-
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Invoker::Power::Balancer do
4
4
  context "matching domain part of incoming request" do
5
5
  before do
6
- @balancer = Invoker::Power::Balancer.new(mock("connection"))
6
+ @balancer = Invoker::Power::Balancer.new(mock("connection"), "http")
7
7
  end
8
8
 
9
9
  it "should do foo.dev match" do
@@ -0,0 +1,44 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Power::LinuxSetup do
4
+ let(:invoker_setup) { Invoker::Power::LinuxSetup.new }
5
+ describe "should only proceed after user confirmation" do
6
+ it "should create config file with port" do
7
+ invoker_setup.expects(:get_user_confirmation?).returns(true)
8
+ invoker_setup.expects(:install_required_software).returns(true)
9
+ invoker_setup.expects(:install_resolver).returns(true)
10
+ invoker_setup.expects(:install_port_forwarder).returns(true)
11
+ invoker_setup.expects(:restart_services).returns(true)
12
+ invoker_setup.expects(:drop_to_normal_user).returns(true)
13
+
14
+ invoker_setup.setup_invoker
15
+
16
+ config = Invoker::Power::Config.load_config
17
+ expect(config.http_port).not_to be_nil
18
+ expect(config.dns_port).to be_nil
19
+ expect(config.https_port).not_to be_nil
20
+ end
21
+ end
22
+
23
+ describe "configuring dnsmasq and rinetd" do
24
+ it "should create proper config file" do
25
+ invoker_setup.expects(:get_user_confirmation?).returns(true)
26
+ invoker_setup.expects(:install_required_software).returns(true)
27
+ invoker_setup.expects(:restart_services).returns(true)
28
+ invoker_setup.expects(:drop_to_normal_user).returns(true)
29
+
30
+ invoker_setup.setup_invoker
31
+
32
+ config = Invoker::Power::Config.load_config
33
+
34
+ dnsmasq_content = File.read(Invoker::Power::LinuxSetup::RESOLVER_FILE)
35
+ expect(dnsmasq_content.strip).to_not be_empty
36
+ expect(dnsmasq_content).to match(/dev/)
37
+
38
+ rinetd_content = File.read(Invoker::Power::LinuxSetup::RINETD_FILE)
39
+ expect(rinetd_content.strip).to_not be_empty
40
+ expect(rinetd_content.strip).to match(/#{config.https_port}/)
41
+ expect(rinetd_content.strip).to match(/#{config.http_port}/)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,96 @@
1
+ require "spec_helper"
2
+
3
+ describe Invoker::Power::OsxSetup do
4
+ describe "When no setup exists" do
5
+ it "should create a config file with port etc" do
6
+ setup = Invoker::Power::OsxSetup.new
7
+ setup.expects(:install_resolver).returns(true)
8
+ setup.expects(:flush_dns_rules).returns(true)
9
+ setup.expects(:drop_to_normal_user).returns(true)
10
+ setup.expects(:install_firewall).once
11
+
12
+ setup.setup_invoker
13
+
14
+ config = Invoker::Power::Config.load_config
15
+ expect(config.http_port).not_to be_nil
16
+ expect(config.dns_port).not_to be_nil
17
+ expect(config.https_port).not_to be_nil
18
+ end
19
+ end
20
+
21
+ describe "when a setup file exists" do
22
+ it "should throw error about existing file" do
23
+ File.open(Invoker::Power::Config::CONFIG_LOCATION, "w") {|fl|
24
+ fl.write("foo test")
25
+ }
26
+ Invoker::Power::Setup.any_instance.expects(:setup_invoker).never
27
+ Invoker::Power::Setup.install()
28
+ end
29
+ end
30
+
31
+ describe "when pow like setup exists" do
32
+ before {
33
+ File.open(Invoker::Power::OsxSetup::RESOLVER_FILE, "w") {|fl|
34
+ fl.write("hello")
35
+ }
36
+ @setup = Invoker::Power::OsxSetup.new
37
+ }
38
+
39
+ describe "when user selects to overwrite it" do
40
+ it "should run setup normally" do
41
+ @setup.expects(:setup_resolver_file).returns(true)
42
+ @setup.expects(:drop_to_normal_user).returns(true)
43
+ @setup.expects(:install_resolver).returns(true)
44
+ @setup.expects(:flush_dns_rules).returns(true)
45
+ @setup.expects(:install_firewall).once()
46
+
47
+ @setup.setup_invoker
48
+ end
49
+ end
50
+
51
+ describe "when user chose not to overwrite it" do
52
+ it "should abort the setup process" do
53
+ @setup.expects(:setup_resolver_file).returns(false)
54
+
55
+ @setup.expects(:install_resolver).never
56
+ @setup.expects(:flush_dns_rules).never
57
+ @setup.expects(:install_firewall).never
58
+
59
+ @setup.setup_invoker
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "uninstalling firewall rules" do
65
+ it "should uninstall firewall rules and remove all files created by setup" do
66
+ setup = Invoker::Power::OsxSetup.new
67
+
68
+ Invoker::CLI::Question.expects(:agree).returns(true)
69
+ setup.expects(:remove_resolver_file).once
70
+ setup.expects(:unload_firewall_rule).with(true).once
71
+ setup.expects(:flush_dns_rules).once
72
+ Invoker::Power::Config.expects(:delete).once
73
+
74
+ setup.uninstall_invoker
75
+ end
76
+ end
77
+
78
+ describe "setup on fresh osx install" do
79
+ context "when resolver directory does not exist" do
80
+ before do
81
+ @setup = Invoker::Power::OsxSetup.new
82
+ FileUtils.rm_rf(Invoker::Power::OsxSetup::RESOLVER_DIR)
83
+ end
84
+
85
+ it "should create the directory and install" do
86
+ @setup.expects(:setup_resolver_file).returns(true)
87
+ @setup.expects(:drop_to_normal_user).returns(true)
88
+ @setup.expects(:flush_dns_rules).returns(true)
89
+ @setup.expects(:install_firewall).once()
90
+
91
+ @setup.setup_invoker
92
+ expect(Dir.exist?(Invoker::Power::OsxSetup::RESOLVER_DIR)).to be_true
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,104 +1,4 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe "Setup" do
4
- describe "When no setup exists" do
5
- it "should create a config file with port etc" do
6
- setup = Invoker::Power::Setup.new()
7
- setup.expects(:install_resolver).returns(true)
8
- setup.expects(:flush_dns_rules).returns(true)
9
- setup.expects(:drop_to_normal_user).returns(true)
10
- setup.expects(:install_firewall).once()
11
-
12
- setup.setup_invoker
13
-
14
- config = Invoker::Power::Config.load_config()
15
- expect(config.http_port).not_to be_nil
16
- expect(config.dns_port).not_to be_nil
17
- end
18
- end
19
-
20
- describe "setup on non osx systems" do
21
- it "should not run setup" do
22
- Invoker.expects(:ruby_platform).returns("i686-linux")
23
- Invoker::Power::Setup.any_instance.expects(:check_if_setup_can_run?).never()
24
- Invoker::Power::Setup.install
25
- end
26
- end
27
-
28
- describe "when a setup file exists" do
29
- it "should throw error about existing file" do
30
- File.open(Invoker::Power::Config::CONFIG_LOCATION, "w") {|fl|
31
- fl.write("foo test")
32
- }
33
- Invoker::Power::Setup.any_instance.expects(:setup_invoker).never
34
- Invoker::Power::Setup.install()
35
- end
36
- end
37
-
38
- describe "when pow like setup exists" do
39
- before {
40
- File.open(Invoker::Power::Setup::RESOLVER_FILE, "w") {|fl|
41
- fl.write("hello")
42
- }
43
- @setup = Invoker::Power::Setup.new
44
- }
45
-
46
- describe "when user selects to overwrite it" do
47
- it "should run setup normally" do
48
- @setup.expects(:setup_resolver_file).returns(true)
49
- @setup.expects(:drop_to_normal_user).returns(true)
50
- @setup.expects(:install_resolver).returns(true)
51
- @setup.expects(:flush_dns_rules).returns(true)
52
- @setup.expects(:install_firewall).once()
53
-
54
- @setup.setup_invoker
55
- end
56
- end
57
-
58
- describe "when user chose not to overwrite it" do
59
- it "should abort the setup process" do
60
- @setup.expects(:setup_resolver_file).returns(false)
61
-
62
- @setup.expects(:install_resolver).never
63
- @setup.expects(:flush_dns_rules).never
64
- @setup.expects(:install_firewall).never
65
-
66
- @setup.setup_invoker
67
- end
68
- end
69
- end
70
-
71
- describe "uninstalling firewall rules" do
72
- it "should uninstall firewall rules and remove all files created by setup" do
73
- setup = Invoker::Power::Setup.new
74
-
75
- Invoker::CLI::Question.expects(:agree).returns(true)
76
- setup.expects(:remove_resolver_file).once
77
- setup.expects(:unload_firewall_rule).with(true).once
78
- setup.expects(:flush_dns_rules).once
79
- Invoker::Power::Config.expects(:delete).once
80
-
81
- setup.uninstall_invoker
82
- end
83
- end
84
-
85
- describe "setup on fresh osx install" do
86
- context "when resolver directory does not exist" do
87
- before do
88
- @setup = Invoker::Power::Setup.new()
89
- FileUtils.rm_rf(Invoker::Power::Setup::RESOLVER_DIR)
90
- end
91
-
92
- it "should create the directory and install" do
93
- @setup.expects(:setup_resolver_file).returns(true)
94
- @setup.expects(:drop_to_normal_user).returns(true)
95
- @setup.expects(:flush_dns_rules).returns(true)
96
- @setup.expects(:install_firewall).once()
97
-
98
- @setup.setup_invoker()
99
-
100
- expect(Dir.exists?(Invoker::Power::Setup::RESOLVER_DIR)).to be_true
101
- end
102
- end
103
- end
104
4
  end
@@ -7,6 +7,8 @@ end
7
7
 
8
8
  require "invoker"
9
9
  require "invoker/power/power"
10
+ $: << File.join(File.dirname(__FILE__), "support")
11
+ require "mock_setup_file"
10
12
  MM = Invoker::IPC::Message
11
13
 
12
14
  RSpec.configure do |config|
@@ -14,44 +16,16 @@ RSpec.configure do |config|
14
16
  config.run_all_when_everything_filtered = true
15
17
  config.filter_run :focus
16
18
  config.mock_framework = :mocha
19
+ config.include MockSetupFile
17
20
 
18
- config.before(:each) do
19
- @original_verbosity = $VERBOSE
21
+ config.around do |example|
22
+ original_verbosity = $VERBOSE
20
23
  $VERBOSE = nil
21
- @old_config = Invoker::Power::Config::CONFIG_LOCATION
22
- Invoker::Power::Config.const_set(:CONFIG_LOCATION, "/tmp/.invoker/config")
23
- FileUtils.mkdir("/tmp/.invoker") unless Dir.exist?("/tmp/.invoker")
24
-
25
- File.exists?(Invoker::Power::Config::CONFIG_LOCATION) &&
26
- File.delete(Invoker::Power::Config::CONFIG_LOCATION)
27
-
28
- @old_resolver = Invoker::Power::Setup::RESOLVER_FILE
29
- Invoker::Power::Setup.const_set(:RESOLVER_FILE, "/tmp/resolver/invoker-dev")
30
- Invoker::Power::Setup.const_set(:RESOLVER_DIR, "/tmp/resolver")
31
-
32
- unless Dir.exists?(Invoker::Power::Setup::RESOLVER_DIR)
33
- FileUtils.mkdir(Invoker::Power::Setup::RESOLVER_DIR)
34
- end
35
-
36
- File.exists?(Invoker::Power::Setup::RESOLVER_FILE) &&
37
- File.delete(Invoker::Power::Setup::RESOLVER_FILE)
24
+ setup_mocked_config_files
25
+ example.run
26
+ remove_mocked_config_files
27
+ $VERBOSE = original_verbosity
38
28
  end
39
-
40
- config.after(:each) do
41
- File.exists?(Invoker::Power::Config::CONFIG_LOCATION) &&
42
- File.delete(Invoker::Power::Config::CONFIG_LOCATION)
43
-
44
- Invoker::Power::Config.const_set(:CONFIG_LOCATION, @old_config)
45
-
46
- File.exists?(Invoker::Power::Setup::RESOLVER_FILE) &&
47
- File.delete(Invoker::Power::Setup::RESOLVER_FILE)
48
-
49
- FileUtils.rm_rf(Invoker::Power::Setup::RESOLVER_DIR)
50
- Invoker::Power::Setup.const_set(:RESOLVER_FILE, @old_resolver)
51
-
52
- $VERBOSE = @original_verbosity
53
- end
54
-
55
29
  # Run specs in random order to surface order dependencies. If you find an
56
30
  # order dependency and want to debug it, you can fix the order by providing
57
31
  # the seed, which is printed after each run.
@@ -0,0 +1,68 @@
1
+ module MockSetupFile
2
+ def setup_mocked_config_files
3
+ setup_invoker_config
4
+ setup_osx_resolver_path
5
+ setup_linux_resolver_path
6
+ end
7
+
8
+ def remove_mocked_config_files
9
+ restore_invoker_config
10
+ restore_osx_resolver_setup
11
+ restore_linux_resolver_path
12
+ end
13
+
14
+ def safe_remove_file(file_location)
15
+ File.exist?(file_location) &&
16
+ File.delete(file_location)
17
+ end
18
+
19
+ def safe_make_directory(directory)
20
+ FileUtils.mkdir(directory) unless Dir.exist?(directory)
21
+ end
22
+
23
+ private
24
+
25
+ def setup_invoker_config
26
+ @old_config = Invoker::Power::Config::CONFIG_LOCATION
27
+ Invoker::Power::Config.const_set(:CONFIG_LOCATION, "/tmp/.invoker/config")
28
+ safe_make_directory("/tmp/.invoker")
29
+ safe_remove_file(Invoker::Power::Config::CONFIG_LOCATION)
30
+ end
31
+
32
+ def restore_invoker_config
33
+ safe_remove_file(Invoker::Power::Config::CONFIG_LOCATION)
34
+ Invoker::Power::Config.const_set(:CONFIG_LOCATION, @old_config)
35
+ $VERBOSE = @original_verbosity
36
+ end
37
+
38
+ def restore_osx_resolver_setup
39
+ safe_remove_file(Invoker::Power::OsxSetup::RESOLVER_FILE)
40
+ FileUtils.rm_rf(Invoker::Power::OsxSetup::RESOLVER_DIR)
41
+ Invoker::Power::OsxSetup.const_set(:RESOLVER_FILE, @old_osx_resolver)
42
+ end
43
+
44
+ def setup_osx_resolver_path
45
+ @old_osx_resolver = Invoker::Power::OsxSetup::RESOLVER_FILE
46
+ Invoker::Power::OsxSetup.const_set(:RESOLVER_FILE, "/tmp/resolver/invoker-dev")
47
+ Invoker::Power::OsxSetup.const_set(:RESOLVER_DIR, "/tmp/resolver")
48
+
49
+ safe_make_directory(Invoker::Power::OsxSetup::RESOLVER_DIR)
50
+ safe_remove_file(Invoker::Power::OsxSetup::RESOLVER_FILE)
51
+ end
52
+
53
+ def setup_linux_resolver_path
54
+ @old_linux_resolver = Invoker::Power::LinuxSetup::RESOLVER_FILE
55
+ @old_rinetd_config = Invoker::Power::LinuxSetup::RINETD_FILE
56
+ Invoker::Power::LinuxSetup.const_set(:RESOLVER_FILE, "/tmp/dev-tld")
57
+ Invoker::Power::LinuxSetup.const_set(:RINETD_FILE, "/tmp/rinetd.conf")
58
+ safe_remove_file(Invoker::Power::LinuxSetup::RESOLVER_FILE)
59
+ safe_remove_file(Invoker::Power::LinuxSetup::RINETD_FILE)
60
+ end
61
+
62
+ def restore_linux_resolver_path
63
+ safe_remove_file(Invoker::Power::LinuxSetup::RESOLVER_FILE)
64
+ safe_remove_file(Invoker::Power::LinuxSetup::RINETD_FILE)
65
+ Invoker::Power::LinuxSetup.const_set(:RESOLVER_FILE, @old_linux_resolver)
66
+ Invoker::Power::LinuxSetup.const_set(:RINETD_FILE, @old_rinetd_config)
67
+ end
68
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: invoker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hemant Kumar
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-11 00:00:00.000000000 Z
12
+ date: 2014-05-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -219,7 +219,6 @@ files:
219
219
  - lib/invoker/cli/tail_watcher.rb
220
220
  - lib/invoker/command_worker.rb
221
221
  - lib/invoker/commander.rb
222
- - lib/invoker/config.rb
223
222
  - lib/invoker/daemon.rb
224
223
  - lib/invoker/dns_cache.rb
225
224
  - lib/invoker/errors.rb
@@ -251,6 +250,8 @@ files:
251
250
  - lib/invoker/power/power.rb
252
251
  - lib/invoker/power/powerup.rb
253
252
  - lib/invoker/power/setup.rb
253
+ - lib/invoker/power/setup/linux_setup.rb
254
+ - lib/invoker/power/setup/osx_setup.rb
254
255
  - lib/invoker/power/templates/404.html
255
256
  - lib/invoker/power/templates/503.html
256
257
  - lib/invoker/process_manager.rb
@@ -277,10 +278,13 @@ files:
277
278
  - spec/invoker/power/config_spec.rb
278
279
  - spec/invoker/power/http_response_spec.rb
279
280
  - spec/invoker/power/port_finder_spec.rb
281
+ - spec/invoker/power/setup/linux_setup_spec.rb
282
+ - spec/invoker/power/setup/osx_setup_spec.rb
280
283
  - spec/invoker/power/setup_spec.rb
281
284
  - spec/invoker/process_manager_spec.rb
282
285
  - spec/invoker/reactor_spec.rb
283
286
  - spec/spec_helper.rb
287
+ - spec/support/mock_setup_file.rb
284
288
  homepage: http://invoker.codemancers.com
285
289
  licenses:
286
290
  - MIT
@@ -305,27 +309,5 @@ rubygems_version: 2.2.2
305
309
  signing_key:
306
310
  specification_version: 4
307
311
  summary: Something small for Process management
308
- test_files:
309
- - spec/invoker/cli/pinger_spec.rb
310
- - spec/invoker/cli/tail_watcher_spec.rb
311
- - spec/invoker/cli_spec.rb
312
- - spec/invoker/command_worker_spec.rb
313
- - spec/invoker/commander_spec.rb
314
- - spec/invoker/config_spec.rb
315
- - spec/invoker/daemon_spec.rb
316
- - spec/invoker/event/manager_spec.rb
317
- - spec/invoker/invoker_spec.rb
318
- - spec/invoker/ipc/client_handler_spec.rb
319
- - spec/invoker/ipc/dns_check_command_spec.rb
320
- - spec/invoker/ipc/message/list_response_spec.rb
321
- - spec/invoker/ipc/message_spec.rb
322
- - spec/invoker/ipc/unix_client_spec.rb
323
- - spec/invoker/power/balancer_spec.rb
324
- - spec/invoker/power/config_spec.rb
325
- - spec/invoker/power/http_response_spec.rb
326
- - spec/invoker/power/port_finder_spec.rb
327
- - spec/invoker/power/setup_spec.rb
328
- - spec/invoker/process_manager_spec.rb
329
- - spec/invoker/reactor_spec.rb
330
- - spec/spec_helper.rb
312
+ test_files: []
331
313
  has_rdoc:
@@ -1,5 +0,0 @@
1
- module Invoker
2
- module Config
3
-
4
- end
5
- end