vagrant-dnsdock-hostupdater 0.0.23 → 0.0.24

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: 024acc29cae06921872cb4dcd8ffae03c9d3651e
4
- data.tar.gz: 9e7f158d7030a282d9daab8a51358bc0120f07f5
3
+ metadata.gz: a0dced9da0ff736e5641dd7d6e5e0154f9db87a4
4
+ data.tar.gz: ab09fc9827e6618275ca8eb3d86fc8d0f6c0afa6
5
5
  SHA512:
6
- metadata.gz: cf9a3f80dc458ef8323318bf49bc01eac8d4a0dd314f086c73afc2ad04fa5f1d01ef44bfcb72ed0e0c38d0a2b7aff86044423d104520f0254abcbcde0614c49b
7
- data.tar.gz: 2f222d9b676aefc501715f5b8afcf2a027d7f5fc76c984d6bd04b9a99887e758465b55796cedc382cba27a3f4bde1a44409bb0cc69f0017e798d69d229060f57
6
+ metadata.gz: 8c9a89a41498583338779437ed08ca5b08a3fc313b20ae7f2f75194b8fdbd4a6b4c030de210b76eac59c93c1829b49f2b1dc2872fb31669ef46737bead77e954
7
+ data.tar.gz: b8fac1c93d16df2f9f056ae1c990fb364156e339599fc7c00b49fc3e45269fe62f6246cba578af698cdfd29e9d120dc343bcf209307fca7d476ebbd9f6e2b407
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- vagrant-dnsdock-hostupdater (0.0.23)
4
+ vagrant-dnsdock-hostupdater (0.0.24)
5
5
  docker-api (~> 1.33)
6
6
  linebreak (~> 2.1.0)
7
7
  log4r (~> 1.1.10)
data/lib/client.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative 'host-manager'
2
+
3
+ HostManager::Client
4
+ .create('192.168.200.1', 2991)
@@ -0,0 +1,51 @@
1
+ require_relative 'host-manager'
2
+ require 'yaml'
3
+ require 'pp'
4
+
5
+ module HostManager
6
+ class DockerEvent
7
+
8
+ def self.update(ip, port, host_suffix)
9
+ client = HostManager::Client.create(ip, port)
10
+ client.host_suffix host_suffix
11
+ client.sync_hosts Docker::Container.all({:all => true})
12
+ client.close
13
+ end
14
+
15
+ def self.run(ip, port, host_suffix)
16
+ # sync existing host entries on start (normally this will remove old left-over entries)
17
+ self.update(ip, port, host_suffix)
18
+
19
+ sleep(2)
20
+ loop {
21
+ run_once(ip, port, host_suffix)
22
+ }
23
+ end
24
+
25
+ private
26
+ def self.run_once(ip, port, host_suffix)
27
+ begin
28
+ Docker::Event.stream { |event|
29
+ HostManager.log.info 'Connected to docker socket. Listening for events.'
30
+ # respond to all container events
31
+
32
+ begin
33
+ if event.type == 'container' && %w(start die).include?(event.action)
34
+ self.update(ip, port, host_suffix)
35
+ end
36
+
37
+ rescue => e
38
+ puts e.inspect
39
+ end
40
+
41
+ break
42
+ }
43
+
44
+ rescue Docker::Error::TimeoutError
45
+ HostManager.log.info 'Docker socket connection timed out whilst listening for events. Reconnecting...'
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ HostManager::DockerEvent.run('192.168.200.1', 2991, '.local.signal.sh')
@@ -0,0 +1,298 @@
1
+ require 'socket' # Get sockets from stdlib
2
+ require 'json'
3
+ require_relative 'hosts/hosts'
4
+ require 'docker'
5
+ require 'logger'
6
+ require 'log4r'
7
+
8
+ module OS
9
+ def OS.windows?
10
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
11
+ end
12
+
13
+ def OS.mac?
14
+ (/darwin/ =~ RUBY_PLATFORM) != nil
15
+ end
16
+
17
+ def OS.unix?
18
+ !OS.windows?
19
+ end
20
+
21
+ def OS.linux?
22
+ OS.unix? and not OS.mac?
23
+ end
24
+ end
25
+
26
+ module HostManager
27
+
28
+ def self.log
29
+ unless @log
30
+ @log = Log4r::Logger.new('main')
31
+ @log.outputters << Log4r::Outputter.stdout
32
+ @log.outputters << Log4r::FileOutputter.new('logmain', :filename => 'host-manager.log')
33
+ end
34
+
35
+ @log
36
+ end
37
+
38
+ def self.comment_prefix
39
+ 'Managed by Vagrant plugin - do not remove.'
40
+ end
41
+
42
+ def self.host_file_path
43
+ OS.windows? ? `echo %SystemRoot%\\System32\\drivers\\etc\\hosts`.chomp : '/etc/hosts'
44
+ end
45
+
46
+ class Base
47
+
48
+ def log
49
+ HostManager.log
50
+ end
51
+
52
+ def host_name(container_name)
53
+ if container_name.include?('.')
54
+ container_name
55
+ else
56
+ sanitize_host_value(container_name) + host_suffix
57
+ end
58
+ end
59
+
60
+ def compose_host_names(container)
61
+ names = []
62
+ labels = container.info['Config']['Labels']
63
+
64
+ name = labels['com.docker.compose.project']
65
+ service = labels['com.docker.compose.service']
66
+
67
+
68
+ if name != nil && service != nil
69
+ service = sanitize_host_value(service)
70
+ name = sanitize_host_value(name)
71
+
72
+ container_num = labels['com.docker.compose.container-number']
73
+ if container_num == '1'
74
+ names.push("#{service}.#{name}#{host_suffix}")
75
+ else
76
+ names.push("#{service}-#{container_num}.#{name}#{host_suffix}")
77
+ end
78
+ else
79
+ names.push(host_name(container.info['Name']))
80
+ end
81
+
82
+ names
83
+ end
84
+
85
+ def host_suffix(suffix = nil)
86
+ if suffix != nil
87
+ @domain_suffix = suffix
88
+ else
89
+ @domain_suffix
90
+ end
91
+ end
92
+
93
+ # Determine if entry is managed by this utility or not
94
+ def valid_entry?(element)
95
+ # check it's a managed host first
96
+ if element.respond_to?(:comment) && element.comment.to_s.start_with?(HostManager.comment_prefix)
97
+ # check we have hostname and ip
98
+ if element.respond_to?(:name) && element.respond_to?(:address)
99
+ return true
100
+ end
101
+ end
102
+ end
103
+
104
+ def get_hosts
105
+ unless @host_manager
106
+ @host_manager = Hosts::File.read(HostManager.host_file_path)
107
+ end
108
+
109
+ @host_manager
110
+ end
111
+
112
+ def build_hosts_data(container_data)
113
+ data = []
114
+
115
+ if container_data && container_data.is_a?(Array)
116
+ container_data.each do |container_info|
117
+ container = Docker::Container.get(container_info.info['id'])
118
+
119
+ if container.info['State']['Running']
120
+ name = container.info['Name']
121
+
122
+ if name
123
+ ip = container.info['NetworkSettings']['IPAddress']
124
+
125
+ if ip
126
+ compose_host_names(container).each do |hostname|
127
+ item = {
128
+ :hostname => hostname,
129
+ :ip => ip,
130
+ :containerId => container.info['id']
131
+ }
132
+
133
+ data.push(item)
134
+ end
135
+ else
136
+ log.warn("Ignored request to create hosts entry due to no IP being returned from container: #{name}")
137
+ end
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+
144
+ data
145
+ end
146
+
147
+ def update_hosts_file(data)
148
+ if data.is_a?(Hash)
149
+ required_keys = %w(action hostname ip containerId)
150
+ required_keys.each do |key|
151
+ unless data.key?(key)
152
+ raise "Data for key #{key} not provided."
153
+ end
154
+ end
155
+ execute(data['action'], data['hostname'], data['ip'], data['containerId'])
156
+
157
+ elsif data.is_a?(Array)
158
+ hosts = get_hosts
159
+
160
+ # initially remove all entries
161
+ hosts.elements.delete_if do |element|
162
+ if valid_entry?(element)
163
+ log.info 'Removing entry for ' + element.name
164
+ true
165
+ end
166
+ end
167
+
168
+ # add recieved entries
169
+ data.each do |entry|
170
+ add_entry(entry, hosts)
171
+ hosts.write
172
+ end
173
+
174
+ hosts.write
175
+
176
+ end
177
+ end
178
+
179
+ def add_entry(entry, hosts)
180
+ if entry[:ip] && entry[:containerId] && entry[:hostname]
181
+ comment = HostManager.comment_prefix + (entry['containerId'] ? " Container ID: #{entry[:containerId]}" : '')
182
+ log.info "Adding entry: #{entry[:hostname]} => #{entry[:ip]}"
183
+ hosts.elements << Hosts::Entry.new(entry[:ip], entry[:hostname], :comment => comment)
184
+
185
+ else
186
+ log.warn 'Unable to write entry due to missing values [ip,containerId,hostname]: ' + entry.to_json
187
+ end
188
+ end
189
+
190
+ def execute(action, hostname, ip, container_id = nil)
191
+ hosts = get_hosts
192
+
193
+ if action == 'create'
194
+ hosts.elements.each do |element|
195
+ if valid_entry?(element) && hostname == element.name
196
+ raise "Entry already exists! (#{ip} #{hostname})"
197
+ end
198
+ end
199
+
200
+ comment = HostManager.comment_prefix + (container_id ? " Container ID: #{container_id}" : '')
201
+
202
+ hosts.elements << Hosts::Entry.new(ip, hostname, :comment => comment)
203
+ hosts.write
204
+
205
+ elsif action == 'delete'
206
+ hosts.elements.delete_if do |element|
207
+ if valid_entry?(element)
208
+ if hostname == element.name
209
+ log.info 'Removing entry for ' + element.name
210
+ true
211
+ end
212
+ end
213
+ end
214
+
215
+ hosts.write
216
+ else
217
+ raise 'No valid action specified.'
218
+ end
219
+ end
220
+
221
+ private
222
+
223
+ def sanitize_host_value(value)
224
+ value.sub(/^\//, '').gsub(/_/, '-')
225
+ end
226
+
227
+ end
228
+
229
+ class Server < Base
230
+ def run(ip, port)
231
+ HostManager.log.info "Running on host manager service on #{ip}:#{port}"
232
+ @tcp_server = TCPServer.new ip, port
233
+
234
+ loop {
235
+
236
+ client = @tcp_server.accept
237
+ content = client.gets
238
+
239
+ log.debug("Recieved data: #{content.to_s.strip}")
240
+
241
+ begin
242
+ unless content.to_s.chomp.strip.empty?
243
+ data = JSON.parse(content)
244
+ update_hosts_file(data)
245
+ end
246
+
247
+ rescue => e
248
+ log.error("Caught exception attempting to execute with data #{content}. #{e}")
249
+ end
250
+
251
+ client.close
252
+ }
253
+
254
+ end
255
+
256
+ def self.create(ip, port)
257
+ server = self.new
258
+ server.run(ip, port)
259
+ end
260
+ end
261
+
262
+ class Client < Base
263
+
264
+ def initialize(ip, port)
265
+ @socket = TCPSocket.new(ip, port)
266
+ end
267
+
268
+ def close
269
+ log.info('Closing client connection.')
270
+ @socket.close
271
+ end
272
+
273
+ def sync_hosts(container_data)
274
+ data = build_hosts_data(container_data)
275
+
276
+ begin
277
+ update_hosts_file(data)
278
+
279
+ `service dnsmasq restart`
280
+
281
+ rescue => e
282
+ log.error("Caught exception attempting to write to hosts file with data #{data.to_json}. #{e}")
283
+ end
284
+
285
+ send(data)
286
+ end
287
+
288
+ def send(data)
289
+ log.info("Sending data via client: #{data.to_json}")
290
+ @socket.write data.to_json + "\n"
291
+ end
292
+
293
+ def self.create(ip, port)
294
+ self.new(ip, port)
295
+ end
296
+ end
297
+
298
+ end
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+ # vi: set ft=ruby :
4
+ require 'docker'
5
+ require 'yaml'
6
+
7
+
8
+ # build up hash of id => project name
9
+ id_project_hash = {}
10
+ Docker::Container.all(all: true, filters: { status: ["running"] }.to_json).each do |container|
11
+ # puts container.info['id']
12
+ # puts container.info['Labels']['com.docker.compose.project'].inspect
13
+
14
+ id_project_hash[container.info['id']] = container.info['Labels']['com.docker.compose.project']
15
+ # puts container.info['NetworkSettings']['IPAddress']
16
+ # puts container.info.to_yaml
17
+ end
18
+
19
+
20
+ module HostManager
21
+ def self.register(hostname, ip)
22
+ entry = "#{ip} #{hostname}"
23
+ puts entry
24
+ end
25
+ end
26
+
27
+ Docker::Network.all.each do |network|
28
+ # puts network.info['Options'].inspect
29
+ # puts network.inspect
30
+ network.info['Containers'].each do |pair|
31
+ id = pair[0]
32
+ container = pair[1]
33
+ ip = container['IPv4Address'][/[^\/]+/]
34
+ if id_project_hash.key?(id) and id_project_hash[id]
35
+ project_name = id_project_hash[id]
36
+ HostManager.register("#{container['Name']}.#{project_name}.local", ip)
37
+ elsif
38
+ HostManager.register("#{container['Name']}.local", ip)
39
+ end
40
+ end
41
+ end
42
+
43
+ # Docker::Event.stream { |event|
44
+ # # respond to all events
45
+ # puts event.Attributes.name;
46
+ # }
data/lib/server.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'host-manager'
2
+
3
+ HostManager::Server.create('0.0.0.0', 2991)
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+
3
+ begin
4
+ require 'vagrant'
5
+ rescue LoadError
6
+ Bundler.require(:default, :development)
7
+ end
8
+
9
+ require 'vagrant-dnsdock-hostupdater/plugin'
10
+ require 'vagrant-dnsdock-hostupdater/command'
data/lib/version.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Vagrant
2
+ module DnsdockHostUpdater
3
+ VERSION = '0.0.24'.freeze
4
+ end
5
+ end
@@ -11,9 +11,9 @@ DNSDock should be configured on the guest machine to enable containers to resolv
11
11
  DESCRIPTION
12
12
  s.authors = ['Brian Coit']
13
13
  s.email = 'brian.coit@cellosignal.com'
14
- s.files = Dir['{lib}'] + ['Rakefile', 'Gemfile', 'Gemfile.lock', 'vagrant-dnsdock-hostupdater.gemspec']
14
+ s.files = Dir['{lib}/**'] + ['Rakefile', 'Gemfile', 'Gemfile.lock', 'vagrant-dnsdock-hostupdater.gemspec']
15
15
  s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
- s.require_paths = ['lib/**']
16
+ s.require_paths = ['lib']
17
17
  s.homepage = 'https://bitbucket.org/briancoit'
18
18
  s.license = 'ISC'
19
19
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-dnsdock-hostupdater
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.23
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Coit
@@ -64,6 +64,13 @@ files:
64
64
  - Gemfile
65
65
  - Gemfile.lock
66
66
  - Rakefile
67
+ - lib/client.rb
68
+ - lib/event-watcher.rb
69
+ - lib/host-manager.rb
70
+ - lib/launch-control
71
+ - lib/server.rb
72
+ - lib/vagrant-dnsdock-hostupdater.rb
73
+ - lib/version.rb
67
74
  - vagrant-dnsdock-hostupdater.gemspec
68
75
  homepage: https://bitbucket.org/briancoit
69
76
  licenses:
@@ -72,7 +79,7 @@ metadata: {}
72
79
  post_install_message:
73
80
  rdoc_options: []
74
81
  require_paths:
75
- - lib/**
82
+ - lib
76
83
  required_ruby_version: !ruby/object:Gem::Requirement
77
84
  requirements:
78
85
  - - ">="