diff --git a/.fixtures.yml b/.fixtures.yml index 093b86bc..b073b02b 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -47,7 +47,7 @@ fixtures: ref: '474ad6d2b84f3d1e03000c2fc340ec1e3408488d' 'haproxy': repo: 'git://github.com/enovance/puppetlabs-haproxy.git' - ref: 'ff713f85d8fac7ade808f3d65d949a1a06b8ea88' + ref: 'fc1166f28d411dfd4f59d4bfd6936595c014a11b' 'keepalived': repo: 'git://github.com/enovance/puppet-module-keepalived.git' ref: 'eb345b6d3b25106cbe166028f2b8dd9974a10230' diff --git a/Puppetfile b/Puppetfile index ac901a63..343ea61b 100644 --- a/Puppetfile +++ b/Puppetfile @@ -79,7 +79,7 @@ mod 'fluentd', :ref => '474ad6d2b84f3d1e03000c2fc340ec1e3408488d' mod 'haproxy', :git => 'git://github.com/enovance/puppetlabs-haproxy.git', - :ref => 'ff713f85d8fac7ade808f3d65d949a1a06b8ea88' + :ref => 'fc1166f28d411dfd4f59d4bfd6936595c014a11b' mod 'inifile', :git => 'git://github.com/enovance/puppetlabs-inifile.git', :ref => 'ae23a4db97d2815ec305d0529912685f07746d3c' diff --git a/manifests/loadbalancer.pp b/manifests/loadbalancer.pp index 7079347a..7f6c8c65 100644 --- a/manifests/loadbalancer.pp +++ b/manifests/loadbalancer.pp @@ -172,7 +172,6 @@ class cloud::loadbalancer( $keystone_api = true, $keystone_api_admin = true, $horizon = true, - $horizon_ssl = false, $spice = true, $haproxy_auth = 'admin:changeme', $keepalived_state = 'BACKUP', @@ -181,6 +180,23 @@ class cloud::loadbalancer( $keepalived_public_ipvs = ['127.0.0.1'], $keepalived_internal_interface = 'eth1', $keepalived_internal_ipvs = false, + $ceilometer_bind_options = [], + $cinder_bind_options = [], + $ec2_bind_options = [], + $glance_api_bind_options = [], + $glance_registry_bind_options = [], + $heat_cfn_bind_options = [], + $heat_cloudwatch_bind_options = [], + $heat_api_bind_options = [], + $keystone_bind_options = [], + $keystone_admin_bind_options = [], + $metadata_bind_options = [], + $neutron_bind_options = [], + $nova_bind_options = [], + $swift_bind_options = [], + $spice_bind_options = [], + $horizon_bind_options = [], + $galera_bind_options = [], $ks_ceilometer_public_port = 8777, $ks_cinder_public_port = 8776, $ks_ec2_public_port = 8773, @@ -196,7 +212,6 @@ class cloud::loadbalancer( $ks_nova_public_port = 8774, $ks_swift_public_port = 8080, $horizon_port = 80, - $horizon_ssl_port = 443, $spice_port = 6082, $vip_public_ip = ['127.0.0.1'], $vip_internal_ip = false, @@ -204,6 +219,8 @@ class cloud::loadbalancer( # Deprecated parameters $keepalived_interface = false, $keepalived_ipvs = false, + $horizon_ssl = false, + $horizon_ssl_port = false, ){ # Manage deprecation when using old parameters @@ -219,6 +236,26 @@ class cloud::loadbalancer( } else { $keepalived_public_ipvs_real = $keepalived_public_ipvs } + if $horizon_ssl { + warning('horizon_ssl parameter is deprecated. Specify ssl in the horizon_bind_options instead.') + $horizon_httpchk = 'ssl-hello-chk' + $horizon_options = { + 'mode' => 'tcp', + 'cookie' => 'sessionid prefix', + 'balance' => 'leastconn' } + } else { + $horizon_httpchk = "httpchk GET /${horizon_auth_url} \"HTTP/1.0\\r\\nUser-Agent: HAproxy-${::hostname}\"" + $horizon_options = { + 'cookie' => 'sessionid prefix', + 'balance' => 'leastconn' } + } + if $horizon_ssl_port { + warning('horizon_ssl_port parameter is deprecated. Specify port with the horizon_port instead.') + $horizon_port_real = $horizon_ssl_port + } else { + $horizon_port_real = '443' + } + # end of deprecation support # Fail if OpenStack and Galera VIP are not in the VIP list if $vip_public_ip and !($vip_public_ip in $keepalived_public_ipvs_real) { @@ -284,29 +321,35 @@ class cloud::loadbalancer( # Instanciate HAproxy binding cloud::loadbalancer::binding { 'keystone_api_cluster': - ip => $keystone_api, - port => $ks_keystone_public_port; + ip => $keystone_api, + port => $ks_keystone_public_port, + bind_options => $keystone_bind_options, } cloud::loadbalancer::binding { 'keystone_api_admin_cluster': - ip => $keystone_api_admin, - port => $ks_keystone_admin_port; + ip => $keystone_api_admin, + port => $ks_keystone_admin_port, + bind_options => $keystone_admin_bind_options, } cloud::loadbalancer::binding { 'swift_api_cluster': - ip => $swift_api, - port => $ks_swift_public_port, - httpchk => 'httpchk /healthcheck'; + ip => $swift_api, + port => $ks_swift_public_port, + bind_options => $swift_bind_options, + httpchk => 'httpchk /healthcheck', } cloud::loadbalancer::binding { 'nova_api_cluster': - ip => $nova_api, - port => $ks_nova_public_port; + ip => $nova_api, + port => $ks_nova_public_port, + bind_options => $nova_bind_options, } cloud::loadbalancer::binding { 'ec2_api_cluster': - ip => $ec2_api, - port => $ks_ec2_public_port; + ip => $ec2_api, + port => $ks_ec2_public_port, + bind_options => $ec2_bind_options, } cloud::loadbalancer::binding { 'metadata_api_cluster': - ip => $metadata_api, - port => $ks_metadata_public_port; + ip => $metadata_api, + port => $ks_metadata_public_port, + bind_options => $metadata_bind_options, } cloud::loadbalancer::binding { 'spice_cluster': ip => $spice, @@ -316,6 +359,7 @@ class cloud::loadbalancer( 'timeout server' => '120m', 'timeout client' => '120m', }, + bind_options => $spice_bind_options, httpchk => 'httpchk GET /'; } cloud::loadbalancer::binding { 'glance_api_cluster': @@ -325,74 +369,73 @@ class cloud::loadbalancer( 'timeout server' => '120m', 'timeout client' => '120m', }, - port => $ks_glance_api_public_port; + port => $ks_glance_api_public_port, + bind_options => $glance_api_bind_options, } cloud::loadbalancer::binding { 'glance_registry_cluster': - ip => $glance_registry, - port => $ks_glance_registry_internal_port; + ip => $glance_registry, + port => $ks_glance_registry_internal_port, + bind_options => $glance_registry_bind_options, } cloud::loadbalancer::binding { 'neutron_api_cluster': - ip => $neutron_api, - port => $ks_neutron_public_port; + ip => $neutron_api, + port => $ks_neutron_public_port, + bind_options => $neutron_bind_options, } cloud::loadbalancer::binding { 'cinder_api_cluster': - ip => $cinder_api, - port => $ks_cinder_public_port; + ip => $cinder_api, + port => $ks_cinder_public_port, + bind_options => $cinder_bind_options, } cloud::loadbalancer::binding { 'ceilometer_api_cluster': - ip => $ceilometer_api, - port => $ks_ceilometer_public_port; + ip => $ceilometer_api, + port => $ks_ceilometer_public_port, + bind_options => $ceilometer_bind_options, } cloud::loadbalancer::binding { 'heat_api_cluster': - ip => $heat_api, - port => $ks_heat_public_port; + ip => $heat_api, + port => $ks_heat_public_port, + bind_options => $heat_api_bind_options, } cloud::loadbalancer::binding { 'heat_cfn_api_cluster': - ip => $heat_cfn_api, - port => $ks_heat_cfn_public_port; + ip => $heat_cfn_api, + port => $ks_heat_cfn_public_port, + bind_options => $heat_cfn_bind_options, } cloud::loadbalancer::binding { 'heat_cloudwatch_api_cluster': - ip => $heat_cloudwatch_api, - port => $ks_heat_cloudwatch_public_port; + ip => $heat_cloudwatch_api, + port => $ks_heat_cloudwatch_public_port, + bind_options => $heat_cloudwatch_bind_options, } - if $horizon { - if $horizon_ssl { - cloud::loadbalancer::listen_https{ 'horizon_ssl_cluster': - ports => $horizon_ssl_port, - listen_ip => $vip_public_ip; - } - } else { - # Horizon URL is not the same on Red Hat and Debian/Ubuntu - if $::operatingsystem == 'RedHat' { - $horizon_auth_url = 'dashboard' - } else { - $horizon_auth_url = 'horizon' - } - cloud::loadbalancer::listen_http{ 'horizon_cluster': - ports => $horizon_port, - httpchk => "httpchk GET /${horizon_auth_url} \"HTTP/1.0\\r\\nUser-Agent: HAproxy-${::hostname}\"", - options => { - 'cookie' => 'sessionid prefix', - 'balance' => 'leastconn' }, - listen_ip => $vip_public_ip; - } - } + if $::operatingsystem == 'RedHat' { + $horizon_auth_url = 'dashboard' + } else { + $horizon_auth_url = 'horizon' + } + cloud::loadbalancer::binding { 'horizon_cluster': + ip => $vip_public_ip, + # to maintain backward compatibility + port => $horizon_port_real, + httpchk => $horizon_httpchk, + options => $horizon_options, + bind_options => $horizon_bind_options, } if ($galera_ip in $keepalived_public_ipvs_real) { warning('Exposing Galera cluster to public network is a security issue.') } haproxy::listen { 'galera_cluster': - ipaddress => $galera_ip, - ports => 3306, - options => { + ipaddress => $galera_ip, + ports => 3306, + options => { 'mode' => 'tcp', 'balance' => 'roundrobin', 'option' => ['tcpka', 'tcplog', 'httpchk'], #httpchk mandatory expect 200 on port 9000 'timeout client' => '400s', 'timeout server' => '400s', - } + }, + bind_options => $galera_bind_options, } # Allow HAProxy to bind to a non-local IP address diff --git a/manifests/loadbalancer/binding.pp b/manifests/loadbalancer/binding.pp index c83739a6..d24fc195 100644 --- a/manifests/loadbalancer/binding.pp +++ b/manifests/loadbalancer/binding.pp @@ -17,8 +17,9 @@ define cloud::loadbalancer::binding ( $ip, $port, - $httpchk = undef, - $options = undef + $httpchk = undef, + $options = undef, + $bind_options = undef, ){ include cloud::loadbalancer @@ -55,10 +56,11 @@ define cloud::loadbalancer::binding ( } } cloud::loadbalancer::listen_http { $name : - ports => $port, - httpchk => $httpchk, - options => $options, - listen_ip => $listen_ip_real; + ports => $port, + httpchk => $httpchk, + options => $options, + listen_ip => $listen_ip_real, + bind_options => $bind_options; } } diff --git a/manifests/loadbalancer/listen_http.pp b/manifests/loadbalancer/listen_http.pp index 63bc0b8e..b94ee7b2 100644 --- a/manifests/loadbalancer/listen_http.pp +++ b/manifests/loadbalancer/listen_http.pp @@ -18,21 +18,23 @@ # cloud::loadbalancer::listen_http # define cloud::loadbalancer::listen_http( - $ports = 'unset', - $httpchk = 'httpchk', - $options = {}, - $listen_ip = '0.0.0.0') { + $ports = 'unset', + $httpchk = 'httpchk', + $options = {}, + $bind_options = [], + $listen_ip = '0.0.0.0') { $options_basic = {'mode' => 'http', 'balance' => 'roundrobin', 'http-check' => 'expect ! rstatus ^5', - 'option' => ['tcpka', 'tcplog', $httpchk] } + 'option' => ['tcpka', 'forwardfor', 'tcplog', $httpchk] } $options_custom = merge($options_basic, $options) haproxy::listen { $name: - ipaddress => $listen_ip, - ports => $ports, - options => $options_custom, + ipaddress => $listen_ip, + ports => $ports, + options => $options_custom, + bind_options => $bind_options, } } diff --git a/manifests/loadbalancer/listen_https.pp b/manifests/loadbalancer/listen_https.pp deleted file mode 100644 index dc754d2d..00000000 --- a/manifests/loadbalancer/listen_https.pp +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (C) 2014 eNovance SAS -# -# 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. -# -# Define:: -# -# cloud::loadbalancer::listen_https -# -define cloud::loadbalancer::listen_https( - $ports = 'unset', - $httpchk = 'ssl-hello-chk', - $options = {}, - $listen_ip = '0.0.0.0') { - - $options_basic = {'mode' => 'tcp', - 'balance' => 'roundrobin', - 'http-check' => 'expect ! rstatus ^5', - 'option' => ['tcpka', 'tcplog', $httpchk] } - - $options_custom = merge($options_basic, $options) - - haproxy::listen { $name: - ipaddress => $listen_ip, - ports => $ports, - options => $options_custom, - } -} diff --git a/spec/classes/cloud_loadbalancer_spec.rb b/spec/classes/cloud_loadbalancer_spec.rb index c03b35a3..ce21585d 100644 --- a/spec/classes/cloud_loadbalancer_spec.rb +++ b/spec/classes/cloud_loadbalancer_spec.rb @@ -37,18 +37,34 @@ describe 'cloud::loadbalancer' do :keystone_api_admin => true, :keystone_api => true, :horizon => true, - :horizon_ssl => false, :spice => true, + :ceilometer_bind_options => [], + :cinder_bind_options => [], + :ec2_bind_options => [], + :glance_api_bind_options => [], + :glance_registry_bind_options => [], + :heat_cfn_bind_options => [], + :heat_cloudwatch_bind_options => [], + :heat_api_bind_options => [], + :keystone_bind_options => [], + :keystone_admin_bind_options => [], + :metadata_bind_options => [], + :neutron_bind_options => [], + :swift_bind_options => [], + :spice_bind_options => [], + :horizon_bind_options => [], + :galera_bind_options => [], :haproxy_auth => 'root:secrete', :keepalived_state => 'BACKUP', :keepalived_priority => 50, :keepalived_public_interface => 'eth0', :keepalived_public_ipvs => ['10.0.0.1', '10.0.0.2'], :horizon_port => '80', - :horizon_ssl_port => '443', :spice_port => '6082', :vip_public_ip => '10.0.0.1', :galera_ip => '10.0.0.2', + :horizon_ssl => false, + :horizon_ssl_port => false, :ks_ceilometer_public_port => '8777', :ks_nova_public_port => '8774', :ks_ec2_public_port => '8773', @@ -191,7 +207,7 @@ describe 'cloud::loadbalancer' do :ports => '6082', :options => { 'mode' => 'http', - 'option' => ['tcpka','tcplog','httpchk GET /'], + 'option' => ['tcpka', 'forwardfor', 'tcplog','httpchk GET /'], 'http-check' => 'expect ! rstatus ^5', 'balance' => 'leastconn', 'timeout server' => '120m', @@ -282,11 +298,92 @@ describe 'cloud::loadbalancer' do it_raises 'a Puppet::Error', /galera_ip should be part of keepalived_public_ipvs or keepalived_internal_ipvs./ end + context 'configure OpenStack binding with HTTPS and SSL offloading' do + before do + params.merge!( + :nova_bind_options => ['ssl', 'crt'] + ) + end + it { should contain_haproxy__listen('nova_api_cluster').with( + :ipaddress => [params[:vip_public_ip]], + :ports => '8774', + :options => { + 'mode' => 'http', + 'option' => ['tcpka','forwardfor','tcplog','httpchk'], + 'http-check' => 'expect ! rstatus ^5', + 'balance' => 'roundrobin', + }, + :bind_options => ['ssl', 'crt'] + )} + end + + context 'configure OpenStack binding with HTTP options' do + before do + params.merge!( + :cinder_bind_options => 'something not secure', + ) + end + it { should contain_haproxy__listen('cinder_api_cluster').with( + :ipaddress => [params[:vip_public_ip]], + :ports => '8776', + :options => { + 'mode' => 'http', + 'option' => ['tcpka','forwardfor','tcplog', 'httpchk'], + 'http-check' => 'expect ! rstatus ^5', + 'balance' => 'roundrobin', + }, + :bind_options => ['something not secure'] + )} + end + + context 'configure OpenStack Horizon SSL with backward compatibility' do + before do + params.merge!( + :horizon_ssl => true, + :horizon_ssl_port => '443' + ) + end + it { should contain_haproxy__listen('horizon_cluster').with( + :ipaddress => [params[:vip_public_ip]], + :ports => '443', + :options => { + 'mode' => 'tcp', + 'http-check' => 'expect ! rstatus ^5', + 'option' => ['tcpka','forwardfor','tcplog', 'ssl-hello-chk'], + 'cookie' => 'sessionid prefix', + 'balance' => 'leastconn', + }, + )} + end + + context 'configure OpenStack Horizon SSL binding' do + before do + params.merge!( + :horizon_ssl => false, + :horizon_ssl_port => false, + :horizon_bind_options => ['ssl', 'crt'] + ) + end + it { should contain_haproxy__listen('horizon_cluster').with( + :ipaddress => [params[:vip_public_ip]], + :ports => '443', + :options => { + 'mode' => 'http', + 'http-check' => 'expect ! rstatus ^5', + 'option' => ["tcpka", "forwardfor", "tcplog", "httpchk GET / \"HTTP/1.0\\r\\nUser-Agent: HAproxy-myhost\""], + 'cookie' => 'sessionid prefix', + 'balance' => 'leastconn', + }, + :bind_options => ['ssl', 'crt'] + )} + end + end # shared:: openstack loadbalancer context 'on Debian platforms' do let :facts do { :osfamily => 'Debian', + :hostname => 'myhost', :concat_basedir => '/var/lib/puppet/concat' } end @@ -296,6 +393,7 @@ describe 'cloud::loadbalancer' do context 'on RedHat platforms' do let :facts do { :osfamily => 'RedHat', + :hostname => 'myhost', :concat_basedir => '/var/lib/puppet/concat' } end