dropdown menu

Resources

When we write puppet code in a manifest file, we want to modify resources on the server. A resource can be anything which is possible to configure on a system, like a user account, a specific file, a directory, a running service, a software package etc. These resources (for example all the users on a server) can be grouped to a resource type, in this case it is called "user".

From this resource type we can create or modify a specific resource( like a user called 'dave'), which has a number of attributes (uid, gid ...). Each attribute has a specific value. 

An example for a resource declaration:
user { 'dave':
  ensure => present,
  uid    => '507',
  gid    => 'admin',
  shell  => '/bin/zsh',
  home   => '/home/dave',
  managehome => true,
}

Some resource related puppet commands:
puppet describe -l                     list all of the resource types available on the system
puppet describe -s <TYPE>              print short information about a type

puppet resource user root              lists the given resource and attributes
puppet resource user katie ensure=present shell="/bin/bash"   setting a new desired state for a resource
puppet resource user katie --edit       change a resource in text editor, after it is saved Puppet will modify that resource

Almost every resource type has one attribute whose value defaults to the resourceʼs title.  For example for the file resource the path attribute is not really needed as it is the default as the title.  Most of the time (user, group, package…), itʼs name.

=========================================

Resource Capitalization:

After creating a resource we can refer to that resource using the name  with capital letter. For example if we create a file resource we can refer to that resource using the name File[ ...]:
file { "sshdconfig":
 path => "/etc/ssh/sshd_config",
 ...
}

service { 'sshd': 
   require => File['sshdconfig', 'sshconfig', 'authorized_keys']
}   

We can now refer to this resource as File["sshdconfig"] as an aliased shorthand Same applies to other resource types, like package. If we create a package named httpd, if we wanted to refer to this package later, we would capitalize its type (package): Package['httpd']

You only use the lowercase type name when defining a new resource. Any other situation will always call for a capitalized type name.

=========================================

User resource:

user { 'vipin':                <--resource type is "user" and the resource title is "vipin" (the title of a resource can be referred to in other parts of puppet code)
   ensure => present,          <--attibutes are ensure, uid, shell, home and each has a value
   uid    => '552', 
   shell  => '/bin/bash', 
   home   => '/home/vipin', 
}

One needs to keep in mind while declaring a resource, that it can be declared only once per config file. Repeating declaration of the same resource more than once will cause an error.

======================================

File resource:

The file resource manipulates files (also the content of files) and can manipulate directories as well.

file { "resolv.conf":
    ensure => present,
    path   => "/etc/resolv.conf",
    owner  => 'root',
    group  => 'system',
    mode   => 0644,
    source => 'puppet:///modules/base_aix_image/resolv.conf',
}

file { "/tmp/testfile":         <--if the file resource name contains the full path, then the path attribute is not needed
  ensure  => "present",
  owner   => "bb",
  group   => "bb",
  mode    => "0777",
  content => "Hello World\n",
}

Source parameter:
It is possible to download files from puppet master using the Puppet file server function. It is very useful when creating modules, so the configuration files, scripts which belongs to the module, can be organized nicely, and later we can use them in the file resource. (The directory structure of a module is described in detail in the Modules section.)

The Puppet file server is built into the Puppet master and in manifest files using the "source" parameter we can download, sync files which are stored remotely (on puppet master). 

source => "puppet://$::server/modules/sudo/etc/sudoers",
source => "puppet:///modules/sudo/etc/sudoers"

Both lines are doing the same. The $::server variable contains the hostname of our Puppet server. If the server name is not specified, then Puppet will use whatever server the client is currently connected to:


The first portion of this share is modules, which tells us that the file is stored in a module. Next we specify the name of the module the file is contained in, in this case ntp. Finally, we specify the path inside that module to find the file. All files in modules are stored under the files directory, so this is not mentioned in the path, only the file name. If there are any extra subdirectories, they work like youʼd expect, so you could have something like puppet:///modules/ntp/config_files/linux/ntp.conf.el.

======================================

Directories, Links:

We want to create a file and also want to make sure the directory exist:
file {'/tmp/test_dir':
  ensure => directory,
  mode => 0644,
}

file {'/tmp/test_file':
  ensure => file,
  content => "Hi.",
  require => File['/tmp/test_dir'],
}

file {'/tmp/test_link':
ensure => link,
target => '/tmp/test_file',
}

ensure => file     implies ensure => present, the resource should be a file, if not a file or does not exist, it will create a file.
ensure => present  just means that the resource should be a file, directory, or link; if it does not exist, it will create a file.

=========================================

Service resource

Service resources are used to make sure services are initialized and enabled. They are also used for service restart.

service { 'tomcat': 
   ensure => running, 
   enable => true 
}

===========================================

Package resource:

It makes sure the given packages is installed:

package { "telnet":
  ensure   => "installed",
}

If needed we can specify what is the type of the package (yum, rpm...), using the provider attribute:
 provider => yum

Remote package install:
Create a file let’s say telegraf.pp, to install an rpm from a remote source.

class remoterpm ( $src ) {

  package { 'package':
    provider         => 'rpm',
    ensure      => installed,
    source => "${remoterpm::src}"
  }
}

class { 'remoterpm':
  src => 'http://rpm.example.io/telegraf-1.4.3-1.x86_64.rpm',
}

You can then apply this class with:
puppet apply --debug --no-daemonize telegraf.pp


===========================================
===========================================
===========================================
===========================================
===========================================


Resource relationships

Between resources there are many times a sort of dependency. For example if we start a service, we need to be sure that the necessary package is already installed on the system for that specific service. To achieve this there are specific keywords (like require, before...).

For example, when we start the http service, we make sure the package is already installed:
package {'httpd':                              
  ensure => 'installed',
}

service {'httpd':
  ensure => running,
  require => Package['httpd'],   <--requires that package is installed (we refer to an already defined resource with capital letter ("P"))
}

These special keywords (like require) are called metaparameters, because they donʼt describe any feature of the resource, they only describe how Puppet should act.
These are the metaparameters which can be used on any resources: before, require, notify, subscribe

===========================

Before, Require:

Before and require make simple dependency relationships, where one resource must be synced before another. Before is used in the earlier resource, and lists resources that depend on it;
require is used in the later resource, and lists the resources that it depends on. 

before  <--a resource applied before the target resource. (it is used in the earlier resource and lists resources that depend on it)
require <--a resource applied after the target resource. (it is used in the later resource, and lists the resources that it depends on.)

In the above httpd example we used require, but it is possible to rewrite it using before, and to achieve the same end result: 
package {'httpd':                              
  ensure => 'installed',
  before => Service ['httpd']
}

service {'httpd':
  ensure => running,
}

===========================

Notify, Subscribe

The notify and subscribe metaparameters make dependency relationships the way before and require do, but they also make notification relationships. Not only will the earlier resource in the pair get synced first, but if Puppet makes any changes to that resource, it will send a refresh event to the later resource, which will react accordingly.

notify    <--a resource to be applied before the target resource. The target resource will refresh if the notifying resource changes.
subscribe <--a resource to be applied after the target resource. The subscribing resource will refresh if the target resource changes.

In this example, the sshd service will be restarted if Puppet has to edit its config file:
file { '/etc/ssh/sshd_config':
  ensure => file,
  mode => 600,
  source => 'puppet:///modules/ssh/sshd_config',
}

service { 'sshd':
  ensure => running,
  enable => true,
  subscribe => File['/etc/ssh/sshd_config'],
}

===========================

Package, file and service dependency:

Usually these 3 are dependent on each other, as files require package, service requires files and package:


 service {'httpd':                         <--define  a service and ensure it is running
   ensure => running,
   require => Package['httpd'],            <--the service requires the httpd package
 }

 package {'httpd':                         <--define the package 
   ensure => installed,
 }

 file {'/etc/httpd/virt.conf':             <--creating a conf file
   content => "<VirtualHost *:80>",
   require => Package['httpd'],            <--this file will be created after the httpd package is installed
   notify => Service['httpd'],             <--after conf file is created httpd service is restarted
 }

===========================

Chaining arrow

Similar relationships can be used, by  the characters -> and ~>
(it will show visually how things should happen in time.)

You can embed relationship information in a resource with the before, require, notify, and subscribe metaparameters.
You can also declare relationships outside a resource with the -> and ~> chaining arrow

-> (ordering arrow)          <-- Causes the resource on the left to be applied before the resource on the right.
~> (notification arrow)      <--Causes the resource on the left to be applied first, and sends a refresh event to the resource on the right if the left resource changes. 

An operand can be shared between two chaining statements, which allows you to link them together into a “timeline:”
Package['ntp'] -> File['/etc/ntp.conf'] ~> Service['ntpd']


2 ways of using these, both are doing the same:

file {'/tmp/test1':
  ensure => present,
  content => "Hi.",
}

notify {'after':
  message => '/tmp/test1 has already been synced.',
}

File['/tmp/test1'] -> Notify['after']

----------------

file {'/tmp/test1':
  ensure => present,
  content => "Hi.",
} ->
notify {'after':
  message => '/tmp/test1 has already been synced.',
}

===========================

Class relationships

The above mentioned metaparameters and chaining arrows are working with classes too.

For example the require function acts like include (so no include is needed for that specific class), but also causes the class to become a dependency of the surrounding container. Puppet will ensure that  foo is realized before bar, but doesn’t care if other resources are realized in between.

class bar {
  require foo
  notify { 'bar': }
}

class foo {
  notify { 'foo': }
}

include bar

-----------------------------------

chaining arrow:

class bar {
  notify { 'bar': }
}

class foo {
  notify { 'foo': }
}

class end {
  notify { 'end': }
}

class wrapper {
  class { 'foo': } ->
  class { 'bar': } ->
  class { 'end': }
}

include wrapper

}

===========================

No comments: