Use Envpuppet To Test with Multiple Puppet Versions

Sometimes you need to flip quickly and easily from one Puppet version to the next. For example, you may need to test new Puppet versions before an upgrade; identify the source of behavioral changes after an upgrade; or be able to definitively track bugs to a specific change.

Manually installing and upgrading specific versions is tedious, and also fails to provide the level of granularity required by tasks like identifying regressions in the Puppet source code. A much more flexible approach is to run Puppet from a Git clone of the source code, which allows any release in the version history to be checked out.

Configuring a machine to run Puppet from source is easy, thanks to a neat script named envpuppet that you can find in the Puppet repository. The flexibility envpuppet offers makes it a valuable addition to the toolkit of any developer working with a puppetized infrastructure.

Creating a Vagrant Environment with Envpuppet

A simple envpuppet setup consists of a single directory that contains clones of the Puppet, Facter and Hiera repositories. This directory can be mounted inside of virtual machines to create isolated testing environments. Testing Puppet behavior inside a VM is a good idea, and prevents unwanted alterations to the configuration of the host system.

The following shell commands can be used to create repository clones under ~/src/puppetlabs:

mkdir -p ~/src/puppetlabs`
cd ~/src/puppetlabs`

# Current versions as of this posting. Update as necessary:
git clone https://github.com/puppetlabs/puppet --branch 3.4.2
git clone https://github.com/puppetlabs/facter --branch 1.7.4
git clone https://github.com/puppetlabs/hiera --branch 1.3.0

The creation and configuration of virtual machines is easily handled by Vagrant. The Vagrantfile listed below sets up an Ubuntu VM, mounts the source directory built above, and adds a fragment to/etc/profile.d that activates envpuppet:

Vagrant.configure('2') do |config|
  config.vm.define :testpuppet do |node|
    # Create VMs running Ubuntu 12.04 with v4.2.10 of the VirtualBox guest
    # extensions and no existing configuration management installations
    # (puppet, chef, etc)
    #
    # An index of pre-built boxes for various operating systems can be found
    # at:
    #
    #   http://puppet-vagrant-boxes.puppetlabs.com
    node.vm.box_url = 'http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-     vbox4210-nocm.box'
    node.vm.box = 'ubuntu-1204-x64-vbox4210-nocm'
    # Install default ruby for Ubuntu
    node.vm.provision :shell, :inline => 'command -v ruby >/dev/null 2>&1 || { apt-get update &&     apt-get install -y ruby; }'

    node.vm.hostname = 'testpuppet.boxnet.vlan'

    node.vm.synced_folder '~/src/puppetlabs', '/puppetlabs'

    # Write a fragment to /etc/profile.d that activates envpuppet
    node.vm.provision :shell, :inline => <<-EOS
tee /etc/profile.d/envpuppet.sh << "EOF"
export ENVPUPPET_BASEDIR=/puppetlabs
eval $($ENVPUPPET_BASEDIR/puppet/ext/envpuppet)
EOF
    EOS

    # The puppet user and group are required to run Puppet 2.7.0 -- 3.1.0.
    node.vm.provision :shell, :inline => <<-EOS
puppet resource group puppet ensure=present
puppet resource user puppet ensure=present gid=puppet
    EOS

  end
end

The Vagrantfile also ensures a puppet user and group are present on the VM. These resources are required to run any Puppet version from 2.7.0 through 3.1.0.

Using Envpuppet Inside a Vagrant Environment

To use the test environment, you execute Puppet actions inside the VM while manipulating the Git repositories shared from the host. In the following examples, actions taken in the VM will be prefixed with vm$ and actions taken on the host will be prefixed with host$.

In Puppet versions prior to 3.3.0, there was an undocumented feature that allowed multiple packages to be installed by assigning an array to the name parameter of a Package resource:

# multiple_packages.pp
package{'editor-support':
  ensure => latest,
  name   => ['exuberant-ctags', 'vim'],
}

During the development of Puppet 3.3.0, a refactor altered the behavior of this feature, and the feature was officially removed in Puppet 3.4.0. We can investigate the changes in behavior by checking out the 3.2.4 release on the host and applying the multiple_packages.pp manifest in the VM:

host$ cd ~/src/puppetlabs/puppet
host$ git checkout 3.2.4

vm$ sudo -i
vm$ puppet --version
3.2.4

vm$ puppet apply -e 'package{["exuberant-ctags", "vim"]: ensure => purged}'
Notice: /Stage[main]//Package[vim]/ensure: ensure changed '2:7.3.429-2ubuntu2.1' to 'purged'
Notice: Finished catalog run in 1.13 seconds

vm$ puppet apply /vagrant/multiple_packages.pp
Notice: /Stage[main]//Package[editor-support]/ensure: ensure changed 'purged' to 'latest'
Notice: Finished catalog run in 2.77 seconds

vm$ puppet apply /vagrant/multiple_packages.pp
Notice: Finished catalog run in 0.21 seconds

The above example sets the initial condition for this experiment by ensuring both the exuberant-ctags and vim packages are removed. The first Puppet run causes the packages to be re-installed in order to sync the state of the system with the Package resource defined in multiple_packages.pp. The second Puppet run results in no changes because the system state is still in sync with the resource definition.

Upon switching to Puppet 3.3.0, a change in behavior can be observed:

host$ git checkout 3.3.0

vm$ puppet --version
3.3.0

vm$ puppet apply /vagrant/multiple_packages.pp
Notice: Compiled catalog for testpuppet.boxnet.vlan in environment production in 0.62 seconds
Notice: /Stage[main]//Package[editor-support]/ensure: ensure changed 'purged' to 'latest'
Notice: Finished catalog run in 0.92 seconds

vm$ puppet apply /vagrant/multiple_packages.pp
Notice: Compiled catalog for testpuppet.boxnet.vlan in environment production in 0.48 seconds
Notice: /Stage[main]//Package[editor-support]/ensure: ensure changed 'purged' to 'latest'
Notice: Finished catalog run in 0.74 seconds

When applying the multiple_packages.pp manifest under Puppet 3.3.0, we would expect no changes to be reported, as the state of these two packages has not changed. However, Puppet now attempts to sync the resource on each run, which indicates the Package resource declared in multiple_packages.pp is no longer functioning as intended.

Switching to Puppet 3.4.0 shows that the misbehavior in 3.3.0 has turned into an error:

host$ git checkout 3.4.0

vm$ puppet --version
3.4.0

vm$ puppet apply /vagrant/multiple_packages.pp
Notice: Compiled catalog for testpuppet.boxnet.vlan in environment production in 0.64 seconds
Error: Parameter name failed on Package[editor-support]: Name must be a String not Array at     /vagrant/multiple_packages.pp:4
Wrapped exception:
Name must be a String not Array

Testing with multiple Puppet versions showed us that the manifest will need to be modified in order for Puppet versions newer than 3.2.4 to correctly manage the exuberant-ctags and vim packages it declares.

Next Steps

The Package example shows how envpuppet makes switching between Puppet versions as easy as running git checkout. The methodology can be extended by using git bisect instead of git checkout to identify the exact commit that caused a change in Puppet behavior. You can also expand the Vagrant environment to include multiple VMs that all share the same Puppet source. Such a collection of machines can be used to simulate the upgrade of a network of masters and agents.

Now go have some fun, knowing you can safely experiment with multiple Puppet versions inside a virtual environment.

Learn More

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