# HaProxy template with consul-templaterb adapted from
# https://github.com/haproxytech/haproxy/blob/master/blog/integration_with_consul/haproxy.conf.tmpl
#
# You might read this article:
# https://www.haproxy.com/blog/haproxy-and-consul-with-dns-for-service-discovery/
#
# This template is more powerful than initial implementation:
# * It discovers by itself the services (by default, all having http tag)
# * It allows having white/blacklists of services
# * It handles nicely services having http/non http tag
#  
# Here is how to configure it with environment variables:
#
# This template can be configure the following way with environment variables
# Environment variables to filter services/instances
#   SERVICES_TAG_FILTER: basic tag filter for service (default HTTP)
#   EXCLUDE_SERVICES: comma-separated services regexps to exclude (default: lbl7.*,netsvc-probe.*,consul-probed.*)
#   SERVICES_MATCHING: regexp to show only services matching the regexp, defaults to '.*'
#
# HaProxy specific:
#   HAPROXY_DOMAIN_NAME the domain name to serve, eg: myservice => myservice.example.com
#   CONSUL_DOMAIN_NAME_SUFFIX = suffix in consul configuration (default 'consul', so services are myservice.service.consul)
#   HAPROXY_PREFIX_PATH = where you want HaProxy to reload config
#   CONSUL_DNS_ADDR: Address of DNS resolver returning consul SRV records (defaults to 127.0.0.1:8600)
#   PORT0: HaProxy port to use to serve (default: 8000)
#   HAPROXY_STATS_BIND: bind stats on... (defaut: '127.0.0.1:1936', can use for instance '*:1936')
#   HAPROXY_ADMIN_USER_PASSWORD: Password to access stats (defaults: none)
#
# USAGE examples:
#
#   Reverse HTTP Proxy for services with tag http and starting with 'web'
# SERVICES_MATCHING='web.*' consul-templaterb samples/haproxy_dns.cfg.erb --sig-reload=HUP --exec 'haproxy -W -f samples/haproxy_dns.cfg'

<%
  consul_domain_name = ENV['CONSUL_DOMAIN_NAME_SUFFIX'] || 'consul'
  ha_proxy_data_prefix = ENV['HAPROXY_PREFIX_PATH'] || File.absolute_path('.')
  ha_proxy_data_prefix += '/' unless ha_proxy_data_prefix.end_with? '/'
  services_tag_filter = ENV['SERVICES_TAG_FILTER'] || 'http'
  services_matching = Regexp.new(ENV['SERVICES_MATCHING'] || '.*')

  # Services to hide
  services_blacklist_raw = (ENV['EXCLUDE_SERVICES'] || 'lbl7.*,netsvc-probe.*,consul-probed.*').split(',')
  services_blacklist = services_blacklist_raw.map { |v| Regexp.new(v) }
%>
  global
  # daemon
  # debug
  pidfile <%= ha_proxy_data_prefix %>haproxy.pid
  stats socket <%= ha_proxy_data_prefix %>haproxy.sock level admin
  # If you want to configure from KV, you might use:
  # You might use instead: `kv("service/haproxy/maxconn").get_value_decoded() || 256`
  maxconn 256 
  log 127.0.0.01:514 local0 info
  server-state-file <%= ha_proxy_data_prefix %>haproxy.serverstates
  description HAProxy / consul demo

resolvers consul
  nameserver <%= consul_domain_name %> <%= ENV['CONSUL_DNS_ADDR'] || '127.0.0.1:8600' %>
  accepted_payload_size 8192

defaults
  log global
  option httplog
  option socket-stats
  load-server-state-from-file global
  default-server init-addr none inter 1s rise 2 fall 2
  mode http
  timeout client 30s
  timeout connect 4s
  timeout http-keep-alive 10s
  timeout http-request 5s
  timeout server 30s

frontend http-in
  bind *:<%= ENV['PORT0'] || 8000 %>
  maxconn 256
  use_backend b_%[req.hdr(Host),lower,word(1,:)]

<%
services(tag: services_tag_filter).each do |service_name, tags|
  if services_matching.match(service_name) && !services_blacklist.any? {|r| r.match(service_name)}
%>
backend b_<%= service_name %>.<%= ENV['HAPROXY_DOMAIN_NAME'] || 'example.com' %>
  server-template <%= service_name %> 10 <%= services_tag_filter %>.<%= service_name %>.service.<%= consul_domain_name %> resolvers consul resolve-prefer ipv4 #check
<%
  end
end
%>

frontend stats
  bind <%= ENV['HAPROXY_STATS_BIND'] || '127.0.0.1:1936' %>
  mode http
  option forceclose
  stats enable
  stats uri /
  stats show-legends
  stats show-desc
  stats show-node
  stats refresh 60
<%
   user_password = ENV['HAPROXY_ADMIN_USER_PASSWORD']
   if user_password
%>
  stats auth <%= user_password %>
<% end %>