
Puppet supports holding multiple values as an environment variable. This feature is supported in Puppet by using facter. In Puppet, facter is a standalone tool that holds the environment level variable. In can be considered similar to env variable of Bash or Linux. Sometimes there can be an overlap between the information stored in facts and environment variable of the machine. In Puppet, the key-value pair is known as “fact”. Each resource has its own facts and in Puppet the user has the leverage to build their own custom facts.
# facter
Facter command can be used to list all the different environment variables and its associated values. These collection of facts comes with facter out-of-the-box and are referred to as core facts. One can add custom facts to the collection.
If one wants to view only one variable. It can be done using the following command.
# facter {Variable Name}
Example
[root@puppetmaster ~]# facter virtual
virtualbox
The reason why facter is important for Puppet is that facter and facts are available throughout Puppet code as “global variable”, which means it can be used in the code at any point of time without any other reference.
[root@puppetmaster modules]# tree brcle_account
brcle_account
└── manifests └── init.pp [root@puppetmaster modules]# cat brcle_account/manifests/init.pp
class brcle_account {
user { 'G01063908':
ensure => 'present',
uid => '121',
shell => '/bin/bash',
home => '/home/G01063908',
}
file {'/tmp/userfile.txt':
ensure => file,
content => "the value for the 'OperatingSystem' fact is: $OperatingSystem \n",
}
}
[root@puppetmaster modules]# puppet agent --test Notice: /Stage[main]/Activemq::Service/Service[activemq]/ensure: ensure changed 'stopped' to 'running' Info: /Stage[main]/Activemq::Service/Service[activemq]: Unscheduling refresh on Service[activemq] Notice: Finished catalog run in 4.09 seconds [root@puppetmaster modules]# cat /tmp/testfile.txt the value for the 'OperatingSystem' fact is: Linux [root@puppetmaster modules]# facter OperatingSystem Linux
As we can notice in the above code snippet, we haven’t defined the OperatingSystem. We have just replaced the value with soft coded value $OperatingSystem as normal variable.
In Puppet, there are three types of fact that can be used and defined −
Core facts are defined at the top level and accessible to all at any point in the code.
Just before an agent requests for a catalog from the master, the agent first compiles a complete list of information available in itself in the form of a key value pair. The information on the agent is gathered by a tool called facter and each key-value pair is referred as a fact. Following is a common output of facts on an agent.
[root@puppetagent1 ~]# facter
architecture => x86_64
augeasversion => 1.0.0
bios_release_date => 13/09/2012
bios_vendor => innotek GmbH
bios_version => VirtualBox
blockdevice_sda_model => VBOX HARDDISK
blockdevice_sda_size => 22020587520
blockdevice_sda_vendor => ATA
blockdevice_sr0_model => CD-ROM
blockdevice_sr0_size => 1073741312
blockdevice_sr0_vendor => VBOX
blockdevices => sda,sr0
boardmanufacturer => Oracle Corporation
boardproductname => VirtualBox
boardserialnumber => 0
domain => codingbee.dyndns.org
facterversion => 2.1.0
filesystems => ext4,iso9660
fqdn => puppetagent1.codingbee.dyndns.org
hardwareisa => x86_64
hardwaremodel => x86_64
hostname => puppetagent1
id => root
interfaces => eth0,lo
ipaddress => 172.228.24.01
ipaddress_eth0 => 172.228.24.01
ipaddress_lo => 127.0.0.1
is_virtual => true
kernel => Linux
kernelmajversion => 2.6
kernelrelease => 2.6.32-431.23.3.el6.x86_64
kernelversion => 2.6.32
lsbdistcodename => Final
lsbdistdescription => CentOS release 6.5 (Final)
lsbdistid => CentOS
lsbdistrelease => 6.5
lsbmajdistrelease => 6
lsbrelease => :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0noarch:graphics-4.0-amd64:
graphics-4.0-noarch:printing-4.0-amd64:printing-4.0noarch
macaddress => 05:00:22:47:H9:77
macaddress_eth0 => 05:00:22:47:H9:77
manufacturer => innotek GmbH
memoryfree => 125.86 GB
memoryfree_mb => 805.86
memorysize => 500 GB
memorysize_mb => 996.14
mtu_eth0 => 1500
mtu_lo => 16436
netmask => 255.255.255.0
netmask_eth0 => 255.255.255.0
network_lo => 127.0.0.0
operatingsystem => CentOS
operatingsystemmajrelease => 6
operatingsystemrelease => 6.5
osfamily => RedHat
partitions => {"sda1"=>{
"uuid"=>"d74a4fa8-0883-4873-8db0-b09d91e2ee8d", "size" =>"1024000",
"mount" => "/boot", "filesystem" => "ext4"}, "sda2"=>{"size" => "41981952",
"filesystem" => "LVM2_member"}
}
path => /usr/lib64/qt3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
physicalprocessorcount => 1
processor0 => Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz
processor1 => Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz
processor2 => Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz
processorcount => 3
productname => VirtualBox
ps => ps -ef
puppetversion => 3.6.2
rubysitedir => /usr/lib/ruby/site_ruby/1.8
rubyversion => 1.8.7
selinux => true
selinux_config_mode => enforcing
selinux_config_policy => targeted
selinux_current_mode => enforcing
selinux_enforced => true
selinux_policyversion => 24
serialnumber => 0
sshdsakey => AAAAB3NzaC1kc3MAAACBAK5fYwRM3UtOs8zBCtRTjuHLw56p94X/E0UZBZwFR3q7
WH0x5+MNsjfmdCxKvpY/WlIIUcFJzvlfjXm4qDaTYalbzSZJMT266njNbw5WwLJcJ74KdW92ds76pjgm
CsjAh+R9YnyKCEE35GsYjGH7whw0gl/rZVrjvWYKQDOmJA2dAAAAFQCoYABgjpv3EkTWgjLIMnxA0Gfud
QAAAIBM4U6/nerfn6Qvt43FC2iybvwVo8ufixJl5YSEhs92uzsW6jiw68aaZ32q095/gEqYzeF7a2knr
OpASgO9xXqStYKg8ExWQVaVGFTR1NwqhZvz0oRSbrN3h3tHgknoKETRAg/imZQ2P6tppAoQZ8wpuLrXU
CyhgJGZ04Phv8hinAAAAIBN4xaycuK0mdH/YdcgcLiSn8cjgtiETVzDYa+jF
swapfree => 3.55 GB
swapfree_mb => 2015.99
swapsize => 3.55 GB
swapsize_mb => 2015.99
timezone => GMT
type => Other
uniqueid => a8c0af01
uptime => 45:012 hours
uptime_days => 0
uptime_hours => 6
uptime_seconds => 21865
uuid => BD8B9D85-1BFD-4015-A633-BF71D9A6A741
virtual => virtualbox
In the above code, we can see some of the data overlap with few of the information available in bash “env” variable. Puppet directly does not use the data, instead it makes use of facter data, Facter data is treated as global variable.
The facts are then available as top level variable and the Puppet master can use them to compile the Puppet catalog for the requesting agent. Facters are called in manifest as normal variable with $ prefix.
if ($OperatingSystem == "Linux") {
$message = "This machine OS is of the type $OperatingSystem \n"
} else {
$message = "This machine is unknown \n"
}
file { "/tmp/machineOperatingSystem.txt":
ensure => file,
content => "$message"
}
The above manifest file only bothers about a single file called machineOperatingSystem.txt, where the content of this file is deducted by the fact called OperatingSystem.
[root@puppetagent1 /]# facter OperatingSystem
Linux
[root@puppetagent1 /]# puppet apply /tmp/ostype.pp
Notice: Compiled catalog for puppetagent1.codingbee.dyndns.org
in environment production in 0.07 seconds
Notice: /Stage[main]/Main/File[/tmp/machineOperatingSystem.txt]/ensure:
defined content as '{md5}f59dc5797d5402b1122c28c6da54d073'
Notice: Finished catalog run in 0.04 seconds
[root@puppetagent1 /]# cat /tmp/machinetype.txt
This machine OS is of the type Linux
All the above facts that we have seen are the core facts of the machine. One can add this custom facts to the node in the following ways −
One can manually add the facts using the export FACTER_{fact’s name} syntax.
[root@puppetagent1 facter]# export FACTER_tallest_mountain="Everest" [root@puppetagent1 facter]# facter tallest_mountain Everest
In Ruby, $LOAD_PATH is equivalent to Bash special parameter. Although it is similar to bash $PATH variable, in real facts $LOAD_PATH is not an environment variable, instead it is a pre-defined variable.
$LOAD_PATH has a synonym “$:”. This variable is an array to search and load the values.
[root@puppetagent1 ~]# ruby -e 'puts $LOAD_PATH' # note you have to use single quotes. /usr/lib/ruby/site_ruby/1.6 /usr/lib64/ruby/site_ruby/1.6 /usr/lib64/ruby/site_ruby/1.6/x86_64-linux /usr/lib/ruby/site_ruby /usr/lib64/ruby/site_ruby /usr/lib64/site_ruby/1.6 /usr/lib64/site_ruby/1.6/x86_64-linux /usr/lib64/site_ruby /usr/lib/ruby/1.6 /usr/lib64/ruby/1.6 /usr/lib64/ruby/1.6/x86_64-linux
Let’s take an example of creating a directory facter and adding a .pp file and appending a content to it.
[root@puppetagent1 ~]# cd /usr/lib/ruby/site_ruby/ [root@puppetagent1 site_ruby]# mkdir facter [root@puppetagent1 site_ruby]# cd facter/ [root@puppetagent1 facter]# ls [root@puppetagent1 facter]# touch newadded_facts.rb
Add the following content to the custom_facts.rb file.
[root@puppetagent1 facter]# cat newadded_facts.rb
Facter.add('tallest_mountain') do
setcode "echo Everest"
end
Facter works in the method of scanning through all the folder listed in $LOAD_PATH, and looks for a director called facter. Once it finds that particular folder, it will load them anywhere in the folder structure. If it finds this folder then it looks for any Ruby file in that facter folder and loads all the defined facts about any particular configuration in the memory.
In Puppet, FACTERLIB works very much similar to $LOAD_PATH but with only one key difference that, it is a OS level environment parameter rather than a Ruby special variable. By default, the environment variable may not be set.
[root@puppetagent1 facter]# env | grep "FACTERLIB" [root@puppetagent1 facter]#
To test FACTERLIB, we need to perform the following steps.
Create a folder called test_facts in the following structure.
[root@puppetagent1 tmp]# tree /tmp/test_facts/ /tmp/some_facts/ ├── vipin │ └── longest_river.rb └── testing └── longest_wall.rb
Add the following contents to the .rb files.
[root@puppetagent1 vipin]# cat longest_river.rb
Facter.add('longest_river') do
setcode "echo Nile"
end
[root@puppetagent1 testing]# cat longest_wall.rb
Facter.add('longest_wall') do
setcode "echo 'China Wall'"
end
Use the export statement.
[root@puppetagent1 /]# export FACTERLIB = "/tmp/some_facts/river:/tmp/some_facts/wall" [root@puppetagent1 /]# env | grep "FACTERLIB" FACTERLIB = /tmp/some_facts/river:/tmp/some_facts/wall
Test the new facter.
[root@puppetagent1 /]# facter longest_river Nile [root@puppetagent1 /]# facter longest_wall China Wall
External facts are very useful when the user wishes to apply some new facts created at the provisioning time. External facts are one of the key ways of applying metadata to a VM at its provisioning stage (e.g. using vSphere, OpenStack, AWS, etc.)
All the metadata and its details created can be used by Puppet to determine what details should be present in the catalog, which is going to be applied.
On the agent machine, we need to create a directory as mentioned below.
$ mkdir -p /etc/facter/facts.d
Create a Shell script in the directory with the following content.
$ ls -l /etc/facter/facts.d total 4 -rwxrwxrwx. 1 root root 65 Sep 18 13:11 external-factstest.sh $ cat /etc/facter/facts.d/external-factstest.sh #!/bin/bash echo "hostgroup = dev" echo "environment = development"
Change the permission of the script file.
$ chmod u+x /etc/facter/facts.d/external-facts.sh
Once done, we can now see the variable present with the key/value pair.
$ facter hostgroup dev $ facter environment development
One can write custom facts in Puppet. As a reference, use the following link from the Puppet site.
https://docs.puppet.com/facter/latest/fact_overview.html#writing-structured-facts