From 30c4b62c098732a70a160b6db8eb981f183df9e6 Mon Sep 17 00:00:00 2001 From: Aleksandr Didenko Date: Mon, 14 Dec 2015 18:18:17 +0100 Subject: [PATCH] Add new provider for backend status checks Haproxy backend status check remains the default provider. Adding new one for basic HTTP checks so it could be possible to use external non-haproxy load balancers. After this we can make provider for haproxy_backend_status in our manifests conditional, based on whether we have external balancer or not. Partial-bug: #1522749 Change-Id: I77921fba265da29332ddd05f371eb84bb1825d8b --- .../haproxy_backend_status/haproxy.rb | 2 + .../provider/haproxy_backend_status/http.rb | 65 ++++++++++++++ .../lib/puppet/type/haproxy_backend_status.rb | 9 ++ .../hapoxy_backend_status/http_spec.rb | 84 +++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 deployment/puppet/haproxy/lib/puppet/provider/haproxy_backend_status/http.rb create mode 100644 deployment/puppet/haproxy/spec/unit/puppet/provider/hapoxy_backend_status/http_spec.rb 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