Lab-23:Getting to know Puppet

Puppet like ansible, chef and salt is a configuration management tool. Say you are a system admin and your job is to manage company servers. You install new packages, add users, delete users and various other tasks.  Puppet allows you to automate all these tasks and make life easier.

You can execute puppet in a standalone mode  or  client server mode. In the client server mode you need to install puppet agent on a machine that needs to be managed and server on another. A single server can manage multiple agents.

Puppet works as pull request where agents pull their configuration data from server. This can be achieved on demand by running ‘puppet agent –test’ command on client machine or periodically. Every 30 min client asks server for configuration data. As far I know there is no push operation from puppet server to client, it is always pull from client

Puppet programs works on desired state, it changes the state of resource from current state to desired state. If resource is already in desired state no action performed. You specify desired state in puppet program (called manifest). Say you want to install a new package on a client machine, you write a puppet program  and specify desired state ‘ensure => ‘present”. When puppet client pulls this configuration data (called catalog) from server it checks for desired state for this particular package, if package already in desired state ‘present’ (package already installed), no action performed. If package is in different state then client will bring it to ‘present’ state (install the package). If you need to delete a package change desired state to ‘absent’ and client will remove the package

In this lab I will demonstrate how to install puppet in a client server configuration. I will show how to create a simple puppet script.

Its good idea to know commonly used  puppet terminology before we start

Puppet master:

Machine which is running puppet server is called puppet master. Master has certification authority (CA) to generate and sign certificate. I use master and server interchangeably

Puppet agent:

Machine running puppet agent is call puppet agent or simply agent. I use agent and client interchangeably

Puppet manifest:

Puppet programs are called manifest, they have .pp extension. A manifest is made of modules

Catalog:

A  document agents pulls from master that contains desired state of each resource. Any time you do ‘puppet agent –test’ it pulls catalog from server

Resource:

Resource is something that you manage on client machine. for example file & package are resources. Using file resource you can create/delete, update file on client

Pre-condition:

A Linux machine. I am using Ubuntu 14.04 LTS. I have created this topology with Linux bridgeI I have created three Ubuntu 14.04 VMs simulating server and agent. They are all in same subnet, I can ping from one VM to another VM thru bridge. Check out  my  lab-15 for Linux bridge setup. Note: If you have two machines you can create one as server and another as  agent no need to follow lab-15

puppet_intro

sjakhwal@rtxl3rld05:/etc/network$ sudo brctl show
[sudo] password for sjakhwal: 
bridge name    bridge id        STP enabled    interfaces
testBr        8000.000acd27b824    no        eth3
                            tap0
                            tap1
virbr0        8000.000000000000    yes

I have created two Ubuntu 14.04 VMs with hostname puppet & puppet-client1.

On VM with hostname puppet install pupperserver.

wget https://apt.puppetlabs.com/puppetlabs-release-pc1-trusty.deb
sudo dpkg -i puppetlabs-release-pc1-trusty.deb
sudo apt-get install puppetserver

labadmin@puppet:$ puppetserver --version
puppetserver version: 2.3.1

On VMs with hostname puppet-client1  install puppet agent

wget https://apt.puppetlabs.com/puppetlabs-release-pc1-trusty.deb
sudo dpkg -i puppetlabs-release-pc1-trusty.deb

labadmin@puppet-client1:~$ puppet --version
4.4.2
labadmin@puppet-client1:~$ 

This completes installation part of puppet. Now let’s setup server to  agent communication.

Puppet agents by default uses hostname ‘puppet’ to communicate with server. I have already setup server hostname as ‘puppet’ now we need to make sure it is resolved from agents.   This can be done by updating   /etc/hosts file

I have added this line in puppet-client1  /etc/hosts file. 192.168.10.101 is server IP address

192.168.10.101  puppet.sunny.net puppet

I have added these lines in server /etc/hosts file to resolve clients hostname

192.168.10.102 puppet-client1.sunny.net puppet-client1

Change domain name in /etc/resolv.conf file on all machines (agents & server). Note:You will lose this setting if machine rebooted a more permanent way is to add domain in interfaces file

search sunny.net

Try ping from agent and server machines using hostname , make sure ping passes

ping puppet
ping puppet-client1.sunny.net

Start puppet server. Check  puppet server is running and port 8140 is listening. Agent uses port 8140 to connect to master. Note:If your agent unable to connect to master make sure port 8140 is not blocked by firewall

Note:Make sure user is part of ‘puppet’ group

#start puppet server
labadmin@puppet:/etc/puppet$sudo service puppetserver start
labadmin@puppet:/etc/puppet$ ps -ef | grep puppet
avahi    10079     1  0 11:28 ?        00:00:00 avahi-daemon: running [puppet.local]
puppet   10577     1  0 11:46 ?        00:02:11 /usr/bin/java -XX:OnOutOfMemoryError=kill -9 %p 
-Djava.security.egd=/dev/urandom -Xms2g -Xmx2g -XX:MaxPermSize=256m -cp 
/opt/puppetlabs/server/apps/puppetserver/puppet-server-release.jar clojure.main 
-m puppetlabs.trapperkeeper.main --config /etc/puppetlabs/puppetserver/conf.d -b 
/etc/puppetlabs/puppetserver/bootstrap.cfg

labadmin@puppet:$ puppetserver --version
puppetserver version: 2.3.1
labadmin@puppet:$ sudo netstat -pan | grep 8140
[sudo] password for labadmin: 
tcp6       0      0 :::8140                 :::*                    LISTEN      10577/java      
labadmin@puppet:$ 

#Use this command to open port 8140 on master if you think port is blocked
$iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8140 -j ACCEPT

Start puppet agent

labadmin@puppet-client1:~$ which puppet
/opt/puppetlabs/bin/puppet
labadmin@puppet-client1:~$ puppet --version
4.4.2
labadmin@puppet-client1:~$ sudo ps -ef | grep puppet
[sudo] password for labadmin: 
avahi     3483     1  0 Apr27 ?        00:00:00 avahi-daemon: running [puppet-client1.local]
root      4261     1  0 12:03 ?        00:00:02 /opt/puppetlabs/puppet/bin/ruby /opt/puppetlabs/puppet/bin/puppet agent
labadmin  6185     1  0 18:37 ?        00:00:03 /opt/puppetlabs/puppet/bin/ruby /opt/puppetlabs/bin/puppet agent --server puppet.sunny.net
labadmin  6838  4453  0 21:44 pts/0    00:00:00 grep --color=auto puppet
labadmin@puppet-client1:~$ 

#start puppet agent
labadmin@puppet-client1:$sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true

#try this command to generate certificates
$puppet agent --test

Sign certificate on server.

#list certificate. make sure you run it as 'sudo' otherwise you will not see 
#anything. As you see client1 certificate is waiting to be signed by server
labadmin@puppet:$ sudo /opt/puppetlabs/bin/puppet cert list
  "puppet-client1.sunny.net" (SHA256) F1:54:9D:D0:15:E6:4C:A9:97:20:A0:A5:82:A1:82:EA:3F:0F:F8:56:36:72:EE:7E:6C:BC:5B:D3:BC:89:F3:AE

#sign certificate for client1
labadmin@puppet:$ sudo /opt/puppetlabs/bin/puppet cert sign puppet-client1.sunny.net
Notice: Signed certificate request for puppet-client1.sunny.net
Notice: Removing file Puppet::SSL::CertificateRequest puppet-client1.sunny.net at '/etc/puppetlabs/puppet/ssl/ca/requests/puppet-client1.sunny.net.pem'

#list all certificates (signed and unsigned), '+' mean signed. server certificate 
#is by default signed
labadmin@puppet:$ sudo /opt/puppetlabs/bin/puppet cert list --all
+ "puppet-client1.sunny.net" (SHA256) 1D:D7:74:54:93:DE:A9:9E:95:B2:6A:83:F4:66:11:DE:BA:BA:98:70:02:50:5F:1F:66:FB:53:83:3E:67:30:9C
+ "puppet.sunny.net"         (SHA256) 50:1A:0C:74:45:98:9A:70:8E:33:AE:70:D8:FF:6F:06:E4:F5:22:8F:97:8F:8D:4A:40:66:DF:6B:13:4F:3A:CB (alt names: "DNS:puppet", "DNS:puppet.sunny.net")
labadmin@puppet:$

This completes the handshaking between server and agent. We are now ready to write our first puppet manifest. We will start with default manifest ‘site.pp’  in this directory /etc/puppetlabs/code/environments/production/manifests.

Create file site.pp and add these contents in the file

labadmin@puppet:/etc/puppetlabs/code/environments/production/manifests$ cat site.pp
              node default {}
              node "puppet-client1" {
              file {"/home/labadmin/hello-puppet.txt":
                              ensure => "file",
                              owner => "labadmin",
                              content => "Congratulations! you have created a test file using puppet\n",
               }
            }

This is a simple manifest with file resource for client1 (hostname puppet-client1). In the file resource we are looking for file ‘hello-puppet.txt’ under directory /home/labadmin, we desire it to be file, owner ‘labadmin’ and its contents ‘Congratulations! you have created a test file using puppet’. If this file is not present in agent, puppet will create it. If file is present but contents doesn’t match, puppet will update contents

Validate our manifest for any syntax. Run this command on server

puppet parser validate site.pp

First make sure our resources in client1 are not in state as desired in manifest.

#no file in /home/labadmin
labadmin@puppet-client1:~$ pwd
/home/labadmin
labadmin@puppet-client1:~$ ls
examples.desktop  puppetlabs-release-pc1-trusty.deb

Now let’s pull client1 configuration from server and check resource state. First do a dry run

#do a dry run
labadmin@puppet-client1:~$ puppet agent --server=puppet --onetime --no-daemonize --verbose --noop
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Applying configuration version '1462070893'
Notice: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]/ensure: current_value absent, should be file (noop)
Notice: Node[puppet-client1]: Would have triggered 'refresh' from 1 events
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Applied catalog in 0.10 seconds
labadmin@puppet-client1:~$ 

#run puppet to pull configuration file. 
labadmin@puppet-client1:~$ puppet agent --test

#check is file been created with right contents
labadmin@puppet-client1:~$ cat hello-puppet.txt 
Congratulations! you have created a test file using puppet
labadmin@puppet-client1:~$ 

Update manifest to change file mode.

#add mode field in the manifest file 'site.pp'
node default {}
node "puppet-client1" {
file {"/home/labadmin/hello-puppet.txt":
        ensure => "file",
        owner => "labadmin",
        mode => "666",
        content => "Congratulations! you have created a test file using puppet\n",
}
}

#do dry run on client1
labadmin@puppet-client1:~$ puppet agent --server=puppet --onetime --no-daemonize --verbose --noop
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Applying configuration version '1462108972'
Notice: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]/mode: current_value 0644, should be 0666 (noop)
Notice: Node[puppet-client1]: Would have triggered 'refresh' from 1 events
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Applied catalog in 0.04 seconds

#as you can see file mode is '644'
labadmin@puppet-client1:~$ ls -la hello-puppet.txt 
-rw-r--r-- 1 labadmin labadmin 59 Apr 30 21:53 hello-puppet.txt

#pull configuration from server
labadmin@puppet-client1:~$ puppet agent --test
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppet-client1.sunny.net
Info: Applying configuration version '1462109031'
Notice: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]/mode: mode changed '0644' to '0666'
Notice: Applied catalog in 0.03 seconds

#as you can see file mode changed to '666'
labadmin@puppet-client1:~$ ls -la hello-puppet.txt 
-rw-rw-rw- 1 labadmin labadmin 59 Apr 30 21:53 hello-puppet.txt
labadmin@puppet-client1:~$

Delete file

#update desire state to 'absent'
node default {}
node "puppet-client1" {
file {"/home/labadmin/hello-puppet.txt":
        ensure => "absent",
        owner => "labadmin",
        mode => "666",
        content => "Congratulations! you have created a test file using puppet\n",
}
}

#
labadmin@puppet-client1:~$ ls -la hello-puppet.txt
-rw-rw-rw- 1 labadmin labadmin   59 Apr 30 21:53 hello-puppet.txt

#do a dry run
labadmin@puppet-client1:~$ puppet agent --server=puppet --onetime --no-daemonize --verbose --noop
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Applying configuration version '1462196853'
Notice: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]/ensure: current_value file, should be absent (noop)
Notice: Node[puppet-client1]: Would have triggered 'refresh' from 1 events
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Applied catalog in 0.04 seconds

#pull configuration from server
labadmin@puppet-client1:~$ puppet agent --test
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppet-client1.sunny.net
Info: Applying configuration version '1462196909'
Info: Computing checksum on file /home/labadmin/hello-puppet.txt
Info: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]: Filebucketed /home/labadmin/hello-puppet.txt to puppet with sum 3b70fe8cd273dfaec69f4356bee53529
Notice: /Stage[main]/Main/Node[puppet-client1]/File[/home/labadmin/hello-puppet.txt]/ensure: removed
Notice: Applied catalog in 0.07 seconds

#as you can see file has been deleted from client1
labadmin@puppet-client1:~$ ls -l
total 24
drwxr-xr-x 2 labadmin labadmin 4096 Apr 29 17:15 Desktop
-rw-r--r-- 1 labadmin labadmin 8980 Apr 27 17:58 examples.desktop
-rw-r--r-- 1 root     root     5244 Apr 19 17:53 puppetlabs-release-pc1-trusty.deb
labadmin@puppet-client1:~$ 

 

References

https://www.digitalocean.com/community/tutorials/getting-started-with-puppet-code-manifests-and-modules

https://docs.puppet.com/puppet/latest/reference/type.html#package-attribute-root