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

Make ParsedFile provider work with composite namevars #9130

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
45 changes: 15 additions & 30 deletions lib/puppet/provider/parsedfile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
extend Puppet::Util::FileParsing

class << self
attr_accessor :default_target, :target, :raise_prefetch_errors
attr_accessor :default_target, :raise_prefetch_errors
end

attr_accessor :property_hash
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure why it needs to be an accessor. I think it can only break things.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree in principal, but it's referenced by subclasses of ParsedFile like https://github.com/puppetlabs/puppetlabs-sshkeys_core/blob/fbd0c6dc9ca7314a567b6873cb66e2adf52af30b/lib/puppet/provider/sshkey/parsed.rb#L32C8-L32C21 and is therefore part of the parsed file API.


def self.clean(hash)
newhash = hash.dup
[:record_type, :on_disk].each do |p|
Expand Down Expand Up @@ -247,7 +245,9 @@ def self.match_providers_with_resources(resources)
resource = match(record, matchers)
if resource
matchers.delete(resource.title)
record[:name] = resource[:name]
resource.class.key_attributes.each do |name|
record[name] = resource[name]
end
resource.provider = new(record)
end
end
Expand All @@ -263,9 +263,10 @@ def self.match_providers_with_resources(resources)
#
# @return [Puppet::Resource, nil] The resource if found, else nil
def self.resource_for_record(record, resources)
name = record[:name]
if name
resources[name]
resources.values.find do |resource|
resource.class.key_attributes.all? do |name|
record[name] == resource[name]
end
end
end

Expand Down Expand Up @@ -311,12 +312,6 @@ def self.prefetch_target(target)
target_records
end

# Is there an existing record with this name?
def self.record?(name)
return nil unless @records
@records.find { |r| r[:name] == name }
end

Copy link
Contributor

Choose a reason for hiding this comment

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

This is called in

@property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} if @property_hash.empty?

# Retrieve the text for the file. Returns nil in the unlikely
# event that it doesn't exist.
def self.retrieve(path)
Expand Down Expand Up @@ -386,12 +381,10 @@ def self.targets(resources = nil)
targets += @target_objects.keys

# Lastly, check the file from any resource instances
if resources
resources.each do |name, resource|
value = resource.should(:target)
if value
targets << value
end
resources&.each do |name, resource|
value = resource[:target]
if value
targets << value
end
end
Comment on lines +384 to 389
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 can probably be optimized by relying on Ruby 2.7+

targets += resources.filter_map { |_name, resource| resource[:target] } if resources


Expand Down Expand Up @@ -429,17 +422,15 @@ def create
end
end
mark_target_modified
(@resource.class.name.to_s + "_created").intern
Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK create is supposed to not return anything.

end

def destroy
# We use the method here so it marks the target as modified.
self.ensure = :absent
(@resource.class.name.to_s + "_deleted").intern
Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIK destroy it not supposed to return anything

end

def exists?
!(@property_hash[:ensure] == :absent or @property_hash[:ensure].nil?)
@property_hash[:ensure] == :present
end

# Write our data to disk.
Expand All @@ -449,7 +440,7 @@ def flush
# If the target isn't set, then this is our first modification, so
# mark it for flushing.
unless @property_hash[:target]
@property_hash[:target] = @resource.should(:target) || self.class.default_target
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this may be because I started to use target as a parameter instead of a property.

@property_hash[:target] = @resource[:target] || self.class.default_target
self.class.modified(@property_hash[:target])
end
@resource.class.key_attributes.each do |attr|
Expand All @@ -465,13 +456,7 @@ def initialize(record)
# The 'record' could be a resource or a record, depending on how the provider
# is initialized. If we got an empty property hash (probably because the resource
# is just being initialized), then we want to set up some defaults.
@property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} if @property_hash.empty?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my testing it's not needed to set the properties when a Puppet::Resource is passed in, but it is needed to set the record_type to skip things. Perhaps skip_record? isn't needed at all anymore and can be dropped. Then this line can also be dropped.

end

# Retrieve the current state from disk.
def prefetch
raise Puppet::DevError, _("Somehow got told to prefetch with no resource set") unless @resource
self.class.prefetch(@resource[:name] => @resource)
@property_hash[:record_type] ||= self.class.name
end

def record_type
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ def resources_by_provider(type_name, provider_name)
@catalog.vertices.each do |resource|
if resource.class.attrclass(:provider)
prov = resource.provider && resource.provider.class.name
@resources_by_provider[resource.type][prov][resource.name] = resource
@resources_by_provider[resource.type][prov][resource.title] = resource
Copy link
Contributor

Choose a reason for hiding this comment

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

Since resource title doesn't always equal name, I'm pretty sure this will be break something.

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like puppet originally prefetched using title (see commit c35d07b)

                prefetchers[provider.class][resource.title] = resource

Later there was a bug reported in the mount provider redmine #2013 And puppet was changed to use name in 9577d3a as "ParsedFile types seem to be the main one that suffers from (mismatch between type and title)"

-                prefetchers[provider.class][resource.title] = resource
+                prefetchers[provider.class][resource.name] = resource

I'm not convinced that changing the transaction to use name was the right fix (as opposed to a bug in the mount provider), but that ship sailed awhile ago. We'll need a different way for parsed file providers to opt-into the new behavior.

end
end
end
Expand Down
Loading