summaryrefslogtreecommitdiff
path: root/puppet/modules
diff options
context:
space:
mode:
Diffstat (limited to 'puppet/modules')
-rw-r--r--puppet/modules/haproxy/.fixtures.yml5
-rw-r--r--puppet/modules/haproxy/.gemfile5
-rw-r--r--puppet/modules/haproxy/.travis.yml23
-rw-r--r--puppet/modules/haproxy/CHANGELOG5
-rw-r--r--puppet/modules/haproxy/Modulefile12
-rw-r--r--puppet/modules/haproxy/README.md87
-rw-r--r--puppet/modules/haproxy/Rakefile1
-rw-r--r--puppet/modules/haproxy/manifests/balancermember.pp95
-rw-r--r--puppet/modules/haproxy/manifests/init.pp149
-rw-r--r--puppet/modules/haproxy/manifests/listen.pp95
-rw-r--r--puppet/modules/haproxy/manifests/params.pp65
-rw-r--r--puppet/modules/haproxy/spec/classes/haproxy_spec.rb138
-rw-r--r--puppet/modules/haproxy/spec/defines/balancermember_spec.rb82
-rw-r--r--puppet/modules/haproxy/spec/defines/listen_spec.rb53
-rw-r--r--puppet/modules/haproxy/spec/spec.opts6
-rw-r--r--puppet/modules/haproxy/spec/spec_helper.rb1
-rw-r--r--puppet/modules/haproxy/templates/haproxy-base.cfg.erb21
-rw-r--r--puppet/modules/haproxy/templates/haproxy_balancermember.erb3
-rw-r--r--puppet/modules/haproxy/templates/haproxy_listen_block.erb10
-rw-r--r--puppet/modules/haproxy/tests/init.pp69
20 files changed, 925 insertions, 0 deletions
diff --git a/puppet/modules/haproxy/.fixtures.yml b/puppet/modules/haproxy/.fixtures.yml
new file mode 100644
index 00000000..8d6f22d6
--- /dev/null
+++ b/puppet/modules/haproxy/.fixtures.yml
@@ -0,0 +1,5 @@
+fixtures:
+ repositories:
+ concat: "git://github.com/ripienaar/puppet-concat.git"
+ symlinks:
+ haproxy: "#{source_dir}"
diff --git a/puppet/modules/haproxy/.gemfile b/puppet/modules/haproxy/.gemfile
new file mode 100644
index 00000000..9aad840c
--- /dev/null
+++ b/puppet/modules/haproxy/.gemfile
@@ -0,0 +1,5 @@
+source :rubygems
+
+puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
+gem 'puppet', puppetversion
+gem 'puppetlabs_spec_helper', '>= 0.1.0'
diff --git a/puppet/modules/haproxy/.travis.yml b/puppet/modules/haproxy/.travis.yml
new file mode 100644
index 00000000..fdbc95dc
--- /dev/null
+++ b/puppet/modules/haproxy/.travis.yml
@@ -0,0 +1,23 @@
+language: ruby
+rvm:
+ - 1.8.7
+ - 1.9.3
+script: "rake spec"
+branches:
+ only:
+ - master
+env:
+ - PUPPET_VERSION=2.6.17
+ - PUPPET_VERSION=2.7.19
+ #- PUPPET_VERSION=3.0.1 # Breaks due to rodjek/rspec-puppet#58
+notifications:
+ email: false
+gemfile: .gemfile
+matrix:
+ exclude:
+ - rvm: 1.9.3
+ gemfile: .gemfile
+ env: PUPPET_VERSION=2.6.17
+ - rvm: 1.8.7
+ gemfile: .gemfile
+ env: PUPPET_VERSION=3.0.1
diff --git a/puppet/modules/haproxy/CHANGELOG b/puppet/modules/haproxy/CHANGELOG
new file mode 100644
index 00000000..0b6d670f
--- /dev/null
+++ b/puppet/modules/haproxy/CHANGELOG
@@ -0,0 +1,5 @@
+2012-10-12 - Version 0.2.0
+- Initial public release
+- Backwards incompatible changes all around
+- No longer needs ordering passed for more than one listener
+- Accepts multiple listen ips/ports/server_names
diff --git a/puppet/modules/haproxy/Modulefile b/puppet/modules/haproxy/Modulefile
new file mode 100644
index 00000000..e729739b
--- /dev/null
+++ b/puppet/modules/haproxy/Modulefile
@@ -0,0 +1,12 @@
+name 'puppetlabs-haproxy'
+version '0.2.0'
+source 'git://github.com/puppetlabs/puppetlabs-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/puppetlabs/puppetlabs-haproxy'
+
+## Add dependencies, if any:
+# dependency 'username/name', '>= 1.2.0'
+dependency 'ripienaar/concat', '>= 0.1.0'
diff --git a/puppet/modules/haproxy/README.md b/puppet/modules/haproxy/README.md
new file mode 100644
index 00000000..d209e9ab
--- /dev/null
+++ b/puppet/modules/haproxy/README.md
@@ -0,0 +1,87 @@
+PuppetLabs Module for haproxy
+=============================
+
+HAProxy is an HA proxying daemon for load-balancing to clustered services. It
+can proxy TCP directly, or other kinds of traffic such as HTTP.
+
+Dependencies
+------------
+
+Tested and built on Debian, Ubuntu and CentOS
+
+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.
+
+Basic Usage
+-----------
+
+This haproxy uses storeconfigs to collect and realize balancer member servers
+on a load balancer server.
+
+*To install and configure HAProxy server listening on port 8140*
+
+```puppet
+node 'haproxy-server' {
+ class { 'haproxy': }
+ haproxy::listen { 'puppet00':
+ ipaddress => $::ipaddress,
+ ports => '8140',
+ }
+}
+```
+
+*To add backend loadbalance members*
+
+```puppet
+node 'webserver01' {
+ @@haproxy::balancermember { $fqdn:
+ listening_service => 'puppet00',
+ server_names => $::hostname,
+ ipaddresses => $::ipaddress,
+ ports => '8140',
+ options => 'check'
+ }
+}
+```
+
+Configuring haproxy options
+---------------------------
+
+The base `haproxy` class can accept two parameters which will configure basic
+behaviour of the haproxy server daemon:
+
+- `global_options` to configure the `global` section in `haproxy.cfg`
+- `defaults_options` to configure the `defaults` section in `haproxy.cfg`
+
+Configuring haproxy daemon listener
+-----------------------------------
+
+One `haproxy::listen` defined resource should be defined for each HAProxy loadbalanced set of backend servers. The title of the `haproxy::listen` resource is the key to which balancer members will be proxied to. The `ipaddress` field should be the public ip address which the loadbalancer will be contacted on. The `ports` attribute can accept an array or comma-separated list of ports which should be proxied to the `haproxy::balancermemeber` nodes.
+
+Configuring haproxy loadbalanced member nodes
+---------------------------------------------
+
+The `haproxy::balacemember` defined resource should be exported from each node
+which is serving loadbalanced traffic. the `listening_service` attribute will
+associate it with `haproxy::listen` directives on the haproxy node.
+`ipaddresses` and `ports` will be assigned to the member to be contacted on. If an array of `ipaddresses` and `server_names` are provided then they will be added to the config in lock-step.
+
+
+Copyright and License
+---------------------
+
+Copyright (C) 2012 [Puppet Labs](https://www.puppetlabs.com/) Inc
+
+Puppet Labs can be contacted at: info@puppetlabs.com
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/puppet/modules/haproxy/Rakefile b/puppet/modules/haproxy/Rakefile
new file mode 100644
index 00000000..cd3d3799
--- /dev/null
+++ b/puppet/modules/haproxy/Rakefile
@@ -0,0 +1 @@
+require 'puppetlabs_spec_helper/rake_tasks'
diff --git a/puppet/modules/haproxy/manifests/balancermember.pp b/puppet/modules/haproxy/manifests/balancermember.pp
new file mode 100644
index 00000000..a0e27539
--- /dev/null
+++ b/puppet/modules/haproxy/manifests/balancermember.pp
@@ -0,0 +1,95 @@
+# == 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::listen resource). This must match up with a declared
+# haproxy::listen resource.
+#
+# [*ports*]
+# An array or commas-separated list of ports 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. If you use an array in server_names and ipaddresses, the
+# same port is used for all balancermembers.
+#
+# [*server_names*]
+# The name of the balancer member server as known to haproxy in the
+# listening service's configuration block. This defaults to the
+# hostname. Can be an array of the same length as ipaddresses,
+# in which case a balancermember is created for each pair of
+# server_names and ipaddresses (in lockstep).
+#
+# [*ipaddresses*]
+# The ip address used to contact the balancer member server.
+# Can be an array, see documentation to server_names.
+#
+# [*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',
+# ports => '8140',
+# server_names => $::hostname,
+# ipaddresses => $::ipaddress,
+# options => 'check',
+# }
+#
+#
+# Collecting the resource on a load balancer
+#
+# Haproxy::Balancermember <<| listening_service == 'puppet00' |>>
+#
+# Creating the resource for multiple balancer members at once
+# (for single-pass installation of haproxy without requiring a first
+# pass to export the resources if you know the members in advance):
+#
+# haproxy::balancermember { 'haproxy':
+# listening_service => 'puppet00',
+# ports => '8140',
+# server_names => ['server01', 'server02'],
+# ipaddresses => ['192.168.56.200', '192.168.56.201'],
+# options => 'check',
+# }
+#
+# (this resource can be declared anywhere)
+#
+define haproxy::balancermember (
+ $listening_service,
+ $ports,
+ $server_names = $::hostname,
+ $ipaddresses = $::ipaddress,
+ $options = ''
+) {
+ # Template uses $ipaddresses, $server_name, $ports, $option
+ concat::fragment { "${listening_service}_balancermember_${name}":
+ order => "20-${listening_service}-${name}",
+ target => '/etc/haproxy/haproxy.cfg',
+ content => template('haproxy/haproxy_balancermember.erb'),
+ }
+}
diff --git a/puppet/modules/haproxy/manifests/init.pp b/puppet/modules/haproxy/manifests/init.pp
new file mode 100644
index 00000000..b91591a3
--- /dev/null
+++ b/puppet/modules/haproxy/manifests/init.pp
@@ -0,0 +1,149 @@
+# == Class: haproxy
+#
+# A Puppet module, using storeconfigs, to model an haproxy configuration.
+# Currently VERY limited - 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.
+#
+# [*version*]
+# Allows you to specify what version of the package to install.
+# Default is simply 'present'
+#
+# [*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.
+#
+# [*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,
+# 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'
+# },
+# 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'
+# },
+# }
+#
+class haproxy (
+ $manage_service = true,
+ $enable = true,
+ $version = 'present',
+ $global_options = $haproxy::params::global_options,
+ $defaults_options = $haproxy::params::defaults_options
+) inherits haproxy::params {
+ include concat::setup
+
+ package { 'haproxy':
+ ensure => $enable ? {
+ true => $version,
+ false => absent,
+ },
+ name => 'haproxy',
+ }
+
+ if $enable {
+ concat { '/etc/haproxy/haproxy.cfg':
+ owner => '0',
+ group => '0',
+ mode => '0644',
+ require => Package['haproxy'],
+ notify => $manage_service ? {
+ true => Service['haproxy'],
+ false => undef,
+ },
+ }
+
+ # Simple Header
+ concat::fragment { '00-header':
+ target => '/etc/haproxy/haproxy.cfg',
+ order => '01',
+ content => "# This file managed by Puppet\n",
+ }
+
+ # Template uses $global_options, $defaults_options
+ concat::fragment { 'haproxy-base':
+ target => '/etc/haproxy/haproxy.cfg',
+ order => '10',
+ content => template('haproxy/haproxy-base.cfg.erb'),
+ }
+
+ if ($::osfamily == 'Debian') {
+ file { '/etc/default/haproxy':
+ content => 'ENABLED=1',
+ require => Package['haproxy'],
+ before => $manage_service ? {
+ true => Service['haproxy'],
+ false => undef,
+ },
+ }
+ }
+
+ file { $global_options['chroot']:
+ ensure => directory,
+ owner => $global_options['user'],
+ group => $global_options['group'],
+ mode => '0550',
+ require => Package['haproxy']
+ }
+
+ }
+
+ if $manage_service {
+ service { 'haproxy':
+ ensure => $enable ? {
+ true => running,
+ false => stopped,
+ },
+ enable => $enable ? {
+ true => true,
+ false => false,
+ },
+ name => 'haproxy',
+ hasrestart => true,
+ hasstatus => true,
+ require => [
+ Concat['/etc/haproxy/haproxy.cfg'],
+ File[$global_options['chroot']],
+ ],
+ }
+ }
+}
diff --git a/puppet/modules/haproxy/manifests/listen.pp b/puppet/modules/haproxy/manifests/listen.pp
new file mode 100644
index 00000000..00636e3d
--- /dev/null
+++ b/puppet/modules/haproxy/manifests/listen.pp
@@ -0,0 +1,95 @@
+# == Define Resource Type: haproxy::listen
+#
+# 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
+#
+# [*ports*]
+# Ports on which the proxy will listen for connections on the ip address
+# specified in the virtual_ip parameter. Accepts either a single
+# comma-separated string or an array of strings which may be ports or
+# hyphenated port ranges.
+#
+# [*ipaddress*]
+# 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'.
+#
+# [*options*]
+# A hash of options that are inserted into the listening service
+# configuration block.
+#
+# [*collect_exported*]
+# Boolean, default 'true'. True means 'collect exported @@balancermember resources'
+# (for the case when every balancermember node exports itself), false means
+# 'rely on the existing declared balancermember resources' (for the case when you
+# know the full set of balancermembers in advance and use haproxy::balancermember
+# with array arguments, which allows you to deploy everything in 1 run)
+#
+#
+# === Examples
+#
+# Exporting the resource for a balancer member:
+#
+# haproxy::listen { 'puppet00':
+# ipaddress => $::ipaddress,
+# ports => '18140',
+# mode => 'tcp',
+# options => {
+# 'option' => [
+# 'tcplog',
+# 'ssl-hello-chk'
+# ],
+# 'balance' => 'roundrobin'
+# },
+# }
+#
+# === Authors
+#
+# Gary Larizza <gary@puppetlabs.com>
+#
+define haproxy::listen (
+ $ports,
+ $ipaddress = [$::ipaddress],
+ $mode = 'tcp',
+ $collect_exported = true,
+ $options = {
+ 'option' => [
+ 'tcplog',
+ 'ssl-hello-chk'
+ ],
+ 'balance' => 'roundrobin'
+ }
+) {
+ # Template uses: $name, $ipaddress, $ports, $options
+ concat::fragment { "${name}_listen_block":
+ order => "20-${name}-00",
+ target => '/etc/haproxy/haproxy.cfg',
+ content => template('haproxy/haproxy_listen_block.erb'),
+ }
+
+ if $collect_exported {
+ Haproxy::Balancermember <<| listening_service == $name |>>
+ }
+ # else: the resources have been created and they introduced their
+ # concat fragments. We don't have to do anything about them.
+}
diff --git a/puppet/modules/haproxy/manifests/params.pp b/puppet/modules/haproxy/manifests/params.pp
new file mode 100644
index 00000000..53442ddc
--- /dev/null
+++ b/puppet/modules/haproxy/manifests/params.pp
@@ -0,0 +1,65 @@
+# == Class: haproxy::params
+#
+# 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::params {
+ case $osfamily {
+ Redhat: {
+ $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'
+ }
+ $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'
+ }
+ }
+ Debian: {
+ $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'
+ }
+ $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 $::osfamily operating system is not supported with the haproxy module") }
+ }
+}
diff --git a/puppet/modules/haproxy/spec/classes/haproxy_spec.rb b/puppet/modules/haproxy/spec/classes/haproxy_spec.rb
new file mode 100644
index 00000000..4b5902ce
--- /dev/null
+++ b/puppet/modules/haproxy/spec/classes/haproxy_spec.rb
@@ -0,0 +1,138 @@
+require 'spec_helper'
+
+describe 'haproxy', :type => :class do
+ let(:default_facts) do
+ {
+ :concat_basedir => '/dne',
+ :ipaddress => '10.10.10.10'
+ }
+ end
+ context 'on supported platforms' do
+ describe 'for OS-agnostic configuration' do
+ ['Debian', 'RedHat'].each do |osfamily|
+ context "on #{osfamily} family operatingsystems" do
+ let(:facts) do
+ { :osfamily => osfamily }.merge default_facts
+ end
+ let(:params) do
+ {'enable' => true}
+ end
+ it { should include_class('concat::setup') }
+ it 'should install the haproxy package' do
+ subject.should contain_package('haproxy').with(
+ 'ensure' => 'present'
+ )
+ end
+ it 'should install the haproxy service' do
+ subject.should contain_service('haproxy').with(
+ 'ensure' => 'running',
+ 'enable' => 'true',
+ 'hasrestart' => 'true',
+ 'hasstatus' => 'true',
+ 'require' => [
+ 'Concat[/etc/haproxy/haproxy.cfg]',
+ 'File[/var/lib/haproxy]'
+ ]
+ )
+ end
+ it 'should set up /etc/haproxy/haproxy.cfg as a concat resource' do
+ subject.should contain_concat('/etc/haproxy/haproxy.cfg').with(
+ 'owner' => '0',
+ 'group' => '0',
+ 'mode' => '0644'
+ )
+ end
+ it 'should manage the chroot directory' do
+ subject.should contain_file('/var/lib/haproxy').with(
+ 'ensure' => 'directory'
+ )
+ end
+ it 'should contain a header concat fragment' do
+ subject.should contain_concat__fragment('00-header').with(
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'order' => '01',
+ 'content' => "# This file managed by Puppet\n"
+ )
+ end
+ it 'should contain a haproxy-base concat fragment' do
+ subject.should contain_concat__fragment('haproxy-base').with(
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'order' => '10'
+ )
+ end
+ describe 'Base concat fragment contents' do
+ let(:contents) { param_value(subject, 'concat::fragment', 'haproxy-base', 'content').split("\n") }
+ it 'should contain global and defaults sections' do
+ contents.should include('global')
+ contents.should include('defaults')
+ end
+ it 'should log to an ip address for local0' do
+ contents.should be_any { |match| match =~ / log \d+(\.\d+){3} local0/ }
+ end
+ it 'should specify the default chroot' do
+ contents.should include(' chroot /var/lib/haproxy')
+ end
+ it 'should specify the correct user' do
+ contents.should include(' user haproxy')
+ end
+ it 'should specify the correct group' do
+ contents.should include(' group haproxy')
+ end
+ it 'should specify the correct pidfile' do
+ contents.should include(' pidfile /var/run/haproxy.pid')
+ end
+ end
+ end
+ context "on #{osfamily} family operatingsystems without managing the service" do
+ let(:facts) do
+ { :osfamily => osfamily }.merge default_facts
+ end
+ let(:params) do
+ {
+ 'enable' => true,
+ 'manage_service' => false,
+ }
+ end
+ it { should include_class('concat::setup') }
+ it 'should install the haproxy package' do
+ subject.should contain_package('haproxy').with(
+ 'ensure' => 'present'
+ )
+ end
+ it 'should install the haproxy service' do
+ subject.should_not contain_service('haproxy')
+ end
+ end
+ end
+ end
+ describe 'for OS-specific configuration' do
+ context 'only on Debian family operatingsystems' do
+ let(:facts) do
+ { :osfamily => 'Debian' }.merge default_facts
+ end
+ it 'should manage haproxy service defaults' do
+ subject.should contain_file('/etc/default/haproxy').with(
+ 'before' => 'Service[haproxy]',
+ 'require' => 'Package[haproxy]'
+ )
+ verify_contents(subject, '/etc/default/haproxy', ['ENABLED=1'])
+ end
+ end
+ context 'only on RedHat family operatingsystems' do
+ let(:facts) do
+ { :osfamily => 'RedHat' }.merge default_facts
+ end
+ end
+ end
+ end
+ context 'on unsupported operatingsystems' do
+ let(:facts) do
+ { :osfamily => 'RainbowUnicorn' }.merge default_facts
+ end
+ it do
+ expect {
+ should contain_service('haproxy')
+ }.to raise_error(Puppet::Error, /operating system is not supported with the haproxy module/)
+ end
+ end
+end
diff --git a/puppet/modules/haproxy/spec/defines/balancermember_spec.rb b/puppet/modules/haproxy/spec/defines/balancermember_spec.rb
new file mode 100644
index 00000000..74bc7a8b
--- /dev/null
+++ b/puppet/modules/haproxy/spec/defines/balancermember_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe 'haproxy::balancermember' do
+ let(:title) { 'tyler' }
+ let(:facts) do
+ {
+ :ipaddress => '1.1.1.1',
+ :hostname => 'dero'
+ }
+ end
+
+ context 'with a single balancermember option' do
+ let(:params) do
+ {
+ :name => 'tyler',
+ :listening_service => 'croy',
+ :ports => '18140',
+ :options => 'check'
+ }
+ end
+
+ it { should contain_concat__fragment('croy_balancermember_tyler').with(
+ 'order' => '20-croy-tyler',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => " server dero 1.1.1.1:18140 check\n\n"
+ ) }
+ end
+
+ context 'with multiple balancermember options' do
+ let(:params) do
+ {
+ :name => 'tyler',
+ :listening_service => 'croy',
+ :ports => '18140',
+ :options => ['check', 'close']
+ }
+ end
+
+ it { should contain_concat__fragment('croy_balancermember_tyler').with(
+ 'order' => '20-croy-tyler',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => " server dero 1.1.1.1:18140 check close\n\n"
+ ) }
+ end
+
+ context 'with multiple servers' do
+ let(:params) do
+ {
+ :name => 'tyler',
+ :listening_service => 'croy',
+ :ports => '18140',
+ :server_names => ['server01', 'server02'],
+ :ipaddresses => ['192.168.56.200', '192.168.56.201'],
+ :options => ['check']
+ }
+ end
+
+ it { should contain_concat__fragment('croy_balancermember_tyler').with(
+ 'order' => '20-croy-tyler',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => " server server01 192.168.56.200:18140 check\n server server02 192.168.56.201:18140 check\n\n"
+ ) }
+ end
+ context 'with multiple servers and multiple ports' do
+ let(:params) do
+ {
+ :name => 'tyler',
+ :listening_service => 'croy',
+ :ports => ['18140','18150'],
+ :server_names => ['server01', 'server02'],
+ :ipaddresses => ['192.168.56.200', '192.168.56.201'],
+ :options => ['check']
+ }
+ end
+
+ it { should contain_concat__fragment('croy_balancermember_tyler').with(
+ 'order' => '20-croy-tyler',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => " server server01 192.168.56.200:18140,192.168.56.200:18150 check\n server server02 192.168.56.201:18140,192.168.56.201:18150 check\n\n"
+ ) }
+ end
+end
diff --git a/puppet/modules/haproxy/spec/defines/listen_spec.rb b/puppet/modules/haproxy/spec/defines/listen_spec.rb
new file mode 100644
index 00000000..31dd4c85
--- /dev/null
+++ b/puppet/modules/haproxy/spec/defines/listen_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe 'haproxy::listen' do
+ let(:title) { 'tyler' }
+ let(:facts) {{ :ipaddress => '1.1.1.1' }}
+ context "when only one port is provided" do
+ let(:params) do
+ {
+ :name => 'croy',
+ :ports => '18140'
+ }
+ end
+
+ it { should contain_concat__fragment('croy_listen_block').with(
+ 'order' => '20-croy-00',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => "listen croy\n\n bind 1.1.1.1:18140\n\n balance roundrobin\n option tcplog\n option ssl-hello-chk\n"
+ ) }
+ end
+ context "when an array of ports is provided" do
+ let(:params) do
+ {
+ :name => 'apache',
+ :ipaddress => '23.23.23.23',
+ :ports => [
+ '80',
+ '443',
+ ]
+ }
+ end
+
+ it { should contain_concat__fragment('apache_listen_block').with(
+ 'order' => '20-apache-00',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => "listen apache\n\n bind 23.23.23.23:80\n\n bind 23.23.23.23:443\n\n balance roundrobin\n option tcplog\n option ssl-hello-chk\n"
+ ) }
+ end
+ context "when a comma-separated list of ports is provided" do
+ let(:params) do
+ {
+ :name => 'apache',
+ :ipaddress => '23.23.23.23',
+ :ports => '80,443'
+ }
+ end
+
+ it { should contain_concat__fragment('apache_listen_block').with(
+ 'order' => '20-apache-00',
+ 'target' => '/etc/haproxy/haproxy.cfg',
+ 'content' => "listen apache\n\n bind 23.23.23.23:80\n\n bind 23.23.23.23:443\n\n balance roundrobin\n option tcplog\n option ssl-hello-chk\n"
+ ) }
+ end
+end
diff --git a/puppet/modules/haproxy/spec/spec.opts b/puppet/modules/haproxy/spec/spec.opts
new file mode 100644
index 00000000..91cd6427
--- /dev/null
+++ b/puppet/modules/haproxy/spec/spec.opts
@@ -0,0 +1,6 @@
+--format
+s
+--colour
+--loadby
+mtime
+--backtrace
diff --git a/puppet/modules/haproxy/spec/spec_helper.rb b/puppet/modules/haproxy/spec/spec_helper.rb
new file mode 100644
index 00000000..2c6f5664
--- /dev/null
+++ b/puppet/modules/haproxy/spec/spec_helper.rb
@@ -0,0 +1 @@
+require 'puppetlabs_spec_helper/module_spec_helper'
diff --git a/puppet/modules/haproxy/templates/haproxy-base.cfg.erb b/puppet/modules/haproxy/templates/haproxy-base.cfg.erb
new file mode 100644
index 00000000..f25d5c34
--- /dev/null
+++ b/puppet/modules/haproxy/templates/haproxy-base.cfg.erb
@@ -0,0 +1,21 @@
+global
+<% @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
+<% @defaults_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/puppet/modules/haproxy/templates/haproxy_balancermember.erb b/puppet/modules/haproxy/templates/haproxy_balancermember.erb
new file mode 100644
index 00000000..1d03f565
--- /dev/null
+++ b/puppet/modules/haproxy/templates/haproxy_balancermember.erb
@@ -0,0 +1,3 @@
+<% Array(ipaddresses).zip(Array(server_names)).each do |ipaddress,host| -%>
+ server <%= host %> <%= ipaddress %>:<%= Array(ports).collect {|x|x.split(',')}.flatten.join(",#{ipaddress}:") %> <%= Array(options).join(" ") %>
+<% end %>
diff --git a/puppet/modules/haproxy/templates/haproxy_listen_block.erb b/puppet/modules/haproxy/templates/haproxy_listen_block.erb
new file mode 100644
index 00000000..129313f1
--- /dev/null
+++ b/puppet/modules/haproxy/templates/haproxy_listen_block.erb
@@ -0,0 +1,10 @@
+listen <%= name %>
+ mode <%= mode %>
+<% Array(ipaddress).uniq.each do |virtual_ip| (ports.is_a?(Array) ? ports : Array(ports.split(","))).each do |port| %>
+ bind <%= virtual_ip %>:<%= port %>
+<% end end %>
+<% options.sort.each do |key, val| -%>
+<% Array(val).each do |item| -%>
+ <%= key %> <%= item %>
+<% end -%>
+<% end -%>
diff --git a/puppet/modules/haproxy/tests/init.pp b/puppet/modules/haproxy/tests/init.pp
new file mode 100644
index 00000000..77590ac8
--- /dev/null
+++ b/puppet/modules/haproxy/tests/init.pp
@@ -0,0 +1,69 @@
+# Declare haproxy base class with configuration options
+class { 'haproxy':
+ enable => true,
+ 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',
+ },
+ 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::listen 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::listen { 'puppet00':
+ order => '20',
+ ipaddress => $::ipaddress,
+ ports => '18140',
+ options => {
+ 'option' => [
+ 'tcplog',
+ 'ssl-hello-chk',
+ ],
+ 'balance' => 'roundrobin',
+ },
+}
+haproxy::listen { 'stats':
+ order => '30',
+ ipaddress => '',
+ ports => '9090',
+ options => {
+ 'mode' => 'http',
+ 'stats' => [
+ 'uri /',
+ 'auth puppet:puppet'
+ ],
+ },
+}