Today I learned (while trying to create a Facter fact ) that if you need to run a one line command that requires an Environment variable set, it's not as straight forward as you would expect.
I started with the example from the Puppet Docs
Facter.add(:rubypath) do
setcode 'which ruby'
end
This gave me the following output
dawiest@old-laptop:~$ puppet apply -e 'notify{"Fact: $rubypath":} 'replaced the command with an example command to cover my case.
Notice: Compiled catalog for old-laptop in environment production in 0.10 seconds
Notice: Fact: /usr/bin/ruby
Notice: /Stage[main]/Main/Notify[Fact: /usr/bin/ruby]/message: defined 'message' as 'Fact: /usr/bin/ruby'
Notice: Finished catalog run in 0.07 seconds
Facter.add(:example_fact) doAnd here is my output, what went wrong!?
setcode 'VAR=hello; echo $VAR'
end
dawiest@old-laptop:~$ puppet apply -e 'notify{"Fact: $example":} 'I figured that the variable declaration was being lost somewhere... how about I run it in a sub-shell?
Notice: Compiled catalog for old-laptop in environment production in 0.11 seconds
Notice: Fact:
Notice: /Stage[main]/Main/Notify[Fact: ]/message: defined 'message' as 'Fact: '
Notice: Finished catalog run in 0.06 seconds
Facter.add(:example_fact) do
setcode 'sh -c "VAR=hello; echo $VAR" '
end
I ran that, and got the same output as last time! But wait! if I reverse the order of the quotes...
Facter.add(:example_fact) do
setcode "sh -c 'VAR=hello; echo $VAR' "
end
Suddenly, it works!
dawiest@old-laptop:~$ puppet apply -e 'notify{"Fact: $example":} '
Notice: Compiled catalog for old-laptop in environment production in 0.10 seconds
Notice: Fact: hello
Notice: /Stage[main]/Main/Notify[Fact: hello]/message: defined 'message' as 'Fact: hello'
Notice: Finished catalog run in 0.06 seconds
One small problem... When I ran my actual command, it didn't work! It wasn't reading my variable! Now to model this...
dawiest@old-laptop:~$ echo 'echo $VAR' > /tmp/example.sh && chmod u+x /tmp/example.sh
And here is my updated fact.
Facter.add(:example_fact) do
setcode "sh -c 'export VAR=hello; /tmp/example.sh' "
end
When I run it again, I get the following output
dawiest@old-laptop:~$ puppet apply -e 'notify{"Fact: $example":} 'So... the problem is that the variable was in scope for the echo call above, but it wasn't making it into my script..... time to export our variable!
Notice: Compiled catalog for old-laptop in environment production in 0.10 seconds
Notice: Fact:
Notice: /Stage[main]/Main/Notify[Fact: ]/message: defined 'message' as 'Fact: '
Notice: Finished catalog run in 0.06 seconds
dawiest@old-laptop:~$ puppet apply -e 'notify{"Fact: $example":} '
Notice: Compiled catalog for old-laptop in environment production in 0.10 seconds
Notice: Fact: hello
Notice: /Stage[main]/Main/Notify[Fact: hello]/message: defined 'message' as 'Fact: hello'
Notice: Finished catalog run in 0.06 seconds
That looks a lot better!
TL:DR. If you are trying to run a command inside of a fact, you need to make sure you export your variable so it passes to the scope of your script, and you probably have to wrap it in a subshell.