Learning puppet chapter 3

Vishal Biyani
Vishal BiyaniFounder & CTO Infracloud Technologies (We are hiring!) at Infracloud technologies Ltd
LEARNING
PUPPET
- 03
SlideBook (Book on slides)
Inspired by Slidedoc -
http://www.duarte.com
-Vishal Biyani
www.vishalbiyani.com
Configuring
aa
server
with
puppet
www.vishalbiyani.comLearning Puppet
What we will learn? Here is what we are going to do in this chapter
Write a very basic manifest which will install and configure tomcat &
run the manifest and see if it actually works?
Move manifest code into a class and package into module – thus
learning how to create module and basics of module
Make class configurable so that we can pass parameters for certain
things – for example port on which tomcat will run etc.
3|
Refactor code to separate configurable parameters, make it modular
in terms of class design & organization etc.
Learn what is containment (Sounds like enlightenment isn't it? ☺)
Finally use templates and ERB templatinging language to manage
configuration files of software being installed
That seems a lot?That’s going to be super easy though!
www.vishalbiyani.comLearning Puppet
First tomcat run! Now let’s log on to agent_0 and fire command:
In our first cut we want to do a few basic things:
install tomcat, start/run it and there should be a
way to test it in browser if it is working right. For
testing part we will install the “ROOT” app which
shows tomcat home page.Where to put all this
code? In the /etc/puppet/manifests/site.pp under
one of nodes.Our site.pp looks like:
1 node 'puppet.learn.com' {
2 package {'vim-enhanced.x86_64':
3 ensure => present,
4 }
5 }
6 node '0.pagent.vb.com' {
7 package { 'tomcat6':
So that will install & bring up tomcat.To check simply hit the
ip_address:8080* (Or find out the IP address that would get assigned from
Vagrantfile, in my case it is 192.168.17.10).You should see tomcat
homepage:
4|
7 package { 'tomcat6':
8 ensure => installed,
9 }
10
11 service { 'tomcat6':
12 ensure => running,
13 }
14 package { 'tomcat6-webapps':
15 ensure => installed,
16 require => Package['tomcat6'],
17 }
18 }
19 node '1.pagent.vb.com' {
20 }
In above snippet we have added lines from 7 – 17
to get done what we want. First we are declaring
that package tomcat6 should be installed,
secondly it should be running. In last block we are
installing the “ROOT” app which is named as
tomcat-webapps and also forming a relation on
installation of tomcat.
To get IP address of agent fire command “ifconfig” – here the IP address in
block eth1 would be accessible from your machine
So we have a basic tomcat server running but there are quite a few things
that need to be taken care of for example:
•Note that our current code will only work on certain operating systems – for
example if package name on a OS anything different than tomcat6 – then it
won’t work.
•Similarly adding code this way to node definition is not scalable for sure.
We need to move the code somewhere else.
But this is a good start for our first cut; we will refine this much more in
coming pages/slides!
www.vishalbiyani.comLearning Puppet
Creating a module! Let’s understand what all goes in module we created:
Gemfile is a where you define dependencies using the dependency
management tool in Ruby: Bundler
Manifests – is where most of the code we write will go.The special file here
is init.pp – this file has class with name same as module name (tomcat).
Note that all other classes should have same name for file in which class is
defined (Best practice) except for init.pp.
Metadata.json stores basic information about your module which you filled
in while generating module.
Rakefile is like a make file in C – which defined tasks for your codebase. And
you know what a README.md is for isn’t it?
Spec directory
Tests is where tests for our module live!
For this chapter we are only going to touch files in manifests directory!
Let’s get our house in order!We put bunch of lines
in node definition to getTomcat up and running
but we want to distribute our tomcat magic code
to others so that they can do the same. Let’s
wrap all of code in a module. For that let’s first
create a barebones module, on master node
navigate to /etc/puppet/modules and fire:
1 sudo puppet module generate learn-tomcat
sudo mv learn-tomcat tomcat
The name we gave is a combination of username
(learn) and module name (tomcat) which is
separated by dash and is the convention followed
5|
For this chapter we are only going to touch files in manifests directory!
If you look at the init.pp in manifests, you will see:
So let’s move the code we had defined inside node definition in this class.
That makes our module functional. If someone has to install tomcat, all one
has to do is in node definition (Try on your setup!):
The effect is same as previous slide.Our first ever module for tomcat is
ready.Our class still does not follow the best coding practices & design
patterns but we will fix that soon too!
* The name of module vs. the combo name of username-modulename is
a known bug and will be fixed in Puppet 4.0 I stumbled on this during
exercise so I added that command. Check
https://tickets.puppetlabs.com/browse/PUP-3124
separated by dash and is the convention followed
by puppet.You will be asked with bunch of
questions and you can fill them or leave blank!
And we need to rename the module name to
tomcat as the username-module name combo
needs to be only in metadata file*. And puppet
generates a basic structure of a module for us!
tomcat/
|── Gemfile
|── manifests
| |── init.pp
|── metadata.json
|── Rakefile
|── README.md
|── spec
| |── classes
| | └── init_spec.rb
| |── spec_helper.rb
|── tests
|── init.pp
1 class tomcat {
2 }
1 node '0.pagent.vb.com' {
2 include tomcat
3 }
www.vishalbiyani.comLearning Puppet
Making things parameterized!
Parameterization – first thing we want to do is
make some of hardcoded values to be passed as
parameters so that end user can customize the
module as per need. For this first of all we create
a class params.pp in manifests directory, that
way parameters will be managed in a different
class and can be referred from all over the
module. Also note that we have default values for
all parameters so even if end user does not
provide them when calling tomcat module, our
code won’t break!
1 class tomcat::params {
2 $package_name = 'tomcat6'
3 $package_ensure = 'installed'
4 $service_manage = true
5 $service_name = 'tomcat6'
6 $service_ensure = 'running'
7 $service_port = '8080'
8 $root_webapp_name = 'tomcat6-webapps‘
9 $root_webapp_ensure = 'installed'
10 }
6|
code won’t break!
Once we get introduced to Hiera in upcoming chapters, we will move the configuration parameters from params.pp to Hiera. We
are for now using loosely called “params class” pattern
Now we will inherit params class in our tomcat
class (init.pp) so that all parameters are
available. Moreover we will take parameters as
class arguments and in case they are not
provided, default values will do magic. You might
have noticed that our code for installing tomcat
etc. is missing – we will take care of that in a
moment. Notice the way we are all namespacing
all classes like “tomcat::params”?
1 class tomcat (
2 $package_name = $tomcat::params::service_name,
3 $package_ensure = $tomcat::params::package_ensure,
4 $service_manage = $tomcat::params::service_manage,
5 $service_name = $tomcat::params::service_name,
6 $service_ensure = $tomcat::params::service_ensure,
7 $service_port = $tomcat::params::service_port,
8 ) inherits ::tomcat::params {
9
10 }
www.vishalbiyani.comLearning Puppet
Code into logical classes
Next we want to break the code logic into
appropriate blocks.We are primarily doing a few
things – managing packages (installing them)
and once they are done then managing service
(Starting tomcat etc.). So it makes sense to add
the relevant chunk in relevant classes.
Our first step of getting packages and installing
them is grouped into install.pp which does same
thing but uses parameters instead of hardcoded
values of package names & states. Looks neat
isn’t it?
1 class tomcat::install inherits tomcat {
2 package { 'tomcat6':
3 name => $package_name,
4 ensure => $package_ensure,
5 }
6 package {'tomcat6-webapps':
7 name => $root_webapp_name,
8 ensure => $root_webapp_ensure,
9 require => Package['tomcat6'],
10 }
11 }
1 class tomcat::service inherits tomcat {
2 if ! ($service_ensure in ['stopped','running']){Next we manage services in service.pp. Here we
7|
2 if ! ($service_ensure in ['stopped','running']){
3 fail("Service status must be one of stopped or running")
4 }
5 if $service_manage == true {
6 service {'tomcat6':
7 ensure => $service_ensure,
8 name => $service_name,
9 }
10 }
11 }
Next we manage services in service.pp. Here we
add a small check to ensure user has not passed
invalid values for service status before we
actually start service.We are also letting user
decide weather service should be started or not
with $service_manage parameter. Rest all is old
code in new bottle (of beer or wine ;) )
1 class tomcat::config inherits tomcat {
2 }
We are adding one more class – config.pp and
leaving it blank, just for future you know!
So we defined classes but never invoked them?
How will this work? It will, in next slide ;)
www.vishalbiyani.comLearning Puppet
Get Set Go..Finally we add the meat to main block of our
original class – tomcat (init.pp).We are using a
magic word – contain and then declaring the
three classes we defined in a specific order.
Because we don’t want to start tomcat service
before it is installed isn’t it? BTWWTH is this
contain?We will understand that in next slide but
for now understand that we are scoping them in
current context so that even if someone declares
them elsewhere with include – we are not
affected! (Remember that irrespective of number
of includes – it is executes only once?)
1 class tomcat (
2 $package_name = $tomcat::params::service_name,
3 $package_ensure = $tomcat::params::package_ensure,
4 $service_manage = $tomcat::params::service_manage,
5 $service_name = $tomcat::params::service_name,
6 $service_ensure = $tomcat::params::service_ensure,
7 $service_port = $tomcat::params::service_port,
8 ) inherits ::tomcat::params {
9 contain tomcat::config
10 contain tomcat::install
11 contain tomcat::service
12
13 Class['tomcat::config'] ->
14 Class['tomcat::install'] ->
15 Class['tomcat::service']
16 }
8|There is an excellent document on Puppet website which talks about good module design, our design is loosely
based on that, it is a MUST read: https://docs.puppetlabs.com/guides/module_guides/bgtm.html
What changes in node classification declaration
from last modification? Not much. Doing a
puppet run on agent would have same effect but
now our code is much cleaner & well structured. If
you need to pass parameters then we will have to
use the resource declaration way as shown in
second code snippet for node declaration:
1 node '0.pagent.vb.com' {
2 include tomcat
3 }
1 node '0.pagent.vb.com' {
2 class {'tomcat':
3 service_ensure => 'stopped',
4 }
5 }
If you noticed something – if you try changing the
port of service to anything other than 8080 – that
does not work, because we have not yet coded for
that.We will do that in next chapter but before
we finish let’s go over what containment is ?
Why can not we pass parameters in include way of class declaration above?
Why we had to fall back to resource based declaration? If you use include
function to declare classes then configuration parameters should ideally
come from Hiera and we will see how in upcoming chapters. It is suggested
to use include way of declaring going forward as we already covered in
chapter 2
www.vishalbiyani.comLearning Puppet
Containment &
Anchor pattern
So how do you contain classes? It is very simple syntax – in include like as
well as resource like declaration. For resource like, you will need to use all 4
lines below and in case of include like only line number 4 is needed!
Containment can be a tricky topic to understand
if we ignore basics, so let’s recap them once more:
•In puppet sequence of execution is not
guaranteed unless you explicitly form that
relationship (Between two resources).
•“include” type of declaration can be done
multiple times although the execution will
happen only once
•Thirdly if you define a resource within a class –
1 class {'tomcat::service':
2 service_ensure => 'stopped',
3 }
4 contain 'tomcat::service'
But there is a small problem – contain function was introduced in Puppet
enterprise 3.2 and puppet open source 3.4. So if you are using versions prior
to those, you will need to use puppetlabs/stdlibs module along with anchor
resource type.This is named “anchor containment pattern”. Let’s look at
some code and then digest it, our above declaration with anchor pattern
now will look like:
1 anchor['tomcat_start:'] ->
9|
•Thirdly if you define a resource within a class –
then you can be sure that the resource code will
be executed after class starts and before class
ends – this is basically called containment of that
resource to class. Resources and defined types by
default are contained.
Now let’s imagine you defined a class A.You
included A in another class B and many other
places. But puppet does not guarantee that A will
be executed within B by default.This means
classes by default are not contained and need to
be contained explicitly.Why? See footnote!
Classes are not contained by default is intentional. Imagine you declared “include class_name” n number of places and
puppet had to contain the class everywhere? At the same time when we design a large module, we want to make sure
parent class can contain other classes. Creating classes to have logical division is a good practice as we already saw!
1 anchor['tomcat_start:'] ->
2 Class['tomcat::service':] ->
3 anchor['tomcat_end':]
4 # Almost same as 'contain tomcat::service'
So here is what is happening:
•The class to be contained should be between two anchors.These anchors
should be unique within containing class.
•You must form relationship between class to be contained and anchors
such that there is one anchor before and after the contained class (-> forms
this relationship)
•Anchor code does not affect the execution – it is only to facilitate the
containment!
www.vishalbiyani.comLearning Puppet
1
Node classification and how to add relevant
infrastructure code to a node
What did we learn?
2
How to create module, it’s basic structure and how
to it all forms together
3
Good practices for class design & parameterization
of classes for configurable values.
10|
4
Calling classes from a module for a given node &
configuring it as per need
5
Containment of classes & why anchor pattern is
needed for certain versions of puppet
1 of 10

More Related Content

What's hot(20)

Puppi. Puppet strings to the shellPuppi. Puppet strings to the shell
Puppi. Puppet strings to the shell
Alessandro Franceschi5.8K views
Being Dangerous with TwigBeing Dangerous with Twig
Being Dangerous with Twig
Ryan Weaver11.2K views
Nginx presNginx pres
Nginx pres
James Fuller13.7K views
Hands-on with the Symfony2 FrameworkHands-on with the Symfony2 Framework
Hands-on with the Symfony2 Framework
Ryan Weaver9.3K views
Power of Puppet 4Power of Puppet 4
Power of Puppet 4
Martin Alfke9.3K views
Puppet Systems Infrastructure Construction KitPuppet Systems Infrastructure Construction Kit
Puppet Systems Infrastructure Construction Kit
Alessandro Franceschi1.6K views
Mastering Namespaces in PHPMastering Namespaces in PHP
Mastering Namespaces in PHP
Nick Belhomme16.7K views
Maven 3.0 at ØredevMaven 3.0 at Øredev
Maven 3.0 at Øredev
Matthew McCullough8.2K views
Intro To Spring PythonIntro To Spring Python
Intro To Spring Python
gturnquist5.8K views
Php simplePhp simple
Php simple
PrinceGuru MS19.4K views
Modules of the twentiesModules of the twenties
Modules of the twenties
Puppet847 views

Similar to Learning puppet chapter 3(20)

Puppet quick start guidePuppet quick start guide
Puppet quick start guide
Suhan Dharmasuriya1.8K views
Pp w tomeePp w tomee
Pp w tomee
Felix Gomez del Alamo327 views
Demystifying MavenDemystifying Maven
Demystifying Maven
Mike Desjardins4.9K views
Mc sl54 051_ (1)Mc sl54 051_ (1)
Mc sl54 051_ (1)
AnkitKumar234330 views
Debugging and Error handlingDebugging and Error handling
Debugging and Error handling
Suite Solutions540 views
Buffer overflow tutorialBuffer overflow tutorial
Buffer overflow tutorial
hughpearse374 views
Apache TomEE  - Tomcat with a kickApache TomEE  - Tomcat with a kick
Apache TomEE - Tomcat with a kick
Vishwanath Krishnamurthi14.9K views
Parrot tutorialParrot tutorial
Parrot tutorial
HarikaReddy11537 views
Makefiles BioinfoMakefiles Bioinfo
Makefiles Bioinfo
Giovanni Marco Dall'Olio4.1K views
MalletMallet
Mallet
Shatakirti Er7.2K views
Dost.jar and fo.jarDost.jar and fo.jar
Dost.jar and fo.jar
Suite Solutions1.5K views
Step by step_linux_guideStep by step_linux_guide
Step by step_linux_guide
vinod31dec8.2K views

More from Vishal Biyani(15)

Gophercon 2018: Kubernetes api golangGophercon 2018: Kubernetes api golang
Gophercon 2018: Kubernetes api golang
Vishal Biyani671 views
Serverless Summit India 2017: FissionServerless Summit India 2017: Fission
Serverless Summit India 2017: Fission
Vishal Biyani5.7K views
SaltStack Advanced ConceptsSaltStack Advanced Concepts
SaltStack Advanced Concepts
Vishal Biyani376 views
Kubernetes 101 WorkshopKubernetes 101 Workshop
Kubernetes 101 Workshop
Vishal Biyani527 views
Serverless Pune meetup 3Serverless Pune meetup 3
Serverless Pune meetup 3
Vishal Biyani283 views
Serverless Pune Meetup 1Serverless Pune Meetup 1
Serverless Pune Meetup 1
Vishal Biyani913 views
Setting up Kubernetes with tectonicSetting up Kubernetes with tectonic
Setting up Kubernetes with tectonic
Vishal Biyani4.6K views
Introduction to KubernetesIntroduction to Kubernetes
Introduction to Kubernetes
Vishal Biyani601 views
Mulesoft cloudhubMulesoft cloudhub
Mulesoft cloudhub
Vishal Biyani4K views
Dell boomiDell boomi
Dell boomi
Vishal Biyani5.3K views
Using CI for continuous delivery Part 3Using CI for continuous delivery Part 3
Using CI for continuous delivery Part 3
Vishal Biyani19.8K views
Using CI for continuous delivery Part 2Using CI for continuous delivery Part 2
Using CI for continuous delivery Part 2
Vishal Biyani19.4K views
Using CI for continuous delivery Part 1Using CI for continuous delivery Part 1
Using CI for continuous delivery Part 1
Vishal Biyani19.9K views
Using CI for continuous delivery Part 4Using CI for continuous delivery Part 4
Using CI for continuous delivery Part 4
Vishal Biyani19.7K views

Learning puppet chapter 3

  • 1. LEARNING PUPPET - 03 SlideBook (Book on slides) Inspired by Slidedoc - http://www.duarte.com -Vishal Biyani www.vishalbiyani.com
  • 3. www.vishalbiyani.comLearning Puppet What we will learn? Here is what we are going to do in this chapter Write a very basic manifest which will install and configure tomcat & run the manifest and see if it actually works? Move manifest code into a class and package into module – thus learning how to create module and basics of module Make class configurable so that we can pass parameters for certain things – for example port on which tomcat will run etc. 3| Refactor code to separate configurable parameters, make it modular in terms of class design & organization etc. Learn what is containment (Sounds like enlightenment isn't it? ☺) Finally use templates and ERB templatinging language to manage configuration files of software being installed That seems a lot?That’s going to be super easy though!
  • 4. www.vishalbiyani.comLearning Puppet First tomcat run! Now let’s log on to agent_0 and fire command: In our first cut we want to do a few basic things: install tomcat, start/run it and there should be a way to test it in browser if it is working right. For testing part we will install the “ROOT” app which shows tomcat home page.Where to put all this code? In the /etc/puppet/manifests/site.pp under one of nodes.Our site.pp looks like: 1 node 'puppet.learn.com' { 2 package {'vim-enhanced.x86_64': 3 ensure => present, 4 } 5 } 6 node '0.pagent.vb.com' { 7 package { 'tomcat6': So that will install & bring up tomcat.To check simply hit the ip_address:8080* (Or find out the IP address that would get assigned from Vagrantfile, in my case it is 192.168.17.10).You should see tomcat homepage: 4| 7 package { 'tomcat6': 8 ensure => installed, 9 } 10 11 service { 'tomcat6': 12 ensure => running, 13 } 14 package { 'tomcat6-webapps': 15 ensure => installed, 16 require => Package['tomcat6'], 17 } 18 } 19 node '1.pagent.vb.com' { 20 } In above snippet we have added lines from 7 – 17 to get done what we want. First we are declaring that package tomcat6 should be installed, secondly it should be running. In last block we are installing the “ROOT” app which is named as tomcat-webapps and also forming a relation on installation of tomcat. To get IP address of agent fire command “ifconfig” – here the IP address in block eth1 would be accessible from your machine So we have a basic tomcat server running but there are quite a few things that need to be taken care of for example: •Note that our current code will only work on certain operating systems – for example if package name on a OS anything different than tomcat6 – then it won’t work. •Similarly adding code this way to node definition is not scalable for sure. We need to move the code somewhere else. But this is a good start for our first cut; we will refine this much more in coming pages/slides!
  • 5. www.vishalbiyani.comLearning Puppet Creating a module! Let’s understand what all goes in module we created: Gemfile is a where you define dependencies using the dependency management tool in Ruby: Bundler Manifests – is where most of the code we write will go.The special file here is init.pp – this file has class with name same as module name (tomcat). Note that all other classes should have same name for file in which class is defined (Best practice) except for init.pp. Metadata.json stores basic information about your module which you filled in while generating module. Rakefile is like a make file in C – which defined tasks for your codebase. And you know what a README.md is for isn’t it? Spec directory Tests is where tests for our module live! For this chapter we are only going to touch files in manifests directory! Let’s get our house in order!We put bunch of lines in node definition to getTomcat up and running but we want to distribute our tomcat magic code to others so that they can do the same. Let’s wrap all of code in a module. For that let’s first create a barebones module, on master node navigate to /etc/puppet/modules and fire: 1 sudo puppet module generate learn-tomcat sudo mv learn-tomcat tomcat The name we gave is a combination of username (learn) and module name (tomcat) which is separated by dash and is the convention followed 5| For this chapter we are only going to touch files in manifests directory! If you look at the init.pp in manifests, you will see: So let’s move the code we had defined inside node definition in this class. That makes our module functional. If someone has to install tomcat, all one has to do is in node definition (Try on your setup!): The effect is same as previous slide.Our first ever module for tomcat is ready.Our class still does not follow the best coding practices & design patterns but we will fix that soon too! * The name of module vs. the combo name of username-modulename is a known bug and will be fixed in Puppet 4.0 I stumbled on this during exercise so I added that command. Check https://tickets.puppetlabs.com/browse/PUP-3124 separated by dash and is the convention followed by puppet.You will be asked with bunch of questions and you can fill them or leave blank! And we need to rename the module name to tomcat as the username-module name combo needs to be only in metadata file*. And puppet generates a basic structure of a module for us! tomcat/ |── Gemfile |── manifests | |── init.pp |── metadata.json |── Rakefile |── README.md |── spec | |── classes | | └── init_spec.rb | |── spec_helper.rb |── tests |── init.pp 1 class tomcat { 2 } 1 node '0.pagent.vb.com' { 2 include tomcat 3 }
  • 6. www.vishalbiyani.comLearning Puppet Making things parameterized! Parameterization – first thing we want to do is make some of hardcoded values to be passed as parameters so that end user can customize the module as per need. For this first of all we create a class params.pp in manifests directory, that way parameters will be managed in a different class and can be referred from all over the module. Also note that we have default values for all parameters so even if end user does not provide them when calling tomcat module, our code won’t break! 1 class tomcat::params { 2 $package_name = 'tomcat6' 3 $package_ensure = 'installed' 4 $service_manage = true 5 $service_name = 'tomcat6' 6 $service_ensure = 'running' 7 $service_port = '8080' 8 $root_webapp_name = 'tomcat6-webapps‘ 9 $root_webapp_ensure = 'installed' 10 } 6| code won’t break! Once we get introduced to Hiera in upcoming chapters, we will move the configuration parameters from params.pp to Hiera. We are for now using loosely called “params class” pattern Now we will inherit params class in our tomcat class (init.pp) so that all parameters are available. Moreover we will take parameters as class arguments and in case they are not provided, default values will do magic. You might have noticed that our code for installing tomcat etc. is missing – we will take care of that in a moment. Notice the way we are all namespacing all classes like “tomcat::params”? 1 class tomcat ( 2 $package_name = $tomcat::params::service_name, 3 $package_ensure = $tomcat::params::package_ensure, 4 $service_manage = $tomcat::params::service_manage, 5 $service_name = $tomcat::params::service_name, 6 $service_ensure = $tomcat::params::service_ensure, 7 $service_port = $tomcat::params::service_port, 8 ) inherits ::tomcat::params { 9 10 }
  • 7. www.vishalbiyani.comLearning Puppet Code into logical classes Next we want to break the code logic into appropriate blocks.We are primarily doing a few things – managing packages (installing them) and once they are done then managing service (Starting tomcat etc.). So it makes sense to add the relevant chunk in relevant classes. Our first step of getting packages and installing them is grouped into install.pp which does same thing but uses parameters instead of hardcoded values of package names & states. Looks neat isn’t it? 1 class tomcat::install inherits tomcat { 2 package { 'tomcat6': 3 name => $package_name, 4 ensure => $package_ensure, 5 } 6 package {'tomcat6-webapps': 7 name => $root_webapp_name, 8 ensure => $root_webapp_ensure, 9 require => Package['tomcat6'], 10 } 11 } 1 class tomcat::service inherits tomcat { 2 if ! ($service_ensure in ['stopped','running']){Next we manage services in service.pp. Here we 7| 2 if ! ($service_ensure in ['stopped','running']){ 3 fail("Service status must be one of stopped or running") 4 } 5 if $service_manage == true { 6 service {'tomcat6': 7 ensure => $service_ensure, 8 name => $service_name, 9 } 10 } 11 } Next we manage services in service.pp. Here we add a small check to ensure user has not passed invalid values for service status before we actually start service.We are also letting user decide weather service should be started or not with $service_manage parameter. Rest all is old code in new bottle (of beer or wine ;) ) 1 class tomcat::config inherits tomcat { 2 } We are adding one more class – config.pp and leaving it blank, just for future you know! So we defined classes but never invoked them? How will this work? It will, in next slide ;)
  • 8. www.vishalbiyani.comLearning Puppet Get Set Go..Finally we add the meat to main block of our original class – tomcat (init.pp).We are using a magic word – contain and then declaring the three classes we defined in a specific order. Because we don’t want to start tomcat service before it is installed isn’t it? BTWWTH is this contain?We will understand that in next slide but for now understand that we are scoping them in current context so that even if someone declares them elsewhere with include – we are not affected! (Remember that irrespective of number of includes – it is executes only once?) 1 class tomcat ( 2 $package_name = $tomcat::params::service_name, 3 $package_ensure = $tomcat::params::package_ensure, 4 $service_manage = $tomcat::params::service_manage, 5 $service_name = $tomcat::params::service_name, 6 $service_ensure = $tomcat::params::service_ensure, 7 $service_port = $tomcat::params::service_port, 8 ) inherits ::tomcat::params { 9 contain tomcat::config 10 contain tomcat::install 11 contain tomcat::service 12 13 Class['tomcat::config'] -> 14 Class['tomcat::install'] -> 15 Class['tomcat::service'] 16 } 8|There is an excellent document on Puppet website which talks about good module design, our design is loosely based on that, it is a MUST read: https://docs.puppetlabs.com/guides/module_guides/bgtm.html What changes in node classification declaration from last modification? Not much. Doing a puppet run on agent would have same effect but now our code is much cleaner & well structured. If you need to pass parameters then we will have to use the resource declaration way as shown in second code snippet for node declaration: 1 node '0.pagent.vb.com' { 2 include tomcat 3 } 1 node '0.pagent.vb.com' { 2 class {'tomcat': 3 service_ensure => 'stopped', 4 } 5 } If you noticed something – if you try changing the port of service to anything other than 8080 – that does not work, because we have not yet coded for that.We will do that in next chapter but before we finish let’s go over what containment is ? Why can not we pass parameters in include way of class declaration above? Why we had to fall back to resource based declaration? If you use include function to declare classes then configuration parameters should ideally come from Hiera and we will see how in upcoming chapters. It is suggested to use include way of declaring going forward as we already covered in chapter 2
  • 9. www.vishalbiyani.comLearning Puppet Containment & Anchor pattern So how do you contain classes? It is very simple syntax – in include like as well as resource like declaration. For resource like, you will need to use all 4 lines below and in case of include like only line number 4 is needed! Containment can be a tricky topic to understand if we ignore basics, so let’s recap them once more: •In puppet sequence of execution is not guaranteed unless you explicitly form that relationship (Between two resources). •“include” type of declaration can be done multiple times although the execution will happen only once •Thirdly if you define a resource within a class – 1 class {'tomcat::service': 2 service_ensure => 'stopped', 3 } 4 contain 'tomcat::service' But there is a small problem – contain function was introduced in Puppet enterprise 3.2 and puppet open source 3.4. So if you are using versions prior to those, you will need to use puppetlabs/stdlibs module along with anchor resource type.This is named “anchor containment pattern”. Let’s look at some code and then digest it, our above declaration with anchor pattern now will look like: 1 anchor['tomcat_start:'] -> 9| •Thirdly if you define a resource within a class – then you can be sure that the resource code will be executed after class starts and before class ends – this is basically called containment of that resource to class. Resources and defined types by default are contained. Now let’s imagine you defined a class A.You included A in another class B and many other places. But puppet does not guarantee that A will be executed within B by default.This means classes by default are not contained and need to be contained explicitly.Why? See footnote! Classes are not contained by default is intentional. Imagine you declared “include class_name” n number of places and puppet had to contain the class everywhere? At the same time when we design a large module, we want to make sure parent class can contain other classes. Creating classes to have logical division is a good practice as we already saw! 1 anchor['tomcat_start:'] -> 2 Class['tomcat::service':] -> 3 anchor['tomcat_end':] 4 # Almost same as 'contain tomcat::service' So here is what is happening: •The class to be contained should be between two anchors.These anchors should be unique within containing class. •You must form relationship between class to be contained and anchors such that there is one anchor before and after the contained class (-> forms this relationship) •Anchor code does not affect the execution – it is only to facilitate the containment!
  • 10. www.vishalbiyani.comLearning Puppet 1 Node classification and how to add relevant infrastructure code to a node What did we learn? 2 How to create module, it’s basic structure and how to it all forms together 3 Good practices for class design & parameterization of classes for configurable values. 10| 4 Calling classes from a module for a given node & configuring it as per need 5 Containment of classes & why anchor pattern is needed for certain versions of puppet