Installing packages from a third-party repository
Most often you will want to install packages from the main distribution repo, so a simple package resource will do:
package { 'exim4': ensure => installed }
Sometimes, you need a package that is only found in a third-party repository (an Ubuntu PPA, for example), or it might be that you need a more recent version of a package than that provided by the distribution, which is available from a third party.
On a manually-administered machine, you would normally do this by adding the repo source configuration to /etc/apt/sources.list.d
(and, if necessary, a gpg key for the repo) before installing the package. We can automate this process easily with Puppet.
How to do it…
In this example, we'll use the popular Percona APT repo (Percona is a MySQL consulting firm who maintain and release their own specialized version of MySQL, more information is available at http://www.percona.com/software/repositories):
- Create the file
modules/admin/manifests/percona_repo.pp
with the following contents:# Install Percona APT repo class admin::percona_repo { exec { 'add-percona-apt-key': unless => '/usr/bin/apt-key list |grep percona', command => '/usr/bin/gpg --keyserver hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A && /usr/bin/gpg -a --export CD2EFD2A | apt-key add -', notify => Exec['percona-apt-update'], } exec { 'percona-apt-update': command => '/usr/bin/apt-get update', require => [File['/etc/apt/sources.list.d/percona.list'], File['/etc/apt/preferences.d/00percona.pref']], refreshonly => true, } file { '/etc/apt/sources.list.d/percona.list': content => 'deb http://repo.percona.com/apt wheezy main', notify => Exec['percona-apt-update'], } file { '/etc/apt/preferences.d/00percona.pref': content => "Package: *\nPin: release o=Percona Development Team\nPin-Priority: 1001", notify => Exec['percona-apt-update'], } }
- Modify your
site.pp
file as follows:node 'cookbook' { include admin::percona_repo package { 'percona-server-server-5.5': ensure => installed, require => Class['admin::percona_repo'], } }
- Run Puppet:
root@cookbook-deb:~# puppet agent -t Info: Caching catalog for cookbook-deb Notice: /Stage[main]/Admin::Percona_repo/Exec[add-percona-apt-key]/returns: executed successfully Info: /Stage[main]/Admin::Percona_repo/Exec[add-percona-apt-key]: Scheduling refresh of Exec[percona-apt-update] Notice: /Stage[main]/Admin::Percona_repo/File[/etc/apt/sources.list.d/percona.list]/ensure: defined content as '{md5}b8d479374497255804ffbf0a7bcdf6c2' Info: /Stage[main]/Admin::Percona_repo/File[/etc/apt/sources.list.d/percona.list]: Scheduling refresh of Exec[percona-apt-update] Notice: /Stage[main]/Admin::Percona_repo/File[/etc/apt/preferences.d/00percona.pref]/ensure: defined content as '{md5}1d8ca6c1e752308a9bd3018713e2d1ad' Info: /Stage[main]/Admin::Percona_repo/File[/etc/apt/preferences.d/00percona.pref]: Scheduling refresh of Exec[percona-apt-update] Notice: /Stage[main]/Admin::Percona_repo/Exec[percona-apt-update]: Triggered 'refresh' from 3 events
How it works…
In order to install any Percona package, we first need to have the repository configuration installed on the machine. This is why the percona-server-server-5.5
package (Percona's version of the standard MySQL server) requires the admin::percona_repo
class:
package { 'percona-server-server-5.5': ensure => installed, require => Class['admin::percona_repo'], }
So, what does the admin::percona_repo
class do? It:
- Installs the Percona APT key with which the packages are signed
- Configures the Percona repo URL as a file in
/etc/apt/sources.list.d
- Runs
apt-get update
to retrieve the repo metadata - Adds an APT pin configuration in
/etc/apt/preferences.d
First of all, we install the APT key:
exec { 'add-percona-apt-key': unless => '/usr/bin/apt-key list |grep percona', command => '/usr/bin/gpg --keyserver hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A && /usr/bin/gpg -a --export CD2EFD2A | apt-key add -', notify => Exec['percona-apt-update'], }
The unless
parameter checks the output of apt-key list
to make sure that the Percona key is not already installed, in which case we need not do anything. Assuming it isn't, the command
runs:
/usr/bin/gpg --keyserver hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A && /usr/bin/gpg -a --export CD2EFD2A | apt-key add -
This command retrieves the key from the GnuPG keyserver, exports it in the ASCII format, and pipes this into the apt-key add
command, which adds it to the system keyring. You can use a similar pattern for most third-party repos that require an APT signing key.
Having installed the key, we add the repo configuration:
file { '/etc/apt/sources.list.d/percona.list': content => 'deb http://repo.percona.com/apt wheezy main', notify => Exec['percona-apt-update'], }
Then run apt-get update
to update the system's APT cache with the metadata from the new repo:
exec { 'percona-apt-update': command => '/usr/bin/apt-get update', require => [File['/etc/apt/sources.list.d/percona.list'], File['/etc/apt/preferences.d/00percona.pref']], refreshonly => true, }
Finally, we configure the APT pin priority for the repo:
file { '/etc/apt/preferences.d/00percona.pref': content => "Package: *\nPin: release o=Percona Development Team\nPin-Priority: 1001", notify => Exec['percona-apt-update'], }
This ensures that packages installed from the Percona repo will never be superseded by packages from somewhere else (the main Ubuntu distro, for example). Otherwise, you could end up with broken dependencies and be unable to install the Percona packages automatically.
There's more...
The APT package framework is specific to the Debian and Ubuntu systems. There is a forge module for managing apt repos, https://forge.puppetlabs.com/puppetlabs/apt. If you're on a Red Hat or CentOS-based system, you can use the yumrepo
resources to manage RPM repositories directly:
http://docs.puppetlabs.com/references/latest/type.html#yumrepo