Module of the Week: stahnma/epel – Add EPEL to your EL systems

Purpose Enable EPEL (extra packages for enterprise linux) to RHEL based systems.
Module stahnma/epel
Puppet Version 2.6+
Platforms RHEL, CentOS, Scientific, Oracle, AscendOS

This week is a back-to-basics week for us. Sometimes we talk about super-complex things you can do with Puppet, and those are great. However, we don't want to lose sight of solving simple problems that can deliver great value in a short amount of time. One of the native types in Puppet since 0.24 days has been a yumrepo. This sets up yum repository configurations from the client side. This week, we’ll take a look at setting up EPEL (extra packages for enterprise linux) on your Enterprise Linux (EL) based clients.

I authored the module and thought I’d take some time to break it down in this week’s Module of the Week post.

Resource Overview

The stahnma/epel module manages the following resources:

Files /etc/pki/rpm-gpg/RPM-GPG_KEY_EPEL-${::os_maj_version}
yumrepo:

epel

epel-debuginfo

epel-source

epel-testing

epel-testing-debuginfo

epel-testing-source

Defined Types: epel::rpm_gpg_key

Installing the Module

Complexity Easy
Installation Time 2 minutes

Installation of stahnma/epel is about as simple as can be. The module has no dependencies. If you’re on Puppet 2.7.14 or higher, Puppet Module Tool is baked into Puppet. It’s also there if you’re on Puppet Enterprise 2.5 or higher. If not, you can use the legacy puppet-module gem or just 'wget' the file from https://forge.puppetlabs.com/system/releases/s/stahnma/stahnma-epel-0.0.2.tar.gz.

In my examples, I’ll be using Puppet Enterprise, but there’s nothing specific to Puppet Enterprise about these steps—the Puppet versions identified above will work the same way.

$  puppet config print modulepath
/etc/puppetlabs/puppet/modules:/opt/puppet/share/puppet/modules

Here you can see that we have two modulepaths. (The default locations on Puppet Enterprise). We’ll install into the first location.

$ cd /etc/puppetlabs/puppet/modules

$ puppet module install stahnma/epel
Preparing to install into /etc/puppetlabs/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppetlabs/puppet/modules
└── stahnma-epel (v0.0.2)

You should now have an epel directory in your module path.

/etc/puppetlabs/puppet/modules/epel

Configuration (Optional)

Complexity Easy
Installation Time 5 minutes

The module has very little that is user configurable. In the file params.pp you’ll see an option to setup an http_proxy. You can set this variable if you need to use an http_proxy to have your systems talk to the outside world. Note that, due to the way yum behaves, you may set your proxy in /etc/yum.conf rather than set each repository individually. The http_proxy variable would make the most sense if you used a proxy to talk to some repositories and not others. Otherwise configuration in yum.conf is preferable, as all yum repositories will fall back to that configuration.

Assign the module in the Enterprise Console

First we add the class in the console.

Assign the class to the node

After creating the class in the console, we can apply it to a node. In my examples I’m assigning to a node cleverly named “centos5-64”.

Try the module in --noop mode on the CLI

The stahnma/epel module comes with an item in the test directory. These are for simple smoke-test type activities. In this example, we’ll run the test in noop mode to see what would happen if this were applied live.

I am running this command on my agent:

$ puppet agent -t --noop
info: Retrieving plugin
info: Loading facts in /etc/puppetlabs/puppet/modules/epel/lib/facter/os_maj_version.rb
info: Loading facts in /opt/puppet/share/puppet/modules/stdlib/lib/facter/facter_dot_d.rb
info: Loading facts in /opt/puppet/share/puppet/modules/stdlib/lib/facter/root_home.rb
info: Caching catalog for centos5-64
info: Applying configuration version '1341959009'
info: create new repo epel-testing-debuginfo in file /etc/yum.repos.d/epel-testing-debuginfo.repo
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - Testing - x86_64 - Debug (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/baseurl: current_value , should be http://download.fedora.redhat.com/pub/epel/testing/5/x86_64/debug (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/enabled: current_value , should be 0 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/failovermethod: current_value , should be priority (noop)
info: create new repo epel-source in file /etc/yum.repos.d/epel-source.repo
notice: /Stage[main]/Epel/Yumrepo[epel-source]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - x86_64 - Source (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-source]/mirrorlist: current_value , should be http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-5&arch=x86_64 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-source]/enabled: current_value , should be 0 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-source]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-source]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-source]/failovermethod: current_value , should be priority (noop)
info: create new repo epel in file /etc/yum.repos.d/epel.repo
notice: /Stage[main]/Epel/Yumrepo[epel]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - x86_64 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel]/mirrorlist: current_value , should be http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=x86_64 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel]/enabled: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel]/failovermethod: current_value , should be priority (noop)
notice: /Stage[main]/Epel/File[/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5]/ensure: current_value absent, should be file (noop)
info: create new repo epel-testing-source in file /etc/yum.repos.d/epel-testing-source.repo
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - Testing - x86_64 - Source (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/baseurl: current_value , should be http://download.fedora.redhat.com/pub/epel/testing/5/SRPMS (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/enabled: current_value , should be 0 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing-source]/failovermethod: current_value , should be priority (noop)
info: create new repo epel-debuginfo in file /etc/yum.repos.d/epel-debuginfo.repo
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - x86_64 - Debug (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/mirrorlist: current_value , should be http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-5&arch=x86_64 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/enabled: current_value , should be 0 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-debuginfo]/failovermethod: current_value , should be priority (noop)
info: create new repo epel-testing in file /etc/yum.repos.d/epel-testing.repo
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/descr: current_value , should be Extra Packages for Enterprise Linux 5 - Testing - x86_64  (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/baseurl: current_value , should be http://download.fedora.redhat.com/pub/epel/testing/5/x86_64 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/enabled: current_value , should be 0 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/gpgcheck: current_value , should be 1 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/gpgkey: current_value , should be file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5 (noop)
notice: /Stage[main]/Epel/Yumrepo[epel-testing]/failovermethod: current_value , should be priority (noop)
notice: Class[Epel]: Would have triggered 'refresh' from 37 events
notice: Stage[main]: Would have triggered 'refresh' from 1 events
notice: Finished catalog run in 2.39 seconds

Notice the use of the --noop flag here. Puppet’s noop, or simulation mode, allows us to see the changes that would occur without actually applying them. Without the --noop tag we would have made actual changes to our system—in this case the puppet master node would have been changed, and nothing else.

The yumrepo type in Puppet creates a separate file for each repository that is being configured (even if it is disabled). This can lead to a bit of output, but is nothing to worry about.

In the Enterprise Console (or Dashboard) you can see a report came in with an orange status of pending. This means there are changes to that would have been applied, but we ran with --noop set.

Peeling back the covers

Simplicity is largely what makes this module useful. Beyond the basic yumrepo resource types, this module includes two other slightly more advanced, albeit very common, components: a custom fact and a defined resource type.

The custom fact is used to determine the major release version of the Enterprise Linux variant we are operating on. Facter includes a fact ($operatingsystemrelease) that tells you something like 6.2. I wanted something that would just output ‘6’. If you have the Linux Standard Base (LSB) packages installed, there is a fact for that ($lsbmajdistrelease) however, the LSB packages pull in roughly 300 MB of stuff I didn’t want on the system. Additionally, this gives us a great example for a custom fact.

Facts are places in module-parent-directory/lib/facter. They are by convention named ‘factname’.rb. When pluginsync is enabled, this fact is distributed to the agents, and sent back to the master with the correct values prior to a catalog being compiled.

Let’s take a look at this custom fact.

# This is a simple fact to get the Major version of an OS without having to
# have the entire LSB suite installed.  LSB seems to pull in about 300 megs of
# stuff I often don't require. This fact is quick to load so it shouldn't be
# much of an issue.

Facter.add(:os_maj_version) do
  v = Facter.value(:operatingsystemrelease)
  setcode do
    v.split('.')[0].strip
  end
end

This fact is pretty simple. It take the value for an existing fact (:operatingsystemrelease) and truncates the value at the first decimal point. It then strips off any whitespace found in that string and returns it. Adding more facts to other modules can be this simple.

The defined type that is used in the EPEL module is an Exec resource. It tells Puppet to have RPM import a GPG for a repository unless the GPG key is already found in the RPM database. This follows our recommended practice of placing the defined resource type in its own file.

define epel::rpm_gpg_key($path) {
  # Given the path to a key, see if it is imported, if not, import it
  exec {  "import-$name":
    path      => '/bin:/usr/bin:/sbin:/usr/sbin',
    command   => "rpm --import $path",
    unless    => "rpm -q gpg-pubkey-`$(echo $(gpg --throw-keyids < $path) | cut --characters=11-18 | tr [A-Z] [a-z])`",
    logoutput => on_failure,
    require   => File[$path],
  }
}

By using $name in the resource title, it can be called multiple times without creating a conflicting resource inside the puppet graph. Additionally, we log output to the screen (or logs) if something would fail with the exec statement.

Apply the Module

From here, you can wait 30 minutes (by default) and Puppet will check in and setup EPEL on your system, or you can run Puppet from the command line (omitting the --noop flag this time).

On the agent we issue a Puppet run:

$ puppet agent -t
info: Loading facts in /etc/puppet/modules/epel/lib/facter/os_maj_version.rb
info: Caching catalog for centos6-64.localdomain
info: Applying configuration version '1341894174'
info: create new repo epel-testing-debuginfo in file /etc/yum.repos.d/epel-testing-debuginfo.repo
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/descr: descr changed '' to 'Extra Packages for Enterprise Linux 6 - Testing - x86_64 - Debug'
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/baseurl: baseurl changed '' to 'http://download.fedora.redhat.com/pub/epel/testing/6/x86_64/debug'
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/enabled: enabled changed '' to '0'
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/gpgcheck: gpgcheck changed '' to '1'
notice: /Stage[main]/Epel/Yumrepo[epel-testing-debuginfo]/gpgkey: gpgkey changed '' to 
...
'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6'
notice: Finished catalog run in 0.32 seconds
…

Now we should have EPEL enabled on the system. To check that out, you can simply search for a package found in EPEL.

$ yum search cdpr
Loaded plugins: fastestmirror, presto
Determining fastest mirrors
 * base: centos.mirror.facebook.net
 * epel: mirrors.solfo.com
 * extras: mirrors.cat.pdx.edu
 * updates: mirrors.cat.pdx.edu
base                                                     | 3.7 kB     00:00     
base/primary_db                                          | 4.5 MB     00:02     
epel                                                     | 4.0 kB     00:00     
epel/primary_db                                          | 4.6 MB     00:04     
extras                                                   | 3.0 kB     00:00     
extras/primary_db                                        | 6.3 kB     00:00     
updates                                                  | 3.0 kB     00:00     
updates/primary_db                                       |  92 kB     00:00     
============================== N/S Matched: cdpr ===============================
cdpr.x86_64 : Cisco Discovery Protocol Analyzer

  Name and summary matches only, use "search all" for everything.

You can see that we can search EPEL. It shows cdpr as a package that is available, and that is found in EPEL.

If you check back on the Enterprise Console (an hour or so later), you'll see some orange, blue and green. The orange remains from when we had pending changes on that node (noop). The blue happened when the Puppet run actually changed resources and created the EPEL yum repository files. Green just indicates Puppet ran and each resource was setup exactly as specified.

Conclusion

The stahnma/epel module is simple, but shows how simple it can be to solve some problems with Puppet:

  • Uses a custom fact
  • Uses a defined type
  • Performs very basic system configuration

Now you could easily model this for other yum repository configurations, or include this a dependency in your module sets.

Learn More:
Puppet sites use proprietary and third-party cookies. By using our sites, you agree to our cookie policy.