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

Add title consistency checks for multi-namevar providers #240

Merged
merged 3 commits into from
Dec 5, 2019
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
60 changes: 52 additions & 8 deletions lib/puppet/resource_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def refresh_current_state

if @rsapi_current_state
type_definition.check_schema(@rsapi_current_state)
strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize')
strict_check(@rsapi_current_state)
else
@rsapi_current_state = if rsapi_title.is_a? Hash
rsapi_title.dup
Expand All @@ -275,7 +275,7 @@ def refresh_current_state
# Use this to set the current state from the `instances` method
def cache_current_state(resource_hash)
@rsapi_current_state = resource_hash
strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize')
strict_check(@rsapi_current_state)
end

def retrieve
Expand Down Expand Up @@ -354,6 +354,22 @@ def raise_missing_params
def strict_check(current_state)
return if Puppet.settings[:strict] == :off

strict_check_canonicalize(current_state) if type_definition.feature?('canonicalize')
strict_check_title_parameter(current_state) if type_definition.namevars.size > 1 && !type_definition.title_patterns.empty?

nil
end

def strict_message(message)
case Puppet.settings[:strict]
when :warning
Puppet.warning(message)
when :error
raise Puppet::DevError, message
end
end

def strict_check_canonicalize(current_state)
# if strict checking is on we must notify if the values are changed by canonicalize
# make a deep copy to perform the operation on and to compare against later
state_clone = Marshal.load(Marshal.dump(current_state))
Expand All @@ -370,15 +386,43 @@ def strict_check(current_state)
Canonicalized values: #{state_clone.inspect}
MESSAGE
#:nocov:
strict_message(message)
end

case Puppet.settings[:strict]
when :warning
Puppet.warning(message)
when :error
raise Puppet::DevError, message
def strict_check_title_parameter(current_state)
unless current_state.key?(:title)
strict_message("#{type_definition.name}[#{@title}]#get has not provided a title attribute.")
return
end

nil
# Logic borrowed from Puppet::Resource.parse_title
title_hash = {}
self.class.title_patterns.each do |regexp, symbols|
captures = regexp.match(current_state[:title])
next if captures.nil?
symbols.zip(captures[1..-1]).each do |symbol_and_lambda, capture|
# The Resource API does not support passing procs in title_patterns
# so, unlike Puppet::Resource, we do not need to handle that here.
symbol = symbol_and_lambda[0]
title_hash[symbol] = capture
end
break
end

return if title_hash == rsapi_title

namevars = type_definition.namevars.reject { |namevar| title_hash[namevar] == rsapi_title[namevar] }

#:nocov:
# codecov fails to register this multiline as covered, even though simplecov does.
message = <<MESSAGE.strip
#{type_definition.name}[#{@title}]#get has provided a title attribute which does not match all namevars.
Namevars which do not match: #{namevars.inspect}
Returned parsed title hash: #{title_hash.inspect}
Expected hash: #{rsapi_title.inspect}
MESSAGE
#:nocov:
strict_message(message)
end

define_singleton_method(:context) do
Expand Down
4 changes: 4 additions & 0 deletions lib/puppet/resource_api/type_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def feature?(feature)
(definition[:features] && definition[:features].include?(feature))
end

def title_patterns
definition[:title_patterns] ||= []
end

def validate_schema(definition, attr_key)
super(definition, attr_key)
[:title, :provider, :alias, :audit, :before, :consume, :export, :loglevel, :noop, :notify, :require, :schedule, :stage, :subscribe, :tag].each do |name|
Expand Down
10 changes: 10 additions & 0 deletions spec/fixtures/test_module/lib/puppet/type/multiple_namevar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
docs: <<-EOS,
This type provides Puppet with the capabilities to manage ...
EOS
title_patterns: [
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a title_patterns test type instead of changing this one, to preserve multiple-namevars-no-title_patterns testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes in this file are no longer necessary after improving the title verification logic and I have removed it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I take back that last comment. I think I need to add a title_patterns definition because that acceptance test deals with multiple namevars and has strict enabled, which means this patch has it trigger errors. Is your expectation that a type with multiple namevars and no title_patterns should emit no warnings or errors?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, my expectation is that a type with multiple namevars and no title_patterns should emit no warnings or errors. Resources with multiple namevars can be specified by passing in values as properties rather than through the title. While a valid design choice in some rare edge-cases, I'm not overly fond of it. Let's keep this acceptance test as it is, but please add a unit test (and associated code) to make sure that title_patterns are not required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the relaxation of the check in a separate commit. If you're fine with it, we can get this merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, looks great! Thanks for doing that. It would have been at least a few days before I could have gotten to it.

pattern: %r{^(?<package>.*[^-])-(?<manager>.*)$},
desc: 'Package and manager with a hyphen seperator',
},
{
pattern: %r{^(?<package>.*)$},
desc: 'Package',
},
],
attributes: {
ensure: {
type: 'Enum[present, absent]',
Expand Down
Loading