Yesterday, I tackled upgrading Linux Puppet Enterprise agents with puppet_agent and said I would give Windows agents a try next. It’s simultaneously extremely easy and really difficult to accomplish this! On the manifest side, it’s as simple as including the class in a profile for Windows agents. On the rspec side, we need to add a lot of custom facts and even mock up some functions. I also encountered an issue with version 1.3.1 that broke my rspec tests. Version 1.3.2 was released in February 2017 to address that.
As usual, let’s start with the rspec test updates. Here’s the starting tests and manifest for an empty profile::base::windows
, where nothing is really managed in the base profile yet.
# spec/classes/profile/base__windows_spec.rb require 'spec_helper' describe 'profile::base::windows', :type => :class do let :facts do { :kernel => 'windows', :operatingsystem => 'windows', :operatingsystemrelease => '2012 R2', :puppetversion => '4.3.1', } end context 'with defaults for all parameters' do it { is_expected.to create_class('profile::base::windows') } end end # dist/profile/manifests/base/windows.pp class profile::base::windows { }
There’s nothing special here. The tests pass, however. Here’s a first pass at the updates, which will generate a lot of failures in testing:
# spec/classes/profile/base__windows_spec.rb require 'spec_helper' describe 'profile::base::windows', :type => :class do let :facts do { :kernel => 'windows', :operatingsystem => 'windows', :operatingsystemrelease => '2012 R2', :puppetversion => '4.3.1', } end context 'with defaults for all parameters' do it { is_expected.to create_class('profile::base::windows') } it { is_expected.to contain_class('puppet_agent') } end end # dist/profile/manifests/base/windows.pp class profile::base::windows ( $manage_puppet_agent = true, # Manage the puppet agent on nodes ) { if $manage_puppet_agent { include puppet_agent } }
Right now, the manifest applies cleanly! If you’ve set your puppet_agent::package_version
in hiera where it will apply to Windows agents, they’ll get upgraded smoothly. However, your tests are going to start turning red for a few reasons. There are custom facts from puppet_agent
that we need to provide values to. For Windows, it also depends on some functions from the master, so we have to mock up the functions and return values. There are also a few other Windows-related facts that the module cares about that probably aren’t in your custom facts setup, even if you switch to using rspec-puppet-facts
to get a majority of Windows facts, as I did. Here’s the rewritten test:
# spec/classes/profile/base__windows_spec.rb require 'spec_helper' aio_build = '1.3.6' # Corresponds to puppet 4.3.6 describe 'profile::base::windows', :type => :class do on_supported_os.each do |os, facts| next unless facts[:kernel] == 'windows' context "on #{os}" do # Required to mock up functions puppet_agent relies on before (:each) do Puppet::Parser::Functions.newfunction(:pe_build_version, type: :rvalue) do |args| '4.0.0' end Puppet::Parser::Functions.newfunction(:pe_compiling_server_aio_build, type: :rvalue) do |args| aio_build end end let (:appdata) { 'C:\ProgramData' } let (:facts) { facts.merge( clientcert: 'puppet_agent_windows', # required for puppet_agent common_appdata: appdata, puppet_confdir: "#{appdata}/PuppetLabs/puppet/etc", mco_confdir: "#{appdata}/Puppetlabs/mcollective/etc", is_pe: true, aio_agent_version: aio_build, env_temp_variable: 'C:\tmp', puppet_master_server: 'puppet.example.com', puppet_agent_pid: 42, puppet_client_datadir: 'C:/ProgramData/PuppetLabs/puppet/cache/client_data' ) } context 'with defaults for all parameters' do it { is_expected.to create_class('profile::base::windows') } it { is_expected.to contain_class('puppet_agent') } end end end end
We’re almost there. If you run rspec now, you’ll still get some errors:
$ bundle exec rspec spec/classes/profile/base__windows_spec.rb [Coveralls] Set up the SimpleCov formatter. [Coveralls] Using SimpleCov's default settings. profile::base::windows on windows-2012 R2-x64 with defaults for all parameters should contain Class[profile::base::windows] (FAILED - 1) should contain Class[puppet_agent] (FAILED - 2) Failures: 1) profile::base::windows on windows-2012 R2-x64 with defaults for all parameters should contain Class[profile::base::windows] Failure/Error: include puppet_agent Puppet::PreformattedError: Evaluation Error: Unknown variable: '::puppet_agent::params::_source'. at /home/rnelson0/puppet/controlrepo/spec/fixtures/modules/puppet_agent/manifests/init.pp:47:22 on node build.nelson.va ...
There are two contributing problems to this. The one we can workaround is that in Puppet 4, strict_variables
defaults to enabled. When $puppet_agent::params::_source
is not set but referenced, it generates an error. To get around that, we provide an environment variable when running the test:
$ STRICT_VARIABLES="no" bundle exec rspec spec/classes/profile/base__windows_spec.rb [Coveralls] Set up the SimpleCov formatter. [Coveralls] Using SimpleCov's default settings. profile::base::windows on windows-2012 R2-x64 with defaults for all parameters should contain Class[profile::base::windows] should contain Class[puppet_agent] Finished in 2.26 seconds (files took 1.99 seconds to load) 2 examples, 0 failures
Of course, that’s just a surface error. The real issue is that $_source
is not populated for the windows osfamily. There are a few other variables that are not set before usage for Windows, so you may see rspec failing on those variables before $puppet_agent::params::_source
. PR203 aims to fix all of these unset variables for Windows. Until then, you’ll need to use the STRICT_VARIABLES="no"
workaround or live with a few red marks in your testing.
Now that we have a working manifest and test, we can have a Windows agent check in against the environment and get an upgrade. Launch Start Command Prompt with Puppet
as an administrator and check in from there:
C:\Windows\system32>puppet --version 4.3.2 C:\Windows\system32>puppet agent -t --environment puppet_agent Info: Using configured environment 'puppet_agent' Info: Retrieving pluginfacts Info: Retrieving plugin Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/facter/env_temp_variable.rb]/ensure: defined content as '{md5}cdbfcfd64baae73ea09d5e5258eaafe1' Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/facter/mco_config.rb]/ensure: defined content as '{md5}935de31c8b94826f513a930434ca98d8' Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/facter/puppet_agent_pid.rb]/ensure: defined content as '{md5}77e8c25824589f5e62b279698a25e78c' Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/facter/settings.rb]/ensure: defined content as '{md5}9131d59ebd9768b7410dbb835e7a1f2a' Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/puppet/parser/functions/uri_host_from_string.rb]/ensure: defined content as '{md5}97b3d860d1b78909d38e17bfa9932874' Notice: /File[C:/ProgramData/PuppetLabs/puppet/cache/lib/puppet/parser/functions/windows_native_path.rb]/ensure: defined content as '{md5}ffaf8b3778cd9be2a7d98ea51d14cd5e' Info: Loading facts Info: Caching catalog for windows.example.com Info: Applying configuration version '1483544760' Notice: /Stage[main]/Puppet_agent::Prepare::Puppet_config/Ini_setting[main/pluginsync]/ensure: removed Notice: /Stage[main]/Puppet_agent::Prepare::Package/File[C:\ProgramData\Puppetlabs\packages]/ensure: created Notice: /Stage[main]/Puppet_agent::Prepare::Package/File[C:\ProgramData\Puppetlabs\packages\puppet-agent-x64.msi]/ensure: defined content as '{sha256lite}01009e50abac71f031a3204235a9864fe3be292d602cef645fe1a47ea8672dbd' Notice: /Stage[main]/Puppet_agent::Windows::Install/File[C:\Users\rnelson0\AppData\Local\Temp\install_puppet.bat]/ensure: defined content as '{md5}5992d0057b05bce4b3b9393b22bc6efe' Notice: /Stage[main]/Puppet_agent::Windows::Install/Exec[install_puppet.bat]/returns: executed successfully Notice: /Stage[main]/Puppet_agent::Windows::Install/Exec[fix inheritable SYSTEM perms]/returns: executed successfully Notice: Applied catalog in 10.35 seconds C:\Windows\system32>puppet --version 'puppet' is not recognized as an internal or external command, operable program or batch file.
That seems scary, but it’s not! We just need to close the command prompt and launch Start Command Prompt with Puppet
as administrator again. You’ll notice it has a new icon from the upgraded puppet agent version. The command prompt environment changed slightly and the new one sees puppet as we would expect:
C:\Windows\system32>puppet --version 4.7.0
You’re almost ready to merge these changes to production so that you can keep your Windows and Linux agents up to date! You will need to update your CI tests to disable STRICT_VARIABLES
, test using a fork of the puppet_agent
module (my branch is here), or maybe even delay merging until PR203 is merged. I definitely would not suggest any option that results in CI tests going red, as that will prevent you from finding regressions in the future – and may even sabotage overall CI efforts if people decide they can’t trust it! It may make sense to split the Windows and Linux commits into two branches and only merge the Linux changes right now. You’ll have to figure out what works for your organization.
This was a little more painful than I imagined, and somewhat annoying that the Windows changes need delayed or implemented with temporary workarounds, but the up front work should save a lot of work later. Hopefully this is helpful to your efforts, as well. Thanks!
2 thoughts on “Updating Windows Puppet Enterprise agent versions with puppet_agent”