Augeas type: Removing an entry from /etc/hosts

4,888 views
Skip to first unread message

Paul Elliott

unread,
Feb 22, 2010, 11:23:35 AM2/22/10
to puppet...@googlegroups.com
Hi all,

I'm just starting to look at using Augeas with Puppet to manage some of
our configuration files. I thought I would start with a simple task of
removing an entry from the /etc/hosts file. I'm not finding it simple
though!

We have a number of hosts with entries in the /etc/hosts file like this:

127.0.1.1 hostname

We would like to remove these lines. Now I know this can be done with a
simple exec of sed but if possible I would like to use it as a good test
exercise with Augeas. Now, it's pretty easy to do this with augtool, as
follows:

root@miscreant:/home/pre500# augtool
augtool> match /files/etc/hosts/*/ipaddr 127.0.1.1
/files/etc/hosts/4/ipaddr
augtool> rm /files/etc/hosts/4
rm : /files/etc/hosts/4 3
augtool> save
Saved 1 file(s)

But I can't see how this would translate to work in Puppet as I need to
match the relevant path before I can issue the rm. Am I missing
something obvious here?

--
Paul Elliott, UNIX Systems Administrator
Computing Service, University of York

John Lyman

unread,
Feb 22, 2010, 11:46:55 AM2/22/10
to Puppet Users
> ... I know this can be done with a simple exec of sed but ...

Or with the "host" native type. See http://docs.reductivelabs.com/references/stable/type.html#host

David Lutterkort

unread,
Feb 22, 2010, 2:25:56 PM2/22/10
to puppet...@googlegroups.com
On Mon, 2010-02-22 at 16:23 +0000, Paul Elliott wrote:
> I'm just starting to look at using Augeas with Puppet to manage some of
> our configuration files. I thought I would start with a simple task of
> removing an entry from the /etc/hosts file. I'm not finding it simple
> though!
>
> We have a number of hosts with entries in the /etc/hosts file like this:
>
> 127.0.1.1 hostname
>
> We would like to remove these lines. Now I know this can be done with a
> simple exec of sed but if possible I would like to use it as a good test
> exercise with Augeas. Now, it's pretty easy to do this with augtool, as
> follows:
>
> root@miscreant:/home/pre500# augtool
> augtool> match /files/etc/hosts/*/ipaddr 127.0.1.1
> /files/etc/hosts/4/ipaddr

You can do this by looking for the entries with a single path
expression:

augtool> match /files/etc/hosts/*[ipaddr = '127.0.1.1']

gives you all entries in /etc/hosts with that IP. To remove them, just
do 'rm' instead of 'match'. From your post, I wasn't sure if you had
multiple such entries in /etc/hosts. If you do, and you want to delete
all of them except the one that has 'host.example.com' as a canonical
name, you can say

augtool> rm /files/etc/hosts/*[ipaddr = '127.0.1.1'][canonical != 'host.example.com]

or, to delete all but the first one:

augtool> rm /files/etc/hosts/*[ipaddr = '127.0.1.1'][position() > 1]

Some docs about this notation is on the Augeas Wiki[1]

David

[1] http://augeas.net/page/Path_expressions

Paul Elliott

unread,
Feb 23, 2010, 5:51:52 AM2/23/10
to puppet...@googlegroups.com
Hi David,

On 22/02/10 19:25, David Lutterkort wrote:
> You can do this by looking for the entries with a single path
> expression:
> augtool> match /files/etc/hosts/*[ipaddr = '127.0.1.1']
> gives you all entries in /etc/hosts with that IP. To remove them, just
> do 'rm' instead of 'match'. From your post, I wasn't sure if you had

<snip>
> [1] http://augeas.net/page/Path_expressions

Perfect, that's just what I was looking for and it works like a charm.

Thanks, Paul.

Jesús Couto

unread,
Feb 23, 2010, 7:37:06 AM2/23/10
to puppet...@googlegroups.com
On a tangent, anybody using augeas under puppet to manage /etc/sudoers? ... and how?

I was thinking about doing so to add/delete several commands to an administrator group as part of setting up an apache/tomcat/whatever instance, but cant figure out how to do it, for reasons similar to this example. And rm doesnt work for adding :-P


--------------------------------------------------------
Jesús Couto F.

Rob McBroom

unread,
Feb 23, 2010, 2:02:15 PM2/23/10
to puppet...@googlegroups.com
On Feb 23, 2010, at 7:37 AM, Jesús Couto wrote:

> On a tangent, anybody using augeas under puppet to manage /etc/sudoers? ... and how?

I tried, but all I could get it to do was add the entries to the end of `/etc/sudoers` over and over every 30 minutes. I gave up and made a define that calls some hacky execs.

I’d love to hear there’s a way (in 0.24.8).

--
Rob McBroom
<http://www.skurfer.com/>

David Lutterkort

unread,
Feb 24, 2010, 6:32:04 PM2/24/10
to puppet...@googlegroups.com
On Tue, 2010-02-23 at 14:02 -0500, Rob McBroom wrote:
> On Feb 23, 2010, at 7:37 AM, Jesús Couto wrote:
>
> > On a tangent, anybody using augeas under puppet to
> > manage /etc/sudoers? ... and how?
>
> I tried, but all I could get it to do was add the entries to the end
> of `/etc/sudoers` over and over every 30 minutes. I gave up and made a
> define that calls some hacky execs.
>
> I’d love to hear there’s a way (in 0.24.8).

I'd wager that the problem was that you were missing an onlyif that
would keep the changes from being applied when the entries are there
already.

David


Rob McBroom

unread,
Feb 26, 2010, 8:24:31 AM2/26/10
to puppet...@googlegroups.com

I know that, and in theory you’re right. But bug #2141 has prevented so many of my `onlyif`s from working in 0.24.8 that I don’t even bother trying.

I’m basically waiting until EPEL gets 0.25.x to really use Augeas.

--
Rob McBroom
<http://www.skurfer.com/>

Because it screws up the order in which people normally read text.

Original message:

> Why is it bad to top-post your reply?


Seth Rice

unread,
Oct 8, 2015, 1:53:40 PM10/8/15
to Puppet Users
I know this is way late, by 5 years or so, but I wanted to share what I just discovered, related to your post. Since your post did help me discover it after all.  I only got into augeas 4 days ago, and puppet about a month ago.

Though augeas is a harsh mistress, I found that you can do some good sudoers stuff with it. Also how to specify if you want it to wipe a matching entry and replace it, or just replace pieces of it.

I have a module that has it's own user that will be created, and permissions granted in sudoers and locked down. Here is what I found works on the current opensource puppet today.

This augeas (awe-geez) excerpt below is from the user manifest in that module. Above I have all the regular puppet jazz to create a user, it's home path, create keys, etc. It all references back to a params.pp file for the variables. I found that with puppet, things work more consistently if you use this type of setup for a variable.

"${User}"

Double quotes, and braces between the $ and the actual variable. However Augeas doesn't like that setup. so once you start getting to the 'changes => [ ' part, you need to change your variable statements to be what you'd have in bash.

$User

Also note, as seen below, I use the double quotes for my commands when using a variable. Otherwise use single quotes.

  augeas { "sudoers user ${User}":
       context  => '/files/etc/sudoers',
       changes  => [
        "set spec[user = '$User']/user $User",
        "set spec[user = '$User']/host_group/host ALL",
        "set spec[user = '$User']/host_group/command ALL",
        "set spec[user = '$User']/host_group/command/runas_user ALL",
        "set spec[user = '$User']/host_group/command/tag NOPASSWD",
       ],
       require  => [ User[$User] ],
  }

  augeas { "sudoers user ${User} TTY":
       context  => '/files/etc/sudoers',
       changes  => [
        "set Defaults[type = ':$User']/type :$User",
        "set Defaults[type = ':$User']/requiretty/negate ''",
       ],
       require => [ augeas["sudoers user $User"] ],
  }

  augeas { "sudoers Cmnd_Alias ${CMNDALIAS}":
       context => '/files/etc/sudoers',
       changes => [
        "rm  Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[.]",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/name $CMNDALIAS",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[1] /bin/cp",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[2] /bin/grep",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[3] /bin/date",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[4] /bin/ls",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[5] /bin/rm",
        "set Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[6] /bin/mv",
       ],
       require => File['/etc/sudoers'],
  }


Now the key thing I wanted to point out that I just discovered in all this, is this line in the Cmnd_Alias section.

        "rm  Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[.]",

There is a subtle difference between using a [.] or a [*]. Because I'm declaring which command goes in what order, the dot will match any command, and the * will match only the ones stated in this manifest, and ignore the rest. So I went to [6] in my command listing above. This means with a dot [.], it will blow away 1-6, as well as any others, like 7-999, or however high it can go. If I use the star [*], then it only replace 1-6, and leave 7-999 or however high, well alone.

Here is a command I've been running on the system I want to apply the changes on, to show me what augeas sees while I work.

watch -n3 "augtool print /files/etc/sudoers | grep -Ei '(use r|host_group|alias|defaults\[11\])' | grep -Ev '(spec\[(1|2)\]|comment)'"

that output for me looks like this:

Every 3.0s: augtool print /files/etc/sudoers | grep ...  Thu Oct  8 11:23:52 2015

/files/etc/sudoers/Defaults[6]/env_keep/var[5] = "USERNAME"
/files/etc/sudoers/spec[3]/user = "dude"
/files/etc/sudoers/spec[3]/host_group
/files/etc/sudoers/spec[3]/host_group/host = "ALL"
/files/etc/sudoers/spec[3]/host_group/command = "ALL"
/files/etc/sudoers/spec[3]/host_group/command/runas_user = "ALL"
/files/etc/sudoers/spec[3]/host_group/command/tag = "NOPASSWD"
/files/etc/sudoers/Defaults[11]
/files/etc/sudoers/Defaults[11]/type = ":dude"
/files/etc/sudoers/Defaults[11]/requiretty
/files/etc/sudoers/Defaults[11]/requiretty/negate
/files/etc/sudoers/Cmnd_Alias
/files/etc/sudoers/Cmnd_Alias/alias
/files/etc/sudoers/Cmnd_Alias/alias/name = "DUDEADMIN"
/files/etc/sudoers/Cmnd_Alias/alias/command[1] = "/bin/cp"
/files/etc/sudoers/Cmnd_Alias/alias/command[2] = "/bin/grep"
/files/etc/sudoers/Cmnd_Alias/alias/command[3] = "/bin/date"
/files/etc/sudoers/Cmnd_Alias/alias/command[4] = "/bin/ls"
/files/etc/sudoers/Cmnd_Alias/alias/command[5] = "/bin/rm"
/files/etc/sudoers/Cmnd_Alias/alias/command[6] = "/bin/mv"

So why does all this matter? As far as I can tell augeas is like SNMP for file content. That is with SNMP you have OID's which can be translated to MIBS. The same is more or less true here. A path of specific bits gets you to an end value. Sometimes that path can be dynamic. That is, the path can change based on the configuration. So in this case I wanted to make sure that the first 6 commands this user could run, via the alias, are only these 6 commands. No more, no less.

The [.] on the rm line ensures that if there are no changes to be made, it leaves well alone. But if they don't match, especially if there are more commands than what shows in the manifest, it blows them all away, and starts fresh for that line.

The most important part comes when I want to create another manifest later on. A manifest that might temporarily add permissions to that user for installation or auditing purposes or something. In that case I would want this manifest to use the [*]. That will ensure that the first 6 commands stated in this manifest don't get over written by any other manifest. However it also will leave any other commands in there. So commands 7-999 or however high, are left alone.

Here is what the puppet output gave me for a diff after running with each type. I manually did a visudo, and added this line. Notice the change for command[2] is now gzip instead of grep. It should change that for both types since it's not what I have in the manifest.
Cmnd_Alias DUDEADMIN = /bin/cp , /bin/gzip , /bin/date , /bin/ls , /bin/rm , /bin/mv , /temp/test , /temp/test2

  Using [.]

"rm  Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[.]",

  It noticed the change, and blew away the entire line, bringing it back only as described in the manifest. Notice the gzip change to grep, for command[2] as desired.

-Cmnd_Alias DUDEADMIN = /bin/cp , /bin/gzip , /bin/date , /bin/ls , /bin/rm , /bin/mv , /temp/test  , /temp/test2
+Cmnd_Alias DUDEADMIN = /bin/cp , /bin/grep , /bin/date , /bin/ls , /bin/rm , /bin/mv



  Using [*]

"rm  Cmnd_Alias[alias/name = '$CMNDALIAS']/alias/command[*]",

It noticed the change for the command[2] position, and changed it from gzip to grep as stated in the manifest. But this time it left the rest alone. Even though the manifest only goes to 6. The * made it ignore 7 to whatever.

-Cmnd_Alias DUDEADMIN = /bin/cp , /bin/gzip , /bin/date , /bin/ls , /bin/rm , /bin/mv , /temp/test , /temp/test2
+Cmnd_Alias DUDEADMIN = /bin/cp , /bin/grep , /bin/date , /bin/ls , /bin/rm , /bin/mv , /temp/test , /temp/test2


Here is what my watch loop shows now

/files/etc/sudoers/Cmnd_Alias
/files/etc/sudoers/Cmnd_Alias/alias
/files/etc/sudoers/Cmnd_Alias/alias/name = "DUDEADMIN"
/files/etc/sudoers/Cmnd_Alias/alias/command[1] = "/bin/cp"
/files/etc/sudoers/Cmnd_Alias/alias/command[2] = "/bin/grep"
/files/etc/sudoers/Cmnd_Alias/alias/command[3] = "/bin/date"
/files/etc/sudoers/Cmnd_Alias/alias/command[4] = "/bin/ls"
/files/etc/sudoers/Cmnd_Alias/alias/command[5] = "/bin/rm"
/files/etc/sudoers/Cmnd_Alias/alias/command[6] = "/bin/mv"
/files/etc/sudoers/Cmnd_Alias/alias/command[7] = "/temp/test"
/files/etc/sudoers/Cmnd_Alias/alias/command[8] = "/temp/test2"

Anyways, Its something way cool that not to many folks seem to post about. I Just wanted to share it with you all.

-Seth
Reply all
Reply to author
Forward
0 new messages