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

(PUP-3399) autorequire local file sources #8909

Open
wants to merge 1 commit into
base: 7.x
Choose a base branch
from

Conversation

evgeni
Copy link
Contributor

@evgeni evgeni commented May 4, 2022

No description provided.

@evgeni evgeni requested a review from a team as a code owner May 4, 2022 09:24
@evgeni evgeni requested a review from a team May 4, 2022 09:24
@puppetlabs-jenkins
Copy link
Collaborator

Can one of the admins verify this patch?

spec/unit/type/file_spec.rb Outdated Show resolved Hide resolved
@CLAassistant
Copy link

CLAassistant commented Apr 19, 2023

CLA assistant check
All committers have signed the CLA.

@evgeni evgeni changed the base branch from main to 7.x September 27, 2023 19:00
@@ -396,6 +396,10 @@ def self.title_patterns
end
# if the resource is a link, make sure the target is created first
req << self[:target] if self[:target]
# if the resource has a source set, make sure it is created first
self[:source]&.each do |src|
req << src.delete_prefix('file://') if src.start_with?('file://')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

it seems on Windows, the file:// prefix is not automatically added and thus this inclusion fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or rather, it is, but the path being set as file:///D:/bar (note the tree slashes), which is obviously not a valid local windows path pointing at D:/bar

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@joshcooper joshcooper Oct 25, 2023

Choose a reason for hiding this comment

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

If source is an absolute path, then it will have been normalized in

if Puppet::Util.absolute_path?(source)
# CGI.unescape will butcher properly escaped URIs
uri_string = Puppet::Util.path_to_uri(source).to_s
# Ruby 1.9.3 and earlier have a URI bug in URI
# to_s returns an ASCII string despite UTF-8 fragments
# since its escaped its safe to universally call encode
# Puppet::Util.uri_unescape always returns strings in the original encoding
Puppet::Util.uri_unescape(uri_string.encode(Encoding::UTF_8))
Essentially doing:

irb(main):034:0> Puppet::Util.uri_unescape(Puppet::Util.path_to_uri("/a path").to_s)
=> "file:///a path"

Since the source has been normalized, I think you can simply do:

irb(main):038:0> Puppet::Util.uri_to_path(URI(Puppet::Util.uri_encode(source)))
=> "/a path"

And it will work correctly on all platforms (including Windows).

Is there a particular scenario where this comes up frequently? Or just something that would be good to fix?

Copy link
Contributor Author

@evgeni evgeni Oct 25, 2023

Choose a reason for hiding this comment

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

"this" being Windows or autorequires for the source attribute?

If the latter: we had it come up in one of our (the foreman) modules and I thought it'd be nice to have. Certainly not everyday material.

Copy link
Contributor

Choose a reason for hiding this comment

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

"this" being Windows or autorequires for the source attribute?

yeah the latter, wondering when you'd need to autorequire local sources.

I thought it'd be nice to have. Certainly not everyday material.

I'm always hesitant to modify the file type/provider given the amount of complexity there. For example, are there cases where a file is ensure => absent but has a source? Puppet doesn't automatically reverse the dependency order so we run into things like #9114 (comment)

Copy link
Contributor Author

@evgeni evgeni Nov 15, 2023

Choose a reason for hiding this comment

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

I opened this because of this hack we have over in theforeman/foreman_proxy:
https://github.com/theforeman/puppet-foreman_proxy/blob/69c038e607d9fd9558436b2afad312949ef530d7/manifests/plugin/remote_execution/mosquitto.pp#L99-L103

The TL;DR version is:

We have a different deployment modes:

  • use Puppet CA for certs
  • use a special module (certs) that deploys the certs to a specific place on the system
  • let the user break stuff at their will

In either case, the certs need to land in a place where mosquitto can read them (selinux, perms, etc), so we need to copy them from one place to another.

Local source seems like the correct way here, but it needs an explicit require, IF the thing is managed by puppet (it might not be).

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm always hesitant to modify the file type/provider given the amount of complexity there. For example, are there cases where a file is ensure => absent but has a source? Puppet doesn't automatically reverse the dependency order so we run into things like #9114 (comment)

I think a source shouldn't apply if something is ensured absent, but you raise a good point.

At first glance, the whole autorequire looks like it's not well designed for ensuring absent. The target relation is not needed either (but probably doesn't hurt in practice). You'd think Finding all ancestors up to the root however is not needed at all and could even introduce problems. Assuming mkdir -p /path/sub:

file { ['/path', '/path/sub']::
  ensure => absent,
}

Yields:

# puppet apply test.pp 
Notice: Compiled catalog for host.example.com in environment production in 0.01 seconds
Notice: /Stage[main]/Main/File[/tmp/path]: Not removing directory; use 'force' to override
Notice: /Stage[main]/Main/File[/tmp/path]/ensure: removed
Notice: /Stage[main]/Main/File[/tmp/path/sub]: Not removing directory; use 'force' to override
Notice: /Stage[main]/Main/File[/tmp/path/sub]/ensure: removed
Notice: Applied catalog in 0.01 seconds

Ok, misleading. So we modify it to:

# puppet apply test.pp 
Notice: Compiled catalog for host.example.com in environment production in 0.01 seconds
Notice: /Stage[main]/Main/File[/tmp/path]/ensure: removed
Notice: Applied catalog in 0.02 seconds

Upon further inspection, this tries to remove the top most directory first. That's actually good. It doesn't list all sub-resources and is probably more efficient. If it then needs to ensure a file within the directory it is actually idempotent: it'll fail because the parent doesn't exist, instead of creating the file and then removing the parent which would cause it fail on the next run.

@joshcooper joshcooper added the enhancement New feature or request label Nov 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants