invoker 1.4.1 → 1.5.1

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +0 -1
  4. data/.travis.yml +4 -2
  5. data/Dockerfile +7 -0
  6. data/Gemfile +3 -0
  7. data/Rakefile +8 -0
  8. data/examples/hello_sinatra.rb +26 -0
  9. data/examples/sample.ini +3 -0
  10. data/invoker.gemspec +2 -1
  11. data/lib/invoker.rb +20 -3
  12. data/lib/invoker/cli.rb +32 -6
  13. data/lib/invoker/dns_cache.rb +2 -2
  14. data/lib/invoker/ipc/add_http_command.rb +1 -1
  15. data/lib/invoker/ipc/dns_check_command.rb +2 -1
  16. data/lib/invoker/ipc/message.rb +2 -2
  17. data/lib/invoker/parsers/config.rb +4 -1
  18. data/lib/invoker/power/balancer.rb +16 -4
  19. data/lib/invoker/power/config.rb +3 -2
  20. data/lib/invoker/power/dns.rb +1 -1
  21. data/lib/invoker/power/pf_migrate.rb +1 -1
  22. data/lib/invoker/power/setup.rb +43 -4
  23. data/lib/invoker/power/setup/distro/arch.rb +1 -4
  24. data/lib/invoker/power/setup/distro/base.rb +23 -21
  25. data/lib/invoker/power/setup/distro/debian.rb +1 -1
  26. data/lib/invoker/power/setup/distro/opensuse.rb +11 -0
  27. data/lib/invoker/power/setup/distro/redhat.rb +1 -7
  28. data/lib/invoker/power/setup/files/invoker_forwarder.sh.erb +17 -0
  29. data/lib/invoker/power/setup/files/socat_invoker.service +12 -0
  30. data/lib/invoker/power/setup/linux_setup.rb +46 -29
  31. data/lib/invoker/power/setup/osx_setup.rb +16 -28
  32. data/lib/invoker/power/url_rewriter.rb +6 -3
  33. data/lib/invoker/process_manager.rb +13 -7
  34. data/lib/invoker/version.rb +1 -1
  35. data/readme.md +4 -4
  36. data/spec/invoker/commander_spec.rb +19 -8
  37. data/spec/invoker/config_spec.rb +22 -27
  38. data/spec/invoker/invoker_spec.rb +2 -1
  39. data/spec/invoker/ipc/client_handler_spec.rb +11 -1
  40. data/spec/invoker/power/config_spec.rb +2 -1
  41. data/spec/invoker/power/pf_migrate_spec.rb +7 -0
  42. data/spec/invoker/power/setup/linux_setup_spec.rb +57 -9
  43. data/spec/invoker/power/setup/osx_setup_spec.rb +22 -8
  44. data/spec/invoker/power/url_rewriter_spec.rb +33 -1
  45. data/spec/invoker/power/web_sockets_spec.rb +61 -0
  46. data/spec/invoker/process_manager_spec.rb +34 -2
  47. data/spec/spec_helper.rb +12 -16
  48. metadata +27 -35
  49. data/spec/support/mock_setup_file.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6fe046d5488f7cd2fe7b7aa6b10df51a0e7b3801
4
- data.tar.gz: d9e3cf26e7bab5677a9fa6d6739ada78a6d79304
3
+ metadata.gz: 35e208abbd4ff8979f1d1ecc0c5896ef3b460799
4
+ data.tar.gz: 6e2e65d581a9705f5358bf8076654a9b34185683
5
5
  SHA512:
6
- metadata.gz: 6119c3f2f8c620956833ffa74af58161d8480dbe296c616cd2366242d3b145c62e8c7b88fb514440bd7772fc56b8c86e84888cc7455e3e1d068dc1bd4cd2e190
7
- data.tar.gz: 65351289ad3f5f5fea61ed8600ffaa03a6306c3592fbe504eb76604d1d0939692c35fc7aea014f11a36dec120e976c90c0ad8de04257a45d8fd4796e6a35c3f6
6
+ metadata.gz: 44eecb467482053d584410fbc279c192e1dc25b7c97f245bf058f20e7bac0a12d9c0c73487d0ab0652d632030ef3f39741449dd5d30391104ef4ec9cc165091f
7
+ data.tar.gz: a4108aab6742c8b02886423a341c2d59c47deba5645d73b671686aff4cac4f7af668677645bb5444b8d37fe260afa8e05631ca249ba9d41f6bc9396426534a30
data/.gitignore CHANGED
@@ -2,7 +2,6 @@ invoker.ini
2
2
  config/
3
3
  *.gem
4
4
  pkg/
5
- *.ini
6
5
  tags
7
6
  .rvmrc
8
7
  vendor/
@@ -1,5 +1,4 @@
1
1
  AllCops:
2
- RunRailsCops: false
3
2
  Excludes:
4
3
  - db/**
5
4
 
@@ -1,8 +1,10 @@
1
1
  language: ruby
2
+ cache: bundler
3
+ sudo: false
2
4
  rvm:
3
- - 1.9.3
4
5
  - 2.0.0
5
6
  - 2.1.0
7
+ - 2.2.0
8
+ - 2.3.0
6
9
 
7
10
  script: bundle exec rake spec
8
-
@@ -0,0 +1,7 @@
1
+ FROM ruby:2.3
2
+
3
+ MAINTAINER hemant@codemancers.com
4
+
5
+ RUN apt-get update && apt-get -y install dnsmasq socat
6
+
7
+ CMD cd /invoker && bundle install --path vendor/ && bundle exec rake spec
data/Gemfile CHANGED
@@ -2,6 +2,9 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'websocket-eventmachine-server', require: false
6
+ gem 'websocket-eventmachine-client', require: false
7
+
5
8
  group :development do
6
9
  gem 'pry'
7
10
  gem 'tins', '~>1.4.0'
data/Rakefile CHANGED
@@ -5,3 +5,11 @@ RSpec::Core::RakeTask.new
5
5
 
6
6
  task :default => :spec
7
7
  task :test => :spec
8
+
9
+ current_directory = File.expand_path(File.dirname(__FILE__))
10
+
11
+ desc "run specs inside docker"
12
+ task :docker_spec do
13
+ system("docker build -t invoker-ruby . ")
14
+ system("docker run --name invoker-rspec --rm -v #{current_directory}:/invoker -t invoker-ruby")
15
+ end
@@ -0,0 +1,26 @@
1
+ # myapp.rb
2
+ require 'sinatra'
3
+
4
+ get '/' do
5
+ 'Hello world!'
6
+ end
7
+
8
+ get "/emacs" do
9
+ redirect to("/vim")
10
+ end
11
+
12
+ get "/vim" do
13
+ "vim rules"
14
+ end
15
+
16
+
17
+ post '/foo' do
18
+ puts request.env
19
+ "done"
20
+ end
21
+
22
+
23
+ post "/api/v1/datapoints" do
24
+ puts request.env
25
+ "done"
26
+ end
@@ -0,0 +1,3 @@
1
+ [rails]
2
+ directory = ./examples
3
+ command = ruby hello_sinatra.rb -p $PORT
@@ -35,8 +35,9 @@ Gem::Specification.new do |s|
35
35
  s.add_dependency("uuid", "~> 2.3")
36
36
  s.add_dependency("facter", "~> 2.2")
37
37
  s.add_dependency("http-parser-lite", "~> 0.6")
38
- s.add_dependency("dotenv", "~> 1.0.2")
38
+ s.add_dependency("dotenv", "~> 2.0")
39
39
  s.add_development_dependency("rspec", "~> 3.0")
40
40
  s.add_development_dependency("mocha")
41
41
  s.add_development_dependency("rake")
42
+ s.add_development_dependency('fakefs')
42
43
  end
@@ -44,6 +44,10 @@ module Invoker
44
44
  ruby_platform.downcase.include?("darwin")
45
45
  end
46
46
 
47
+ def linux?
48
+ ruby_platform.downcase.include?("linux")
49
+ end
50
+
47
51
  def ruby_platform
48
52
  RUBY_PLATFORM
49
53
  end
@@ -100,18 +104,27 @@ module Invoker
100
104
  end
101
105
 
102
106
  def notify_user(message)
103
- run_without_bundler { check_and_notify_with_terminal_notifier(message) }
107
+ if Invoker.darwin?
108
+ run_without_bundler { check_and_notify_with_terminal_notifier(message) }
109
+ elsif Invoker.linux?
110
+ notify_with_libnotify(message)
111
+ end
104
112
  end
105
113
 
106
114
  def check_and_notify_with_terminal_notifier(message)
107
- return unless Invoker.darwin?
108
-
109
115
  command_path = `which terminal-notifier`
110
116
  if command_path && !command_path.empty?
111
117
  system("terminal-notifier -message '#{message}' -title Invoker")
112
118
  end
113
119
  end
114
120
 
121
+ def notify_with_libnotify(message)
122
+ begin
123
+ require "libnotify"
124
+ Libnotify.show(body: message, summary: "Invoker", timeout: 2.5)
125
+ rescue LoadError; end
126
+ end
127
+
115
128
  def migrate_old_config(old_config, config_location)
116
129
  new_config = File.join(config_location, 'config')
117
130
  File.open(new_config, 'w') do |file|
@@ -131,5 +144,9 @@ module Invoker
131
144
  Etc.getpwuid(Process.uid).dir
132
145
  end
133
146
  end
147
+
148
+ def default_tld
149
+ 'dev'
150
+ end
134
151
  end
135
152
  end
@@ -13,8 +13,11 @@ module Invoker
13
13
  end
14
14
 
15
15
  desc "setup", "Run Invoker setup"
16
+ option :tld,
17
+ type: :string,
18
+ banner: 'Configure invoker to use a different top level domain'
16
19
  def setup
17
- Invoker::Power::Setup.install
20
+ Invoker::Power::Setup.install(get_tld(options))
18
21
  end
19
22
 
20
23
  desc "version", "Print Invoker version"
@@ -39,7 +42,7 @@ module Invoker
39
42
  port = options[:port] || 9000
40
43
  Invoker.daemonize = options[:daemon]
41
44
  Invoker.load_invoker_config(file, port)
42
- warn_about_terminal_notifier
45
+ warn_about_notification
43
46
  warn_about_old_configuration
44
47
  pinger = Invoker::CLI::Pinger.new(unix_socket)
45
48
  abort("Invoker is already running".color(:red)) if pinger.invoker_running?
@@ -51,9 +54,9 @@ module Invoker
51
54
  unix_socket.send_command('add', process_name: name)
52
55
  end
53
56
 
54
- desc "add_http process_name port", "Add an external http process to Invoker DNS server"
55
- def add_http(name, port)
56
- unix_socket.send_command('add_http', process_name: name, port: port)
57
+ desc "add_http process_name port [IP]", "Add an external http process to Invoker DNS server"
58
+ def add_http(name, port, ip = nil)
59
+ unix_socket.send_command('add_http', process_name: name, port: port, ip: ip)
57
60
  end
58
61
 
59
62
  desc "tail process1 process2", "Tail a particular process"
@@ -105,12 +108,35 @@ module Invoker
105
108
  tasks.keys + ["help"]
106
109
  end
107
110
 
111
+ def get_tld(options)
112
+ if options[:tld] && !options[:tld].empty?
113
+ options[:tld]
114
+ else
115
+ 'dev'
116
+ end
117
+ end
118
+
108
119
  def unix_socket
109
120
  Invoker::IPC::UnixClient.new
110
121
  end
111
122
 
123
+ def warn_about_notification
124
+ if Invoker.darwin?
125
+ warn_about_terminal_notifier
126
+ else
127
+ warn_about_libnotify
128
+ end
129
+ end
130
+
131
+ def warn_about_libnotify
132
+ require "libnotify"
133
+ rescue LoadError
134
+ Invoker::Logger.puts "You can install libnotify gem for Invoker notifications "\
135
+ "via system tray".color(:red)
136
+ end
137
+
112
138
  def warn_about_terminal_notifier
113
- if RUBY_PLATFORM.downcase.include?("darwin")
139
+ if Invoker.darwin?
114
140
  command_path = `which terminal-notifier`
115
141
  if !command_path || command_path.empty?
116
142
  Invoker::Logger.puts "You can enable OSX notification for processes "\
@@ -16,8 +16,8 @@ module Invoker
16
16
  @dns_mutex.synchronize { dns_data[process_name] }
17
17
  end
18
18
 
19
- def add(name, port)
20
- @dns_mutex.synchronize { dns_data[name] = { 'port' => port } }
19
+ def add(name, port, ip = nil)
20
+ @dns_mutex.synchronize { dns_data[name] = { 'port' => port, 'ip' => ip } }
21
21
  end
22
22
  end
23
23
  end
@@ -2,7 +2,7 @@ module Invoker
2
2
  module IPC
3
3
  class AddHttpCommand < BaseCommand
4
4
  def run_command(message_object)
5
- Invoker.dns_cache.add(message_object.process_name, message_object.port)
5
+ Invoker.dns_cache.add(message_object.process_name, message_object.port, message_object.ip)
6
6
  true
7
7
  end
8
8
  end
@@ -6,7 +6,8 @@ module Invoker
6
6
 
7
7
  dns_check_response = Invoker::IPC::Message::DnsCheckResponse.new(
8
8
  process_name: message_object.process_name,
9
- port: process_detail ? process_detail['port'] : nil
9
+ port: process_detail ? process_detail['port'] : nil,
10
+ ip: process_detail && process_detail['ip'] ? process_detail['ip'] : '0.0.0.0'
10
11
  )
11
12
  send_data(dns_check_response)
12
13
  true
@@ -118,7 +118,7 @@ module Invoker
118
118
 
119
119
  class AddHttp < Base
120
120
  include Serialization
121
- message_attributes :process_name, :port
121
+ message_attributes :process_name, :port, :ip
122
122
  end
123
123
 
124
124
  class Reload < Base
@@ -151,7 +151,7 @@ module Invoker
151
151
 
152
152
  class DnsCheckResponse < Base
153
153
  include Serialization
154
- message_attributes :process_name, :port
154
+ message_attributes :process_name, :port, :ip
155
155
  end
156
156
 
157
157
  class Ping < Base
@@ -16,7 +16,6 @@ module Invoker
16
16
  # value by 1, that way generating different ports for different commands.
17
17
  def initialize(filename, port)
18
18
  @filename = filename || autodetect_config_file
19
-
20
19
  print_message_and_abort if invalid_config_file?
21
20
 
22
21
  @port = port - 1
@@ -38,6 +37,10 @@ module Invoker
38
37
  power_config && power_config.https_port
39
38
  end
40
39
 
40
+ def tld
41
+ power_config && power_config.tld
42
+ end
43
+
41
44
  def autorunnable_processes
42
45
  processes.reject(&:disable_autorun)
43
46
  end
@@ -22,7 +22,7 @@ module Invoker
22
22
  end
23
23
 
24
24
  class Balancer
25
- attr_accessor :connection, :http_parser, :session, :protocol
25
+ attr_accessor :connection, :http_parser, :session, :protocol, :upgraded_to
26
26
 
27
27
  def self.run(options = {})
28
28
  start_http_proxy(InvokerHttpProxy, 'http', options)
@@ -43,6 +43,7 @@ module Invoker
43
43
  @protocol = protocol
44
44
  @http_parser = HttpParser.new(protocol)
45
45
  @session = nil
46
+ @upgraded_to = nil
46
47
  @buffer = []
47
48
  end
48
49
 
@@ -71,7 +72,7 @@ module Invoker
71
72
 
72
73
  dns_check_response = UrlRewriter.new.select_backend_config(headers['Host'])
73
74
  if dns_check_response && dns_check_response.port
74
- connection.server(session, host: '0.0.0.0', port: dns_check_response.port)
75
+ connection.server(session, host: dns_check_response.ip, port: dns_check_response.port)
75
76
  else
76
77
  return_error_page(404)
77
78
  http_parser.reset
@@ -80,8 +81,12 @@ module Invoker
80
81
  end
81
82
 
82
83
  def upstream_data(data)
83
- append_for_http_parsing(data)
84
- nil
84
+ if upgraded_to == "websocket"
85
+ data
86
+ else
87
+ append_for_http_parsing(data)
88
+ nil
89
+ end
85
90
  end
86
91
 
87
92
  def append_for_http_parsing(data)
@@ -93,6 +98,13 @@ module Invoker
93
98
 
94
99
  def backend_data(backend, data)
95
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
+
96
108
  data
97
109
  end
98
110
 
@@ -60,9 +60,10 @@ module Invoker
60
60
  def dns_port; @config[:dns_port]; end
61
61
  def http_port; @config[:http_port]; end
62
62
  def ipfw_rule_number; @config[:ipfw_rule_number]; end
63
+ def https_port; @config[:https_port]; end
63
64
 
64
- def https_port
65
- @config[:https_port]
65
+ def tld
66
+ @config[:tld] || Invoker.default_tld
66
67
  end
67
68
 
68
69
  def save
@@ -31,7 +31,7 @@ module Invoker
31
31
  end
32
32
 
33
33
  def name_matches?(name)
34
- name =~ /.*\.dev/
34
+ name =~ /.*\.#{Invoker.config.tld}/
35
35
  end
36
36
  end
37
37
  end
@@ -13,7 +13,7 @@ module Invoker
13
13
  def migrate
14
14
  if firewall_config_requires_migration? && ask_user_for_migration
15
15
  sudome
16
- osx_setup = Invoker::Power::OsxSetup.new()
16
+ osx_setup = Invoker::Power::OsxSetup.new(Invoker.config.tld)
17
17
  osx_setup.install_firewall(Invoker.config.http_port, Invoker.config.https_port)
18
18
  drop_to_normal_user
19
19
  Invoker::Logger.puts "Invoker has updated its configuration for yosemite."\
@@ -3,15 +3,17 @@ require "eventmachine"
3
3
  module Invoker
4
4
  module Power
5
5
  class Setup
6
- attr_accessor :port_finder
7
- def self.install
6
+ attr_accessor :port_finder, :tld
7
+
8
+ def self.install(tld)
8
9
  selected_installer_klass = installer_klass
9
- selected_installer_klass.new.install
10
+ selected_installer_klass.new(tld).install
10
11
  end
11
12
 
12
13
  def self.uninstall
14
+ power_config = Invoker::Power::Config.load_config
13
15
  selected_installer_klass = installer_klass
14
- selected_installer_klass.new.uninstall_invoker
16
+ selected_installer_klass.new(power_config.tld).uninstall_invoker
15
17
  end
16
18
 
17
19
  def self.installer_klass
@@ -22,6 +24,14 @@ module Invoker
22
24
  end
23
25
  end
24
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
+
25
35
  def install
26
36
  if check_if_setup_can_run?
27
37
  setup_invoker
@@ -46,6 +56,35 @@ module Invoker
46
56
  def check_if_setup_can_run?
47
57
  !File.exists?(Invoker::Power::Config.config_file)
48
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
49
88
  end
50
89
  end
51
90
  end