<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Content and Tooling – Posts</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/</link><description>Recent content in Posts on Content and Tooling</description><generator>Hugo -- gohugo.io</generator><atom:link href="https://puppetlabs.github.io/content-and-tooling-team/blog/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: A one stop shop for everything Puppet.Dsc!</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/puppet.dsc_blog/</link><pubDate>Tue, 27 Feb 2024 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/puppet.dsc_blog/</guid><description>
&lt;h2 id="a-brief-history">A brief history&lt;/h2>
&lt;p>It has taken a couple of iterations to get to where we are today with the integration between Puppet and Powershell&amp;rsquo;s DSC. We&amp;rsquo;ve taken a number of approaches over recent years, and admittedly it hasn&amp;rsquo;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 &amp;ldquo;a management platform in PowerShell that enables you to manage your IT and development infrastructure with configuration as code.&amp;rdquo;, 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.&lt;/p>
&lt;p>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!&lt;/p>
&lt;h3 id="puppetlabs-dsc">puppetlabs-dsc&lt;/h3>
&lt;p>First off, &lt;a href="https://forge.puppet.com/modules/puppetlabs/dsc/readmes">puppetlabs-dsc&lt;/a>. 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 &lt;code>on the fly&lt;/code>, 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 &lt;code>Invoke-DscResource&lt;/code> cmdlet, which would invoke DSC as if you were running it directly.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">WindowsFeature IIS {
Ensure = &lt;span style="color:#f1fa8c">&amp;#39;present&amp;#39;&lt;/span>
Name = &lt;span style="color:#f1fa8c">&amp;#39;Web-Server&amp;#39;&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip;would translate to this in Puppet:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">dsc_windowsfeature&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;IIS&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;present&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Web-Server&amp;#39;&lt;/span>,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>So what happened? As time went on the module became fragile and stale and required regular manual maintenance.&lt;/p>
&lt;h3 id="puppetlabs-dsc_lite">puppetlabs-dsc_lite&lt;/h3>
&lt;p>Our next stop on this trip down memory lane is with the &lt;a href="https://github.com/puppetlabs/puppetlabs-dsc_lite">puppetlabs-dsc_lite&lt;/a> module (for simplicities stake, lets call this dsc_lite). Dsc_lite was like puppetlabs-dsc, but minus any guardrails and Puppet&amp;rsquo;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 &amp;ldquo;one size fits all&amp;rdquo; solution, unlike it&amp;rsquo;s puppetlabs-dsc counterpart.&lt;/p>
&lt;p>There were some notable differences between how you would define a manifest in puppetlabs-dsc vs dsc_lite.
The below manifest in puppetlabs-dsc&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">dsc_windowsfeature&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;IIS&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;present&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Web-Server&amp;#39;&lt;/span>,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>would have an equivalent manifest in dsc_lite like&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">dsc&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;iis&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">resource_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;WindowsFeature&amp;#39;&lt;/span>,&lt;span style="color:#6272a4"> # name of DSC resource&lt;/span>
&lt;span style="color:#50fa7b">module&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;PSDscResources&amp;#39;&lt;/span>,&lt;span style="color:#6272a4"> # name of DSC module on powershell gallery&lt;/span>
&lt;span style="color:#50fa7b">properties&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> {&lt;span style="color:#6272a4"> # name and value of properties to be passed to Invoke-DscResource&lt;/span>
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;present&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Web-Server&amp;#39;&lt;/span>,
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>However, this did have its drawbacks!&lt;/p>
&lt;ul>
&lt;li>Required extensive knowledge of native dsc&lt;/li>
&lt;li>&lt;code>puppetlabs-dsc_lite&lt;/code> has no way of knowing whether the values for each property you provided were correct until &lt;em>after&lt;/em> dsc invocation. In other words, no way to tell if you goofed til run time.&lt;/li>
&lt;/ul>
&lt;p>So, back to the drawing board we went..&lt;/p>
&lt;h3 id="puppetdsc">Puppet.Dsc&lt;/h3>
&lt;p>And ultimately, due to all to the reasons above, we were finally led to where we are today, &lt;a href="https://forge.puppet.com/modules/dsc">Puppet&amp;rsquo;s auto-generated DSC modules&lt;/a>. Thanks to the amazing wizardy that is &lt;a href="https://www.powershellgallery.com/packages/Puppet.Dsc">Puppet.Dsc&lt;/a>, we are able to take any DSC module directly from the &lt;a href="https://www.powershellgallery.com/">Powershell Gallery&lt;/a> (DSC&amp;rsquo;s answer to &lt;a href="https://forge.puppet.com/">Puppet forge&lt;/a>), and generate an equivalent Puppet module. Puppet.Dsc would retrieve a module from the gallery and convert each DSC resource into &lt;a href="https://www.puppet.com/docs/puppet/7/about_the_resource_api.html">Puppet Resource API&lt;/a> types and providers. This meant that user&amp;rsquo;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.&lt;/p>
&lt;p>This was and has been the recommended way to run DSC through Puppet in recent years.&lt;/p>
&lt;blockquote>
&lt;p>Like the above, there are some limitations to this method. Not all DSC modules are compatible with Puppet.Dsc.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Not all DSC and puppet properties have a one-to-one mapping. I.e. Dsc &lt;code>keys&lt;/code> and Puppet &lt;code>namevars&lt;/code> may appear the same on the surface, but behave differently when passed solely in a manifest.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Such discrepancies can arise and cause unexpected behaviour. Luckily, these instances are rare, and usually very niche.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>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.&lt;/strong>&lt;/p>
&lt;h2 id="getting-started-with-puppetdsc">Getting started with Puppet.Dsc&lt;/h2>
&lt;p>The &lt;a href="https://www.powershellgallery.com/packages/Puppet.Dsc">&lt;code>Puppet.Dsc&lt;/code> PowerShell module&lt;/a> is available on the &lt;a href="https://www.powershellgallery.com/">PowerShell Gallery&lt;/a>; 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:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Install-Module&lt;/span> -Name Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Import-Module&lt;/span> -Name Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Get-Command&lt;/span> -Module Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Get-Help&lt;/span> -Name &lt;span style="color:#8be9fd;font-style:italic">New-PuppetDscModule&lt;/span> -ShowWindow
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="puppetizing-a-powershell-module">Puppetizing a PowerShell module&lt;/h2>
&lt;p>So, you want to turn a PowerShell module with DSC Resources into a Puppet module?
You can do this with a single command:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># If you run this command without the PassThru flag it returns nothing to the output stream.&lt;/span>
&lt;span style="color:#6272a4"># Any conversion errors will be in the error stream, as usual.&lt;/span>
&lt;span style="color:#6272a4"># If you&amp;#39;d like a deeper look at what it&amp;#39;s doing, try running it with the Verbose flag.&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">New-PuppetDscModule&lt;/span> -PowerShellModuleName ComputerManagementDsc -PassThru
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Unfortunately, the output from running it isn&amp;rsquo;t all that exciting:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/new-puppetdscmodule.png" alt="Output from a PowerShell console showing the running of the command above as well as the return output, which is the folder object representing the new Puppet module on disk">&lt;/p>
&lt;p>Behind the scenes, the command:&lt;/p>
&lt;ol>
&lt;li>Uses the &lt;a href="https://puppet.com/docs/pdk/3.x/pdk.html">PDK&lt;/a> to create a new Puppet module&lt;/li>
&lt;li>Searches the &lt;a href="https://www.powershellgallery.com/">PowerShell Gallery&lt;/a> for the ComputerManagementDsc module and vendor it into the new Puppet module&lt;/li>
&lt;li>Converts each of the DSC Resources from the vendored PowerShell module into a Puppet Resource API type and provider&lt;/li>
&lt;li>Updates the Puppet module&amp;rsquo;s metadata and documentation based on the PowerShell module.&lt;/li>
&lt;li>Outputs the generated module to &lt;code>$PWD.Path/imports/YourDscModule&lt;/code>&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>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 &lt;em>does&lt;/em> work without administrator privileges, the function cannot fully map nested CIM instances without administrator privileges.
For more information on this process, check out the &lt;a href="https://github.com/puppetlabs/Puppet.Dsc/blob/main/docs/about_Puppetization.md">&lt;code>about_Puppetization&lt;/code> HelpFile&lt;/a> via &lt;code>Get-Help&lt;/code> for a more in-depth documentation of this process.&lt;/p>
&lt;/blockquote>
&lt;h2 id="using-puppetized-modules">Using puppetized modules&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>Prerequisite&lt;/strong>: Ensure the module is installed within your environment&amp;rsquo;s modulepath, or path to the directory containing the module is supplied to your puppet apply command using the &lt;code>--modulepath=path/to/modules/dir&lt;/code> flag. See &lt;a href="https://www.puppet.com/docs/puppet/latest/dirs_modulepath.html">here&lt;/a> for more information on modulepath usage.&lt;/p>
&lt;/blockquote>
&lt;p>On the one hand, there&amp;rsquo;s not much to say about using the Puppetized modules with DSC Resources;
you use them &lt;em>precisely&lt;/em> like any other Puppet module, after all.
On the other hand, there&amp;rsquo;s some strong utility worth going over in more detail you may or may not be aware of!&lt;/p>
&lt;p>To get the most value from your workflow, we &lt;strong>strongly&lt;/strong> recommend you author your manifests that include Puppetized DSC Resources in &lt;a href="https://code.visualstudio.com/">VSCode&lt;/a> with the &lt;a href="https://github.com/puppetlabs/puppet-vscode">Puppet extension&lt;/a> enabled.&lt;/p>
&lt;p>When we open a file named &lt;code>example.pp&lt;/code> 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.&lt;/p>
&lt;p>For example, if we&amp;rsquo;ve installed the &lt;code>computermanagementdsc&lt;/code> Puppet module, we need only type &lt;code>dsc_execution&lt;/code> before IntelliSense kicks in and helps us out:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/intellisense-resource.png" alt="A VSCode window showing the text &amp;lsquo;dsc_execution&amp;rsquo; has raised a tooltip which lists multiple possible matches, including dsc_powershellexecutionpolicy, and to the right it shows the help information for this resource.">&lt;/p>
&lt;p>Note that it tells us not just what available resources might match, it also displays the available documentation for each resource.&lt;/p>
&lt;p>We also get IntelliSense for each property we want to pass, too;
again, this doesn&amp;rsquo;t just show the available options but also includes any available documentation for each property.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/intellisense-property.png" alt="A VSCode window showing the text &amp;lsquo;dsc&amp;rsquo; inside a Puppet resource declaration for dsc_powershellexecutionpolicy, with a tooltip listing the possible properties, including dsc_executionpolicy and dsc_executionpolicyscope; as before, the help information (now including valid values) is to the right.">&lt;/p>
&lt;p>You can also review the documentation for a property by hovering over it:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/docs-property.png" alt="A VSCode window showing an empty declaration for &amp;lsquo;dsc_executionpolicy&amp;rsquo; with the mouse hovering over that key, displaying a tooltip which includes the documentation and valid values for the property.">&lt;/p>
&lt;p>Where this combination really begins to sing is when you&amp;rsquo;ve begun authoring a manifest and something goes wrong.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems.png" alt="A VSCode window showing a fully defined manifest with markings to highlight issues.">&lt;/p>
&lt;p>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.&lt;/p>
&lt;p>VSCode (via the extension) knows &lt;em>something&lt;/em> is wrong with our manifest;
we can click on those symbols to bring up the Problems Pane and investigate:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems-pane.png" alt="A VSCode window displaying the Problems Pane with two entries">&lt;/p>
&lt;p>This tells us there&amp;rsquo;s a warning about the indentation of a hash rocket and some sort of syntax error preventing the extension from parsing line 3.&lt;/p>
&lt;p>A quick look at the code tells us that we&amp;rsquo;re missing a comma in the resource declaration on line 2, and as soon as we add that comma in we get confirmation:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems-added-comma.png" alt="A VSCode window displaying the Problems Pane with only one warning">&lt;/p>
&lt;p>All that remains now is the formatting issue.
Luckily, VSCode is able to automatically handle this for us via the &lt;em>Format Document&lt;/em> command:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/format-document-option.png" alt="A VSCode window displaying the right-click menu over the manifest, highlighting the &amp;lsquo;Format Document&amp;rsquo; command with a hotkey combination of &amp;lsquo;Shift+Alt+F&amp;rsquo;">&lt;/p>
&lt;p>Which we can see does in fact move the hash rocket and resolve our last problem:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/manifest-fixed.png" alt="A VSCode window displaying the manifest with no issues or warnings, the hash rocket moved appropriately to ensure preferred formatting for the manifest.">&lt;/p>
&lt;p>We&amp;rsquo;re ready to apply this manifest!&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">puppet apply ./example.pp
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Only&amp;hellip; there was a problem;
without reading the documentation for &lt;code>dsc_executionpolicyscope&lt;/code> thoroughly enough, we specified &lt;code>Machine&lt;/code> instead of &lt;code>MachinePolicy&lt;/code>!&lt;/p>
&lt;p>Puppet gives us back a pretty good error message though:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">Error: Parameter dsc_executionpolicyscope failed on Dsc_powershellexecutionpolicy[[OPS-213]]: dsc_powershellexecutionpolicy.dsc_executionpolicyscope expects a match for Enum[&amp;#39;CurrentUser&amp;#39;, &amp;#39;LocalMachine&amp;#39;, &amp;#39;MachinePolicy&amp;#39;, &amp;#39;Process&amp;#39;, &amp;#39;UserPolicy&amp;#39;], got &amp;#39;Machine&amp;#39;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>We get an explicit list of the allowed values &lt;em>before&lt;/em> it tries to invoke DSC with the &lt;code>Set&lt;/code> action.
This is unlike our prior implementation in &lt;code>puppetlabs-dsc_lite&lt;/code>, which has no way of knowing whether the values you&amp;rsquo;ve provided are correct.&lt;/p>
&lt;p>Once we correct our manifest to specify &lt;code>LocalMachine&lt;/code> and re-run the command, we get something else:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">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 &amp;#39;Unrestricted&amp;#39; to &amp;#39;RemoteSigned&amp;#39;
Notice: dsc_powershellexecutionpolicy[{:name=&amp;gt;&amp;#34;[OPS-213]&amp;#34;, :dsc_executionpolicyscope=&amp;gt;&amp;#34;LocalMachine&amp;#34;}]: Updating: Finished in 0.809555 seconds
Notice: Applied catalog in 1.68 seconds
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This highlights a change from both of our prior implementations:
you now get &lt;em>property-by-property&lt;/em> reporting for DSC Resources when using Puppet!
This implementation knows not just &lt;em>that&lt;/em> 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.&lt;/p>
&lt;p>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!&lt;/p>
&lt;h2 id="some-helpful-resources">Some helpful resources&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=Rw1gB-h77X0">DSC overview and puppetizing a module with Puppet.Dsc&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=i-eo58NaYKg">More on puppetizing modules&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-25-troubleshooting-puppetized-dsc-modules/">Troubleshooting Puppet DSC modules&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="youre-all-set">You&amp;rsquo;re all set!&lt;/h2>
&lt;p>You now know how to start generating your own puppet DSC modules. Happy puppeting! :-)&lt;/p></description></item><item><title>Blog: Firewall Update - Converted to the resource_api</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-08-25-firewall-update/</link><pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-08-25-firewall-update/</guid><description>
&lt;h2 id="firewall-update---converting-to-the-resource_api">Firewall Update - Converting to the resource_api&lt;/h2>
&lt;h3 id="what-has-changed-and-what-will-i-need-to-update">What has changed and what will I need to update?&lt;/h3>
&lt;p>While there have been significant changes to the module, when it comes to the users experiance, there are only six that I would deem backwards incompatible:&lt;/p>
&lt;ol>
&lt;li>The &lt;code>provider&lt;/code> attribute for the Firewall type, which sets whether the rule is for &lt;code>iptables&lt;/code> or &lt;code>ip6tables&lt;/code>, has been renamed to &lt;code>protocol&lt;/code>. This is for two reasons; firstly due to the resource_api specifically forbidding the use of &lt;code>provider&lt;/code> as an attribute name as it is deemed bad practice and secondly to bring it in line with its Firewallchain counterpart.
&lt;ul>
&lt;li>Of note, the attribute has also been updated to allow &lt;code>IPv4&lt;/code> or &lt;code>IPv6&lt;/code> to be passed in place of &lt;code>iptables&lt;/code> or &lt;code>ip6tables&lt;/code> as it is with Firewallchain, though either style is accepted as valid.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>The &lt;code>action&lt;/code> attribute has been removed as it was merely a restricted version of the &lt;code>jump&lt;/code> attribute, with both of them managing the same function. Though this was reasoned as a way to enforce the use of generic parameters I found it to be needlesly complex and so &lt;code>jump&lt;/code> should now be used in all situations.&lt;/li>
&lt;li>Strict types have been declared for all attributes, the type of information that can be passed to each attribute is now validated on a higher level.&lt;/li>
&lt;li>The &lt;code>port&lt;/code> attribute has been removed as it has been deprecated for several years now and is no longer relevant.&lt;/li>
&lt;li>Attributes that allow both arrays and negated values have now been updated.
&lt;ul>
&lt;li>For attributes that require that all passed values be negated as one, you now merely have to negate the first value within the array, rather than all of them, though negating all is still accepted.&lt;/li>
&lt;li>For attributes that allow passed values to be negated seperately this is not the case, with each value being negated, or not negated as it were, seperately. All attributes in this situation are noted within their personal description.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>One last change, that while not backwards incompatible, I feel shoul be mentioned is that the &lt;code>sport&lt;/code> and &lt;code>dport&lt;/code> attributes have now been updated to allow ranges of values to be passed with the &lt;code>:&lt;/code> symbol as a seperator, as this is how they are passed into the iptables command. The original form of the seperator &lt;code>-&lt;/code>, is still accepted however.&lt;/li>
&lt;/ol>
&lt;p>Overall, while there may be some changes that you will have to make to you manifests in order to make them compliant with the new form of the module, I have done my best in order to keep them to a minimum and feel that, for the most part, I have succeeded.&lt;/p>
&lt;h4 id="example-manifest-comparison">Example manifest comparison&lt;/h4>
&lt;p>Some example manifest changes, pulled from the tests, are show below.&lt;/p>
&lt;ul>
&lt;li>An manifest applying a hoplimit on &lt;code>ip6tables&lt;/code>:&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-Puppet=" data-lang="Puppet=">firewall { '571 - hop_limit':
ensure =&amp;gt; present,
proto =&amp;gt; 'tcp',
dport =&amp;gt; '571',
action =&amp;gt; 'accept',
hop_limit =&amp;gt; '5',
provider =&amp;gt; 'ip6tables',
}
&lt;/code>&lt;/pre>&lt;pre>&lt;code class="language-Puppet=" data-lang="Puppet=">firewall { '571 - hop_limit':
ensure =&amp;gt; present,
proto =&amp;gt; 'tcp',
dport =&amp;gt; '571',
jump =&amp;gt; 'accept',
hop_limit =&amp;gt; '5',
protocol =&amp;gt; 'IPv6',
}
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>A manifest blocking access to a pair of ports on &lt;code>iptables&lt;/code>:&lt;/li>
&lt;/ul>
&lt;pre>&lt;code class="language-puppet=" data-lang="puppet=">firewall { '560 - negated ports':
proto =&amp;gt; `tcp`,
sport =&amp;gt; ['! 560-570','! 580'],
action =&amp;gt; `accept`,
}
&lt;/code>&lt;/pre>&lt;pre>&lt;code class="language-puppet=" data-lang="puppet=">firewall { '560 - negated ports':
proto =&amp;gt; `tcp`,
sport =&amp;gt; '! 560:570','580',
jump =&amp;gt; `accept`,
}
&lt;/code>&lt;/pre>&lt;h3 id="main-improvements">Main improvements&lt;/h3>
&lt;p>In regards to how these changes will improve the modules usage, I will be honest and say that they will mainly effect the maintanence and future improvement of the module, increasing the ease with which it can be debugged and with which requested fixes and improvements can be made.
While there is some functional improvement, with the module now more efficiently parsing the returned/given values, it has been largely limited by the necessity of each change in rule being applied with it&amp;rsquo;s own command.&lt;/p>
&lt;h3 id="future-improvements">Future improvements&lt;/h3>
&lt;p>While this has been a large improvement to the module there are many more that can be made for the future:&lt;/p>
&lt;ul>
&lt;li>A community suggestion was made to implement the &lt;code>optparse&lt;/code> ruby module in parsing the retrieved and applied rules from their correct form to the Puppet hash values that we set in or manifests. This could help to replace the most complex part of the updated module and reduce the overall amount of code within the providers and further simplify the module as a whole.&lt;/li>
&lt;li>Many of the currently implemented attributes can be negated but do not currently allow it, this is especially true of the boolean values, the code for which will need to be updated specifically to allow this.&lt;/li>
&lt;/ul>
&lt;h3 id="closing-thoughts">Closing Thoughts&lt;/h3>
&lt;p>Implementing the resource_api into this module is something that I have long considered a vital improvement and one that I am happy that I was able to close of myself.&lt;/p>
&lt;p>I have learned alot in the process and have thouroughly enjoyed the work with my hope being that everyone who utilises or works on the module going forward is appreciative of the changes made and find the module as a whole much easier to work with.&lt;/p>
&lt;p>David&lt;/p></description></item><item><title>Blog: Deprecation of puppetlabs-stdlib functions</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-05-12-deprecation-of-stdlib-functions/</link><pubDate>Fri, 12 May 2023 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-05-12-deprecation-of-stdlib-functions/</guid><description>
&lt;p>Throughout the massive push to get our modules Puppet 8 compatible, we have also been working on finally removing old deprecated functions that have been living in the codebase for quite some time. Keep an eye out for the removals as this may impact your code base if you are using them.&lt;/p>
&lt;h3 id="impacted-functions">Impacted Functions&lt;/h3>
&lt;ul>
&lt;li>abs&lt;/li>
&lt;li>camelcase&lt;/li>
&lt;li>capitalize&lt;/li>
&lt;li>ceiling&lt;/li>
&lt;li>chomp&lt;/li>
&lt;li>chop&lt;/li>
&lt;li>dig44&lt;/li>
&lt;li>downcase&lt;/li>
&lt;li>getvar&lt;/li>
&lt;li>hash&lt;/li>
&lt;li>has_key&lt;/li>
&lt;li>is_array&lt;/li>
&lt;li>is_bool&lt;/li>
&lt;li>is_float&lt;/li>
&lt;li>is_ip_address&lt;/li>
&lt;li>is_ipv4_address&lt;/li>
&lt;li>is_ipv6_address&lt;/li>
&lt;li>is_numeric&lt;/li>
&lt;li>is_string&lt;/li>
&lt;li>lstrip&lt;/li>
&lt;li>max&lt;/li>
&lt;li>min&lt;/li>
&lt;li>private&lt;/li>
&lt;li>round&lt;/li>
&lt;li>rstrip&lt;/li>
&lt;li>sort&lt;/li>
&lt;li>sprintf_hash&lt;/li>
&lt;li>strip&lt;/li>
&lt;li>upcase&lt;/li>
&lt;li>unique&lt;/li>
&lt;li>validate_absolute_path&lt;/li>
&lt;li>validate_array&lt;/li>
&lt;li>validate_bool&lt;/li>
&lt;li>validate_hash&lt;/li>
&lt;li>validate_integer&lt;/li>
&lt;li>validate_ip_address&lt;/li>
&lt;li>validate_ipv4_address&lt;/li>
&lt;li>validate_ipv6_address&lt;/li>
&lt;li>validate_numeric&lt;/li>
&lt;/ul>
&lt;p>This list is not exhaustive and for more information please check out the module source code &lt;a href="https://github.com/puppetlabs/puppetlabs-stdlib">here&lt;/a>.&lt;/p>
&lt;h2 id="thank-you-to-everyone-that-contributed-and-helped-us">Thank you to everyone that contributed and helped us!&lt;/h2>
&lt;p>I would like to take the opportunity to do a massive shout to the community with helping us on this one, it has been a massive team effort. None of this would have been possible without the dedication from everyone and in particular &lt;a href="https://github.com/smortex">smortex&lt;/a>, &lt;a href="https://github.com/b4ldr">b4ldr&lt;/a>, &lt;a href="https://github.com/bastelfreak">bastelfreak&lt;/a>, &lt;a href="https://github.com/alexjfisher">alexjfisher&lt;/a> and &lt;a href="https://github.com/MartyEwings">MartyEwings&lt;/a>.&lt;/p>
&lt;h2 id="need-to-chat-to-us">Need to chat to us?&lt;/h2>
&lt;p>Catch us on &lt;a href="https://puppetcommunity.slack.com/archives/C11LCKKQ9">Slack&lt;/a> and during &lt;a href="https://puppetcommunity.slack.com/archives/CFD8Z9A4T">office hours&lt;/a> weekly (Tuesday 2pm BST).&lt;/p></description></item><item><title>Blog: puppet-lint: Already initialized constant warnings</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-03-16-puppet-lint-already-initialized-constant/</link><pubDate>Thu, 16 Mar 2023 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-03-16-puppet-lint-already-initialized-constant/</guid><description>
&lt;p>For a &lt;a href="https://github.com/voxpupuli/voxpupuli-puppet-lint-plugins/commit/04879bddcd1d2f52bcb8806140cf666bd94120cb">while now&lt;/a>,
the &lt;a href="https://github.com/voxpupuli/voxpupuli-puppet-lint-plugins">&lt;code>voxpupuli-puppet-lint-plugins&lt;/code>&lt;/a> meta gem has provided the community
with a number of amazing plugins for &lt;code>puppet-lint&lt;/code>.&lt;/p>
&lt;p>With the latest release of &lt;code>puppet-lint&lt;/code> and and Vox&amp;rsquo;s plugins gem, a few things have changed that might cause a bit of friction when updating.&lt;/p>
&lt;p>I wanted to take a second to go over a few scenarios that might help you on your journey.&lt;/p>
&lt;h2 id="problem">Problem&lt;/h2>
&lt;p>First of all, lets talk about the problem.&lt;/p>
&lt;p>In &lt;code>puppet-lint&lt;/code> v3.1.0 we adopted two plugins which are now included as default checks:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/mmckinst/puppet-lint-legacy_facts-check">puppet-lint-legacy_facts-check&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/mmckinst/puppet-lint-top_scope_facts-check">puppet-lint-top_scope_facts-check&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Prior to v4.0.0 of &lt;code>voxpupuli-puppet-lint-plugins&lt;/code>, these plugins were included in the meta gem.&lt;/p>
&lt;p>So now we have a scenario where it&amp;rsquo;s possible to update &lt;code>puppet-lint&lt;/code> (&amp;gt;= 3.1.0) and end up with duplicate plugins installed.&lt;/p>
&lt;p>In this case, users may see warnings like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">warning: already initialized constant PuppetLint::CheckLegacyFacts
warning: previous definition of CheckLegacyFacts was here
warning: already initialized constant LEGACY_FACTS_VAR_TYPES
....
warning: already initialized constant TOP_SCOPE_FACTS_VAR_TYPES
warning: previous definition of TOP_SCOPE_FACTS_VAR_TYPES was here
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Not the end of the world, but it&amp;rsquo;s extra noise that you don&amp;rsquo;t want in your pipeline.&lt;/p>
&lt;h3 id="help-this-is-happening-to-me">Help! This is happening to me!&lt;/h3>
&lt;p>So you are seeing these warnings? Read on&amp;hellip;&lt;/p>
&lt;p>What we are seeing here is a soft dependency conflict.&lt;/p>
&lt;p>We have two identical plugins registering the same code inside puppet lint.
That&amp;rsquo;s what is causing the &lt;code>already initialized constant&lt;/code> warning.&lt;/p>
&lt;p>The best way forward is to clean up our environment and start again.&lt;/p>
&lt;h4 id="remove-voxpupuli-puppet-lint-plugins-and-its-dependencies">Remove voxpupuli-puppet-lint-plugins and it&amp;rsquo;s dependencies&lt;/h4>
&lt;p>We can start by removing dependencies of &lt;code>voxpupuli-puppet-lint-plugins&lt;/code>.&lt;/p>
&lt;p>The command below will do just that. We grab the dependencies of Vox&amp;rsquo;s meta gem and remove them one by one.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">gem dependency voxpupuli-puppet-lint-plugins --pipe | grep &lt;span style="color:#f1fa8c">&amp;#34;puppet-lint&amp;#34;&lt;/span> | cut -d&lt;span style="color:#f1fa8c">&amp;#34; &amp;#34;&lt;/span> -f1 | xargs gem uninstall -aIx
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note: Take extra care when running commands like this! 👀&lt;/p>
&lt;/blockquote>
&lt;p>After the previous command has completed, we should be left with the &lt;code>voxpupuli-puppet-lint-plugins&lt;/code> meta gem.&lt;/p>
&lt;p>Let&amp;rsquo;s remove it with the following command:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">gem uninstall voxpupuli-puppet-lint-plugins
&lt;/code>&lt;/pre>&lt;/div>&lt;p>..and check to see if everything has really gone.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">gem list | grep &lt;span style="color:#f1fa8c">&amp;#34;puppet-lint&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Tldr; It should return nothing! Hurrah 🎉&lt;/p>
&lt;h4 id="re-install-the-latest-gems">Re-install the latest gems&lt;/h4>
&lt;p>Now we are free to re-install puppet-lint and &lt;code>voxpupuli-puppet-lint-plugins&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">gem install puppet-lint
gem install voxpupuli-puppet-lint-plugins
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once they have installed you can enjoy a warning free &lt;code>puppet-lint&lt;/code> experience with all of the joys from &lt;code>voxpupuli-puppet-lint-plugins&lt;/code>!&lt;/p>
&lt;p>&amp;hellip; unless you have linting issues!&lt;/p></description></item><item><title>Blog: Removing puppet-modules-gems</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-01-10-remove-puppet-module-gems/</link><pubDate>Tue, 10 Jan 2023 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2023-01-10-remove-puppet-module-gems/</guid><description>
&lt;h2 id="what-are-puppet-module-gems-and-why-are-they-now-considered-harmful">What are &lt;code>puppet-module-gems&lt;/code> and why are they now considered harmful?&lt;/h2>
&lt;p>Okay, that might be a bit of a melodramatic take on the situation, but the &lt;code>puppet-module-gems&lt;/code> really did serve a useful purpose at one point. Let&amp;rsquo;s go back over why it exists and what&amp;rsquo;s changed in the meantime.&lt;/p>
&lt;p>We&amp;rsquo;ll start with Bundler&amp;ndash;a local environment manager for Ruby projects.
It runs a Ruby project with all of its required dependencies in a sandbox, meaning that you don&amp;rsquo;t need to install gems globally.
This is great for repeatability and means that each project can have the specific gem versions it requires without interfering with other projects that might need different versions.&lt;/p>
&lt;p>This worked great for Puppet back in the good old days when things were simple.
All the gems Puppet used were specified in the &lt;code>Gemfile&lt;/code> and Bundler environments just worked.
But then the Ruby ecosystem evolved and gems started taking advantage of new functionality.
Version 1.2 of a gem might run on Ruby 1.8, but an upgrade to version 1.4 was required to use Ruby 2.0 and then Ruby 2.5 needed yet another version.
This got to be rather complex, and worse &lt;em>Bundler couldn&amp;rsquo;t resolve these dependencies properly!&lt;/em> We had to &lt;a href="https://github.com/puppetlabs/puppetlabs-stdlib/blob/4b15c970f5ac6bc683cfde32d782f51a63bee867/Gemfile#L29-L34">do it ourselves&lt;/a>, making the &lt;code>Gemfiles&lt;/code> brittle and harder to read and maintain.&lt;/p>
&lt;p>CI was breaking, module authors were struggling to test on multiple platforms, users were having a hard time validating updates.
Clearly we needed a solution, and the &lt;code>puppet-module-gems&lt;/code> were the answer.
We created meta-gems for each Ruby version we supported and specified the proper dependencies in these gems.
Then the &lt;code>Gemfile&lt;/code> would conditionally depend on the properly versioned meta-gem based on the version of Ruby running.&lt;/p>
&lt;p>This worked reasonably well, but had its challenges.
The dependencies were opaque and the extra level of abstraction meant that looking at the &lt;code>Gemfile&lt;/code> didn&amp;rsquo;t really tell you much about what gems would be installed or used.
Worse, we had to manually resolve and specify all the dependencies for every Ruby version, and keeping up with those turned out to be easier said than done.
We often fell behind and our more adventurous users would regularly &lt;a href="https://tickets.puppetlabs.com/browse/MODULES-11161">remind us of that&lt;/a>.
The situation certainly wasn&amp;rsquo;t ideal, but it was a workable compromise.&lt;/p>
&lt;p>Until Bundler got smarter, learned how to resolve Ruby version dependencies, and made this workaround no longer necessary.&lt;/p>
&lt;h2 id="whats-changing">What&amp;rsquo;s Changing&lt;/h2>
&lt;p>With these Bundler updates, we no longer require such tight control over dependencies; Bundler will do the right thing and resolve them properly, taking gems' supported Ruby versions into account. &lt;strong>We have decided to stop maintaining the &lt;code>puppet-module-gems&lt;/code> and instead move fully to managing gem dependencies with each module&amp;rsquo;s &lt;code>Gemfile&lt;/code>.&lt;/strong> This is standard practice for the Ruby ecosystem, so it will be easier to maintain in the long term. Since it&amp;rsquo;s more flexible, it will also better allow downstream users to modify according to their own needs.&lt;/p>
&lt;p>This is especially relevant now as it means that the &lt;code>puppet-modules-gems&lt;/code> have not been updated to account for Ruby 3, which the upcoming Puppet 8 release will release with. &lt;strong>This means that any module that has not yet converted to the new format will be not be testable on Puppet 8&lt;/strong>.&lt;/p>
&lt;h2 id="what-you-need-to-do">What You Need To Do&lt;/h2>
&lt;p>If you maintain your own Puppet modules, the rest of this post is for you.
If you only &lt;em>use&lt;/em> modules from the Forge, then no action is necessary on your part, other than to file bug reports with a link to this blog post if you notice modules which should be updated.&lt;/p>
&lt;p>Thankfully, the solution to adopting the new standard is relatively simple, at least for those who are using the PDK and the default templates. We&amp;rsquo;ve already made the updates for you and you&amp;rsquo;ll just need to update your module with these changes. This will replace &lt;code>puppet-module-gems&lt;/code> in the &lt;code>Gemfile&lt;/code> with the actual dependencies that the meta-gem represented.&lt;/p>
&lt;pre>&lt;code>$ pdk update
&lt;/code>&lt;/pre>&lt;p>An example of the changes this update includes can be seen on many of our modules, with one example shown &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/pull/2324">here&lt;/a>.&lt;/p>
&lt;p>In the event that you are not using the default PDK templates then you will need to update each &lt;code>Gemfile&lt;/code> yourself. Look at the config default values &lt;a href="https://github.com/puppetlabs/pdk-templates/blob/dd87389c8e88f312861e57cea2d3d4ba52af2bd7/config_defaults.yml#L556">here&lt;/a> and copy what you need into your own template repository, updating them according to your own needs.&lt;/p>
&lt;p>If you are not using the PDK at all, you can find an example of a current &lt;code>Gemfile&lt;/code> below, which you can copy and modify as you need. Tracking the default versions listed under the &lt;code>Gemfile&lt;/code> key in &lt;a href="https://github.com/puppetlabs/pdk-templates/blob/main/config_defaults.yml">config_defaults.yml&lt;/a> will help you keep these versions correct as you update over time.&lt;/p>
&lt;pre>&lt;code>group :development do
# These where already set in pdk templates and so may not be relevant to you
gem &amp;quot;json&amp;quot;, '~&amp;gt; 2.0', require: false
gem &amp;quot;voxpupuli-puppet-lint-plugins&amp;quot;, '~&amp;gt; 3.0', require: false
# The main group of rules we are adding
gem &amp;quot;facterdb&amp;quot;, '~&amp;gt; 1.18', require: false
gem &amp;quot;metadata-json-lint&amp;quot;, '&amp;gt;= 2.0.2', '&amp;lt; 4.0.0', require: false
gem &amp;quot;puppetlabs_spec_helper&amp;quot;, '&amp;gt;= 2.9.0', '&amp;lt; 4.0.0', require: false
gem &amp;quot;rspec-puppet-facts&amp;quot;, '&amp;gt;= 1.10.0', '&amp;lt; 3.0.0', require: false
gem &amp;quot;codecov&amp;quot;, '~&amp;gt; 0.2', require: false
gem &amp;quot;dependency_checker&amp;quot;, '~&amp;gt; 0.2', require: false
gem &amp;quot;parallel_tests&amp;quot;, '~&amp;gt; 3.4', require: false
gem &amp;quot;pry&amp;quot;, '~&amp;gt; 0.10', require: false
gem &amp;quot;simplecov-console&amp;quot;, '~&amp;gt; 0.5', require: false
gem &amp;quot;puppet-debugger&amp;quot;, '~&amp;gt; 1.0', require: false
## We pin these in order to keep the style rules static
gem &amp;quot;rubocop&amp;quot;, '= 1.6.1', require: false
gem &amp;quot;rubocop-performance&amp;quot;, '= 1.9.1', require: false
gem &amp;quot;rubocop-rspec&amp;quot;, '= 2.0.1', require: false
gem &amp;quot;rb-readline&amp;quot;, '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw]
# Added locally and used by us as part of the release process, may not be relevant to you
gem &amp;quot;github_changelog_generator&amp;quot;, require: false
end
group :system_tests do
gem &amp;quot;puppet_litmus&amp;quot;, '&amp;lt; 1.0.0', require: false, platforms: [:ruby]
gem &amp;quot;serverspec&amp;quot;, '~&amp;gt; 2.41', require: false
end
&lt;/code>&lt;/pre>&lt;h2 id="conclusions">Conclusions&lt;/h2>
&lt;p>Since we are not un-publishing the existing &lt;code>puppet-module-gems&lt;/code> meta-gems, we don&amp;rsquo;t expect many people to be impacted by this change.
Many module authors won&amp;rsquo;t even notice it, as they&amp;rsquo;ll &lt;code>pdk update&lt;/code> their modules naturally at some point and inherit the updates before it becomes critical for them.
What this does mean, though, is that you should get more used to running &lt;code>pdk update&lt;/code> regularly as this is the standard way in which updated dependencies and support for new Ruby versions will be delivered.&lt;/p>
&lt;p>Good luck, and happy Puppeting!&lt;/p></description></item><item><title>Blog: Puppet Approved Modules are back!</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2022-10-28-module-approval-process/</link><pubDate>Fri, 28 Oct 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2022-10-28-module-approval-process/</guid><description>
&lt;h2 id="what-does-approved-mean">What does Approved mean?&lt;/h2>
&lt;p>An approved module means we have checked against a specific criterion, if the module meets the suggested criteria, we do not officially offer support, however it is a module that we would recommend using. For a more extensive write-up on exactly what this means check out our &lt;a href="https://forge.puppet.com/about/approved">definition on the Puppet Forge&lt;/a>.&lt;/p>
&lt;h2 id="what-does-it-look-like">What does it look like?&lt;/h2>
&lt;p>When your module is ‘Approved’ it will receive an ‘Approved’ badge on the Puppet Forge.
Here is an example of what an ‘Approved’ module will look like:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2022-10-28-module-approval-process/puppet_approved_module.png" alt="Example of an approved module">&lt;/p>
&lt;h2 id="how-can-i-get-my-module-approved">How can I get my module ‘Approved’?&lt;/h2>
&lt;p>If you feel that your module is actively maintained and meets the guidelines published &lt;a href="https://forge.puppet.com/about/approved/criteria">here&lt;/a> then all you need to do is create an issue in &lt;a href="https://github.com/puppetlabs/puppet-approved-modules">puppet-approved-modules&lt;/a> and one of our team will get around to checking it as soon as they can. They will provide feedback on anything they need to, or award you an ‘Approved’ badge (Yes, it is that simple!).&lt;/p>
&lt;p>Catch us on &lt;a href="https://puppetcommunity.slack.com/archives/C11LCKKQ9">Slack&lt;/a> for any further information or questions.&lt;/p></description></item><item><title>Blog: Changes to Supported Modules</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2022-06-30-changes-to-supported-modules/</link><pubDate>Thu, 30 Jun 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2022-06-30-changes-to-supported-modules/</guid><description>
&lt;p>We are continually reviewing our Supported modules list and understanding usage and value to users. We want to ensure that the CAT team
is prioritizing support for the modules that matter the most to you.&lt;/p>
&lt;p>We are taking the step to remove Puppet support from the below listed models, this change will happen effective 15 July 2022. While these
will not be supported any longer by Puppet, the repos will stay active for use and community contributions, as such they are not going away.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/helm">Helm&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/rook">Rook&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/panos">Panos&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/cisco_ios">Cisco-IOS&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/tagmail">Tagmail&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/vsphere">Vsphere&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/ibm_installation_manager">IBM Installation Manager&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://forge.puppet.com/modules/puppetlabs/websphere_application_server">Websphere Application Server&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="why-are-we-making-these-changes">Why are we making these changes?&lt;/h2>
&lt;p>We are making this move in order for us to focus on providing more robust and quality content for our other existing modules and to also allow
us to bring to our user base new and exciting content that can help you manage and run your environments.&lt;/p>
&lt;h2 id="reminder-on-reporting-of-issues">Reminder on reporting of Issues&lt;/h2>
&lt;p>In order to better triage and prioritize work surrounding each module, please remember to raise issues to the GitHub repositories. We have
deactivated new submissions for the Modules Jira Project and have moved existing tickets into our workflow to be reviewed.&lt;/p>
&lt;p>Catch us on &lt;a href="https://puppetcommunity.slack.com/archives/C11LCKKQ9">Slack&lt;/a> for any further info or questions and look out for some exciting updates in the future.&lt;/p></description></item><item><title>Blog: Community Day returns on the 16th of May! 🎉</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/return-of-community-day/</link><pubDate>Wed, 11 May 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/return-of-community-day/</guid><description>
&lt;p>We are excited to announce that community day is returning on May 16th 2022 and will be continuing every Monday for the foreseeable future.&lt;/p>
&lt;h2 id="why-is-community-day-so-good-anyway">Why is community day so good anyway?&lt;/h2>
&lt;p>It means we get to spend time with our &lt;strong>amazing&lt;/strong> community, understand how our content is being used and help level up our modules and tools by addressing issues and pull requests.&lt;/p>
&lt;p>Community day benefits us as a team too!&lt;/p>
&lt;ul>
&lt;li>Promotes collaboration and healthy team work ❤️&lt;/li>
&lt;li>Upskills new &lt;em>and&lt;/em> existing engineers 👷🏾‍♀️&lt;/li>
&lt;li>Increases productivity 💯&lt;/li>
&lt;li>Overall increase of team morale 👍&lt;/li>
&lt;/ul>
&lt;h2 id="what-to-expect">What to expect&lt;/h2>
&lt;p>We are here to help &lt;strong>you&lt;/strong>!&lt;/p>
&lt;ul>
&lt;li>🕘 We will be available between 9am and 5pm UK time&lt;/li>
&lt;li>🏢 We hang out on &lt;a href="https://puppetlabs.github.io/">GitHub&lt;/a> and our &lt;a href="https://puppetcommunity.slack.com/archives/C11LCKKQ9">community slack channel&lt;/a>&lt;/li>
&lt;li>📚 We want to help you with issues, pull requests and product related questions&lt;/li>
&lt;/ul>
&lt;h2 id="signing-off">Signing off&lt;/h2>
&lt;p>That&amp;rsquo;s it for now! We are excited to see you all on Monday.&lt;/p>
&lt;p>For more information about who we are and what we do in the Content and Tooling team, check out our intro &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/blog/posts/team-rebrand/">blog post&lt;/a>.&lt;/p></description></item><item><title>Blog: Puppet Runtime Manager 0.2.0 Release 🤘</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/prm-0-2-0-release/</link><pubDate>Fri, 06 May 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/prm-0-2-0-release/</guid><description>
&lt;p>We are happy to announce that version 0.2.0 has been released. 🎉&lt;/p>
&lt;p>With this release we introduce the &lt;code>build&lt;/code> and &lt;code>validate&lt;/code> commands along with a number of &lt;a href="https://github.com/puppetlabs/prm/blob/main/CHANGELOG.md">other fixes&lt;/a>.&lt;/p>
&lt;h2 id="build-">Build 🏗&lt;/h2>
&lt;p>After developing a tool you generally want to share it with the wider community or your team.&lt;/p>
&lt;p>Let&amp;rsquo;s take a quick look at what that might look like.&lt;/p>
&lt;p>&lt;code>prm build&lt;/code> provides functionality that will package the current directory and ensure that the resulting artefact is a valid PRM tool.&lt;/p>
&lt;p>A basic project should contain at least a &lt;code>prm-config.yml&lt;/code> and a &lt;code>content&lt;/code> directory.&lt;/p>
&lt;p>&lt;img src="https://i.imgur.com/1VTWFIt.png" alt="">&lt;/p>
&lt;p>Assuming that your project structure looks OK, you can run &lt;code>prm build&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://i.imgur.com/6RgJ0JD.png" alt="">&lt;/p>
&lt;p>The resulting archive will be created in the &lt;code>pkg&lt;/code> directory by default. However you can change the location that the package is created in by providing &lt;code>--targetdir&lt;/code> flag.&lt;/p>
&lt;p>&lt;img src="https://i.imgur.com/OCpnxuB.png" alt="">&lt;/p>
&lt;p>Your package can now be &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/usage/tool_installation/#local-archive">installed&lt;/a> by anyone with &lt;code>prm install&lt;/code>!&lt;/p>
&lt;h2 id="validate-">Validate ✅&lt;/h2>
&lt;p>A validator is a tool which can read and validate a codebase of Puppet content.&lt;/p>
&lt;p>&lt;code>prm validate&lt;/code> enables a content creator to quickly validate Puppet content.
This command allows you to run multiple validation tools serially or concurrently.&lt;/p>
&lt;p>The results of validation can either be outputted to a log file or to the terminal.&lt;/p>
&lt;p>Running the validate command will look something like this:&lt;/p>
&lt;pre>&lt;code class="language-bash=" data-lang="bash=">$ prm validate --codedir . --group syntax_validation
3:49PM INF Found tool group: syntax_validation
3:49PM INF Validating with the metadata-json-lint tool
3:49PM INF Validating with the puppet-syntax tool
3:49PM INF Validating with the puppet-lint tool
TOOL NAME | VALIDATION EXIT CODE | FILE LOCATION
---------------------+----------------------+--------------------------------------------------------------------------------
puppet-syntax | 1 | .prm-validate/syntax_validation/puppet-syntax_2022_April_26_16-49-59.log
metadata-json-lint | 0 | .prm-validate/syntax_validation/metadata-json-lint_2022_April_26_16-49-59.log
puppet-lint | 0 | .prm-validate/syntax_validation/puppet-lint_2022_April_26_16-49-59.log
3:49PM ERR Validation returned 1 error
&lt;/code>&lt;/pre>&lt;p>Check out the &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/usage/validate/">docs&lt;/a> for more information on PRM and how to use these new features!&lt;/p>
&lt;h2 id="feedback-">Feedback 🗣&lt;/h2>
&lt;p>If you try PRM and notice any bugs, have ideas for future features, or would like to learn more about the development, feel free contact anyone from our
team via &lt;a href="https://slack.puppet.com/">community Slack&lt;/a> or submission of a &lt;a href="https://github.com/puppetlabs/prm">GitHub issue&lt;/a>.&lt;/p></description></item><item><title>Blog: Hello From The CAT Team 👋</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/team-rebrand/</link><pubDate>Fri, 22 Apr 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/team-rebrand/</guid><description>
&lt;p>Hey Everyone,&lt;/p>
&lt;p>Firstly let me introduce myself, I am Aaron Robinson, the Engineering Manager for the newly rebranded Content and Tooling Team (CAT).
You may have known us under previous guises such as DevX and IAC, but following on from some organizational changes we have merged these two teams together and rebranded as the Content and Tooling Team.&lt;/p>
&lt;h3 id="what-do-we-do">&lt;strong>What do we do?&lt;/strong>&lt;/h3>
&lt;p>The CAT team are responsible for maintaining and developing a number of supported modules and tools in the Puppet ecosystem.
It is our mission to empower partners, contributors and users to create and consume high quality content.&lt;/p>
&lt;h3 id="who-are-we">&lt;strong>Who are we?&lt;/strong>&lt;/h3>
&lt;p>The Content and Tooling team is based in the UK, with the majority of our engineers in the Belfast office and one remote engineer in mainland UK.
Our Product team is based out of our Portland HQ and we regularly collaborate with them to ensure our strategic direction is aligned.&lt;/p>
&lt;p>Check out below for some quick intros to the team!&lt;/p>
&lt;p>&lt;strong>Aaron Robinson - Engineering Manager&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>I joined Puppet in January this year, moving from an Infrastructure Management role(Network Engineering to be specific) and have over 10 years experience in the tech industry.
I am a sports fanatic and I can usually be found in the stands supporting my local football(soccer if you are in the US) team or the Ulster Rugby team.
If not there, you will find me on the golf course or the squash court.&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/Aaron-Rob">GitHub&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Craig Gumbley - Principal Software Engineer&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hello! I’m Craig, I ❤️ open source &amp;amp; automation.
I’m excited to be starting a new journey with the Content and Tooling team.
Outside of work, I enjoy listening to and making music, coding and just about anything that is technology related.&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/chelnak">GitHub&lt;/a> and &lt;a href="https://twitter.com/_chelnak">Twitter&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Paula Muir - Senior Software Engineer&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hey! I’m Paula and I have been with many different variations of this team over the past 6 years.
I have 2 small children that keep me super busy.
Any downtime I have I like to try to get creative and attempt baking, sewing, and some gardening.&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/pmcmaw">Github&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>David Swan - Software Engineer&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hey, you all should hopefully know me by now, but in case you don&amp;rsquo;t I&amp;rsquo;m David Swan, a software engineer within the CAT team.
I&amp;rsquo;ve been a member of the main team and its spin offs for a few years now, back when it was simply called Modules.
Anyway, I&amp;rsquo;ll be continuing to work on the team for the foreseeable future, so please don&amp;rsquo;t hesitate to reach out to me whenever you need.&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/david22swan">GitHub&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Lukas Audzevicius - Associate Software Engineer&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hello, I&amp;rsquo;m Lukas Audzevicius, an associate level software engineer who joined Puppet in January.
I graduated last year (2021) and although my journey in the IT industry has been short so far, I hope I will be able to learn and grow more working in Puppet.
Outside of work, some of my most common pastimes are gaming and listening to music.
I look forward to having the opportunity to work with Puppet and the community to build great things!&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/LukasAud">GitHub&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Peter Murphy - Software Engineer Intern&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hi, my name is Peter Murphy.
I am a Software Engineering student at Queen&amp;rsquo;s University Belfast and I’m working for Puppet on a year-long internship.
I’ve always had an interest in computers and software, so I’m very happy to be working in a field I enjoy.
Outside of work, I have many hobbies including scuba diving, badminton and hiking.&lt;/p>
&lt;p>You can find me on &lt;a href="https://github.com/petergmurphy">GitHub&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Micah Wilson - CAT Product Manager&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Hi, I’m Micah Wilson.
I’m the PM for the CAT team, the Forge team, and the PIE team.
I live in Portland, OR, more specifically way out in the suburb of Damascus.
Outside of work I enjoy playing volleyball, doing OrangeTheory, and playing with my adorable French Bulldog, Toulouse.&lt;/p>
&lt;/blockquote>
&lt;h3 id="the-future">&lt;strong>The Future&lt;/strong>&lt;/h3>
&lt;p>Now with those intros out of the way we can get on with the good stuff.&lt;/p>
&lt;p>With the relaunch of our team, we are currently detailing our strategy moving forward and will be continuing work on &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/docs/prm">PRM&lt;/a> which, alongside &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/docs/pct">PCT&lt;/a>, promises to provide a cleaner and lighter &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/blog/posts/future-of-pdk/">future for our development tools&lt;/a>.&lt;/p>
&lt;p>On the modules side we have been focusing on stability and reviewing the supported modules on the forge.
Over the coming weeks will be reducing the number of supported modules to reflect recommendations proposed in the review.
This will allow us to focus on the modules that we feel have true value and are aligned with our customers and support teams.&lt;/p>
&lt;p>We are hoping to bring forward some new partnerships with a number of providers to look to establish partner modules and further evolve those we have so keep an eye out for some details on these as we progress through 2022.&lt;/p>
&lt;p>Finally, with our rebrand and now our relaunch complete, we will be reinstating Community Day on Monday 16th May.
For those of you unfamiliar with Community Day, it occurs each Monday.
During this time we will triage and address new issues and pull requests from the community and not from our internal workslate.
These are then prioritized and either actioned or put into the backlog for further discussion.&lt;/p>
&lt;p>As the team gets up to speed you will see a lot more community engagement from the team and we will look to build on this and work with the community to build a brighter future for content at Puppet.&lt;/p>
&lt;p>Thank you for taking the time to read this blog, we look forward to working alongside our community again and rebuilding that relationship.&lt;/p>
&lt;p>Feel free to reach out and say hello via the community slack channel and I anticipate many great ideas coming forward to us on how we enhance and build the experience with our modules and tools.&lt;/p>
&lt;p>Aaron.&lt;/p></description></item><item><title>Blog: Puppet Runtime Manager 0.1.0 Release 🚀</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/prm-initial-release/</link><pubDate>Mon, 31 Jan 2022 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/prm-initial-release/</guid><description>
&lt;p>We are proud to announce the first release for the new tool for executing arbitrary commands against your code in a Puppet runtime: The &lt;strong>Puppet Runtime Manager (PRM)&lt;/strong>.&lt;/p>
&lt;p>The &lt;strong>Puppet Runtime Manager&lt;/strong> abstracts away the Puppet Ruby development environment to enable you to execute against and validate content for any Puppet Product that you might author!&lt;/p>
&lt;h2 id="installing-prm-">Installing PRM 💾&lt;/h2>
&lt;p>To get started, you can either download the release from the &lt;a href="https://github.com/puppetlabs/prm/releases/tag/0.1.0">PRM repo&lt;/a> or use our installer scripts:&lt;/p>
&lt;ul class="nav nav-tabs" id="tabs-0" role="tablist">&lt;li class="nav-item">
&lt;a class="nav-link active tab-Unix-Systems"
id="tabs-0-0-tab" data-toggle="tab" href="#tabs-0-0" role="tab" onclick="handleClick(&amp;#34;Unix-Systems&amp;#34;);"
aria-controls="tabs-0-0" aria-selected="true">
Unix Systems
&lt;/a>
&lt;/li>&lt;li class="nav-item">
&lt;a class="nav-link tab-Windows-Systems"
id="tabs-0-1-tab" data-toggle="tab" href="#tabs-0-1" role="tab" onclick="handleClick(&amp;#34;Windows-Systems&amp;#34;);"
aria-controls="tabs-0-1" aria-selected="false">
Windows Systems
&lt;/a>
&lt;/li>&lt;/ul>
&lt;div class="tab-content" id="tabs-0-content">&lt;div class="tab-pane fade show active"
id="tabs-0-0" role="tabpanel" aria-labelled-by="tabs-0-0-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">curl -L https://pup.pt/prm/install.sh | sh&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;div class="tab-pane fade"
id="tabs-0-1" role="tabpanel" aria-labelled-by="tabs-0-1-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Powershell" data-lang="Powershell">&lt;span style="color:#8be9fd;font-style:italic">iex &lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&amp;amp;{ &lt;/span>$(&lt;span style="color:#8be9fd;font-style:italic">irm &lt;/span>https://pup.pt/prm/install.ps1)&lt;span style="color:#f1fa8c">; Install-Prm }&amp;#34;&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;p>This will install the latest release of PRM to &lt;code>~/.puppetlabs/prm&lt;/code>.&lt;/p>
&lt;div class="alert alert-warning" role="alert">
&lt;h4 class="alert-heading">PRM is Experimental!&lt;/h4>
PRM is currently in an EXPERIMENTAL phase and feedback is encouraged via &lt;a href="https://github.com/puppetlabs/pct/discussions">our Discussions page on GitHub&lt;/a>.
&lt;/div>
&lt;h3 id="telemetry--prm">Telemetry &amp;amp; PRM&lt;/h3>
&lt;p>By default, PRM collects some telemetry during each run.
This information is non-identifying and does not include any personal or organizational details.&lt;/p>
&lt;p>For more information, see &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/concepts/telemetry/">our documentation on Telemetry&lt;/a>.&lt;/p>
&lt;p>If you&amp;rsquo;d like to install PRM &lt;em>without&lt;/em> telemetry, you can use these scripts:&lt;/p>
&lt;ul class="nav nav-tabs" id="tabs-3" role="tablist">&lt;li class="nav-item">
&lt;a class="nav-link active tab-Notel-on-Unix-Systems"
id="tabs-3-0-tab" data-toggle="tab" href="#tabs-3-0" role="tab" onclick="handleClick(&amp;#34;Notel-on-Unix-Systems&amp;#34;);"
aria-controls="tabs-3-0" aria-selected="true">
Notel on Unix Systems
&lt;/a>
&lt;/li>&lt;li class="nav-item">
&lt;a class="nav-link tab-Notel-on-Windows-Systems"
id="tabs-3-1-tab" data-toggle="tab" href="#tabs-3-1" role="tab" onclick="handleClick(&amp;#34;Notel-on-Windows-Systems&amp;#34;);"
aria-controls="tabs-3-1" aria-selected="false">
Notel on Windows Systems
&lt;/a>
&lt;/li>&lt;/ul>
&lt;div class="tab-content" id="tabs-3-content">&lt;div class="tab-pane fade show active"
id="tabs-3-0" role="tabpanel" aria-labelled-by="tabs-3-0-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">curl -L https://pup.pt/prm/install.sh | sh -s -- --no-telemetry&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;div class="tab-pane fade"
id="tabs-3-1" role="tabpanel" aria-labelled-by="tabs-3-1-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Powershell" data-lang="Powershell">&lt;span style="color:#8be9fd;font-style:italic">iex &lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&amp;amp;{ &lt;/span>$(&lt;span style="color:#8be9fd;font-style:italic">irm &lt;/span>https://pup.pt/prm/install.ps1)&lt;span style="color:#f1fa8c">; Install-Prm -NoTelemetry}&amp;#34;&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;h3 id="prerequisites--support">Prerequisites &amp;amp; Support&lt;/h3>
&lt;p>In this initial release, PRM only supports one backend for running tools: Docker.
You will need to be able to use Docker locally to pull, build, and run container images for this release (though PRM handles all those steps for you).&lt;/p>
&lt;p>Right now, only Linux containers in Docker are supported, but the Docker backend is functional on Windows, Linux, and MacOS systems.&lt;/p>
&lt;p>A future release will add a local execution backend, enabling you to just use your locally installed Puppet Agent for the runtime.&lt;/p>
&lt;p>If there are other backends you&amp;rsquo;d like to see supported, please &lt;a href="https://github.com/puppetlabs/pct/discussions">raise a discussion with us!&lt;/a>&lt;/p>
&lt;h2 id="docs-in-the-terminal-">Docs in the Terminal 📃&lt;/h2>
&lt;p>PRM has a pair of robust help systems built in for reviewing reference, concept, and narrative documentation.&lt;/p>
&lt;p>To see the help for any command or subcommand:&lt;/p>
&lt;ul class="nav nav-tabs" id="tabs-4" role="tablist">&lt;li class="nav-item">
&lt;a class="nav-link active tab-Use-the-help-subcommand"
id="tabs-4-0-tab" data-toggle="tab" href="#tabs-4-0" role="tab" onclick="handleClick(&amp;#34;Use-the-help-subcommand&amp;#34;);"
aria-controls="tabs-4-0" aria-selected="true">
Use the help subcommand
&lt;/a>
&lt;/li>&lt;li class="nav-item">
&lt;a class="nav-link tab-Use-the-help-flag"
id="tabs-4-1-tab" data-toggle="tab" href="#tabs-4-1" role="tab" onclick="handleClick(&amp;#34;Use-the-help-flag&amp;#34;);"
aria-controls="tabs-4-1" aria-selected="false">
Use the help flag
&lt;/a>
&lt;/li>&lt;/ul>
&lt;div class="tab-content" id="tabs-4-content">&lt;div class="tab-pane fade show active"
id="tabs-4-0" role="tabpanel" aria-labelled-by="tabs-4-0-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">prm &lt;span style="color:#8be9fd;font-style:italic">help&lt;/span> &lt;span style="color:#6272a4"># Displays the help for PRM itself&lt;/span>
prm &lt;span style="color:#8be9fd;font-style:italic">help&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> &lt;span style="color:#6272a4"># Displays the help for the prm exec command&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;div class="tab-pane fade"
id="tabs-4-1" role="tabpanel" aria-labelled-by="tabs-4-1-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">prm --help &lt;span style="color:#6272a4"># Displays the help for PRM itself&lt;/span>
prm &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> --help &lt;span style="color:#6272a4"># Displays the help for the prm exec command&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;p>To read the concept and narrative documentation locally instead of &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/">online&lt;/a>:&lt;/p>
&lt;ul class="nav nav-tabs" id="tabs-6" role="tablist">&lt;li class="nav-item">
&lt;a class="nav-link active tab-List-Available-Topics"
id="tabs-6-0-tab" data-toggle="tab" href="#tabs-6-0" role="tab" onclick="handleClick(&amp;#34;List-Available-Topics&amp;#34;);"
aria-controls="tabs-6-0" aria-selected="true">
List Available Topics
&lt;/a>
&lt;/li>&lt;li class="nav-item">
&lt;a class="nav-link tab-Filter-Available-Topics"
id="tabs-6-1-tab" data-toggle="tab" href="#tabs-6-1" role="tab" onclick="handleClick(&amp;#34;Filter-Available-Topics&amp;#34;);"
aria-controls="tabs-6-1" aria-selected="false">
Filter Available Topics
&lt;/a>
&lt;/li>&lt;li class="nav-item">
&lt;a class="nav-link tab-Display-a-Topic"
id="tabs-6-2-tab" data-toggle="tab" href="#tabs-6-2" role="tab" onclick="handleClick(&amp;#34;Display-a-Topic&amp;#34;);"
aria-controls="tabs-6-2" aria-selected="false">
Display a Topic
&lt;/a>
&lt;/li>&lt;/ul>
&lt;div class="tab-content" id="tabs-6-content">&lt;div class="tab-pane fade show active"
id="tabs-6-0" role="tabpanel" aria-labelled-by="tabs-6-0-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">prm explain --list
prm explain &lt;span style="color:#6272a4"># Identical to prm explain --list&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;div class="tab-pane fade"
id="tabs-6-1" role="tabpanel" aria-labelled-by="tabs-6-1-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">prm explain --category concept &lt;span style="color:#6272a4"># Only list concept docs&lt;/span>
prm explain --tag tools &lt;span style="color:#6272a4"># Only list docs about tools&lt;/span>
prm explain --category concept --tag tools &lt;span style="color:#6272a4"># Multi-filter&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;div class="tab-pane fade"
id="tabs-6-2" role="tabpanel" aria-labelled-by="tabs-6-2-tab">&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-Bash" data-lang="Bash">prm --help &lt;span style="color:#6272a4"># Displays the help for PRM itself&lt;/span>
prm &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> --help &lt;span style="color:#6272a4"># Displays the help for the prm exec command&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;p>For more detailed information on the &lt;code>explain&lt;/code> subsystem and documentation, see &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/usage/explain-subsystem/">our narrative document on it&lt;/a>.&lt;/p>
&lt;h2 id="run-tools-against-your-content-">Run Tools Against Your Content 🏃🏻‍♀️&lt;/h2>
&lt;p>&lt;strong>PRM&lt;/strong> can run tools against any type of a Puppet Product project.
You can run r10k against Puppet &lt;a href="https://github.com/puppetlabs/control-repo">control repos&lt;/a>, validate EPP files in Puppet &lt;a href="https://puppet.com/docs/puppet/7/modules_fundamentals.html">modules&lt;/a>, rubocop Bolt &lt;a href="https://puppet.com/docs/bolt/latest/projects.html">projects&lt;/a>, and more!&lt;/p>
&lt;p>We&amp;rsquo;ve shipped with a subset of tools you can use:&lt;/p>
&lt;ul>
&lt;li>EPP&lt;/li>
&lt;li>Heira EYAML&lt;/li>
&lt;li>metadata-json-lint&lt;/li>
&lt;li>onceover&lt;/li>
&lt;li>puppet-lint&lt;/li>
&lt;li>puppet-strings&lt;/li>
&lt;li>puppet-syntax&lt;/li>
&lt;li>r10k&lt;/li>
&lt;li>ra10ke&lt;/li>
&lt;li>rubocop&lt;/li>
&lt;li>rspec-puppet&lt;/li>
&lt;/ul>
&lt;p>These tools are currently maintained by the DevX team in the &lt;a href="https://github.com/puppetlabs/fantastic-adventure">fantastic-adventure repository&lt;/a>.
If you&amp;rsquo;d like to learn more about how they&amp;rsquo;re constructed or how to develop your own, check out our &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/concepts/tool-anatomy/">&lt;em>Anatomy of a Tool&lt;/em> guide&lt;/a>.&lt;/p>
&lt;p>Since PRM tools are external to the PRM code base, Puppet Product teams, Partners and the wider OSS Community can publish their own tool packages without input or effort from the DevX team.
This enables a single tool to support many products.&lt;/p>
&lt;h3 id="example-generate-reference-docs-for-puppetlabs-acl">Example: Generate Reference Docs for puppetlabs-acl&lt;/h3>
&lt;div class="alert alert-info" role="alert">
This example is a shortened version of our &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/docs/prm/quick-start/">Quick Start Guide&lt;/a>, which includes a more detailed walkthrough and includes configuring PRM beyond the defaults.
&lt;/div>
&lt;p>Before we generate the reference documents for a Puppet module, we might want to ensure that we have full coverage for our module.&lt;/p>
&lt;p>Assuming we&amp;rsquo;ve already cloned a copy of [https://github.com/puppetlabs/puppetlabs-acl] locally to &lt;code>~/code/modules/puppetlabs-acl&lt;/code>, we can run the following command:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">prm exec puppetlabs/puppet-strings --codedir ~/code/modules/puppetlabs-acl
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">4:54PM INF Creating new image. Please wait...
4:54PM INF Code path: ~/code/modules/puppetlabs-acl
4:54PM INF Cache path: ~/.pdk/prm/cache
4:54PM INF Additional Args: []
Files: 5
Modules: 2 ( 0 undocumented)
Classes: 4 ( 0 undocumented)
Constants: 25 ( 0 undocumented)
Attributes: 9 ( 0 undocumented)
Methods: 49 ( 0 undocumented)
Puppet Data Types: 0 ( 0 undocumented)
Puppet Data Type Aliases: 0 ( 0 undocumented)
Puppet Classes: 0 ( 0 undocumented)
Puppet Types: 1 ( 0 undocumented)
Puppet Providers: 1 ( 0 undocumented)
Puppet Functions: 0 ( 0 undocumented)
Puppet Defined Types: 0 ( 0 undocumented)
Puppet Plans: 0 ( 0 undocumented)
Puppet Tasks: 0 ( 0 undocumented)
100.00% documented
4:54PM INF Tool puppetlabs/puppet-strings executed successfully
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Behind the scenes, PRM built a docker container on the fly from the tool definition for &lt;code>puppet-strings&lt;/code> and then executed it against the specified directory.
The output we see without the PRM log prefix is what the docker container&amp;rsquo;s stdout returned;
in this case, the documentation results for the ACL module.&lt;/p>
&lt;p>We can also pass arbitrary arguments to the tool;
to generate the reference documentation, we need to specify that we want to generate the document and set the format to markdown.
This will create (or update if it exists) the &lt;code>REFERENCE.md&lt;/code> file in the module&amp;rsquo;s folder.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">prm &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> puppetlabs/puppet-strings --codedir ~/code/modules/puppetlabs-acl --toolArgs &lt;span style="color:#f1fa8c">&amp;#34;strings generate --format markdown&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">4:54PM INF Creating new image. Please wait...
4:54PM INF Code path: ~/code/modules/puppetlabs-acl
4:54PM INF Cache path: ~/.pdk/prm/cache
4:54PM INF Additional Args: [strings generate --format markdown]
Files: 5
Modules: 2 ( 0 undocumented)
Classes: 4 ( 0 undocumented)
Constants: 25 ( 0 undocumented)
Attributes: 9 ( 0 undocumented)
Methods: 49 ( 0 undocumented)
Puppet Data Types: 0 ( 0 undocumented)
Puppet Data Type Aliases: 0 ( 0 undocumented)
Puppet Classes: 0 ( 0 undocumented)
Puppet Types: 1 ( 0 undocumented)
Puppet Providers: 1 ( 0 undocumented)
Puppet Functions: 0 ( 0 undocumented)
Puppet Defined Types: 0 ( 0 undocumented)
Puppet Plans: 0 ( 0 undocumented)
Puppet Tasks: 0 ( 0 undocumented)
100.00% documented
4:54PM INF Tool puppetlabs/puppet-strings executed successfully
&lt;/code>&lt;/pre>&lt;/div>&lt;p>While the output of Puppet Strings itself isn&amp;rsquo;t any different, we can check the timestamp on the &lt;code>REFERENCE.md&lt;/code> file and verify that it was just updated (or created if it didn&amp;rsquo;t already exist).&lt;/p>
&lt;p>So!
That&amp;rsquo;s how you run a PRM tool against a folder and can send the tool specific arguments, too!&lt;/p>
&lt;h2 id="coming-soon">Coming Soon❗&lt;/h2>
&lt;p>As mentioned earlier, this is the &lt;em>initial&lt;/em> release for PRM;
we&amp;rsquo;re not done!&lt;/p>
&lt;p>Our next planned release, &lt;code>0.2.0&lt;/code>, will add the &lt;code>validate&lt;/code> functionality you may remember from the PDK.
In short, this will enable you to run multiple tools against your code in parallel and report back to you both pass/fail and detailed failure notes (if any).
We are targeting this release for late March/early April.&lt;/p>
&lt;p>After that, our &lt;code>0.3.0&lt;/code> release will add local execution as a backend, removing the dependency on Docker so long as you have the Puppet Agent installed locally.&lt;/p>
&lt;p>In the meantime, we will be improving and adding tools; if you add any yourself, we&amp;rsquo;d love to hear about it and highlight them in future blog posts!&lt;/p>
&lt;p>Til next time!&lt;/p>
&lt;p>~ The DevX Team&lt;/p></description></item><item><title>Blog: A Fond Farewell For Now to Community Day &amp; Norman</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-10-20-fond-farewell/</link><pubDate>Wed, 20 Oct 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-10-20-fond-farewell/</guid><description>
&lt;h2 id="iac-community-day">IAC Community Day&lt;/h2>
&lt;h3 id="background">Background&lt;/h3>
&lt;p>The Infrastructure Automation Content (IAC) team formed from the merger of 4 core content-focused teams (Modules, Windows, Cloud &amp;amp; Containers, and Networking),
maintaining forty-five open-source supported Puppet modules and over a dozen tools that help reduce the content maintenance and support costs.&lt;/p>
&lt;p>A crucial part of Puppet’s success has always been the support of the community.
The IAC team, like with all module teams before, would have had a dedicated engineer or engineers assigned to community triage, usually on a rotational basis.&lt;/p>
&lt;p>The triage rota consumed 20% of the team&amp;rsquo;s engineering resources. It was challenging due to:&lt;/p>
&lt;ul>
&lt;li>Lack of domain knowledge&lt;/li>
&lt;li>Work spilling over either into or out of triage during rotation&lt;/li>
&lt;li>Impact to other team members not on rotation&lt;/li>
&lt;li>Engineers left feeling drained, low self-esteem&lt;/li>
&lt;li>Engineers dreading rotating onto triage.&lt;/li>
&lt;/ul>
&lt;h3 id="community-day-introduced-in-november-2020">Community Day (Introduced in November 2020)&lt;/h3>
&lt;p>Community day came about as part of reviewing of our triaging commitments and chatting with the team listening to their concerns.&lt;/p>
&lt;p>As mentioned, 20% of the team’s engineering resourcing and effort was already going into the triage rotation. So we asked ourselves the question:&lt;/p>
&lt;blockquote>
&lt;p>What if we focused this 20% effort and had the whole team take part in a full day community triage?&lt;/p>
&lt;/blockquote>
&lt;p>Benefits:&lt;/p>
&lt;ul>
&lt;li>Upskilling&lt;/li>
&lt;li>Teamwork&lt;/li>
&lt;li>Reduced distractions&lt;/li>
&lt;li>Greater community focus&lt;/li>
&lt;li>Starting the week off with a win&lt;/li>
&lt;li>Productivity within the team increased (hard to believe even for us, at first)&lt;/li>
&lt;/ul>
&lt;p>Not only have we been able to address the backlog of community requests across forty-five supported open source modules (plus over a dozen tooling repos), the team have been able to focus on feature delivery.&lt;/p>
&lt;p>Since switching to the new community day, over the last eleven months, the team have:&lt;/p>
&lt;ul>
&lt;li>Handled† 1536 issues&lt;/li>
&lt;li>Performed 205 module releases&lt;/li>
&lt;li>Released 30 tooling updates&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>† Handled meaning a team member has either:&lt;/p>
&lt;ul>
&lt;li>Closed a PR or Jira&lt;/li>
&lt;li>Merged community a PR&lt;/li>
&lt;li>or provided feedback on a community PR&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>By committing to community day and limiting distractions to 1 day, the team have also delivered:&lt;/p>
&lt;ol>
&lt;li>A new Cloud CI
&lt;ol>
&lt;li>With multi-node testing support&lt;/li>
&lt;li>New automated workflow&lt;/li>
&lt;li>Internal developer environment support&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Cisco Network device enhancement&lt;/li>
&lt;li>New DSC builder generating &amp;gt;300 DSC PowerShell modules uploaded on the forge&lt;/li>
&lt;li>3 OS certifications&lt;/li>
&lt;li>Certified all the supported modules again Puppet 7, including:
&lt;ol>
&lt;li>Raising and testing fixes for numerous issues in Puppet 7 nightly agent builds prior to release&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Rolled out the Trusted Contributor program&lt;/li>
&lt;li>Improved our community communication with a weekly blog post, enhancing our community reporting&lt;/li>
&lt;/ol>
&lt;p>All in all, the IAC community day has not only enabled the team to reconnect with the community, address the content backlog, and upskill across the team;
it has also improved team productivity by reducing distraction and increasing team morale.
Mondays are, at the best of times, a tough day.
Starting a week off with a win? Priceless.&lt;/p>
&lt;p>Sadly, Community Day is coming to an end.
Due to a significant reduction in resourcing, it is no longer possible to provide the technical support needed to run a dedicated community support day.&lt;/p>
&lt;p>The content maintained by the IAC team is still of high importance to Puppet.
Puppet would like to encourage our community to reach out via our public slack channels for assistance.
Our PM team will help prioritize issues raised.&lt;/p>
&lt;h2 id="farewell-norman-">Farewell, Norman 💜&lt;/h2>
&lt;p>This week we have to say farewell to Norman, the Engineering Manager of the IAC and DevX Teams.
This is a particularly sad goodbye as many of us, past and present, consider Norman one of the best leaders we have had the privilege of working with.&lt;/p>
&lt;p>In just under three years, Norman led us to some fantastic achievements and kept us motivated and moving forward through turbulent times.
Norman has shown unparalleled dedication to his team’s wellbeing, motivation, and personal development whilst still acting as a clarifying arbiter between the high-level vision and plans of the organisation.
It was a tough balancing act that he seemed to be able to do, with his usual 110% dedication he never falters from.&lt;/p>
&lt;p>Norman motivated and enabled us to become far better engineers and people than we were prior to being taken under his wing.
The remit of the IAC team is a tough one, and one that can often be underappreciated, but Norman always fought our corner and sung our praises to anyone who stood still long enough to listen.
Norman was great at suggesting and soliciting us to suggest new processes / ideas (Community Day being a prime example), that would make us more efficient and motivated, as a team.
We benefited from his wealth of knowledge, experience (both technical and managerial) and genuine care for his colleagues and team.&lt;/p>
&lt;p>We’d like to thank Norman for his hard work and support over these nearly three years.
The IAC and DevX teams owe him a huge gratitude and we’ll miss him, as we bid farewell and good luck in your next venture!&lt;/p></description></item><item><title>Blog: The future of the Puppet Developer Kit (PDK)</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/future-of-pdk/</link><pubDate>Tue, 14 Sep 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/future-of-pdk/</guid><description>
&lt;p>The Puppet Developer Kit was launched in 2017 to help our users develop high quality modules faster and over the years, it has seen regular development towards that goal.&lt;/p>
&lt;p>It was designed to be a single install that would provide everything you needed to write, lint, test and publish a Puppet module — and for the most part, that&amp;rsquo;s what it did.&lt;/p>
&lt;h2 id="what-worked">What worked&lt;/h2>
&lt;p>The PDK did exactly what it set out to do. It enabled users of Puppet and its ecosystem — regardless of experience level — to create Modules that were testable, deployable, and shareable. It provided functionality to keep those modules running against all supported Puppet versions, as well as the core Gemset to run all the features built into the template.&lt;/p>
&lt;h2 id="what-didnt-work">What didn’t work&lt;/h2>
&lt;p>In order for all this to work, the PDK hinged on that single template which was maintained by the Puppet Developer Experience (PDE) team.&lt;/p>
&lt;p>Since its launch, the PDK has come to support the creation of more than just modules and classes. With each successive addition, the template and the packaging system had to support more dependencies, and these dependencies needed to be monitored and updated in line with Puppet agent support and things like security fixes. This overhead meant the PDK couldn’t move forward quickly in supporting the wealth of content our users wanted. And every new feature made the template system that much more complex and awkward to customize for your own needs.&lt;/p>
&lt;h2 id="the-path-forward">The path forward&lt;/h2>
&lt;p>The DevX strategy is to build a new PDK while maintaining the existing PDK at version 2.x. What this means is that updates to the PDK 2.x will be limited to bug fixes and updates to support the latest Puppet gem.&lt;/p>
&lt;p>We will be designing and building multiple tools to cover the functionality of the existing PDK:&lt;/p>
&lt;ul>
&lt;li>Content creation&lt;/li>
&lt;li>Linting / Validation&lt;/li>
&lt;li>Testing&lt;/li>
&lt;li>Packaging and sharing&lt;/li>
&lt;li>Runtime management&lt;/li>
&lt;li>Each tool will be released ASAP for early feedback and iteration. They will be designed to work independently of each other, giving you the choice to download and install the parts of the Kit that you need.&lt;/li>
&lt;/ul>
&lt;h2 id="puppet-content-templates">Puppet Content Templates&lt;/h2>
&lt;p>You may already be aware of the DevX team&amp;rsquo;s first part of this strategy: Puppet Content Templates (PCT).&lt;/p>
&lt;p>PCT expands on the original PDK’s “new” functionality enabling Puppet, Puppet content creators, and our customers to create their own templates and share them with their teams. No longer do we have a single one-size-fits-all template. Instead we have many small and composable templates that allow you to mix &amp;amp; match to make your modules everything you want — and only what you want.&lt;/p>
&lt;p>If you’re new to Puppet, PCT ships with the common templates:&lt;/p>
&lt;ul>
&lt;li>Module&lt;/li>
&lt;li>Class&lt;/li>
&lt;li>Type&lt;/li>
&lt;/ul>
&lt;p>This functionality was available in PDK, but with our new approach, we’ve been able to quickly build templates for other Puppet content:&lt;/p>
&lt;ul>
&lt;li>Control Repo&lt;/li>
&lt;li>Resource API Provider&lt;/li>
&lt;li>Bolt Projects&lt;/li>
&lt;li>Bolt Plans&lt;/li>
&lt;li>Bolt Tasks&lt;/li>
&lt;/ul>
&lt;div class="alert alert-primary" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
At the time of writing, we are in the process of shipping PCT 0.3.0 which adds the ability to package and install new templates. This makes it possible to share the templates with others on your team by just distributing a tarball.
&lt;/div>
&lt;p>In the near future we also plan to allow for the publication of templates to the Puppet Forge for sharing, download and installation. If you want all your modules to include GitHub actions for auto-publishing to the Forge when you tag a release, you&amp;rsquo;d just install that template. If you prefer GitLab or CircleCI instead, you&amp;rsquo;d choose the appropriate template. And if one doesn&amp;rsquo;t exist that does what you need, then you could write it yourself and contribute it to the community.&lt;/p>
&lt;div class="alert alert-primary" role="alert">
&lt;h4 class="alert-heading">Note&lt;/h4>
PCT is in active development and is pre-release; therefore it is not recommended for production use at this time.
&lt;/div>
&lt;p>To find out more on PCT, you can watch James Pogran’s coverage of it on Pulling the Strings LIVE.&lt;/p>
&lt;h2 id="technical-choices">Technical Choices&lt;/h2>
&lt;p>To build these new tools, we have consciously chosen to move away from Ruby as a platform and are instead developing these CLIs in Go. This allows us to ship a compiled binary which is faster for you to run, and faster for us to build and test. This results in our team’s ability to iterate faster and ship new rich features more often. It also means that your experience of creating a new module happens before your finger has lifted from the enter key.&lt;/p>
&lt;p>Ruby will always be present when testing and validating. Puppet and its ecosystem are built upon it. Our new tooling will include a system that will provide the PDK functionality of a Puppet Runtime sandbox, with you choosing which version of Puppet to install and run our tooling against.&lt;/p>
&lt;p>The aim for the new tools is to make them loosely coupled to Puppet, while still providing a clear workflow that allows you to build great Puppet content. This means that you will not be forced to update when the pdk-templates are updated, or to include functionality in your code that you don’t want or need. We hope this approach will provide flexibility for different development choices and will help new users understand wider Puppet concepts without the sometimes intrusive guardrails provided by the current PDK.&lt;/p>
&lt;p>Finally, we want the tools to be extensible. With PCT, you can install new templates. With our validation tool, we want content creators to be able to plug in new validators, and to write validation tools for testing their content. And with our Packaging and Sharing tool, we want you to be able to share content to multiple locations, including the Forge.&lt;/p>
&lt;p>With this flexible plugin architecture, this could mean eventually supporting Onceover on your control repository before upgrading to a new version of Puppet, or being able to fire up Corey&amp;rsquo;s Puppet Debugger on a previous version of Puppet to figure out the intended behavior of that old module you&amp;rsquo;ve inherited.&lt;/p>
&lt;h2 id="feedback">Feedback&lt;/h2>
&lt;p>Feedback is so important to us at this early stage of design and development. The DevX team would love to engage with our community about our roadmap and we hope that you can see yourself using these tools in the future. Your feedback can have a real impact on what we build.&lt;/p>
&lt;p>To get in touch, you can find us on the #office-hours channel within Puppet Community Slack every Monday, alternating weekly between about 1pm and 5pm GMT.&lt;/p>
&lt;p>Out of those hours, please get involved in our discussions at Discussions · puppetlabs/pct · GitHub.&lt;/p></description></item><item><title>Blog: Puppet Content Templates 0.1.0 🚀</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-06-04-pct-early-release/</link><pubDate>Fri, 04 Jun 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-06-04-pct-early-release/</guid><description>
&lt;h1 id="pdk-puppet-content-templates-010-released-">PDK Puppet Content Templates 0.1.0 released ✨&lt;/h1>
&lt;p>We are proud to announce the first release for the new PDK templating system: &lt;strong>Puppet Content Templates (PCT)&lt;/strong>.&lt;/p>
&lt;p>&lt;strong>Puppet Content Templates&lt;/strong> codify a structure to produce content for any Puppet Product that can be authored without direct oversight of the Puppet PDK team.&lt;/p>
&lt;p>To get started download the release from the &lt;a href="https://github.com/puppetlabs/pct/">pct repo&lt;/a>. A step by step guide is included in the README.&lt;/p>
&lt;blockquote>
&lt;p>PCT is currently in an EXPERIMENTAL phase and feedback is encouraged via &lt;a href="https://github.com/puppetlabs/pct/discussions">pct/discussions&lt;/a>. ⚠️&lt;/p>
&lt;/blockquote>
&lt;h2 id="create-all-types-of-content-">Create all types of content 🎨&lt;/h2>
&lt;p>A &lt;strong>PCT&lt;/strong> can create any type of a Puppet Product project. You can create Puppet &lt;a href="https://github.com/puppetlabs/control-repo">control repos&lt;/a>, Puppet &lt;a href="https://puppet.com/docs/puppet/7/modules_fundamentals.html">modules&lt;/a>, Bolt &lt;a href="https://puppet.com/docs/bolt/latest/projects.html">projects&lt;/a>, and more!&lt;/p>
&lt;p>A &lt;strong>PCT&lt;/strong> can also create one or more independent files to be used inside a project. You can create Puppet &lt;a href="https://puppet.com/docs/puppet/7/lang_classes.html">classes&lt;/a>, &lt;a href="https://puppet.com/docs/puppet/7/fact_overview.html">facts&lt;/a>, &lt;a href="https://puppet.com/docs/puppet/7/functions_ruby_overview.html">functions&lt;/a>, or other tooling configuration files such as CI files, gitignores, or rubocop.yml.&lt;/p>
&lt;p>Since a PCT is external to the PDK code base, Puppet Product teams, Partners and the wider OSS Community can publish their own content without input or effort from the DevX team. This enables a single tool to support many products.&lt;/p>
&lt;h2 id="building-blocks-">Building blocks 🧱&lt;/h2>
&lt;p>A set of individual &lt;strong>PCTs&lt;/strong> can be combined to produce something as simple as a Puppet module with several Puppet classes or as complex as a complete Puppet Control repo with roles and profiles ready to deploy.&lt;/p>
&lt;p>We want to enable a building block experience. An experience where you can pick and choose from an array of templates to build the content you want. We aim to be like your favorite building block toy, where you choose your components and end up with a wonderful structure.&lt;/p>
&lt;p>An opt-in experience, where you choose what is added to your content, instead of dealing with a long list of files you&amp;rsquo;ll never use.&lt;/p>
&lt;h2 id="customizable-">Customizable 📐&lt;/h2>
&lt;p>Each &lt;strong>PCT&lt;/strong> comes with parts that can be controlled via configuration. These parts have common defaults, but can be changed to suit your environment. The idea is to enable quick deployment of templates, but allow customization to suit your needs.&lt;/p>
&lt;p>This user can customize how PCTs operate by using YAML files and never need to know how to make a template.&lt;/p>
&lt;p>If you want a more drastic change, you can copy the &lt;strong>PCT&lt;/strong> and add your own files and changes, then use that &lt;strong>PCT&lt;/strong> without having to get a pull request approved.&lt;/p></description></item><item><title>Blog: Run multi-node module tests with cloud continuous integration (CI) in Google Cloud Platform (GCP)</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-05-07-running-multinode-modules-gcp/</link><pubDate>Fri, 07 May 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-05-07-running-multinode-modules-gcp/</guid><description>
&lt;p>Multi-node modules are modules which use multiple nodes to run integration tests. Integration testing is where you set up multiple Virtual Machines (VM) or containers, and test interactions between them. For example, this could be:&lt;/p>
&lt;ul>
&lt;li>Installing Puppet Enterprise (PE) and multiple Puppet agents.&lt;/li>
&lt;li>Setting up an NTP server and registering NTP clients.&lt;/li>
&lt;li>Installing open source Puppet Server and multiple Puppet agents.&lt;/li>
&lt;/ul>
&lt;p>The order you perform integration tests is important, and you need to be able to run a test on an individual system.&lt;/p>
&lt;p>Running multi-node modules in GCP involves the following steps:&lt;/p>
&lt;ul>
&lt;li>Provision a node using a Bolt task.&lt;/li>
&lt;li>Set up a multi-node environment for testing using a Bolt task or plan.&lt;/li>
&lt;li>Run a test - you can use existing serverspec or Litmus helpers to set up any dependencies required by the module.&lt;/li>
&lt;li>Teardown the machine using a provision task.&lt;/li>
&lt;/ul>
&lt;p>This guide walks you through each step, and then provides examples of how your code would look in different environments.&lt;/p>
&lt;h2 id="provision-a-node">Provision a node&lt;/h2>
&lt;p>You can use Litmus and a Bolt task to provision a VM or a container. The provision module&amp;rsquo;s &lt;a href="https://github.com/puppetlabs/provision/blob/main/tasks">available tasks&lt;/a> spin up the test environment. When run, it creates a &lt;code>litmus_inventory.yaml&lt;/code> file that allows &lt;a href="https://github.com/puppetlabs/bolt">Bolt&lt;/a> and &lt;a href="https://serverspec.org/">serverspec&lt;/a> to communicate with that VM.&lt;/p>
&lt;p>Running tasks in the provision module allows you to add arbitrary key/pair values to the Bolt inventory file. The Bolt variables allows you to have multiple labels associated with a single machine. For example:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-05-07-running-multinode-modules-gcp/inventory_role.png" alt="Showing role info in litmus_inventory.yaml file">
&lt;a href="https://github.com/puppetlabs/puppetlabs-websphere_application_server/blob/main/plans/provision_machines.pp">Example_websphere_provision_plan&lt;/a>&lt;/p>
&lt;h2 id="set-up-a-multi-node-environment-for-testing">Set up a multi-node environment for testing&lt;/h2>
&lt;p>To step up Litmus for your acceptance tests, you need to:&lt;/p>
&lt;ul>
&lt;li>Install a Puppet agent — you can do this using a Bolt &lt;a href="https://github.com/puppetlabs/puppetlabs-puppet_agent/tree/main/tasks">task&lt;/a>.&lt;/li>
&lt;li>Install a module — use a rake task that uses Puppet Development Kit (PDK) to build the module for testing, and install it on the target VM.&lt;/li>
&lt;li>Install &lt;code>spec/spec_helper_acceptance_local.rb&lt;/code> — this may require extra setup to test a module. You can use &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/blob/main/spec/spec_helper_acceptance_local.rb">puppetlabs/puppetlabs-apache&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>To set up integration testing, use a Bolt plan and inventory variable to add labels. You can then run Puppet code against a specific system. You can use &lt;a href="https://github.com/puppetlabs/puppetlabs-websphere_application_server/blob/main/plans/pe_server_setup.pp">puppetlabs-websphere_application_server&lt;/a>&lt;/p>
&lt;p>An example provision plan looks like:&lt;/p>
&lt;pre>&lt;code>plan websphere_application_server::provision_machines(
Optional[String] $using = 'abs',
Optional[String] $image = 'centos-7-x86_64'
) {
# provision machines, set roles
['server', 'appserver', 'dmgr', 'ihs'].each |$role| {
run_task(&amp;quot;provision::${using}&amp;quot;, 'localhost', action =&amp;gt; 'provision', platform =&amp;gt; $image, vars =&amp;gt; &amp;quot;role: ${role}&amp;quot;)
}
}
&lt;/code>&lt;/pre>&lt;p>You can use &lt;code>spec/spec_helper_acceptance_local.rb&lt;/code> if you need to test a module — &lt;a href="https://github.com/puppetlabs/puppetlabs-websphere_application_server/blob/main/spec/spec_helper_acceptance_local.rb">puppetlabs-websphere_application_server&lt;/a>&lt;/p>
&lt;h2 id="run-a-test">Run a test&lt;/h2>
&lt;p>To identify which tests to run in an integeration environment, you can use rspec labelling and rake tasks.&lt;/p>
&lt;p>You can label tests using rspec labeling — tag the test as an integration and keep everything else can stay the same. For example:&lt;/p>
&lt;pre>&lt;code>describe 'Install the websphere dmgr', :integration do
before(:all) do
@agent = WebSphereHelper.dmgr_host
WebSphereInstance.install(@agent)
WebSphereDmgr.install(@agent)
end
it 'is installed' do
expect(WebSphereHelper.remote_file_exists(@agent, WebSphereConstants.dmgr_status))
expect(WebSphereHelper.remote_file_exists(@agent, WebSphereConstants.ws_admin))
end
end
&lt;/code>&lt;/pre>&lt;p>To run a rake task, add to the Rakefile of the module. For example:&lt;/p>
&lt;pre>&lt;code>require 'rspec/core/rake_task'
namespace :websphere_application_server do
RSpec::Core::RakeTask.new(:integration) do |t|
t.pattern = 'spec/acceptance/**{,/*/**}/*_spec.rb'
t.rspec_opts = &amp;quot;--tag integration&amp;quot;
end
end
&lt;/code>&lt;/pre>&lt;p>To target a test at a specific VM or container, you can use helper methods. You need to do this if you are using serverspec or Litmus.&lt;/p>
&lt;p>The examples below show how to filter to get either a single VM or container, or how to retrieve multiple targets.
&lt;a href="https://github.com/puppetlabs/puppetlabs-websphere_application_server/blob/main/spec/spec_helper_acceptance_local.rb">puppetlabs-websphere_application_server&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://github.com/puppetlabs/puppetlabs-kubernetes/blob/main/spec/spec_helper_acceptance_local.rb">puppetlabs-kubernetes&lt;/a>&lt;/p>
&lt;p>To identify a target node, the code would look like:&lt;/p>
&lt;pre>&lt;code> context 'application deployment' do
before(:all) { change_target_host('controller') }
after(:all) { reset_target_host }
it 'can deploy an application into a namespace and expose it' do
run_shell('KUBECONFIG=/etc/kubernetes/admin.conf kubectl create -f /tmp/nginx.yml') do |r|
expect(r.stdout).to match(/my-nginx created\nservice\/my-nginx created\n/)
end
end
&lt;/code>&lt;/pre>&lt;p>To only run on tests labelled as ‘integration’, use the following command:&lt;/p>
&lt;p>&lt;code>bundle exec rake websphere_application_server:integration&lt;/code>&lt;/p>
&lt;h2 id="teardown-the-machine">Teardown the machine&lt;/h2>
&lt;p>To teardown all the provisioned machines, use the following provision task:&lt;/p>
&lt;p>&lt;code>bundle exec rake litmus:tear_down&lt;/code>&lt;/p>
&lt;h3 id="multi-node-testing-examples">Multi-node testing examples&lt;/h3>
&lt;p>&lt;em>&lt;strong>Multiple Puppet agents&lt;/strong>&lt;/em>&lt;/p>
&lt;p>A setup where you have multiple Puppet agents, with a module installed and tests run.&lt;/p>
&lt;p>Commands&lt;/p>
&lt;pre>&lt;code>bundle install --path .bundle/gems/ --jobs 4
bundle exec rake spec_prep
bundle exec bolt --modulepath spec/fixtures/modules plan run ntp::provision_gcp
bundle exec rake litmus:install_agent
bundle exec rake litmus:install_module
bundle exec rake ntp:integration
bundle exec rake 'litmus:tear_down'
&lt;/code>&lt;/pre>&lt;p>Example
&lt;a href="https://github.com/puppetlabs/puppetlabs-ntp/tree/multinodentp">puppetlabs-ntp&lt;/a>&lt;/p>
&lt;p>&lt;em>&lt;strong>Puppet server and multiple agents&lt;/strong>&lt;/em>&lt;/p>
&lt;p>A setup where you have Puppet Server and multiple Puppet agents.&lt;/p>
&lt;p>You can use Bolt plans for provisioning multiple nodes, with roles tagged to each of it.&lt;/p>
&lt;p>Puppet has a new &lt;a href="https://github.com/puppetlabs/provision/blob/main/tasks/install_puppetserver.json">task&lt;/a> that installs an open source Puppet server in the provision module.&lt;/p>
&lt;p>Commands&lt;/p>
&lt;pre>&lt;code>bundle install --path .bundle/gems/ --jobs 4
bundle exec rake spec_prep
bundle exec bolt --modulepath spec/fixtures/modules plan run kubernetes::provision_cluster
bundle exec bolt --modulepath spec/fixtures/modules -i ./spec/fixtures/litmus_inventory.yaml plan run kubernetes::puppetserver_setup
bundle exec rake litmus:install_agent
bundle exec rake litmus:install_module
bundle exec rake kubernetes:integration
bundle exec rake 'litmus:tear_down'
&lt;/code>&lt;/pre>&lt;p>Example
&lt;a href="https://github.com/puppetlabs/puppetlabs-kubernetes">puppetlabs-kubernetes&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-05-07-running-multinode-modules-gcp/github_workflow.png" alt="Example github workflow run">&lt;/p>
&lt;p>&lt;em>&lt;strong>PE and agents&lt;/strong>&lt;/em>&lt;/p>
&lt;p>A setup where you have a PE server and multiple Puppet agents.&lt;/p>
&lt;p>You can use Bolt plans for provisioning multiple nodes with roles tagged to each of it.&lt;/p>
&lt;p>There is a task to install PE in the &lt;code>puppet-deploy_pe module&lt;/code>.
&lt;a href="https://github.com/jarretlavallee/puppet-deploy_pe/tree/master/plans">provision_master/agents&lt;/a>&lt;/p>
&lt;p>Commands&lt;/p>
&lt;pre>&lt;code>bundle install --path .bundle/gems/ --jobs 4
bundle exec rake spec_prep
bundle exec bolt --modulepath spec/fixtures/modules plan run ntp::provision_gcp
bundle exec bolt --modulepath spec/fixtures/modules -i ./spec/fixtures/litmus_inventory.yaml plan run ntp::pe_server
bundle exec bolt --modulepath spec/fixtures/modules -i ./spec/fixtures/litmus_inventory.yaml plan run ntp::pe_agent
bundle exec rake litmus:install_module
bundle exec rake ntp:integration
bundle exec rake 'litmus:tear_down'
&lt;/code>&lt;/pre>&lt;p>Example
&lt;a href="https://github.com/puppetlabs/puppetlabs-ntp/tree/multinodentp">puppetlabs-ntp&lt;/a>&lt;/p>
&lt;p>An example plan that installs a PE server:&lt;/p>
&lt;pre>&lt;code>plan ntp::pe_server(
Optional[String] $version = '2019.8.5',
Optional[Hash] $pe_settings = {password =&amp;gt; 'puppetlabs'}
) {
# identify pe server node
$puppet_server = get_targets('*').filter |$n| { $n.vars['role'] == 'ntpserver' }
# install pe server
run_plan(
'deploy_pe::provision_master',
$puppet_server,
'version' =&amp;gt; $version,
'pe_settings' =&amp;gt; $pe_settings
)
}
&lt;/code>&lt;/pre>&lt;p>An example plan that installs a Puppet agent:&lt;/p>
&lt;pre>&lt;code>plan ntp::pe_agent() {
# identify pe server and agent nodes
$puppet_server = get_targets('*').filter |$n| { $n.vars['role'] == 'ntpserver' }
$puppet_agent = get_targets('*').filter |$n| { $n.vars['role'] == 'ntpclient' }
# install agent
run_plan(
'deploy_pe::provision_agent',
$puppet_agent,
'master' =&amp;gt; $puppet_server,
)
}
&lt;/code>&lt;/pre>&lt;p>For more GitHub Action workflow examples, see the following:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/puppetlabs/puppetlabs-websphere_application_server/tree/main/.github/workflows">puppetlabs-websphere_application_server&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/puppetlabs/puppetlabs-kubernetes/tree/main/.github/workflows">puppetlabs-kubernetes&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Thanks &lt;a href="https://github.com/tphoney">TP&lt;/a> for the valuable work on integration testing.
Thanks &lt;a href="https://github.com/MartyEwings">Marty&lt;/a> for the work on installing PE on cloud CI.&lt;/p></description></item><item><title>Blog: Converting to use Puppetized DSC Modules</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-26-converting-puppetized-dsc-modules/</link><pubDate>Tue, 26 Jan 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-26-converting-puppetized-dsc-modules/</guid><description>
&lt;h2 id="whats-new-with-dsc-and-puppet">What&amp;rsquo;s new with DSC and Puppet?&lt;/h2>
&lt;p>To check out our reasons on why we think converting your module is a good idea, check out these blog posts written by &lt;a href="https://github.com/michaeltlombardi">Michael&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://puppetlabs.github.io/iac/news/roadmap/2020/03/30/dsc-announcement.html">DSC accouncement post&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://puppetlabs.github.io/iac/news/roadmap/2020/09/21/dsc-release.html">DSC release post&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>The blog posts cover information including:&lt;/p>
&lt;ul>
&lt;li>Why we are doing this&lt;/li>
&lt;li>Details about the builder&lt;/li>
&lt;li>How to Pupperize your Powershell module&lt;/li>
&lt;li>How to use your Puppetized module&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Seriously though what is there to not love?&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Minimal module maintainence costs&lt;/li>
&lt;li>Automated module building&lt;/li>
&lt;li>Property by property reporting&lt;/li>
&lt;li>VSCode Extension with intellisense&lt;/li>
&lt;li>We have 68 modules on the Forge in the &lt;a href="https://forge.puppet.com/dsc">DSC namespace&lt;/a>&lt;/li>
&lt;li>Converting is relatively straight forward&lt;/li>
&lt;/ul>
&lt;h2 id="so-how-can-i-do-this">So how can I do this?&lt;/h2>
&lt;p>&lt;em>Old method:&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">mod&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;puppetlabs-dsc&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;1.9.4&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;em>New method:&lt;/em>&lt;/p>
&lt;p>Add entries for &lt;code>puppetlabs-pwshlib&lt;/code> and the &lt;code>dsc-*&lt;/code> modules whose resources you want to use to your puppetfile.
The entries on the list below are the &lt;em>closest&lt;/em> match for the resources found in the old &lt;code>puppetlabs-dsc&lt;/code> module; while we specified versions here, remember: there have been releases to the DSC modules since the &lt;code>puppetlabs-dsc&lt;/code> last had its resources updated, so there are newer versions you may want to take advantage of (just be sure to test thoroughly when upgrading)!&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note:&lt;/strong> You want to &lt;em>very specifically&lt;/em> only add the necessary &lt;code>dsc-*&lt;/code> module pins to your puppetfile; if you&amp;rsquo;re not using any of the resources contained in a module, there&amp;rsquo;s no need to specify it and take on the overhead of shipping the code around.&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;code>mod 'puppetlabs-pwshlib', '0.7.1'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-activedirectorycsdsc', '3.1.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-auditpolicydsc', '1.4.0-0-1'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-certificatedsc', '4.4.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-computermanagementdsc', '6.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-dfsdsc', '4.3.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-networkingdsc', '7.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-officeonlineserverdsc', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-securitypolicydsc', '2.7.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-sharepointdsc', '3.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-sqlserverdsc', '12.3.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-storagedsc', '4.5.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-systemlocaledsc', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xactivedirectory', '2.24.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xazure', '0.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xazurepack', '1.4.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xbitlocker', '1.4.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xcredssp', '1.3.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdatabase', '1.9.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdefender', '0.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdhcpserver', '2.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdisk', '1.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdismfeature', '1.3.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xdnsserver', '1.11.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xexchange', '1.27.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xfailovercluster', '1.12.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'ddsc-xhyper_v', '3.16.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xinternetexplorerhomepage', '1.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xjea', '0.2.16-6-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xmysql', '2.1.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xpendingreboot', '0.4.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xphp', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xpowershellexecutionpolicy', '3.1.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xpsdesiredstateconfiguration', '8.5.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xremotedesktopadmin', '1.1.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xremotedesktopsessionhost', '1.8.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xrobocopy', '2.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscdpm', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscom', '1.3.3-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscsma', '2.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscspf', '1.3.1-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscsr', '1.3.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xscvmm', '1.2.4-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xsmbshare', '2.1.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xsqlps', '1.4.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xtimezone', '1.8.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwebadministration', '2.5.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwebdeploy', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwindowseventforwarding', '1.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwindowsrestore', '1.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwindowsupdate', '2.7.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwineventlog', '1.2.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-xwordpress', '1.1.0-0-0'&lt;/code>&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Note that the versions for the &lt;code>dsc-*&lt;/code> modules are all 5-digits long.
The first four digits are a match for the puppetized PowerShell module&amp;rsquo;s own version - so &lt;code>1.4.0-0-0&lt;/code> represents a PowerShell module at version &lt;code>1.4.0.0&lt;/code> on the PowerShell Gallery.
The fifth digit is the &lt;em>Puppetized Build Increment&lt;/em> for that version; that goes up whenever we rebuild the module to fix a bug or add a feature to the Puppet interface to the DSC Resource.
In general, you&amp;rsquo;ll &lt;em>almost always&lt;/em> want the latest build of a module.
So even though we specify Puppet Build Increments of &lt;code>0&lt;/code> in the list above, make sure to choose the latest build for the PowerShell module version you want to use.&lt;/p>
&lt;/blockquote>
&lt;h2 id="a-few-caveats">A few caveats&lt;/h2>
&lt;p>The following modules cannot be automatically puppetized at the same version because they referenced commit SHAs instead of versions discoverable on the &lt;a href="https://www.powershellgallery.com">gallery;&lt;/a>
instead, we recommend using the next released stable version after those SHA&amp;rsquo;s, as listed below:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Note:&lt;/strong> These are close but not precise replacements:&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;code>mod 'dsc-fsrmdsc', '2.5.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-iscsidsc', '2.0.0-0-0'&lt;/code>&lt;/li>
&lt;li>&lt;code>mod 'dsc-wsmandsc', '2.4.0-0-0'&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Here are links to the specific commit SHAs that have been referenced:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/dsccommunity/FSRMDsc/commit/8945f610fa9a6f7f920260abf4e50d91db25bac0">FSRMDsc&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/dsccommunity/iSCSIDsc/commit/2208ad24a0cc0a85ce19fb377e72fbc21d366587">iSCSIDsc&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/dsccommunity/wsmandsc/commit/1aa6400e7ffa1932505bf9904a7ce9e147af9c45">WSManDsc&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Note:&lt;/strong> puppetized as &lt;code>dsc/wminamespacesecurity&lt;/code> due to the name of the module changing when pushed to the &lt;a href="https://www.powershellgallery.com">PowerShell Gallery&lt;/a> vs the old code repository.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;code>mod 'dsc-wminamespacesecuritydsc', '0.3.0-0-0'&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>Again here is a link to the specific commit SHA that has been referenced:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/PowerShell/WmiNamespaceSecurityDsc/commit/d49daa4c18f12aabf32fd60631d927c6d276a453">WmiNamespaceSecurityDsc&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="guidance-on-troubleshooting">Guidance on troubleshooting&lt;/h2>
&lt;p>Coincidentally, &lt;a href="https://github.com/michaeltlombardi">Michael&lt;/a> has just published a blog post on how to troubleshoot for DSC.&lt;/p>
&lt;p>Check it out on our &lt;a href="https://puppetlabs.github.io/iac/">blog page&lt;/a>!&lt;/p>
&lt;h2 id="some-things-come-for-free">Some things come for free!&lt;/h2>
&lt;p>We suggest using the Puppet VSCode extension as it comes built in with an auto-completer. This will help you keep your pins up to date with the puppetfile resolver.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-26-converting-dsc-modules/puppetfile-resolver.gif" alt="Showing validation errors in your Puppetfile">&lt;/p>
&lt;h2 id="what-else-is-coming">What else is coming&lt;/h2>
&lt;p>As part of our next phase we plan to flesh out and update our testing infrastructure for this module on our road to the &lt;code>1.0.0&lt;/code> release of &lt;code>Puppet.Dsc&lt;/code>.
In the pipeline, we still plan on getting nightly builds into place to ensure that there is never more than a 24 hour lag between published Powershell modules with DSC Resources and our Puppetized modules on the Forge.&lt;/p>
&lt;p>As always if you have any questions don&amp;rsquo;t hesistate to reach out to us via &lt;a href="https://slack.puppet.com/">Slack&lt;/a> or &lt;a href="mailto:dsc@puppet.com">emailing&lt;/a> and we will be as accomodating as we can be!&lt;/p></description></item><item><title>Blog: Troubleshooting Puppetized DSC Modules</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-25-troubleshooting-puppetized-dsc-modules/</link><pubDate>Mon, 25 Jan 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-25-troubleshooting-puppetized-dsc-modules/</guid><description>
&lt;p>&lt;em>[An edited version of this post was also published on the &lt;a href="https://ospassist.puppet.com/">OSPAssist Portal&lt;/a> as &lt;a href="https://ospassist.puppet.com/hc/en-us/articles/1500002388661-Troubleshooting-Puppetized-DSC-modules">Troubleshooting Puppetized DSC modules&lt;/a> and &lt;a href="https://ospassist.puppet.com/hc/en-us/articles/360061073994-Advanced-troubleshooting-dig-deeper-with-pry">Advanced troubleshooting: dig deeper with pry&lt;/a>]&lt;/em>&lt;/p>
&lt;p>Authoring Puppet manifests using the new &lt;a href="https://forge.puppet.com/dsc">Puppetized DSC Resources&lt;/a> is, like using any other Puppet modules, a few steps and a deploy away for most use cases.
Sometimes you will run into a problem trying to apply a manifest containing one or more puppetized DSC resources.
What could be causing the problem?&lt;/p>
&lt;p>Is it a problem with the builder?
The Puppet representation of the DSC Resource could not match the API surface, resulting in misgenerated types, enums or method calls.&lt;/p>
&lt;p>Could the problem be the DSC Resource itself?
The PowerShell DSC code could not work, which would be hidden underneath the Puppet Ruby exception stacktrace.&lt;/p>
&lt;p>What happens if it&amp;rsquo;s Puppet?
There could be an error in the Ruby code that translates the DSC resource back and forth between Puppet and PowerShell, in which case the issue lies in the &lt;a href="https://forge.puppet.com/modules/puppetlabs/pwshlib">&lt;code>pwshlib&lt;/code>&lt;/a> module.&lt;/p>
&lt;p>Somewhere in between?
How do you tell which symptom is which problem?
Where do you begin to troubleshoot this?
This blog post will help you find your way foreward.&lt;/p>
&lt;h2 id="basic-troubleshooting">Basic Troubleshooting&lt;/h2>
&lt;p>The first thing to note is that there&amp;rsquo;s actually a &lt;a href="https://github.com/puppetlabs/Puppet.Dsc#troubleshooting">basic troubleshooting guide for &lt;code>Puppet.Dsc&lt;/code>&lt;/a>.
That guide covers finding problems like &lt;a href="https://github.com/puppetlabs/Puppet.Dsc#type-errors">type errors&lt;/a> or &lt;a href="https://github.com/puppetlabs/Puppet.Dsc#incorrect-enum">incorrect enums&lt;/a> in the module builder, &lt;a href="https://github.com/puppetlabs/Puppet.Dsc#error-during-invocation">invocation errors&lt;/a> during a Puppet run, and problems with the tanslation layer in &lt;code>pwshlib&lt;/code>. There is a lot of good information there, so we won&amp;rsquo;t cover those areas again here.&lt;/p>
&lt;p>The guide also covers running Puppet in &lt;strong>debug&lt;/strong> mode, which you will need to know about for the next couple sections.
In short, if you append the &lt;code>--debug&lt;/code> flag to the end of your Puppet invocation, you&amp;rsquo;ll get a &lt;em>ton&lt;/em> of additional information out of the run.
Please make sure to read the guide to ensure you have a reference point before we proceed here.&lt;/p>
&lt;h2 id="advanced-troubleshooting">Advanced Troubleshooting&lt;/h2>
&lt;p>So, you have a Puppet manifest with one or more Puppetized DSC Resource declarations in it.
Things are not working and the basic troubleshooting guide didn&amp;rsquo;t solve the problem.&lt;/p>
&lt;p>The first place to start is to validate that what you declared in the manifest was translated correctly to the PowerShell DSC code to execute.&lt;/p>
&lt;h3 id="validating-manifests-and-the-powershell-hash">Validating manifests and the PowerShell hash&lt;/h3>
&lt;p>When you specify a DSC Resource in your Puppet manifest, behind the scenes Puppet converts that into PowerShell code to pass to &lt;code>Invoke-DscResource&lt;/code>.
In debug mode, you can actually see what Puppet thinks you passed &lt;em>and&lt;/em> that generated code.&lt;/p>
&lt;p>Lets walk through an example manifest:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">dsc_psrepository&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;PowerShell Gallery&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;psGallery&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_installationpolicy&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Trusted&amp;#39;&lt;/span>,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we execute Puppet in debug mode, we&amp;rsquo;ll get the following (abbreviated) output:&lt;/p>
&lt;pre>&lt;code>Debug: dsc_psrepository[{:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;}]: Updating: Invoking Set Method for '{:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;}' with {:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;, :dsc_installationpolicy=&amp;gt;&amp;quot;Trusted&amp;quot;}
... (snipped for brevity)
dsc_psrepository[{:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;}]: Updating: Script:
... (snipped for brevity)
$InvokeParams = @{Name = 'PSRepository'; Method = 'set'; Property = @{name = 'psGallery'; installationpolicy = 'Trusted'}; ModuleName = @{ModuleName = 'C:/pathToPuppetModules/powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet/PowerShellGet.psd1'; RequiredVersion = '2.2.4.1'}} Try {
$Result = Invoke-DscResource @InvokeParams
} catch {
$Response.errormessage = $_.Exception.Message
return ($Response | ConvertTo-Json -Compress)
}
&lt;/code>&lt;/pre>&lt;p>Breaking this apart, there are several sections of information to pull out.&lt;/p>
&lt;p>The first line is Puppet telling us why it&amp;rsquo;s doing what it&amp;rsquo;s doing and with what information it has to execute.
We see its the PowerShell Gallery module, using the Gallery DSC Resource and setting the &lt;code>installationpolicy&lt;/code> to &lt;code>Trusted&lt;/code>.&lt;/p>
&lt;pre>&lt;code>Debug: dsc_psrepository[{:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;}]: Updating: Invoking Set Method for '{:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;}' with {:name=&amp;gt;&amp;quot;PowerShell Gallery&amp;quot;, :dsc_name=&amp;gt;&amp;quot;psGallery&amp;quot;, :dsc_installationpolicy=&amp;gt;&amp;quot;Trusted&amp;quot;}
&lt;/code>&lt;/pre>&lt;p>This can be more easily read as as Ruby hash:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">{
&lt;span style="color:#f1fa8c">:name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;PowerShell Gallery&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">:dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;psGallery&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">:dsc_installationpolicy&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;Trusted&amp;#34;&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The next part in the log to look at is the invocation parameters.
This is the PowerShell code generated from the section we just examined:&lt;/p>
&lt;pre>&lt;code>$InvokeParams = @{Name = 'PSRepository'; Method = 'set'; Property = @{name = 'psGallery'; installationpolicy = 'Trusted'}; ModuleName = @{ModuleName = 'C:/pathToPuppetModules/powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet/PowerShellGet.psd1'; RequiredVersion = '2.2.4.1'}}
&lt;/code>&lt;/pre>&lt;p>Translating that to a PowerShell hash, we can see a similar represation of the Ruby hash we just looked at.
This is the exact code that will be passed to &lt;code>Invoke-DscResource&lt;/code> (expanded from one line for clarity; note your &lt;code>ModuleName&lt;/code> path will be system-specific):&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">$InvokeParams&lt;/span> = @{
Name = &lt;span style="color:#f1fa8c">&amp;#39;PSRepository&amp;#39;&lt;/span>;
Method = &lt;span style="color:#f1fa8c">&amp;#39;get&amp;#39;&lt;/span>;
Property = @{ name = &lt;span style="color:#f1fa8c">&amp;#39;psGallery&amp;#39;&lt;/span> };
ModuleName = @{
ModuleName = &lt;span style="color:#f1fa8c">&amp;#39;C:/pathToPuppetModules/powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet/PowerShellGet.psd1&amp;#39;&lt;/span>;
RequiredVersion = &lt;span style="color:#f1fa8c">&amp;#39;2.2.4.1&amp;#39;&lt;/span>
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>In summary, the debug logs from a Puppet execution run provide us detailed information about how your Puppet manifest was translated into PowerShell code to invoke the DSC Resource.&lt;/p>
&lt;p>This leads us neatly into trying to use this information to invoke the DSC Resource outside of Puppet to debug it.&lt;/p>
&lt;h3 id="invoking-without-puppet">Invoking without Puppet&lt;/h3>
&lt;p>After inspecting the debug Puppet logs, we now have the PowerShell code Puppet was executing to try out. We can take that code and move to a test machine and walk through the execution ourselves interactively.&lt;/p>
&lt;p>In a PowerShell console with administrator permissions, you&amp;rsquo;ll copy and paste the &lt;code>$InvokeParams&lt;/code> line from the debug log we pulled out above. Then you&amp;rsquo;ll invoke it using &lt;code>Invoke-DscRsource&lt;/code>. For example:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">PS &lt;/span>C:\&amp;gt; &lt;span style="color:#8be9fd;font-style:italic">$InvokeParams&lt;/span> = @{
&amp;gt;&amp;gt; Name = &lt;span style="color:#f1fa8c">&amp;#39;PSRepository&amp;#39;&lt;/span>;
&amp;gt;&amp;gt; Method = &lt;span style="color:#f1fa8c">&amp;#39;get&amp;#39;&lt;/span>;
&amp;gt;&amp;gt; Property = @{ name = &lt;span style="color:#f1fa8c">&amp;#39;psGallery&amp;#39;&lt;/span> };
&amp;gt;&amp;gt; ModuleName = @{
&amp;gt;&amp;gt; ModuleName = &lt;span style="color:#f1fa8c">&amp;#39;C:/pathToPuppetModules/powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet/PowerShellGet.psd1&amp;#39;&lt;/span>;
&amp;gt;&amp;gt; RequiredVersion = &lt;span style="color:#f1fa8c">&amp;#39;2.2.4.1&amp;#39;&lt;/span>
&amp;gt;&amp;gt; }
&amp;gt;&amp;gt; }
&lt;span style="color:#8be9fd;font-style:italic">PS &lt;/span>C:\&amp;gt; &lt;span style="color:#8be9fd;font-style:italic">Invoke-DscResource&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">@InvokeParams&lt;/span> -Verbose
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now you can evaluate the success/failure of the invocation without involving Puppet at all;
this way you can determine if the values being passed were incorrect or if the DSC Resource itself is misbehaving.&lt;/p>
&lt;p>If the code fails after pasting in the &lt;code>$InvokeParams&lt;/code> block, then there is something wrong with the values or the hash statement.
If something &lt;em>has&lt;/em> gone wrong converting the values in your Puppet manifest to the &lt;code>InvokeParams&lt;/code> hash being passed to &lt;code>Invoke-DscResource&lt;/code>, please do &lt;a href="https://github.com/puppetlabs/Puppet.Dsc/issues/new?assignees=&amp;amp;labels=Bug%2C+bug&amp;amp;template=bug-report.md&amp;amp;title=">file an issue&lt;/a> with us and we&amp;rsquo;ll be sure to take a look.&lt;/p>
&lt;p>If the code fails after invoking &lt;code>Invoke-DscResource&lt;/code>, then there is likely a problem inside the DSC Resource itself.
If it&amp;rsquo;s an issue with the DSC Resource, hopefully you&amp;rsquo;ll have enough information from the execution to put together a bug report for the upstream PowerShell module and work with that DSC resource&amp;rsquo;s authors for a resolution.&lt;/p>
&lt;h4 id="invoking-dsc-resources-with-pscredentials">Invoking DSC Resources with PSCredentials&lt;/h4>
&lt;p>When your manifest specifies a PSCredential, you&amp;rsquo;ll see one or more lines above the &lt;code>InvokeParams&lt;/code> declaration, like this (expanded for readability):&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">$febabd4f_19e8_4ed6_a218_188e275ecc05&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">New-PSCredential&lt;/span> -User apple -Password &lt;span style="color:#f1fa8c">&amp;#39;#&amp;lt;Sensitive [value redacted]&amp;gt;&amp;#39;&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">$InvokeParams&lt;/span> = @{
Name = &lt;span style="color:#f1fa8c">&amp;#39;PSRepository&amp;#39;&lt;/span>;
Method = &lt;span style="color:#f1fa8c">&amp;#39;set&amp;#39;&lt;/span>;
Property = @{
name = &lt;span style="color:#f1fa8c">&amp;#39;psGallery&amp;#39;&lt;/span>;
installationpolicy = &lt;span style="color:#f1fa8c">&amp;#39;Trusted&amp;#39;&lt;/span>;
psdscrunascredential = &lt;span style="color:#8be9fd;font-style:italic">$febabd4f_19e8_4ed6_a218_188e275ecc05&lt;/span>
};
ModuleName = @{
ModuleName = &lt;span style="color:#f1fa8c">&amp;#39;C:/pathToPuppetModules/powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet/PowerShellGet.psd1&amp;#39;&lt;/span>;
RequiredVersion = &lt;span style="color:#f1fa8c">&amp;#39;2.2.5&amp;#39;&lt;/span>
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that it is building a credential object from plain text before passing that object to DSC;
the debug logs will strip the password from being returned.&lt;/p>
&lt;p>In this case, you will need some of the custom helper code that we snipped for brevity earlier, namely this function:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#ff79c6">function&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">new-pscredential&lt;/span> {
[&lt;span style="color:#ff79c6">CmdletBinding&lt;/span>()]
&lt;span style="color:#ff79c6">param&lt;/span> (
[&lt;span style="color:#ff79c6">parameter&lt;/span>(&lt;span style="color:#ff79c6">Mandatory&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">$true&lt;/span>,
&lt;span style="color:#ff79c6">ValueFromPipelineByPropertyName&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">$true&lt;/span>)]
[string]
&lt;span style="color:#8be9fd;font-style:italic">$user&lt;/span>,
[&lt;span style="color:#ff79c6">parameter&lt;/span>(&lt;span style="color:#ff79c6">Mandatory&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">$true&lt;/span>,
&lt;span style="color:#ff79c6">ValueFromPipelineByPropertyName&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">$true&lt;/span>)]
[string]
&lt;span style="color:#8be9fd;font-style:italic">$password&lt;/span>
)
&lt;span style="color:#8be9fd;font-style:italic">$secpasswd&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">ConvertTo-SecureString&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$password&lt;/span> -AsPlainText -Force
&lt;span style="color:#8be9fd;font-style:italic">$credentials&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">New-Object&lt;/span> System.Management.Automation.PSCredential (&lt;span style="color:#8be9fd;font-style:italic">$user&lt;/span>, &lt;span style="color:#8be9fd;font-style:italic">$secpasswd&lt;/span>)
&lt;span style="color:#ff79c6">return&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$credentials&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Make sure to copy that code into your terminal &lt;em>before&lt;/em> you try to copy in the invocation variables and &lt;em>also&lt;/em> remember to replace &lt;code>#&amp;lt;Sensitive [value redacted]&amp;gt;&lt;/code> with the appropriate password string.
Alternatively, you could use &lt;code>Get-Credential&lt;/code> and capture the output of that command to the same variable name from your debug log.&lt;/p>
&lt;h4 id="invoking-dsc-resources-with-cim-instances">Invoking DSC Resources with CIM Instances&lt;/h4>
&lt;p>Some DSC Resources use nested CIM instances to pass hashes as property values.
In these cases, there&amp;rsquo;s one or more lines above the definition of the &lt;code>InvokeParams&lt;/code> variable which creates these CIM instances.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">$b615d113_bb6e_49e4_9776_7e895dfe20c7&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">New-CimInstance&lt;/span> -ClientOnly -ClassName &lt;span style="color:#f1fa8c">&amp;#39;MSFT_KeyValuePair&amp;#39;&lt;/span> -Property @{&lt;span style="color:#f1fa8c">&amp;#39;key&amp;#39;&lt;/span> = &lt;span style="color:#f1fa8c">&amp;#39;Accept-Language&amp;#39;&lt;/span> ; &lt;span style="color:#f1fa8c">&amp;#39;value&amp;#39;&lt;/span> = &lt;span style="color:#f1fa8c">&amp;#39;en-US&amp;#39;&lt;/span>}
&lt;span style="color:#8be9fd;font-style:italic">$InvokeParams&lt;/span> = @{
Name = &lt;span style="color:#f1fa8c">&amp;#39;xRemoteFile&amp;#39;&lt;/span>;
Method = &lt;span style="color:#f1fa8c">&amp;#39;set&amp;#39;&lt;/span>;
Property = @{
destinationpath = &lt;span style="color:#f1fa8c">&amp;#39;C:\dsc-xpsdesiredstateconfiguration-9.1.0-0-1.tar.gz&amp;#39;&lt;/span>;
headers = [CimInstance[]]@(&lt;span style="color:#8be9fd;font-style:italic">$b615d113_bb6e_49e4_9776_7e895dfe20c7&lt;/span>);
uri = &lt;span style="color:#f1fa8c">&amp;#39;https://forge.puppet.com/v3/files/dsc-xpsdesiredstateconfiguration-9.1.0-0-1.tar.gz&amp;#39;&lt;/span>
};
ModuleName = @{
ModuleName = &lt;span style="color:#f1fa8c">&amp;#39;C:/pathToPuppetModules/xpsdesiredstateconfiguration/lib/puppet_x/xpsdc/dsc_resources/xPSDesiredStateConfiguration/xPSDesiredStateConfiguration.psd1&amp;#39;&lt;/span>;
RequiredVersion = &lt;span style="color:#f1fa8c">&amp;#39;9.1.0&amp;#39;&lt;/span>
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is necessary for DSC to correctly handle the objects, &lt;em>especially&lt;/em> if they have a custom CIM instance class specific to the DSC Resource being called.&lt;/p>
&lt;h2 id="digging-deeper-with-pry">Digging deeper with Pry&lt;/h2>
&lt;p>Sometimes, reading the debug logs doesn&amp;rsquo;t give you enough information about what&amp;rsquo;s going on.
You may need to &lt;em>pry&lt;/em> into the parts of Puppet that happen after the execution starts, but before the PowerShell code is executed.&lt;/p>
&lt;p>When this is the case, the most powerful thing you can do is learn to interactively debug a Puppet run using a tool called &lt;a href="https://github.com/pry/pry">pry&lt;/a>.&lt;/p>
&lt;p>&lt;a href="https://github.com/pry/pry">Pry&lt;/a> is a powerful tool for interactively debugging ruby.
Using it with Puppet on Windows is a bit involved but it can be an extremely useful tool in your kit.&lt;/p>
&lt;p>First, you&amp;rsquo;ll want to get a functional ruby environment installed &lt;em>separate&lt;/em> from the PDK.&lt;/p>
&lt;blockquote>
&lt;p>Right now, the PDK does not support prying into a Puppet run due to limitations around native gems.
If you don&amp;rsquo;t know what this means right now, don&amp;rsquo;t worry too much.
As you get more used to how Ruby and Puppet works it will make more sense.&lt;/p>
&lt;/blockquote>
&lt;p>You can accomplish this however you want, but make sure there is an installation of both Ruby and the associated Devkit installed when you are done.
We suggest you do this via &lt;a href="https://www.powershellgallery.com/packages/RubyInstaller">Glenn Sarti&amp;rsquo;s &lt;code>RubyInstaller&lt;/code>&lt;/a> PowerShell module:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Install-Module&lt;/span> RubyInstaller -Scope CurrentUser
&lt;span style="color:#6272a4"># This will kick off an interactive installation of Ruby, including the necessary dependencies&lt;/span>
&lt;span style="color:#6272a4"># It relies on Chocolatey (and will install it if needed)&lt;/span>
&lt;span style="color:#6272a4"># Strongly suggest installation option G (&amp;#39;2.5.1-2 (x64)&amp;#39;) at the time of this writing.&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">Install-Ruby&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The next step is to find the module files on disk.
They&amp;rsquo;re &lt;em>probably&lt;/em> in a location like this one:&lt;/p>
&lt;pre>&lt;code>C:/ProgramData/PuppetLabs/code/environments/&amp;lt;your environment name&amp;gt;/modules/
&lt;/code>&lt;/pre>&lt;p>The actual location will depend on how you configured your Puppet Environments.&lt;/p>
&lt;p>Next, you&amp;rsquo;re going to &lt;code>Set-Location&lt;/code> to the module you want to debug, like so:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Set-Location&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;C:/ProgramData/PuppetLabs/code/environments/production/modules/powershellget&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>We strongly suggest opening this location in VSCode to make editing a bit easier on yourself.&lt;/p>
&lt;/blockquote>
&lt;p>In any case, you will want to &lt;em>delete&lt;/em> the file &lt;code>Gemfile.lock&lt;/code> in this directory and create a new file, &lt;code>Gemfile.local&lt;/code>, with the following content:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">gem &lt;span style="color:#f1fa8c">&amp;#39;fuubar&amp;#39;&lt;/span>
gem &lt;span style="color:#f1fa8c">&amp;#39;pry-byebug&amp;#39;&lt;/span>
gem &lt;span style="color:#f1fa8c">&amp;#39;pry-stack_explorer&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next, you will run the following commands:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># This loads ruby 2.5 for use; if you don&amp;#39;t do this, you won&amp;#39;t be able to run other commands&lt;/span>
uru 2.5
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># This is only necessary after you first install a ruby version; it&amp;#39;s a tool to manage ruby dependencies&lt;/span>
gem install bundler
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># This will cause bundler install all of the ruby dependencies into the folder you&amp;#39;re currently in&lt;/span>
bundle config &lt;span style="color:#8be9fd;font-style:italic">set &lt;/span>path &lt;span style="color:#f1fa8c">&amp;#39;.bundle/gems&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># This will install all of your ruby dependencies&lt;/span>
bundle install
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># This will pull down a copy of the `pwslib` module for use and editing in the rest of your debugging&lt;/span>
bundle exec rake spec_prep
&lt;/code>&lt;/pre>&lt;/div>&lt;p>At this point, you have a functioning Ruby installation and a Puppet Module setup and ready to be debugged.&lt;/p>
&lt;p>The next step is to create a new file in the module folder at &lt;code>examples/test.pp&lt;/code> and put your test manifest code in there.&lt;/p>
&lt;p>Now, you can run your test manifest with the following command:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">bundle exec puppet apply ./examples/test.pp --modulepath ./spec/fixtures/modules
&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you want to run in debug mode, append &lt;code>--debug&lt;/code> to the end of that command.
The output you saw during a normal Puppet run will show, and the command runs until it stops at the error you are currently investigating.&lt;/p>
&lt;p>Now, you&amp;rsquo;re ready to start adding &lt;em>pry&lt;/em> statements to the base provider and digging around.&lt;/p>
&lt;h3 id="prying-into-the-base-provider">Prying into the base provider&lt;/h3>
&lt;p>For the rest of this section we&amp;rsquo;ll be looking at the &lt;code>dsc_base_provider.rb&lt;/code> file in the &lt;a href="https://forge.puppet.com/modules/puppetlabs/pwshlib">&lt;code>puppetlabs-pwshlib&lt;/code>&lt;/a> module, which you can find at &lt;code>./spec/fixtures/modules/pwshlib/puppet/provider/dsc_base_provider&lt;/code> in the module folder.
That file is the shared provider that &lt;em>all&lt;/em> Puppetized DSC Resources rely on.&lt;/p>
&lt;p>For this brief tutorial, we&amp;rsquo;re going to pry into &lt;code>invoke_get_method&lt;/code>, but these techniques apply to all of the included methods you may want to debug.&lt;/p>
&lt;p>First, find the method in the provider file (at the time of this writing, that&amp;rsquo;s around line 231):&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">invoke_get_method&lt;/span>(context, name_hash)
&lt;span style="color:#ff79c6">...&lt;/span>
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>We&amp;rsquo;re going to add a pry binding to this method.
For the purposes of this tutorial, we&amp;rsquo;re going to add it just before the DSC invocation (around line 241 at the time of this writing):&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">context&lt;span style="color:#ff79c6">.&lt;/span>debug(&lt;span style="color:#f1fa8c">&amp;#34;Script:&lt;/span>&lt;span style="color:#f1fa8c">\n&lt;/span>&lt;span style="color:#f1fa8c"> &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>redact_secrets(script_content)&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>)
&lt;span style="color:#6272a4"># This is the new code we&amp;#39;re adding, which will tell ruby to enter a pry debugging session:&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">require&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;pry&amp;#39;&lt;/span> ; &lt;span style="color:#8be9fd;font-style:italic">binding&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>pry
output &lt;span style="color:#ff79c6">=&lt;/span> ps_manager&lt;span style="color:#ff79c6">.&lt;/span>execute(script_content)&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:stdout&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will get you an interactive prompt inside the Puppet run:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/initial-pry.PNG" alt="Initial execution of pry">&lt;/p>
&lt;p>You can call &lt;code>ls&lt;/code> in that context to see what methods and variables are available:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/ls-pry.PNG" alt="Demonstrating the ls command in pry">&lt;/p>
&lt;p>You can type the name of one of the variables, such as &lt;code>name_hash&lt;/code> and hit enter to see what it is set to:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/name-hash-pry.PNG" alt="Printing the name_hash variable in pry">&lt;/p>
&lt;p>You can use the &lt;code>whereami&lt;/code> command to show where you are in the code.
If you pass an integer to this command, it will show you that many lines around your current line.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/whereami-pry.PNG" alt="Running the whereami command in pry">&lt;/p>
&lt;p>Next, we&amp;rsquo;ll execute the invocation script and assign it to our own variable (this will take a bit as it&amp;rsquo;s spinning up PowerShell for the first time and running &lt;code>Invoke-DscResource&lt;/code>):&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/execute-pry.PNG" alt="Executing independent code in pry">&lt;/p>
&lt;p>In my case, it looks like we got some data for &lt;code>stdout&lt;/code>, an exit code of zero, and no errors.&lt;/p>
&lt;p>If we call &lt;code>next&lt;/code>, pry will execute the next line of code.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/next-pry.PNG" alt="Calling the next command in pry">&lt;/p>
&lt;p>Note that the marker for our current line has updated to 243.
We can keep using &lt;code>next&lt;/code> to walk through the code execution, investigating any variables or running any methods for ourselves to see.
I&amp;rsquo;ll keep doing that til we hit line 267, where the code manipulates the output data a little bit:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/data-line-pry.PNG" alt="Showing the context that will modify the data variable in pry">&lt;/p>
&lt;p>Before we run these lines, lets check on some state:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/data-initial-pry.PNG" alt="Printing the initial value of the data variable in pry">&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/valid_attributes-pry.PNG" alt="Printing the value of the valid_attributes variable in pry">&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/parameters-pry.PNG" alt="Printing the value of the parameters variable in pry">&lt;/p>
&lt;p>Okay, so that shows us the current state of the data, the list of valid attributes, and the parameters respectively.
We can then run &lt;code>next&lt;/code> and check the value of &lt;code>data&lt;/code> again to see what the &lt;code>data.select!&lt;/code> line did:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/data-selected-pry.PNG" alt="Printing the value of the data variable in pry after the select! method is used on it">&lt;/p>
&lt;p>It looks like the list of key-value pairs has been trimmed down - we do this so only the values that Puppet cares about will be evaluated in the rest of the Puppet run.&lt;/p>
&lt;p>If we use &lt;code>next&lt;/code> again and look at data a final time:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/data-rejected-pry.PNG" alt="Printing the value of the data variable in pry after the reject! method is used on it">&lt;/p>
&lt;p>We see that the key for &lt;code>PSDscRunAsCredential&lt;/code> has been removed, which happens because it was the only key which was in the list of parameters.&lt;/p>
&lt;p>This brings us to a loop in the code.
If we want to see what happens &lt;em>inside&lt;/em> the loop, we need to use the &lt;code>step&lt;/code> command.
This command also lets you shift contexts inside of any method being called.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-25-troubleshooting-puppetized-dsc-modules/step-loop-pry.PNG" alt="Showing the result of stepping into a loop in Pry">&lt;/p>
&lt;p>Note that we&amp;rsquo;re now &lt;em>inside&lt;/em> the loop - if we had called &lt;code>next&lt;/code>, it would&amp;rsquo;ve evaluated the whole loop and gone to the next line after it.&lt;/p>
&lt;p>If we want to just let Puppet run it&amp;rsquo;s course, we can use the &lt;code>continue&lt;/code> command - this will keep us in the pry session, looking for the next &lt;code>pry.binding&lt;/code> in our code.
Right now we only have the one, but you can have any number of them.&lt;/p>
&lt;p>If instead we want to exit the puppet run entirely, we can use the &lt;code>exit!&lt;/code> command, which will bring you back to your PowerShell prompt.&lt;/p>
&lt;p>And that&amp;rsquo;s it for basic pry debugging!
A few commands and tools to help you look around and try stuff out to investigate where you think something has gone wrong.&lt;/p>
&lt;h4 id="places-to-look">Places to look&lt;/h4>
&lt;p>Here are a few methods you may want to investigate with a pry binding and reasons for that:&lt;/p>
&lt;ul>
&lt;li>&lt;code>canonicalize&lt;/code> - this method retrieves the state of the DSC Resource on the node, if it exists, and loads it into a cache for comparing later - if something goes wrong here, chances are you&amp;rsquo;ll get idempotency issues.&lt;/li>
&lt;li>&lt;code>invoke_get_method&lt;/code> - this is responsible not just for querying the state of the DSC Resource but also for puppetizing the returned data&lt;/li>
&lt;li>&lt;code>ps_script_content&lt;/code> - this method builds the PowerShell script that gets invoked to query or set the state of a DSC Resource.
The methods included in it, particularly &lt;code>prepare_credentials&lt;/code>, &lt;code>prepare_cim_instances&lt;/code>, and &lt;code>invoke_params&lt;/code> are where things are most likely to go wrong when turning Puppet code into PowerShell code.&lt;/li>
&lt;/ul></description></item><item><title>Blog: Reaching the IAC Team</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-20-reaching-out/</link><pubDate>Wed, 20 Jan 2021 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2021-01-20-reaching-out/</guid><description>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/hello.png" alt="hello">{:height=&amp;ldquo;170px&amp;rdquo; width=&amp;ldquo;170px&amp;rdquo;}&lt;/p>
&lt;p>To improve collaboration and avoid issues falling through the cracks, we have collected information on all the ways to get in contact with us. Whether this be to review a PR, highlight a nasty bug or really for any other reason, let us know what we did well, and what we need to do better.&lt;/p>
&lt;h2 :height="30px" width="30px" id="monday-is-community-day-slackcontent-and-tooling-teamassets2021-01-20-reaching-outcalendarpng">Monday is Community Day &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/calendar.png" alt="slack">&lt;/h2>
&lt;p>Yes, that&amp;rsquo;s right! The whole team dedicates a full day to you every week. Every Monday we go over pull requests, releases, new issues and anything else module related.&lt;/p>
&lt;h2 :height="45px" width="45px" id="reaching-out-via-slack-slackcontent-and-tooling-teamassets2021-01-20-reaching-outslackpng">Reaching out via Slack &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/slack.png" alt="slack">&lt;/h2>
&lt;p>As part of Community Monday, we have weekly office hours on Monday 1.00pm and 5.00pm GMT alternating each week. Check the &lt;a href="https://puppet.com/community/office-hours">calendar&lt;/a> for the events in your timezone. Join #office-hours on our &lt;a href="https://puppetcommunity.slack.com">community-slack&lt;/a>. Between these hours the IAC team will be online and can chat about anything module related and much more!&lt;/p>
&lt;p>Outside the office hours, some of us hang out in #forge-modules and #testing on our &lt;a href="https://puppetcommunity.slack.com">community-slack&lt;/a>. Even if nobody from the team is around, other community members might be able to help.&lt;/p>
&lt;p>&lt;strong>Use the &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/sos.gif" alt="sos">{:height=&amp;ldquo;50px&amp;rdquo; width=&amp;ldquo;50px&amp;rdquo;}
emoji on urgent issues that require the attention of a puppet employee.&lt;/strong>&lt;/p>
&lt;h2 :height="40px" width="40px" id="reaching-out-via-jirahttpsticketspuppetlabscombrowsemodules-bugcontent-and-tooling-teamassets2021-01-20-reaching-outbugpng">Reaching out via &lt;a href="https://tickets.puppetlabs.com/browse/MODULES">Jira&lt;/a> &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/bug.png" alt="bug">&lt;/h2>
&lt;p>A link to raising an issue using Jira can be found &lt;a href="https://tickets.puppetlabs.com/browse/MODULES">here&lt;/a>.&lt;/p>
&lt;p>When you come across an issue with one of our supported modules and want to raise an issue, in order for to it to come directly to us there are a few things we would doing first.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Confirm this issue hasn&amp;rsquo;t already been raised by using the JIRA search function&lt;/p>
&lt;/li>
&lt;li>
&lt;p>If the repository has issues enabled, use this instead of JIRA&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Once the above has been confirmed, it is recommended that you complete the following settings in the ticket. This will ensure that our team sees the ticket pretty quick.&lt;/p>
&lt;p>The values we would recommend setting are:&lt;/p>
&lt;p>&lt;code>Project:&lt;/code> This will always need set to &lt;strong>&amp;lsquo;Modules&amp;rsquo;&lt;/strong> if you want it to land with our team.&lt;/p>
&lt;p>&lt;code>Issue Type:&lt;/code> In most cases you will be raising bugs against our supported modules however you can choose the description that best suits your problem.&lt;/p>
&lt;p>&lt;code>Summary:&lt;/code> Just a quick simple summary of the topic you are looking to highlight to us.&lt;/p>
&lt;p>&lt;code>Component:&lt;/code> This is used to tag the module affected and ensure the correct person sees your issue.&lt;/p>
&lt;p>&lt;code>Description:&lt;/code> This is one of the most important sections, add in here as much details as you possibly can, this should include:&lt;/p>
&lt;pre>&lt;code>1) Description of the issue you are seeing
2) Steps to Reproduce
3) Expected Results
4) Actual Results
5) Logs/Screenshots/Sample Manifests - in particular, logs generated with the --trace and --debug flags
&lt;/code>&lt;/pre>
&lt;p>For more information on writing a good bug report check out this page on &lt;a href="https://rubygarage.org/blog/how-to-write-a-quality-bug-report">RubyGarage&lt;/a>.&lt;/p>
&lt;p>&lt;code>Environment:&lt;/code> What OS did did you see it on? Which puppet version is affected? What is the module version? You can even include more information like the Ruby version. Again the more information you include here, the higher likelihood of us being able to reproduce and speed up our turnaround.&lt;/p>
&lt;p>&lt;code>Acceptance Criteria:&lt;/code> What exactly do you want to be able to achieve with the issue being resolved?&lt;/p>
&lt;h2 :height="40px" width="40px" id="some-things-just-cant-wait-clockcontent-and-tooling-teamassets2021-01-20-reaching-outclockpng">Some things just can&amp;rsquo;t wait &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/clock.png" alt="clock">&lt;/h2>
&lt;p>If you ever find yourself in this position please don&amp;rsquo;t hesitate to reach out to our team using email and we will do our best to help you out. Our team alias is: &lt;a href="mailto:ia_content@puppet.com">ia_content@puppet.com&lt;/a>.&lt;/p>
&lt;h2 :height="40px" width="40px" id="useful-tips-magiccontent-and-tooling-teamassets2021-01-20-reaching-outmagicpng">Useful Tips &lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2021-01-20-reaching-out/magic.png" alt="magic">&lt;/h2>
&lt;ul>
&lt;li>All supported modules have an examples directory with example manifests&lt;/li>
&lt;li>If your struggling to write a manifest check out our tests in &lt;code>spec/acceptance&lt;/code>&lt;/li>
&lt;li>We have a some demos uploaded on &lt;a href="https://www.youtube.com/user/PuppetLabsInc">youtube&lt;/a>!&lt;/li>
&lt;/ul>
&lt;h2 id="other-team-contacts">Other team contacts&lt;/h2>
&lt;h3 id="security-team">Security Team&lt;/h3>
&lt;p>For security critical information use &lt;a href="mailto:security@puppet.com">security@puppet.com&lt;/a>.&lt;/p>
&lt;p>&lt;em>Your alert will be handled by our security specialists and routed to the right team. See also the &lt;a href="https://puppet.com/security/">security page&lt;/a> on puppet.com.&lt;/em>&lt;/p>
&lt;h3 id="bolt-team">Bolt Team&lt;/h3>
&lt;p>Use the issues tab &lt;a href="https://github.com/puppetlabs/bolt/issues">on the repo&lt;/a>.&lt;/p>
&lt;h3 id="puppet-agent-team">Puppet Agent Team&lt;/h3>
&lt;p>&lt;a href="mailto:team-nw@puppet.com">team-nw@puppet.com&lt;/a>&lt;/p>
&lt;h3 id="forge-team">Forge Team&lt;/h3>
&lt;p>&lt;a href="mailto:forge@puppet.com">forge@puppet.com&lt;/a>&lt;/p></description></item><item><title>Blog: Puppetize Digital 2020 - Content Selection</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-11-23-puppetize-digital/</link><pubDate>Mon, 23 Nov 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-11-23-puppetize-digital/</guid><description>
&lt;p>Last week saw &lt;a href="https://digital.puppetize.com/">Puppetize Digital 2020&lt;/a>, our annual conference on all things Puppet.
Over the weekend, the production team uploaded all the talks to &lt;a href="https://www.youtube.com/user/PuppetLabsInc/videos">the Puppet YouTube channel&lt;/a>, so if you missed anything, you can now catch up at your own leisure.
There is a &lt;a href="https://www.youtube.com/playlist?list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW">playlist&lt;/a> with all videos, and in this post I&amp;rsquo;ll directly link to my favourites - of course focused on Puppet Content and the IAC team&amp;rsquo;s work.&lt;/p>
&lt;h2 id="puppet-pair-programming-with-visual-studio-code">Puppet Pair Programming with Visual Studio Code&lt;/h2>
&lt;p>The &lt;a href="https://puppet-vscode.github.io/">Puppet VSCode Plugin&lt;/a> has evolved into THE canonical way to edit puppet modules.
The authors of the plugin, &lt;a href="https://www.linkedin.com/in/jamespogran/">James Pogran&lt;/a> and &lt;a href="https://www.linkedin.com/in/glenn-sarti/">Glenn Sarti&lt;/a> are sharing the newest updates to the plugin, as well as some of the benefits of working with a modern, full-featured Development Environment:&lt;/p>
&lt;div class="800">
&lt;iframe src="https://www.youtube.com/embed/j3o-U1c_dXs" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;p>Since last week we also provide a default &lt;a href="https://gitpod.io">gitpod&lt;/a> and &lt;a href="https://github.com/features/codespaces">codespaces&lt;/a> environment on our supported modules. This way you can try out and use all of that goodness directly from your browser.&lt;/p>
&lt;h2 id="the-new-puppet-developer-experience-its-all-about-you">The new Puppet Developer Experience: it&amp;rsquo;s all about you&lt;/h2>
&lt;p>&lt;a href="https://www.linkedin.com/in/binford2k/">Ben Ford&lt;/a>, our Developer Advocate and Product Manager, on the state of Puppet Content.&lt;/p>
&lt;ul>
&lt;li>recent updates to the Forge in form and function&lt;/li>
&lt;li>announcing the Trusted Contributor programme&lt;/li>
&lt;li>a demo by &lt;a href="https://www.linkedin.com/in/daniel-carabas-b2bb0851/">Daniel Carabas&lt;/a> to show off our new public Cloud CI for modules&lt;/li>
&lt;/ul>
&lt;div class="800">
&lt;iframe src="https://www.youtube.com/embed/FspzumfFvBg" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;h2 id="puppetizing-dsc">Puppetizing DSC&lt;/h2>
&lt;p>As the IAC&amp;rsquo;s headline feature this year, &lt;a href="https://www.linkedin.com/in/michaeltlombardi/">Michael Lombardi&lt;/a> is talking about how we finally fixed the &amp;ldquo;DSC-update&amp;rdquo; problem.
From now on, we can publish up-to-date puppet wrappers of &lt;a href="https://www.powershellgallery.com/packages">all DSC module from the gallery&lt;/a> (select &amp;ldquo;DSC Resource&amp;rdquo; in the filters) to the new &lt;a href="https://forge.puppet.com/dsc">DSC namespace on the forge&lt;/a>.
This means that any improvement on upstream DSC resources will become available in a timely manner - and without additional build steps - to all Puppet users.
The way it is designed also means that from this point forward, everyone can build their local DSC resources into a puppet module using the &lt;a href="https://www.powershellgallery.com/packages/Puppet.Dsc">Puppet.Dsc Powershell Module&lt;/a>.&lt;/p>
&lt;div class="800">
&lt;iframe src="https://www.youtube.com/embed/i-eo58NaYKg" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;h2 id="automate-everything">Automate Everything&lt;/h2>
&lt;p>If you need to manage a lot of module repositories, &lt;a href="https://github.com/op-ct">Chris Tessmer&lt;/a> has your back.
Based on a few scripts and bolt, he single-handedly (and very handily) replaces modulesync and pdksync with a much nicer alternative.
&lt;a href="https://github.com/op-ct/puppetsync">puppetsync&lt;/a> is a set of tasks and plans supporting managing &lt;a href="https://forge.puppet.com/simp">SIMP&lt;/a>&amp;rsquo;s modules on github.
In his talk, Chris shows how it is used, and a number of useful tips and tricks for working with bolt plans.&lt;/p>
&lt;div class="800">
&lt;iframe src="https://www.youtube.com/embed/48m8b5VRWoY" allowfullscreen title="YouTube Video">&lt;/iframe>
&lt;/div>
&lt;h2 id="further-content-watching">Further Content Watching&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=mDhmxH0hi9Q&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=5">ServiceNow integration&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=PEn5UZR0bso&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=8">Preparing People for Proper Patching with Puppet Plans&lt;/a> (also aspirant for alliteration award)&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=55KSc63W1_E&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=18">Roles and Profiles&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=hYdF5vJu_HA&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=20">Application Stack Builds&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=xLF6UkzpBQ4&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=24">Automating Windows&lt;/a>
&lt;ul>
&lt;li>More in-depth info in the &lt;a href="https://www.youtube.com/watch?v=NFnVSENjRGs&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=43">workshop&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=bbZ9T3Hp_xI&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=26">Update your code safely&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=8FblErxC1OY&amp;amp;list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW&amp;amp;index=33">Git Workflows for Puppet&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>You can find the &lt;a href="https://www.youtube.com/playlist?list=PLV86BgbREluXpEPnW_Bb4kgZAlGit4EnW">entire playlist on YouTube&lt;/a>.&lt;/p></description></item><item><title>Blog: Collecting GCP info and system metrics for Honeycomb</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-10-05-honeycomb-gcp-metrics/</link><pubDate>Mon, 05 Oct 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-10-05-honeycomb-gcp-metrics/</guid><description>
&lt;p>For a new and exciting project, the team is currently onboarding on &lt;a href="https://en.wikipedia.org/wiki/Google_Cloud_Platform">Google Cloud Platform (GCP)&lt;/a> development.&lt;/p>
&lt;!-- This is part of a series of posts describing our journey. -->
&lt;p>I can&amp;rsquo;t wait until I&amp;rsquo;m able to share more, but for now I can only say we&amp;rsquo;re looking at a &lt;a href="http://sinatrarb.com/intro.html">Sinatra&lt;/a>-hosted Ruby API server.
To gain a better understanding how the service is performing, we want to collect some &amp;ldquo;traditional&amp;rdquo; metrics.
Since we&amp;rsquo;re already using honeycomb for tracing &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-teamblog/updates/2020-03-30-debugging-unit-tests-with-honeycomb.md">tests&lt;/a> and &lt;a href="https://docs.honeycomb.io/getting-data-in/ruby/beeline/#sinatra">API calls&lt;/a>, looking into honeycomb for more was my first choice.
Most of the content here is based off the &amp;ldquo;Getting Started With Honeycomb Metrics&amp;rdquo; whitepaper at [https://www.honeycomb.io/white-papers/], made specific to Ruby and GCP.&lt;/p>
&lt;h2 id="static-runtime-information">Static runtime information&lt;/h2>
&lt;p>The first thing to collect is some static information about the container runtime hosting the current process.
We&amp;rsquo;re using &lt;a href="https://cloud.google.com/run/docs">Cloud Run&lt;/a> as our primary deployment infrastructure for the API services, so this is our first stop.
The &lt;a href="https://cloud.google.com/compute/docs/storing-retrieving-metadata">metadata server&lt;/a> provides details about the container instance as described in &amp;ldquo;&lt;a href="https://cloud.google.com/run/docs/reference/container-contract#metadata-server">Container instance metadata server&lt;/a>&amp;rdquo;.&lt;/p>
&lt;p>The GCP ruby gems provide &lt;code>Google::Cloud.env&lt;/code> to access the metadata server.
Here is a pruned example of how to add metadata to all spans for easy filtering:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#8be9fd;font-style:italic">require&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;honeycomb-beeline&amp;#39;&lt;/span>
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>configure &lt;span style="color:#ff79c6">do&lt;/span> &lt;span style="color:#ff79c6">|&lt;/span>config&lt;span style="color:#ff79c6">|&lt;/span>
config&lt;span style="color:#ff79c6">.&lt;/span>service_name &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;backend&amp;#39;&lt;/span>
&lt;span style="color:#ff79c6">end&lt;/span>
env &lt;span style="color:#ff79c6">=&lt;/span> Google&lt;span style="color:#ff79c6">::&lt;/span>Cloud&lt;span style="color:#ff79c6">.&lt;/span>env
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.project_id&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>project_id)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_id&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>lookup_metadata(&lt;span style="color:#f1fa8c">&amp;#39;instance&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;id&amp;#39;&lt;/span>))
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_name&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>instance_name)
region_result &lt;span style="color:#ff79c6">=&lt;/span> env&lt;span style="color:#ff79c6">.&lt;/span>lookup_metadata &lt;span style="color:#f1fa8c">&amp;#34;instance&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;region&amp;#34;&lt;/span>
region &lt;span style="color:#ff79c6">=&lt;/span> region_result&lt;span style="color:#ff79c6">&amp;amp;.&lt;/span>split(&lt;span style="color:#f1fa8c">&amp;#39;/&amp;#39;&lt;/span>)&lt;span style="color:#ff79c6">&amp;amp;.&lt;/span>last
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_region&amp;#39;&lt;/span>, region)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_zone&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>instance_zone)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_machine_type&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>instance_machine_type)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.instance_blog_tags&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>instance_blog_tags)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.knative_service_id&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>knative_service_id)
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;gcp.knative_service_revision&amp;#39;&lt;/span>, env&lt;span style="color:#ff79c6">.&lt;/span>knative_service_revision)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Put this code somewhere that is loaded on app start up.
For rack-based frameworks like sinatra this is the &lt;code>config.ru&lt;/code>, where we include this code through &lt;code>require&lt;/code>.&lt;/p>
&lt;p>At the same time, we can also add private configuration flags from our service, to track their influence.
For example, to capture whether &lt;code>FLAG_ENABLED&lt;/code> has been set in the container&amp;rsquo;s variables:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;flag_enabled&amp;#39;&lt;/span>, ENV&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;FLAG_ENABLED&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span> &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;true&amp;#39;&lt;/span>)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The attributes show up in the trace/span sidebar and can be used in any query:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-10-05-honeycomb-gcp-metrics/gcp_attributes.png" alt="">&lt;/p>
&lt;h2 id="dynamic-data">Dynamic Data&lt;/h2>
&lt;p>For the actual system metrics, like CPU and memory usage, &lt;a href="https://github.com/honeycombio/libhoney-rb">libhoney&lt;/a> offers builders and &lt;a href="https://docs.honeycomb.io/getting-data-in/ruby/sdk/#advanced-usage-dynamic-fields">dynamic fields&lt;/a> (&lt;a href="https://www.rubydoc.info/gems/libhoney/Libhoney%2FClient:add_dynamic_field">API docs&lt;/a>).
Dynamic fields get evaluated at the start of each span[&lt;a href="https://github.com/honeycombio/beeline-ruby/blob/15341f01740001acbc1f2748e68cbe380bfc3f7f/lib/honeycomb/span.rb#L31">1&lt;/a>] and added to the fields sent to Honeycomb.&lt;/p>
&lt;p>To access the current &lt;a href="http://en.wikipedia.org/wiki/Resident_set_size">Resident Set Size&lt;/a> (RSS, &amp;ldquo;memory in use&amp;rdquo;) we use the &lt;a href="https://github.com/schneems/get_process_mem">get_process_mem gem&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#8be9fd;font-style:italic">require&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;get_process_mem&amp;#39;&lt;/span>
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_dynamic_field(&lt;span style="color:#f1fa8c">&amp;#39;global.memory_inuse_bytes&amp;#39;&lt;/span>, &lt;span style="color:#8be9fd;font-style:italic">proc&lt;/span> { GetProcessMem&lt;span style="color:#ff79c6">.&lt;/span>new&lt;span style="color:#ff79c6">.&lt;/span>bytes&lt;span style="color:#ff79c6">.&lt;/span>to_i })
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The total lifetime of the process can be calculated as the difference from the start time to now:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">start &lt;span style="color:#ff79c6">=&lt;/span> Time&lt;span style="color:#ff79c6">.&lt;/span>now
Honeycomb&lt;span style="color:#ff79c6">.&lt;/span>client&lt;span style="color:#ff79c6">.&lt;/span>libhoney&lt;span style="color:#ff79c6">.&lt;/span>add_dynamic_field(&lt;span style="color:#f1fa8c">&amp;#39;global.process_uptime_seconds&amp;#39;&lt;/span>, &lt;span style="color:#8be9fd;font-style:italic">proc&lt;/span> { Time&lt;span style="color:#ff79c6">.&lt;/span>now &lt;span style="color:#ff79c6">-&lt;/span> start }
&lt;/code>&lt;/pre>&lt;/div>&lt;p>After a few minutes of the heartbeat API call:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-10-05-honeycomb-gcp-metrics/first_results.png" alt="">&lt;/p>
&lt;h2 id="closing-notes">Closing Notes&lt;/h2>
&lt;p>This post was written while implementing the first stab at collecting metrics.
As we continue to improve our understanding of the capabilities and limitations of GCP, I expect we will have to revisit the exact metrics collected.
For example, data written to disk in Cloud Run is stored in RAM and also counted against the service&amp;rsquo;s quota.
This sounds like something to keep an eye on eventually.&lt;/p>
&lt;p>Honeycomb recommends keeping system metrics in a separate dataset from application events.
During development we currently have very little traffic on the service, so for simplicities sake, we keep everything global and attached to all events.
We&amp;rsquo;ll have to revisit this once we get more traffic on the service.&lt;/p></description></item><item><title>Blog: Docker params change detection</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-09-23-docker-params-change-detection/</link><pubDate>Wed, 23 Sep 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-09-23-docker-params-change-detection/</guid><description>
&lt;h2 id="docker-params-change-detection">Docker params change detection&lt;/h2>
&lt;p>The problem was reported by a client with the ticket &lt;a href="https://tickets.puppetlabs.com/browse/MODULES-10734">MODULES-10734&lt;/a>. After analysis, we discovered that we don&amp;rsquo;t have parameter change detection mechanisms. In this blog post, we try to explain the problem in detail with examples.&lt;/p>
&lt;p>An interesting behaviour was present in docker::run component. The problem was that if any parameter was added/modified/removed puppet agent would only apply the change only if you stopped, removed the container manually and reapplied the manifest, forcing a new container creation.&lt;/p>
&lt;p>The solution was to create a new function that detects if at least one parameter is changed. The detection mechanism is based on the check between parameter values from the manifest file and correspondent field from the docker inspect object of the currently running container. The solution is present in the 3.11.0 version.&lt;/p>
&lt;p>So now let&amp;rsquo;s see how the problem can be reproduced by using version &lt;code>&amp;lt;= 3.10.2&lt;/code>:&lt;/p>
&lt;h3 id="1-install-puppetlabsdocker-module">1. install puppetlabs/docker module&lt;/h3>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">$: puppet module install puppetlabs/docker --version 3.10.2
&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-apply-this-manifest">2. apply this manifest:&lt;/h3>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#ff79c6">class&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;docker&amp;#39;&lt;/span>: }
&lt;span style="color:#50fa7b">docker&lt;/span>::&lt;span style="color:#50fa7b">run&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;servercore&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">image&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;hello-world:linux&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">restart&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;always&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">net&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$facts[&amp;#39;os&amp;#39;]&lt;/span>[&lt;span style="color:#f1fa8c">&amp;#39;name&amp;#39;&lt;/span>] &lt;span style="color:#ff79c6">?&lt;/span> {
&lt;span style="color:#f1fa8c">&amp;#39;windows&amp;#39;&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;nat&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">default&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;bridge&amp;#39;&lt;/span>,
},
}
&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-check-the-image-tag-by-running-this-command">3. check the image tag by running this command:&lt;/h3>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">$: docker inspect --format&lt;span style="color:#ff79c6">=&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;{{ .Config.Image }}&amp;#34;&lt;/span> servercore
$: hello-world:linux
&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-change-the-image-tag-from-hello-worldlinux-to-hello-worldlatest-and-reapply-the-manifest">4. change the image tag from &lt;code>hello-world:linux&lt;/code> to &lt;code>hello-world:latest&lt;/code> and reapply the manifest.&lt;/h3>
&lt;p>The manifest should look like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#ff79c6">class&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;docker&amp;#39;&lt;/span>: }
&lt;span style="color:#50fa7b">docker&lt;/span>::&lt;span style="color:#50fa7b">run&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;servercore&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">image&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;hello-world:latest&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">restart&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;always&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">net&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$facts[&amp;#39;os&amp;#39;]&lt;/span>[&lt;span style="color:#f1fa8c">&amp;#39;name&amp;#39;&lt;/span>] &lt;span style="color:#ff79c6">?&lt;/span> {
&lt;span style="color:#f1fa8c">&amp;#39;windows&amp;#39;&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;nat&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">default&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;bridge&amp;#39;&lt;/span>,
},
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip; and now check if the change was applied&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">$: docker inspect --format&lt;span style="color:#ff79c6">=&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;{{ .Config.Image }}&amp;#34;&lt;/span> servercore
$: hello-world:linux
&lt;/code>&lt;/pre>&lt;/div>&lt;p>so&amp;hellip; something is wrong, the tag was not changed to &lt;code>hello-world:latest&lt;/code>. If we want to apply this change we need to do a few more steps:&lt;/p>
&lt;ul>
&lt;li>stop the container: &lt;code>docker stop servercore&lt;/code>&lt;/li>
&lt;li>remove the container: &lt;code>docker rm servercore&lt;/code>&lt;/li>
&lt;li>reapply the manifest detailed above: &lt;code>puppet apply &amp;lt;manifest_file_name&amp;gt;&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>In conclusion in the puppetlabs/docker module versions &lt;code>&amp;lt;= 3.10.2 &lt;/code>the parameter change is not detected. If we want to change some parameters for the same container, the puppet agent will not apply these changes for us until we delete the container manually.
Using the latest versions(&lt;code>&amp;gt;=3.11.0&lt;/code>) this problem is resolved by having the parameter detection mechanism implemented for the most important parameters such as image, volumes and ports.
Also please take a look at the &lt;a href="https://github.com/puppetlabs/puppetlabs-docker/pull/648">solution&lt;/a>.&lt;/p>
&lt;p>Kind regards,
&lt;a href="https://github.com/adrianiurca">Adrian Iurca&lt;/a>&lt;/p></description></item><item><title>Blog: DSC + Puppet: Arrived!</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-09-21-dsc-release/</link><pubDate>Mon, 21 Sep 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-09-21-dsc-release/</guid><description>
&lt;p>Earlier this year, we &lt;a href="https://puppetlabs.github.io/iac/news/roadmap/2020/03/30/dsc-announcement.html">announced an upcoming project&lt;/a> to drastically improve the story for using DSC Resources with Puppet.
Today, we&amp;rsquo;re announcing the general availability of that project!&lt;/p>
&lt;p>The &lt;a href="https://github.com/puppetlabs/Puppet.Dsc">&lt;code>Puppet.Dsc&lt;/code> PowerShell module&lt;/a> is now available on the &lt;a href="https://www.powershellgallery.com/packages/Puppet.Dsc">PowerShell Gallery&lt;/a>;
furthermore, an initial batch of &lt;strong>twenty-six&lt;/strong> PowerShell modules with DSC Resources have been Puppetized and &lt;a href="https://forge.puppet.com/dsc">published to the Forge&lt;/a>!&lt;/p>
&lt;p>We picked several of the most-downloaded modules with DSC Resources released in the last year to start with, but in the coming weeks you should find &lt;em>everything&lt;/em> available on the PowerShell Gallery up on the Forge!&lt;/p>
&lt;p>But today, in addition to sharing this news, I want to go into a bit more detail, both with what&amp;rsquo;s going on under the hood and with how you can use these auto-generated modules.&lt;/p>
&lt;h3 id="installing-the-modules">Installing the Modules&lt;/h3>
&lt;p>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:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Install-Module&lt;/span> -Name Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Import-Module&lt;/span> -Name Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Get-Command&lt;/span> -Module Puppet.Dsc
&lt;span style="color:#8be9fd;font-style:italic">Get-Help&lt;/span> -Name &lt;span style="color:#8be9fd;font-style:italic">New-PuppetDscModule&lt;/span> -ShowWindow
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Some of the functions from the PowerShell module rely on the &lt;a href="https://puppet.com/docs/pdk/1.x/pdk.html">Puppet Development Kit (PDK)&lt;/a> being installed;
we suggest using &lt;a href="https://chocolatey.org/">Chocolatey&lt;/a> to do so, but you can also &lt;a href="https://puppet.com/try-puppet/puppet-development-kit/">manually download and install&lt;/a> if you prefer.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">choco install pdk
&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you want to do the same sort of thing with one of the Puppetized modules from the forge, you can install them and treat them just like any other Puppet module:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">&lt;span style="color:#6272a4"># For example, installing the Puppetized ComputerManagementDsc module manually:&lt;/span>
puppet module install dsc-computermanagementdsc --Version 8.4.0-0-0
&lt;span style="color:#6272a4"># Or via r10k / Code Manager / Bolt:&lt;/span>
mod &lt;span style="color:#f1fa8c">&amp;#39;dsc-computermanagementdsc&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;8.4.0-0-0&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="puppetizing-a-powershell-module">Puppetizing a PowerShell module&lt;/h2>
&lt;p>So, you want to turn a PowerShell module with DSC Resources into a Puppet module?
You can do this with a single command:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#6272a4"># If you run this command without the PassThru flag it returns nothing to the output stream.&lt;/span>
&lt;span style="color:#6272a4"># Any conversion errors will be in the error stream, as usual.&lt;/span>
&lt;span style="color:#6272a4"># If you&amp;#39;d like a deeper look at what it&amp;#39;s doing, try running it with the Verbose flag.&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">New-PuppetDscModule&lt;/span> -PowerShellModuleName ComputerManagementDsc -PassThru
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Unfortunately, the output from running it isn&amp;rsquo;t all that exciting:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/new-puppetdscmodule.png" alt="Output from a PowerShell console showing the running of the command above as well as the return output, which is the folder object representing the new Puppet module on disk">&lt;/p>
&lt;p>Behind the scenes, the command:&lt;/p>
&lt;ol>
&lt;li>Uses the &lt;a href="https://puppet.com/docs/pdk/1.x/pdk.html">PDK&lt;/a> to create a new Puppet module&lt;/li>
&lt;li>Searches the &lt;a href="https://www.powershellgallery.com">PowerShell Gallery&lt;/a> for the ComputerManagementDsc module and vendor it into the new Puppet module&lt;/li>
&lt;li>Converts each of the DSC Resources from the vendored PowerShell module into a Puppet Resource API type and provider&lt;/li>
&lt;li>Updates the Puppet module&amp;rsquo;s metadata and documentation based on the PowerShell module.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>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 &lt;em>does&lt;/em> work without administrator privileges, the function cannot fully map nested CIM instances without administrator privileges.
For more information on this process, check out the &lt;a href="https://github.com/puppetlabs/Puppet.Dsc/blob/main/docs/about_Puppetization.md">&lt;code>about_Puppetization&lt;/code> HelpFile&lt;/a> via &lt;code>Get-Help&lt;/code> for a more in-depth documentation of this process.&lt;/p>
&lt;/blockquote>
&lt;h2 id="using-puppetized-modules">Using puppetized modules&lt;/h2>
&lt;p>On the one hand, there&amp;rsquo;s not much to say about using the Puppetized modules with DSC Resources;
you use them &lt;em>precisely&lt;/em> like any other Puppet module, after all.
On the other hand, there&amp;rsquo;s some strong utility worth going over in more detail you may or may not be aware of!&lt;/p>
&lt;p>To get the most value from your workflow, we &lt;strong>strongly&lt;/strong> recommend you author your manifests that include Puppetized DSC Resources in &lt;a href="https://code.visualstudio.com/">VSCode&lt;/a> with the &lt;a href="https://puppet-vscode.github.io/">Puppet extension&lt;/a> enabled.&lt;/p>
&lt;p>When we open a file named &lt;code>example.pp&lt;/code> 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.&lt;/p>
&lt;p>For example, if we&amp;rsquo;ve installed the &lt;code>computermanagementdsc&lt;/code> Puppet module, we need only type &lt;code>dsc_execution&lt;/code> before IntelliSense kicks in and helps us out:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/intellisense-resource.png" alt="A VSCode window showing the text &amp;lsquo;dsc_execution&amp;rsquo; has raised a tooltip which lists multiple possible matches, including dsc_powershellexecutionpolicy, and to the right it shows the help information for this resource.">&lt;/p>
&lt;p>Note that it tells us not just what available resources might match, it also displays the available documentation for each resource.&lt;/p>
&lt;p>We also get IntelliSense for each property we want to pass, too;
again, this doesn&amp;rsquo;t just show the available options but also includes any available documentation for each property.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/intellisense-property.png" alt="A VSCode window showing the text &amp;lsquo;dsc&amp;rsquo; inside a Puppet resource declaration for dsc_powershellexecutionpolicy, with a tooltip listing the possible properties, including dsc_executionpolicy and dsc_executionpolicyscope; as before, the help information (now including valid values) is to the right.">&lt;/p>
&lt;p>You can also review the documentation for a property by hovering over it:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/docs-property.png" alt="A VSCode window showing an empty declaration for &amp;lsquo;dsc_executionpolicy&amp;rsquo; with the mouse hovering over that key, displaying a tooltip which includes the documentation and valid values for the property.">&lt;/p>
&lt;p>Where this combination really begins to sing is when you&amp;rsquo;ve begun authoring a manifest and something goes wrong.&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems.png" alt="A VSCode window showing a fully defined manifest with markings to highlight issues.">&lt;/p>
&lt;p>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.&lt;/p>
&lt;p>VSCode (via the extension) knows &lt;em>something&lt;/em> is wrong with our manifest;
we can click on those symbols to bring up the Problems Pane and investigate:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems-pane.png" alt="A VSCode window displaying the Problems Pane with two entries">&lt;/p>
&lt;p>This tells us there&amp;rsquo;s a warning about the indentation of a hash rocket and some sort of syntax error preventing the extension from parsing line 3.&lt;/p>
&lt;p>A quick look at the code tells us that we&amp;rsquo;re missing a comma in the resource declaration on line 2, and as soon as we add that comma in we get confirmation:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/problems-added-comma.png" alt="A VSCode window displaying the Problems Pane with only one warning">&lt;/p>
&lt;p>All that remains now is the formatting issue.
Luckily, VSCode is able to automatically handle this for us via the &lt;em>Format Document&lt;/em> command:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/format-document-option.png" alt="A VSCode window displaying the right-click menu over the manifest, highlighting the &amp;lsquo;Format Document&amp;rsquo; command with a hotkey combination of &amp;lsquo;Shift+Alt+F&amp;rsquo;">&lt;/p>
&lt;p>Which we can see does in fact move the hash rocket and resolve our last problem:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-09-21-dsc-release/manifest-fixed.png" alt="A VSCode window displaying the manifest with no issues or warnings, the hash rocket moved appropriately to ensure preferred formatting for the manifest.">&lt;/p>
&lt;p>We&amp;rsquo;re ready to apply this manifest!&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">puppet apply ./example.pp
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Only&amp;hellip; there was a problem;
without reading the documentation for &lt;code>dsc_executionpolicyscope&lt;/code> thoroughly enough, we specified &lt;code>Machine&lt;/code> instead of &lt;code>MachinePolicy&lt;/code>!&lt;/p>
&lt;p>Puppet gives us back a pretty good error message though:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">Error: Parameter dsc_executionpolicyscope failed on Dsc_powershellexecutionpolicy[[OPS-213]]: dsc_powershellexecutionpolicy.dsc_executionpolicyscope expects a match for Enum[&amp;#39;CurrentUser&amp;#39;, &amp;#39;LocalMachine&amp;#39;, &amp;#39;MachinePolicy&amp;#39;, &amp;#39;Process&amp;#39;, &amp;#39;UserPolicy&amp;#39;], got &amp;#39;Machine&amp;#39;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>We get an explicit list of the allowed values &lt;em>before&lt;/em> it tries to invoke DSC with the &lt;code>Set&lt;/code> action.
This is unlike our prior implementation in &lt;code>puppetlabs-dsc_lite&lt;/code>, which has no way of knowing whether the values you&amp;rsquo;ve provided are correct.&lt;/p>
&lt;p>Once we correct our manifest to specify &lt;code>LocalMachine&lt;/code> and re-run the command, we get something else:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">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 &amp;#39;Unrestricted&amp;#39; to &amp;#39;RemoteSigned&amp;#39;
Notice: dsc_powershellexecutionpolicy[{:name=&amp;gt;&amp;#34;[OPS-213]&amp;#34;, :dsc_executionpolicyscope=&amp;gt;&amp;#34;LocalMachine&amp;#34;}]: Updating: Finished in 0.809555 seconds
Notice: Applied catalog in 1.68 seconds
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This highlights a change from both of our prior implementations:
you now get &lt;em>property-by-property&lt;/em> reporting for DSC Resources when using Puppet!
This implementation knows not just &lt;em>that&lt;/em> 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.&lt;/p>
&lt;p>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!&lt;/p>
&lt;h2 id="coming-up">Coming Up&lt;/h2>
&lt;p>This wave of converted DSC Resources and the release of the &lt;code>Puppet.Dsc&lt;/code> module to the PowerShell Gallery is not the &lt;em>last&lt;/em> step of our support for using DSC with Puppet, just the initial step.&lt;/p>
&lt;p>Over the coming weeks we&amp;rsquo;re going to be looking to you for feedback and incorporating it as fast as we can manage.&lt;/p>
&lt;p>We&amp;rsquo;re also moving towards automatically Puppetizing &lt;em>every&lt;/em> PowerShell module with DSC Resources on the Gallery.
If there&amp;rsquo;s a module you want to use that isn&amp;rsquo;t yet published under our &lt;a href="https://forge.puppet.com/dsc">&lt;strong>dsc&lt;/strong> namespace on the Forge&lt;/a>, let us know in &lt;a href="https://slack.puppet.com/">Slack&lt;/a> or by &lt;a href="mailto:dsc@puppet.com">emailing us&lt;/a> and we&amp;rsquo;ll publish it as soon as we can!&lt;/p>
&lt;p>In the long run, we plan to get some nightly builds in place to ensure that there&amp;rsquo;s never more than a 24 hour lag between when a PowerShell module with DSC Resources is published (new or merely updated) to the Gallery and when that same module is Puppetized and published to the Forge.&lt;/p>
&lt;p>We hope to hear from you soon!&lt;/p></description></item><item><title>Blog: Apache MOD Test Maintenance</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-07-03-apache-mod-test-improvements/</link><pubDate>Fri, 03 Jul 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-07-03-apache-mod-test-improvements/</guid><description>
&lt;p>This week sees version &lt;code>v5.5.0&lt;/code> of the &lt;a href="https://forge.puppet.com/puppetlabs/apache">puppetlabs-apache&lt;/a> module released.
There are a lot of new features within this release - check out the &lt;a href="https://forge.puppet.com/puppetlabs/apache/changelog#v550-2020-07-01">CHANGELOG entry for this version&lt;/a> to see what&amp;rsquo;s included.&lt;/p>
&lt;p>The last release of this module was &lt;code>v5.4.0&lt;/code> on &lt;code>2020-01-23&lt;/code>, over 5 months ago.
Currently the IAC Team is responsible for these supported &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/modules/">modules&lt;/a> and &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/tools/">tools&lt;/a>.
As a small team we always continue to improve our processes to ensure we&amp;rsquo;re maximising our time and efforts.
Still, the gap in time between the release of &lt;code>v5.4.0&lt;/code> and &lt;code>v5.5.0&lt;/code> of the &lt;a href="https://forge.puppet.com/puppetlabs/apache">puppetlabs-apache&lt;/a> module was a concern for us.
What happened and how did we address this issue?&lt;/p>
&lt;h2 id="why-the-delay">Why the delay?&lt;/h2>
&lt;p>There was no shortage of excellent community contributions to the &lt;a href="https://github.com/puppetlabs/puppetlabs-apache">puppetlabs-apache&lt;/a> module in the period between these two releases.
The team were keen to get a new release of the module out sooner than this, so the community could take advantage of these contributions.
Part of the process of releasing a module involves us running our release check suite on our internal VM infrastructure.
We were finding that there were cases where tests for &lt;a href="https://httpd.apache.org/docs/2.4/mod">Apache MODs&lt;/a> were failing on certain platforms after someone in the community put forward a fix.&lt;/p>
&lt;h2 id="what-was-the-issue">What was the issue?&lt;/h2>
&lt;p>There are multiple reasons we ended up in this scenario, which ultimately had the same root cause, namely, a lack of test coverage.
Some examples are:&lt;/p>
&lt;ul>
&lt;li>New platforms changing MOD package names (e.g. &lt;a href="https://github.com/farebers">farebers&amp;rsquo;s&lt;/a> fix in &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/pull/2021">#2021&lt;/a>)&lt;/li>
&lt;li>&lt;a href="https://github.com/puppetlabs/puppetlabs-apache/pull/1913">Fixes for one environment&lt;/a> having a knock-on effect for a &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/pull/2041">different environment&lt;/a> (thanks to &lt;a href="https://github.com/h-haaks">h-haaks&lt;/a> for the fix!)&lt;/li>
&lt;/ul>
&lt;p>When a new version of an OS comes out, it is quite common for issues to manifest when trying to configure some of the less mainstream &lt;a href="https://httpd.apache.org/docs/2.4/mod">Apache MODs&lt;/a>:&lt;/p>
&lt;ul>
&lt;li>A simple change in it&amp;rsquo;s package name (&lt;em>thankfully a relatively quick fix!&lt;/em>)&lt;/li>
&lt;li>The package is no longer available from the core &amp;ldquo;out-of-the-box&amp;rdquo; repositories (e.g. a 3rd party repos or edge/experimental/extra package streams need to be configured)&lt;/li>
&lt;li>Package dependencies are unavailable in non-standard repositories&lt;/li>
&lt;li>Support is dropped altogether - there is no way to locate the package or dependencies for a newer OS version&lt;/li>
&lt;/ul>
&lt;p>This led us to a conversation about how we continue to support all the various prerequisites and configurations required when presented with a matrix of &lt;a href="https://httpd.apache.org/docs/2.4/mod">Apache MODs&lt;/a> and &lt;a href="https://forge.puppet.com/puppetlabs/apache/compatibility">compatible OSs&lt;/a>.
We could, if time permitted, ensure that we have the steps to install every version&amp;hellip;of every MOD&amp;hellip;on every OS&amp;hellip;documented and implemented.&lt;/p>
&lt;p>Time permitting&amp;hellip;&lt;/p>
&lt;h2 id="solution">Solution&lt;/h2>
&lt;h3 id="test-support-policy">Test Support Policy&lt;/h3>
&lt;p>Straight away, we realised that, in the future, we need to strictly time box the amount of time we spend attempting to configure the OS with the correct repositories and/or dependencies for any given MOD.
A rule of thumb was that if it&amp;rsquo;s not available in the default repositories of the OS, or a common, well supported auxiliary repository (e.g. EPEL), then we are not going to pin down the very unique snowflake configuration required for that MOD.
There is always the concept of &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/blob/master/manifests/default_mods.pp">default MODs&lt;/a> in Apache and these will &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/blob/master/spec/acceptance/default_mods_spec.rb">remain supported&lt;/a> with the module, however, in future, we are going to evaluate how we proceed with a test failure with a much stricter time limit.&lt;/p>
&lt;h3 id="mods-arent-supported-anymore">MODs aren&amp;rsquo;t supported anymore!?&lt;/h3>
&lt;p>Absolutely not! They are still supported! If you want to add support for a new MOD, we do ask that you also write an acceptance test too.
The IAC Team are always happy to help you with this process.&lt;/p>
&lt;h3 id="i-cant-get-the-test-to-pass-on-all-platforms">I can&amp;rsquo;t get the test to pass on all platforms!&lt;/h3>
&lt;p>Yes - this is likely an issue you&amp;rsquo;re going to run in to.
Kudos to those who chase down ALL the package, package dependencies and configurations required for ALL of the &lt;a href="https://forge.puppet.com/puppetlabs/apache/compatibility">compatible platforms&lt;/a> of the Apache module.
Realistically, you will likely encounter a few OSs where it is beyond reasonable to try and get this MOD working.
In these scenarios, we&amp;rsquo;ll start a conversation on the PR about what the acceptable minimum is for the change being proposed - there&amp;rsquo;s no hard/fast rule here.&lt;/p>
&lt;h3 id="weve-agreed-were-not-supporting-this-mod-on-this-os-version---what-now">We&amp;rsquo;ve agreed we&amp;rsquo;re not supporting this MOD on this OS version - what now?&lt;/h3>
&lt;p>You may be familiar with &lt;a href="https://relishapp.com/rspec/rspec-core/v/3-8/docs/filtering/conditional-filters">RSpec&amp;rsquo;s conditional filtering&lt;/a>?
If not, &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/blob/51ce2adcfc231c6a78dda5cc59c2aaf4028bb5bd/spec/acceptance/mod_ldap_spec.rb#L4">here is an example&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">describe &lt;span style="color:#f1fa8c">&amp;#39;apache::mod::ldap&amp;#39;&lt;/span>, &lt;span style="color:#ff79c6">unless&lt;/span>: os&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:family&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span> &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;redhat&amp;#39;&lt;/span> &lt;span style="color:#ff79c6">&amp;amp;&amp;amp;&lt;/span> os&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:release&lt;/span>&lt;span style="color:#ff79c6">].&lt;/span>to_i &lt;span style="color:#ff79c6">&amp;gt;=&lt;/span> &lt;span style="color:#bd93f9">8&lt;/span> &lt;span style="color:#ff79c6">do&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will mean that this test will &lt;strong>not&lt;/strong> run if the OS family is &lt;code>RedHat&lt;/code> and the version is &lt;code>8&lt;/code> or higher.
These work well, but, things can start to get messy when there is quite a narrow band of compatible OSs for a MOD.
Consider &lt;a href="https://github.com/zmartzone/mod_auth_openidc/releases/tag/v2.4.3">&lt;code>v2.4.3&lt;/code> of &lt;code>mod_auth_openidc&lt;/code>&lt;/a> - we can see from the build artifacts' names that we &amp;ldquo;officially&amp;rdquo; have support for:&lt;/p>
&lt;ul>
&lt;li>Ubuntu 16.04&lt;/li>
&lt;li>Ubuntu 18.04&lt;/li>
&lt;li>Debian 10&lt;/li>
&lt;li>RHEL 7&lt;/li>
&lt;/ul>
&lt;p>This does not consider the fact that there are many other OSs derived from RHEL and other distro vendors / maintainers can port packages to their OS.
For example, after a bit more digging, I can see that the &lt;code>mod_auth_openidc&lt;/code> package is available for the following OSs too:&lt;/p>
&lt;ul>
&lt;li>CentOS 7&lt;/li>
&lt;li>CentOS 8 (via AppStream)&lt;/li>
&lt;li>RHEL 8 (via AppStream)&lt;/li>
&lt;li>Fedora 30&lt;/li>
&lt;li>Fedora 31&lt;/li>
&lt;li>Fedora 32&lt;/li>
&lt;/ul>
&lt;p>This search was not exhaustive, and to make it so would require a lot more effort, which is part of the issue we find ourselves up against.
Still, we now have a list of platforms that we want to include/exclude from being tested - depending on how we look at it.
I&amp;rsquo;m sure you can envisage that the filtering rule for this test is going to become pretty gnarly?
What if I were to also throw in some of the challenges the IAC team face, on top:&lt;/p>
&lt;ul>
&lt;li>Expanding test coverage uncovering more MOD / OS incompatibility&lt;/li>
&lt;li>Some tests invoking a MOD load/configure indirectly whist testing other functionality&lt;/li>
&lt;li>New OS support requirements&lt;/li>
&lt;/ul>
&lt;h3 id="tagging-and-helper-methods">Tagging and Helper Methods&lt;/h3>
&lt;p>We had to come up with some better solution than ridiculously complex filtering rules.
After some conversations and design reviews, we settled on an idea of using &lt;a href="https://www.rubydoc.info/gems/yard/file/docs/blog_tags.md#note">YARD&amp;rsquo;s note blog_tags&lt;/a>.
This gives us the benefit of:&lt;/p>
&lt;ul>
&lt;li>Keeping within the conventions already in use&lt;/li>
&lt;li>Easy syntax to understand&lt;/li>
&lt;li>Free documentation whilst we&amp;rsquo;re at it&lt;/li>
&lt;/ul>
&lt;p>All the class definitions for &lt;a href="https://httpd.apache.org/docs/2.4/mod">Apache MODs&lt;/a> live under &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/tree/983b1fd3ff178d46145f4b8c0a88bae36dfad12b/manifests/mod">&lt;code>manifest/mod&lt;/code>&lt;/a>.
This seemed like the most logical place for our blog_tags to live.
Next, we wanted to decide whether this was an &amp;ldquo;opt-in&amp;rdquo; or &amp;ldquo;opt-out&amp;rdquo; affair.
In the end, we determined that it would be best to &amp;ldquo;opt-out&amp;rdquo; and so, the tag became &lt;code>Unsupported platforms&lt;/code>.
You can now define what platforms a given MOD will &lt;em>not&lt;/em> be expected to run on:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#6272a4"># @note Unsupported platforms: RedHat: 5, 6; Ubuntu: 14.04; SLES: all; Scientific: 11 SP1&lt;/span>
&lt;span style="color:#ff79c6">class&lt;/span> apache&lt;span style="color:#ff79c6">::&lt;/span>mod&lt;span style="color:#ff79c6">::&lt;/span>actions {
apache&lt;span style="color:#ff79c6">::&lt;/span>mod { &lt;span style="color:#f1fa8c">&amp;#39;actions&amp;#39;&lt;/span>: }
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>For a full overview of the tag syntax rules, see &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/blob/c726313dad64683d05465d2f978965ad14690f35/README.md#apache-mod-test--support-lifecycle">this section of the README&lt;/a> in the module.&lt;/p>
&lt;p>When RSpec tests are kicked off in the module, we will parse the &lt;code>Unsupported platform&lt;/code> blog_tags under &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/tree/983b1fd3ff178d46145f4b8c0a88bae36dfad12b/manifests/mod">&lt;code>manifest/mod&lt;/code>&lt;/a> as part of the &lt;code>Rspec.before&lt;/code> hooks and generate a mapping of MOD -&amp;gt; Unsupported Platforms.
Now, from within the tests, you can make use of the &lt;code>mod_supported_on_platform&lt;/code> helper method to determine whether the test should run on a given platform or be filtered out:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">describe &lt;span style="color:#f1fa8c">&amp;#39;auth_oidc&amp;#39;&lt;/span>, &lt;span style="color:#ff79c6">if&lt;/span>: mod_supported_on_platform(&lt;span style="color:#f1fa8c">&amp;#39;apache::mod::auth_openidc&amp;#39;&lt;/span>) &lt;span style="color:#ff79c6">do&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hopefully you&amp;rsquo;ll agree that this is a much cleaner solution that a complex filtering rule?
For the IAC Team, it makes our life a lot easier, and hopefully means more frequent updates released for the Apache module for the community.&lt;/p>
&lt;h4 id="want-more-details">Want more details?&lt;/h4>
&lt;p>You can see the implementation on &lt;a href="https://github.com/puppetlabs/puppetlabs-apache/pull/2036">#2036&lt;/a>, which has a detailed description outlining the functionality.
JIRA tickets &lt;a href="https://tickets.puppetlabs.com/browse/IAC-801">IAC-801&lt;/a> and &lt;a href="https://tickets.puppetlabs.com/browse/IAC-824">IAC-824&lt;/a> outline the design and implementation, respectively, should you wish to take a look.&lt;/p></description></item><item><title>Blog: Debugging unit-tests with Honeycomb</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-30-debugging-unit-tests-with-honeycomb/</link><pubDate>Mon, 30 Mar 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-30-debugging-unit-tests-with-honeycomb/</guid><description>
&lt;p>Since &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-teamblog/updates/2020-03-27-status-update.md#litmus-progress">last week&lt;/a> we&amp;rsquo;re collecting unit-test results and acceptance test runs in &lt;a href="https://honeycomb.io/">honeycomb&lt;/a>, a tool for introspecting and interrogating production systems. In our team&amp;rsquo;s case, CI is the &amp;ldquo;production&amp;rdquo; environment we manage. Today Daniel pointed out that there was a curious issue with one of our test suites:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#f1fa8c">NoMethodError&lt;/span>:
undefined &lt;span style="color:#8be9fd;font-style:italic">method&lt;/span> &lt;span style="color:#f1fa8c">`message_lines&amp;#39; for #&amp;lt;RSpec::Core::Notifications::SkippedExampleNotification:0x00007f8407ac3018&amp;gt;
&lt;/span>&lt;span style="color:#f1fa8c"># /Users/danielcarabas/.rvm/gems/ruby-2.6.3/gems/rspec_honeycomb_formatter-0.2.0/lib/rspec_honeycomb_formatter.rb:95:in `&lt;/span>example_pending&amp;#39;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>That clearly rings a bell, but a trivial try at reproducing this using &lt;code>pending&lt;/code> brought up a weird issue:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#f1fa8c">From&lt;/span>: &lt;span style="color:#f1fa8c">/home/&lt;/span>david&lt;span style="color:#ff79c6">/&lt;/span>git&lt;span style="color:#ff79c6">/&lt;/span>rspec_honeycomb_formatter&lt;span style="color:#ff79c6">/&lt;/span>lib&lt;span style="color:#ff79c6">/&lt;/span>rspec_honeycomb_formatter&lt;span style="color:#ff79c6">.&lt;/span>rb @ line &lt;span style="color:#bd93f9">99&lt;/span> RSpecHoneycombFormatter&lt;span style="color:#6272a4">#example_pending:&lt;/span>
&lt;span style="color:#bd93f9">95&lt;/span>: &lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">example_pending&lt;/span>(notification)
&lt;span style="color:#bd93f9">96&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;rspec.result&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;pending&amp;#39;&lt;/span>)
&lt;span style="color:#bd93f9">97&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;name&amp;#39;&lt;/span>, notification&lt;span style="color:#ff79c6">.&lt;/span>example&lt;span style="color:#ff79c6">.&lt;/span>description)
&lt;span style="color:#bd93f9">98&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;rspec.description&amp;#39;&lt;/span>, notification&lt;span style="color:#ff79c6">.&lt;/span>example&lt;span style="color:#ff79c6">.&lt;/span>description)
&lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#bd93f9">99&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">require&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;pry&amp;#39;&lt;/span>;&lt;span style="color:#8be9fd;font-style:italic">binding&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>pry
&lt;span style="color:#bd93f9">100&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;rspec.message&amp;#39;&lt;/span>, strip_ansi(notification&lt;span style="color:#ff79c6">.&lt;/span>message_lines&lt;span style="color:#ff79c6">.&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>&lt;span style="color:#f1fa8c">\n&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>)))
&lt;span style="color:#bd93f9">101&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>add_field(&lt;span style="color:#f1fa8c">&amp;#39;rspec.backtrace&amp;#39;&lt;/span>, notification&lt;span style="color:#ff79c6">.&lt;/span>formatted_backtrace&lt;span style="color:#ff79c6">.&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>&lt;span style="color:#f1fa8c">\n&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>))
&lt;span style="color:#bd93f9">102&lt;/span>: &lt;span style="color:#8be9fd;font-style:italic">@example_span&lt;/span>&lt;span style="color:#ff79c6">.&lt;/span>send
&lt;span style="color:#bd93f9">103&lt;/span>: &lt;span style="color:#ff79c6">end&lt;/span>
&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#bd93f9">1&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span> pry(&lt;span style="color:#6272a4">#&amp;lt;RSpecHoneycombFormatter&amp;gt;)&amp;gt; notification.class&lt;/span>
&lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> RSpec&lt;span style="color:#ff79c6">::&lt;/span>Core&lt;span style="color:#ff79c6">::&lt;/span>Notifications&lt;span style="color:#ff79c6">::&lt;/span>PendingExampleFailedAsExpectedNotification
&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#bd93f9">2&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span> pry(&lt;span style="color:#6272a4">#&amp;lt;RSpecHoneycombFormatter&amp;gt;)&amp;gt;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The class here is not the same as the initial report is complaining about.
And this does not fail.
&lt;code>PendingExampleFailedAsExpectedNotification&lt;/code> does have &lt;code>message_lines&lt;/code>.
Since the original report didn&amp;rsquo;t have any more information attached (and for the sake of the pacing of this blog post) I went to honeycomb to see if other modules were exhibiting the same problem.
After a couple of clicks this was what I had:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-03-30-debugging-with-honeycomb/honeycomb-heatmap.png" alt="honeycomb heatmap screenshot">&lt;/p>
&lt;p>The query selects by the error message and returns all examples with that error message.
Clearly this has been going on for a while.
Clicking through to the raw data I could jump to the full log of one of the runs:&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-03-30-debugging-with-honeycomb/honeycomb-raw-data.png" alt="honeycomb raw data screenshot">&lt;/p>
&lt;p>Which brings us to &lt;a href="https://github.com/puppetlabs/puppetlabs-package/runs/544125013#step:3:445">this failure on github actions&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">================&lt;/span>
unlikely&lt;span style="color:#ff79c6">-&lt;/span>toxin&lt;span style="color:#ff79c6">.&lt;/span>delivery&lt;span style="color:#ff79c6">.&lt;/span>puppetlabs&lt;span style="color:#ff79c6">.&lt;/span>net, win&lt;span style="color:#ff79c6">-&lt;/span>&lt;span style="color:#bd93f9">2008&lt;/span>r2&lt;span style="color:#ff79c6">-&lt;/span>x86_64
&lt;span style="color:#ff79c6">**&lt;/span>F&lt;span style="color:#ff79c6">****&lt;/span>FFFFFF
&lt;span style="color:#f1fa8c">Pending&lt;/span>: (Failures listed here are expected &lt;span style="color:#ff79c6">and&lt;/span> &lt;span style="color:#ff79c6">do&lt;/span> &lt;span style="color:#ff79c6">not&lt;/span> affect your suite&lt;span style="color:#f1fa8c">&amp;#39;s status)
&lt;/span>&lt;span style="color:#f1fa8c">
&lt;/span>&lt;span style="color:#f1fa8c"> 1) package task install installs pry
&lt;/span>&lt;span style="color:#f1fa8c"> # Don&amp;#39;&lt;/span>t run on Windows
On host &lt;span style="color:#f1fa8c">`unlikely-toxin.delivery.puppetlabs.net&amp;#39;
&lt;/span>&lt;span style="color:#f1fa8c"> Failure/Error: @example_span.add_field(&amp;#39;rspec.message&amp;#39;, strip_ansi(notification.message_lines.join(&amp;#34;&lt;/span>&lt;span style="color:#f1fa8c">\n&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;)))
&lt;/span>&lt;span style="color:#f1fa8c"> NoMethodError:
&lt;/span>&lt;span style="color:#f1fa8c"> undefined method `&lt;/span>message_lines&amp;#39; &lt;span style="color:#ff79c6">for&lt;/span> &lt;span style="color:#6272a4">#&amp;lt;RSpec::Core::Notifications::SkippedExampleNotification:0x00007fe474773368&amp;gt;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This in turn I can look up in &lt;a href="https://github.com/puppetlabs/puppetlabs-package/blob/b7ff8d9a3982287f30a20111f86413b0350d20d6/spec/acceptance/init_spec.rb">the source code&lt;/a>.
I&amp;rsquo;m assuming the following clause is the issue:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">before(&lt;span style="color:#f1fa8c">:each&lt;/span>) &lt;span style="color:#ff79c6">do&lt;/span>
skip &lt;span style="color:#f1fa8c">&amp;#34;Don&amp;#39;t run on Windows&amp;#34;&lt;/span> &lt;span style="color:#ff79c6">if&lt;/span> operating_system_fact &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;windows&amp;#39;&lt;/span>
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Putting that into the manual test case quickly confirmed that this was indeed the problem.
After being able to reproduce this locally, it was a matter of poking pry to figure out what needs to be done about it.
The &lt;code>SkippedExampleNotification&lt;/code> doesn&amp;rsquo;t have a &lt;code>message_lines&lt;/code> method, and needs to be handled differently.
The result has been posted in the &lt;a href="https://github.com/puppetlabs/rspec_honeycomb_formatter/pull/10">&amp;ldquo;Fix missing message_lines method&amp;rdquo; PR&lt;/a> and should be merged and released by the time you read this post.&lt;/p>
&lt;p>Finally, to cross-check that this is the only problem we&amp;rsquo;ve been seeing, I&amp;rsquo;ve added a &lt;code>rspec.message does-not-contain SkippedExampleNotification&lt;/code> clause to the honeycomb query.
That new query did not return any results, increasing my confidence in having addressed all currently visible issues with the formatter.&lt;/p></description></item><item><title>Blog: DSC + Puppet: Incoming!</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-30-dsc-announcement/</link><pubDate>Mon, 30 Mar 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-30-dsc-announcement/</guid><description>
&lt;p>As &lt;a href="https://github.com/glennsarti">Glenn&lt;/a> and I alluded to on the &lt;a href="https://player.fm/series/powerscripting-podcast/episode-334-powerscripting-podcast-glenn-sarti-michael-lombardi">PowerScripting Podcast&lt;/a>, our team has been hard at work re-envisioning how we want to present the DSC + Puppet story for our users.&lt;/p>
&lt;p>&lt;a href="https://tickets.puppetlabs.com/browse/IAC-41">Long story short&lt;/a>, for lots of reasons, our &lt;a href="https://forge.puppet.com/puppetlabs/dsc">original implementation&lt;/a> for calling DSC resources from inside Puppet (shoutout to &lt;a href="https://github.com/msutter">Marc Sutter&lt;/a>, the initial implementer!) was getting fragile, stale, and maintenance costs kept rising.&lt;/p>
&lt;p>As a stop gap, we put together the &lt;a href="https://forge.puppet.com/puppetlabs/dsc_lite">dsc_lite&lt;/a> module for people to use which dropped the guardrails and help in exchange for letting you just get to work if you needed to use it.
Essentially the thinnest of wrappers over &lt;a href="https://docs.microsoft.com/en-us/powershell/module/psdesiredstateconfiguration/invoke-dscresource?view=powershell-7">&lt;code>Invoke-DscResource&lt;/code>&lt;/a>, requiring you to get those resources onto the target and to pass an arbitrary hash of &lt;em>hopefully&lt;/em> correct properties to the DSC resource;
no way to tell if you goofed til run time.&lt;/p>
&lt;p>We made &lt;a href="https://forge.puppet.com/puppetlabs/dsc_lite">dsc_lite&lt;/a> for the DSC expert, &lt;a href="https://github.com/puppetlabs/puppetlabs-dsc_lite/blob/master/README_Tradeoffs.md">basically&lt;/a>.
But as time went on and we could no longer use our old builder to update our original module&amp;hellip;
we were leaving a &lt;strong>lot&lt;/strong> of people in the cold with a less than stellar UX.&lt;/p>
&lt;p>So my team decided to change that story.&lt;/p>
&lt;p>We talked it out, &lt;a href="https://tickets.puppetlabs.com/browse/IAC-41">planned some stuff&lt;/a> and adopted &lt;a href="https://github.com/jpogran">James Pogran&lt;/a>&amp;rsquo;s INCREDIBLE &lt;a href="https://github.com/jpogran/PuppetDscBuilder">prototype work&lt;/a>—he did 80% of the initial work for this, basically all the hardest bits. 💜&lt;/p>
&lt;h2 id="so-about-this-builder">So, About This Builder&lt;/h2>
&lt;p>The &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder">whole thing&lt;/a> is written in and relies on PowerShell, not Ruby.
The only non-PowerShell dependency is the &lt;a href="https://puppet.com/docs/pdk/1.x/pdk.html">Puppet Development Kit&lt;/a> for scaffolding the Puppet module out (no reason to re-implement that!)&lt;/p>
&lt;p>It builds on two important technologies:&lt;/p>
&lt;ol>
&lt;li>The &lt;a href="https://puppet.com/docs/puppet/latest/about_the_resource_api.html">resource_api&lt;/a> (largely developed by &lt;a href="https://github.com/DavidS">David Schmitt&lt;/a>), makes writing Puppet types and providers &lt;em>actually&lt;/em> doable for people like me—the type file is just data, the provider adheres to a simple schema.&lt;/li>
&lt;li>The &lt;a href="https://github.com/puppetlabs/ruby-pwsh/">ruby-pwsh&lt;/a> gem, based on work by numerous members of the former Windows team at Puppet:
&lt;a href="https://github.com/glennsarti">Glenn Sarti&lt;/a>, &lt;a href="https://github.com/jpogran">James Pogran&lt;/a>, &lt;a href="https://github.com/Iristyle">Ethan Brown&lt;/a>, &lt;a href="https://github.com/RandomNoun7">Bill Hurt&lt;/a>, &lt;a href="https://github.com/ThoughtCrhyme">Erick Banks&lt;/a>, &lt;a href="https://github.com/ferventcoder">Rob Reynolds&lt;/a>, and me.
This gem is a library that gives you a &lt;a href="https://github.com/puppetlabs/ruby-pwsh/blob/master/DESIGN.md">PowerShell manager&lt;/a>, enabling you to interop between PowerShell &amp;amp; Ruby.
That lets us take advantage of having a PowerShell host process and not shell out for every command.
It&amp;rsquo;s &lt;em>much&lt;/em> faster and paves the way for some really cool improvements.
It&amp;rsquo;s also what powers all of our Puppet modules which rely heavily on PowerShell calls!&lt;/li>
&lt;/ol>
&lt;p>This builder scaffolds a new Puppet module, vendors a PowerShell module from the Gallery (&lt;em>with&lt;/em> dependencies), introspects that module for DSC resources, then generates a Puppet resource_api type and provider for each DSC resource.&lt;/p>
&lt;p>It has a &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder/blob/c5d349f51883abcca926a0dc6be465a037dfe957/Get-DscResourceTypeInformation.ps1">helper function&lt;/a> which desperately needs refactoring but which parses the &lt;a href="https://mikefrobbins.com/2018/09/28/learning-about-the-powershell-abstract-syntax-tree-ast/">AST&lt;/a> for the DSC resource&amp;rsquo;s source file (if it can) to retrieve the reference docs, default values, and whether the parameter is mandatory for get/set operations.
If it &lt;em>can&amp;rsquo;t&lt;/em> parse the AST (as with binary/class-based DSC resources in this iteration) it still works&amp;ndash;
it just won&amp;rsquo;t have the reference docs and will rely on the best info it can find in the output from &lt;a href="https://docs.microsoft.com/en-us/powershell/module/psdesiredstateconfiguration/get-dscresource?view=powershell-7">&lt;code>Get-DscResource&lt;/code>&lt;/a>.&lt;/p>
&lt;p>Okay, &lt;em>fine&lt;/em>, &lt;em>&lt;strong>weeeee&lt;/strong>&lt;/em>, it &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder/files/4395886/michaeltlombardi-powershellget-0.1.0.tar.gz">builds a module&lt;/a>, great.
But what does using it look like?
I&amp;rsquo;m glad you asked.
First of all, here&amp;rsquo;s what a very basic manifest using a &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder/files/4395886/michaeltlombardi-powershellget-0.1.0.tar.gz">puppetized module&lt;/a> looks like&amp;ndash;in this case, &lt;a href="https://www.powershellgallery.com/packages/PowerShellGet/2.2.3">PowerShellGet&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">dsc_psrepository&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;Add team shared module folder as a repository&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;foo&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">present&lt;/span>,&lt;span style="color:#6272a4">
&lt;/span>&lt;span style="color:#6272a4"> # This location is nonsense, can be any valid folder on your
&lt;/span>&lt;span style="color:#6272a4"> # machine or in a share, any location the SourceLocation param
&lt;/span>&lt;span style="color:#6272a4"> # for the DSC resource will accept.&lt;/span>
&lt;span style="color:#50fa7b">dsc_sourcelocation&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;C:\Program Files&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_installationpolicy&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#50fa7b">untrusted&lt;/span>,
}
&lt;span style="color:#50fa7b">dsc_psrepository&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;Trust the PowerShell Gallery&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;PSGallery&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">present&lt;/span>,
&lt;span style="color:#50fa7b">dsc_installationpolicy&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#50fa7b">trusted&lt;/span>,
}
&lt;span style="color:#50fa7b">dsc_psmodule&lt;/span> {&lt;span style="color:#f1fa8c">&amp;#39;Ensure Ruby is Manageable via uru&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">dsc_name&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;RubyInstaller&amp;#39;&lt;/span>,
&lt;span style="color:#50fa7b">dsc_ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">absent&lt;/span>,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>And, well? It works! It&amp;rsquo;s idempotent! And, much more interestingly from my perspective, it gives you property-by-property reporting for your DSC resources&amp;ndash;it knows what the state of the resource is on your node before it calls the Set method for Invoke-DscResource&amp;hellip;&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-03-30-dsc-announcement/property-rep.png" alt="Puppet run output reading &amp;ldquo;dsc_sourcelocation changed &amp;lsquo;C:\code\temp&amp;rsquo; to &amp;lsquo;C:\Program Files&amp;rsquo;"">&lt;/p>
&lt;p>So it can actually tell you &lt;em>what changed&lt;/em> during the run and when.
In other words, DSC resources in this implementation now report &lt;strong>just&lt;/strong> like any other Puppet resource.&lt;/p>
&lt;p>That&amp;rsquo;s pretty neat!!&lt;/p>
&lt;p>What else do you get?
Intellisense and some other awesome magic!
Thanks to the &lt;a href="https://puppet-vscode.github.io/">VSCode extension&lt;/a> maintained by &lt;a href="https://github.com/jpogran">James Pogran&lt;/a> and &lt;a href="https://github.com/glennsarti">Glenn Sarti&lt;/a>—in this screenshot, the editor is aware of all the parameters you might select, what their type is, and the valid values!&lt;/p>
&lt;p>![Image displaying intellisense capabilities of the VSCode extension where it is predicting which parameters to use and displaying their help information inline in the editor.](/content-and-tooling-team/assets/2020-03-30-dsc-announcement/intellisense.jfif %})&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Aside:&lt;/strong>
You &lt;em>are&lt;/em> writing your Puppet code in VSCode with the &lt;a href="https://puppet-vscode.github.io/">Puppet extension&lt;/a> installed, aren&amp;rsquo;t you?
You&amp;rsquo;re taking advantage of the &lt;a href="https://puppet-vscode.github.io/docs/features/intellisense">intellisense&lt;/a>, &lt;a href="https://puppet-vscode.github.io/docs/features/code-navigation">code navigation&lt;/a>, &lt;a href="https://puppet-vscode.github.io/docs/features/linting">auto linting&lt;/a>, &lt;a href="https://puppet-vscode.github.io/docs/features/debugging-puppet-code">debugging&lt;/a>, and the &lt;a href="https://puppet-vscode.github.io/docs/features/puppet-development-kit">PDK&lt;/a>, &lt;a href="https://puppet-vscode.github.io/docs/features/puppet-bolt">Bolt&lt;/a>, &amp;amp; &lt;a href="https://puppet-vscode.github.io/docs/features/control-repository">Control Repo&lt;/a> integrations&amp;hellip; right??&lt;/p>
&lt;/blockquote>
&lt;h2 id="so-it-works-what-next">So It Works. What Next?&lt;/h2>
&lt;p>We still have some testing and a host of improvements to make (including probably swapping our template engine out, shout out to &lt;a href="https://github.com/FriedrichWeinmann">Fred Weinmann&lt;/a> for the &lt;a href="https://psframework.org/documentation/documents/psmoduledevelopment/templates.html">templating engine&lt;/a> in the &lt;a href="https://github.com/PowershellFrameworkCollective/PSModuleDevelopment">PSModuleDevelopment&lt;/a> module), but the next big step—and likely the last I&amp;rsquo;ll be involved with before my paternity leave hits—is &lt;a href="https://tickets.puppetlabs.com/browse/IAC-648">turning this build script into a PowerShell module and adding testing to it&lt;/a>.
It &lt;em>works&lt;/em> as a build script, but it can definitely be improved.
And, okay, a module on the Gallery is great and all&amp;hellip;&lt;/p>
&lt;p>But the &lt;strong>really cool&lt;/strong> end-user magic will arrive in the &lt;a href="https://tickets.puppetlabs.com/browse/IAC-649">third phase&lt;/a>, where we hope to be able to automatically build and publish Puppet modules that 1:1 wrap PowerShell modules with DSC resources and expose them as Puppet types and providers!&lt;/p>
&lt;p>We&amp;rsquo;re envisioning a future where not only can you Puppetize any DSC-Resource-having-module you want for yourself, but you can just find all of the modules publicly available on the Gallery already wrapped up and ready for you on the Puppet Forge!&lt;/p>
&lt;h2 id="caveats-and-warnings">Caveats and Warnings&lt;/h2>
&lt;p>We&amp;rsquo;re &lt;em>just&lt;/em> wrapping the underlying DSC resources and making them available to you.
If there&amp;rsquo;s a problem &lt;em>calling&lt;/em> the DSC resources from Puppet, we&amp;rsquo;ll work on it, but if there&amp;rsquo;s a problem with &lt;em>how&lt;/em> those resources behave, that&amp;rsquo;s upstream.&lt;/p>
&lt;p>Our team is full of lovely humans who do incredible amounts of work (seven people for &lt;a href="https://puppetlabs.github.io/community_management/">&amp;gt;250 PRs/month, ~50 supported modules&lt;/a>, &lt;a href="https://puppetlabs.github.io/iac/tools/">over a dozen open source tools&lt;/a>, contributing to dozens more) but we can&amp;rsquo;t adopt &amp;gt; 300 DSC modules too. 💔&lt;/p>
&lt;p>We&amp;rsquo;ll also continue to improve the underlying provider and build system, of course, and are excited to get the output modules fully functional for PowerShell 7+ - meaning they&amp;rsquo;ll be cross-platform compatible if the underlying resources are!
This first prototype is just 5.1 though.&lt;/p>
&lt;h2 id="wrapping-up-call-to-action">Wrapping Up, Call to Action&lt;/h2>
&lt;p>So! If you&amp;rsquo;re interested in the work so far, you can &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder">check it out on GitHub&lt;/a>&amp;ndash;
the &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder/pull/1">latest PR&lt;/a> includes functional instructions for testing the new builder or just &lt;a href="https://github.com/puppetlabs/PuppetDscBuilder/files/4395886/michaeltlombardi-powershellget-0.1.0.tar.gz">grabbing the test module&lt;/a> and playing with it in your own lab!&lt;/p>
&lt;p>We wanna tighten the loop and ensure we&amp;rsquo;re solving your problems with this rework because the &lt;em>whole point&lt;/em> is to make your lives easier if you&amp;rsquo;re using Puppet and DSC.
We&amp;rsquo;re here to help you get your configuration under control and free you up to do all the other hard work you have on your backlog.&lt;/p>
&lt;p>With that in mind, we would love your feedback, so if this tickles your interest at all, please &lt;a href="mailto:dsc@puppet.com">email us&lt;/a> (&lt;a href="mailto:dsc@puppet.com">dsc@puppet.com&lt;/a>) or comment below and let us know:&lt;/p>
&lt;ol>
&lt;li>What are the top three PowerShell modules with DSC resources you&amp;rsquo;d like to see Puppetized?&lt;/li>
&lt;li>Are you interested in joining our beta test group for this ongoing project?&lt;/li>
&lt;/ol>
&lt;p>If you just wanna keep an eye on things, you can follow the repository on GitHub and the &lt;a href="https://tickets.puppetlabs.com/browse/IAC-41">parent epic in JIRA&lt;/a>!&lt;/p>
&lt;p>Thanks, folx!&lt;/p></description></item><item><title>Blog: How to use agent-side information on the puppetserver</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-18-how-to-use-agent-information-on-puppetserver/</link><pubDate>Wed, 18 Mar 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-03-18-how-to-use-agent-information-on-puppetserver/</guid><description>
&lt;p>This question was posted on the &lt;a href="https://slack.puppet.com/">Puppet Community Slack&lt;/a> yesterday:&lt;/p>
&lt;blockquote>
&lt;p>Is there any way like the below in puppet code we can use:&lt;/p>
&lt;pre>&lt;code>$var=‘run command locally on agent, if $?=0 echo “present”, else echo “absent”’
if $var == present {
# my code
} else {
# something else
}
&lt;/code>&lt;/pre>&lt;/blockquote>
&lt;p>(by user &lt;a href="https://app.slack.com/team/URGFPBS0N">IlovPuppet&lt;/a>, edited for presentation)&lt;/p>
&lt;p>There are a number of reasons why this question comes up.
First is likely that folks are not aware of the options available at all.
Then, sometimes, the common options (like custom facts) just don&amp;rsquo;t cut it for security or performance reasons.
Last but not least, organisational and technical circumstances can make one option more appealing than others.&lt;/p>
&lt;p>From my answer there, I wrote up a more detailed exposition here.
Based on the specifics of your situation,
there are several different options to solve this,
described in detail below:&lt;/p>
&lt;ul>
&lt;li>make the decision explicit&lt;/li>
&lt;li>a &lt;code>Deferred&lt;/code> function call&lt;/li>
&lt;li>using &lt;code>onlyif&lt;/code> or &lt;code>unless&lt;/code> on an &lt;code>exec&lt;/code> resource&lt;/li>
&lt;li>a custom fact&lt;/li>
&lt;li>a custom resource&lt;/li>
&lt;/ul>
&lt;h2 id="explicit-decisions">Explicit Decisions&lt;/h2>
&lt;p>&lt;strong>What is it?&lt;/strong>&lt;/p>
&lt;p>Puppet shines when we can make our configuration decisions explicit.
Make the dynamic decision a static configuration and ensure that whatever is producing the different states is also managed by puppet.
Having a hard look at what the command is trying to decide and whether this couldn&amp;rsquo;t be enforced instead of queried can save complexity.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>&lt;/p>
&lt;p>A simple example from my past as a technical consultant is a client who wanted to base a configuration decision off whether or not a particular package was installed on a workstation. In this particular case it turned out that installing that additional package was not very expensive (compared to coding up a dynamic solution), so we just rolled out the package to everyone and removed another thing that was different across the fleet.&lt;/p>
&lt;p>&lt;strong>Use it &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>if you can take control of the source of your question.&lt;/li>
&lt;li>if you can key off another configuration instead of querying active system state.&lt;/li>
&lt;li>if you can make your general configuration easier by removing a source of variation.&lt;/li>
&lt;li>if the query code is difficult and/or unreliable.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Don&amp;rsquo;t use it if &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>the input is truly dynamic.&lt;/li>
&lt;li>the configuration is outside of your organisational scope (but try talking to the other team first!).&lt;/li>
&lt;li>the computed value is sensitive and should not be transmitted or stored outside the node.&lt;/li>
&lt;/ul>
&lt;h2 id="deferred">&lt;code>Deferred&lt;/code>&lt;/h2>
&lt;p>&lt;strong>What is it?&lt;/strong>&lt;/p>
&lt;p>The &lt;code>Deferred&lt;/code> function computes a value on the agent everytime the catalog is executed and uses the value immediately in the catalog.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>&lt;/p>
&lt;p>The &lt;a href="https://forge.puppet.com/puppet/vault_lookup">puppet/vault_lookup&lt;/a> module shows how to use &lt;code>Deferred&lt;/code> with its &lt;code>vault_lookup::lookup&lt;/code> function:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#8be9fd;font-style:italic">$d&lt;/span> &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#50fa7b">Deferred&lt;/span>(&lt;span style="color:#f1fa8c">&amp;#39;vault_lookup::lookup&amp;#39;&lt;/span>, [&lt;span style="color:#f1fa8c">&amp;#34;secret/test&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;https://vault.hostname:8200&amp;#39;&lt;/span>])
&lt;span style="color:#ff79c6">node&lt;/span> &lt;span style="color:#ff79c6">default&lt;/span> {
&lt;span style="color:#ff79c6">notify&lt;/span> { &lt;span style="color:#50fa7b">example&lt;/span> :
&lt;span style="color:#50fa7b">message&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$d&lt;/span>
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>(from &lt;a href="https://github.com/voxpupuli/puppet-vault_lookup#usage">voxpupuli/puppet-vault_lookup&lt;/a>)&lt;/p>
&lt;p>&lt;strong>Use it &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>for values specific to one or a few agents, for which managing via Hiera would be cumbersome.&lt;/li>
&lt;li>for sensitive values that should not be exposed outside the individual agent.&lt;/li>
&lt;li>for setting properties on resources.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Don&amp;rsquo;t use it if &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>you need to change &lt;strong>which&lt;/strong> resources are managed.&lt;/li>
&lt;li>you need the value in PE Console for classification or reporting.&lt;/li>
&lt;li>the computed value depends on resources managed earlier in the catalog.&lt;/li>
&lt;li>a simpler solution (see above) works.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Further Reading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://puppet.com/docs/puppet/latest/write_a_puppet_function_to_store_secrets.html">Write a Puppet function to store secrets&lt;/a>: the original use-case for &lt;code>Deferred&lt;/code>&lt;/li>
&lt;li>&lt;a href="http://puppet-on-the-edge.blogspot.com/2018/10/the-topic-is-deferred.html">The Topic is Deferred&lt;/a>: blogpost with hints and tricks how to use &lt;code>Deferred&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://binford2k.com/2019/11/12/deferred-functions/">Agent Side Functions in Puppet 6&lt;/a>: technical deep-dive on how &lt;code>Deferred&lt;/code> works&lt;/li>
&lt;li>&lt;a href="https://www.hashicorp.com/resources/agent-side-lookups-with-hashicorp-vault-puppet-6">HashiCorp Vault 🧡 Puppet6 webinar&lt;/a>: deferred functions in Puppet 6, which unlocks new authentication methods and workflows for HashiCorp Vault + Puppet setups.&lt;/li>
&lt;/ul>
&lt;h2 id="exec-resources">&lt;code>exec&lt;/code> resources&lt;/h2>
&lt;p>&lt;strong>What is it?&lt;/strong>&lt;/p>
&lt;p>The &lt;code>exec&lt;/code> resource has attributes to dynamically decide to run the managed command or not.
By passing a command to &lt;code>onlyif&lt;/code> or &lt;code>unless&lt;/code> the command is executed &lt;em>only if&lt;/em> or &lt;em>unless&lt;/em> the condition successfully executes.
Use &lt;code>refreshonly&lt;/code> to react to another resource being changed.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>&lt;/p>
&lt;p>The &lt;a href="https://forge.puppet.com/puppetlabs/mysql">mysql module&lt;/a> has this &lt;code>exec&lt;/code> resource to clean up after installation. This should never run after &lt;code>${secret_file}&lt;/code> has been dealt with.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#ff79c6">exec&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;remove install pass&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">command&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$rm_pass_cmd,&lt;/span>
&lt;span style="color:#50fa7b">onlyif&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;test -f ${secret_file}&amp;#34;&lt;/span>,
&lt;span style="color:#50fa7b">path&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin&amp;#39;&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>(from &lt;a href="https://github.com/puppetlabs/puppetlabs-mysql/blob/312aca80ba7699ab37f9051d871aac2e05b217b3/manifests/server/root_password.pp#L20-L24">root_password.pp&lt;/a>)&lt;/p>
&lt;p>&lt;strong>Use it for &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>running one-off commands on a condition.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Don&amp;rsquo;t use it if &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>an exec is not a good fit for your problem.&lt;/li>
&lt;li>the condition is very complex or timeconsuming.&lt;/li>
&lt;li>the condition has to be repeated often.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Further Reading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://puppet.com/docs/puppet/latest/types/exec.html">Resource Type: &lt;code>exec&lt;/code>&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="custom-facts">Custom Facts&lt;/h2>
&lt;p>&lt;strong>What is it?&lt;/strong>&lt;/p>
&lt;p>Custom facts are distributed to Puppet clients and are available for use in manifests and templates,
just like any other fact is.
They can be used to write conditional expressions based on site-specific data that isn’t available via Facter.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>&lt;/p>
&lt;p>The apt module has a few &lt;a href="https://github.com/puppetlabs/puppetlabs-apt#facts">custom facts&lt;/a>. The &lt;code>apt_update_last_success&lt;/code> fact is used in &lt;a href="https://github.com/puppetlabs/puppetlabs-apt/blob/master/manifests/update.pp">update.pp&lt;/a> to decide whether or not it is necessary to update apt caches depending on the various configurations specified.&lt;/p>
&lt;p>&lt;strong>Use it &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>when you need to centrally collect and evaluate the values.&lt;/li>
&lt;li>when you want to get the value from all your nodes.&lt;/li>
&lt;li>to change the set of resources and classes included for each node.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Don&amp;rsquo;t use it if &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>the computed value is sensitive and should not be transmitted or stored outside the node.&lt;/li>
&lt;li>a simpler solution (see above) works.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Further Reading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://puppet.com/docs/puppet/latest/fact_overview.html">Custom facts&lt;/a>: the current puppet documentation&lt;/li>
&lt;li>&lt;a href="https://puppet.com/docs/puppet/latest/custom_facts.html">Custom facts walkthrough&lt;/a>: how to write your own facts&lt;/li>
&lt;li>&lt;a href="https://glennsarti.github.io/blog/puppet-ruby-facts/">Starting out with Puppet custom facts&lt;/a>: a quick start to converting external facts to ruby custom facts on Windows&lt;/li>
&lt;/ul>
&lt;h2 id="custom-resources">Custom Resources&lt;/h2>
&lt;p>&lt;strong>What is it?&lt;/strong>&lt;/p>
&lt;p>With a native ruby plugin you can fully take control of how puppet manages a resource. Through this you get fine-grained control over reporting and enforcing system state through puppet.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>&lt;/p>
&lt;p>The &lt;a href="https://forge.puppet.com/puppetlabs/mysql">mysql module&lt;/a> contains custom types and providers to control databases, users and grants.&lt;/p>
&lt;blockquote>
&lt;p>Note that the mysql module is still using the low-level API. Using the PDK and the Resource API, programming types and providers has become a lot easier as of late. Check out the &amp;ldquo;Further Reading&amp;rdquo; section below.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Use it for &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>things that can be modeled as a puppet resource.&lt;/li>
&lt;li>fine-grained control.&lt;/li>
&lt;li>full integration into the puppet tooling.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Don&amp;rsquo;t use it if &amp;hellip;&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>you do not want to code ruby.&lt;/li>
&lt;li>a simpler solution (see above) works.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Further Reading&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://puppet.com/docs/puppet/latest/custom_resources.html">Custom Resources&lt;/a>: main documentation on writing custom resources.&lt;/li>
&lt;li>&lt;a href="https://github.com/puppetlabs/puppet-resource_api/tree/master/docs">HUE hands on lab&lt;/a>: hands-on lab for a custom remote resource interacting with a API.&lt;/li>
&lt;/ul>
&lt;h2 id="final-words">Final Words&lt;/h2>
&lt;p>To summarize, Puppet provides you with a number of alternatives to make your configuration smarter.
Thanks to IluvPuppet for the great question, and &lt;a href="https://github.com/hpcprofessional">Paul Anderson&lt;/a> and Paul Reed for reviewing and feedback.&lt;/p></description></item><item><title>Blog: Setting up basic infrastructure for your gem</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-19-infrastructure-for-the-gem/</link><pubDate>Wed, 19 Feb 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-19-infrastructure-for-the-gem/</guid><description>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>Here we will be going through the steps and best practices for setting up basic infrastructure for your gem.
The steps given can be followed by anyone to setup the basic infrastructure for gem development which does the following.&lt;/p>
&lt;ul>
&lt;li>creates the basic file structure for the gem.&lt;/li>
&lt;li>adds the rubocop which validates the guidelines outlined in the community Ruby Style Guide.&lt;/li>
&lt;li>adds the travis or appveyor testing to the repo which validates the changes to the repo.&lt;/li>
&lt;li>adds the dependendabot to the repo which creates pull requests to keep dependencies up to date.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;h4 id="note">Note:&lt;/h4>
&lt;p>This walkthrough assumes you have the following software installed:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.ruby-lang.org/en/downloads/">Ruby&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>It also assumes familiarity with the &lt;a href="https://rubygems.org/">Ruby gems&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="infrastructure-for-your-gem">Infrastructure for your gem&lt;/h2>
&lt;p>We&amp;rsquo;re going through the steps and best practices for setting up basic infrastructure for your gem.&lt;/p>
&lt;p>For any repo created for developing a Gem we add owner, access and license to the repo.
Follow the steps below to add them.&lt;/p>
&lt;ol>
&lt;li>Open a &lt;a href="https://github.com">git hub&lt;/a> page, perform the rest of these actions from there.
&lt;ol>
&lt;li>
&lt;p>Click on + to create a new repo.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/newrepo.png" alt="+">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Provider the owner information, repo name and license.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/owner.png" alt="owner information and repo name">
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/owner.png" alt="Example image">
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/license.png" alt="license">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Click on Create repository button.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Open the new repo created and navigate to settings tab to update the access.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Provide your team as admin on github. (This example shows Puppet&amp;rsquo;s modules team)
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/githubowner.png" alt="admin">&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;p>Follow the steps below for creating the gem structure, add the rubocop validation, add the travis or appveyor testing to the repo.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Open the command line and perform the rest of these actions from there.&lt;/p>
&lt;ol>
&lt;li>Clone the new repo created. Add the upstream project and checkout the branch.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">git clone https://github.com/sheenaajay/puppet-modulebuilder.git
git remote add puppetlabs https://github.com/puppetlabs/puppet-modulebuilder.git
git checkout -b blogpost
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>Create a ruby gem with bundler and perform the commit.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">bundle gem puppet-modulebuilder
git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Initial commit of puppet-modulebuilder gem scaffolding&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>See [Clarifying the Roles of the .gemspec and Gemfile](https://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/) on whether you want to commit the `Gemfile.lock` or not.
&lt;/code>&lt;/pre>
&lt;ol start="3">
&lt;li>Remove unused default gem development scripts if any and perform the commit.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">rm -r bin/console
rm -r bin/setup
git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Remove unused default gem development scripts&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>Update gemspec with actual values for spec.authors, spec.email, spec.summary, spec.description, spec.homepage, spec.metadata.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/gemspec.png" alt="gemspec">&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Update gemspec with actual values&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">
&lt;li>Copy puppet-style rubocop rules(Example from &lt;a href="https://github.com/puppetlabs/pdk/blob/master/.rubocop.yml">pdk repo&lt;/a>), activate and apply default fixes.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">bundle install --path .bundle/gems/
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rubocop
git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Include, activate rubocop, apply default fixes&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="6">
&lt;li>Add instruction files for travis-ci and appveyor. Sample &lt;a href="https://github.com/puppetlabs/puppet-modulebuilder/pull/1">PR&lt;/a> contains travis.yml and appveyor.yml.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Add instruction files for travis-ci and appveyor&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="7">
&lt;li>Add modules team to CODEOWNERS.
Create the CODEOWNERS file in .github/CODEOWNERS&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">git add -A
git commit -m &lt;span style="color:#f1fa8c">&amp;#34;Add modules team to CODEOWNERS&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Finally push your changes to the branch and create the PR &amp;ldquo;Basic infrastructure&amp;rdquo;
Sample &lt;a href="https://github.com/puppetlabs/puppet-modulebuilder/pull/1">PR&lt;/a> for reference&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Follow the steps below for enabling CI jobs and dependabot for the repo.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Set up travs-ci.org for simple rubocop and spec testing. Open a &lt;a href="https://travis-ci.org/account/repositories">travis-ci-org&lt;/a> page. Click on Sync account.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/syncaccount.png" alt="Sync account">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Set up appveyor for simple rubocop and spec testing. Open a &lt;a href="https://ci.appveyor.com/account/puppetlabs/projects/new">ci-appveyor&lt;/a> page. Click on Add.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/add.png" alt="Add">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Allow dependabot access the new repo created. Open a &lt;a href="https://app.dependabot.com/accounts/puppetlabs/">dependabot&lt;/a> page.
Click on + , select the repo and provide access.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/dependabotadd.png" alt="+">&lt;/p>
&lt;p>&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/dependabot.png" alt="repo created">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Enable dependabot for the repo.
&lt;img src="https://puppetlabs.github.io/content-and-tooling-team/content-and-tooling-team/assets/2020-02-19-infrastructure-for-the-gem/dependabotenable.png" alt="+">&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;h2 id="wrapping-up">Wrapping Up&lt;/h2>
&lt;p>Hooray! We&amp;rsquo;ve created the infrastructure for our gem !&lt;/p></description></item><item><title>Blog: Gem Testing with pdksync</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-12-gem-testing-with-pdksync/</link><pubDate>Wed, 12 Feb 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-12-gem-testing-with-pdksync/</guid><description>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>pdksync enables you to do a lot more than just pdk update against a set of defined modules. In this blog post we will be going through single or multi gem testing features of pdksync.&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>Download a fork of the repo, which can be found here &lt;a href="https://github.com/puppetlabs/pdksync">pdksync&lt;/a>. Or you can install via Rubygems, it can be found here &lt;a href="https://rubygems.org/gems/pdksync">pdksync&lt;/a>.
Install gems by using &lt;code>bundle install&lt;/code>.
Ensure you have a GITHUB_TOKEN set in your env, if you don&amp;rsquo;t add it by running &lt;code>export GITHUB_TOKEN=&amp;lt;your github token&amp;gt;&lt;/code>, this is required for authentication.
Important - Manually edit the list contained in &amp;lsquo;managed_modules.yml&amp;rsquo; to ensure it is correct with the modules you wish to update. Please note this is critical as this tool will create PRs against the repos included in this list - you don&amp;rsquo;t want to run this against a module you aren&amp;rsquo;t familiar with. Do not proceed to the next step without doing this.
Run the rake task by using &lt;code>bundle exec rake pdksync&lt;/code>.&lt;/p>
&lt;h2 id="part-one-functionality-single-gem-testing">Part One: Functionality Single Gem Testing&lt;/h2>
&lt;p>pdksync tool comes with the feature to update the Gemfile. Puppet provides a lot of useful gems to access and manage their functionality between modules. This functionality will help user to perform gem testing prior to release. User is given new rake tasks to update SHA/Version/Branch/line in the Gemfile. Then the changes can be committed, PR can be created which will run the acceptance tests in the PR. If all the tests are executing successfully then the user can close the PRS and release the gem.&lt;/p>
&lt;blockquote>
&lt;h4 id="note">Note:&lt;/h4>
&lt;p>It assumes very limited familiarity with the &lt;a href="https://github.com/puppetlabs/pdksync">pdksync&lt;/a> and &lt;a href="https://puppet.com/blog/keep-your-puppet-modules-up-to-date-pdk/">pdk&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>Run gem_file_update against modules&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:gem_file_update&lt;span style="color:#ff79c6">[&lt;/span>:gem_to_test, :gem_line, :gem_sha_finder, :gem_sha_replacer, :gem_version_finder, :gem_version_replacer, :gem_branch_finder, :gem_branch_replacer&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>eg rake to update gem line&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:gem_file_update&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet_litmus&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;gem &amp;#39;puppet_litmus&amp;#39;\, git: &amp;#39;https://github.com/test/puppet_litmus.git&amp;#39;\, branch: &amp;#39;testbranch&amp;#39;&amp;#34;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>&amp;#39;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>eg rake to update sha&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:gem_file_update&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet_litmus&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;20ee04ba1234e9e83eb2ffb5056e23d641c7a018&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;20ee04ba1234e9e83eb2ffb5056e23d641c7a31&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>eg rake to update version&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:gem_file_update&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet_litmus&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;= 0.9.0&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#34;&amp;lt;= 0.10.0&amp;#34;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>eg rake to update branch&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:gem_file_update&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet_litmus&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;testbranch&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;testbranches&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Below given are the workflows for doing single gem testing with pdksync.&lt;/p>
&lt;p>In Workflow 1 we can clone modules, update the gem file, create the commit, push the changes and create the PR using separate rake tasks.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">bundle install --path .bundle/gems/
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake git:clone_managed_modules
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;pdksync:gem_file_update[]&amp;#39;&lt;/span>
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;git:create_commit[]&amp;#39;&lt;/span>
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;git:push&amp;#39;&lt;/span>
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;git:create_pr[]&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>In Workflow 2 we can clone modules, update the gem file, create the commit, push the changes and create the PR using single rake task&lt;/p>
&lt;pre>&lt;code>Using single rake job
bundle install --path .bundle/gems/
bundle exec rake 'gem_testing[]'
&lt;/code>&lt;/pre>&lt;p>Once the verified gem is released we can use pdksync to update the the new version of gem released in the &lt;code>.sync.yaml&lt;/code> file.&lt;/p>
&lt;h2 id="part-two-functionality-multi-gem-testing">Part Two: Functionality Multi Gem Testing&lt;/h2>
&lt;p>pdksync tool is extended with the feature to perform multi gem testing (&lt;code>puppet-module-gems&lt;/code>). This functionality will identify the current version and bump the version by one. Then it will build and push the gems to gemfury account. Export the GEMFURY_TOKEN to use this rake task.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">&lt;span style="color:#8be9fd;font-style:italic">export&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">GEMFURY_TOKEN&lt;/span>&lt;span style="color:#ff79c6">=&lt;/span>&amp;lt;access_token&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Run the following commands to check that everything is working as expected:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">bundle install --path .bundle/gems/
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake -T
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;git:clone_gem[puppet-module-gems]&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Run multigem_file_update against modules:&lt;/p>
&lt;p>Clone gem&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">git:clone_gem&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet-module-gems&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Build and Push new gems built to the gemfury account for testing&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:multi_gem_testing&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet-module-gems&amp;#39;&lt;/span>,&lt;span style="color:#f1fa8c">&amp;#39;config/info.yml&amp;#39;&lt;/span>,&lt;span style="color:#f1fa8c">&amp;#39;exe/build-gems.rb&amp;#39;&lt;/span>,&lt;span style="color:#f1fa8c">&amp;#39;pkg&amp;#39;&lt;/span>,&lt;span style="color:#f1fa8c">&amp;#39;gem_tester&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Update Gemfile of the modules with the new gem should be pushed to Gemfury.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">pdksync:multigem_file_update&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;puppet-module&amp;#39;&lt;/span>,&lt;span style="color:#f1fa8c">&amp;#39;tester&amp;#39;&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Below given is the workflows for doing multi gem testing with pdksync.&lt;/p>
&lt;p>In this workflow we can clone gems, update the version, build the gem, push the changes to gemfury and update the gem file of the required modules with the latest gem updated in the fury. Then we can create PR or run tests locally or run tests through jenkins to verify the module test results.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">bundle install --path .bundle/gems/
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;git:clone_gem[puppet-module-gems]&amp;#39;&lt;/span>
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;pdksync:multi_gem_testing[]&amp;#39;&lt;/span>
bundle &lt;span style="color:#8be9fd;font-style:italic">exec&lt;/span> rake &lt;span style="color:#f1fa8c">&amp;#39;pdksync:multigem_file_update[]&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="wrapping-up">Wrapping Up&lt;/h2>
&lt;p>These are the steps that we can follow to perform single or multi gem testing using pdksync.&lt;/p></description></item><item><title>Blog: Developing a PowerShell-Dependent Puppet Type &amp; Provider</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-05-powershell-type-and-provider-i/</link><pubDate>Wed, 05 Feb 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-02-05-powershell-type-and-provider-i/</guid><description>
&lt;blockquote>
&lt;p>Part One: Basic Functionality&lt;/p>
&lt;/blockquote>
&lt;p>Sometimes when managing resources with Puppet you come across a use case that you might initially solve via a few custom &lt;code>exec&lt;/code> resources&amp;ndash;
but though this solves your problem in the short run, it doesn&amp;rsquo;t scale well and leaves a lot of problems around managing reporting and idempotency.
At a certain point, it becomes advisable to write a type and provider&amp;ndash;for more information, check out our &lt;a href="https://learn.puppet.com/course/getting-started-with-the-puppet-resource-api">hands on lab&lt;/a>!&lt;/p>
&lt;p>For the purposes of this walkthrough, we&amp;rsquo;re going to create a resource API compliant type and provider to manage SMB shares on Windows.
What we want to be able to do is put something like this into a manifest, thereby creating a share on the machine:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#50fa7b">smb_share&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;basic_example&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">present&lt;/span>,
&lt;span style="color:#50fa7b">path&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;C:\Path\To\A\Share&amp;#39;&lt;/span>,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Before we can dig into the meat of writing the type and provider though, we&amp;rsquo;ve got some standardized setup to do.&lt;/p>
&lt;blockquote>
&lt;h4 id="note">Note:&lt;/h4>
&lt;p>This walkthrough assumes you have the following software installed:&lt;/p>
&lt;ul>
&lt;li>The &lt;a href="https://puppet.com/docs/pdk/1.x/pdk_install.html">Puppet Development Kit&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://code.visualstudio.com/download">Visual Studio Code&lt;/a> with the &lt;a href="https://lingua-pupuli.github.io/">Puppet extension&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>It also assumes very limited familiarity with the &lt;a href="https://puppet.com/blog/introducing-puppet-resource-api/">Resource API Walkthrough&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;ol>
&lt;li>Open a PowerShell console, perform the rest of these actions from there.&lt;/li>
&lt;li>&lt;code>pdk new module smb&lt;/code>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): PDK collects anonymous usage information to help us understand how
it is being used and make decisions on how to improve it. You can
find out more about what data we collect and how it is used in the
PDK documentation at
https://puppet.com/docs/pdk/latest/pdk_install.html.
[Q 1/1] Do you consent to the collection of anonymous PDK usage information?
--&amp;gt; Yes
pdk (INFO): You can opt in or out of the usage data collection at any time by
editing the analytics configuration file at
C:\Users\vagrant\AppData\Local/puppet/analytics.yml and changing
the &amp;#39;disabled&amp;#39; value.
pdk (INFO): Creating new module: smb
We need to create the metadata.json file for this module, so we&amp;#39;re going to ask you 4 questions.
If the question is not applicable to this module, accept the default option shown after each question. You can modify any answers at any time by manually updating the metadata.json file.
[Q 1/4] If you have a Puppet Forge username, add it here.
We can use this to upload your module to the Forge when it&amp;#39;s complete.
--&amp;gt; michaeltlombardi
[Q 2/4] Who wrote this module?
This is used to credit the module&amp;#39;s author.
--&amp;gt; michaeltlombardi
[Q 3/4] What license does this module code fall under?
This should be an identifier from https://spdx.org/licenses/. Common values are &amp;#34;Apache-2.0&amp;#34;, &amp;#34;MIT&amp;#34;, or &amp;#34;proprietary&amp;#34;.
--&amp;gt; Apache-2.0
[Q 4/4] What operating systems does this module support?
Use the up and down keys to move between the choices, space to select and enter to continue.
--&amp;gt; Windows
Metadata will be generated based on this information, continue? Yes
pdk (INFO): Module &amp;#39;smb&amp;#39; generated at path &amp;#39;C:/Users/vagrant/smb&amp;#39;, from template &amp;#39;file:///C:/Program Files/Puppet Labs/DevelopmentKit/share/cache/pdk-templates.git&amp;#39;.
pdk (INFO): In your module directory, add classes with the &amp;#39;pdk new class&amp;#39; command.
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;code>cd smb ; code .&lt;/code>&lt;/li>
&lt;li>Update dependencies by editing the following files in VSCode:
&lt;ul>
&lt;li>&lt;code>.fixtures.yml&lt;/code>:
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="color:#ff79c6">fixtures&lt;/span>:
&lt;span style="color:#ff79c6">forge_modules&lt;/span>:
&lt;span style="color:#ff79c6">pwshlib&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;puppetlabs/pwshlib&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;code>.sync.yml&lt;/code> (you&amp;rsquo;ll need to create this file):
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="color:#ff79c6">Gemfile&lt;/span>:
&lt;span style="color:#ff79c6">optional&lt;/span>:
&lt;span style="color:#ff79c6">&amp;#39;:development&amp;#39;&lt;/span>:
- &lt;span style="color:#ff79c6">gem&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#39;ruby-pwsh&amp;#39;&lt;/span>
- &lt;span style="color:#ff79c6">gem&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#39;puppet-resource_api&amp;#39;&lt;/span>
&lt;span style="color:#ff79c6">spec/spec_helper.rb&lt;/span>:
&lt;span style="color:#ff79c6">mock_with&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#39;:rspec&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;code>metadata.json&lt;/code>:
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-json" data-lang="json">&lt;span style="color:#f1fa8c">&amp;#34;dependencies&amp;#34;&lt;/span>: [
{
&lt;span style="color:#ff79c6">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;puppetlabs/pwshlib&amp;#34;&lt;/span>,
&lt;span style="color:#ff79c6">&amp;#34;version_requirement&amp;#34;&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#34;&amp;gt;= 0.4.0 &amp;lt; 2.0.0&amp;#34;&lt;/span>
}
],
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>pdk update&lt;/code>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Updating michaeltlombardi-smb using the default template, from blog_tags/1.15.0 to 1.15.0
----------Files to be modified----------
Gemfile
spec/spec_helper.rb
----------------------------------------
You can find a report of differences in update_report.txt.
Do you want to continue and make these changes to your module? Yes
[*] Installing missing Gemfile dependencies.
------------Update completed------------
2 files modified.
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;code>pdk new provider smb_share&lt;/code>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Creating &amp;#39;C:/Users/vagrant/smb/lib/puppet/provider/smb_share/smb_share.rb&amp;#39; from template.
pdk (INFO): Creating &amp;#39;C:/Users/vagrant/smb/lib/puppet/type/smb_share.rb&amp;#39; from template.
pdk (INFO): Creating &amp;#39;C:/Users/vagrant/smb/spec/unit/puppet/provider/smb_share/smb_share_spec.rb&amp;#39; from template.
pdk (INFO): Creating &amp;#39;C:/Users/vagrant/smb/spec/unit/puppet/type/smb_share_spec.rb&amp;#39; from template.
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;code>pdk bundle exec rake spec_prep&lt;/code>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
I, [2020-01-17T13:18:26.702383 #1696] INFO -- : Creating symlink from spec/fixtures/modules/smb to C:\Users\vagrant\smb
Notice: Preparing to install into C:/Users/vagrant/smb/spec/fixtures/modules ...
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: Installing -- do not interrupt ...
C:/Users/vagrant/smb/spec/fixtures/modules
└── puppetlabs-pwshlib (v0.4.0)
&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Now we&amp;rsquo;re ready to really dig into writing our type and provider.&lt;/p>
&lt;h2 id="defining-the-initial-type">Defining the Initial Type&lt;/h2>
&lt;p>The type file, &lt;code>lib/puppet/type/smb_share.rb&lt;/code>, requires a little editing.
We&amp;rsquo;ll be adding some documentation and filling out the different properties of the SMB share we want to manage.&lt;/p>
&lt;p>Two properties are already provided for us in the &lt;code>attributes&lt;/code> key: &lt;code>ensure&lt;/code> and &lt;code>name&lt;/code>.
In order to get a minimum viable implementation for our share, we&amp;rsquo;ll need to implement &lt;code>path&lt;/code> as well.
Add the following hash to the list of attributes in the type file:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#f1fa8c">path&lt;/span>: {
&lt;span style="color:#f1fa8c">type&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#39;String&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">desc&lt;/span>: &lt;span style="color:#f1fa8c">&amp;#39;The path of the SMB share.&amp;#39;&lt;/span>,
},
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This property is fairly simple to define - the path to the SMB share will always be a string.
For now, this is all we need to add to be able to implement the basic provider functionality.&lt;/p>
&lt;blockquote>
&lt;h4 id="note-1">Note:&lt;/h4>
&lt;p>We did not update the rest of the docs here - we will return to the documentation aspect in a future blog post when we expand the properties this type manages.&lt;/p>
&lt;/blockquote>
&lt;h2 id="writing-the-prototype-provider">Writing the Prototype Provider&lt;/h2>
&lt;p>The next file we need to look at is the provider, &lt;code>lib/puppet/provider/smb_share.rb&lt;/code>, which is where most of the heavy lifting will happen.&lt;/p>
&lt;!-- First, at the top of the file _just_ inside the provider class definition (after line 4), we need to confine this provider to only run on Windows machines when the ruby-pwsh library is available:
```ruby
class Puppet::Provider::SmbShare::SmbShare &lt; Puppet::ResourceApi::SimpleProvider
confine :operatingsystem => :windows
confine :feature => :pwshlib
``` -->
&lt;p>First, add a requires statement to the top of the file to ensure we have access to the PowerShell gem:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#8be9fd;font-style:italic">require&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;ruby-pwsh&amp;#39;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next, inside the provider class definition, we need to add two new methods which make using the PowerShell gem&amp;rsquo;s manager easier:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#6272a4"># Returns a new instance of the PowerShell manager if one does not exist or is dead,&lt;/span>
&lt;span style="color:#6272a4"># otherwise returns the existing usable instance for performance reasons.&lt;/span>
&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">ps_manager&lt;/span>
debug_output &lt;span style="color:#ff79c6">=&lt;/span> Puppet&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">::&lt;/span>Log&lt;span style="color:#ff79c6">.&lt;/span>level &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">:debug&lt;/span>
Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Manager&lt;span style="color:#ff79c6">.&lt;/span>instance(Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Manager&lt;span style="color:#ff79c6">.&lt;/span>powershell_path, Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Manager&lt;span style="color:#ff79c6">.&lt;/span>powershell_args, &lt;span style="color:#f1fa8c">debug&lt;/span>: debug_output)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;span style="color:#6272a4"># Wraps executions for the PowerShell Manager to do some basic error raising in Puppet.&lt;/span>
&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">invoke_command&lt;/span>(command)
result &lt;span style="color:#ff79c6">=&lt;/span> ps_manager&lt;span style="color:#ff79c6">.&lt;/span>execute(command)
&lt;span style="color:#ff79c6">raise&lt;/span> result&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:errormessage&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span> &lt;span style="color:#ff79c6">unless&lt;/span> result&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:exitcode&lt;/span>&lt;span style="color:#ff79c6">].&lt;/span>zero?
result
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, we&amp;rsquo;re ready to start implementing some functionality.&lt;/p>
&lt;h3 id="getting-the-shares">Getting the Shares&lt;/h3>
&lt;p>The information we need to retrieve about our shares was defined in our type file; right now, we need the name of the share, the path to the share, and whether or not it exists. To find out this information though, we&amp;rsquo;re going to need to do a little PowerShell:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Get-SMBShare&lt;/span> -ErrorAction Stop |
&lt;span style="color:#8be9fd;font-style:italic">Select-Object&lt;/span> -Property Name, Path
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Which in Ruby, using the PowerShell manager, would be:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#39;Get-SMBShare -ErrorAction Stop&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;Select-Object -Property Name, Path&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39; | &amp;#39;&lt;/span>)
invoke_command(command)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here, we declare the commands in a Ruby array and join them with a &lt;code>|&lt;/code>.
This makes it easier for us to modify the commands we need to run without having to manage a huge string that&amp;rsquo;s hard to read.
This will return all of the SMB shares on the machine, but there&amp;rsquo;s a couple problems:&lt;/p>
&lt;ol>
&lt;li>We need to return JSON for easy translation to usable objects in ruby&lt;/li>
&lt;li>We need to add a property for Ensure - right now, we&amp;rsquo;re missing that third property.
We could add it either to the &lt;code>Select-Object statement&lt;/code> (as a name-expression hash with a static expression of &lt;code>'present'&lt;/code>) or to ruby afterwards.
For the purpose of this example, we&amp;rsquo;ll just add it to the Select-Object statement.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">properties &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#39;Name&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;Path&amp;#39;&lt;/span>,
Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>custom_powershell_property(&lt;span style="color:#f1fa8c">&amp;#39;ensure&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#34;present&amp;#34;&amp;#39;&lt;/span>),
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39;, &amp;#39;&lt;/span>)
command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#39;Get-SMBShare -ErrorAction Stop&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#34;Select-Object -Property &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>properties&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;ConvertTo-Json&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39; | &amp;#39;&lt;/span>)
result &lt;span style="color:#ff79c6">=&lt;/span> invoke_command(command)
Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>symbolize_hash_keys(Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>snake_case_hash_keys(JSON&lt;span style="color:#ff79c6">.&lt;/span>parse(result&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:stdout&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>)))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Notice we added a new &lt;code>properties&lt;/code> variable, in which we declare the properties we want to return on the SMB share and join them with a comma, which is how they&amp;rsquo;ll need to be passed to &lt;code>Select-Object&lt;/code>.
This lets us decouple the properties to select from the command itself and will make things more readable as we add more properties to manage.&lt;/p>
&lt;p>We&amp;rsquo;re also using a helper method (&lt;code>custom_powershell_property&lt;/code>) from the PowerShell gem to create a PowerShell hash representing a custom object property.
In this case, it will be:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">@{Name = &lt;span style="color:#f1fa8c">&amp;#39;ensure&amp;#39;&lt;/span>; Expression = {&lt;span style="color:#f1fa8c">&amp;#34;present&amp;#34;&lt;/span>}}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>It&amp;rsquo;s important to note that the string passed as the expression is &lt;em>exactly&lt;/em> what will be placed in the expression script block;
without the internal quotes, PowerShell would try to run a command called &lt;code>present&lt;/code> in the scriptlock and fail.&lt;/p>
&lt;p>For our command, the major changes are that we interpolate the properties list for Select-Object and ensure we convert our output to JSON before passing it back to Ruby.&lt;/p>
&lt;p>Finally, we want to capture the output of our command invocation so we can return the results.
The last line of this command is doing a &lt;em>bunch&lt;/em> of heavy lifting, so let&amp;rsquo;s break it down:&lt;/p>
&lt;ul>
&lt;li>&lt;code>result[:stdout]&lt;/code> - this is what we returned from our command pipeline - in this case, we told PowerShell to return us the SMB object with the properties we specified as a JSON string.&lt;/li>
&lt;li>&lt;code>JSON.parse()&lt;/code> - this is the Ruby method for converting from a JSON string to a Ruby hash, loosely analogous to &lt;code>ConvertFrom-Json&lt;/code> in PowerShell.&lt;/li>
&lt;li>&lt;code>Pwsh::Util.symbolize_hash_keys()&lt;/code> - this is a helper method for converting a Ruby hash&amp;rsquo;s keys from strings &lt;code>&amp;quot;key_name&amp;quot;&lt;/code> to symbols &lt;code>:key_name&lt;/code> which is necessary for returning values in a way that will neatly compare with what our type and provider are expecting.&lt;/li>
&lt;li>&lt;code>Pwsh::Util.snake_case_hash_keys()&lt;/code> - this is another helper method, this one converting a Ruby hash&amp;rsquo;s keys to a &lt;code>snake_case&lt;/code> from &lt;code>PascalCase&lt;/code>, &lt;code>camelCase&lt;/code>, or &lt;code>kebab-case&lt;/code>.
As with &lt;code>symbolize_hash_keys()&lt;/code>, this method helps ensure we&amp;rsquo;re returning a hash that our type/provider can neatly compare to.&lt;/li>
&lt;/ul>
&lt;p>So, if we put this all together for a ruby method to use in our provider, we&amp;rsquo;ll have:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">get_smb_share&lt;/span> &lt;span style="color:#6272a4"># rubocop:disable Style/AccessorMethodName&lt;/span>
properties &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#39;Name&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;Path&amp;#39;&lt;/span>,
Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>custom_powershell_property(&lt;span style="color:#f1fa8c">&amp;#39;ensure&amp;#39;&lt;/span>, &lt;span style="color:#f1fa8c">&amp;#39;&amp;#34;present&amp;#34;&amp;#39;&lt;/span>),
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39;, &amp;#39;&lt;/span>)
command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#39;Get-SMBShare -ErrorAction Stop&amp;#39;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#34;Select-Object -Property &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>properties&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;ConvertTo-Json&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39; | &amp;#39;&lt;/span>)
result &lt;span style="color:#ff79c6">=&lt;/span> invoke_command(command)
Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>symbolize_hash_keys(Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>snake_case_hash_keys(JSON&lt;span style="color:#ff79c6">.&lt;/span>parse(result&lt;span style="color:#ff79c6">[&lt;/span>&lt;span style="color:#f1fa8c">:stdout&lt;/span>&lt;span style="color:#ff79c6">]&lt;/span>)))
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note: We added a comment to tell rubocop, a tool for enforcing ruby style guidelines, to ignore this method&amp;rsquo;s name.
In Ruby, methods like &lt;code>get_smb_share&lt;/code> are normally just &lt;code>smb_share&lt;/code> - in this case, it will help PowerShell folx better understand what&amp;rsquo;s happening, so it makes sense to ignore the rule.&lt;/p>
&lt;/blockquote>
&lt;p>For now, this is good enough, so we&amp;rsquo;ll update the &lt;code>get&lt;/code> method in our provider to just call &lt;code>get_smb_share&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">get&lt;/span>(context)
context&lt;span style="color:#ff79c6">.&lt;/span>debug(&lt;span style="color:#f1fa8c">&amp;#39;Returning discovered SMB shares&amp;#39;&lt;/span>)
get_smb_share
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>We can test that our code is working by running &lt;a href="https://puppet.com/docs/puppet/latest/man/resource.html">puppet resource&lt;/a>.&lt;/p>
&lt;blockquote>
&lt;p>Note that we&amp;rsquo;re using the PDK bundle for development purposes;
We&amp;rsquo;re also specifying the modulepath to a special folder in our repository;
This was created in the set up stage when you ran &lt;code>pdk bundle exec rake spec_prep&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet resource smb_share --modulepath ./spec/fixtures/modules/
&lt;/code>&lt;/pre>&lt;/div>&lt;p>That should give you back information that looks like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
smb_share { &amp;#39;ADMIN$&amp;#39;:
path =&amp;gt; &amp;#39;C:\Windows&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
smb_share { &amp;#39;C$&amp;#39;:
path =&amp;gt; &amp;#39;C:\&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
smb_share { &amp;#39;IPC$&amp;#39;:
path =&amp;gt; &amp;#39;&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Later, when we start adding to our use case (managing, say, permissions) we will expand on this method.&lt;/p>
&lt;h3 id="creating-a-share">Creating a Share&lt;/h3>
&lt;p>Retrieving resources from a machine is useful, but not as useful as creating them, so let&amp;rsquo;s enable that functionality next.&lt;/p>
&lt;p>We&amp;rsquo;ll create a &lt;code>new_smb_share()&lt;/code> method that passes along the arguments we specified to the &lt;code>New-SmbShare&lt;/code> cmdlet:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">new_smb_share&lt;/span>(arguments)
arguments&lt;span style="color:#ff79c6">.&lt;/span>reject! { &lt;span style="color:#ff79c6">|&lt;/span>k, _v&lt;span style="color:#ff79c6">|&lt;/span> k&lt;span style="color:#ff79c6">.&lt;/span>to_s &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Ensure&amp;#39;&lt;/span> }
command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#34;$Arguments = &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>format_powershell_value(arguments)&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;New-SmbShare @Arguments -ErrorAction Stop&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39; ; &amp;#39;&lt;/span>)
invoke_command(command)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The first thing we do is remove &lt;code>Ensure&lt;/code> from the hash of arguments passed to this method if it exists &amp;ndash; since we&amp;rsquo;re sending that hash to PowerShell for splatting and &lt;code>New-SmbShare&lt;/code> will have &lt;strong>no&lt;/strong> idea what to do with an &lt;code>Ensure&lt;/code> parameter, we need to make sure it gets removed.
The &lt;code>reject&lt;/code> method used here iterates over the &lt;code>arguments&lt;/code> hash for each key-value pair and filters out any pairs which match the condition; in this case, if the key is &lt;code>Ensure&lt;/code>.
In PowerShell, this is loosely analogous to doing something like:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">$Arguments&lt;/span> = &lt;span style="color:#8be9fd;font-style:italic">$Should&lt;/span>
&lt;span style="color:#8be9fd;font-style:italic">$Arguments&lt;/span>.Remove(&lt;span style="color:#f1fa8c">&amp;#39;Ensure&amp;#39;&lt;/span>)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the command array we can rely on another utility from the PowerShell gem: &lt;code>format_powershell_value&lt;/code> will convert a Ruby object into an appropriate PowerShell representation.
In this case, arguments is a hash and so will be represented as something like:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">@{KeyName = &lt;span style="color:#f1fa8c">&amp;#39;value&amp;#39;&lt;/span>; NextKey = 1}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>We then rely on the hash table we stored in &lt;code>$Arguments&lt;/code> to enable us to do some &lt;a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting?view=powershell-7">splatting&lt;/a>.
Finally, we join these commands with a semi-colon&amp;ndash;remember, each invocation against the Manager does &lt;em>not&lt;/em> share state with prior ones!&lt;/p>
&lt;p>Okay, great, but how do we pass the correct arguments to &lt;code>new_smb_share&lt;/code>?
We can do that with a little munging in the &lt;code>create&lt;/code> method:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">create&lt;/span>(context, &lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>, should)
context&lt;span style="color:#ff79c6">.&lt;/span>notice(&lt;span style="color:#f1fa8c">&amp;#34;Creating &amp;#39;&lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39; with &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>should&lt;span style="color:#ff79c6">.&lt;/span>inspect&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>)
arguments &lt;span style="color:#ff79c6">=&lt;/span> Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>pascal_case_hash_keys(should)
new_smb_share(arguments)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">new_smb_share&lt;/span>(arguments)
arguments&lt;span style="color:#ff79c6">.&lt;/span>reject! { &lt;span style="color:#ff79c6">|&lt;/span>k, _v&lt;span style="color:#ff79c6">|&lt;/span> k&lt;span style="color:#ff79c6">.&lt;/span>to_s &lt;span style="color:#ff79c6">==&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;Ensure&amp;#39;&lt;/span> }
command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#ff79c6">[&lt;/span>
&lt;span style="color:#f1fa8c">&amp;#34;$Arguments = &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>format_powershell_value(arguments)&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>,
&lt;span style="color:#f1fa8c">&amp;#39;New-SmbShare @Arguments -ErrorAction Stop&amp;#39;&lt;/span>,
&lt;span style="color:#ff79c6">].&lt;/span>join(&lt;span style="color:#f1fa8c">&amp;#39; ; &amp;#39;&lt;/span>)
invoke_command(command)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that the create and update methods both specify the &lt;code>name&lt;/code> and something called &lt;code>should&lt;/code>; these are automatically handled and passed by Puppet during a run.
The &lt;code>should&lt;/code> variable is a Ruby hash representing the parameters specified for a given resource.
So if someone defined a manifest, it would include all of the properties and parameters for the specified SMB share included in that resource declaration.&lt;/p>
&lt;p>The notice will show up in the logs of a run, explaining what share is being created and specifying the parameters.&lt;/p>
&lt;p>We then pass the arguments hash to a utility function, &lt;code>pascal_case_hash_keys&lt;/code> converts them from the snake_case Ruby prefers to the PascalCase that PowerShell normally prefers;
though our current parameters are all single words, this will help us in the future should we want to specify something like the concurrent user limit on the SMB share.&lt;/p>
&lt;p>Once we&amp;rsquo;ve munged our arguments to be what we need we can pass them to our helper function, &lt;code>new_smb_share&lt;/code>.&lt;/p>
&lt;p>We can test this code by adding a manifest to our examples folder.
Create a new file, &lt;code>examples/basic.pp&lt;/code>, and paste the following into it:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#8be9fd;font-style:italic">$share_path&lt;/span> &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;C:\\smb_share_folder_example_a&amp;#34;&lt;/span>
&lt;span style="color:#ff79c6">file&lt;/span> { &lt;span style="color:#8be9fd;font-style:italic">$share_path:&lt;/span>
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;directory&amp;#39;&lt;/span>
}
&lt;span style="color:#50fa7b">smb_share&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;basic_example&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">present&lt;/span>,
&lt;span style="color:#50fa7b">path&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$share_path,&lt;/span>
&lt;span style="color:#50fa7b">require&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">File&lt;/span>[&lt;span style="color:#8be9fd;font-style:italic">$share_path]&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note that we have to ensure that the directory we will use as the path for the SMB share&amp;ndash;if it doesn&amp;rsquo;t exist, the command will fail.&lt;/p>
&lt;p>Also note that VSCode will present you with a pop up in the bottom right corner asking if you want to add an extension for &lt;code>.pp&lt;/code> files - you &lt;em>absolutely&lt;/em> do want to add the &lt;a href="https://puppet-vscode.github.io/">Puppet Extension for VSCode&lt;/a> if you&amp;rsquo;re not already using it; it includes dozens of helpful features to make writing and maintaining Puppet code easier!&lt;/p>
&lt;/blockquote>
&lt;p>And then we&amp;rsquo;ll run a command &lt;em>with administrative privileges&lt;/em> (needed to create the SMB share) to execute this manifest:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet apply ./examples/basic.pp --modulepath ./spec/fixtures/modules/
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Which should produce output like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
Notice: Compiled catalog for .mshome.net in environment production in 0.21 seconds
Notice: /Stage[main]/Main/File[C:\smb_share_folder_example_a]/ensure: created
Notice: /Stage[main]/Main/Smb_share[basic_example]/ensure: defined &amp;#39;ensure&amp;#39; as &amp;#39;present&amp;#39;
Notice: smb_share[basic_example]: Creating: Creating &amp;#39;basic_example&amp;#39; with {:name=&amp;gt;&amp;#34;basic_example&amp;#34;, :ensure=&amp;gt;&amp;#34;present&amp;#34;, :path=&amp;gt;&amp;#34;C:\\smb_share_folder_example_a&amp;#34;}
Notice: smb_share[basic_example]: Creating: Finished in 1.23 seconds
Notice: Applied catalog in 9.22 seconds
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Awesome! We&amp;rsquo;ve created an SMB share!
We can even verify this by rerunning the &lt;code>puppet resource&lt;/code> command from earlier:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet resource smb_share --modulepath ./spec/fixtures/modules/
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
smb_share { &amp;#39;ADMIN$&amp;#39;:
path =&amp;gt; &amp;#39;C:\Windows&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
smb_share { &amp;#39;C$&amp;#39;:
path =&amp;gt; &amp;#39;C:\&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
smb_share { &amp;#39;IPC$&amp;#39;:
path =&amp;gt; &amp;#39;&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
smb_share { &amp;#39;basic_example&amp;#39;:
path =&amp;gt; &amp;#39;C:\smb_share_folder_example_a&amp;#39;,
ensure =&amp;gt; &amp;#39;present&amp;#39;,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="removing-a-share">Removing a Share&lt;/h3>
&lt;p>Now, let&amp;rsquo;s figure out how to remove an SMB share.
Luckily, removing a share in PowerShell is straightforward:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="color:#8be9fd;font-style:italic">Remove-SmbShare&lt;/span> -Name &lt;span style="color:#f1fa8c">&amp;#39;name of the share&amp;#39;&lt;/span> -Force
&lt;/code>&lt;/pre>&lt;/div>&lt;p>So we can write this in ruby leveraging the PowerShell manager:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">remove_smb_share&lt;/span>(&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>)
command &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;Remove-SmbShare -Name &amp;#39;&lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39; -Force -ErrorAction Stop&amp;#34;&lt;/span>
invoke_command(command)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>And call it from the &lt;code>delete()&lt;/code> method:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">delete&lt;/span>(context, &lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>)
context&lt;span style="color:#ff79c6">.&lt;/span>notice(&lt;span style="color:#f1fa8c">&amp;#34;Deleting &amp;#39;&lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39;&amp;#34;&lt;/span>)
remove_smb_share(&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Let&amp;rsquo;s test our newly updated provider!
We can use &lt;code>puppet resource&lt;/code> to change the property of a managed resource&amp;ndash;in this case, we want to use &lt;code>ensure=absent&lt;/code> to remove the SMB share.
Remember, this needs to be run &lt;em>with&lt;/em> administrative privileges.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet resource smb_share basic_example ensure=absent --modulepath ./spec/fixtures/modules
&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
Notice: /Smb_share[basic_example]/ensure: undefined &amp;#39;ensure&amp;#39; from &amp;#39;present&amp;#39;
Notice: smb_share[basic_example]: Deleting: Deleting &amp;#39;basic_example&amp;#39;
Notice: smb_share[basic_example]: Deleting: Finished in 0.804902 seconds
smb_share { &amp;#39;basic_example&amp;#39;:
ensure =&amp;gt; &amp;#39;absent&amp;#39;,
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>You should see a notification that the share has been removed.
Go ahead and rerun the manifest to recreate the share and prepare for our next step:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet apply ./examples/basic.pp --modulepath ./spec/fixtures/modules/
&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="updating-a-share">Updating a Share&lt;/h3>
&lt;p>While there are &lt;em>better&lt;/em> ways to manage updating SMB shares, the &lt;em>easiest&lt;/em> is to delete it and recreate it with the appropriate parameters passed through&amp;ndash;in fact, this is &lt;em>necessary&lt;/em> if you need to change the path of an SMB share.&lt;/p>
&lt;p>Luckily, we&amp;rsquo;ve already written the methods for creating and deleting the share so all we need to do is fill in the &lt;code>update&lt;/code> method:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#ff79c6">def&lt;/span> &lt;span style="color:#50fa7b">update&lt;/span>(context, &lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>, should)
context&lt;span style="color:#ff79c6">.&lt;/span>notice(&lt;span style="color:#f1fa8c">&amp;#34;Updating &amp;#39;&lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#39; with &lt;/span>&lt;span style="color:#f1fa8c">#{&lt;/span>should&lt;span style="color:#ff79c6">.&lt;/span>inspect&lt;span style="color:#f1fa8c">}&lt;/span>&lt;span style="color:#f1fa8c">&amp;#34;&lt;/span>)
arguments &lt;span style="color:#ff79c6">=&lt;/span> Pwsh&lt;span style="color:#ff79c6">::&lt;/span>Util&lt;span style="color:#ff79c6">.&lt;/span>pascal_case_hash_keys(should)
remove_smb_share(&lt;span style="color:#8be9fd;font-style:italic">name&lt;/span>)
new_smb_share(arguments)
&lt;span style="color:#ff79c6">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Let&amp;rsquo;s modify the share path variable to end in &lt;code>b&lt;/code> instead of &lt;code>a&lt;/code>; this will cause Puppet to create a new folder, remove the original SMB share, and create a new one that uses the correct folder.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="color:#8be9fd;font-style:italic">$share_path&lt;/span> &lt;span style="color:#ff79c6">=&lt;/span> &lt;span style="color:#f1fa8c">&amp;#34;C:\\smb_share_folder_example_b&amp;#34;&lt;/span>
&lt;span style="color:#ff79c6">file&lt;/span> { &lt;span style="color:#8be9fd;font-style:italic">$share_path:&lt;/span>
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#f1fa8c">&amp;#39;directory&amp;#39;&lt;/span>
}
&lt;span style="color:#50fa7b">smb_share&lt;/span> { &lt;span style="color:#f1fa8c">&amp;#39;basic_example&amp;#39;&lt;/span>:
&lt;span style="color:#50fa7b">ensure&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">present&lt;/span>,
&lt;span style="color:#50fa7b">path&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#8be9fd;font-style:italic">$share_path,&lt;/span>
&lt;span style="color:#50fa7b">require&lt;/span> &lt;span style="color:#ff79c6">=&amp;gt;&lt;/span> &lt;span style="color:#ff79c6">File&lt;/span>[&lt;span style="color:#8be9fd;font-style:italic">$share_path]&lt;/span>
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then rerun the manifest:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-powershell" data-lang="powershell">pdk bundle exec puppet apply ./examples/basic.pp --modulepath ./spec/fixtures/modules/
&lt;/code>&lt;/pre>&lt;/div>&lt;p>You should see a line like this in your Puppet output:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-text" data-lang="text">pdk (INFO): Using Ruby 2.5.7
pdk (INFO): Using Puppet 6.11.1
Notice: Compiled catalog for .mshome.net in environment production in 0.21 seconds
Notice: /Stage[main]/Main/File[C:\smb_share_folder_example_b]/ensure: created
Notice: /Stage[main]/Main/Smb_share[basic_example]/path: path changed &amp;#39;C:\smb_share_folder_example_a&amp;#39; to &amp;#39;C:\smb_share_folder_example_b&amp;#39;
Notice: smb_share[basic_example]: Updating: Updating &amp;#39;basic_example&amp;#39; with {:name=&amp;gt;&amp;#34;basic_example&amp;#34;, :ensure=&amp;gt;&amp;#34;present&amp;#34;, :path=&amp;gt;&amp;#34;C:\\smb_share_folder_example_b&amp;#34;}
Notice: smb_share[basic_example]: Updating: Finished in 1.67 seconds
Notice: Applied catalog in 9.23 seconds
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="wrapping-up">Wrapping Up&lt;/h2>
&lt;p>Hooray! We&amp;rsquo;ve written a functional implementation of a type and provider for an SMB Share using the PowerShell gem and manager!
Next time, we&amp;rsquo;re going to expand on our start here to make sure we are able to fully manage the properties and access of an SMB share, so stay tuned!&lt;/p></description></item><item><title>Blog: Introduction to the IAC Team</title><link>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-01-29-infrastructure-automation-content-team/</link><pubDate>Wed, 29 Jan 2020 00:00:00 +0000</pubDate><guid>https://puppetlabs.github.io/content-and-tooling-team/blog/posts/2020-01-29-infrastructure-automation-content-team/</guid><description>
&lt;h2 id="workflow-of-the-puppet-iac-team">Workflow of the Puppet IAC Team&lt;/h2>
&lt;p>During a recent &lt;a href="https://puppet.com/community/office-hours/">Office Hours&lt;/a> event (more about that later!) a question was asked by one of the Puppet Community&amp;rsquo;s many talented and inquisitive folk.
Usually, in &lt;a href="https://puppet.com/community/office-hours/">Office Hours&lt;/a>, we are used to fielding questions from folks who are trying to enhance functionality in a module, determine the best way to test or maybe they want to know how to get started to write a new module from scratch.
This one was a little bit different, ragnarkon asked, &amp;ldquo;What is the module development lifecycle like in Puppet?&amp;rdquo;, along with other questions about our tech stack, work priorization processes and my favourite, &amp;ldquo;Who names the conference rooms @ Puppet? ’cause they’re awesome&amp;rdquo;.
I hope I answered that particular community member&amp;rsquo;s questions, but it prompted a discussion amongst the team about whether the people within the Puppet Community know who we are, what we do, how we can help you, and how to reach us if you need that help.&lt;/p>
&lt;h2 id="who-are-we">Who are we?&lt;/h2>
&lt;p>Firstly, an introduction - the Infrastructure Automation Content (IAC) team spans across 3 time zones: from East to West we have three members in Timișoara, Romania, six members in Belfast, Northern Ireland (including our Engineering Manager) and finally, one man and his dog holding the fort in St. Louis, Missouri, USA.
We also work closely with Product Management teams both in our Portland, Oregon HQ and Belfast.&lt;/p>
&lt;h2 id="what-do-we-do">What do we do?&lt;/h2>
&lt;p>The IAC team is responsible for developing and maintaining tooling that contributors to Puppet can use to enhance existing or add new modules to Puppet.
We are also responsible for reviewing the submissions from the community, assisting in development and testing efforts (if required), and releasing new versions of modules to the Forge.&lt;/p>
&lt;h2 id="workflow-and-processes">Workflow and Processes&lt;/h2>
&lt;h3 id="work-prioritization-ticketing-and-development">Work Prioritization, Ticketing and Development&lt;/h3>
&lt;p>We follow the KanBan model of work prioritization and categorisation.
We have chosen &lt;a href="https://tickets.puppetlabs.com/projects/IAC/summary">JIRA&lt;/a> as our ticketing system. Within JIRA, the IAC team has a number of epics which we categorise work under.
A few examples of day-to-day epics we interact with a lot:&lt;/p>
&lt;ul>
&lt;li>Customer Escalations&lt;/li>
&lt;li>&lt;a href="https://tickets.puppetlabs.com/browse/IAC-5">Triage&lt;/a> Tasks (more about Triage later!)&lt;/li>
&lt;/ul>
&lt;p>We also have Epics for larger pieces of work, for example:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tickets.puppetlabs.com/browse/IAC-42">Cloud Platform Provisioning in Litmus&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tickets.puppetlabs.com/browse/IAC-158">Automated Gem &amp;amp; Testing Release&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>We also follow the AGILE methodology of having a stand-up meeting daily, where all members describe what they have been working on since the last meeting, and what they will work on until the next meeting.
It&amp;rsquo;s also during this meeting that we can attempt to unblock individuals who are stuck - either during the stand-up or by assigning time at some stage after. We&amp;rsquo;re in constant communication throughout the day, either face-to-face or over Slack.
We can also jump into meeting rooms / booths and chat to our colleagues in other time zones and screen share.
So it&amp;rsquo;s never the case that we&amp;rsquo;re stuck for very long - we all like to have each other&amp;rsquo;s backs and help at short notice.&lt;/p>
&lt;p>As mentioned above, there is constant interaction with our fellow team members throughout the process.
We&amp;rsquo;re constantly asking for or providing feedback, assisting in testing efforts, or pairing up for more tricky issues.
We tend to use Confluence as a first port of call for our documentation.
If the note or document is to become public facing, it will be ported somewhere visible by all.
Github PRs are where we do most of our code reviews from other team members or Puppet Community contributors.&lt;/p>
&lt;h3 id="testing-and-ci-process">Testing and CI Process&lt;/h3>
&lt;p>For testing effort, we like to have as much automated coverage as possible and have mechanisms in place to display the CI test results for each PR.
Sometimes, as part of the planning documentation we may need to outline a test plan more formally; but this should ultimately be translated in to &lt;a href="https://relishapp.com/rspec">RSpec&lt;/a> unit and acceptance tests.
This means that on every code change and PR, we are quickly be alerted to breaking changes.&lt;/p>
&lt;h3 id="prioritization-of-work">Prioritization of Work&lt;/h3>
&lt;p>Work is prioritised by a number of factors.
Product Management will have an influence over a lot of the work we undertake and they have many factors to consider.
One key component that drives work prioritization is feedback from the IAC team itself.
We like to be very interactive with the Puppet Community contributors and understand what they require.
We will often bring feedback from the community to our stand-ups and more global meetings with Engineering and Product Management.
Through this feedback we&amp;rsquo;re trying to ensure that the user experience is as close to the requirements of the people using and contributing to the product.&lt;/p>
&lt;p>One valuable feedback vector is through the weekly &lt;a href="https://puppet.com/community/office-hours/">Office Hours&lt;/a> sessions.
Once a week, members from the IAC team will down tools and be available to any queries coming in via Slack or the video conferencing session from Puppet Community contributors.
If you need help with module development or testing, or you want to determine the best way to do something with a module on the Forge, then this is the place to get that help and send that feedback.
Quite often, if a limitation or issue in a module has been highlighted here, we will bring this up in our next stand-up meeting, raise a JIRA ticket and ensure that it gets prioritization for resources.
There&amp;rsquo;s no better feedback than the people using actively participating in the module ecosystem and we like to make the most of this valuable resource.&lt;/p>
&lt;h3 id="types-of-work">Types of Work&lt;/h3>
&lt;p>Our number one remit and focus is to ensure that those who want to contribute to the Forge have as frictionless an experience as possible.
That spans everything from a module&amp;rsquo;s lifespan, through initial design / prototyping, to version 1.0.0, right up to the point where it&amp;rsquo;s a veteran module with 100,000s of downloads and a wide and active contributor base.
Our goal is to develop the tools and processes to ensure that is possible.&lt;/p>
&lt;p>One very important aspect of our job is the Content Triage rotation.
Two members of the IAC team will take it in turns to review community contributors to Puppet Forge modules.
We&amp;rsquo;re there to ensure that the change meets the quality standard required but more important, we&amp;rsquo;re there to help contributors understand how to do that.
We&amp;rsquo;re very fortunate to receive lots of high quality contributions or those willing to act upon feedback.
The goal is to ensure that the quality of the Puppet modules remains high, whilst constantly being enhanced and reactive to the needs of the community.&lt;/p>
&lt;h3 id="tech-stack">Tech Stack&lt;/h3>
&lt;p>Some folks may be curious as to what we use day-to-day to get the job done.
There is quite a large amount of software, platforms and tools we use, some you&amp;rsquo;ll likely have heard of and some internal proprietary tools.
For internal tooling, we&amp;rsquo;re in a constant effort to evolve them and make them available for use by the Puppet Community.
We have started a collection on the &lt;a href="https://puppetlabs.github.io/content-and-tooling-team/tools/index.html">tools&lt;/a> page.&lt;/p>
&lt;h4 id="development-and-debugging">Development and Debugging&lt;/h4>
&lt;h5 id="ides">IDEs&lt;/h5>
&lt;p>For the most part, the IDE of choice for us is VSCode.
It has support for Puppet manifests and more via &lt;a href="https://marketplace.visualstudio.com/items?itemName=puppet.puppet-vscode">the Puppet Extension&lt;/a>.
Some of the team also use RubyMine and Sublime Text can also be found on a lot of laptops.
The &lt;a href="https://rubygems.org/gems/pry/">Ruby gem pry&lt;/a> is a heavily utilised one.
This has proven an invaluable tool for debugging during development or investigation when reproducing issues reported to us.&lt;/p>
&lt;h5 id="pdk">PDK&lt;/h5>
&lt;p>Some of you in the Puppet Community will be aware of the Puppet Development Kit (PDK) already.
From the IAC team&amp;rsquo;s use cases it is a very useful tool that allows us to keep modules on the Forge up-to-date with the necessary configuration / metadata changes.
It also allows us to rapidly prototype or develop new modules should someone from the Puppet Community require help.&lt;/p>
&lt;h5 id="pdksync">PDKSync&lt;/h5>
&lt;p>PDKSync is an excellent tool we use to perform and test bulk changes to many modules.
It also allows us to push PRs to Github so we can quickly deploy these changes.&lt;/p>
&lt;h4 id="testing-and-ci-tools">Testing and CI Tools&lt;/h4>
&lt;h5 id="litmus">Litmus&lt;/h5>
&lt;p>Litmus! Litmus is a fantastic resource and probably the most valuable productivity tools that we use day-to-day.
I encourage you to check out the &lt;a href="https://puppetlabs.github.io/litmus/">Docs for Litmus&lt;/a> if you&amp;rsquo;re thinking of becoming a module contributor.
Litmus is a tool that allows us to quickly set up, execute and tear down a test environment for our modules.
You can provision your test environment using Docker or Vagrant.
For the IAC team, we have access to vmpooler, a proprietary tool/API that spins up and tears down virtual machines in our vSphere infrastructure.
In as little as a few seconds, I can have an environment ready to run acceptance tests on all compatible OSs for a given module, or I can have an environment to replicate a specific customer environment (e.g. on Windows Server 2012 R2, with the Scheduled Task module, I was seeing an issue with&amp;hellip;).&lt;/p>
&lt;h5 id="rspec-and-puppet-rspec">RSpec and Puppet RSpec&lt;/h5>
&lt;p>&lt;a href="https://relishapp.com/rspec">RSpec&lt;/a> is the test framework we use to write and execute our unit and acceptance tests.
However, we also have the &lt;a href="https://rspec-puppet.com/">RSpec-Puppet gem&lt;/a> which provides a lot of helper methods to make life easier when testing modules.&lt;/p>
&lt;h5 id="ci-tools">CI Tools&lt;/h5>
&lt;p>We use a number of CI automation servers: Jenkins, Travis, AppVeyor, and most recently Github Actions.
There are different requirements for the variety of modules we have either authored, support, or both, and we are constantly evaluating the best tools / platform for our use cases and those of the Puppet Community.
CI executed test runs from PRs are available from the PR itself - this allows us to quickly determine if there is an issue and drill down in to more specific test log output if we need to, regardless of the platform.&lt;/p></description></item></channel></rss>