7 min to read
Linting the Puppet Control Repository with PDK

The Puppet Development Kit (PDK) is a super useful suite of tools for quickly developing modules for Open Source and Enterprise Puppet. Of particular note is the pdk validate
command which will perform handy tests like validating validating your tasks, code, data, and metadata. Out of the box, the Puppet Control Repository is not set up to work with PDK but with few small tweaks, we can get it working like a charm enabling you to get the same value out of their robust validation tools just like you would for module development.
Actual installation and deployment of PDK, Puppet, and the control repo are out of scope for this article and I’m assuming you’ve already got them up and running.
Table of Contents
PDK No Worky
Normally, when you try to run this against Puppet’s control repository, PDK will throw an error informing you that the control repo is not PDK compatible.
$ pdk validate
pdk (ERROR): '/home/kitsutron/checkout/labnet-puppet/metadata.json' does not exist or is not a file.
pdk (ERROR): This module is not PDK compatible. Run `pdk convert` to make it compatible with your version of PDK.
Following the recommendation to run pdk convert
results in another frustrating error, which is somewhat amusing as we have no metadata.json anywhere in the control repo which we can confirm with tree
.
$ pdk convert
pdk (ERROR): Invalid 'name' field in metadata.json: Module name must contain only alphanumeric or underscore characters.
$ tree
.
├── CODEOWNERS
├── LICENSE
├── Puppetfile
├── README.md
├── controls.md
├── data
│ ├── common.yaml
│ ├── nodes
│ │ └── example.yaml
│ ├── production.yaml
│ └── secrets
│ ├── common.eyaml
│ └── nodes
│ └── example.eyaml
├── environment.conf
├── hiera.yaml
├── manifests
│ └── site.pp
├── pdk.yaml
├── scripts
│ ├── config_version-r10k.rb
│ ├── config_version-rugged.rb
│ └── config_version.sh
└── site-modules
├── adhoc
│ ├── plans
│ └── tasks
├── profile
│ └── manifests
│ └── example.pp
└── role
└── manifests
└── example.pp
Providing the Missing Piece
Fortunately, we can do the legwork for PDK and generate our own metadata.json for it to hook on and use. In this example, I’m targeting Rocky 8 and RHEL 8 which have been my lab buddies for the last 12 months, but realisticlaly you can target any OS and major OS release that Puppet supports.
$ cat <<'EOF' >metadata.json
{
"name": "labnet-puppet",
"version": "0.1.0",
"author": "kitsutron",
"summary": "Control repo for labnet",
"license": "GPL-3.0-or-later",
"source": "",
"dependencies": [
],
"operatingsystem_support": [
{
"operatingsystem": "RedHat",
"operatingsystemrelease": [
"8"
]
},
{
"operatingsystem": "Rocky",
"operatingsystemrelease": [
"8"
]
}
],
"requirements": [
{
"name": "puppet",
"version_requirement": ">= 6.21.0 < 8.0.0"
}
],
"pdk-version": "2.5.0",
"template-url": "pdk-default#2.5.0",
"template-ref": "tags/2.5.0-0-g369d483"
}
EOF
Now PDK happily complains about problems with my control repo like it should.
pdk (INFO): Using Ruby 2.7.6
pdk (INFO): Using Puppet 7.16.0
pdk (INFO): Running all available validators...
pdk (INFO): Validator 'puppet-epp' skipped for '/Users/lok/Checkout/labnet-puppet-temp'. No files matching '["**/*.epp"]' found to validate.
pdk (INFO): Validator 'task-name' skipped for '/Users/lok/Checkout/labnet-puppet-temp'. No files matching '["tasks/**/*"]' found to validate.
pdk (INFO): Validator 'task-metadata-lint' skipped for '/Users/lok/Checkout/labnet-puppet-temp'. No files matching '["tasks/*.json"]' found to validate.
┌ [✔] Running metadata validators ...
├── [✔] Checking metadata syntax (metadata.json tasks/*.json).
└── [✔] Checking module metadata style (metadata.json).
┌ [✖] Running puppet validators ...
├── [✔] Checking Puppet manifest syntax (**/*.pp).
└── [✖] Checking Puppet manifest style (**/*.pp).
┌ [✖] Running ruby validators ...
└── [✖] Checking Ruby code style (**/**.rb).
┌ [✔] Running tasks validators ...
├── [✔] Checking task names (tasks/**/*).
└── [✔] Checking task metadata style (tasks/*.json).
┌ [✔] Running yaml validators ...
└── [✔] Checking YAML syntax (**/*.yaml **/*.yml).
pdk (WARNING): puppet-lint: class not documented (site-modules/role/manifests/example.pp:1:1)
pdk (ERROR): puppet-lint: there should be a single space or newline before a closing brace (site-modules/role/manifests/example.pp:5:24)
pdk (WARNING): puppet-lint: top-scope variable being used without an explicit namespace (site-modules/profile/manifests/example.pp:9:17)
pdk (CONVENTION): rubocop: Missing frozen string literal comment. (Puppetfile:1:1)
pdk (CONVENTION): rubocop: Unnecessary spacing detected. (Puppetfile:7:25)
pdk (CONVENTION): rubocop: Align the arguments of a method call if they span more than one line. (Puppetfile:60:3)
pdk (CONVENTION): rubocop: Align the arguments of a method call if they span more than one line. (Puppetfile:64:3)
pdk (CONVENTION): rubocop: Align the arguments of a method call if they span more than one line. (Puppetfile:80:3)
pdk (CONVENTION): rubocop: Missing space after `#`. (Puppetfile:85:1)
pdk (CONVENTION): rubocop: Missing space after `#`. (Puppetfile:89:1)
pdk (CONVENTION): rubocop: Missing frozen string literal comment. (scripts/config_version-r10k.rb:1:1)
pdk (CONVENTION): rubocop: Missing frozen string literal comment. (scripts/config_version-rugged.rb:1:1)
Extra Goodness
Now that PDK is working, we can also start tuning out some of the warnings that are less relevant to us. PDK’s linter (puppet-lint) thankfully includes a simple run commands file where you can configure ignores for warnings which don’t provide any value to your use case. Here’s how I generate mine which ignores the extremely long lines warning (as I have a couple of gross inline strings I haven’t broken up yet), and the Puppet URL without modules warning (which doesn’t help since we’re using Puppet as a fileserver).
cat <<'EOF' >.puppet-lint.rc
--no-puppet_url_without_modules-check
--no-140chars-check
EOF
Now when we run pdk validate
, neither of these checks will run. This is particularly useful if you’re wanting to use PDK to validate your control repository as part of some kind of CI/CD pipeline as it means you aren’t stuck doing some kind of hacky workaround if accepted risks show up in your output.
Last Thoughts for Today
I’m not 100% sure why the Puppet control repository doesn’t come with a metadata file by default, especially since PDK explicitly comes with a validator for control repositories, but presumably this is just an oversight given the size and complexity of Puppet as a platform.
$pdk validate --list
pdk (INFO): Available validators: control-repo, metadata, puppet, ruby, tasks, yaml
Regardless, hopefully this will help you keep your control repository in check as it grows and evolves.