diff options
Diffstat (limited to 'puppet/modules')
21 files changed, 936 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/.gitrepo b/puppet/modules/haproxy/.gitrepo new file mode 100644 index 00000000..ed92831a --- /dev/null +++ b/puppet/modules/haproxy/.gitrepo @@ -0,0 +1,11 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] +	remote = https://leap.se/git/puppet_haproxy +	branch = master +	commit = af322a73c013f80a958ab7d5d31d0c75cf6d0523 +	parent = 04279dd8d1390d61d696d2c14817199304ccd4d8 +	cmdver = 0.3.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' +    ], +  }, +} | 
