meepo 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|