forked from puppetlabs/opv
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request puppetlabs#13 from sheenaajay/opv/issue1
(puppetlabs#1) update check_http provider and type with new attributes
- Loading branch information
Showing
5 changed files
with
173 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'puppet/resource_api' | ||
require 'puppet/resource_api/simple_provider' | ||
require 'net/http' | ||
require 'retriable' | ||
|
||
# Implementation for the check_http type using the Resource API. | ||
class Puppet::Provider::CheckHttp::CheckHttp | ||
def get(_context) | ||
[] | ||
end | ||
|
||
def set(context, changes) | ||
changes.each do |name, _change| | ||
uri = URI(name) | ||
context.processing(uri.to_s, {}, {}, message: 'checking http') do | ||
if Net::HTTP.get(uri) | ||
context.info("successfully connected to #{name}") | ||
end | ||
def set(context, changes); end | ||
|
||
# Update the check_http provider to use the above attributes to execute up to retries number of times | ||
# with success being defined as having one of the expected_statuses | ||
# and the body of the response matches body_matcher while taking into account request_timeout. | ||
|
||
def insync?(context, name, attribute_name, _is_hash, should_hash) | ||
context.debug("Checking whether #{attribute_name} is up-to-date") | ||
uri = URI.parse(should_hash[:url]) | ||
|
||
# This callback provides the exception that was raised in the current try, the try_number, the elapsed_time for all tries so far, and the time in seconds of the next_interval. | ||
do_this_on_each_retry = proc do |exception, try, elapsed_time, next_interval| | ||
context.info("#{exception.class}: '#{exception.message}' - #{try} tries in #{elapsed_time} seconds and #{next_interval} seconds until the next try.") unless exception.nil? | ||
end | ||
|
||
Retriable.retriable(tries: should_hash[:retries], max_elapsed_time: should_hash[:request_timeout], max_interval: should_hash[:max_backoff], | ||
multiplier: should_hash[:exponential_backoff_base], on_retry: do_this_on_each_retry) do | ||
response = Net::HTTP.get_response(uri) | ||
|
||
unless should_hash[:expected_statuses].include? response.code.to_i | ||
raise Puppet::Error, "check_http response code check failed. The return response '#{response.code}' is not matching with the expected_statuses '#{should_hash[:expected_statuses]}.to_s'" | ||
end | ||
context.debug("The return response '#{response.code}' is matching with the expected_statuses '#{should_hash[:expected_statuses]}'") | ||
unless response.body.match(should_hash[:body_matcher]) | ||
raise Puppet::Error, "check_http response body check failed. The return response body '#{response.body[0..99]}' is not matching body_matcher '#{should_hash[:body_matcher].to_s}'" | ||
end | ||
context.debug("The return response body '#{response.body[0..99]}' is matching with body_matcher '#{should_hash[:body_matcher].to_s}'") | ||
context.debug("Successfully connected to '#{name}'") | ||
return true | ||
end | ||
false | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
check_http {'https://www.google.com': | ||
expected_statuses => [200], | ||
body_matcher => /Google/, | ||
request_timeout => 30, | ||
retries => 3, | ||
backoff => 1, | ||
exponential_backoff_base => 2, | ||
max_backoff => 40, | ||
timeout => 60, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,98 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'spec_helper' | ||
require 'webmock/rspec' | ||
|
||
ensure_module_defined('Puppet::Provider::CheckHttp') | ||
require 'puppet/provider/check_http/check_http' | ||
|
||
RSpec.describe Puppet::Provider::CheckHttp::CheckHttp do | ||
subject(:provider) { described_class.new } | ||
WebMock.disable_net_connect!(allow_localhost: true) | ||
|
||
let(:context) { instance_double('Puppet::ResourceApi::BaseContext', 'context') } | ||
let(:context) { double('Puppet::ResourceApi::BaseContext') } | ||
let(:valid_uri) { 'https://www.google.com' } | ||
let(:invalid_uri) { 'https://abc.test.net' } | ||
let(:valid_hash) { { name: 'foo', url: valid_uri, ensure: 'present',expected_statuses: [200], body_matcher: /Google/, request_timeout: 30, retries: 3, backoff: 1, exponential_backoff_base:2, max_backoff:40, timeout:60 } } | ||
let(:invalid_hash) { { name: 'foos', url: invalid_uri, ensure: 'present',expected_statuses: [200], body_matcher: /Google/, request_timeout: 30, retries: 3, backoff: 1, exponential_backoff_base:2, max_backoff:40, timeout:60 } } | ||
|
||
describe '#get' do | ||
describe 'get(context)' do | ||
it 'processes resources' do | ||
expect(context).to receive(:debug).with('Returning pre-canned example data') | ||
expect(provider.get(context)).to eq [ | ||
{ | ||
name: 'foo', | ||
ensure: 'present', | ||
}, | ||
{ | ||
name: 'bar', | ||
ensure: 'present', | ||
}, | ||
] | ||
expect(provider.get(context)).to eq [] | ||
end | ||
end | ||
|
||
describe 'create(context, name, should)' do | ||
it 'creates the resource' do | ||
expect(context).to receive(:notice).with(%r{\ACreating 'a'}) | ||
|
||
provider.create(context, 'a', name: 'a', ensure: 'present') | ||
describe 'insync?(context, name, attribute_name, is_hash, should_hash) without Retry' do | ||
it 'processes resources' do | ||
stub_request(:get, "https://www.google.com/"). | ||
with( | ||
headers: { | ||
'Accept'=>'*/*', | ||
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', | ||
'Host'=>'www.google.com', | ||
'User-Agent'=>'Ruby' | ||
}).to_return(status: 200, body: "Google", headers: {}) | ||
expect(context).to receive(:debug).with('Checking whether foo is up-to-date') | ||
expect(context).to receive(:debug).with("The return response '200' is matching with the expected_statuses '[200]'") | ||
expect(context).to receive(:debug).with("The return response body 'Google' is matching with body_matcher '(?-mix:Google)'") | ||
expect(context).to receive(:debug).with("Successfully connected to 'foo'") | ||
expect(provider.insync?(context, 'foo', 'foo', valid_hash, valid_hash)).to be(true) | ||
end | ||
end | ||
|
||
describe 'update(context, name, should)' do | ||
it 'updates the resource' do | ||
expect(context).to receive(:notice).with(%r{\AUpdating 'foo'}) | ||
describe 'insync?(context, name, attribute_name, is_hash, should_hash) expected_status not matching' do | ||
it 'processes resources' do | ||
stub_request(:get, invalid_uri). | ||
with( | ||
headers: { | ||
'Accept'=>'*/*', | ||
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', | ||
'Host'=>'abc.test.net', | ||
'User-Agent'=>'Ruby' | ||
}).to_return(status: 500, body: "invalidbody", headers: {}) | ||
allow(context).to receive(:debug) | ||
allow(context).to receive(:debug) | ||
expect(context).to receive(:debug).with('Checking whether foo is up-to-date') | ||
expect { provider.insync?(context, 'foo', 'foo', invalid_hash, invalid_hash) }.to raise_error(/check_http response code check failed./) | ||
end | ||
end | ||
|
||
provider.update(context, 'foo', name: 'foo', ensure: 'present') | ||
describe 'insync?(context, name, attribute_name, is_hash, should_hash) body_matcher not matching' do | ||
it 'processes resources' do | ||
stub_request(:get, invalid_uri). | ||
with( | ||
headers: { | ||
'Accept'=>'*/*', | ||
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', | ||
'Host'=>'abc.test.net', | ||
'User-Agent'=>'Ruby' | ||
}).to_return(status: 200, body: "invalidbody", headers: {}) | ||
allow(context).to receive(:debug) | ||
allow(context).to receive(:debug) | ||
expect(context).to receive(:debug).with('Checking whether foo is up-to-date') | ||
expect(context).to receive(:debug).with("The return response '200' is matching with the expected_statuses '[200]'") | ||
expect { provider.insync?(context, 'foo', 'foo', invalid_hash, invalid_hash) }.to raise_error(/check_http response body check failed./) | ||
end | ||
end | ||
|
||
describe 'delete(context, name)' do | ||
it 'deletes the resource' do | ||
expect(context).to receive(:notice).with(%r{\ADeleting 'foo'}) | ||
describe 'insync?(context, name, attribute_name, is_hash, should_hash) with Retry' do | ||
it 'processes resources' do | ||
allow(context).to receive(:debug) | ||
allow(context).to receive(:debug) | ||
expect(context).to receive(:debug).with('Checking whether foo is up-to-date') | ||
stub_request(:get, invalid_uri). | ||
with( | ||
headers: { | ||
'Accept'=>'*/*', | ||
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', | ||
'Host'=>'abc.test.net', | ||
'User-Agent'=>'Ruby' | ||
}).to_raise(StandardError) | ||
expect(context).to receive(:info).with(/StandardError: 'Exception from WebMock' - 1 tries/) | ||
expect(context).to receive(:info).with(/StandardError: 'Exception from WebMock' - 2 tries/) | ||
expect(context).to receive(:info).with(/StandardError: 'Exception from WebMock' - 3 tries/) | ||
|
||
provider.delete(context, 'foo') | ||
expect { provider.insync?(context, 'foo', 'foo', invalid_hash, invalid_hash) }.to raise_error(StandardError) | ||
end | ||
end | ||
end |