diff --git a/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb b/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb index 6b498062..bf0a9895 100644 --- a/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb +++ b/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb @@ -20,11 +20,6 @@ #FIXME: delete group when it's not needed anymore #FIXME: need to find/write OCF for haproxy -# Recommendation from the OpenStack HA guide is to use "source" as balance -# algorithm. This obviously is less useful for load balancing, but we care more -# about HA and things working than about load balancing. -node.default["haproxy"]["defaults"]["balance"] = "source" - # With the default bufsize, getting a keystone PKI token from its ID doesn't # work, because the URI path is too long for haproxy node.default["haproxy"]["global"]["bufsize"] = 32768 diff --git a/chef/cookbooks/haproxy/providers/loadbalancer.rb b/chef/cookbooks/haproxy/providers/loadbalancer.rb index ada975dd..e25d108f 100644 --- a/chef/cookbooks/haproxy/providers/loadbalancer.rb +++ b/chef/cookbooks/haproxy/providers/loadbalancer.rb @@ -47,6 +47,13 @@ else section["mode"] = new_resource.mode end + unless new_resource.balance.empty? + section["balance"] = new_resource.balance + end + + section["stick"] = new_resource.stick + section["stick"]["expire"] ||= "30m" + section["options"] = new_resource.options || [] if section["options"].empty? || section["options"].include?("defaults") section["options"].delete("defaults") diff --git a/chef/cookbooks/haproxy/resources/loadbalancer.rb b/chef/cookbooks/haproxy/resources/loadbalancer.rb index 64e498fc..1ee82346 100644 --- a/chef/cookbooks/haproxy/resources/loadbalancer.rb +++ b/chef/cookbooks/haproxy/resources/loadbalancer.rb @@ -25,6 +25,8 @@ attribute :address, kind_of: String, default: "0.0.0.0" attribute :port, kind_of: Integer, default: 0 attribute :mode, kind_of: String, default: "http", equal_to: ["http", "tcp", "health"] +attribute :balance, kind_of: String, default: "", equal_to: ["", "roundrobin", "static-rr", "leastconn", "first", "source"] attribute :use_ssl, kind_of: [TrueClass, FalseClass], default: false +attribute :stick, kind_of: Hash, default: {} attribute :options, kind_of: Array, default: [] attribute :servers, kind_of: Array, default: [] diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index c2559031..3bfd33d6 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -39,11 +39,47 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats <% content = node[:haproxy][:sections][type][name] -%> <%= type %> <%= name %> bind <%= content[:address] %>:<%= content[:port] %> - <% if content[:use_ssl] -%> - mode tcp - balance source - <% else -%> mode <%= content[:mode] %> + <% unless content[:balance].nil? -%> + balance <%= content[:balance] %> + <% end -%> + + <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> + # maximum SSL session ID length is 32 bytes. + stick-table type binary len 32 size 30k expire <%= content[:stick][:expire] %> + + acl clienthello req_ssl_hello_type 1 + acl serverhello rep_ssl_hello_type 2 + + # use tcp content accepts to detects ssl client and server hello. + tcp-request inspect-delay 5s + tcp-request content accept if clienthello + + # no timeout on response inspect delay by default. + tcp-response content accept if serverhello + + # SSL session ID (SSLID) may be present on a client or server hello. + # Its length is coded on 1 byte at offset 43 and its value starts + # at offset 44. + # Match and learn on request if client hello. + stick on payload_lv(43,1) if clienthello + + # Learn on response if server hello. + stick store-response payload_lv(43,1) if serverhello + <% elsif content[:mode] == "http" && content[:stick] && + content[:stick][:cookies] && !content[:stick][:cookies].empty? + # There are various options here, described in: + # http://stackoverflow.com/questions/27094501/haproxy-1-5-8-how-do-i-configure-cookie-based-stickiness + # We go with the stick-table to avoid no-cache and exposing backends + # through cookies. + # Note that appsession is easier, but deprecated: + # http://serverfault.com/questions/550910/haproxy-appsession-vs-cookie-precedence + -%> + stick-table type string len 64 size 100k expire <%= content[:stick][:expire] %> + <% content[:stick][:cookies].each do |cookie| -%> + stick store-response res.cook(<%= cookie %>) + stick match req.cook(<%= cookie %>) + <% end -%> <% end -%> <% content[:options].each do |option| -%>