A one stop shop for everything Puppet.Dsc!
Categories:
A brief history
It has taken a couple of iterations to get to where we are today with the integration between Puppet and Powershell’s DSC. We’ve taken a number of approaches over recent years, and admittedly it hasn’t always been the smoothest of roads. The idea for this integration between two configuration management tools stem from their overwhelming similiarties, DSC, as described by Microsoft themselves is “a management platform in PowerShell that enables you to manage your IT and development infrastructure with configuration as code.”, so essentially the end goal of both Puppet and DSC is the same. We aim to empower users to manage and configure their IT infastructure at scale efficiently.
Naturally, this got the brains at Puppet here thinking about how we can leverage the power of DSC, through the even greater power of Puppet. And so the saga began!
puppetlabs-dsc
First off, puppetlabs-dsc. This module would generate Puppet types based on DSC Resources MOF (Managed Object Format) schema files. puppetlabs-dsc was an innovative idea, and essentially generated puppet types on the fly
, which all ran through a generic powershell provider. Essentially, when you ran puppetlabs-dsc it would create a Puppet Type for each resource defined in your manifest, all of which would utilise the powershell provider. Each time Puppet was ran, the provider would generate the equivalent DSC powershell script, which contained the Invoke-DscResource
cmdlet, which would invoke DSC as if you were running it directly.
WindowsFeature IIS {
Ensure = 'present'
Name = 'Web-Server'
}
…would translate to this in Puppet:
dsc_windowsfeature {'IIS':
dsc_ensure => 'present',
dsc_name => 'Web-Server',
}
So what happened? As time went on the module became fragile and stale and required regular manual maintenance.
puppetlabs-dsc_lite
Our next stop on this trip down memory lane is with the puppetlabs-dsc_lite module (for simplicities stake, lets call this dsc_lite). Dsc_lite was like puppetlabs-dsc, but minus any guardrails and Puppet’s native data types to hold your hand. Like its predecessor, it also created puppet types for each dsc resource defined in your puppet manfiest, whilst executing the equivalent dsc powershell scripts through a generic powershell provider. This was a much more lightweight, maintainable and was a “one size fits all” solution, unlike it’s puppetlabs-dsc counterpart.
There were some notable differences between how you would define a manifest in puppetlabs-dsc vs dsc_lite. The below manifest in puppetlabs-dsc
dsc_windowsfeature {'IIS':
dsc_ensure => 'present',
dsc_name => 'Web-Server',
}
would have an equivalent manifest in dsc_lite like
dsc {'iis':
resource_name => 'WindowsFeature', # name of DSC resource
module => 'PSDscResources', # name of DSC module on powershell gallery
properties => { # name and value of properties to be passed to Invoke-DscResource
ensure => 'present',
name => 'Web-Server',
}
}
However, this did have its drawbacks!
- Required extensive knowledge of native dsc
puppetlabs-dsc_lite
has no way of knowing whether the values for each property you provided were correct until after dsc invocation. In other words, no way to tell if you goofed til run time.
So, back to the drawing board we went..
Puppet.Dsc
And ultimately, due to all to the reasons above, we were finally led to where we are today, Puppet’s auto-generated DSC modules. Thanks to the amazing wizardy that is Puppet.Dsc, we are able to take any DSC module directly from the Powershell Gallery (DSC’s answer to Puppet forge), and generate an equivalent Puppet module. Puppet.Dsc would retrieve a module from the gallery and convert each DSC resource into Puppet Resource API types and providers. This meant that user’s could manage their Puppet DSC modules, the same way they would with their regular old Puppet modules, just installing what module and version you needed in your environment, no fuss.
This was and has been the recommended way to run DSC through Puppet in recent years.
Like the above, there are some limitations to this method. Not all DSC modules are compatible with Puppet.Dsc.
Not all DSC and puppet properties have a one-to-one mapping. I.e. Dsc
keys
and Puppetnamevars
may appear the same on the surface, but behave differently when passed solely in a manifest.
Such discrepancies can arise and cause unexpected behaviour. Luckily, these instances are rare, and usually very niche.
Under the hood all three approaches are the same, all they are is a DSC abstration, ran through the familiar interface of a Puppet manifest.
Getting started with Puppet.Dsc
The Puppet.Dsc
PowerShell module is available on the PowerShell Gallery; If you just want to get your hands on the PowerShell module to read the help and experiment on your own, you can install it like any other PowerShell module:
Install-Module -Name Puppet.Dsc
Import-Module -Name Puppet.Dsc
Get-Command -Module Puppet.Dsc
Get-Help -Name New-PuppetDscModule -ShowWindow
Puppetizing a PowerShell module
So, you want to turn a PowerShell module with DSC Resources into a Puppet module? You can do this with a single command:
# If you run this command without the PassThru flag it returns nothing to the output stream.
# Any conversion errors will be in the error stream, as usual.
# If you'd like a deeper look at what it's doing, try running it with the Verbose flag.
New-PuppetDscModule -PowerShellModuleName ComputerManagementDsc -PassThru
Unfortunately, the output from running it isn’t all that exciting:
Behind the scenes, the command:
- Uses the PDK to create a new Puppet module
- Searches the PowerShell Gallery for the ComputerManagementDsc module and vendor it into the new Puppet module
- Converts each of the DSC Resources from the vendored PowerShell module into a Puppet Resource API type and provider
- Updates the Puppet module’s metadata and documentation based on the PowerShell module.
- Outputs the generated module to
$PWD.Path/imports/YourDscModule
At this time, for best results we strongly recommend you run the command with administrator privileges in a Windows PowerShell 5.1 session. While it does work without administrator privileges, the function cannot fully map nested CIM instances without administrator privileges. For more information on this process, check out the
about_Puppetization
HelpFile viaGet-Help
for a more in-depth documentation of this process.
Using puppetized modules
Prerequisite: Ensure the module is installed within your environment’s modulepath, or path to the directory containing the module is supplied to your puppet apply command using the
--modulepath=path/to/modules/dir
flag. See here for more information on modulepath usage.
On the one hand, there’s not much to say about using the Puppetized modules with DSC Resources; you use them precisely like any other Puppet module, after all. On the other hand, there’s some strong utility worth going over in more detail you may or may not be aware of!
To get the most value from your workflow, we strongly recommend you author your manifests that include Puppetized DSC Resources in VSCode with the Puppet extension enabled.
When we open a file named example.pp
to edit, the Puppet extension automatically begins to load;
once this is finished, we have access to a ton of useful authoring support, including intellisense.
For example, if we’ve installed the computermanagementdsc
Puppet module, we need only type dsc_execution
before IntelliSense kicks in and helps us out:
Note that it tells us not just what available resources might match, it also displays the available documentation for each resource.
We also get IntelliSense for each property we want to pass, too; again, this doesn’t just show the available options but also includes any available documentation for each property.
You can also review the documentation for a property by hovering over it:
Where this combination really begins to sing is when you’ve begun authoring a manifest and something goes wrong.
The image above shows that the file name in the left-hand pane has changed colors and is now red. It also underscores two entries in the manifest that VSCode has highlighted - one with orange underlining, indicating a warning, and one with red underlining, indicating an error. Finally, down in the bottom left corner it highlights the problem symbols for errors and warnings, both of which display a count of one.
VSCode (via the extension) knows something is wrong with our manifest; we can click on those symbols to bring up the Problems Pane and investigate:
This tells us there’s a warning about the indentation of a hash rocket and some sort of syntax error preventing the extension from parsing line 3.
A quick look at the code tells us that we’re missing a comma in the resource declaration on line 2, and as soon as we add that comma in we get confirmation:
All that remains now is the formatting issue. Luckily, VSCode is able to automatically handle this for us via the Format Document command:
Which we can see does in fact move the hash rocket and resolve our last problem:
We’re ready to apply this manifest!
puppet apply ./example.pp
Only… there was a problem;
without reading the documentation for dsc_executionpolicyscope
thoroughly enough, we specified Machine
instead of MachinePolicy
!
Puppet gives us back a pretty good error message though:
Error: Parameter dsc_executionpolicyscope failed on Dsc_powershellexecutionpolicy[[OPS-213]]: dsc_powershellexecutionpolicy.dsc_executionpolicyscope expects a match for Enum['CurrentUser', 'LocalMachine', 'MachinePolicy', 'Process', 'UserPolicy'], got 'Machine'
We get an explicit list of the allowed values before it tries to invoke DSC with the Set
action.
This is unlike our prior implementation in puppetlabs-dsc_lite
, which has no way of knowing whether the values you’ve provided are correct.
Once we correct our manifest to specify LocalMachine
and re-run the command, we get something else:
Notice: Compiled catalog for michael.lombardi-pf12aa84 in environment workstation_production in 1.04 seconds
Notice: /Stage[main]/Main/Dsc_powershellexecutionpolicy[[OPS-213]]/dsc_executionpolicy: dsc_executionpolicy changed 'Unrestricted' to 'RemoteSigned'
Notice: dsc_powershellexecutionpolicy[{:name=>"[OPS-213]", :dsc_executionpolicyscope=>"LocalMachine"}]: Updating: Finished in 0.809555 seconds
Notice: Applied catalog in 1.68 seconds
This highlights a change from both of our prior implementations: you now get property-by-property reporting for DSC Resources when using Puppet! This implementation knows not just that a DSC Resource was out of sync and therefore applied, but it can tell you exactly which properties were out of sync, what their value was, and what it has been set to in this run.
This brings DSC Resources in line with all of the rest of the resources you manage with Puppet and drastically improves the usefulness of your run reports!
Some helpful resources
- DSC overview and puppetizing a module with Puppet.Dsc
- More on puppetizing modules
- Troubleshooting Puppet DSC modules
You’re all set!
You now know how to start generating your own puppet DSC modules. Happy puppeting! :-)