jazzace.ca

Anthony’s Mac Labs Blog

📦 AutoPkg Input Variables

Posted 2019 November 11

I’ve made reference to some of the ways AutoPkg Input variables work in previous posts, but a couple of discussions this past week in the #autopkg channel of the MacAdmins Slack plus a recent issue I had with an updated recipe made me think that it was worth documenting this more fully. The big learning for me: there are reasons why you might want to omit some Input variables from an override. But let me start with some AutoPkg fundamentals.

The Default Value for an Input Variable

In an AutoPkg recipe chain (e.g., download-munki, download-pkg-jss), any recipe in the chain can declare an Input variable. Once such a variable is declared, any child of that recipe can reference it; it does not have to be re-declared. However, if you do re-declare it in a child recipe, AutoPkg will use the value assigned in the last declaration in the chain. This makes sense because we give AutoPkg the child recipe’s information when we ask it to run a recipe, so it needs to work backwards through any parent recipes to find all the possible variables and processor steps. This is why recipe overrides work. Since an override is created with all the Input variables used by that recipe chain, AutoPkg doesn’t have to look past the override for the desired value when you run from that override.

Testing 1, 2, 3, 4

I wrote a few recipes (mostly stubs) a while back to test this principle out. If you already understand the concept from my description above, you can skip ahead to the next section. However, if you wish to play with them and do your own experiments, I’ve put them in a repo on my personal GitHub account:

You can add this repo to your AutoPkg instance, even temporarily, by typing autopkg repo-add jazzace/autopkg-recipes in a Terminal session. Alternately, you could copy the recipes into your AutoPkg Recipes folder (usually ~/Library/AutoPkg/Recipes), especially if you wanted to use these as a starting point for your own tests. These InputTest recipes don’t do anything useful — in fact, only the download recipe has any processor steps, and all that one does is interrupt execution based on an Input variable value (using the StopProcessingIf processor).

For completeness, I created 4 typical recipes: download, pkg, munki, and ds. I set the NAME variable to 1 in download, 2 in pkg, 3 in ds, and I omitted the NAME variable in munki. The ds and munki recipes are a child of the pkg recipe and the pkg recipe is a child of the download recipe. I ran each of these recipes “as is” with strict trust verification off; the value of NAME (which you can discern by using 3 levels of verbosity, i.e. -vvv) was 1 for download, 2 for pkg, 3 for ds, and 2 for munki (since it adopted the value of its direct parent, pkg).

I then created an override for each of these recipes and confirmed that the recipe adopts the override variable value as expected. When I changed the value of NAME to 4 in any of these overrides, the StopProcessingIf processor in the first recipe in the chain correctly evaluated NAME as having a value of 4 and stopped processing at that point. I intentionally put the only processor step in the first recipe in the chain to confirm that the value was set from the outset of the run. Hopefully, this is fairly straightforward and is the behaviour you would expect.

(Re-)Declaring

Based on our testing with the mock munki recipe above, we know that we do not need to re-declare any Input variable in a child recipe for that child to be able to use it. Since best practice is now to run all recipes in production from an override (which generally has all the defined Input variables in the chain), the only redeclaration that is important is when we want to change the default value of a variable for a particular child recipe. An example of this is the set of Microsoft Office from the core AutoPkg recipes repo. They consist of a primary parent download recipe, supplemented by product-specific child recipes that simply re-declare the PRODUCT variable and assign a product-appropriate value (e.g., Excel2019). No processor steps are added in those child recipes. (I explained this in detail in a previous post.)

My general practice recently has been to not re-declare Input variables in later child recipes unless I am changing the default value, adding documentation as needed in the Description. If I have no variables to add in a particular child recipe, I use an Input section with an empty dictionary, like so:

<key>Input</key>
<dict/>

Note that omitting the Input section altogether should also work,[1] but I am choosing this style as a reminder that a parent recipe has an Input variable (the NAME variable is almost always present somewhere). Declaring a variable just once should help avoid induced errors (like typos) from needless redeclaration in child recipes.

Input Variables and Overrides

But can we go further? Are there times when we should omit a declared variable from an override? Yes! There is one specific case where doing so is very beneficial, namely when a recipe author has decided to use the Input variable section to establish what is meant to be a constant, such as a download URL or a regular expression (for use with URLTextSearcher, for example). I also wrote about this in that same previous post, pointing out that the main pitfall of this method was that changes to those values would require users to create new overrides or know that they had to change the values in their override manually. By removing those particular variables from the override, AutoPkg will load the default values on each recipe run, just like a constant — if the recipe author updates the values for such an Input variable, you will still have to update trust information, but you will get the new value for the constant(s) for free. Personally, I am still going to hardcode such constants into the recipes that I write, but this method is a great way to work with recipes from others with constants in the Input section. It would have saved me some debugging earlier this month when I encountered just this problem after a recipe update; perhaps you can save yourself the same effort.

Postscript

I promised in a previous post that I was going to write something about the form most download recipes should take, as described in my most recent talk at MacTech Conference. I said it might take the form of updating the AutoPkg Wiki (rather than a post on this blog) and it has. I made fairly significant changes to the Recipe Writing Guidelines page this past week and added a minor update related to this post today. Everything else related to the basic download recipe form was already on the Recipe Format page; it just needed an update to include Trust Verification and to reflect the current state of the examples provided. Since these are fairly significant changes, I encourage those of you who have contributed to the wiki (or wish to do so) to give those pages a look; I didn’t have a proofer.


[1] If you omit the Input section in an override, it will fail strict trust verification. I’ve filed this as an issue. Providing an Input key followed by an empty dict as shown in the body of this article avoids this problem. [Return to main text]