| Facter 3 and 4 behave inconsistently with respect to fact values that return nil vs empty strings summarized as below:
| Fact Type |
Facter 3 |
Facter 4 |
| custom legacy |
omitted |
omitted |
| custom structured |
nil |
nil |
| external legacy |
"" |
omitted |
| external structured |
omitted |
nil |
custom means the fact is defined using the Ruby API Facter.add external means the fact is defined as a JSON data file legacy means the fact returns a single value structured means the fact's value is a Hash Puppet always converts nil fact values to "", see PUP-11446, so the "external legacy" case means puppet 7 may omit a fact that was previously included when requesting a catalog. For example:
# puppet apply -e 'notice($external_legacy == undef)' |
Notice: Scope(Class[main]): false |
... |
# puppet apply --facterng -e 'notice($external_legacy == undef)' |
Warning: Unknown variable: 'external_legacy'. (line: 1, column: 8) |
Notice: Scope(Class[main]): true |
...
|
If you're using strict_variables then catalog compilation will fail (since the fact is missing):
# puppet apply --strict_variables --facterng -e 'notice($external_legacy == undef)' |
Error: Evaluation Error: Unknown variable: 'external_legacy'. (line: 1, column: 8) on node
|
The "external structured" case has the opposite problem. Previously the fact was omitted and now it will be present with an empty value (due to Puppet converting nil to ""):
# puppet apply -e 'notice($facts["external_structured"].keys)' |
Notice: Scope(Class[main]): [boolean, integer] |
... |
# puppet apply --facterng -e 'notice($facts["external_structured"].keys)' |
Notice: Scope(Class[main]): [null, integer, boolean] |
... |
# puppet apply --facterng -e 'notice($facts["external_structured"].values)' |
Notice: Scope(Class[main]): [, 42, false] |
... |
# puppet apply --facterng -e 'notice($facts["external_structured"].values[0] =~ String)' |
Notice: Scope(Class[main]): true
|
These might break puppet manifests that are not expecting to receive the "extra" key-value pair. Custom Legacy Facts Facter 3 and 4 both omit legacy facts with nil values when collecting all facts Facter.to_hash:
# cat custom/custom_legacy.rb |
Facter.add(:custom_legacy) { setcode { nil } } |
# /opt/puppetlabs/puppet/bin/facter -j --custom-dir /root/custom | grep custom_legacy |
# /opt/puppetlabs/puppet/bin/facter-ng -j --custom-dir /root/custom | grep custom_legacy |
#
|
One inconsistency is if you ask for the fact by name, Facter 3 returns a fact with an empty value, while Facter 4 returns nil:
# /opt/puppetlabs/puppet/bin/facter -j --custom-dir /root/custom custom_legacy |
{ |
"custom_legacy": "" |
} |
# /opt/puppetlabs/puppet/bin/facter-ng -j --custom-dir /root/custom custom_legacy |
{ |
"custom_legacy": null |
}
|
Custom Structured Facts Facter 3 and 4 are consistent when a structured fact contains a fact whose value is nil (the fact is present with a nil value)
# cat custom/custom_structured.rb |
Facter.add(:custom_structured) do |
setcode do |
{ |
"null" => nil, |
"integer" => 42, |
"boolean" => false |
} |
end |
end |
# /opt/puppetlabs/puppet/bin/facter -j --custom-dir /root/custom custom_structured |
{ |
"custom_structured": { |
"null": null, |
"integer": 42, |
"boolean": false |
} |
} |
# /opt/puppetlabs/puppet/bin/facter-ng -j --custom-dir /root/custom custom_structured |
{ |
"custom_structured": { |
"boolean": false, |
"integer": 42, |
"null": null |
} |
}
|
External Legacy Facts Facter 3 returns an empty string, while Facter 4 omits the fact:
# cat external/external_legacy.txt |
external_legacy= |
# /opt/puppetlabs/puppet/bin/facter -j --external-dir /root/external | grep external_legacy |
"external_legacy": "", |
# /opt/puppetlabs/puppet/bin/facter-ng -j --external-dir /root/external | grep external_legacy |
#
|
External Structured Facts Facter 3 omits structured facts whose values are nil, while Facter 4 returns the fact with a nil value:
# cat external/external_structured.json |
{ |
"external_structured": { |
"null": null, |
"integer": 42, |
"boolean": false |
} |
} |
# /opt/puppetlabs/puppet/bin/facter -j --external-dir /root/external external_structured |
{ |
"external_structured": { |
"boolean": false, |
"integer": 42 |
} |
} |
# /opt/puppetlabs/puppet/bin/facter-ng -j --external-dir /root/external external_structured |
{ |
"external_structured": { |
"boolean": false, |
"integer": 42, |
"null": null |
} |
}
|
|