On Monday, December 7, 2015 at 4:51:10 PM UTC-6, Sean wrote:
>
> John,
>
> Thanks for the reply. To answer your first question, no I'm not
> completely sure. What I can say is that I can run the commands in a shell
> by hand and the result is what I hope for. When I run puppet, with this
> particular class included, puppet hangs for a while with no screen output.
> This leads me to believe that the "unless" fails and the "command"
> executes.
>
I suggest that instead of guessing, you run the agent with --debug output
enabled, which indeed you have done. That should give you a pretty good
idea of which commands run and which do not, and at least a somewhat more
certain understanding of why.
> I can verify that by running (in another shell):
>
> [root@desktop ~]# ps -ef|grep aide
> root 28085 1 0 14:42 ? 00:00:00 sh -c /usr/sbin/aide --init
> >/dev/null 2>&1 && cp -p ${DBDIR}/${DBNEW} ${DBDIR}/${DBFILE}
> root 28088 28085 20 14:42 ? 00:01:24 /usr/sbin/aide --init
>
>
> I can say when I run the various piece by hand inside an interactive shell
> everything comes out as expected:
>
> [root@desktop ~]# DBDIR=$(egrep '^@@define DBDIR ' /etc/aide.conf |awk
> '{print $NF}')
> [root@desktop ~]# echo $DBDIR
> /var/lib/aide
> [root@desktop ~]# DBFILE=$(egrep '^database=file' /etc/aide.conf |awk -F/
> '{print $NF}')
> [root@desktop ~]# echo $DBFILE
> aide.db.gz
> [root@desktop ~]# DBNEW=$(egrep '^database_out=file' /etc/aide.conf |awk
> -F/ '{print $NF}')
> [root@desktop ~]# echo $DBNEW
> aide.db.new.gz
> [root@desktop ~]# test -f ${DBDIR}/${DBNEW} && test -f ${DBDIR}/${DBFILE}
> [root@desktop ~]# echo $?
> 0
> [root@desktop ~]# /usr/sbin/aide --init >/dev/null 2>&1 && cp -p
> ${DBDIR}/${DBNEW} ${DBDIR}/${DBFILE}
> cp: overwrite ‘/var/lib/aide/aide.db.gz’? y
>
>
The most important point that I was trying to convey to you in my previous
message was that Puppet does not use a mechanism anything like that to set
up the environment for the Exec's commands. It takes the environment
strings you provide, as interpreted by Puppet at catalog-building time, and
inserts them *directly* into the environment. There will therefore be no
command substitution performed, and any variable interpolation will be of
Puppet variables, in catalog-building context, not of environment variables
in the command's runtime context.
As I said, if you need to determine the values of your environment
variables in the manner you present, then you absolutely do need to script
that, and have Puppet execute the resulting script. I also suggested that
you might write Ruby code that computes the same values, and build a custom
type and provider around that, with which to replace your Exec. Although
cleaner, that would probably require a lot more effort than it's worth.
> The cp overwrite prompt above comes from the alias cp='cp -i ' in my
> shell. I'm not sure if that would be there inside puppet, but if so I'll
> modify to negate that option.
>
> For testing, I created a separate class for just this one exec. I
> modified the unless and command statements as follows:
>
> command => 'echo "/usr/sbin/aide --init >/dev/null 2>&1 && cp -p
> ${DBDIR}/${DBNEW} ${DBDIR}/${DBFILE}"',
> unless => 'echo "test -f ${DBDIR}/${DBNEW} && test -f
> ${DBDIR}/${DBFILE}" && test -f ${DBDIR}/${DBNEW} && test -f
> ${DBDIR}/${DBFILE}',
>
> So basically the "unless" echo's what it's doing, then tries to do it.
> The "command" just echoes what it would do. Here's the puppet agent
> --test --debug output for the class:
>
> Debug: Exec[init-aide-database](provider=posix): Executing check 'echo
> "test -f ${DBDIR}/${DBNEW} && test -f ${DBDIR}/${DBFILE}" && test -f
> ${DBDIR}/${DBNEW} && test -f ${DBDIR}/${DBFILE}'
> Debug: Executing 'echo "test -f ${DBDIR}/${DBNEW} && test -f
> ${DBDIR}/${DBFILE}" && test -f ${DBDIR}/${DBNEW} && test -f
> ${DBDIR}/${DBFILE}'
> Debug: /Stage[main]/Testenv/Exec[init-aide-database]/unless: test -f $(egrep
> '^@@define DBDIR ' /etc/aide.conf|awk '{print $NF}')/$(egrep
> '^database_out=file' /etc/aide.conf|awk -F/ '{print $NF}') && test -f $(egrep
> '^@@define DBDIR ' /etc/aide.conf|awk '{print $NF}')/$(egrep
> '^database=file' /etc/aide.conf|awk -F/ '{print $NF}')
>
That last is the 'unless' command and its standard output. Look carefully
at what that's telling you: you set up the output to echo the command, and
the result will reflect all shell expansions applicable to the command. I
say again: no further substitutions or expansions will be performed on the
command or its arguments. That's the literal command that Puppet is trying
to execute for you. I'm sure that if you analyze it carefully enough
you'll be able to determine why the result is
> Debug: /Stage[main]/Testenv/Exec[init-aide-database]/unless: sh: line 0:
> test: too many arguments
>
This is a failure result, albeit not one of the ones you intended, so
Puppet proceeds to execute the main command:
> Debug: Exec[init-aide-database](provider=posix): Executing 'echo
> "/usr/sbin/aide --init >/dev/null 2>&1 && cp -p ${DBDIR}/${DBNEW}
> ${DBDIR}/${DBFILE}"'
>
At this point you should also take note of the "provider=posix". This
reflects the default Exec provider for your platform, which the agent seems
to have determined is Unix-y. It is extremely important to understand that
the 'posix' provider executes your command directly, not via a shell.
Thus, redirections, variable expansions, and other shell constructs in the
command are not recognized as anything special. Since this seems not to be
what you want, you can instruct Puppet to execute the command via a shell
by adding the parameter provider => 'shell' to your Exec declaration.
> Debug: Executing 'echo "/usr/sbin/aide --init >/dev/null 2>&1 && cp -p
> ${DBDIR}/${DBNEW} ${DBDIR}/${DBFILE}"'
> Notice: /Stage[main]/Testenv/Exec[init-aide-database]/returns: /usr/sbin/aide
> --init >/dev/null 2>&1 && cp -p $(egrep '^@@define DBDIR ' /etc/aide.conf|awk
> '{print $NF}')/$(egrep '^database_out=file' /etc/aide.conf|awk -F/ '{print
> $NF}') $(egrep '^@@define DBDIR ' /etc/aide.conf|awk '{print $NF}')/$(egrep
> '^database=file' /etc/aide.conf|awk -F/ '{print $NF}')
> Notice: /Stage[main]/Testenv/Exec[init-aide-database]/returns: executed
> successfully
>
And this shows the result: your Exec was executed successfully, producing
the given output. Since it was just an 'echo' command, it is unsurprising
that this did not have the desired effect on your system's state.
> Debug: /Stage[main]/Testenv/Exec[init-aide-database]: The container Class[
> Testenv] will propagate my refresh event
> Debug: Class[Testenv]: The container Stage[main] will propagate my
> refresh event
>
> So it looks like the strings inside the environment variables aren't
> interpreted by the shell, they're just passed as literal strings.
>
Well yes, that's exactly what I said before.
> But notably, the the unless test fails with an error from /usr/bin/test
> that doesn't surface when running interactively.
>
For exactly the reason you just gave.
> I will attempt to run in the shell provider instead of posix,
>
As I said, your approach to setting up the environment will not work as you
want. Using the 'shell' provider likely will solve some of your problems,
but not that one.
> but if that fails, I just re-code everything into shell scripts and have
> puppet push and execute them. If we need to make this a bug,
>
I don't see any buggy behavior. Puppet seems to be behaving exactly as I
would expect, with the only potentially surprising thing being that even
the 'posix' provider runs the 'unless' and 'onlyif' commands via the
shell. I do not account that a bug, however, as (1) it's probably more
useful behavior, and (2) it's consistent with the example in the docs.
John
--
You received this message because you are subscribed to the Google Groups
"Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/puppet-users/c06b7ff7-8836-47c2-accf-dc9f1a4218e5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.