Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new raw blocks: listen, frontend, backend #652

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions jobs/haproxy/spec
kinjelom marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -635,19 +635,19 @@ properties:

ha_proxy.global_config:
description: |
A block of raw HAProxy config that will be added to the HA proxy global section
Raw HAProxy config that will be added to the HA proxy global section, provided either as a multiline text blob or as an array of lines.

ha_proxy.default_config:
description: |
A block of raw HAProxy config that will be added to the HA proxy default section
Raw HAProxy config that will be added to the HA proxy default section, provided either as a multiline text blob or as an array of lines.

ha_proxy.frontend_config:
description: |
A block of raw HAProxy config that will be added to each HA proxy frontend definition
Raw HAProxy config that will be added to each HA proxy frontend definition, provided either as a multiline text blob or as an array of lines.

ha_proxy.backend_config:
description: |
A block of raw HAProxy config that will be added to the default HTTP + routed HTTP backend definitions
Raw HAProxy config that will be added to the default HTTP + routed HTTP backend definitions, provided either as a multiline text blob or as an array of lines.

ha_proxy.custom_http_error_files:
description: |
Expand All @@ -664,13 +664,44 @@ properties:
</body></html>
ha_proxy.tcp_backend_config:
description: |
A block of raw HAProxy config that will be added to the CF TCP Router + Generic TCP backend definitions
Raw HAProxy config that will be added to the CF TCP Router + Generic TCP backend definitions, provided either as a multiline text blob or as an array of lines.

ha_proxy.raw_config:
description: |
A multiline text blob of an entire haproxy config. Overrides every other
option available, so you can provide your own config, and do whatever
you want. Use at your own risk.
ha_proxy.raw_blocks:
description: |
A hash of block types, where each type contains a hash of specific block names with their respective configurations.
The configurations are provided as either multiline text blobs or arrays of lines.
This structure will be appended to the end of the HAProxy configuration file.
Use at your own risk.
example:
listen:
my-listen-x: |
bind :81
mode http
server-template srv 1-3 q-s0.web.default.deployment-x.bosh:8080 check inter 1000
my-listen-y:
- bind :82
- mode http
- server-template srv 1-3 q-s0.web.default.deployment-y.bosh:8080 check inter 1000
frontend:
my-frontend-x: |
bind :83
use_backend my-backend-x if { hdr(host) -i x.example.com }
my-frontend-y:
- bind :84
- use_backend my-backend-y if { hdr(host) -i y.example.com }
backend:
my-backend-x: |
mode http
server-template srv-x 1-3 q-s0.web.default.deployment-x.bosh:8080 check inter 1000
my-backend-y:
- mode http
- server-template srv-y 1-3 q-s0.web.default.deployment-y.bosh:8080 check inter 1000

ha_proxy.max_open_files:
description: The number of file descriptors HAProxy can have open at one time
default: 256000
Expand Down
59 changes: 47 additions & 12 deletions jobs/haproxy/templates/haproxy.config.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
<%- # see https://bosh.io/docs/jobs/#properties for documentation of bosh ERB templates -%>
<% if properties.ha_proxy.raw_config -%>
<%
def format_indented_multiline_config(raw_config)
kinjelom marked this conversation as resolved.
Show resolved Hide resolved
ident = " "
if raw_config
if raw_config.is_a?(Array)
out = ""
sep = ""
raw_config.each do |line|
out = out + sep+ line
sep = "\n"+ident
end
return out
else
raw_config.strip.gsub(/\n/, "\n"+ident)
end
end
end

if properties.ha_proxy.raw_config -%>
<%= p("ha_proxy.raw_config") %>
<%- else -%>
<%-
Expand Down Expand Up @@ -228,7 +246,7 @@ global
log <%= p('ha_proxy.syslog_server') %> len <%= p('ha_proxy.log_max_length') %> format <%= p('ha_proxy.log_format') %> syslog <%= p('ha_proxy.log_level') %>
daemon
<%- if properties.ha_proxy.global_config -%>
<%= p("ha_proxy.global_config") %>
<%= format_indented_multiline_config(p("ha_proxy.global_config")) %>
<%- end -%>
<%- if p("ha_proxy.nbthread") > 1 -%>
nbthread <%= p("ha_proxy.nbthread") %>
Expand Down Expand Up @@ -300,7 +318,7 @@ defaults
timeout http-request <%= (p("ha_proxy.request_timeout").to_f * 1000).to_i %>ms
timeout queue <%= (p("ha_proxy.queue_timeout").to_f * 1000).to_i %>ms
<%- if properties.ha_proxy.default_config -%>
<%= p("ha_proxy.default_config") %>
<%= format_indented_multiline_config(p("ha_proxy.default_config")) %>
<%- end -%>

<% if p("ha_proxy.stats_enable") -%>
Expand Down Expand Up @@ -355,7 +373,7 @@ frontend http-in
mode http
bind <%= p("ha_proxy.binding_ip") %>:80 <%= accept_proxy %> <%= v4v6 %>
<%- if properties.ha_proxy.frontend_config -%>
<%= p("ha_proxy.frontend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.frontend_config")) %>
<%- end -%>
<%- if_p("ha_proxy.connections_rate_limit.table_size", "ha_proxy.connections_rate_limit.window_size") do -%>
tcp-request connection track-sc0 src table st_tcp_conn_rate
Expand Down Expand Up @@ -468,7 +486,7 @@ frontend https-in
<%- end -%>
<%- end -%>
<%- if properties.ha_proxy.frontend_config -%>
<%= p("ha_proxy.frontend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.frontend_config")) %>
<%- end -%>
<%- if_p("ha_proxy.connections_rate_limit.table_size", "ha_proxy.connections_rate_limit.window_size") do -%>
tcp-request connection track-sc0 src table st_tcp_conn_rate
Expand Down Expand Up @@ -599,7 +617,6 @@ frontend https-in
<%- end -%>
acl xfp_exists hdr_cnt(X-Forwarded-Proto) gt 0
http-request add-header X-Forwarded-Proto "https" if ! xfp_exists

<%- if p("ha_proxy.disable_backend_http2_websockets") -%>
# Send websockets to a backend that forces HTTP/1.1. This avoids bugs in Go & Gorouter's HTTP/2 websocket support
# https://github.com/cloudfoundry/routing-release/issues/230
Expand Down Expand Up @@ -638,7 +655,7 @@ frontend wss-in
<%- end -%>
<%- end -%>
<%- if properties.ha_proxy.frontend_config -%>
<%= p("ha_proxy.frontend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.frontend_config")) %>
<%- end -%>
<%- if_p("ha_proxy.cidr_whitelist") do -%>
acl whitelist src -f /var/vcap/jobs/haproxy/config/whitelist_cidrs.txt
Expand Down Expand Up @@ -753,7 +770,6 @@ frontend wss-in
<%- end -%>
acl xfp_exists hdr_cnt(X-Forwarded-Proto) gt 0
http-request add-header X-Forwarded-Proto "https" if ! xfp_exists

<%- if p("ha_proxy.disable_backend_http2_websockets") -%>
# Send websockets to a backend that forces HTTP/1.1. This avoids bugs in Go & Gorouter's HTTP/2 websocket support
# https://github.com/cloudfoundry/routing-release/issues/230
Expand Down Expand Up @@ -784,7 +800,7 @@ backend <%= backend[:name] %>
compression type <%= p("ha_proxy.compress_types") %>
<%- end -%>
<%- if properties.ha_proxy.backend_config -%>
<%= p("ha_proxy.backend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.backend_config")) %>
<%- end -%>
<%- p('ha_proxy.custom_http_error_files', {}).keys.each do |status_code| -%>
errorfile <%= status_code %> /var/vcap/jobs/haproxy/errorfiles/custom<%=status_code%>.http
Expand Down Expand Up @@ -815,7 +831,7 @@ backend http-routed-backend-<%= prefix_hash %>
compression type <%= p("ha_proxy.compress_types") %>
<%- end -%>
<%- if properties.ha_proxy.backend_config -%>
<%= p("ha_proxy.backend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.backend_config")) %>
<%- end -%>
<%
resolvers = ""
Expand Down Expand Up @@ -872,7 +888,7 @@ frontend cf_tcp_routing
backend cf_tcp_routers
mode tcp
<%- if properties.ha_proxy.tcp_backend_config -%>
<%= p("ha_proxy.tcp_backend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.tcp_backend_config")) %>
<%- end -%>
option httpchk GET /health
<% tcp_router.instances.each_with_index do |instance, index| %>
Expand Down Expand Up @@ -906,7 +922,7 @@ frontend tcp-frontend_<%= tcp_proxy["name"]%>
backend tcp-<%= tcp_proxy["name"] %>
mode tcp
<%- if properties.ha_proxy.tcp_backend_config -%>
<%= p("ha_proxy.tcp_backend_config") %>
<%= format_indented_multiline_config(p("ha_proxy.tcp_backend_config")) %>
<%- end -%>
<%- if tcp_proxy["balance"] -%>
balance <%= tcp_proxy["balance"] %>
Expand Down Expand Up @@ -959,3 +975,22 @@ listen health_check_http_tcp-<%= tcp_proxy["name"] %>

# }}}
<% end -%>
<%- if properties.ha_proxy.raw_blocks && !properties.ha_proxy.raw_blocks.empty? -%>
# raw blocks {{{
<%-
correct_types_order = %w[global defaults listen frontend backend resolvers peers mailers]
raw_blocks = p('ha_proxy.raw_blocks', {})
ordered_blocks = correct_types_order.select { |type| raw_blocks.key?(type) }
additional_types = raw_blocks.keys - correct_types_order
all_found_types = ordered_blocks + additional_types
all_found_types.each do |block_type|
raw_blocks[block_type].each do |block_id, block_raw_config|
%>
<%= block_type %> <%= block_id %>
<%= format_indented_multiline_config(block_raw_config) %>
<%-
end
end
%>
# }}}
<%- end -%>
59 changes: 59 additions & 0 deletions spec/haproxy/templates/haproxy_config/raw_blocks_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

require 'rspec'

describe 'config/haproxy.config ha_proxy.raw_blocks' do
let(:haproxy_conf) do
parse_haproxy_config(template.render({ 'ha_proxy' => properties }))
end

context 'when multiline configurations are provided for some raw blocks' do
let(:properties) do
{
'raw_blocks' => {
'some' => {
'raw-block-1' => "line 1\nline 2\nline 3",
'raw-block-2' => "\n\nline 1\nline 2\nline 3\n\n",
'raw-block-3' => ['line 1', 'line 2', 'line 3']
}
}
}
end

it 'formats the configuration as expected' do
expected_block_content = ['line 1', 'line 2', 'line 3']
expect(haproxy_conf['some raw-block-1']).to eq(expected_block_content)
expect(haproxy_conf['some raw-block-2']).to eq(expected_block_content)
expect(haproxy_conf['some raw-block-3']).to eq(expected_block_content)
end
end

context 'when there are many types of raw blocks' do
let(:properties) do
{
'raw_blocks' => {
'unknown' => {
'raw-test-1' => 'test',
'raw-test-2' => 'test'
},
'mailers' => { 'raw-test' => 'test' },
'peers' => { 'raw-test' => 'test' },
'resolvers' => { 'raw-test' => 'test' },
'backend' => { 'raw-test' => 'test' },
'frontend' => { 'raw-test' => 'test' },
'listen' => { 'raw-test' => 'test' },
'defaults' => { '# raw-test' => 'test' },
'global' => { '# raw-test' => 'test' }
}
}
end

it 'arranges them all in the correct order' do
raw_keys = haproxy_conf.keys.select { |key| key.include?('raw-test') }
expect(raw_keys).to eq(['global # raw-test', 'defaults # raw-test',
'listen raw-test', 'frontend raw-test', 'backend raw-test',
'resolvers raw-test', 'peers raw-test', 'mailers raw-test',
'unknown raw-test-1', 'unknown raw-test-2'])
end
end
end