Jira (FACT-3111) Facter 3 and 4 handle facts with value nil differently

4 views
Skip to first unread message

Josh Cooper (Jira)

unread,
Mar 30, 2022, 7:17:02 PM3/30/22
to puppe...@googlegroups.com
Josh Cooper created an issue
 
Facter / Bug FACT-3111
Facter 3 and 4 handle facts with value nil differently
Issue Type: Bug Bug
Assignee: Unassigned
Created: 2022/03/30 4:16 PM
Priority: Normal Normal
Reporter: Josh Cooper

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
  }
}

Add Comment Add Comment
 
This message was sent by Atlassian Jira (v8.20.2#820002-sha1:829506d)
Atlassian logo
Reply all
Reply to author
Forward
0 new messages