Adapt new haproxy module to Fuel

Change-Id: I48038540d2a69a116521466369aaaddae02bceb3
Implements: blueprint ssl-endpoints
This commit is contained in:
Stanislaw Bogatkin 2015-05-22 19:11:43 +03:00
parent 1a0f3c0a6d
commit f94ad53471
11 changed files with 340 additions and 19 deletions

View File

@ -67,7 +67,6 @@ class cluster::haproxy (
Package['haproxy'] -> Class['haproxy::base']
Class['haproxy::base'] -> Class['cluster::haproxy_ocf']
Class['haproxy::base'] -> Haproxy::Service <||>
if defined(Corosync::Service['pacemaker']) {
Corosync::Service['pacemaker'] -> Class['cluster::haproxy_ocf']

View File

@ -5,7 +5,7 @@ group :development, :unit_tests do
gem 'rspec-core', '3.1.7', :require => false
gem 'rspec-puppet', '~> 1.0', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', :require => false
gem 'puppet-lint', '~> 0.3.2'
gem 'simplecov', :require => false
gem 'puppet_facts', :require => false
gem 'json', :require => false

View File

@ -0,0 +1,144 @@
require 'open-uri'
require 'socket'
require 'timeout'
Puppet::Type.type(:haproxy_backend_status).provide(:haproxy) do
desc 'Wait for HAProxy backend to become online'
# get the raw csv value using one of the methods
# retry if operations fails
# @return [String]
def csv
@resource[:count].times do
begin
csv = Timeout::timeout(@resource[:step] * 3) do
if @resource[:socket]
debug "Get CSV from socket '#{@resource[:socket]}'"
get_csv_unix
else
debug "Get CSV from url '#{@resource[:url]}'"
get_csv_url
end
end
return csv if csv
rescue
nil
end
sleep @resource[:step]
end
if @resource[:socket]
raise Puppet::Error, "Could not get CSV from socket #{@resource[:socket]}"
else
raise Puppet::Error, "Could not get CSV from url #{@resource[:url]}"
end
end
# return the parsed stats structure
# @return [Hash<String => Symbol>]
def stats
return @stats if @stats
stats = {}
csv.split("\n").each do |line|
next if line.start_with? '#'
fields = line.split(',')
name = fields[0]
type = fields[1]
status = fields[17]
next unless name and type and status
next unless type == 'BACKEND'
case status
when 'UP'
status = :up
when 'DOWN'
status = :down
else
next
end
stats.store name, status
end
@stats = stats
end
# reset mnemoization of stats
def stats_reset
@stats = nil
end
# get the current backend status value
# @return [:up, :down, :absent, :present]
def ensure
debug "Call 'ensure' on HAProxy backend '#{@resource[:name]}'"
unless exists?
debug 'Return: absent'
return :absent
end
if [:present, :absent].include? @resource[:ensure]
debug 'Return: present'
return :present
end
out = status
debug "Return: #{out}"
out
end
# wait for backend status to change into specified value
# @param value [:up, :down]
def ensure=(value)
debug "Waiting for HAProxy backend '#{@resource[:name]}' to change status to '#{value}'"
@resource[:count].times do
stats_reset
return true if self.ensure == value
sleep @resource[:step]
end
raise Puppet::Error, "Timeout waiting for HAProxy backend '#{@resource[:name]}' status to become '#{value}' after #{@resource[:count] * @resource[:step]} seconds!"
end
# check if backend exists
# @return [TrueClass, FalseClass]
def exists?
stats.key? @resource[:name]
end
# get backend status from stats structure
# @return [:up, :down]
def status
stats.fetch @resource[:name], :absent
end
# get csv from HAProxy socket
# @return [String, NilClass]
def get_csv_unix
csv = ''
socket = @resource[:socket]
begin
UNIXSocket.open(socket) do |opened_socket|
opened_socket.puts 'show stat'
loop do
line = opened_socket.gets
break unless line
csv << line
end
end
rescue
nil
end
return nil unless csv and not csv.empty?
csv
end
# download csv from url
# @return [String, NilClass]
def get_csv_url
begin
url = open(@resource[:url])
csv = url.read
rescue
nil
end
return nil unless csv and not csv.empty?
csv
end
end

View File

@ -0,0 +1,47 @@
Puppet::Type.newtype(:haproxy_backend_status) do
desc 'Wait for HAProxy backend to become online'
newparam(:name) do
desc 'The name of HAProxy backend to monitor'
isnamevar
end
newparam(:url) do
desc 'Use this url to get CSV status'
end
newparam(:socket) do
desc 'Use this socket to get CSV status'
end
newproperty(:ensure) do
desc 'Expected backend status'
newvalues :up, :down, :present, :absent
defaultto :up
end
newparam(:count) do
desc 'How many times try to perform check?'
newvalues(/\d+/)
defaultto 100
munge do |n|
n.to_i
end
end
newparam(:step) do
desc 'How many seconds to wait between retries?'
newvalues(/\d+/)
defaultto 6
munge do |n|
n.to_i
end
end
def validate
unless self[:socket].nil? ^ self[:url].nil?
raise 'You should give either url or socket to get HAProxy status and not both!'
end
end
end

View File

@ -55,6 +55,10 @@
# If true, then add "cookie SERVERID" stickiness options.
# Default false.
#
# [*define_backups*]
# If true, declare all non-primary servers as backups. Use this option
# when you need to enforce active-passive failover.
#
# === Examples
#
# Exporting the resource for a balancer member:
@ -88,19 +92,28 @@
#
define haproxy::balancermember (
$listening_service,
$ports = undef,
$server_names = $::hostname,
$ipaddresses = $::ipaddress,
$ensure = 'present',
$options = '',
$define_cookies = false
$ports = undef,
$server_names = $::hostname,
$ipaddresses = $::ipaddress,
$ensure = 'present',
$order = '20',
$options = '',
$define_cookies = false,
$define_backups = false,
$use_include = $haproxy::params::use_include,
) {
# Template uses $ipaddresses, $server_name, $ports, $option
concat::fragment { "${listening_service}_balancermember_${name}":
ensure => $ensure,
order => "20-${listening_service}-01-${name}",
target => $::haproxy::config_file,
order => $use_include ? {
true => "01-${name}",
false => "${order}-${listening_service}-01-${name}",
},
target => $use_include ? {
true => "/etc/haproxy/conf.d/${order}-${name}.cfg",
false => $::haproxy::config_file,
},
content => template('haproxy/haproxy_balancermember.erb'),
}
}

View File

@ -0,0 +1,83 @@
# == Class: haproxy::base
#
# This class will create haproxy.cfg and populate it with global and
# defaults configuration sections.
#
# === Parameters
#
# [*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.
#
# [*use_include*]
# Chooses whether include directive can be used to collect haproxy
# configuration from multiple fragment files in a conf.d directory,
# or all fragments have to be contatenated into a single haproxy.cfg.
#
class haproxy::base (
$global_options = $haproxy::params::global_options,
$defaults_options = $haproxy::params::defaults_options,
$use_include = $haproxy::params::use_include,
$use_stats = $haproxy::params::use_stats,
$stats_port = $haproxy::params::stats_port,
$stats_ipaddresses = $haproxy::params::stats_ipaddresses,
) inherits haproxy::params {
include concat::setup
concat { '/etc/haproxy/haproxy.cfg':
owner => '0',
group => '0',
mode => '0644',
before => Service['haproxy'],
}
# Simple Header
concat::fragment { 'haproxy-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 $global_options['chroot'] {
file { $global_options['chroot']:
ensure => directory,
}
}
if $use_stats {
concat::fragment { 'haproxy-stats' :
target => '/etc/haproxy/haproxy.cfg',
order => '90',
content => template('haproxy/haproxy-stats.cfg.erb'),
}
}
if $use_include {
concat::fragment { 'haproxy-include':
target => '/etc/haproxy/haproxy.cfg',
order => '99',
content => "\ninclude conf.d/*.cfg\n",
}
file { '/etc/haproxy/conf.d':
ensure => 'directory',
owner => '0',
group => '0',
}
}
}

View File

@ -81,6 +81,7 @@ define haproxy::listen (
$bind = undef,
$mode = undef,
$collect_exported = true,
$order = '20',
$options = {
'option' => [
'tcplog',
@ -88,6 +89,7 @@ define haproxy::listen (
],
'balance' => 'roundrobin'
},
$use_include = $haproxy::params::use_include,
# Deprecated
$bind_options = '',
) {
@ -109,10 +111,25 @@ define haproxy::listen (
fail("An haproxy::backend resource was discovered with the same name (${name}) which is not supported")
}
if $use_include {
$target = "/etc/haproxy/conf.d/${order}-${name}.cfg"
$fragment_order = '00'
concat { $target:
owner => '0',
group => '0',
mode => '0644',
}
} else {
$target = '/etc/haproxy/haproxy.conf'
$fragment_order = "${order}-${name}-00"
}
# Template uses: $name, $ipaddress, $ports, $options
concat::fragment { "${name}_listen_block":
order => "20-${name}-00",
target => $::haproxy::config_file,
order => $fragment_order,
target => $target,
content => template('haproxy/haproxy_listen_block.erb'),
}

View File

@ -65,4 +65,8 @@ class haproxy::params {
}
default: { fail("The ${::osfamily} operating system is not supported with the haproxy module") }
}
$use_include = false
$use_stats = true
$stats_port = '10000'
$stats_ipaddresses = ['127.0.0.1']
}

View File

@ -0,0 +1,12 @@
listen Stats
<% Array(@stats_ipaddresses).uniq.each do |ip| -%>
bind <%= ip %>:<%= @stats_port %>
<% end -%>
mode http
stats enable
stats uri /
stats refresh 5s
stats show-node
stats show-legends
stats hide-version

View File

@ -1,9 +1,9 @@
<% Array(@ipaddresses).zip(Array(@server_names)).each do |ipaddress,host| -%>
<% if @ports -%>
<%- Array(@ports).each do |port| -%>
server <%= host %> <%= ipaddress %>:<%= port %><%= if @define_cookies then " cookie " + host end %> <%= Array(@options).sort.join(" ") %>
server <%= host %> <%= ipaddress %>:<%= port %><%= if @define_cookies then " cookie " + host end %> <%= if @define_backups and @server_names.first != host then "backup" end -%> <%= Array(@options).sort.join(" ") %>
<%- end -%>
<% else -%>
server <%= host %> <%= ipaddress %><%= if @define_cookies then " cookie " + host end %> <%= Array(@options).sort.join(" ") %>
server <%= host %> <%= ipaddress %><%= if @define_cookies then " cookie " + host end %> <%= if @define_backups and @server_names.first != host then "backup" end -%> <%= Array(@options).sort.join(" ") %>
<%- end -%>
<% end -%>

View File

@ -40,11 +40,12 @@ define openstack::ha::haproxy_service (
}
haproxy::listen { $name:
order => $order,
ipaddress => $virtual_ips,
ports => $listen_port,
options => $haproxy_config_options,
mode => $mode,
order => $order,
ipaddress => $virtual_ips,
ports => $listen_port,
options => $haproxy_config_options,
mode => $mode,
use_include => true,
}
haproxy::balancermember { $name:
@ -56,6 +57,7 @@ define openstack::ha::haproxy_service (
options => $balancermember_options,
define_cookies => $define_cookies,
define_backups => $define_backups,
use_include => true,
}
# Dirty hack, due Puppet can't send notify between stages