puppet file_line: remove line with unknown number of whitespaces

0

1

I'd like to remove a line from the sudoers. All works fine as long as I give the exact line. But there might be differences in white space on some machines. Couldn't find a workaround even with "match".

file_line { '/etc/sudoers':
          ensure => absent,
          path   => '/etc/sudoers',
          line   => 'myuser  ALL=NOPASSWD:/bin/su -', }

Any ideas? Thanks Acki

Acki

Posted 2014-05-26T13:35:00.420

Reputation: 1

Answers

2

I would not use ensure => absent here as it only allows for an exact match. A simple but effective workaround would be using a comment (or empty) line along with a match regex to look for to replace:

file_line { 'sudoers-myuser':
          path   => '/etc/sudoers',
          line   => '# myuser  ALL=NOPASSWD:/bin/su -', 
          match  => 'myuser.*ALL=NOPASSWD:/bin/su.*-',
}

This would introduce line even if the match is not present in the file, but as the content is a no-op, it should not present any serious issues. Take care to escape regex special characters in the match line.

syneticon-dj

Posted 2014-05-26T13:35:00.420

Reputation: 621

1

file_line is an "ok" resource for ensuring lines appear in a file but not so good for ensuring lines are not there -- which is why I completely stopped using it.

If you really need to manage this file piecemeal and need to ensure the line is absolutely gone, the augeas resource will accomplish it much better. It's rather complicated but does the job really well. And there should already be a lens for the sudoers file.

But lornix is correct. You should not be managing this file this way. It is laden with dangers and there be monsters here.

Prefer templates and include files.

To answer your question explicitly: You can't. One look at the source code for file_line shows that it only looks for an exact match -- white space and all.

  def destroy
    local_lines = lines
    File.open(resource[:path],'w') do |fh|
      fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
    end
  end

rojs

Posted 2014-05-26T13:35:00.420

Reputation: 121

0

Here's an interesting solution.

file_line { 'sudoers-myuser':
          ensure => 'absent',
          path   => '/etc/sudoers',
          match  => 'myuser.*ALL=NOPASSWD:/bin/su.*-',
          match_for_absence => true,
}

Note: For some reason, if we want to remove an entry based on 'match', 'replace' must be false.

Explanation (as best I can offer):

  • file_line does not allow for a RegEx in the line parameter, only in the match parameter.
  • Normally, 'line' is required, but match_for_absence obviates the need for 'line'.
  • The documentation states:
    • match_for_absence (defaults to: false)

      An optional value to determine if match should be applied when ensure => absent. If set to true and match is set, the line that matches match will be deleted.

  • Should you need to remove multiple matches of the same RegEx, add this parameter:
    multiple => true,

More details here: file_line cannot delete lines by regexp?

Scottie H

Posted 2014-05-26T13:35:00.420

Reputation: 231

(1) Did you “discover” this by thinking and experimenting, or did you read it somewhere?  If you read it somewhere, you must say so and identify the source.  Linking to the source document and saying “More details here” isn’t sufficient; you must *say* that you copied your answer from there. (2) Likewise, you should link to documentation when you quote it.  (If you have a better source for the information about match_for_absence, please add it.) (3) Since the objective is to match whitespace, you should probably use ­ * (space + star) rather than *`.`**. – Scott – 2019-06-01T20:29:57.007

1

By the way, I noticed that your user profile has a typo: “Words cam later.”

– Scott – 2019-06-01T20:29:59.200

It is e lionka combination of both. I read the link that I posted, and did some experimenting on my own. The answer the I posted is my own answer for something I was doing. – Scottie H – 2019-06-02T21:08:53.270

0

Put your user information into a new file, place this new file in /etc/sudoers.d

See the sudoers man page for better details. (Mostly just observe that name of file in /etc/sudoers.d cannot contain '~' or a '.'. So john_doe is good, while john.doe is bad)

This will completely remove the difficulty you're having, trying to exactly match entries in a file. Many services have ?.d subdirectories to make this easier. (cron.d, sysctl.d, /etc/modprobe.d,... and so on)

lornix

Posted 2014-05-26T13:35:00.420

Reputation: 9 633

1Sorry, but my question is more about puppet and file_line. I have to remove an entry! So your answer does not really help. – Acki – 2014-05-27T15:11:50.537