Featured Post

Directory environments in Puppet

Environments are individual groups of Puppet agents each environment have there own completely different manifests and module-paths. This basically is useful for testing changes to our Puppet code before implementing them on production machines. There are two types of implementation of environments structure in Puppet one if directory based and another is config file based here we will see bit of an insight about directory based. As usual for more information about this you can visit puppetlabs official website. On the master node: Append following details in puppet.conf which is placed under /etc/puppet or /etc/puppetlabs/puppet:     Under [main] section add a variable called confdir with value as /etc/puppet or /etc/puppetlabs/puppet     confdir=/etc/puppet Then add information regarding environments/manifests and modulepath in it.      #environments     environmentpath = $confdir/environments     default_manfiest = $confdir/manifests     basemodulepath =

Exec in Puppet

Exec is a very useful resource type present in Puppet which is used to executes external commands.

Puppet basically runs as a daemon in which it executes every 30 mins. So while writing an exec resource type make sure that the exec resource must be able to run multiple times without causing any harm to the machine i.e. it must be idempotent.

Suppose you just want to run a command like reload a service for that what you can do is?

exec { "reload httpd":
command => "service httpd reload",
path => "/usr/local/bin/:/bin/:/sbin/",
}

Lets break this line by line:
  • exec { "reload httpd":
    • This specifies that the resource type is exec type and has a human readable name as "reload httpd".
  • command => "service httpd reload",
    • This specified which command to execute when puppet is executed.
  • path => "/usr/local/bin/:/bin/:/sbin/",
    • This specifies where the binary service can be found in your machine. In this case we have specified all three locations where all the necessary binaries are kept.
    • Either you can use this path attribute in this or while specifying the command you can give its absolute path i.e. command => "/sbin/service httpd reload",
    • You can use one more alternative for this as path => [ "/usr/local/bin/", "/bin/", "/sbin/" ], to make your code look nicer.
Lets run this code:

[root@puppet manifests]# puppet apply site.pp
notice: /Stage[main]//Exec[reload httpd]/returns: executed successfully
notice: Finished catalog run in 0.08 seconds
[root@puppet manifests]#

It states that "reload httpd" exec resource type was executed successfully.

One thing which should be kept in mind is that to use a human readable names [because exec can run this "exec { "/sbin/service httpd reload":" too just a single line of code will reload httpd] while declaring exec names like here we did "reload httpd" it clearly states that below code will reload httpd, so that it is helpful for the naive users or a new person who joins your team in getting them understand what this exec resource will actually do.

Another example you want to add a user "optimus" via exec resource and add that user to "transformers" group. In this case I have written two exec resources one to create a group [prerequisites as without transformers group a user optimus cannot be added].

exec { "Add user optimus":
        command => "useradd optimus -g transformers",
        path => "/usr/local/bin/:/bin/:/sbin/:/usr/sbin/",
        require => Exec ["Add group transformers"],
}
exec { "Add group transformers":
        command => "groupadd transformers",
        path => "/usr/local/bin/:/bin/:/sbin/:/usr/sbin/",
}

Here you can see that we have used path attribute in both the exec resources separately to save our bit of a code we can get this defined globally and can use this as: 

Exec { path => [ "/usr/local/bin/", "/bin/" , "/sbin/", "/usr/sbin/" ] }
exec { "Add user optimus":
        command => "useradd optimus -g transformers",
        require => Exec ["Add group transformers"],
}
exec { "Add group transformers":
        command => "groupadd transformers",
}

Lets apply site.pp:
[root@puppet manifests]# puppet apply site.pp
notice: /Stage[main]//Exec[Add group transformers]/returns: executed successfully
notice: /Stage[main]//Exec[Add user optimus]/returns: executed successfully
notice: Finished catalog run in 0.36 seconds
[root@puppet manifests]# 

But if you try to run above command again it will throw errors as both the user and group are already added to the machine.
[root@puppet manifests]# puppet apply site.pp
err: /Stage[main]//Exec[Add group transformers]/returns: change from notrun to 0 failed: groupadd transformers returned 9 instead of one of [0] at /etc/puppet/manifests/nodes.pp:10
notice: /Stage[main]//Exec[Add user optimus]: Dependency Exec[Add group transformers] has failures: true
warning: /Stage[main]//Exec[Add user optimus]: Skipping because of failed dependencies
notice: Finished catalog run in 0.09 seconds
[root@puppet manifests]#

Remember Puppet basically runs as a daemon in which it executes every 30 mins, so the code should be idempotent.

For getting above error resolved we can use onlyif or unless attribute.

unless => "grep -c optimus /etc/passwd", [For add user exec resource].
unless => "grep -c transformers /etc/group", [For add group exec resource].

So now our full code will be:

Exec { path => [ "/usr/local/bin/", "/bin/" , "/sbin/", "/usr/sbin/" ] }
exec { "Add user optimus":
        command => "useradd optimus -g transformers",
        unless => "grep -c optimus /etc/passwd",
        require => Exec ["Add group transformers"],
}
exec { "Add group transformers":
        command => "groupadd transformers",
        unless => "grep -c transformers /etc/group",
}

Lets run this again:
[root@puppet manifests]# puppet apply site.pp
notice: Finished catalog run in 0.16 seconds
[root@puppet manifests]#

Refer Puppetlabs online documentation for more information on this like what all attributes are there for exec and who are the providers for exec [like windows, shell etc].

Comments

Popular posts from this blog

Un-revoke the revoked certificate in Puppet

Dry run in Puppet --noop