puppetlabs / puppet-lint

Check that your Puppet manifests conform to the style guide

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

puppet-lint: Fails to parse parameter of data-type Optional with no default-value

ChrLau opened this issue · comments

Introduction

Puppet defines "optional parameters" as parameters with a default value (undef is NOT allowed).
Example: String $i_am_an_optional_parameter = "Because I have a value"
Documentation: https://www.puppet.com/docs/puppet/8/style_guide.html#params-display-order

Puppet also has the Optional data-type for parameters marking them as - well - optional in the terms that undef IS allowed.
Example: Optional[String] $am_i_an_optional_parameter_too = "or not?"
Or with undef:
Example: Optional[String] $am_i_an_optional_parameter_too
Documentation: https://www.puppet.com/docs/puppet/8/lang_data_abstract.html#optional-data-type

Puppet explictily states that: "This is useful for matching values that are allowed to be absent."
Full parapgraph:

The Optional data type wraps one other data type, and results in a data type that matches anything that type would match plus undef. This is useful for matching values that are allowed to be absent.

This naming convention is absolutely misleading as in 99% my clients refer to the later example when they use the term "optional parameter". While "Parameter of data-type optional" would be precise.

Hence I recommend getting rid of the term "optional parameter" in the warning messages all together as it's too ambiguous and therefore not helpful. (Or least make the warning more explanatory.)
Currently, when puppet-lint encounters an optional value which doesn't meet it's criteria it will print the following warning:
WARNING: optional parameter listed before required parameter on line X (check: parameter_order)

Additionlly the official Puppet documentation doesn't help much in the way that it too spreads confusion by stating that "you can list required parameters before optional parameters", when this is clearly not the case. As you MUST list all required parameters (parameters without a default-value) BEFORE any optional parameter (paramters with a default-value).

In parameterized class and defined resource type definitions, you can list required parameters before optional parameters (that is, parameters with defaults).
Documentation: https://www.puppet.com/docs/puppet/8/style_guide.html#params-display-order

Adding to problem is the fact that many people list parameters without the Optional data-type first, and then the parameters with the Optional data-type after them.
Which from my point of view also originates from the fact that the term "optional parameter" is poorly choosen in relation to what it really means technically. (How about the term: "valued parameter"?)

Describe the Bug

These 2 code examples will illustrate the problem as they generate the exact same warning:

  1. Data-Type Optional with a default-value listed before required parameter $blatest with no default-value
class profile::services::test (
  # Switch the next 2 lines and puppet-lint won't print a warning
  Optional[Hash[Stdlib::Port, Stdlib::Host]] $backupservers = {},
  String $blatest,
  String $password = "test",
  Pattern[/^\d+\.\d+\.\d+(?:-\d+)?$/] $version = '11.2.3-4',
  String $system = 'SOMEEXAMPELSTRING',
) {
# intentionally left empty
}
  1. Data-Type Optional with no default-value listed after all parameters which are not of data-type Optional
    This should be allowed according to the documentation. But it isn't.
class profile::services::test (
  String $blatest,
  String $password = "test",
  Pattern[/^\d+\.\d+\.\d+(?:-\d+)?$/] $version = '11.2.3-4',
  String $system = 'SOMEEXAMPELSTRING',
  # Define the Hash as empty or move he lint above/below the $blatest parameter and it passes puppet-lint
  Optional[Hash[Stdlib::Port, Stdlib::Host]] $backupservers,
) {
# intentionally left empty
}

While these 2 code examples will pass puppet-lint:
3. Data-Type Optional with default-value listed after all parameters which are not of data-type Optional and correct ordering of parameters with (no) default-value.

class profile::services::test (
  String $blatest,
  String $password = "test",
  Pattern[/^\d+\.\d+\.\d+(?:-\d+)?$/] $version = '11.2.3-4',
  String $system = 'SOMEEXAMPELSTRING',
  Optional[Hash[Stdlib::Port, Stdlib::Host]] $backupservers = {},
) {
# intentionally left empty
}
  1. Data-Type Optional with no default-value listed before parameters with default-value
class profile::services::test (
  Optional[Hash[Stdlib::Port, Stdlib::Host]] $backupservers,
  String $blatest,
  String $password = "test",
  Pattern[/^\d+\.\d+\.\d+(?:-\d+)?$/] $version = '11.2.3-4',
  String $system = 'SOMEEXAMPELSTRING',
) {
# intentionally left empty
}

However from what the documentation says the code in example 2 should pass puppet-lint without a warning.
Currently it does not.

Expected Behavior

That parameters with no-default value and the Data-Type of Optional produce no linter warning.

This should work according to the documentation:

class profile::services::test (
  String $blatest,
  String $password = "test",
  Pattern[/^\d+\.\d+\.\d+(?:-\d+)?$/] $version = '11.2.3-4',
  String $system = 'SOMEEXAMPELSTRING',
  # Define the Hash as empty or move the line above/below the $blatest parameter and it passes puppet-lint
  Optional[Hash[Stdlib::Port, Stdlib::Host]] $backupservers,
) {
# intentionally left empty
}

Fixed linter warning

Maybe adjust the message from:
WARNING: optional parameter listed before required parameter on line X (check: parameter_order)

to:
WARNING: parameter with default-value ("optional parameter") listed before parameter without default-value ("required parameter") on line X (check: parameter_order)

Environment

  • puppet-lint 4.2.1 (Currently can't test with 5.0.0 because of issue Issue #169 )

See also #122 which might have added to the confusion/complexity back then.

I close this issue. The main problem is that Puppet has the term "optional parameter" for parameters with an assigned default.
But also the Optional-DataType. And that most people refer to the later (as Parameters with that DataType can be undef).