Jira (PUP-10214) Unexpected results on "replace => false" on symlinks

20 views
Skip to first unread message

Corey Hickey (JIRA)

unread,
Jan 2, 2020, 7:18:04 PM1/2/20
to puppe...@googlegroups.com
Corey Hickey created an issue
 
Puppet / Bug PUP-10214
Unexpected results on "replace => false" on symlinks
Issue Type: Bug Bug
Affects Versions: PUP 5.5.17
Assignee: Unassigned
Components: Catalog Application
Created: 2020/01/02 4:17 PM
Priority: Normal Normal
Reporter: Corey Hickey

Puppet Version: 5.5.17-1.el7
Puppet Server Version:5.3.10-1.el7
OS Name/Version: Centos 7

This is a copy of an old redmine ticket that was never resolved:

https://projects.puppetlabs.com/issues/4872

To summarize, if puppet contains a declaration:

file { '/foo':
    ensure  => 'link',
    target  => '/bar'
    replace => false,
}

...and '/foo' already exists as a dangling symlink (pointing to a file that does not exist), then puppet will change the symlink to point back to '/bar'.

Desired Behavior:

Puppet should respect replace => false and not replace the symlink.

Actual Behavior:

As described above, puppet replaces the symlink.

 

I looked at the code and I think the current behavior is the same in master, though I don't have the means to test it myself. These parts seem relevant:

lib/puppet/type/file/target.rb

     def insync?(currentvalue)
      if [:nochange, :notlink].include?(self.should) or @resource.recurse?
        return true
      elsif ! @resource.replace? and Puppet::FileSystem.exist?(@resource[:path])
        return true
      else

lib/puppet/file_system.rb

  # Determines if a file exists by verifying that the file can be stat'd.
  # Will follow symlinks and verify that the actual target path exists.
  #
  # @return [Boolean] true if the named file exists.
  #
  # @api public
  #
  def self.exist?(path)
    @impl.exist?(assert_path(path))
  end 

I think that for this functionality, the file resource code should instead use a function that does not follow symlinks. Puppet is managing the file, not the target.

 

Thanks,
Corey

Add Comment Add Comment
 
This message was sent by Atlassian JIRA (v7.7.1#77002-sha1:e75ca93)
Atlassian logo

Corey Hickey (JIRA)

unread,
Jan 2, 2020, 7:23:03 PM1/2/20
to puppe...@googlegroups.com
Corey Hickey updated an issue
Change By: Corey Hickey
*Puppet Version: 5.5.17-1.el7*
*Puppet Server Version:5.3.10-1.el7*
*OS Name/Version: Centos 7*


This is a copy of an old redmine ticket that was never resolved:

[https://projects.puppetlabs.com/issues/4872]

To summarize, if puppet contains a declaration:
{code}file { '/foo':

    ensure  => 'link',
    target  => '/bar'
    replace => false,
}
{code}

...and '/foo' already exists as a dangling symlink (pointing to a file that does not exist), then puppet will change the symlink to point back to '/bar'.

*Desired Behavior:*


Puppet should respect {{replace =>}} false and not replace the symlink.

*Actual Behavior:*


As described above, puppet replaces the symlink.

 

I looked at the code and I think the current behavior is the same in master, though I don't have the means to test it myself. These parts seem relevant:

lib/puppet/type/file/target.rb
{code}     def insync?(currentvalue)

      if [:nochange, :notlink].include?(self.should) or @resource.recurse?
        return true
      elsif ! @resource.replace? and Puppet::FileSystem.exist?(@resource[:path])
        return true
      else
{code}
lib/puppet/file_system.rb
{code}  # Determines if a file exists by verifying that the file can be stat'd.

  # Will follow symlinks and verify that the actual target path exists.
  #
  # @return [Boolean] true if the named file exists.
  #
  # @api public
  #
  def self.exist?(path)
    @impl.exist?(assert_path(path))
  end
{code}
I think that for this functionality, the file resource code should instead use a function that does _not_ follow symlinks. Puppet is
supposed to be managing the file symlink , and the target (present or not ) is irrelevant. When creating a symlink, puppet correctly does not care if the target exists .

 

Thanks,
Corey

Corey Hickey (JIRA)

unread,
Jan 2, 2020, 8:52:03 PM1/2/20
to puppe...@googlegroups.com
Corey Hickey commented on Bug PUP-10214
 
Re: Unexpected results on "replace => false" on symlinks

As a related issue, the creates parameter to the exec resource also follows symlinks, so it breaks when the symlink is dangling. This issue seems to be abandoned as well:

https://projects.puppetlabs.com/issues/13126

-Corey

Jorie Tappa (JIRA)

unread,
Jan 6, 2020, 1:16:03 PM1/6/20
to puppe...@googlegroups.com
Jorie Tappa commented on Bug PUP-10214

Hi Corey Hickey, we'll try and investigate this issue, but because it seems to relate to other symlink behavior we've already closed as "won't fix" it's unlikely we'll be able to triage this into our work.

Josh Cooper (JIRA)

unread,
Jan 6, 2020, 5:11:03 PM1/6/20
to puppe...@googlegroups.com

Josh Cooper (JIRA)

unread,
Jan 6, 2020, 5:11:04 PM1/6/20
to puppe...@googlegroups.com
Josh Cooper commented on Bug PUP-10214
 
Re: Unexpected results on "replace => false" on symlinks

Corey Hickey you'd need to take into account whether puppet is managing the symlink or following, which is controlled via the links parameter. So the logic would need to be something like:

def insync?(currentvalue)
  if [:nochange, :notlink].include?(self.should) or @resource.recurse?
    return true
  elsif ! @resource.replace?
    begin
      if @resource[:links] == :follow
        Puppet::FileSystem.stat(@resource[:path])
      else
        Puppet::FileSystem.lstat(@resource[:path])
      end
      true
    rescue Errno::ENOENT
      false
    end
  else
    return super(currentvalue)
  end
end

Corey Hickey (JIRA)

unread,
Jan 6, 2020, 9:06:04 PM1/6/20
to puppe...@googlegroups.com
Corey Hickey commented on Bug PUP-10214

Josh Cooper I thought the links parameter was for how to handle files local to the puppetmaster, but it would seem appropriate to extend the parameter to this case, especially as in your example where the default behavior fixes the bug.

Jorie Tappa thanks for your comment. I took a look at PUP-5830 and I think I would characterize that ticket as describing "strange behavior when given pathological parameters", whereas my ticket here is more "incorrect behavior under some circumstances when given appropriate parameters". So, I don't think it would be fair to consider PUP-5830 as precedent.

-Corey

Josh Cooper (JIRA)

unread,
Jan 7, 2020, 2:47:04 PM1/7/20
to puppe...@googlegroups.com

Josh Cooper (JIRA)

unread,
Jan 7, 2020, 2:48:04 PM1/7/20
to puppe...@googlegroups.com

I thought the links parameter was for how to handle files local to the puppetmaster

Nah, it's how the the agent should manage the link (either the link itself or the thing the link points to).

Josh Cooper (Jira)

unread,
Jun 5, 2020, 7:40:02 PM6/5/20
to puppe...@googlegroups.com
Josh Cooper updated an issue
Change By: Josh Cooper
Epic Link: PUP-7548
This message was sent by Atlassian Jira (v8.5.2#805002-sha1:a66f935)
Atlassian logo

Josh Cooper (Jira)

unread,
Jun 15, 2021, 1:28:02 PM6/15/21
to puppe...@googlegroups.com
Josh Cooper commented on Bug PUP-10214
 
Re: Unexpected results on "replace => false" on symlinks

This is a dup of PUP-6998. If the resource is not currently a symlink and target is specified, then puppet will create the symlink always (regardless of replace). I'll add a note on the ticket about the replace behavior and close this.

This message was sent by Atlassian Jira (v8.13.2#813002-sha1:c495a97)
Atlassian logo

Corey Hickey (Jira)

unread,
Jun 16, 2021, 2:23:03 AM6/16/21
to puppe...@googlegroups.com
Corey Hickey commented on Bug PUP-10214

Thanks Josh Cooper , but I think the two bugs are different. PUP-6998 seems to be more of a logic issue in puppet deciding to manage a file as a symlink rather than as the specified ensure.

For this bug, I revisited it on the current main git branch.

First, I don't understand your point about the links parameter. I tested that with a simple manifest:

file { '/tmp/foo':
    ensure  => 'file',
    content => "new\n",
    links   => 'follow',
}

Via:

$ echo orig > /tmp/bar
$ ln -s bar /tmp/foo
$ ls -l /tmp/foo
lrwxrwxrwx 1 chickey chickey 3 2021-06-15 22:59:39 /tmp/foo -> bar
 $ RUBYLIB=./lib bin/puppet --version
7.9.0
$ RUBYLIB=./lib bin/puppet apply test.pp
Notice: Compiled catalog for corey.tagged.com in environment production in 0.01 seconds
Notice: Applied catalog in 0.03 seconds
$ ls -l /tmp/foo
-rwxrwxrwx 1 chickey chickey 4 2021-06-15 22:59:53 /tmp/foo
$ cat /tmp/foo
new

This behavior is what I expect; the documentation is vague, but it does not specify "local system" as it does in other cases to refer to the system that is being managed by puppet. Thus, my understanding is that the "links" parameter applies to the compilation of the catalog, not the application of the catalog.

As for the original bug, I just made a PR:
https://github.com/puppetlabs/puppet/pull/8643

I'm not sure if the tests will pass; if not, I'll probably need advice. This is a start, at least.

-Corey

Reply all
Reply to author
Forward
0 new messages