-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Puppet 8 Compatibility
We recently announced our plans for Puppet 8 and this document describes steps you can take to prepare. The first section describes possible compatibility issues with Ruby 3.2, while the second describes issues with Puppet 8..
To verify your code is Ruby 3.2 compatible, run tests locally against Ruby 3.2:
rbenv install 3.2.0
rbenv shell 3.2.0
rm Gemfile.lock
bundle
bundle exec rake spec
And add it to your Github Action test matrix. For example, Puppet did this for Ubuntu 22.04 and Windows.
Note that if you are attempting to do this on Centos 7, the version of gcc shipped with the OS is too old (gcc 4 vs. 6). Follow the instructions at https://linuxize.com/post/how-to-install-gcc-compiler-on-centos-7/, and this will allow you to install Ruby 3.2.
Here are common "gotchas" you may run into during this process:
Changes to the way keyword and positional arguments are handled in ruby 3 are extensively documented in this post: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
Note that this will happen at run time (not when the code is loaded). Errors will usually be "wrong number of arguments".
Example commit: https://github.com/puppetlabs/bolt/commit/acda807a1c0c00f8221ebad8c7acd446dda8ae4f
Broadly the psych library support for parsing has included several breaking changes. Some common ones:
Legacy functions used to determine psych version: https://github.com/puppetlabs/bolt/pull/3093/commits/d43a071894fcb88267cb2116e7d3486d7af5acd9
YAML#safe_load
positional vs named arguments:
https://github.com/puppetlabs/bolt/pull/3093/commits/e04a399c3324da506a0df4367a1b56938e89863a
These are now standardized to exist?
.
https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/
Example commit: https://github.com/puppetlabs/puppet/commit/a94db64910381add4428a7654d867ad023d27844
These are now standardized as Etc::Passwd
and Etc::Group
respectively.
Example commit: https://github.com/puppetlabs/puppet/commit/dd3df54c190cf017f62c9292ccb3cc5cb21230f1
This was extracted into a separate sorted_set gem. Consider using Set
or perhaps .uniq.sort
on a plain array.
The Kernel#taint
and Kernel#untaint
methods were removed.
https://bugs.ruby-lang.org/issues/16131
Versions of the fast-gettext
gem prior to 2.1
call Kernel#untaint
and therefore won't run on Ruby 3.2 This also affects modules that depend on the gem directly or transitively through gettext-setup
or r10k
. You'll want to update to fast-gettext 2.1
or later.
Example commits: https://github.com/puppetlabs/r10k/commit/cb0a34638f72e0a96c0f2e322d084fb9b1cead14 https://github.com/puppetlabs/gettext-setup-gem/commit/f4b292c51d2c72e76515f3b81d5ebd379a2bbda8
Passing positional arguments to ERB.new
is no longer allowed, so you'll have to change:
-ERB.new(content, 0, '-')
+ERB.new(content, trim_mode: '-')
Earlier versions of rspec-mocks incorrectly verified expectations when passing positional arguments to a method that accepted keyword arguments and vice-versa. Use rspec-* 3.12.2 or later when testing against Ruby 3.2. Note that the "rspec" gem only has a 3.12.0 version, but has a dependency on rspec-core, rspec-expectations, and rspec-mocks that will use the latest Z of these gems, so you should not need to specify them explicitly unless you already are.
Earlier versions of rake called FileUtils
with an options hash, but it only accept keyword arguments. This resulted in failures like:
`touch': wrong number of arguments (given 2, expected 1)
A number of issues exist in 13.0.0 and 13.0.5, so use 13.0.6 or greater.
Example commit: https://github.com/puppetlabs/facter/commit/30061cc5bc7694ef0237d1cdf25dc1321849e1f3
Puppet 8 vendors OpenSSL 3. To verify your code works as expected, we recommend testing against ubuntu-22.04
in your github action, since the OS ships with OpenSSL 3. The windows
github runner for ruby 3.2 also ships with OpenSSL 3:
Prior to ruby 3.0, Dir.glob returned filenames in non-deterministic order. In ruby 3.0 and up, the method returns sorted filenames by default. This can lead to subtle changes in behavior when upgrading from ruby 2.7. Though the resulting behavior will be deterministic moving forward.
https://bugs.ruby-lang.org/issues/8709
If you have a puppet module, then you will want to follow this process to verify it will run on Puppet 8:
- Update
metadata.json
to allow puppet 8.0, for example"version_requirement": ">= 6.0.0 < 9.0.0"
- Run
pdk update
to update the module's templates. You'll need to use template versions later than 2.6.0 to remove the dependency onpuppet-module-gems
. - Run unit tests against puppet 8 gem, either from a local checkout or github:
export PUPPET_GEM_VERSION=https://github.com/puppetlabs/puppet#main rm Gemfile.lock bundle install bundle exec rake spec
- Run acceptance tests against nightly puppet-agent packages (the latter is coming soon). Alternatively, test against the last passing puppet-agent build, if you have access to that.
Here is a list of issues your module may run into during this process and steps to remediate.
By default, puppet 8 agents will no longer send legacy facts to the server, so those facts cannot be referenced in puppet code, ERB & EPP templates nor hiera configuration. To check for legacy facts in puppet code, we recommend using the legacy_facts
puppet-lint plugin.
Note the check will only detect legacy facts in puppet code. ERB/EPP templates and hiera configuration must be checked manually.
Example commit to puppet code in puppetlabs-ntp.
Example change to ERB template:
-<%= $fqdn %>
+<%= $facts.dig("networking","fqdn") %>
Example change to hiera config.yaml:
-os/%{osfamily}.yaml
+os/%{facts.os.family}.yaml
It is possible to restore puppet's 7.x behavior by setting include_legacy_facts=true
in puppet.conf
.
Puppet now defaults strict_variables=true
and strict=error
. As a result, puppet code like the following will not compile. This assumes var
is the name of an undefined variable:
notice($var)
Nor will code that performs coersions like:
notice("1" + 1)
In previous versions of Puppet, facts and variables were conflated in Hiera lookups. This meant that many hierarchies reference legacy facts as top-level variables, which is problematic now because referencing an undefined variable in a hiera lookup will now fail:
hierarchy:
- name: "missing"
path: "%{var}.yaml"
However, lookup will continue to work as expected for undefined facts, since that's what allows optional hierarchy levels to exist. For example, if the fact is missing, then the lookup will fall through to common.yaml
:
hierarchy:
- name: "overrides"
path: "%{facts.optional}.yaml"
- name: "common"
path: "common.yaml"
It is possible to restore puppet's 7.x behavior, by setting strict=warning
and/or strict_variables=false
in puppet.conf
.
The hiera
gem no longer ships in puppet-agent 8 packages. If you have a v3 backend that extends Hiera::Backend
or a hiera v5 data provider that delegates to hiera v3, then you'll need to update the backend to hiera v5. Alteratively, you can install the hiera
gem in puppetserver's JRuby and reload puppetserver:
package { 'puppetserver-hiera':
ensure => present,
name => 'hiera',
provider => puppetserver_gem
}
~> Service[puppetserver]
And install the hiera
gem into the agent's ruby so that puppet lookup
continues to work:
package { 'puppet-hiera':
ensure => present,
name => 'hiera',
provider => puppet_gem
}
Puppet 8 will no longer vendor PSON:
PSON is a variant of JSON that puppet uses for serializing data to transmit across the network or store on disk. Whereas JSON requires that the serialized form is valid unicode (usually UTF-8), PSON is 8-bit ASCII, which allows it to represent arbitrary byte sequences in strings. PSON was forked from upstream pure JSON v1.1.9 and patches were added to allow binary data.
PSON is implemented in ruby without native extensions, so it's much slower and memory intensive than JSON or MessagePack. And PSON hasn't been updated to keep up with changes made in the upstream pure JSON library. Also if binary data is accidentally added to the catalog, such as trying to manage a Kerberos keytab file, and the catalog contains Deferred
, Sensitive
, etc data types, then the agent run will downgrade to PSON and fail.
In Puppet 6, we enabled "rich data" support by default between agents and servers. This is what enables Deferred
functions to be evaluated on the agent. Puppet also supports a Binary
data type, so there isn't any reason to use PSON anymore. For example, to distribute small binary content, you can use the binary_file
function.
The PSON gem monkey patches core Ruby classes like Hash
, Array
, String
, etc. This is why it's possible to call Hash#to_pson
. Note JSON and MessagePack do the same thing with to_json
and to_msgpack
, respectively. This means in Puppet 8, the to_pson
method will not be defined on core Ruby classes.
Puppet extensions like termini, functions, report processors, etc can check if PSON is enabled by checking the puppet setting:
if Puppet[:preferred_serialization_format] == "pson"
We extracted the PSON code into a separate repo and published the puppet-pson
gem to rubygems.org. PSON can be re-enabled by installing the gem on agents and servers (similar to how Hiera 3 is being handled) and configuring the preferred_serialization_format
setting.