Updating Linux Puppet Enterprise agent versions with puppet_agent

Happy New Year, everyone! I know that when I last blogged before the holiday, I was getting settled in with Jenkins, but I really needed to relax during the break so I had to hold off on that. I promise, I’ll get back to that soon, but in the meantime I encountered an issue that needed fixed and required a little more than the docs provided.

I ran into an issue recently with Puppet Enterprise agents that weren’t able to purge some resource types properly due to the use of Anchors. This is an issue with Puppet, not the module in question, and it was fixed in Puppet 4.4.0 but affected nodes were running older versions. Of course, rather than upgrade the agents by hand, I decided to automate it. Puppet has an Upgrading PE agents: *nix page that describes how to do this in a few ways. The latter options require manual effort, but the first option, via the module puppet_agent, can do this automatically for us. I diverged from the instructions a bit because I do my classifying with hiera rather than the PE Classifier and because there’s a missing step! (I’m trying to get that document updated, as well)

The guide says to install the module on the master and add some classification. To do this in a traditional roles and profiles setup using hiera as the classifier and with a monolithic controlrepo, we need to add the module to Puppetfile and .fixtures.yml, then add either a profile for puppet_agent or add it to a base profile. I chose the latter. Let’s add the module first:

# Puppetfile
mod 'puppetlabs-puppet_agent', '1.3.1'

# .fixtures.yml
fixtures:
  <snip>
  forge_modules:
    <snip>
    puppet_agent:
      repo: "puppetlabs/puppet_agent"
      ref: "1.3.1"

I’ve added the class to profile::base::linux (I haven’t had time to test it with Windows but assume it will work; look for a new post shortly to confirm that). We start with the spec tests first:

# spec/classes/profile/base__linux_spec.rb, added to the default context
  it { is_expected.to contain_class('puppet_agent') }

Then we update the profile class. I added a conditional flag in case we have nodes where we simply don’t want to manage this at all:

# dist/profile/manifests/base/linux.pp
class profile::base::linux (
  #...
  $manage_puppet   = true,  # Manage the puppet-agent including upgrades
) {
  if $manage_puppet {
    include puppet_agent
  }
  #...
}

If you run the tests now, you’ll get a lot of errors as puppet_agent provides a custom fact and expects it to exist, as well as a few other facts that you may not have mocked up. There are a number of ways to add these facts. I chose a global method to avoid forgetting to add the facts directly to a spec test where the class is indirectly called. To add the global facts, we need to update spec/spec_helper.rb and create spec/default_facts.yaml:

# spec/spec_helper.rb
RSpec.configure do |c|
  #...
  default_facts = {
   puppetversion: Puppet.version,
   facterversion: Facter.version
 }
 default_facts.merge!(YAML.load(File.read(File.expand_path('../default_facts.yml', __FILE__)))) if File.exist?(File.expand_path('../default_facts.yml', __FILE__))
 c.default_facts = default_facts
end

# spec/default_facts.yaml
#################
## puppet_agent #
#################
# custom fact
puppet_stringify_facts: false
# other variables
servername: 'puppet.example.com'
platform_tag: 'el-7-x86_64'

When running rspec now, the contents of spec/default_facts.yml are added to the default_facts hash, providing us with the facts that puppet_agent depends on. We can run spec tests and all our tests pass:

$ be rspec spec/classes/profile/base__linux_spec.rb

profile::base::linux
  on redhat-6-x86_64
    with defaults for all parameters
      #...
      should contain Class[puppet_agent]
  #...

Finished in 19.64 seconds (files took 4.67 seconds to load)
40 examples, 0 failures

We have one last thing to do! I mentioned a missing step in the documentation. By default, puppet_agent defaults to a version of present. The agent is already installed, so this doesn’t help us much with an upgrade unless we are coming from PE 3.8, where the puppet package was called puppet instead of puppet-agent. Since we’re already on 4.x, we need to increase that to a higher version. We have to specify a specific version as latest does not work. The version of Puppet Enterprise on my master includes puppet-agent 1.7.1, so I set that in my hiera’s least specific tier. There’s just one line you need to add:

puppet_agent::package_version: '1.7.1'

You can add this at a different tier, or have different values throughout; by default, the first match wins. Set this where you need it rather than mirroring my configuration. Also remember that we added a feature flag profile::base::linux::manage_puppet that you can set to false where you don’t want this class to be included at all.

We can commit our changes, push them upstream to a new environment, and test it on a node. Here’s the entire run’s output:

$ sudo puppet --version
4.3.2

$ sudo puppet agent -t --environment puppet_agent
Info: Using configured environment 'puppet_agent'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Info: Caching catalog for example.puppet.com
Info: Applying configuration version '1483481416'
Notice: /Stage[main]/Puppet_agent::Osfamily::Redhat/File[/etc/pki/rpm-gpg/RPM-GPG-KEY-puppetlabs]/ensure: defined content as '{md5}7b4ed31e1028f921b5c965df0a42e508'
Notice: /Stage[main]/Puppet_agent::Osfamily::Redhat/File[/etc/pki/rpm-gpg/RPM-GPG-KEY-puppet]/ensure: defined content as '{md5}16e3e148bc861ee66906e475f8342f81'
Notice: /Stage[main]/Puppet_agent::Osfamily::Redhat/Exec[import-RPM-GPG-KEY-puppet]/returns: executed successfully
Notice: /Stage[main]/Puppet_agent::Osfamily::Redhat/Yumrepo[pc_repo]/ensure: created
Info: changing mode of /etc/yum.repos.d/pc_repo.repo from 600 to 644
Notice: /Stage[main]/Puppet_agent::Install/Package[puppet-agent]/ensure: ensure changed '1.3.6-1.el7' to '1.7.1-1.el7'
Warning: /Stage[main]/Ssh::Knownhosts/Sshkey[othernode.example.com_dsa]: Anchor[ssh::server::end],Anchor[ssh::client::end] still depend on me -- not purging
Warning: /Stage[main]/Ssh::Knownhosts/Sshkey[othernode.example.com_rsa]: Anchor[ssh::server::end],Anchor[ssh::client::end] still depend on me -- not purging
Notice: Applied catalog in 211.20 seconds

$ sudo puppet --version
4.7.0

It can take a while to run, over 3 minutes(!) so don’t despair if it seems like it’s hanging. You can see I’m still getting the warnings about anchors, but that’s okay because that agent run was done with puppet 4.3.2. After running it again, I can see the purged resources being cleaned up:

$ sudo puppet agent -t --environment puppet_agent
Info: Using configured environment 'puppet_agent'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Info: Caching catalog for chi-build05.mss.local
Info: Applying configuration version '1483481701'
Notice: /Stage[main]/Puppet_agent::Osfamily::Redhat/Yumrepo[pc_repo]/enabled: enabled changed 'true' to 'True'
Notice: /Stage[main]/Docker::Repos/Yumrepo[docker]/gpgcheck: gpgcheck changed 'true' to 'True'
Notice: /Stage[main]/Ssh::Knownhosts/Sshkey[othernode.example.com_dsa]/ensure: removed
Info: Computing checksum on file /etc/ssh/ssh_known_hosts
Notice: /Stage[main]/Ssh::Knownhosts/Sshkey[othernode.example.com_rsa]/ensure: removed
Notice: /Stage[main]/Puppet_enterprise::Mcollective::Server/File[/etc/puppetlabs/mcollective/server.cfg]/content:
--- /etc/puppetlabs/mcollective/server.cfg      2016-11-17 02:18:50.332523423 +0000
+++ /tmp/puppet-file20170103-13188-1g2s6ai      2017-01-03 22:15:11.868383609 +0000
@@ -1,5 +1,5 @@

-# Centrally managed by Puppet version 4.3.2
+# Centrally managed by Puppet version 4.7.0
 # https://docs.puppetlabs.com/mcollective/configure/server.html

 # Connector settings (required):

Info: Computing checksum on file /etc/puppetlabs/mcollective/server.cfg
Info: /Stage[main]/Puppet_enterprise::Mcollective::Server/File[/etc/puppetlabs/mcollective/server.cfg]: Filebucketed /etc/puppetlabs/mcollective/server.cfg to puppet with sum f3dbe7e960ecd15ba6990196b4cc7d9d
Notice: /Stage[main]/Puppet_enterprise::Mcollective::Server/File[/etc/puppetlabs/mcollective/server.cfg]/content: content changed '{md5}f3dbe7e960ecd15ba6990196b4cc7d9d' to '{md5}188788f65505a9ae31bcd427cc9405c0'
Info: /Stage[main]/Puppet_enterprise::Mcollective::Server/File[/etc/puppetlabs/mcollective/server.cfg]: Scheduling refresh of Service[mcollective]
Notice: /Stage[main]/Puppet_enterprise::Mcollective::Service/Service[mcollective]: Triggered 'refresh' from 1 events
Notice: Applied catalog in 4.42 seconds

Mcollective does a little cleanup and for some reason true is converted to True in a few spots (I’m sure if I look up the release notes between 4.3.2 and 4.7.0, I’d find the cause if I were really interested) but future runs are stable, as expected.

We now have Puppet Enterprise agents that automatically receive the correct version on deployment and can be upgraded just through a single hiera update and waiting a while. When the master is upgraded in the future, you just need to bump the puppet_agent::package_version value to the new puppet-agent version. Enjoy!

3 thoughts on “Updating Linux Puppet Enterprise agent versions with puppet_agent

  1. Pingback: Updating Windows Puppet Enterprise agent versions with puppet_agent | rnelson0
  2. Pingback: Upgrading Puppet OpenSource Agents with puppet_agent and jlambert121/puppet | rnelson0
  3. Pingback: Upgrading Puppet Enterprise from 2016.4 to 2017.3 | rnelson0

Leave a comment