summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Larizza <gary@puppetlabs.com>2012-05-07 14:26:21 -0700
committerGary Larizza <gary@puppetlabs.com>2012-05-07 14:26:21 -0700
commitc4799e59b9d9891e6c296c554a11814f14a5abfc (patch)
tree1ba82aa54bf523abb30ee03255114ba58fef1d20
Initial Commit
-rw-r--r--Modulefile12
-rw-r--r--README14
-rw-r--r--manifests/balancermember.pp86
-rw-r--r--manifests/config.pp75
-rw-r--r--manifests/data.pp29
-rw-r--r--manifests/init.pp110
-rw-r--r--spec/spec_helper.rb17
-rw-r--r--templates/haproxy-base.cfg.erb21
-rw-r--r--templates/haproxy_balancermember.erb1
-rw-r--r--templates/haproxy_config_block.erb11
-rw-r--r--tests/init.pp50
11 files changed, 426 insertions, 0 deletions
diff --git a/Modulefile b/Modulefile
new file mode 100644
index 0000000..c8e5647
--- /dev/null
+++ b/Modulefile
@@ -0,0 +1,12 @@
+name 'puppet-haproxy'
+version '0.0.1'
+source 'git://github.com/glarizza/puppet-haproxy'
+author 'Puppet Labs'
+license 'Apache License, Version 2.0'
+summary 'Haproxy Module'
+description 'An Haproxy module for Redhat family OSes using Storeconfigs'
+project_page 'http://github.com/glarizza/puppet-haproxy'
+
+## Add dependencies, if any:
+# dependency 'username/name', '>= 1.2.0'
+dependency 'ripienaar/concat', '>= 0.1.0'
diff --git a/README b/README
new file mode 100644
index 0000000..76b6667
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+haproxy
+
+This haproxy uses storeconfigs to collect and realize balancer member servers
+on a load balancer server. Currently Redhat family OSes are supported, but
+support for other OS Families shouldn't be too difficult to merge in. Pull
+requests accepted!
+
+License
+-------
+Apache 2.0
+
+Contact
+-------
+Gary Larizza <gary@puppetlabs.com>
diff --git a/manifests/balancermember.pp b/manifests/balancermember.pp
new file mode 100644
index 0000000..50e90c0
--- /dev/null
+++ b/manifests/balancermember.pp
@@ -0,0 +1,86 @@
+# == Define Resource Type: haproxy::balancermember
+#
+# This type will setup a balancer member inside a listening service
+# configuration block in /etc/haproxy/haproxy.cfg on the load balancer.
+# currently it only has the ability to specify the instance name,
+# ip address, port, and whether or not it is a backup. More features
+# can be added as needed. The best way to implement this is to export
+# this resource for all haproxy balancer member servers, and then collect
+# them on the main haproxy load balancer.
+#
+# === Requirement/Dependencies:
+#
+# Currently requires the ripienaar/concat module on the Puppet Forge and
+# uses storeconfigs on the Puppet Master to export/collect resources
+# from all balancer members.
+#
+# === Parameters
+#
+# [*name*]
+# The title of the resource is arbitrary and only utilized in the concat
+# fragment name.
+#
+# [*listening_service*]
+# The haproxy service's instance name (or, the title of the
+# haproxy::config resource). This must match up with a declared
+# haproxy::config resource.
+#
+# [*balancer_port*]
+# A unique port for which the balancer member will accept connections
+# from the load balancer. Note that cookie values aren't yet supported,
+# but shouldn't be difficult to add to the configuration.
+#
+# [*order*]
+# The order, or numerical weight, of the fragment created by this defined
+# resource type. This is necessary to ensure the fragment is associated
+# with the correct listening service instance.
+#
+# [*server_name*]
+# The name of the balancer member server as known to haproxy in the
+# listening service's configuration block. This defaults to the
+# hostname
+#
+# [*balancer_ip*]
+# The ip address used to contact the balancer member server
+#
+# [*balancermember_options*]
+# An array of options to be specified after the server declaration
+# in the listening service's configuration block.
+#
+#
+# === Examples
+#
+# Exporting the resource for a balancer member:
+#
+# @@haproxy::balancermember { 'haproxy':
+# listening_service => 'puppet00',
+# balancer_port => '8140',
+# order => '21',
+# server_name => $::hostname,
+# balancer_ip => $::ipaddress,
+# balancermember_options => 'check',
+# }
+#
+#
+# Collecting the resource on a load balancer
+#
+# Haproxy::Balancermember <<| listening_service == 'puppet00' |>>
+#
+# === Authors
+#
+# Gary Larizza <gary@puppetlabs.com>
+#
+define haproxy::balancermember (
+ $listening_service,
+ $balancer_port,
+ $order = '20',
+ $server_name = $::hostname,
+ $balancer_ip = $::ipaddress,
+ $balancermember_options = ''
+) {
+ concat::fragment { "${listening_service}_balancermember_${name}":
+ order => $order,
+ target => '/etc/haproxy/haproxy.cfg',
+ content => template('haproxy/haproxy_balancermember.erb'),
+ }
+}
diff --git a/manifests/config.pp b/manifests/config.pp
new file mode 100644
index 0000000..55b40d7
--- /dev/null
+++ b/manifests/config.pp
@@ -0,0 +1,75 @@
+# == Define Resource Type: haproxy::config
+#
+# This type will setup a listening service configuration block inside
+# the haproxy.cfg file on an haproxy load balancer. Each listening service
+# configuration needs one or more load balancer member server (that can be
+# declared with the haproxy::balancermember defined resource type). Using
+# storeconfigs, you can export the haproxy::balancermember resources on all
+# load balancer member servers, and then collect them on a single haproxy
+# load balancer server.
+#
+# === Requirement/Dependencies:
+#
+# Currently requires the ripienaar/concat module on the Puppet Forge and
+# uses storeconfigs on the Puppet Master to export/collect resources
+# from all balancer members.
+#
+# === Parameters
+#
+# [*name*]
+# The namevar of the defined resource type is the listening service's name.
+# This name goes right after the 'listen' statement in haproxy.cfg
+#
+# [*virtual_ip_port*]
+# A unique port, or a port range for which the proxy will accept connections
+# for the ip address specified in the virtual_ip parameter.
+#
+# [*order*]
+# The order, or numerical weight, of the fragment created by this defined
+# resource type. This is necessary to ensure the fragment is associated
+# with the correct listening service instance.
+#
+# [*virtual_ip*]
+# The ip address the proxy binds to. Empty addresses, '*', and '0.0.0.0'
+# mean that the proxy listens to all valid addresses on the system.
+#
+# [*mode*]
+# The mode of operation for the listening service. Valid values are 'tcp',
+# HTTP', and 'health'.
+#
+# [*haproxy_config_options*]
+# A hash of options that are inserted into the listening service
+# configuration block.
+#
+#
+# === Examples
+#
+# Exporting the resource for a balancer member:
+#
+# haproxy::config { 'puppet00':
+# order => '20',
+# virtual_ip => $::ipaddress,
+# virtual_ip_port => '18140',
+# mode => 'tcp',
+# haproxy_config_options => {'option' => 'tcplog', 'option' => 'ssl-hello-chk', 'balance' => 'roundrobin'},
+# }
+#
+# === Authors
+#
+# Gary Larizza <gary@puppetlabs.com>
+#
+define haproxy::config (
+ $virtual_ip_port,
+ $order = '20',
+ $virtual_ip = $::ipaddress,
+ $mode = 'tcp',
+ $haproxy_config_options = {'option' => 'tcplog', 'option' => 'ssl-hello-chk', 'balance' => 'roundrobin'},
+) {
+ concat::fragment { "${name}_config_block":
+ order => $order,
+ target => '/etc/haproxy/haproxy.cfg',
+ content => template('haproxy/haproxy_config_block.erb'),
+ }
+
+ Haproxy::Balancermember <<| listening_service == $name |>>
+}
diff --git a/manifests/data.pp b/manifests/data.pp
new file mode 100644
index 0000000..aa49285
--- /dev/null
+++ b/manifests/data.pp
@@ -0,0 +1,29 @@
+# == Class: haproxy::data
+#
+# This is a container class holding default parameters for for haproxy class.
+# currently, only the Redhat family is supported, but this can be easily
+# extended by changing package names and configuration file paths.
+#
+class haproxy::data {
+ case $osfamily {
+ Redhat: {
+ $haproxy_global_options = { 'log' => "${::ipaddress} local0",
+ 'chroot' => '/var/lib/haproxy',
+ 'pidfile' => '/var/run/haproxy.pid',
+ 'maxconn' => '4000',
+ 'user' => 'haproxy',
+ 'group' => 'haproxy',
+ 'daemon' => '',
+ 'stats' => 'socket /var/lib/haproxy/stats'
+ }
+ $haproxy_defaults_options = { 'log' => 'global',
+ 'stats' => 'enable',
+ 'option' => 'redispatch',
+ 'retries' => '3',
+ 'timeout' => ['http-request 10s', 'queue 1m', 'connect 10s', 'client 1m', 'server 1m', 'check 10s'],
+ 'maxconn' => '8000'
+ }
+ }
+ default: { fail("The $::operatingsystem operating system is not supported with the haproxy module") }
+ }
+}
diff --git a/manifests/init.pp b/manifests/init.pp
new file mode 100644
index 0000000..6dde629
--- /dev/null
+++ b/manifests/init.pp
@@ -0,0 +1,110 @@
+# == Class: puppet-haproxy
+#
+# A Puppet module, using storeconfigs, to model an haproxy configuration.
+# Currently VERY limited - assumes Redhat/CentOS setup. Pull requests accepted!
+#
+# === Requirement/Dependencies:
+#
+# Currently requires the ripienaar/concat module on the Puppet Forge and
+# uses storeconfigs on the Puppet Master to export/collect resources
+# from all balancer members.
+#
+# === Parameters
+#
+# [*enable*]
+# Chooses whether haproxy should be installed or ensured absent.
+# Currently ONLY accepts valid boolean true/false values.
+#
+# [*haproxy_global_options*]
+# A hash of all the haproxy global options. If you want to specify more
+# than one option (i.e. multiple timeout or stats options), pass those
+# options as an array and you will get a line for each of them in the
+# resultant haproxy.cfg file.
+#
+# [*haproxy_defaults_options*]
+# A hash of all the haproxy defaults options. If you want to specify more
+# than one option (i.e. multiple timeout or stats options), pass those
+# options as an array and you will get a line for each of them in the
+# resultant haproxy.cfg file.
+#
+#
+# === Examples
+#
+# class { 'haproxy':
+# enable => true,
+# haproxy_global_options => { 'log' => "${::ipaddress} local0",
+# 'chroot' => '/var/lib/haproxy',
+# 'pidfile' => '/var/run/haproxy.pid',
+# 'maxconn' => '4000',
+# 'user' => 'haproxy',
+# 'group' => 'haproxy',
+# 'daemon' => '',
+# 'stats' => 'socket /var/lib/haproxy/stats'
+# },
+# haproxy_defaults_options => { 'log' => 'global',
+# 'stats' => 'enable',
+# 'option' => 'redispatch',
+# 'retries' => '3',
+# 'timeout' => ['http-request 10s', 'queue 1m', 'connect 10s', 'client 1m', 'server 1m', 'check 10s'],
+# 'maxconn' => '8000'
+# },
+#
+# }
+#
+# === Authors
+#
+# Gary Larizza <gary@puppetlabs.com>
+#
+class haproxy (
+ $enable = true,
+ $haproxy_global_options = $haproxy::data::haproxy_global_options,
+ $haproxy_defaults_options = $haproxy::data::haproxy_defaults_options
+) inherits haproxy::data {
+ include concat::setup
+
+ package { 'haproxy':
+ ensure => $enable ? {
+ true => present,
+ false => absent,
+ },
+ name => 'haproxy',
+ }
+
+ if $enable {
+ concat { '/etc/haproxy/haproxy.cfg':
+ owner => '0',
+ group => '0',
+ mode => '0644',
+ require => Package['haproxy'],
+ notify => Service['haproxy'],
+ }
+
+ # Simple Header
+ concat::fragment { '00-header':
+ target => '/etc/haproxy/haproxy.cfg',
+ order => '01',
+ content => "# This file managed by Puppet\n",
+ }
+
+ # Most of the variables are used inside the haproxy-base.cfg.erb template
+ concat::fragment { 'haproxy-base':
+ target => '/etc/haproxy/haproxy.cfg',
+ order => '10',
+ content => template('haproxy/haproxy-base.cfg.erb'),
+ }
+ }
+
+ service { 'haproxy':
+ ensure => $enable ? {
+ true => running,
+ false => stopped,
+ },
+ enable => $enable ? {
+ true => true,
+ false => false,
+ },
+ name => 'haproxy',
+ hasstatus => true,
+ require => Concat['/etc/haproxy/haproxy.cfg'],
+ }
+}
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..5fda588
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,17 @@
+dir = File.expand_path(File.dirname(__FILE__))
+$LOAD_PATH.unshift File.join(dir, 'lib')
+
+require 'mocha'
+require 'puppet'
+require 'rspec'
+require 'spec/autorun'
+
+Spec::Runner.configure do |config|
+ config.mock_with :mocha
+end
+
+# We need this because the RAL uses 'should' as a method. This
+# allows us the same behaviour but with a different method name.
+class Object
+ alias :must :should
+end
diff --git a/templates/haproxy-base.cfg.erb b/templates/haproxy-base.cfg.erb
new file mode 100644
index 0000000..3e21436
--- /dev/null
+++ b/templates/haproxy-base.cfg.erb
@@ -0,0 +1,21 @@
+global
+<% haproxy_global_options.sort.each do |key,val| -%>
+<% if val.is_a?(Array) -%>
+<% val.each do |item| -%>
+ <%= key %> <%= item %>
+<% end -%>
+<% else -%>
+ <%= key %> <%= val %>
+<% end -%>
+<% end -%>
+
+defaults
+<% haproxy_defaults_options.sort.each do |key,val| -%>
+<% if val.is_a?(Array) -%>
+<% val.each do |item| -%>
+ <%= key %> <%= item %>
+<% end -%>
+<% else -%>
+ <%= key %> <%= val %>
+<% end -%>
+<% end -%> \ No newline at end of file
diff --git a/templates/haproxy_balancermember.erb b/templates/haproxy_balancermember.erb
new file mode 100644
index 0000000..b739e11
--- /dev/null
+++ b/templates/haproxy_balancermember.erb
@@ -0,0 +1 @@
+ server <%= server_name %> <%= balancer_ip %>:<%= balancer_port %> <% balancermember_options.each do |item| %> <%= item %> <% end %>
diff --git a/templates/haproxy_config_block.erb b/templates/haproxy_config_block.erb
new file mode 100644
index 0000000..8737dfc
--- /dev/null
+++ b/templates/haproxy_config_block.erb
@@ -0,0 +1,11 @@
+
+listen <%= name %> <%= virtual_ip %>:<%= virtual_ip_port %>
+<% haproxy_config_options.sort.each do |key, val| -%>
+<% if val.is_a?(Array) -%>
+<% val.each do |item| -%>
+ <%= key %> <%= item %>
+<% end -%>
+<% else -%>
+ <%= key %> <%= val %>
+<% end -%>
+<% end -%>
diff --git a/tests/init.pp b/tests/init.pp
new file mode 100644
index 0000000..32c32c7
--- /dev/null
+++ b/tests/init.pp
@@ -0,0 +1,50 @@
+# Declare haproxy base class with configuration options
+class { 'haproxy':
+ enable => true,
+ haproxy_global_options => { 'log' => "${::ipaddress} local0",
+ 'chroot' => '/var/lib/haproxy',
+ 'pidfile' => '/var/run/haproxy.pid',
+ 'maxconn' => '4000',
+ 'user' => 'haproxy',
+ 'group' => 'haproxy',
+ 'daemon' => '',
+ 'stats' => 'socket /var/lib/haproxy/stats'
+ },
+ haproxy_defaults_options => { 'log' => 'global',
+ 'stats' => 'enable',
+ 'option' => 'redispatch',
+ 'retries' => '3',
+ 'timeout' => ['http-request 10s', 'queue 1m', 'connect 10s', 'client 1m', 'server 1m', 'check 10s'],
+ 'maxconn' => '8000'
+ },
+
+}
+
+# Export a balancermember server, note that the listening_service parameter
+# will/must correlate with an haproxy::config defined resource type.
+@@haproxy::balancermember { $fqdn:
+ order => '21',
+ listening_service => 'puppet00',
+ server_name => $::hostname,
+ balancer_ip => $::ipaddress,
+ balancer_port => '8140',
+ balancermember_options => 'check'
+}
+
+# Declare a couple of Listening Services for haproxy.cfg
+# Note that the balancermember server resources are being collected in
+# the haproxy::config defined resource type with the following line:
+# Haproxy::Balancermember <<| listening_service == $name |>>
+haproxy::config { 'puppet00':
+ order => '20',
+ virtual_ip => $::ipaddress,
+ virtual_ip_port => '18140',
+ haproxy_config_options => { 'option' => ['tcplog', 'ssl-hello-chk'], 'balance' => 'roundrobin' },
+}
+haproxy::config { 'stats':
+ order => '30',
+ virtual_ip => '',
+ virtual_ip_port => '9090',
+ haproxy_config_options => { 'mode' => 'http', 'stats' => ['uri /', 'auth puppet:puppet'] },
+}
+