From 596ceae88af119734ee5231d5d8aa020fb2f6734 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 6 Mar 2018 11:35:45 +0000 Subject: [PATCH] (PDK-513) implement `supports_noop` See https://github.com/DavidS/puppet-specifications/blob/resourceapi/language/resource-api/README.md#provider-feature-supports_noop for a definition of the feature. Since puppet is not calling `flush` for us, this is only a example implementation, that likely will never be exercised. --- README.md | 3 + lib/puppet/resource_api.rb | 11 +++- spec/acceptance/noop_spec.rb | 29 +++++++++ .../test_noop_support/test_noop_support.rb | 15 ++--- .../lib/puppet/type/test_noop_support.rb | 2 +- spec/puppet/resource_api_spec.rb | 65 +++++++++++++++++++ 6 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 spec/acceptance/noop_spec.rb diff --git a/README.md b/README.md index 067789d4..9513cd9d 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,9 @@ There are still a few notable gaps between the implementation and the specificat * Only a single runtime environment (the Puppet commands) is currently implemented. * `auto*` definitions. +Restrictions of running under puppet: +* `supports_noop` is not effective, as puppet doesn't call into the type under noop. + ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. diff --git a/lib/puppet/resource_api.rb b/lib/puppet/resource_api.rb index b10169a9..6a3bdbe4 100644 --- a/lib/puppet/resource_api.rb +++ b/lib/puppet/resource_api.rb @@ -10,6 +10,11 @@ def register_type(definition) raise Puppet::DevError, 'requires a name' unless definition.key? :name raise Puppet::DevError, 'requires attributes' unless definition.key? :attributes + definition[:features] ||= [] + supported_features = %w[supports_noop canonicalize].freeze + unknown_features = definition[:features] - supported_features + Puppet.warning("Unknown feature detected: #{unknown_features.inspect}") unless unknown_features.empty? + # prepare the ruby module for the provider # this has to happen before Puppet::Type.newtype starts autoloading providers # it also needs to be guarded against the namespace already being defined by something @@ -207,7 +212,11 @@ def my_provider Puppet.debug("Target State: #{target_state.inspect}") - my_provider.set(context, title => { is: @rapi_current_state, should: target_state }) + if definition[:features] && definition[:features].include?('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? + end raise 'Execution encountered an error' if context.failed? end diff --git a/spec/acceptance/noop_spec.rb b/spec/acceptance/noop_spec.rb new file mode 100644 index 00000000..c59ce741 --- /dev/null +++ b/spec/acceptance/noop_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +require 'open3' +require 'tempfile' + +RSpec.describe 'exercising noop' do + let(:common_args) { '--verbose --trace --modulepath spec/fixtures' } + + describe 'using `puppet resource`' do + it 'is setup correctly' do + stdout_str, status = Open3.capture2e("puppet resource #{common_args} test_noop_support") + expect(stdout_str.strip).to match %r{^test_noop_support} + expect(status).to eq 0 + end + + it 'executes a change' do + stdout_str, status = Open3.capture2e("puppet resource #{common_args} test_noop_support foo ensure=absent") + expect(stdout_str.strip).to match %r{noop: false} + expect(status).to eq 0 + end + + it 'respects --noop' do + pending 'puppet does not call flush() to trigger execution' + stdout_str, status = Open3.capture2e("puppet resource #{common_args} --noop test_noop_support foo ensure=absent") + expect(stdout_str.strip).to match %r{noop: true} + expect(status).to eq 0 + end + end +end diff --git a/spec/fixtures/test_module/lib/puppet/provider/test_noop_support/test_noop_support.rb b/spec/fixtures/test_module/lib/puppet/provider/test_noop_support/test_noop_support.rb index 789cce14..9e7effee 100644 --- a/spec/fixtures/test_module/lib/puppet/provider/test_noop_support/test_noop_support.rb +++ b/spec/fixtures/test_module/lib/puppet/provider/test_noop_support/test_noop_support.rb @@ -2,7 +2,7 @@ require 'puppet/resource_api/simple_provider' # Implementation for the test_noop_support type using the Resource API. -class Puppet::Provider::TestNoopSupport::TestNoopSupport < Puppet::ResourceApi::SimpleProvider +class Puppet::Provider::TestNoopSupport::TestNoopSupport def get(_context) [ { @@ -16,15 +16,8 @@ def get(_context) ] end - def create(context, name, should) - context.notice("Creating '#{name}' with #{should.inspect}") - end - - def update(context, name, should) - context.notice("Updating '#{name}' with #{should.inspect}") - end - - def delete(context, name) - context.notice("Deleting '#{name}'") + def set(context, changes, noop: false) + context.notice("noop: #{noop}") + context.notice("inspect: #{changes.inspect}") end end diff --git a/spec/fixtures/test_module/lib/puppet/type/test_noop_support.rb b/spec/fixtures/test_module/lib/puppet/type/test_noop_support.rb index f9fd668b..71998a25 100644 --- a/spec/fixtures/test_module/lib/puppet/type/test_noop_support.rb +++ b/spec/fixtures/test_module/lib/puppet/type/test_noop_support.rb @@ -5,7 +5,7 @@ docs: <<-EOS, This type provides Puppet with the capabilities to manage ... EOS - features: [], + features: ['supports_noop'], attributes: { ensure: { type: 'Enum[present, absent]', diff --git a/spec/puppet/resource_api_spec.rb b/spec/puppet/resource_api_spec.rb index c8194cbd..bdfd1c50 100644 --- a/spec/puppet/resource_api_spec.rb +++ b/spec/puppet/resource_api_spec.rb @@ -837,4 +837,69 @@ def set(_context, changes) it { expect(type.apply_to).to eq(:device) } end end + + context 'with a `supports_noop` provider', agent_test: true do + let(:definition) do + { + name: 'test_noop_support', + features: ['supports_noop'], + attributes: { + ensure: { + type: 'Enum[present, absent]', + default: 'present', + }, + name: { + type: 'String', + behaviour: :namevar, + }, + }, + } + end + let(:type) { Puppet::Type.type(:test_noop_support) } + let(:provider_class) do + # Hide the `noop:` kwarg from older jruby, which is still on ruby-1.9 syntax. + eval(<