haproxy-tools 0.5.0 → 0.6.0

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.
@@ -1,31 +1,34 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'haproxy/version'
5
+ require "haproxy/version"
5
6
 
6
7
  Gem::Specification.new do |gem|
7
- gem.name = 'haproxy-tools'
8
+ gem.name = "haproxy-tools"
8
9
  gem.version = HAProxy::VERSION
9
- gem.authors = ['Jason Wadsworth']
10
- gem.email = ['jdwadsworth@gmail.com']
11
- gem.description = %q{Ruby tools for HAProxy, including config file management.}
12
- gem.summary = %q{HAProxy Tools for Ruby}
13
- gem.homepage = 'https://github.com/subakva/haproxy-tools'
14
- gem.license = 'MIT'
10
+ gem.authors = ["Jason Wadsworth"]
11
+ gem.email = ["jdwadsworth@gmail.com"]
12
+ gem.description = "Ruby tools for HAProxy, including config file management."
13
+ gem.summary = "HAProxy Tools for Ruby"
14
+ gem.homepage = "https://github.com/subakva/haproxy-tools"
15
+ gem.license = "MIT"
15
16
 
16
17
  gem.files = `git ls-files`.split($/)
17
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
18
19
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
- gem.require_paths = ['lib']
20
+ gem.require_paths = ["lib"]
20
21
 
21
- gem.required_ruby_version = '>= 1.9.3'
22
+ gem.required_ruby_version = ">= 2.2.0"
22
23
 
23
- gem.add_dependency('net-scp')
24
- gem.add_dependency('treetop')
25
- gem.add_development_dependency('rake')
26
- gem.add_development_dependency('rspec')
27
- gem.add_development_dependency('yard')
28
- gem.add_development_dependency('simplecov')
29
- gem.add_development_dependency('cane')
24
+ gem.add_dependency("net-scp")
25
+ gem.add_dependency("treetop")
26
+ gem.add_development_dependency("awesome_print")
27
+ gem.add_development_dependency("cane")
28
+ gem.add_development_dependency("rake")
29
+ gem.add_development_dependency("rspec")
30
+ gem.add_development_dependency("simplecov")
31
+ gem.add_development_dependency("standard")
32
+ gem.add_development_dependency("yard")
30
33
  # gem.add_development_dependency('pry-debugger')
31
34
  end
data/lib/haproxy-tools.rb CHANGED
@@ -1 +1,3 @@
1
- require 'haproxy_tools'
1
+ # frozen_string_literal: true
2
+
3
+ require "haproxy_tools"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HAProxy
2
4
  Default = Struct.new(:name, :options, :config)
3
5
  Backend = Struct.new(:name, :options, :config, :servers)
@@ -16,12 +18,11 @@ module HAProxy
16
18
  new_server.host = host
17
19
  new_server.port = options[:port] if options[:port]
18
20
  new_server.attributes ||= options[:attributes] || {}
19
- self.servers[name] = new_server
21
+ servers[name] = new_server
20
22
  new_server
21
23
  end
22
24
  end
23
25
 
24
-
25
26
  # Represents a listener configuration block.
26
27
  class Listener
27
28
  include ServerList
@@ -46,23 +47,23 @@ module HAProxy
46
47
  end
47
48
 
48
49
  def listener(name)
49
- self.listeners.find { |l| l.name == name }
50
+ listeners.find { |l| l.name == name }
50
51
  end
51
52
 
52
53
  def backend(name)
53
- self.backends.find { |b| b.name == name }
54
+ backends.find { |b| b.name == name }
54
55
  end
55
56
 
56
57
  def frontend(name)
57
- self.frontends.find { |f| f.name == name }
58
+ frontends.find { |f| f.name == name }
58
59
  end
59
60
 
60
- def default(name=nil)
61
- self.defaults.find { |d| d.name == name }
61
+ def default(name = nil)
62
+ defaults.find { |d| d.name == name }
62
63
  end
63
64
 
64
65
  def render
65
- renderer = HAProxy::Renderer.new(self, self.original_parse_tree)
66
+ renderer = HAProxy::Renderer.new(self, original_parse_tree)
66
67
  renderer.render
67
68
  end
68
69
 
@@ -75,4 +76,3 @@ module HAProxy
75
76
  end
76
77
  end
77
78
  end
78
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HAProxy
2
4
  # Responsible for reading an HAProxy config file and building an HAProxy::Config instance.
3
5
  class Parser
@@ -5,42 +7,51 @@ module HAProxy
5
7
  Error = Class.new(StandardError)
6
8
 
7
9
  # haproxy 1.3
8
- SERVER_ATTRIBUTE_NAMES_1_3 = %w{
10
+ SERVER_ATTRIBUTE_NAMES_1_3 = %w[
9
11
  addr backup check cookie disabled fall id inter fastinter downinter
10
12
  maxconn maxqueue minconn port redir rise slowstart source track weight
11
- }
13
+ ]
12
14
  # Added in haproxy 1.4
13
- SERVER_ATTRIBUTE_NAMES_1_4 = %w{error-limit observe on-error}
15
+ SERVER_ATTRIBUTE_NAMES_1_4 = %w[error-limit observe on-error]
14
16
  # Added in haproxy 1.5
15
- SERVER_ATTRIBUTE_NAMES_1_5 = %w{
17
+ SERVER_ATTRIBUTE_NAMES_1_5 = %w[
16
18
  agent-check agent-inter agent-port ca-file check-send-proxy check-ssl
17
19
  ciphers crl-file crt error-limit force-sslv3 force-tlsv10 force-tlsv11
18
20
  force-tlsv12 no-sslv3 no-tls-tickets no-tlsv10 no-tlsv11 no-tlsv12 non-stick observe
19
21
  on-error on-marked-down on-marked-up send-proxy send-proxy-v2 send-proxy-v2-ssl
20
22
  send-proxy-v2-ssl-cn ssl verify verifyhost
21
- }
23
+ ]
22
24
  # Added in haproxy 1.6
23
- SERVER_ATTRIBUTE_NAMES_1_6 = %w{
25
+ SERVER_ATTRIBUTE_NAMES_1_6 = %w[
24
26
  namespace no-ssl-reuse resolve-prefer resolvers sni tcp-ut
25
- }
27
+ ]
26
28
  # Added in haproxy 1.7
27
- SERVER_ATTRIBUTE_NAMES_1_7 = %w{
29
+ SERVER_ATTRIBUTE_NAMES_1_7 = %w[
28
30
  agent-send init-addr resolve-net
29
- }
30
- SERVER_ATTRIBUTE_NAMES_1_8 = %w{
31
+ ]
32
+ SERVER_ATTRIBUTE_NAMES_1_8 = %w[
31
33
  agent-addr check-sni enabled force-tlsv13 no-agent-check no-backup no-check no-check-ssl
32
- no-send-proxy no-send-proxy-v2 no-send-proxy-v2-ssl no-send-proxy-v2-ssl-cn no-ssl no-tlsv13
34
+ no-send-proxy no-send-proxy-v2 no-send-proxy-v2-ssl no-send-proxy-v2-ssl-cn no-ssl no-tlsv13
33
35
  no-verifyhost ssl-max-ver ssl-min-ver ssl-reuse stick tls-tickets
34
- }
35
- # SERVER_ATTRIBUTE_NAMES_1_9 = %w{ } # as of 1/16/18 I do not see new server attributes in haproxy 1.9
36
- SERVER_ATTRIBUTE_NAMES = SERVER_ATTRIBUTE_NAMES_1_3 + SERVER_ATTRIBUTE_NAMES_1_4 + SERVER_ATTRIBUTE_NAMES_1_5 \
37
- + SERVER_ATTRIBUTE_NAMES_1_6 + SERVER_ATTRIBUTE_NAMES_1_7 + SERVER_ATTRIBUTE_NAMES_1_8
36
+ ]
37
+ SERVER_ATTRIBUTE_NAMES_1_9 = %w[
38
+ alpn check-alpn max-reuse npn pool-max-conn pool-purge-delay proto proxy-v2-options
39
+ ].freeze
40
+ SERVER_ATTRIBUTE_NAMES = [
41
+ SERVER_ATTRIBUTE_NAMES_1_3,
42
+ SERVER_ATTRIBUTE_NAMES_1_4,
43
+ SERVER_ATTRIBUTE_NAMES_1_5,
44
+ SERVER_ATTRIBUTE_NAMES_1_6,
45
+ SERVER_ATTRIBUTE_NAMES_1_7,
46
+ SERVER_ATTRIBUTE_NAMES_1_8,
47
+ SERVER_ATTRIBUTE_NAMES_1_9,
48
+ ].flatten.freeze
38
49
 
39
50
  attr_accessor :verbose, :options, :parse_result
40
51
 
41
52
  def initialize(options = nil)
42
53
  options ||= {}
43
- options = { :verbose => false }.merge(options)
54
+ options = {verbose: false}.merge(options)
44
55
 
45
56
  self.options = options
46
57
  self.verbose = options[:verbose]
@@ -48,7 +59,7 @@ module HAProxy
48
59
 
49
60
  def parse_file(filename)
50
61
  config_text = File.read(filename)
51
- self.parse(config_text)
62
+ parse(config_text)
52
63
  end
53
64
 
54
65
  def parse(config_text)
@@ -131,22 +142,18 @@ module HAProxy
131
142
  result.defaults.map { |ds| build_default(ds) }
132
143
  end
133
144
 
134
-
135
145
  def try_send(node, *method_names)
136
146
  method_name = method_names.shift
137
147
  if node.respond_to?(method_name)
138
148
  next_node = node.send(method_name)
139
149
  method_names.empty? ? next_node : try_send(next_node, *method_names)
140
- else
141
- nil
142
150
  end
143
151
  end
144
152
 
145
153
  def server_hash_from_config_section(cs)
146
- cs.servers.inject({}) do |ch, s|
154
+ cs.servers.each_with_object({}) do |s, ch|
147
155
  value = try_send(s, :value, :content)
148
156
  ch[s.name] = Server.new(s.name, s.host, s.port, parse_server_attributes(value))
149
- ch
150
157
  end
151
158
  end
152
159
 
@@ -161,46 +168,42 @@ module HAProxy
161
168
  def parse_server_attributes(value)
162
169
  parts = value.to_s.split(/\s/)
163
170
  current_name = nil
164
- pairs = parts.inject({}) do |pairs, part|
171
+ pairs = parts.each_with_object({}) { |part, attrs|
165
172
  if SERVER_ATTRIBUTE_NAMES.include?(part)
166
- current_name = part
167
- pairs[current_name] = []
173
+ current_name = part
174
+ attrs[current_name] = []
168
175
  elsif current_name.nil?
169
176
  raise "Invalid server attribute: #{part}"
170
177
  else
171
- pairs[current_name] << part
178
+ attrs[current_name] << part
172
179
  end
173
- pairs
174
- end
180
+ }
175
181
 
176
- return clean_parsed_server_attributes(pairs)
182
+ clean_parsed_server_attributes(pairs)
177
183
  end
178
184
 
179
185
  # Converts attributes with no values to true, and combines everything else into space-
180
186
  # separated strings.
181
187
  def clean_parsed_server_attributes(pairs)
182
- pairs.each do |k,v|
183
- if v.empty?
184
- pairs[k] = true
188
+ pairs.each do |k, v|
189
+ pairs[k] = if v.empty?
190
+ true
185
191
  else
186
- pairs[k] = v.join(' ')
192
+ v.join(" ")
187
193
  end
188
194
  end
189
195
  end
190
196
 
191
197
  def options_hash_from_config_section(cs)
192
- cs.option_lines.inject({}) do |ch, l|
198
+ cs.option_lines.each_with_object({}) do |l, ch|
193
199
  ch[l.keyword.content] = l.value ? l.value.content : nil
194
- ch
195
200
  end
196
201
  end
197
202
 
198
203
  def config_hash_from_config_section(cs)
199
- cs.config_lines.reject{|l| l.keyword.content == 'option'}.inject({}) do |ch, l|
204
+ cs.config_lines.reject {|l| l.keyword.content == "option"}.each_with_object({}) do |l, ch|
200
205
  ch[l.keyword.content] = l.value ? l.value.content : nil
201
- ch
202
206
  end
203
207
  end
204
-
205
208
  end
206
- end
209
+ end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HAProxy
2
4
  # Responsible for rendering an HAProxy::Config instance to a string.
3
5
  class Renderer
4
-
5
6
  attr_accessor :config, :source_tree
6
7
 
7
8
  def initialize(config, source_tree)
@@ -11,11 +12,11 @@ module HAProxy
11
12
  @config_list = {}
12
13
  @context = self.config
13
14
  @prev_context = self.config
14
- @config_text = ''
15
+ @config_text = "".dup
15
16
  end
16
17
 
17
18
  def render
18
- render_node(self.source_tree)
19
+ render_node(source_tree)
19
20
  handle_context_change
20
21
  @config_text
21
22
  end
@@ -33,18 +34,19 @@ module HAProxy
33
34
  next if @context.servers[e.name].nil?
34
35
  end
35
36
 
36
- if e.class == HAProxy::Treetop::ConfigLine and @context.class == HAProxy::Default
37
- # Keep track of the configs in this config block we've seen, so that we can detect and render new ones.
37
+ if (e.class == HAProxy::Treetop::ConfigLine) && (@context.class == HAProxy::Default)
38
+ # Keep track of the configs in this config block we've seen, so that
39
+ # we can detect and render new ones.
38
40
  @config_list[e.key] = e
39
41
  # Don't render the config *if* it's been removed from the config block.
40
- next if @context.config[e.key].nil?
42
+ next unless @context.config.key?(e.key)
41
43
  end
42
44
 
43
45
  if e.class == HAProxy::Treetop::ServerLine
44
46
  # Use a custom rendering method for servers, since we allow them to be
45
47
  # added/removed/changed.
46
48
  render_server_element(e)
47
- elsif e.class== HAProxy::Treetop::ConfigLine and @context.class == HAProxy::Default
49
+ elsif (e.class == HAProxy::Treetop::ConfigLine) && (@context.class == HAProxy::Default)
48
50
  # Use a custom rendering method for configs, since we allow them to be
49
51
  # added/removed/changed.
50
52
  render_config_line_element(e)
@@ -64,14 +66,15 @@ module HAProxy
64
66
  end
65
67
 
66
68
  def render_config_line_element(e)
67
- config_key = e.key.gsub(/\s+/, ' ')
69
+ config_key = e.key.gsub(/\s+/, " ")
68
70
  config_value = @context.config[e.key]
69
- config_value = config_value.gsub(/\s+/, ' ') if not config_value.nil?
71
+ config_value = config_value.gsub(/\s+/, " ") unless config_value.nil?
70
72
  render_config_line(config_key, config_value)
71
73
  end
72
74
 
73
75
  def render_config_line(key, value)
74
- @config_text << "\t#{key} #{value}\n"
76
+ content = "#{key} #{value}".strip
77
+ @config_text << "\t#{content}\n"
75
78
  end
76
79
 
77
80
  def render_server_element(e)
@@ -81,7 +84,8 @@ module HAProxy
81
84
 
82
85
  def render_server(server)
83
86
  attribute_string = render_server_attributes(server.attributes)
84
- @config_text << "\tserver #{server.name} #{server.host}:#{server.port} #{attribute_string}\n"
87
+ content = "server #{server.name} #{server.host}:#{server.port} #{attribute_string}".strip
88
+ @config_text << "\t#{content}\n"
85
89
  end
86
90
 
87
91
  def handle_context_change
@@ -108,7 +112,7 @@ module HAProxy
108
112
  end
109
113
 
110
114
  def render_server_attributes(attributes)
111
- attribute_string = ""
115
+ attribute_string = "".dup
112
116
  attributes.each do |name, value|
113
117
  attribute_string << name.to_s
114
118
  attribute_string << " "
@@ -123,18 +127,18 @@ module HAProxy
123
127
  def update_render_context(e)
124
128
  @prev_context = @context
125
129
  case e.class.name
126
- when 'HAProxy::Treetop::GlobalSection'
130
+ when "HAProxy::Treetop::GlobalSection"
127
131
  @context = @config.global
128
- when 'HAProxy::Treetop::DefaultsSection'
132
+ when "HAProxy::Treetop::DefaultsSection"
129
133
  section_name = e.defaults_header.proxy_name ? e.defaults_header.proxy_name.content : nil
130
134
  @context = @config.default(section_name)
131
- when 'HAProxy::Treetop::ListenSection'
135
+ when "HAProxy::Treetop::ListenSection"
132
136
  section_name = e.listen_header.proxy_name ? e.listen_header.proxy_name.content : nil
133
137
  @context = @config.listener(section_name)
134
- when 'HAProxy::Treetop::FrontendSection'
138
+ when "HAProxy::Treetop::FrontendSection"
135
139
  section_name = e.frontend_header.proxy_name ? e.frontend_header.proxy_name.content : nil
136
140
  @context = @config.frontend(section_name)
137
- when 'HAProxy::Treetop::BackendSection'
141
+ when "HAProxy::Treetop::BackendSection"
138
142
  section_name = e.backend_header.proxy_name ? e.backend_header.proxy_name.content : nil
139
143
  @context = @config.backend(section_name)
140
144
  else
@@ -143,4 +147,3 @@ module HAProxy
143
147
  end
144
148
  end
145
149
  end
146
-
@@ -88,7 +88,7 @@ module HAProxy::Treetop
88
88
  end
89
89
 
90
90
  rule keyword
91
- (("errorfile" / "timeout") whitespace)? [a-z0-9\-\.]+ <Keyword>
91
+ (("errorfile" / "timeout") whitespace)? [a-z0-9_\-\.]+ <Keyword>
92
92
  end
93
93
 
94
94
  rule server_name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HAProxy
2
4
  module Treetop
3
5
  extend self
@@ -5,53 +7,54 @@ module HAProxy
5
7
  # Include this module to always strip whitespace from the text_value
6
8
  module StrippedTextContent
7
9
  def content
8
- self.text_value.strip
10
+ text_value.strip
9
11
  end
10
12
  end
11
13
 
12
14
  # Include this module if the node contains a config element.
13
15
  module ConfigBlockContainer
14
16
  def option_lines
15
- self.config_block.elements.select {|e| e.class == OptionLine}
17
+ config_block.elements.select {|e| e.class == OptionLine}
16
18
  end
17
19
 
18
20
  def config_lines
19
- self.config_block.elements.select {|e| e.class == ConfigLine}
21
+ config_block.elements.select {|e| e.class == ConfigLine}
20
22
  end
21
23
  end
22
24
 
23
25
  # Include this module if the node contains a service address element.
24
26
  module ServiceAddressContainer
25
27
  def service_address
26
- self.elements.find {|e| e.class == ServiceAddress }
28
+ elements.find {|e| e.class == ServiceAddress }
27
29
  end
28
30
 
29
31
  def host
30
- self.service_address.host.text_value.strip
32
+ service_address.host.text_value.strip
31
33
  end
32
34
 
33
35
  def port
34
- self.service_address.port.text_value.strip
36
+ service_address.port.text_value.strip
35
37
  end
36
38
  end
37
39
 
38
40
  # Include this module if the node contains a server elements.
39
41
  module ServerContainer
40
42
  def servers
41
- self.config_block.elements.select {|e| e.class == ServerLine}
43
+ config_block.elements.select {|e| e.class == ServerLine}
42
44
  end
43
45
  end
44
46
 
45
47
  # Include this module if the value is optional for the node.
46
48
  module OptionalValueElement
47
49
  def value
48
- self.elements.find {|e| e.class == Value}
50
+ elements.find {|e| e.class == Value}
49
51
  end
50
52
  end
51
53
 
54
+ # Helper class for whitespace nodes
52
55
  class Whitespace < ::Treetop::Runtime::SyntaxNode
53
56
  def content
54
- self.text_value
57
+ text_value
55
58
  end
56
59
  end
57
60
 
@@ -102,18 +105,18 @@ module HAProxy
102
105
  include StrippedTextContent
103
106
  end
104
107
 
108
+ # Helper class for config nodes
105
109
  class ConfigLine < ::Treetop::Runtime::SyntaxNode
106
110
  include StrippedTextContent
107
111
  include OptionalValueElement
108
112
 
109
113
  def key
110
- self.keyword.content
114
+ keyword.content
111
115
  end
112
116
 
113
117
  def attribute
114
- self.value.content
118
+ value.content
115
119
  end
116
-
117
120
  end
118
121
 
119
122
  class OptionLine < ::Treetop::Runtime::SyntaxNode
@@ -121,13 +124,14 @@ module HAProxy
121
124
  include OptionalValueElement
122
125
  end
123
126
 
127
+ # Helper class for server nodes
124
128
  class ServerLine < ::Treetop::Runtime::SyntaxNode
125
129
  include StrippedTextContent
126
130
  include ServiceAddressContainer
127
131
  include OptionalValueElement
128
132
 
129
133
  def name
130
- self.server_name.content
134
+ server_name.content
131
135
  end
132
136
  end
133
137
 
@@ -135,10 +139,11 @@ module HAProxy
135
139
  include StrippedTextContent
136
140
  end
137
141
 
142
+ # Helper class for defaults header nodes
138
143
  class DefaultsHeader < ::Treetop::Runtime::SyntaxNode
139
144
  include StrippedTextContent
140
145
  def proxy_name
141
- self.elements.select {|e| e.class == ProxyName}.first
146
+ elements.select {|e| e.class == ProxyName}.first
142
147
  end
143
148
  end
144
149
 
@@ -187,41 +192,44 @@ module HAProxy
187
192
  include ServerContainer
188
193
  end
189
194
 
195
+ # Helper class for the root config file node
190
196
  class ConfigurationFile < ::Treetop::Runtime::SyntaxNode
191
197
  def global
192
- self.elements.select {|e| e.class == GlobalSection}.first
198
+ elements.select {|e| e.class == GlobalSection}.first
193
199
  end
194
200
 
195
201
  def defaults
196
- self.elements.select {|e| e.class == DefaultsSection}
202
+ elements.select {|e| e.class == DefaultsSection}
197
203
  end
198
204
 
199
205
  def listeners
200
- self.elements.select {|e| e.class == ListenSection}
206
+ elements.select {|e| e.class == ListenSection}
201
207
  end
202
208
 
203
209
  def frontends
204
- self.elements.select {|e| e.class == FrontendSection}
210
+ elements.select {|e| e.class == FrontendSection}
205
211
  end
206
212
 
207
213
  def backends
208
- self.elements.select {|e| e.class == BackendSection}
214
+ elements.select {|e| e.class == BackendSection}
209
215
  end
210
216
  end
211
217
 
212
218
  def print_node(e, depth, options = nil)
213
219
  options ||= {}
214
- options = {:max_depth => 2}.merge(options)
220
+ options = {max_depth: 2}.merge(options)
215
221
 
216
222
  puts if depth == 0
217
223
  print "--" * depth
218
- print " #{e.class.name.split('::').last}"
224
+ print " #{e.class.name.split("::").last}"
219
225
  print " [#{e.text_value}]" if e.class == ::Treetop::Runtime::SyntaxNode
220
226
  print " [#{e.content}]" if e.respond_to? :content
221
227
  puts
222
- e.elements.each do |child|
223
- print_node(child, depth + 1, options)
224
- end if depth < options[:max_depth] && e.elements && !e.respond_to?(:content)
228
+ if depth < options[:max_depth] && e.elements && !e.respond_to?(:content)
229
+ e.elements.each do |child|
230
+ print_node(child, depth + 1, options)
231
+ end
232
+ end
225
233
  end
226
234
  end
227
235
  end