vagrant-dnsdock-hostupdater 0.0.10

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9c1d494bc348ad4bf14e33a49b68878e9089ad25
4
+ data.tar.gz: f58089650e77004454d1c56d7beec701dc534b96
5
+ SHA512:
6
+ metadata.gz: 716cdb7352cd498a5636712a6e488e713ee80ef8ba6dacad2a7e23b0c86a8641f1b5da568d73b48260511a80f63821e496a0018e46b59c64f4323b0be8ffc087
7
+ data.tar.gz: 150e266e511a23b431fced083a0c22d5fcd1659fba4f780146aadfd7aa57abe8ba04110b2f53ae0509322d88325f9599a0a010b1ed34889eee1feb50a190ebfa
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler::GemHelper.install_tasks
data/lib/client.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'host-manager'
2
+
3
+ HostManager::Client
4
+ .create('10.10.10.1', 2991)
5
+ .send_action('delete', 'the1234.test.host', '127.0.0.1', 'containerid')
@@ -0,0 +1,35 @@
1
+ require_relative 'host-manager'
2
+ require 'yaml'
3
+
4
+ loop {
5
+ begin
6
+ Docker::Event.stream { |event|
7
+ HostManager.log.info 'Connected to docker socket. Listening for events.'
8
+ # respond to all container events
9
+ if event.type == 'container'
10
+ container_id = event.actor.id.chomp
11
+
12
+ container = Docker::Container.get(container_id)
13
+ ip = container.info['NetworkSettings']['IPAddress']
14
+ container_name = container.info['Name'].sub!(/^\//, '')
15
+
16
+ client = HostManager::Client.create('10.10.10.1', 2991)
17
+ client.host_suffix '.local.signal.sh'
18
+
19
+ if event.action == 'start'
20
+ client.send_action('create', container_name, ip, container_id)
21
+ elsif event.action == 'die'
22
+ client.send_action('delete', container_name, ip, container_id)
23
+ end
24
+
25
+ client.close
26
+ end
27
+
28
+ break
29
+ }
30
+
31
+ rescue Docker::Error::TimeoutError
32
+ HostManager.log.warn 'Docker socket connection timed out whilst listening for events. Reconnecting...'
33
+ end
34
+ }
35
+
@@ -0,0 +1,193 @@
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
+ container_name + host_suffix
57
+ end
58
+ end
59
+
60
+ def host_suffix(suffix = nil)
61
+ if suffix != nil
62
+ @domain_suffix = suffix
63
+ else
64
+ @domain_suffix
65
+ end
66
+ end
67
+ end
68
+
69
+ class Server < Base
70
+ def run(ip, port)
71
+ HostManager.log.info "Running on host manager service on #{ip}:#{port}"
72
+ @tcp_server = TCPServer.new ip, port
73
+
74
+ loop {
75
+
76
+ client = @tcp_server.accept
77
+ content = client.gets
78
+
79
+ log.debug("Recieved data: #{content.to_s.strip}")
80
+
81
+ begin
82
+ unless content.to_s.chomp.strip.empty?
83
+ data = JSON.parse(content)
84
+ required_keys = %w(action hostname ip containerId)
85
+ required_keys.each do |key|
86
+ unless data.key?(key)
87
+ raise "Data for key #{key} not provided."
88
+ end
89
+ end
90
+ execute(data['action'], data['hostname'], data['ip'], data['containerId'])
91
+ end
92
+ rescue => e
93
+ log.error("Caught exception attempting to execute with data #{content}. #{e}")
94
+ end
95
+
96
+ client.close
97
+ }
98
+
99
+ end
100
+
101
+ def get_hosts
102
+ Hosts::File.read(HostManager.host_file_path)
103
+ end
104
+
105
+ def execute(action, hostname, ip, container_id = nil)
106
+ hosts = get_hosts
107
+
108
+ if action == 'create'
109
+ hosts.elements.each do |element|
110
+ if valid_entry?(element)
111
+ if hostname == element.name && ip == element.address
112
+ raise "Entry already exists! (#{ip} #{hostname})"
113
+ end
114
+ end
115
+ end
116
+
117
+ comment = HostManager.comment_prefix + (container_id ? " Container ID: #{container_id}" : '')
118
+
119
+ hosts.elements << Hosts::Entry.new(ip, hostname, :comment => comment)
120
+ hosts.write
121
+
122
+ elsif action == 'delete'
123
+ hosts.elements.delete_if do |element|
124
+ if valid_entry?(element)
125
+ if hostname == element.name
126
+ log.info 'Removing entry for ' + element.name
127
+ true
128
+ end
129
+ end
130
+ end
131
+
132
+ hosts.write
133
+ else
134
+ raise 'No valid action specified.'
135
+ end
136
+ end
137
+
138
+ def self.create(ip, port)
139
+ server = self.new
140
+ server.run(ip, port)
141
+ end
142
+
143
+ private
144
+
145
+ # Determine if entry is managed by this utility or not
146
+ def valid_entry?(element)
147
+ # check it's a managed host first
148
+ if element.respond_to?(:comment) && element.comment.to_s.start_with?(HostManager.comment_prefix)
149
+ # check we have hostname and ip
150
+ if element.respond_to?(:name) && element.respond_to?(:address)
151
+ return true
152
+ end
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ class Client < Base
159
+
160
+ def initialize(ip, port)
161
+ @socket = TCPSocket.new(ip, port)
162
+ end
163
+
164
+ def close
165
+ log.info('Closing client connection.')
166
+ @socket.close
167
+ end
168
+
169
+ def send_action(action, hostname, ip, container_id = nil)
170
+ data = {
171
+ :action => action,
172
+ :hostname => host_name(hostname),
173
+ :ip => ip,
174
+ }
175
+
176
+ if container_id
177
+ data[:containerId] = container_id
178
+ end
179
+
180
+ send(data)
181
+ end
182
+
183
+ def send(data)
184
+ log.info("Sending data via client: #{data.to_json}")
185
+ @socket.write data.to_json + "\n"
186
+ end
187
+
188
+ def self.create(ip, port)
189
+ self.new(ip, port)
190
+ end
191
+ end
192
+
193
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@raxys.net>, 2012
4
+
5
+ This file is part of Hosts.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require 'set'
21
+ require 'pathname'
22
+ require_relative 'linebreak/linebreak'
23
+
24
+ # Namespace for projects of Alexander E. Fischer <aef@raxys.net>.
25
+ #
26
+ # If you want to be able to simply type Example instead of Aef::Example to
27
+ # address classes in this namespace simply write the following before using the
28
+ # classes.
29
+ #
30
+ # @example Including the namespace
31
+ # include Aef
32
+ # @author Alexander E. Fischer
33
+ module Aef
34
+
35
+ # Namespace for the hosts library
36
+ module Hosts
37
+
38
+ # An exception for errors happening while parsing a hosts file
39
+ class ParserError < RuntimeError; end
40
+ end
41
+ end
42
+
43
+ require_relative 'hosts/version'
44
+ require_relative 'hosts/helpers'
45
+ require_relative 'hosts/file'
46
+ require_relative 'hosts/element'
47
+ require_relative 'hosts/section'
48
+ require_relative 'hosts/entry'
49
+ require_relative 'hosts/comment'
50
+ require_relative 'hosts/empty_element'
51
+
@@ -0,0 +1,73 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@raxys.net>, 2012
4
+
5
+ This file is part of Hosts.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require_relative '../hosts'
21
+
22
+ module Aef
23
+ module Hosts
24
+
25
+ # Represents a comment-only line as element of a hosts file
26
+ class Comment < Element
27
+
28
+ # The comment
29
+ #
30
+ # @return [String]
31
+ attr_reader :comment
32
+
33
+ # Initializes a comment
34
+ #
35
+ # @param comment [String] the comment
36
+ # @param options [Hash]
37
+ # @option options [String] :cache sets a cached String representation
38
+ def initialize(comment, options = {})
39
+ validate_options(options, :cache)
40
+
41
+ raise ArgumentError, 'Comment cannot be empty' unless comment
42
+
43
+ @comment = comment.to_s
44
+ @cache = options[:cache].to_s unless options[:cache].nil?
45
+ end
46
+
47
+ # Sets the comment
48
+ def comment=(comment)
49
+ set_if_changed(:comment, comment.to_s) do
50
+ invalidate_cache!
51
+ end
52
+ end
53
+
54
+ # A String representation for debugging purposes
55
+ #
56
+ # @return [String]
57
+ def inspect
58
+ generate_inspect(self, :comment, :cache)
59
+ end
60
+
61
+ protected
62
+
63
+ # Defines the algorithm to generate a String representation from scratch.
64
+ #
65
+ # @return [String] a generated String representation
66
+ def generate_string(options = {})
67
+ "##{comment}\n"
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+
@@ -0,0 +1,108 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@raxys.net>, 2012
4
+
5
+ This file is part of Hosts.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require_relative '../hosts'
21
+
22
+ module Aef
23
+ module Hosts
24
+
25
+ # The base class for elements which are aggregated by the Aef::Hosts::File
26
+ # class.
27
+ #
28
+ # @abstract This class is not supposed to be instantiated.
29
+ class Element
30
+
31
+ include Helpers
32
+
33
+ # Cached String representation
34
+ #
35
+ # @return [String, Hash, nil]
36
+ attr_reader :cache
37
+
38
+ # Deletes the cached String representation
39
+ #
40
+ # @return [Aef::Hosts::Element] a self reference
41
+ def invalidate_cache!
42
+ @cache = nil
43
+
44
+ self
45
+ end
46
+
47
+ # Tells if a String representation is cached or not
48
+ #
49
+ # @return [true, false] true if cache is not empty
50
+ def cache_filled?
51
+ @cache ? true : false
52
+ end
53
+
54
+ # A String representation for debugging purposes
55
+ #
56
+ # @return [String]
57
+ def inspect
58
+ generate_inspect(self, :cache)
59
+ end
60
+
61
+ # Provides a String representation of the element
62
+ #
63
+ # @param [Hash] options
64
+ # @option options [true, false] :force_generation if set to true, the
65
+ # cache won't be used, even if it not empty
66
+ # @option options [:unix, :windows, :mac] :linebreak_encoding the
67
+ # linebreak encoding of the result. If nothing is specified the result
68
+ # will be encoded as if :unix was specified.
69
+ # @see Aef::Linebreak#encode
70
+ def to_s(options = {})
71
+ validate_options(options, :force_generation, :linebreak_encoding)
72
+
73
+ string = ''
74
+
75
+ if !cache_filled? || options[:force_generation]
76
+ string << generate_string(options)
77
+ else
78
+ string << cache_string(options)
79
+ end
80
+
81
+ if options[:linebreak_encoding]
82
+ string = Aef::Linebreak.encode(string, options[:linebreak_encoding])
83
+ end
84
+
85
+ string
86
+ end
87
+
88
+ protected
89
+
90
+ # Defines the algorithm to generate a String representation from scratch.
91
+ #
92
+ # @abstract This method needs to be implemented in descendant classes.
93
+ # @return [String] a generated String representation
94
+ def generate_string(options = {})
95
+ raise NotImplementedError
96
+ end
97
+
98
+ # Defines the algorithm to construct the String representation from cache
99
+ #
100
+ # @return [String] the cached String representation
101
+ def cache_string(options = {})
102
+ @cache.dup
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+