Include file conditionally based on a bash script - bash

I have a bash command that will return either 1 or 0. I want to run said command from puppet:
exec { 'Check if Thinkpad':
command => 'sudo dmidecode | grep -q ThinkPad && echo 1 || echo 0',
path => '/usr/bin/:/bin/bash/',
environment => "HOME=/root"
}
Is there a way I can include a file using puppet only if my command returned 1?
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}

You can use an external fact to use the bash script as is. Inside the module's facts.d directory, you could place the script.
#!/bin/bash
if [ dmidecode | grep -q ThinkPad ]
echo 'is_thinkpad=true'
else
echo 'is_thinkpad=false'
fi
You can also use a custom fact inside the lib/facter directory of your module.
Facter.add(:is_thinkpad) do
confine kernel: linux
setcode do
`dmidecode | grep -q ThinkPad && echo true || echo false`
end
end
In both cases, the fact name of is_thinkpad follows the convention for the nomenclature of boolean facts for types of systems. You can then update the code in your manifest for this boolean.
if $facts['is_thinkpad'] == true {
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}
}
This will provide you with the functionality you desire.
https://docs.puppet.com/facter/3.6/custom_facts.html#adding-custom-facts-to-facter
https://docs.puppet.com/facter/3.6/custom_facts.html#external-facts

You will probably need to turn your bash script into a "custom fact" -- which is something I've only done once and don't fully understand enough to teach you how.
I want to say that the easiest way to set up a custom fact is to put your script into /etc/facter/facts.d/ on the agent machine, and make sure it ends with a line that says
echo "thinkpadcheck=1"
or
echo "thinkpadcheck=0"
You can test it with (note: you must be root)
sudo facter -p | grep think
and it should return
thinkpadcheck => 1
But once you have done that, then your puppet script can say
if $thinkpadcheck == 1
{
file { '/etc/i3/config':
source => 'puppet:///modules/i3/thinkpad',
owner => 'root',
group => 'root',
mode => '0644',
}
}
else
{
notify { "thinkpadcheck failed for $hostname" : }
}

I'd like to share another method I found in the Puppet Cookbook 3rd edition (page 118):
message.rb
#!/usr/bin/env ruby
puts "This runs on the master if you are centralized"
Make your script executable with:
sudo chmod +x /usr/local/bin/message.rb
message.pp
$message = generate('/usr/local/bin/message.rb')
notify { $message: }
Then run:
puppet apply message.pp
This example uses a ruby script but any type of script including a basic shell script, as was needed in my case, can be used to set a variable in puppet.

Related

Logstash 6.5.4 executing bash script in filter ruby plugin

I am attempting to execute a bash script using Logstash using filter ruby plugin.
My bash code:
#!/bin/bash
name=$1 log_file="/tmp/test.json"
if [[ -n "$name" ]]; then
echo "$1=$( date +%s )" >> ${log_file} else
echo "argument error" fi
My Logstash config:
input {
file{
path => "/var/log/nginx/access.log"
start_position => "beginning"
codec => "json"
type => "json"
sincedb_write_interval => "1"
discover_interval => "1"
}
}
filter {
if [host] {
ruby { code => '
require "open3"
host = event.get("host")
cmd = "/bin/bash /etc/logstash/conf.d/bash_scripts/execute.sh #{host}"
stdin, stdout, stderr = Open3.popen3(cmd) '
}
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "bash_execute"
}
}
No errors, the events from the file just go and the bash script does not get triggered. I do not really care about any event confirmation or something like that, just want to execute arbitrary bash script that can accept an external argument from the Logstash event.
Can anyone assist?

MAC OS X Terminal force print f to ignore some variables

i am experiencing a Problem with the printf function on MAC OS X terminal.
I already declared a variable and when i call it, it works. The problem is the following:
On the text i have some variables that start with "$" but belong to another system. I just want them to be printed on the file i am creating exactly this way ($foo) without bash trying to read them as its own variables. The result i get is an empty string.
I have the following code (dummy code):
echo "Type the wished folder name followed by [ENTER]:"
read baseName
echo '' > ext_emconf.php
printf " $VARIABLE[$ANOTHERVARIABLE] = [
'title' => '%s - Templates'
];
" $basename> ext_emconf.php
The result i get is this after the user gave for example "Amazon":
[] = [
'title' => 'Amazon - Templates'
];
Although i was expecting:
$VARIABLE[$ANOTHERVARIABLE] = [
'title' => 'Amazon - Templates'
];
Thanks in advance
It is double-quotes in bash tries to expand them as variables, but it has no definition for it. Use single quotes or better use here strings to print nice multi line formatted strings. Here is a sample way to do with some variables.
foo=bar
bar=foo
basename=foobar
tee ext_emconf.php <<EOF
$foo[$bar] = [
'title' => '$basename- Templates'
];
EOF
The above example uses tee to write both to stdout and to the file mentioned. Also you can also just redirect stdout to /dev/null if you don't want it to be seen in console.
tee ext_emconf.php <<EOF > /dev/null
$foo[$bar] = [
'title' => '$basename- Templates'
];
EOF

Puppet: Exec from class when Exec from another class is successful

I want to call an Exec only when another Exec from a different class is executed successfully.
class mysql {
exec { 'load-sql':
command => 'mysql -uadmi -pxxx general < /vagrant/sites/ddbb/general.sql',
path => ['/bin', '/usr/bin'],
timeout => 0,
onlyif => "test -f /vagrant/sites/ddbb/general.sql",
}
exec { 'delete-general-sql':
command => 'sudo rm /vagrant/sites/ddbb/general.sql',
path => ['/bin', '/usr/bin'],
onlyif => "test -f /vagrant/sites/ddbb/general.sql",
require => Exec['load-sql'],
}
}
class sphinx {
exec { 'sphinx-create-all-index':
command => 'sudo indexer -c /etc/sphinxsearch/sphinx.conf --all --rotate',
require => Exec['load-sql'],
path => '/usr/bin/';
}
}
The command 'delete-general-sql' is executed only if 'load-sql' is executed successfully but 'sphinx-create-all-index'ignores the result of 'load-sql'...
Thanks in advance!
You mess up with require and onlyif.
Read about puppet ordering.
require
Causes a resource to be applied after the target resource.
so
require => Exec['load-sql'],
means, execute resource after execution of exec{'load-sql':} resource.
On the other hand onlyif in exec means:
If this parameter is set, then this exec will only run if the command has an exit code of 0.
So you must add onlyif with proper test (probably onlyif => "test -f /vagrant/sites/ddbb/general.sql) to 'sphinx-create-all-index'.
To make the dependent exec run only once the previous one did run, you can use subscribe and refreshonly.
exec { 'sphinx-create-all-index':
command => 'sudo indexer -c /etc/sphinxsearch/sphinx.conf --all --rotate',
subscribe => Exec['load-sql'],
refreshonly => true,
path => '/usr/bin/';
}
This has some caveats - you may have a hard time to get Puppet to execute this task again if something goes wrong the first time around.

exec command unless directory exists in puppet

How to exec a command if directory does not exists in puppet file?
exec { "my_exec_task":
command => "tar zxf /home/user/tmp/test.tar.gz",
unless => "test -d /home/user/tmp/new_directory",
path => "/usr/local/bin/:/bin/",
}
I get error: "Could not evaluate: Could not find command 'test'". Also is this the best practice to check if directory does not exists?
test work for me at /usr/bin, so adding it to path could solve error.
unless => 'bash -c "test -d /home/user/tmp/new_directory"',
Should work too. But I think the correct way is to use creates:
exec { "my_exec_task":
command => "tar zxf /home/user/tmp/test.tar.gz",
creates => "/home/user/tmp/new_directory",
path => "/usr/local/bin/:/bin/",
}
Actual problem is in path:
path => [ '/usr/local/bin', '/sbin', '/bin', '/usr/sbin', '/usr/bin' ]

Set Environment Variables with Puppet

I am using vagrant with puppet to set up virtual machines for development environments. I would like to simply set a few environment variables in the .pp file. Using virtual box and a vagrant base box for Ubuntu 64 bit.
I have this currently.
$bar = 'bar'
class foobar {
exec { 'foobar':
command => "export Foo=${bar}",
}
}
but when provisioning I get an error: Could not find command 'export'.
This seems like it should be simple enough am I missing some sort of require or path for the exec type? I noticed in the documentation there is an environment option to set up environment variables, should I be using that?
If you only need the variables available in the puppet run, whats wrong with :
Exec { environment => [ "foo=$bar" ] }
?
Simplest way to acomplish this is to put your env vars in /etc/environment, this ensures they are available to everything (or pretty much everything).
Something like this:
class example($somevar) {
file { "/etc/environment":
content => inline_template("SOMEVAR=${somevar}")
}
}
Reason for having the class parameterised is so you can target it from hiera with automatic variable lookup (http://docs.puppetlabs.com/hiera/1/puppet.html#automatic-parameter-lookup) ... if you're sticking something in /etc/environment, it's usually best if you actually make it environment specific.
note: I've only tested this on ubuntu
The way I got around it is to also use /etc/profile.d:
$bar = 'bar'
file { "/etc/profile.d/my_test.sh":
content => "export Foo=${bar}",
mode => 755
}
This ensures that everytime you login (ex ssh), the variable $MYVAR gets exported to your environment. After you apply through puppet and login (ex ssh localhost), echo $Foo would return bar
You can set an environment variable by defining it on a line in /etc/environment and you can ensure a line inside a file using file_line in puppet. Combine these two into the following solution:
file_line { "foo_env_var":
ensure => present,
line => "Foo=${bar}",
path => "/etc/environment",
}
You could try the following, which sets the environment variable for this exec:
class foobar {
exec { 'foobar' :
command => "/bin/bash -c \"export Foo=${bar}\"",
}
}
Something like this would work while preserving existing contents of the /etc/environment file:
/code/environments/{environment}/manifests/environment/variable.pp:
define profile::environment::variable (
$variable_name,
$value,
$ensure => present,
) {
file_line { $variable_name:
path => '/etc/environment',
ensure => $ensure,
line => "$variable_name=$value",
match => "$variable_name=",
}
}
Usage (in the body of a node manifest):
profile::environment::variable { 'JAVA_HOME':
variable_name => 'JAVA_HOME',
value => '/usr/lib/jvm/java-1.8.0',
}
I know this is an old question, but I was able to set the PS1 prompt value and add it to my .bashrc file like this:
$PS1 = '\[\e[0;31m\]\u\[\e[m\] \[\e[1;34m\]\w\[\e[m\] \$ '
and within a class:
exec {"vagrant-prompt":
unless => "grep -F 'export PS1=\"${PS1}\"' ${HOME_DIR}/.bashrc",
command => "echo 'export PS1=\"${PS1}\"' >> ${HOME_DIR}/.bashrc",
user => "${APP_USER}",
}
The -F makes grep it interpret it as a fixed string. Otherwise it won't find it and keeps adding to the .bashrc file.
Another variation. This has the advantage that stdlib isn't required (as is with file_line solutions), and the existing content of /etc/environment is preserved:
exec {'echo foo=bar>>/etc/environment':
onlyif => 'test -f /etc/environment',
unless => 'grep "foo=bar" /etc/environment',
path => '/usr/bin',
}
Check out the documentation https://puppet.com/docs/puppet/5.5/types/exec.html
class envcheck {
file { '/tmp/test':
ensure => file,
}
exec { 'foobar':
command => 'echo $bar >> /tmp/test',
environment => ['bar=foo'],
path => ['/bin/'],
}
}
Creating an empty file because an echo would happen in the shell Puppet is running the command in, not the one we're looking at.
Setting an environment variable bar to equal foo.
Setting the path for the echo binary, this isn't normally necessary for system commands but useful to know about.

Resources