How to Prioritize Yum Repository Configuration in Puppet Before Package Installation


1 views

When managing package installations across multiple servers with Puppet, you'll often encounter situations where specific repositories must be configured before packages can be installed. This is particularly common with specialized repositories like IUS Community that provide updated versions of common packages.

Puppet offers several ways to control execution order. The most straightforward method is using resource relationships with the require metaparameter:

# First, ensure the repository package is installed
package { 'ius-release':
  ensure   => 'installed',
  provider => 'rpm',
  source   => 'https://repo.ius.io/ius-release-el7.rpm',
}

# Then make all other packages depend on it
Package {
  require => Package['ius-release'],
}

package { ['php72u', 'python36u']:
  ensure => 'installed',
}

For more complex scenarios, Puppet stages allow you to create execution phases:

stage { 'repo_setup':
  before => Stage['main'],
}

class { 'yum_repos':
  stage => 'repo_setup',
}

class yum_repos {
  package { 'ius-release':
    ensure   => 'installed',
    provider => 'rpm',
    source   => 'https://repo.ius.io/ius-release-el7.rpm',
  }
}

The anchor pattern helps manage dependencies between classes without using stages:

class repo_setup {
  package { 'ius-release':
    ensure   => 'installed',
    provider => 'rpm',
    source   => 'https://repo.ius.io/ius-release-el7.rpm',
  }
  
  anchor { 'repo_setup::begin': }
  anchor { 'repo_setup::end': }
  
  Anchor['repo_setup::begin'] -> Package['ius-release'] -> Anchor['repo_setup::end']
}

class my_app {
  require repo_setup
  package { 'php72u': 
    ensure => 'installed',
  }
}

When implementing repository-first configurations:

  • Always verify repository URLs and GPG keys
  • Consider using a local repository mirror for large deployments
  • Test repository configurations in a staging environment first
  • Monitor for repository changes that might break your configurations

For complex scenarios with multiple repositories, use a defined type:

define custom_repo(
  $repo_url,
  $gpg_key
) {
  package { $name:
    ensure   => 'installed',
    provider => 'rpm',
    source   => $repo_url,
  }
  
  file { "/etc/pki/rpm-gpg/${name}-key":
    source => $gpg_key,
    before => Package[$name],
  }
}

custom_repo { 'ius':
  repo_url => 'https://repo.ius.io/ius-release-el7.rpm',
  gpg_key  => 'puppet:///modules/repos/ius-key',
}

When managing RHEL/CentOS systems with Puppet, we often encounter a chicken-and-egg problem: we need custom repositories configured before installing packages, but Puppet's resource evaluation order isn't inherently sequential. Here's how to enforce proper ordering.

The simplest approach uses Puppet's relationship metaparameters. For IUS Community Repo setup:

# Install EPEL first (dependency for IUS)
package { 'epel-release':
  ensure => installed,
  before => Yumrepo['ius'],
}

yumrepo { 'ius':
  ensure   => present,
  descr    => 'IUS Community Repository',
  baseurl  => 'https://repo.ius.io/7/$basearch/',
  gpgkey   => 'https://repo.ius.io/RPM-GPG-KEY-IUS-7',
  gpgcheck => 1,
  before   => Package['php73u'],
}

For more complex environments, leverage Puppet stages:

stage { 'repo_setup': 
  before => Stage['main'],
}

class { 'ius_repo':
  stage => 'repo_setup',
}

class ius_repo {
  package { 'epel-release':
    ensure => installed,
  }
  
  yumrepo { 'ius':
    # ... (same attributes as above)
  }
}

When working with modules, the anchor pattern ensures proper ordering:

class profile::base::repos {
  # IUS repo resources here
  
  anchor { 'profile::base::repos::begin': }
  anchor { 'profile::base::repos::end': }
  
  Anchor['profile::base::repos::begin'] -> Package['epel-release'] -> Yumrepo['ius'] -> Anchor['profile::base::repos::end']
}

class profile::php {
  require profile::base::repos
  # PHP packages here
}

Here's a production-ready example managing both IUS and EPEL:

class profile::yum_repos {
  $repos = {
    'epel' => {
      ensure   => 'present',
      descr    => 'EPEL Repository',
      baseurl  => 'https://download.fedoraproject.org/pub/epel/7/$basearch',
      gpgkey   => 'https://download.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7',
      gpgcheck => '1',
    },
    'ius'  => {
      ensure   => 'present',
      descr    => 'IUS Community Repository',
      baseurl  => 'https://repo.ius.io/7/$basearch/',
      gpgkey   => 'https://repo.ius.io/RPM-GPG-KEY-IUS-7',
      gpgcheck => '1',
      require  => Yumrepo['epel'],
    }
  }
  
  create_resources('yumrepo', $repos)
  
  package { 'epel-release':
    ensure => installed,
    before => Yumrepo['epel'],
  }
  
  exec { 'clean_yum_cache':
    command     => '/usr/bin/yum clean all',
    refreshonly => true,
    subscribe   => Yumrepo['ius'],
  }
}

After implementation, verify with:

puppet agent -t --noop | grep -E '(Yumrepo|Package)'
yum repolist | grep -i ius

Common issues to watch for:

  • Network connectivity during initial repo setup
  • GPG key verification failures
  • Conflicts with existing repository definitions