droxy 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/droxy +46 -0
- data/droxy.gemspec +28 -0
- data/lib/droxy.rb +65 -0
- data/lib/droxy/dns_server.rb +43 -0
- data/lib/droxy/error.rb +5 -0
- data/lib/droxy/installer.rb +37 -0
- data/lib/droxy/max_age_cache.rb +23 -0
- data/lib/droxy/resolver_file.rb +28 -0
- data/lib/droxy/version.rb +3 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 344f633d38aca8537671158c97b1d29a075051ca
|
4
|
+
data.tar.gz: ca1f60bc75628f9d1c8c1f09fc97c513b0aa0131
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 75f5260349488353a406b44acfd0e686bb85ee0e051253acc68884735819b0cdf83c03f8761dd2c15164ae4222e8b48b65c3f699b79fbe29683a865aae5dd0fd
|
7
|
+
data.tar.gz: 2138c9bc3ae0ec777d6daa79729e5b58264de8500e98ba1d513b636cbc159c6287615a4a99f1e565aeae3a7fd9637e35e5f467b529327f2c9b346084948de427
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 James Dabbs
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Droxy
|
2
|
+
|
3
|
+
Like [pow](http://pow.cx/), but for [docker machines](https://docs.docker.com/machine/).
|
4
|
+
|
5
|
+
With `droxy` running, `dev.dock:3000` will resolve to `$(docker-machine ip dev):3000`.
|
6
|
+
|
7
|
+
__N.B. droxy uses /etc/resolver, and thus will likely only work on OSX__
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
One-time setup:
|
12
|
+
|
13
|
+
$ gem install droxy
|
14
|
+
$ sudo droxy install
|
15
|
+
|
16
|
+
Droxy writes a [/etc/resolver](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/resolver.5.html) file, and thus needs sudo access to install.
|
17
|
+
|
18
|
+
Once droxy is installed, run the dns server with
|
19
|
+
|
20
|
+
$ droxy start
|
21
|
+
|
22
|
+
You will, of course, need `docker-machine` installed and available.
|
23
|
+
|
24
|
+
# TODO
|
25
|
+
|
26
|
+
* Have installer write a plist file to auto-start on boot
|
27
|
+
* Some mechanism for showing errors (is the docker machine not running?)
|
28
|
+
* Better way to restart the network config after writing a resolver file?
|
29
|
+
* More Celluloid
|
30
|
+
* Port to Celluloid::DNS once it's fully extracted
|
31
|
+
* Make the ip (pre-)fetcher/cache an actor
|
data/Rakefile
ADDED
data/bin/droxy
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "droxy"
|
4
|
+
|
5
|
+
require "colorize"
|
6
|
+
require "thor"
|
7
|
+
|
8
|
+
class DroxyCLI < Thor
|
9
|
+
desc "install", "install /etc/resolver file"
|
10
|
+
method_option :tld, desc: "TLD to proxy to docker", default: "dock"
|
11
|
+
method_option :port, desc: "Port to run DNS server on", default: 20562
|
12
|
+
def install
|
13
|
+
require "droxy/installer"
|
14
|
+
|
15
|
+
Droxy::Installer.new(
|
16
|
+
tld: options[:tld],
|
17
|
+
port: options[:port]
|
18
|
+
).install
|
19
|
+
rescue Droxy::SudoRequired
|
20
|
+
ask_for_sudo __method__
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "uninstall", "uninstall /etc/resolver file"
|
24
|
+
method_option :tld, desc: "TLD to proxy to docker", default: "dock"
|
25
|
+
def uninstall
|
26
|
+
require "droxy/installer"
|
27
|
+
|
28
|
+
Droxy::Installer.new(tld: options[:tld]).uninstall
|
29
|
+
rescue Droxy::SudoRequired
|
30
|
+
ask_for_sudo __method__
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "start", "start droxy server"
|
34
|
+
method_option :tld, desc: "TLD to proxy to docker", default: "dock"
|
35
|
+
def start
|
36
|
+
Droxy::Server.new(tld: options[:tld]).run!
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def ask_for_sudo method
|
42
|
+
error "Permission denied. Please re-run #{method} with sudo.".light_red
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
DroxyCLI.start
|
data/droxy.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'droxy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "droxy"
|
8
|
+
spec.version = Droxy::VERSION
|
9
|
+
spec.authors = ["James Dabbs"]
|
10
|
+
spec.email = ["jamesdabbs@gmail.com"]
|
11
|
+
spec.summary = %q{Like pow, but for docker machines}
|
12
|
+
spec.description = %q{A small DNS server and resolver hook to route machine.dock tp $(docker-machine ip machine)}
|
13
|
+
spec.homepage = "https://github.com/jamesdabbs/droxy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "colorize"
|
22
|
+
spec.add_dependency "rubydns", "~> 1.0"
|
23
|
+
spec.add_dependency "thor", "~> 0.19"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "pry"
|
28
|
+
end
|
data/lib/droxy.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "droxy/version"
|
2
|
+
require "droxy/error"
|
3
|
+
require "droxy/max_age_cache"
|
4
|
+
require "droxy/resolver_file"
|
5
|
+
require "droxy/dns_server"
|
6
|
+
|
7
|
+
require "open3"
|
8
|
+
|
9
|
+
|
10
|
+
module Droxy
|
11
|
+
|
12
|
+
class Server
|
13
|
+
attr_reader :tld
|
14
|
+
|
15
|
+
def initialize tld:
|
16
|
+
@tld = tld
|
17
|
+
@ip_cache = MaxAgeCache.new duration: 24 * 60 * 60
|
18
|
+
|
19
|
+
@dns = DNSServer.new tld: tld, port: dns_port
|
20
|
+
end
|
21
|
+
|
22
|
+
def ip_for_name name
|
23
|
+
@ip_cache.fetch(name) { query_ip name }
|
24
|
+
end
|
25
|
+
|
26
|
+
def query_ip name
|
27
|
+
docker_machine "ip", name do |ip|
|
28
|
+
return ip.empty? ? nil : ip
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def dns_port
|
33
|
+
@_dns_port ||= ResolverFile.new(tld: tld).read_port
|
34
|
+
end
|
35
|
+
|
36
|
+
def run!
|
37
|
+
prefetch_running_ips
|
38
|
+
@dns.translate { |name| ip_for_name name }
|
39
|
+
end
|
40
|
+
|
41
|
+
def prefetch_running_ips
|
42
|
+
docker_machine "ls" do |output|
|
43
|
+
header, *machines = output.lines
|
44
|
+
col = header =~ /URL\s/
|
45
|
+
raise "Could not find URL in docker-machine output: #{output}" unless col
|
46
|
+
machines.each do |line|
|
47
|
+
name = line.split(/\s+/).first
|
48
|
+
ip = line[col..-1].split(/\s+/).first
|
49
|
+
|
50
|
+
@ip_cache.fetch(name) { URI.parse(ip).host }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def docker_machine *args, &block
|
58
|
+
Open3.popen3 "docker-machine", *args do |i,o,_,t|
|
59
|
+
return unless t.value.success?
|
60
|
+
block.call o.read.strip
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "rubydns"
|
2
|
+
|
3
|
+
module Droxy
|
4
|
+
class DNSServer
|
5
|
+
IN = Resolv::DNS::Resource::IN
|
6
|
+
|
7
|
+
attr_reader :tld, :port
|
8
|
+
|
9
|
+
def initialize tld:, port:
|
10
|
+
@tld, @port = tld, port
|
11
|
+
end
|
12
|
+
|
13
|
+
def interfaces
|
14
|
+
[ [:udp, "0.0.0.0", port], [:tcp, "0.0.0.0", port] ]
|
15
|
+
end
|
16
|
+
|
17
|
+
def translate &block
|
18
|
+
srv = self # yay, metaprogramming
|
19
|
+
RubyDNS.run_server listen: interfaces do
|
20
|
+
logger.level = Logger::INFO
|
21
|
+
|
22
|
+
match /(\w+)\.#{srv.tld}/, IN::AAAA do
|
23
|
+
next!
|
24
|
+
end
|
25
|
+
|
26
|
+
match /(\w+)\.#{srv.tld}/, IN::A do |transaction, capture|
|
27
|
+
if ip = block.call(capture[1])
|
28
|
+
transaction.respond! ip
|
29
|
+
else
|
30
|
+
next!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
otherwise { |transaction| transaction.passthrough! srv.fallback_dns }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def fallback_dns
|
39
|
+
@_fallback_dns ||= RubyDNS::Resolver.new([ [:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53] ])
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/droxy/error.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Droxy
|
2
|
+
class Installer
|
3
|
+
attr_reader :tld
|
4
|
+
|
5
|
+
def initialize tld:, port: nil
|
6
|
+
@tld, @port = tld, port
|
7
|
+
end
|
8
|
+
|
9
|
+
def port
|
10
|
+
@port || raise("Port not specified")
|
11
|
+
end
|
12
|
+
|
13
|
+
def install
|
14
|
+
ResolverFile.new(tld: tld).write port: port
|
15
|
+
reload_network_configuration
|
16
|
+
rescue Errno::EACCES
|
17
|
+
raise SudoRequired
|
18
|
+
end
|
19
|
+
|
20
|
+
def uninstall
|
21
|
+
ResolverFile.new(tld: tld).remove
|
22
|
+
reload_network_configuration
|
23
|
+
rescue Errno::EACCES
|
24
|
+
raise SudoRequired
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def reload_network_configuration
|
30
|
+
location = `networksetup -getcurrentlocation`
|
31
|
+
`networksetup -createlocation "droxy$$" >/dev/null 2>&1`
|
32
|
+
`networksetup -switchtolocation "droxy$$" >/dev/null 2>&1`
|
33
|
+
`networksetup -switchtolocation "#{location}" >/dev/null 2>&1`
|
34
|
+
`networksetup -deletelocation "droxy$$" >/dev/null 2>&1`
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Droxy
|
2
|
+
class MaxAgeCache
|
3
|
+
Entry = Struct.new :value, :created
|
4
|
+
|
5
|
+
attr_reader :duration
|
6
|
+
|
7
|
+
def initialize duration:
|
8
|
+
@duration, @store = duration, {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch key, &block
|
12
|
+
unless acceptable? @store[key]
|
13
|
+
@store[key] = Entry.new block.call, Time.now
|
14
|
+
end
|
15
|
+
@store[key].value
|
16
|
+
end
|
17
|
+
|
18
|
+
def acceptable? entry
|
19
|
+
return false if entry.nil? || entry.value.nil?
|
20
|
+
Time.now - entry.created < duration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Droxy
|
2
|
+
class ResolverFile
|
3
|
+
attr_reader :tld
|
4
|
+
|
5
|
+
def initialize tld:
|
6
|
+
@tld = tld
|
7
|
+
end
|
8
|
+
|
9
|
+
def path
|
10
|
+
"/etc/resolver/#{tld}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def write port:
|
14
|
+
File.write path, <<-EOF
|
15
|
+
nameserver 127.0.0.1
|
16
|
+
port #{port}
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove
|
21
|
+
FileUtils.rm path
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_port
|
25
|
+
@_read_port ||= File.read(path) =~ /^port (\d+)/ && Integer($1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: droxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Dabbs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubydns
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.19'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.19'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: A small DNS server and resolver hook to route machine.dock tp $(docker-machine
|
98
|
+
ip machine)
|
99
|
+
email:
|
100
|
+
- jamesdabbs@gmail.com
|
101
|
+
executables:
|
102
|
+
- droxy
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- ".gitignore"
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/droxy
|
112
|
+
- droxy.gemspec
|
113
|
+
- lib/droxy.rb
|
114
|
+
- lib/droxy/dns_server.rb
|
115
|
+
- lib/droxy/error.rb
|
116
|
+
- lib/droxy/installer.rb
|
117
|
+
- lib/droxy/max_age_cache.rb
|
118
|
+
- lib/droxy/resolver_file.rb
|
119
|
+
- lib/droxy/version.rb
|
120
|
+
homepage: https://github.com/jamesdabbs/droxy
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
metadata: {}
|
124
|
+
post_install_message:
|
125
|
+
rdoc_options: []
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 2.4.5
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Like pow, but for docker machines
|
144
|
+
test_files: []
|