diff --git a/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/haproxy.rb b/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/haproxy.rb index b9ad3f1180..fee5ce85c1 100644 --- a/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/haproxy.rb +++ b/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/haproxy.rb @@ -7,6 +7,8 @@ require 'uri' Puppet::Type.type(:haproxy_backend_status).provide(:haproxy) do desc 'Wait for HAProxy backend to become online' + defaultfor :osfamily => :linux + # get the raw csv value using one of the methods # retry if operations fails # @return [String] diff --git a/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/http.rb b/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/http.rb new file mode 100644 index 0000000000..8dc144ad26 --- /dev/null +++ b/deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/http.rb @@ -0,0 +1,65 @@ +require 'net/https' +require 'uri' +require 'openssl' + +Puppet::Type.type(:haproxy_backend_status).provide(:http) do + desc 'Wait for HTTP backend to become online' + + # get the current backend status value + # @return [:up, :down, :absent, :present] + def ensure + debug 'Call: ensure' + out = status + debug "Return: #{out}" + out + end + + # get backend status based on HTTP reply + # @return [:up, :down, :present, :absent] + def status + status = get_url + return :absent unless status + return :present if [:present, :absent].include? @resource[:ensure] + return :up if status.kind_of? Net::HTTPSuccess or status.kind_of? Net::HTTPRedirection + return :down if status.kind_of? Net::HTTPServerError or status.kind_of? Net::HTTPClientError + :present + end + + # check backend using HTTP request + # @return [false, Net::HTTP Constant] + def get_url + begin + uri = URI.parse(@resource[:url]) + http = Net::HTTP.new(uri.host, uri.port) + if @resource[:url].start_with?('https') + http.use_ssl = true + case @resource[:ssl_verify_mode] + when 'none' + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + when 'peer' + http.verify_mode = OpenSSL::SSL::VERIFY_PEER + end + end + request = Net::HTTP::Get.new(uri.request_uri) + http.request(request) + rescue Exception => e + debug "Got error while checking backend: #{e}" + false + end + end + + # wait for backend status to change into specified value + # @param value [:up, :down] + def ensure=(value) + debug "Call: ensure=(#{value})" + debug "Waiting for backend: '#{@resource[:name]}' to change its status to: '#{value}'" + @resource[:count].times do + if self.status == value + return true + end + sleep @resource[:step] + end + fail "Timeout waiting for backend: '#{@resource[:name]}' status to become: '#{value}' after #{@resource[:count] * @resource[:step]} seconds!" + end + +end diff --git a/deployment/puppet/haproxy/lib/puppet/type/haproxy_backend_status.rb b/deployment/puppet/haproxy/lib/puppet/type/haproxy_backend_status.rb index 7ffe0511e8..32e01c8445 100644 --- a/deployment/puppet/haproxy/lib/puppet/type/haproxy_backend_status.rb +++ b/deployment/puppet/haproxy/lib/puppet/type/haproxy_backend_status.rb @@ -47,6 +47,15 @@ Puppet::Type.newtype(:haproxy_backend_status) do end end + newparam(:ssl_verify_mode) do + desc 'HTTPS SSL verify mode. Defaults to `default` which means built-in default.' + newvalues('none', 'peer', 'default') + defaultto 'default' + munge do |value| + value.to_s + 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!' diff --git a/deployment/puppet/haproxy/spec/unit/puppet/provider/hapoxy_backend_status/http_spec.rb b/deployment/puppet/haproxy/spec/unit/puppet/provider/hapoxy_backend_status/http_spec.rb new file mode 100644 index 0000000000..ef53e272de --- /dev/null +++ b/deployment/puppet/haproxy/spec/unit/puppet/provider/hapoxy_backend_status/http_spec.rb @@ -0,0 +1,84 @@ +require 'puppet' +require 'net/http' + +describe Puppet::Type.type(:haproxy_backend_status).provider(:http) do + + let (:resource) do + Puppet::Type::Haproxy_backend_status.new( + { + :name => 'test', + :url => 'http://10.10.10.5:5000/', + :provider => 'http' + } + ) + end + + let (:http_100) do + Net::HTTPContinue.new('1.1', '100', 'Continue') + end + + let (:http_200) do + Net::HTTPOK.new('1.1', '200', 'OK') + end + + let (:http_404) do + Net::HTTPNotFound.new('1.1', '404', 'Not Found') + end + + let (:http_302) do + Net::HTTPFound.new('1.1', '302', 'Found') + end + + let (:http_503) do + Net::HTTPServiceUnavailable.new('1.1', '503', 'Service Unavailable') + end + + let (:provider) do + provider = resource.provider + if ENV['SPEC_PUPPET_DEBUG'] + class << provider + def debug(msg) + puts msg + end + end + end + provider + end + + it 'should return :up for running backend (HTTP 200)' do + resource[:name] = 'test-up' + provider.stubs(:get_url).returns(http_200) + expect(provider.ensure).to eq(:up) + end + + it 'should return :up for running backend (HTTP 302)' do + resource[:name] = 'test-up' + provider.stubs(:get_url).returns(http_302) + expect(provider.ensure).to eq(:up) + end + + it 'should return :down for broken backend (HTTP 404)' do + resource[:name] = 'test-down' + provider.stubs(:get_url).returns(http_404) + expect(provider.ensure).to eq(:down) + end + + it 'should return :down for broken backend (HTTP 503)' do + resource[:name] = 'test-down' + provider.stubs(:get_url).returns(http_503) + expect(provider.ensure).to eq(:down) + end + + it 'should return :present for weird backend (HTTP 100)' do + resource[:name] = 'test-up' + provider.stubs(:get_url).returns(http_100) + expect(provider.ensure).to eq(:present) + end + + it 'should return :absent for missing backend (conection refused)' do + resource[:name] = 'test-absent' + provider.stubs(:get_url).returns(false) + expect(provider.ensure).to eq(:absent) + end + +end