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,131 @@
|
|
|
1
|
+
require 'em-proxy'
|
|
2
|
+
require 'http-parser'
|
|
3
|
+
require "invoker/power/http_parser"
|
|
4
|
+
require "invoker/power/url_rewriter"
|
|
5
|
+
|
|
6
|
+
module Invoker
|
|
7
|
+
module Power
|
|
8
|
+
class InvokerHttpProxy < EventMachine::ProxyServer::Connection
|
|
9
|
+
attr_accessor :host, :ip, :port
|
|
10
|
+
def set_host(host, selected_backend)
|
|
11
|
+
self.host = host
|
|
12
|
+
self.ip = selected_backend[:host]
|
|
13
|
+
self.port = selected_backend[:port]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class InvokerHttpsProxy < InvokerHttpProxy
|
|
18
|
+
def post_init
|
|
19
|
+
super
|
|
20
|
+
start_tls
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Balancer
|
|
25
|
+
attr_accessor :connection, :http_parser, :session, :protocol, :upgraded_to
|
|
26
|
+
|
|
27
|
+
def self.run(options = {})
|
|
28
|
+
start_http_proxy(InvokerHttpProxy, 'http', options)
|
|
29
|
+
start_http_proxy(InvokerHttpsProxy, 'https', options)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.start_http_proxy(proxy_class, protocol, options)
|
|
33
|
+
port = protocol == 'http' ? Invoker.config.http_port : Invoker.config.https_port
|
|
34
|
+
EventMachine.start_server('0.0.0.0', port,
|
|
35
|
+
proxy_class, options) do |connection|
|
|
36
|
+
balancer = Balancer.new(connection, protocol)
|
|
37
|
+
balancer.install_callbacks
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize(connection, protocol)
|
|
42
|
+
@connection = connection
|
|
43
|
+
@protocol = protocol
|
|
44
|
+
@http_parser = HttpParser.new(protocol)
|
|
45
|
+
@session = nil
|
|
46
|
+
@upgraded_to = nil
|
|
47
|
+
@buffer = []
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def install_callbacks
|
|
51
|
+
http_parser.on_headers_complete { |headers| headers_received(headers) }
|
|
52
|
+
http_parser.on_message_complete { |full_message| complete_message_received(full_message) }
|
|
53
|
+
connection.on_data { |data| upstream_data(data) }
|
|
54
|
+
connection.on_response { |backend, data| backend_data(backend, data) }
|
|
55
|
+
connection.on_finish { |backend, name| frontend_disconnect(backend, name) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def complete_message_received(full_message)
|
|
59
|
+
connection.relay_to_servers(full_message)
|
|
60
|
+
http_parser.reset
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def headers_received(headers)
|
|
64
|
+
if @session
|
|
65
|
+
return
|
|
66
|
+
end
|
|
67
|
+
@session = UUID.generate()
|
|
68
|
+
if !headers['Host'] || headers['Host'].empty?
|
|
69
|
+
return_error_page(400)
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
dns_check_response = UrlRewriter.new.select_backend_config(headers['Host'])
|
|
74
|
+
if dns_check_response && dns_check_response.port
|
|
75
|
+
connection.server(session, host: dns_check_response.ip, port: dns_check_response.port)
|
|
76
|
+
else
|
|
77
|
+
return_error_page(404)
|
|
78
|
+
http_parser.reset
|
|
79
|
+
connection.close_connection_after_writing
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def upstream_data(data)
|
|
84
|
+
if upgraded_to == "websocket"
|
|
85
|
+
data
|
|
86
|
+
else
|
|
87
|
+
append_for_http_parsing(data)
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def append_for_http_parsing(data)
|
|
93
|
+
http_parser << data
|
|
94
|
+
rescue HTTP::Parser::Error
|
|
95
|
+
http_parser.reset
|
|
96
|
+
connection.close_connection_after_writing
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def backend_data(backend, data)
|
|
100
|
+
@backend_data = true
|
|
101
|
+
|
|
102
|
+
# check backend data for websockets connection. check for upgrade headers
|
|
103
|
+
# - Upgarde: websocket\r\n
|
|
104
|
+
if data =~ /Upgrade: websocket/
|
|
105
|
+
@upgraded_to = "websocket"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
data
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def frontend_disconnect(backend, name)
|
|
112
|
+
http_parser.reset
|
|
113
|
+
unless @backend_data
|
|
114
|
+
return_error_page(503)
|
|
115
|
+
end
|
|
116
|
+
@backend_data = false
|
|
117
|
+
connection.close_connection_after_writing if backend == session
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def return_error_page(status)
|
|
123
|
+
http_response = Invoker::Power::HttpResponse.new()
|
|
124
|
+
http_response.status = status
|
|
125
|
+
http_response['Content-Type'] = "text/html; charset=utf-8"
|
|
126
|
+
http_response.use_file_as_body(File.join(File.dirname(__FILE__), "templates/#{status}.html"))
|
|
127
|
+
connection.send_data(http_response.http_string)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module Invoker
|
|
4
|
+
module Power
|
|
5
|
+
# Save and Load Invoker::Power config
|
|
6
|
+
class ConfigExists < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Config
|
|
9
|
+
def self.has_config?
|
|
10
|
+
File.exist?(config_file)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.create(options = {})
|
|
14
|
+
if has_config?
|
|
15
|
+
raise ConfigExists, "Config file already exists at location #{config_file}"
|
|
16
|
+
end
|
|
17
|
+
config = new(options)
|
|
18
|
+
config.save
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.delete
|
|
22
|
+
if File.exist?(config_file)
|
|
23
|
+
File.delete(config_file)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.config_file
|
|
28
|
+
File.join(Invoker.home, ".invoker", "config")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.config_dir
|
|
32
|
+
File.join(Invoker.home, ".invoker")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(options = {})
|
|
36
|
+
@config = options
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.load_config
|
|
40
|
+
config_hash = File.open(config_file, "r") { |fl| YAML.load(fl) }
|
|
41
|
+
new(config_hash)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def dns_port=(dns_port)
|
|
45
|
+
@config[:dns_port] = dns_port
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def http_port=(http_port)
|
|
49
|
+
@config[:http_port] = http_port
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def https_port=(https_port)
|
|
53
|
+
@config[:https_port] = https_port
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ipfw_rule_number=(ipfw_rule_number)
|
|
57
|
+
@config[:ipfw_rule_number] = ipfw_rule_number
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def dns_port; @config[:dns_port]; end
|
|
61
|
+
def http_port; @config[:http_port]; end
|
|
62
|
+
def ipfw_rule_number; @config[:ipfw_rule_number]; end
|
|
63
|
+
def https_port; @config[:https_port]; end
|
|
64
|
+
|
|
65
|
+
def tld
|
|
66
|
+
@config[:tld] || Invoker.default_tld
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def save
|
|
70
|
+
File.open(self.class.config_file, "w") do |fl|
|
|
71
|
+
YAML.dump(@config, fl)
|
|
72
|
+
end
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require "logger"
|
|
2
|
+
require 'rubydns'
|
|
3
|
+
|
|
4
|
+
module Invoker
|
|
5
|
+
module Power
|
|
6
|
+
class DNS < RubyDNS::Server
|
|
7
|
+
def self.server_ports
|
|
8
|
+
[
|
|
9
|
+
[:udp, '127.0.0.1', Invoker.config.dns_port],
|
|
10
|
+
[:tcp, '127.0.0.1', Invoker.config.dns_port]
|
|
11
|
+
]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@logger = ::Logger.new($stderr)
|
|
16
|
+
@logger.level = ::Logger::FATAL
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def process(name, resource_class, transaction)
|
|
20
|
+
if name_matches?(name) && resource_class_matches?(resource_class)
|
|
21
|
+
transaction.respond!("127.0.0.1")
|
|
22
|
+
else
|
|
23
|
+
transaction.fail!(:NXDomain)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def resource_class_matches?(resource_class)
|
|
30
|
+
resource_class == Resolv::DNS::Resource::IN::A
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def name_matches?(name)
|
|
34
|
+
name =~ /.*\.#{Invoker.config.tld}/
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
module Power
|
|
3
|
+
class HttpParser
|
|
4
|
+
attr_accessor :host, :parser, :protocol
|
|
5
|
+
|
|
6
|
+
def initialize(protocol)
|
|
7
|
+
@protocol = protocol
|
|
8
|
+
@parser = HTTP::Parser.new
|
|
9
|
+
@header = {}
|
|
10
|
+
initialize_message_content
|
|
11
|
+
parser.on_headers_complete { complete_headers_received }
|
|
12
|
+
parser.on_header_field { |field_name| @last_key = field_name }
|
|
13
|
+
parser.on_header_value { |field_value| header_value_received(field_value) }
|
|
14
|
+
|
|
15
|
+
parser.on_message_complete { complete_message_received }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# define a callback for invoking when complete header is parsed
|
|
19
|
+
def on_headers_complete(&block)
|
|
20
|
+
@on_headers_complete_callback = block
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def header_value_received(value)
|
|
24
|
+
@header[@last_key] = value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# define a callback to invoke when a full http message is received
|
|
28
|
+
def on_message_complete(&block)
|
|
29
|
+
@on_message_complete_callback = block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reset
|
|
33
|
+
@header = {}
|
|
34
|
+
initialize_message_content
|
|
35
|
+
parser.reset
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def << data
|
|
39
|
+
@full_message.write(data)
|
|
40
|
+
parser << data
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def complete_message_received
|
|
46
|
+
full_message_string = @full_message.string.dup
|
|
47
|
+
if full_message_string =~ /\r\n\r\n/
|
|
48
|
+
full_message_string.sub!(/\r\n\r\n/, "\r\nX_FORWARDED_PROTO: #{protocol}\r\n\r\n")
|
|
49
|
+
end
|
|
50
|
+
if @on_message_complete_callback
|
|
51
|
+
@on_message_complete_callback.call(full_message_string)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def initialize_message_content
|
|
56
|
+
@full_message = StringIO.new
|
|
57
|
+
@full_message.set_encoding('ASCII-8BIT')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# gets invoker when complete header is received
|
|
61
|
+
def complete_headers_received
|
|
62
|
+
if @on_headers_complete_callback
|
|
63
|
+
@on_headers_complete_callback.call(@header)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
|
|
3
|
+
module Invoker
|
|
4
|
+
module Power
|
|
5
|
+
class HttpResponse
|
|
6
|
+
STATUS_MAPS = {
|
|
7
|
+
200 => "OK",
|
|
8
|
+
201 => "Created",
|
|
9
|
+
202 => "Accepted",
|
|
10
|
+
204 => "No Content",
|
|
11
|
+
205 => "Reset Content",
|
|
12
|
+
206 => "Partial Content",
|
|
13
|
+
301 => "Moved Permanently",
|
|
14
|
+
302 => "Found",
|
|
15
|
+
304 => "Not Modified",
|
|
16
|
+
400 => "Bad Request",
|
|
17
|
+
401 => "Unauthorized",
|
|
18
|
+
402 => "Payment Required",
|
|
19
|
+
403 => "Forbidden",
|
|
20
|
+
404 => "Not Found",
|
|
21
|
+
411 => "Length Required",
|
|
22
|
+
500 => "Internal Server Error",
|
|
23
|
+
501 => "Not Implemented",
|
|
24
|
+
502 => "Bad Gateway",
|
|
25
|
+
503 => "Service Unavailable",
|
|
26
|
+
504 => "Gateway Timeout"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
HTTP_HEADER_FIELDS = [
|
|
30
|
+
'Cache-Control', 'Connection', 'Date',
|
|
31
|
+
'Pragma', 'Trailer', 'Transfer-Encoding',
|
|
32
|
+
'Accept-Ranges', 'Age', 'Etag',
|
|
33
|
+
'Server', 'Location', 'Allow',
|
|
34
|
+
'Content-Encoding', 'Content-Language', 'Content-Location',
|
|
35
|
+
'Content-MD5', 'Content-Range',
|
|
36
|
+
'Content-Type', 'Expires',
|
|
37
|
+
'Last-Modified', 'extension-header'
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
attr_accessor :header, :body, :status
|
|
41
|
+
|
|
42
|
+
def initialize
|
|
43
|
+
@header = {}
|
|
44
|
+
header['Server'] = "Invoker #{Invoker::VERSION}"
|
|
45
|
+
header['Date'] = Time.now.httpdate
|
|
46
|
+
@status = 200
|
|
47
|
+
@body = ""
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def []=(key, value)
|
|
51
|
+
header[key] = value
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def use_file_as_body(file_name)
|
|
55
|
+
if file_name && File.exists?(file_name)
|
|
56
|
+
file_content = File.read(file_name)
|
|
57
|
+
self.body = file_content
|
|
58
|
+
else
|
|
59
|
+
raise Invoker::Errors::InvalidFile, "Invalid file as body"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def http_string
|
|
64
|
+
final_string = []
|
|
65
|
+
final_string << "HTTP/1.1 #{status} #{STATUS_MAPS[status]}"
|
|
66
|
+
|
|
67
|
+
if header['Transfer-Encoding'].nil? && body.empty?
|
|
68
|
+
header['Content-Length'] = body.length
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
HTTP_HEADER_FIELDS.each do |key|
|
|
72
|
+
if value = header[key]
|
|
73
|
+
final_string << "#{key}: #{value}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
final_string.join("\r\n") + "\r\n\r\n" + body
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Invoker
|
|
2
|
+
module Power
|
|
3
|
+
# for migrating existins users to pf
|
|
4
|
+
class PfMigrate
|
|
5
|
+
def firewall_config_requires_migration?
|
|
6
|
+
return false if !Invoker.darwin?
|
|
7
|
+
# lets not migrate on osx < 10.10
|
|
8
|
+
return false if osx_version < Invoker::Version.new("14.0.0")
|
|
9
|
+
# also verify if firewall config is old
|
|
10
|
+
check_firewall_file?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def migrate
|
|
14
|
+
if firewall_config_requires_migration? && ask_user_for_migration
|
|
15
|
+
sudome
|
|
16
|
+
osx_setup = Invoker::Power::OsxSetup.new(Invoker.config.tld)
|
|
17
|
+
osx_setup.install_firewall(Invoker.config.http_port, Invoker.config.https_port)
|
|
18
|
+
drop_to_normal_user
|
|
19
|
+
Invoker::Logger.puts "Invoker has updated its configuration for yosemite."\
|
|
20
|
+
" Please restart OSX to complete the configuration process.".color(:red)
|
|
21
|
+
exit(-1)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ask_user_for_migration
|
|
26
|
+
if not_already_root?
|
|
27
|
+
Invoker::Logger.puts "Invoker has detected you are running OSX 10.10 "\
|
|
28
|
+
" but your invoker configuration does not support it."
|
|
29
|
+
Invoker::Logger.puts "Invoker can update its configuration automaticaly"\
|
|
30
|
+
" but it will require a system reboot.".color(:red)
|
|
31
|
+
Invoker::CLI::Question.agree("Update Invoker configuration (y/n) :")
|
|
32
|
+
else
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# http://jimeh.me/blog/2010/02/22/built-in-sudo-for-ruby-command-line-tools/
|
|
38
|
+
def sudome
|
|
39
|
+
if not_already_root?
|
|
40
|
+
exec("sudo #{$0} #{ARGV.join(' ')}")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def not_already_root?
|
|
45
|
+
ENV["USER"] != "root"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def drop_to_normal_user
|
|
49
|
+
EventMachine.set_effective_user(ENV["SUDO_USER"])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def osx_version
|
|
53
|
+
osx_kernel_version = `uname -r`.strip
|
|
54
|
+
Invoker::Version.new(osx_kernel_version)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def check_firewall_file?
|
|
58
|
+
return false unless File.exist?(Invoker::Power::OsxSetup::FIREWALL_PLIST_FILE)
|
|
59
|
+
firewall_contents = File.read(Invoker::Power::OsxSetup::FIREWALL_PLIST_FILE)
|
|
60
|
+
!!firewall_contents.match(/ipfw/)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|