Munki uses information from the pkginfo file and looks for the software items to decide whether or not a given item must be installed. To create a functional pkginfo item, understand the methods used by Munki to check the list of software items.
Methods
In the order of precedence, Munki uses the following methods to determine if the given item needs to be installed (or removed):
- Install macOS Applications using the Check Script
- Install macOS Applications using the Install Items
- Install macOS Applications using the Receipts
When combining these methods, only the highest priority method is used. For example, if a given pkginfo item has both an "installs" list and a "receipts" list, the receipts is ignored for purposes of determining the installation status. Even in this case, though, receipts may be used when removing an item, as they help Munki determine exactly which files were installed.
Install macOS Applications using the Check Script
A pkginfo item may optionally contain an installcheck_script. Install ckeck script provides a method for determining if an software item needs to be installed, where providing installs/receipts is inadequate or impractical.
Command-line tools typically installed through port (macports) or Python modules installed using easy_install or pip are prime examples as they provide no easy method for determining their installed version.
An install check_script should be written such that an exit code of 0 indicates that the item is currently not installed and should therefore be installed. All non-zero exit codes indicate that the item is installed.
An example of installcheck_script illustrating a check to determine if the current version of the argparse Python module is installed.
#!/bin/sh# Grab current version of installed python moduleversion="$(python -c 'import argparse;print argparse.__version__' 2>/dev/null)"# Compare with the version we want to installif [ ${version:-0} < 1.2.1 ]; thenexit 0elseexit 1fi
Optionally, an explicit uninstallcheck_script can be provided to determine whether or not an software item should be removed. In this case, the script with an exit code of 0 indicate that the item is currently installed and that removal should occur. All non-zero exit codes indicate that the item is not installed.
Install macOS Applications using the Install Items
The install items list is generated by the VMware AirWatch Admin Assistant for some types of installation items(.dmg), but not for Apple packages (.pkg or .mpkg). You can generate (or modify) this list and is the most flexible mechanism for determining the installation status.
The installs list can contain any number of items such as applications, preference panes, frameworks, or other bundle-style items, info.plists, simple directories, or files. You can use any combination of items to help Munki determine if an item is installed or not.
An example of an auto-generated "installs" list for Firefox 6.0
<key>installs</key><array>
<dict>
<key>CFBundleIdentifier</key>
<string>org.mozilla.firefox</string>
<key>CFBundleName</key>
<string>Firefox</string>
<key>CFBundleShortVersionString</key>
<string>6.0</string>
<key>minosversion</key>
<string>10.5</string>
<key>path</key>
<string>Applications/Firefox.app</string>
<key>type</key>
<string>application</string>
</dict>
</array>
To determine if Firefox 6 is installed or not, Munki checks for an application with a CFBundleIdentifier of org.mozilla.firefox and if found, verifies that its version (CFBundleShortVersionString) is at least 6.0. If Munki cannot find the application or its version is lower than 6.0, it considers Firefox-6.0 as not installed. Installs lists can contain multiple items. If any item is missing or has an older version, the item is considered not installed. You can manually generate items to add to an installs list using the following pkginfo:
/Library/Application\ Support/AirWatch/Data/Munki/bin/makepkginfo -f /Library/Interne
t\ Plug-Ins/Flash\ Player.plugin
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/Prope
rtyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>installs</key>
<array>
<dict>
<key>CFBundleShortVersionString</key>
<string>10.3.183.5</string>
<key>path</key>
<string>/Library/Internet Plug-Ins/Flash Player.plugin</string>
<key>type</key>
<string>bundle</string>
</dict>
</array>
</dict>
</plist>
Copy and paste the entire installs key and value, or copy the dict value and add it to an existing installs list inside your pkginfo file. Munki checks for the existence of /Library/Internet Plug-Ins/Flash Player.plugin and if found, check its version. If the version is lower than 10.3.183.5, the item is be considered not installed. You can generate installs items for any filesystem item, but Munki only knows how to determine the versions for bundle-style items that contain an Info.plist or version.plist with the version information.
For other filesystem items, Munki can only determine the existence of a non-bundle directory, or can calculate a checksum (for files). For files with checksums, the test fails (and therefore the item is considered not installed) if the checksum for the file on disk does not match the checksum in the pkginfo.
<key>installs</key>
<array>
<dict>
<key>md5checksum</key>
<string>087fe4805b63412ec3ed559b0cd9be71</string>
<key>path</key>
<string>/private/var/db/dslocal/nodes/MCX/computergroups/loginwindow.plist</s
tring>
<key>type</key>
<string>file</string>
</dict>
</array>
If you want Munki to only check for the existence of a file and do not care about its contents, remove the generated md5checksum information in the installs item info. Make sure the provided path is intact.
<key>installs</key>
<array>
<dict>
<key>path</key>
<string>/private/var/db/dslocal/nodes/MCX/computergroups/loginwindow.plist
</string>
<key>type</key>
<string>file</string>
</dict>
</array>
Install macOS Applications using the Receipts
When an Apple-style package is installed, you can generate a receipt on the machine. Metapackages generate multiple receipts. The VMware AirWatch Admin Assistant adds the names and versions of those receipts to a receipts array in the pkginfo for a package.
Following is a receipts array for the Avid LE QuickTime codecs, version 2.3.4.
<key>receipts</key>
<array>
<dict>
<key>filename</key>
<string>AvidCodecsLE.pkg</string>
<key>installed_size</key>
<integer>1188</integer>
<key>name</key>
<string>AvidCodecsLE</string>
<key>packageid</key>
<string>com.avid.avidcodecsle</string>
<key>version</key>
<string>2.3.4</string>
</dict>
</array>
If Munki is using the receipts array to determine the installation status, it verifies for the existence and the version of each receipt in the array. If any receipt is missing or has a lower version number than the version specified for that receipt in the receipts array, the item is considered not installed. Only if every receipt is present and all versions are the same as the ones in the pkginfo (or higher) is the item considered installed. To troubleshoot issues, use the pkgutil tool to examine the installed receipts.
# pkgutil --pkg-info com.avid.avidcodecsle
No receipt for 'com.avid.avidcodecsle' found at '/'.
In this case, the receipt for the Avid LE QuickTime codecs was not found on this machine. A common complication with receipts is, with many metapackages, the installation logic results in only a subset of the subpackages being installed. Generally, the receipts list contains a receipt for every subpackage in a metapackage (and needs this info if Munki is asked to remove the software item based on package receipts). But if it is normal and expected that not every subpackage is installed, Munki marks the item as not currently installed and offer to install it again and again. One solution for this issue is to add an optional key with the value of true to the receipts that are optionally installed. Munki does not consider these receipts when determining installation status.
<key>receipts</key>
<array>
<dict>
<key>filename</key>
<string>mandatory.pkg</string>
<key>installed_size</key>
<integer>1188</integer>
<key>name</key>
<string>Mandatory</string>
<key>packageid</key>
<string>com.foo.mandatory</string>
<key>version</key>
<string>1.0</string>
</dict>
<dict>
<key>filename</key>
<string>optional.pkg</string>
<key>installed_size</key>
<integer>1188</integer>
<key>name</key>
<string>Optional</string>
<key>optional</key>
<true/>
<key>packageid</key>
<string>com.foo.optional</string>
<key>version</key>
<string>1.0</string>
</dict>
</array>
Another solution for this situation is to provide the intalls array with the lists items that are installed by the package. Munki can use the installs array information instead of the receipts to determine the installation status.