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

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.

Related

Include file conditionally based on a bash script

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.

Capistrano: Override shared_dir variable

First off, very new to Capistrano, so excuse my newbness.
I am deploying a CodeIgniter application of which I have a data folder that lives outside the current web directory that I am trying to symlink to. This is what I have used to create the symlink
set :shared_dir, %w(/var/www/website/)
set :linked_dirs, %w{43b621acdfc9523443f27b7767e}
This is the result of the deployed application
43b621acdfc9523443f27b7767e -> /var/www/website/shared/43b621acdfc9523443f27b7767e
My goal is to override the shared_dir variable to generate a symlink of
/var/www/website/43b621acdfc9523443f27b7767e
I am using Capistrano 3. Any insight greatly appreciated.
Thanks
You can create an specific task to take care of creating and updating the symlink from anywhere in your application to anywhere in your system on each deploy. For example:
namespace :terminal do
task :link_external_dir, :except => { :no_release => true } do
capifony_pretty_print '--> Generating soft link with external_example_dir'
run "sharedWebDir=#{shared_path}/web; cd $sharedWebDir; if [ -d $sharedWebDir/internal_example_dir -o -f $sharedWebDir/internal_example_dir ]; then rm -rf $sharedWebDir/internal_example_dir; fi; if [ ! -L $sharedWebDir/internal_example_dir ]; then ln -s /srv/example/vhost/external_example_dir $sharedWebDir/internal_example_dir; fi;"
capifony_puts_ok
end
task :rm_shared_example_dir, :except => { :no_release => true } do
capifony_pretty_print '--> Removing sharedDir/internal_example_dir symlink'
run "sharedWebDir=#{shared_path}/internal_example_dir; if [ -L $sharedWebDir/internal_example_dir ]; then rm $sharedWebDir/internal_example_dir; fi;"
capifony_puts_ok
end
end
Now call each function on each deploy:
before "deploy", "terminal:rm_shared_example_dir"
after "deploy", "deploy:cleanup"
after "deploy", "terminal:link_external_dir"
What we are trying to accomplish is:
1.Before Deploy, remove the file from your main sharedDir that links to your external dir.
REMOVE
/var/www/website/shared/externalDir -> /srv/example/vhost/external_example_dir
2.Deploy your app.
3.Generate the custom symlink again.
ln -s /srv/example/vhost/external_example_dir $sharedWebDir/internal_example_dir

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' ]

passing parameters from external file (template) to puppet script

Hi I'm trying to execute an exe file using puppet script. My exe file is accepting 3 parameters like param1, param2 and param3. All I want is to pass these parameters through external file. How can I do this?
Here is my sample code:
exec { "executing exe file":
command => 'copyfile.exe "DestinatoinPath" "sourcefilename" "destinationfilename" ',
}
All I want is to pass all these values from external file and use it here.
Can someone help me to resolve this
Here is my trail:
Here is my directory structure:
puppet\modules\mymodule\manifests\myfile.pp and
puppet\modules\mymodule\templates\params.erb
and my erb file is having a value of path ex: d:\test1.txt e:\test1.txt testfilename
$myparams = template("mymodule/params.erb")
exec { "executing exe file":
command => '$myparams',
}
EDIT:
The root of the problem was trying to call the module manifest directly, thus the template lookup failed. The solution was not to use a module and specify the full template path.
There are 2 main ways to go about it:
Declare the variables in scope
#acceptable for a throwaway manifest
$path = "DestinationPath"
$source = "sourcefilename"
$destination "destinationfilename"
exec { "executing exe file":
command => 'copyfile.exe ${path} ${source} ${destination}',
}
Wrap it in a parameterized class/defined type
# parameterized class, included only once
class executing_exe_file ($path, $source, $destination) {
exec { "executing exe file":
command => 'copyfile.exe ${path} ${source} ${destination}',
}
}
OR
# defined resource, can be repeated multiple times
define executing_exe_file ($path, $source, $destination) {
exec { "executing exe file":
command => 'copyfile.exe ${path} ${source} ${destination}',
}
}
THEN
executing_exe_file { "executing exe file":
path: "DestinationPath",
source: "sourcefilename",
destination: "destinationfilename",
}
Also as a side note, you have to make sure copyfile.exe is fully qualified.

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