Skip to content
Richard Glaser edited this page Sep 13, 2022 · 7 revisions

Introduction

Demo

pkgctl is a tool focused on packages. Some packages, especially web browsers, are updated so often it is a major burden to keep them up-to-date. pkgctl aims to make working with packages much easier. It looks at the server data from the viewpoint of the package, that is, it finds every policy, patch software title, patch policy, and computer group that includes a reference to each package and it lets you work with this data from the package viewpoint.

Without any arguments pkgctl goes into an interactive mode that lets you select package groups and easily move the policies, patch policies, and computer groups from one package version to another (see the example above). Specifying -c, -g, or -u causes pkgctl to print the information in different formats (for viewing groups, usage, and clean up). Specifying -p causes pkgctl to go through all patch software titles and their versions and set the package definitions if they match a regular expression.

Getting Help

To display help use the help command with jctl you can enter the following arguments:

pkgctl --help or pkgctl -h

This is the current usage at the time of this writing.

usage: pkgctl [-h] [-c] [-p] [-g] [-u] [-a [AUTO_PROMOTE [AUTO_PROMOTE ...]]] [-i [ID [ID ...]]] [-n [NAME [NAME ...]]] [-r [REGEX [REGEX ...]]] [-C CONFIG] [-v]

optional arguments:
  -h, --help            show this help message and exit
  -c, --cleanup         Show packages sorted by usage
  -p, --patch-definitions
                        Set patch definitions
  -g, --groups          Display packages as groups and exit
  -u, --usage           Display package usage and exit
  -a [AUTO_PROMOTE [AUTO_PROMOTE ...]], --auto-promote [AUTO_PROMOTE [AUTO_PROMOTE ...]]
                        Automatically update policies, groups, and patch policies that match supplied regular expression.
  -i [ID [ID ...]], --id [ID [ID ...]]
                        Search for id matches
  -n [NAME [NAME ...]], --name [NAME [NAME ...]]
                        Search for exact name matches
  -r [REGEX [REGEX ...]], --regex [REGEX [REGEX ...]]
                        Search for regular expression matches
  -C CONFIG, --config CONFIG
                        path to config file
  -v, --version         print version and exit

Performance

Except when printing package groups and setting patch definitions, pkgctl retrieves all the data from every policy, patch software title, patch policy, and computer group on your Jamf Pro server. Because of this, pkgctl can take awhile to run. In a simple test, retrieving 300 of these records took about 27 seconds, or about 11 requests per second. pkgctl has the ability to limit package records, but loading package data isn't what takes so long, it's loading all the related data, so limiting packages doesn't improve performance.

The only saving grace is that the main usage scenario for pkgctl is interactive and so you only need to load the data once. As long as the server data doesn't change while pkgctl is running it should be good. When pkgctl changes the server data it will reload the relevant data, which only takes a second.

Interactive Mode

Without any arguments pkgctl goes into interactive mode that prints out a list of all of your packages organized in groups that are similarly named. It then asks to pick a group or some other options.

See the example above to see it in action.

Note, pkgctl looks at the "packages installed by Casper" criteria in smart computers groups. It doesn't look at or change policy or group names, but it might in the future.

Package Grouping

The package grouping is determined in jamf/records.py, Package.parse_package_name. It uses the following regular expressions to group packages. If the first one doesn't match it tries the second one.

([^-]*)-(.*)\.([^\.]*)$
([^-]*)\.([^\.]*)$

If these aren't working for you and you want to hack it yourself, pkgctl -g is specifically for seeing how the groupings are working for you. Please contribute if you improve this mechanism.

Here's an example. Again, all of these package names were created by AutoPkg recipes.

1Password
  1Password-7.8.6.pkg
  1Password-7.8.7.pkg
  1Password-7.8.8.pkg
  1Password-7.9.1.pkg
  1Password-7.9.pkg
BBEdit
  BBEdit-14.0.1.pkg
  BBEdit-14.0.2.pkg
  BBEdit-14.0.pkg
Box Drive
  Box Drive-2.22.445.pkg
  Box Drive-2.23.422.pkg
  Box Drive-2.24.193.pkg
  Box Drive-2.24.198.pkg
Brave Browser
  Brave Browser-1.28.105.0.pkg
  Brave Browser-1.28.106.0.pkg
  Brave Browser-1.29.76.0.pkg
  Brave Browser-1.29.77.0.pkg
  Brave Browser-1.29.79.0.pkg
  Brave Browser-1.29.80.0.pkg
  Brave Browser-1.29.81.0.pkg
  Brave Browser-1.30.86.0.pkg
  Brave Browser-1.30.87.0.pkg
  Brave Browser-1.30.89.0.pkg
  Brave Browser-1.31.87.0.pkg
  Brave Browser-1.31.88.0.pkg
  Brave Browser-1.31.91.0.pkg
  Brave Browser-1.32.106.0.pkg
Dropbox
  Dropbox-126.4.4618.pkg
  Dropbox-127.4.4265.pkg
  Dropbox-128.4.2870.pkg
  Dropbox-129.4.3571.pkg
  Dropbox-130.4.4978.pkg
  Dropbox-131.4.3968.pkg
  Dropbox-132.4.3800.pkg
  Dropbox-133.4.4089.pkg
  Dropbox-134.3.4107.pkg
  Dropbox-134.3.4111.pkg
  Dropbox-134.4.4115.pkg
  Dropbox-135.4.4221.pkg
  Dropbox-136.3.4318.pkg
Firefox
  Firefox-90.0.1.pkg
  Firefox-90.0.2.pkg
  Firefox-91.0.1.pkg
  Firefox-91.0.2.pkg
  Firefox-91.0.pkg
  Firefox-92.0.1.pkg
  Firefox-92.0.pkg
  Firefox-93.0.pkg
  Firefox-94.0.1.pkg
  Firefox-94.0.2.pkg
  Firefox-94.0.pkg
GoogleChrome
  GoogleChrome-94.0.4606.81.pkg
  GoogleChrome-95.0.4638.54.pkg
  GoogleChrome-95.0.4638.69.pkg
  GoogleChrome-96.0.4664.45.pkg
  GoogleChrome-96.0.4664.55.pkg
Visual Studio Code
  Visual Studio Code-1.58.2.pkg
  Visual Studio Code-1.59.0.pkg
  Visual Studio Code-1.59.1.pkg
  Visual Studio Code-1.60.0.pkg
  Visual Studio Code-1.60.1.pkg
  Visual Studio Code-1.60.2.pkg
  Visual Studio Code-1.61.0.pkg
  Visual Studio Code-1.61.1.pkg
  Visual Studio Code-1.61.2.pkg
  Visual Studio Code-1.62.0.pkg
  Visual Studio Code-1.62.1.pkg
  Visual Studio Code-1.62.2.pkg
  Visual Studio Code-1.62.3.pkg
Zoom
  Zoom-5.7.3.809.pkg
  Zoom-5.7.4.898.pkg
  Zoom-5.7.5.1123.pkg
  Zoom-5.7.6.1320.pkg
  Zoom-5.8.0.1780.pkg
  Zoom-5.8.1.1983.pkg
  Zoom-5.8.3.2240.pkg
  Zoom-5.8.4.2421.pkg
iTerm2
  iTerm2-3.4.10.pkg
  iTerm2-3.4.11.pkg
  iTerm2-3.4.12.pkg
  iTerm2-3.4.8.pkg

Set Patch Definitions

pkgctl -p will go through all patch software titles and their versions and set the package definitions if they match a regular expression.

% pkgctl -p
Updating patch definitions...
Matched Zoom-5.8.4 (2421).pkg
Matched Zoom-5.8.3 (2240).pkg
Matched Zoom-5.8.1 (1983).pkg

It is possible to limit the titles modified by using -i <id>, -n <name> or -r <regex>.

The regular expresion that controls this matching is loosely based off of package names that are created by common AutoPkg recipes. The regular expression is found in jamf/records.py, PatchSoftwareTitle.set_all_packages_update_during.

.*<patch-software-title>.*<patch-version>\.pkg"

There is also a dictionary of regular expressions for software titles that don't work with the above regular expression. It is in the same set_all_packages_update_during method. It's mostly based off of my packages and I realize it should probably be lengthened and generalized more. Community help here would be appreciated, especially if we can get AutoPkg to standardize packages names.

The keys listed in policy_regex are patch software title names that Jamf uses. The value is the regular expression to match packages.

        policy_regex = {
            '1Password 7': '^1Password-%VERSION%\.pkg',
            'Apple GarageBand 10': '^GarageBand-%VERSION%\.pkg',
            'Apple Keynote': '^Keynote-%VERSION%\.pkg',
            'Apple Numbers': '^Numbers-%VERSION%\.pkg',
            'Apple Pages': '^Pages-%VERSION%\.pkg',
            'Apple Xcode': '^Xcode-%VERSION%\.pkg',
            'Apple iMovie': '^iMovie-%VERSION%\.pkg',
            'Arduino IDE': '^Arduino-%VERSION%\.pkg',
            'Bare Bones BBEdit':'BBEdit-%VERSION%\.pkg',
            'BusyCal 3': '^BusyCal-%VERSION%\.pkg',
            'Microsoft Remote Desktop 10': '^Microsoft Remote Desktop-%VERSION%\.pkg',
            'Microsoft Visual Studio Code': '^Visual Studio Code-%VERSION%\.pkg',
            'Microsoft Teams': '^Microsoft_Teams_%VERSION%\.pkg',
            'Mozilla Firefox': '^Firefox-%VERSION%\.pkg',
            'R for Statistical Computing': '^R-%VERSION%\.pkg',
            'RStudio Desktop': 'RStudio-%VERSION%\.dmg',
            'Sublime Text 3': 'Sublime Text-%VERSION%\.pkg',
            'VLC media player': 'VLC-%VERSION%\.pkg',
            'VMware Fusion 12': 'VMware Fusion-%VERSION%\.pkg',
            'VMware Horizon 8 Client': 'VMwareHorizonClient-%VERSION%.pkg',
            'Zoom Client for Meetings': 'Zoom-%VERSION%.pkg',
        }