Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PDK-512) Add support for simple_get_filter #37

Merged
merged 2 commits into from
Mar 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions lib/puppet/resource_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def register_type(definition)
raise Puppet::DevError, 'requires attributes' unless definition.key? :attributes

definition[:features] ||= []
supported_features = %w[supports_noop canonicalize].freeze
supported_features = %w[supports_noop canonicalize remote_resource simple_get_filter].freeze
unknown_features = definition[:features] - supported_features
Puppet.warning("Unknown feature detected: #{unknown_features.inspect}") unless unknown_features.empty?

Expand All @@ -38,15 +38,23 @@ def my_provider
self.class.my_provider
end

if definition[:features] && definition[:features].include?('remote_resource')
define_singleton_method(:feature_support?) do |feature|
definition[:features] && definition[:features].include?(feature)
end

def feature_support?(feature)
self.class.feature_support?(feature)
end

if feature_support?('remote_resource')
apply_to_device
end

define_method(:initialize) do |attributes|
# $stderr.puts "A: #{attributes.inspect}"
attributes = attributes.to_hash if attributes.is_a? Puppet::Resource
# $stderr.puts "B: #{attributes.inspect}"
if definition.key?(:features) && definition[:features].include?('canonicalize')
if feature_support?('canonicalize')
attributes = my_provider.canonicalize(context, [attributes])[0]
end
# $stderr.puts "C: #{attributes.inspect}"
Expand Down Expand Up @@ -164,10 +172,15 @@ def my_provider

define_method(:retrieve) do
# puts "retrieve(#{title.inspect})"
result = Puppet::Resource.new(self.class, title)
current_state = my_provider.get(context).find { |h| h[namevar_name] == title }
result = Puppet::Resource.new(self.class, title)

current_state = if feature_support?('simple_get_filter')
my_provider.get(context, [title]).first
else
my_provider.get(context).find { |h| h[namevar_name] == title }
end

strict_check(current_state) if current_state && (definition.key?(:features) && definition[:features].include?('canonicalize'))
strict_check(current_state) if current_state && feature_support?('canonicalize')

# require 'pry'; binding.pry

Expand All @@ -187,11 +200,10 @@ def my_provider

define_method(:flush) do
# puts 'flush'
# require'pry';binding.pry
target_state = Hash[@parameters.map { |k, v| [k, v.value] }]
# remove puppet's injected metaparams
target_state.delete(:loglevel)
target_state = my_provider.canonicalize(context, [target_state]).first if definition.key?(:features) && definition[:features].include?('canonicalize')
target_state = my_provider.canonicalize(context, [target_state]).first if feature_support?('canonicalize')

retrieve unless @rapi_current_state

Expand All @@ -200,7 +212,7 @@ def my_provider

Puppet.debug("Target State: #{target_state.inspect}")

if definition[:features] && definition[:features].include?('supports_noop')
if feature_support?('supports_noop')
my_provider.set(context, { title => { is: @rapi_current_state, should: target_state } }, noop: noop?)
else
my_provider.set(context, title => { is: @rapi_current_state, should: target_state }) unless noop?
Expand Down
10 changes: 10 additions & 0 deletions lib/puppet/resource_api/base_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ def failed?
@failed
end

def feature_support?(feature)
supported = Puppet::Type.type(@typename).feature_support?(feature)
if supported
Puppet.debug("#{@typename} supports `#{feature}`")
else
Puppet.debug("#{@typename} does not support `#{feature}`")
end
supported
end

[:debug, :info, :notice, :warning, :err].each do |level|
define_method(level) do |*args|
if args.length == 1
Expand Down
7 changes: 6 additions & 1 deletion lib/puppet/resource_api/simple_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ module Puppet::ResourceApi
class SimpleProvider
def set(context, changes)
changes.each do |name, change|
is = change.key?(:is) ? change[:is] : (get(context) || []).find { |r| r[:name] == name }
is = if context.feature_support?('simple_get_filter')
change.key?(:is) ? change[:is] : (get(context, [name]) || []).find { |r| r[:name] == name }
else
change.key?(:is) ? change[:is] : (get(context) || []).find { |r| r[:name] == name }
end

should = change[:should]

is = { name: name, ensure: 'absent' } if is.nil?
Expand Down
39 changes: 39 additions & 0 deletions spec/acceptance/simple_get_filter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'spec_helper'

require 'open3'
require 'tempfile'

RSpec.describe 'exercising simple_get_filter' do
let(:common_args) { '--verbose --debug --trace --modulepath spec/fixtures' }

describe 'using `puppet resource`' do
context 'when using `get` to access all resources' do
it 'does not receive names array' do
stdout_str, status = Open3.capture2e("puppet resource #{common_args} test_simple_get_filter")

expect(stdout_str.strip).to match %r{^test_simple_get_filter \{ \"bar\"}
expect(stdout_str.strip).to match %r{^test_simple_get_filter \{ \"foo\"}
expect(status).to eq 0
end
end

context 'when using `get` to access a specific resource' do
it 'does not receive names array' do
stdout_str, status = Open3.capture2e("puppet resource #{common_args} test_simple_get_filter foo")

expect(stdout_str.strip).to match %r{test_string\s*=>\s*'default'}
expect(status).to eq 0
end
end

context 'when using `get` to access a specific resource' do
it 'receives names array' do
stdout_str, status = Open3.capture2e("puppet resource #{common_args} test_simple_get_filter foo ensure=absent")

expect(stdout_str.strip).to match %r{ensure\s*=>\s*'absent'}
expect(stdout_str.strip).to match %r{test_string\s*=>\s*'foo found'}
expect(status).to eq 0
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'puppet/resource_api'
require 'puppet/resource_api/simple_provider'

# Implementation for the test_simple_get_filter type using the Resource API.
class Puppet::Provider::TestSimpleGetFilter::TestSimpleGetFilter < Puppet::ResourceApi::SimpleProvider
def get(_context, names = nil)
if names.nil?
[
{
name: 'bar',
ensure: :present,
test_string: 'default'
},
{
name: 'foo',
ensure: :present,
test_string: 'default'
},
]
elsif names.include?('foo')
[
{
name: 'foo',
ensure: :absent,
test_string: 'foo found'
}
]
else
[
{
name: 'foo',
ensure: :present,
test_string: 'not foo'
}
]
end
end

def create(_context, _name, _should)
end

def update(_context, _name, _should)
end

def delete(_context, _name)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'puppet/resource_api'

Puppet::ResourceApi.register_type(
name: 'test_simple_get_filter',
docs: <<-EOS,
This type provides Puppet with the capabilities to manage ...
EOS
features: ['simple_get_filter'],
attributes: {
ensure: {
type: 'Enum[present, absent]',
desc: 'Whether this resource should be present or absent on the target system.',
default: 'present',
},
name: {
type: 'String',
desc: 'The name of the resource you want to manage.',
behaviour: :namevar,
},
test_string: {
type: 'String',
desc: 'Used for testing our expected outcomes',
},
},
)
21 changes: 21 additions & 0 deletions spec/puppet/resource_api/base_context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,25 @@ def send_log(log, msg)
describe '#send_log' do
it { expect { described_class.new(nil).send_log(nil, nil) }.to raise_error RuntimeError, %r{Received send_log\(\) on an unprepared BaseContext\. Use IOContext, or PuppetContext instead} }
end

describe '#feature_support?' do
let(:puppet_type) { double('A Resource API Type') } # rubocop:disable RSpec/VerifiedDoubles

before(:each) do
allow(Puppet::Type).to receive(:type).and_return(puppet_type)
allow(puppet_type).to receive(:feature_support?).with('simple_get_filter').and_return(return_val)
end

context 'when type supports feature' do
let(:return_val) { true }

it { expect(described_class.new('supported_feature')).to be_feature_support('simple_get_filter') }
end

context 'when type does not support a feature' do
let(:return_val) { false }

it { expect(described_class.new('supported_feature')).not_to be_feature_support('simple_get_filter') }
end
end
end
17 changes: 16 additions & 1 deletion spec/puppet/resource_api/simple_provider_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
let(:context) { instance_double('Puppet::ResourceApi::BaseContext', 'context') }
let(:provider_class) do
Class.new(described_class) do
def get(context); end
def get(context, _names = nil); end

def create(context, _name, _should); end

Expand Down Expand Up @@ -57,6 +57,7 @@ def delete(context, _name); end

before(:each) do
allow(context).to receive(:creating).with('title').and_yield
allow(context).to receive(:feature_support?).with('simple_get_filter')
end

it 'calls create once' do
Expand All @@ -71,6 +72,17 @@ def delete(context, _name); end
expect(provider).to receive(:delete).never
provider.set(context, changes)
end

context 'with a type that supports `simple_get_filter`' do
before(:each) do
allow(context).to receive(:feature_support?).with('simple_get_filter').and_return(true)
end

it 'calls `get` with name' do
expect(provider).to receive(:get).with(context, ['title'])
provider.set(context, changes)
end
end
end

context 'with a single change to update a resource' do
Expand All @@ -86,6 +98,7 @@ def delete(context, _name); end

before(:each) do
allow(context).to receive(:updating).with('title').and_yield
allow(context).to receive(:feature_support?).with('simple_get_filter')
end

it 'does not call create' do
Expand Down Expand Up @@ -115,6 +128,7 @@ def delete(context, _name); end

before(:each) do
allow(context).to receive(:deleting).with('title').and_yield
allow(context).to receive(:feature_support?).with('simple_get_filter')
end

it 'does not call create' do
Expand Down Expand Up @@ -153,6 +167,7 @@ def delete(context, _name); end
allow(context).to receive(:creating).with('to create').and_yield
allow(context).to receive(:updating).with('to update').and_yield
allow(context).to receive(:deleting).with('to delete').and_yield
allow(context).to receive(:feature_support?).with('simple_get_filter').exactly(3).times
end

it 'calls the crud methods' do
Expand Down
Loading