Notify - puppet debugging
The notify
statement can be used in module definitions to print & log useful debugging information.
For instance, if large trees of logic are being traversed, insertion of a notify statement will allow you to determine whether the class is being declared or not.
notify { 'Puppet is now activating Class "blah"': }
or
notify { 'another':
{ 'This is another message'
}
Metaparameters
Parameters which work with any resource tupe
- Schedule
- This will prevent puppet from being run outside of the defined window. Similar to operation windows in CommVault.
- alias
- Create an alias name for a resource
- noop
- Exclude just a single resource from being enforced (whilst the rest of the resources will be enforced)
- loglevel
- Set log level to standard syslog levels
- tag
- Custom tags for resources - useful for reporting
File Resources
ensure => file, directory, or symlink,
mode => 755,
owner => 'robbie',
group => 'admins',
Some others include
- Content
- a string which will become the contents of the file
- Source
- will retrieve a file from a remote source (if the local doesn't exist or if the contents are different)
Dependencies
service {'nginx':
require => Package['nginx'],
ensure => 'running',
enable => 'true',
}
would specify that the nginx package needs to be installed before the service can be started.
Note - all resources need to be explicitly defined in Puppet. If for instance a user "root" was required, this would not be valid unless a "root" user resource was also declared (regardless of the fact that the root user exists in /etc/passwd).
Auto restart service
service {'nginx':
subscribe => File['file'],
require => Package['nginx'],
ensure => 'running',
enable => 'true',
}
Will restart the service if there is a change in the speficied file (e.g. the config file). i.e. if Puppet detects that your local copy is not correct and it needs to change that file, it will then restart the service.
subscribe => ['/dir/files1', '/dir1/file2', 'dir2/file1'],
Would watch all three of these files and restart the service if any of these are changed by puppet.
Strings & Variables
- Variables are immutable
- Variables must be unique within the scope
- Variables declared within class apply within the scope
- Node scope applies to node
- Top scope is global
- Single quotes pass literal strings to the var (i.e. ${http_dir wouldn't be evaluated)
$var1 = "my value is ${http_dir} on this system"
Defaults
Default resource attributes can be configured using a capital letter at the beginning, with no title. e.g.
File {
owner => 'root',
}
Would mean that any file resources defined later would automatically adopt this owner, unless the later resource defines a different attribute value.
file('test.sh':
name => '/tmp/test.sh',
}
would adopt the default above, whereas the below
file('test.sh':
name => '/tmp/test.sh',
owner => 'ted'
}
would override the default and set the owner to "ted"
Case Statements
If you're using lots of logic (perhaps more than two options), case might be a better approach
case $::operatingsystem {
'redhat', 'centos': { include redhat } # This applies the redhat class
'debian', 'ubuntu': { include debian } # This applies the debian class
'windows': { include windows } # This applies the windows class
'amazon': {
include amazon # This applies the amazon class
include redhat # This also applies the redhat class
}
default: { fail("Operating System ${::operatingsystem} not supported") }
}
or (demonstrating different package names and configs to use). Note - kernel variable has come from facter (check facter
output for examples of what can be used
case $::osfamily {
'redhat' : {
$package_name = 'redhat'
$nginx_package_name = 'nginx'
}
'debian' : {
$package_name = 'debian'
$nginx_package_name = 'nginx'
}
'windows' : {
$package_name = 'windows'
$nginx_package_name = 'nginx-service'
}
default : {
fail( "Unsupported osfamily ${::osfamily}")
}
}
package {'nginx':
ensure => present,
name => $nginx_package_name
}
file {'/var/www':
ensure => directory,
name => '/var/www',
}
file {'index.html':
ensure => file,
name => '/var/www/index.html',
source => 'puppet:///modules/nginx/index.html',
}
file {'default.conf':
ensure => present,
name => '/etc/nginx/conf.d/default.conf',
source => "puppet:///modules/nginx/default-${::kernel}.conf",
require => Package['nginx']
}
file {'nginx.conf':
ensure => present,
name => '/etc/nginx/nginx.conf',
source => "puppet:///modules/nginx/${package_name}.conf",
require => Package['nginx']
}
if / elsif / else Statements
Pretty standard flow, just new syntax to get used to
if $server != 'fileserver01' and $role != 'filesharing' {
file {'/etc/smb.conf': ensure => absent}
}
else {
file {'/etc/smb.conf': ensure => present}
}
Kinda simplistic example, but it demonstrates the basic if/else workflow.
Operators
- boolean
- and, or, not
- Comparison
- ==, !=, =~, <, >, <=, >=
- Arithmetic
- +, -, *, /, >>, <<
- Membership
- in
Precedence is
- ! (not)
- *, / (divide)
- -, - (plus and minus)
- <<, >> (left shift and right shift)
- ==, !=, =~ (Equal, Not equal, Regex equal)
-
=, <=, <, > (greater than equal, less than equal, greater than, less than)
- and
- or
Parentheses can be used to manually override/set precedence
Embedded Ruby (ERB) Templates
- Templates are generally text files
- Using ERB tags allows you to
- display and act on interpreted variable values
- Modify the flow of logic
- Execute ruby code for calculations or iterations
- Templates reside in the {module}/templates directory
Example
root@robbie:~/puppetcode/modules # cat nginx/templates/index.html.erb
<HEAD>
<TITLE> Test Web Page for <%= @kernel %> platform</TITLE>
</HEAD>
<BODY>
This is a test web page for the <%= @kernel %> Platform
Added some additional content
</BODY>
root@robbie:~/puppetcode/modules # cat ./nginx/manifests/init.pp
file {'index.html':
ensure => file,
name => '/var/www/index.html',
content => template('nginx/index.html.erb'),
}
Classes vs Defined Resource Types
Classes can have 1 instance
DRTs can have infinite (i.e. many) instances
define nginx::vhost () {
notify { "this is generating the vhost ${title}" }
# ... additional code here
}
nginx::vhost { "www.puppettest.com":
ensure => present
}
Simple Example - nginx
project dir: /home/robbie/puppetcode/
git dir: /home/robbie/puppetcode/.git
- modules (i.e. an nginx module, a users module, etc) reside in a subdir in here
- this example looks specifically at the nginx module
- The permissions are wrapped up in the "File" resource default, rather than repeating them in every file declaration.
- Note the capital "F".
Below is some sample code.
root@robbie:~/puppetcode # cat ./modules/nginx/manifests/init.pp
class nginx {
notify {'begin':
message => 'Commencing installation of nginx',
}
package {'nginx':
ensure => present,
}
File {
owner => 'root',
group => 'root',
mode => '644',
}
file {'/var/www':
ensure => directory,
name => '/var/www',
}
file {'index.html':
ensure => file,
name => '/var/www/index.html',
source => 'puppet:///modules/nginx/index.html',
}
file {'default.conf':
ensure => present,
name => '/etc/nginx/conf.d/default.conf',
source => 'puppet:///modules/nginx/default.conf',
}
service {'nginx':
require => Package['nginx'],
subscribe => File['index.html', 'default.conf'],
ensure => running,
enable => 'true',
}
}
[master]root@robbie:~/puppetcode # cat ./modules/nginx/examples/init.pp
include nginx
[master]root@robbie:~/puppetcode # ll ./modules/nginx/files/
total 12
-rw-r--r-- 1 root root 1277 Aug 26 02:00 default.conf
-rw-r--r-- 1 root root 161 Aug 26 02:00 index.html
-rw-r--r-- 1 root root 1059 Aug 26 02:00 nginx.conf
[master]root@robbie:~/puppetcode #