Viewing entries tagged
package

Munki Business - A Guide to Munki 2

4 Comments

Munki Business - A Guide to Munki 2

A lot has changed since my original post on Munki 1, with Munki 2 well and truly out I have taken the opportunity to write an updated guide on Munki 2.

What is Munki?

Munki is a community driven project created by Greg Neagle, allowing IT Administrators to efficiently deploy software to large numbers of Macs.

A Munki implementation can be broken down into two core parts;
a) repository hosted on a web server
b) bunch of clients running the Munki software
 

A Munki Repository

Since a Munki repository is simply a collection of organised files served out by a web server it can be hosted on any web server (e.g. IIS, Apache, etc.) regardless of platform. In the situation where the repository is hosted on a remote server, Administrators can remotely edit the repository over a network share.

Every Munki repository is comprised of the following four directories:
pkgs: All package (.pkg) and disk image (.dmg, .iso) files.

pkgsinfo: For each piece of software in the pkgs directory there is an associated file in pkgsinfo. These files contain detailed information about that piece of software and the catalog(s) that software is assigned to. Conventionally these pkgsinfo files have the .plist extension.

catalogs: Catalog files are generated from the contents of pkginfo files, they are used to separate production (tested) from development (untested) versions of software.

manifests: Clients are configured to download a particular manifest file. These manifest files contain a list of software to install and the catalog (version) to use.

Note: Apart from the contents of pkgs every other directory contains standard Extensible Markup Language (XML) files.

With the release of Munki 2, there are three additional directories:
artwork: A place to store any images used within software descriptions.

client_resources: Home to the Managed Software Center application theme files.

icons: Contains images (.png) used as software icons in the Managed Software Center application. The recommended icon resolution is 300x300.

Setting Up a Repository

The steps for setting up a Munki repository vary depending on web server and platform. For OS X the standard procedure involves creating a ‘munki_repo’ directory in ‘/Users/Shared/‘, populating it with the directories listed above. Then creating a symbolic link from ‘/Users/Shared/munki_repo’ to ‘/Library/Server/Web/Data/Sites/Default/’ and enabling the OS X Server web server.

Managing Munki Repositories

Download and install the latest release of Munki Tools here.

Part of Munki Tools are the Munki Admin Tools for command-line management of Munki repositories. Unless you enjoy working purely in the command-line, I recommend downloading Hannes Juutilainen’s MunkiAdmin, a user-friendly application for managing Munki repositories. 

Install AutoPkg

AutoPkg automates the process of downloading and importing third party software updates straight into the Munki repository. Look at setting up AutoPkg by following my guide here.

Manually Importing New Software

If you wish to manually import a piece of software here are the steps:

Before we can use the Munki Admin Tools we need to complete the initial setup. To start the setup open Terminal and type:

munkiimport --configure

The 'Repo fileshare URL' can be left blank if the Munki repository is stored on the local disk, otherwise provide a network share path (e.g. smb://SERVERADDRESS/munki_repo).

I recommend following the guidelines below, to keep your Munki repository tidy:
First rename the software you wish to import:

  • Match the name to the software (e.g. jre-7u67-macosx-x64.dmg > java.dmg).
  • Only use lowercase letters (e.g. Firefox 32.0.3.dmg > firefox.dmg).
  • Do not use dashes, underscores or spaces (e.g. Skype_6.19.0.452.dmg > skype.dmg).
  • Delete version numbers (e.g. vlc-2.1.5.dmg > vlc.dmg).
  • Omit the developer’s name (e.g. googlechrome.dmg > chrome.dmg).

Once renamed open Terminal and type ‘munkiimport ‘ (take note of the trailing space).
Drag the renamed package onto the Terminal window and hit return.
When prompted for an item name enter the name of the package without the extension (e.g. firefox.dmg > firefox).
The display name can contain spaces and capitals (e.g. Flash Player).
The description can be left blank for now, as it can be added in later with MunkiAdmin.
The version number is pulled from the software, verify it is accurate and hit return, otherwise type in the correct version number.
When prompted for a category, use the Mac App Store categories as a guide (e.g. Productivity, Utilities, etc).
Enter the developer’s name (e.g. Apple, Google, etc).
When prompted for Catalogs hit return.
You will be presented with a summary of your input, if you are happy that it is all correct type y and hit return.
Just hit return when asked for a subdirectory path.
Munki may offer to extract an icon, type y and hit return. 
You are given a chance to make any alterations to the newly generated pkginfo file, simply press control + X.
Lastly you are asked if you would like to rebuild catalogs, type y and hit return.

Assigning Software to Manifests

To put it simply manifests contain lists of software to install and the catalogs (software version) to use. Software can either be set as mandatory (managed_installs) or optional (optional_installs). Optional installs provide a self-service experience similar to the Mac App Store.

MunkiAdmin makes the process of assigning software to manifests simple, just add a new item under either the Installs tab (mandatory) or the Optional Installs tab.

As seen in the diagram below, every Mac installs a SOE (Standard Operating Environment) suite of software. Depending on the Mac’s location (e.g. Art, Music, etc.) and the intended user type (e.g. staff or student), additional software (e.g. Photoshop, Sibelius, etc.) is installed. Since Munki clients can only check a single manifest, I have dealt with this limitation by stacking manifests.

It may seem confusing at first, but once the manifest infrastructure is in place, assigning new software to all relevant clients is simple. The green bubbles are manifests that clients check and we normally avoid adding any software directly to these. Yellow are purely for merging manifests, again nothing should be added to these. Blue are core attributes (e.g. laptop, staff, science, etc.) and software is assigned to these.

Configuring Munki Clients

Once Munki Tools is installed, clients need to be configured with the Munki repository's address and which manifest to check. Often these settings are configured using DeployStudio, a payload-free package or another means of script execution. This can be performed manually in Terminal with:

defaults write /Library/Preferences/ManagedInstalls.plist SoftwareRepoURL http://SERVERADDRESS/munki_repo
defaults write /Library/Preferences/ManagedInstalls.plist ClientIdentifier MANIFESTNAME

Testing Software

Before pushing out software to every Munki client it is important to thoroughly test that it works as expected. You should configure at least one test machine the same way as the rest of your client’s with the exception of pointing it to a testing manifest.

A testing manifest should include both the development and production catalogs, as well as a manifest directly accessed by clients.

Once that piece of software has been deemed stable, add it to the production catalog and watch as the rest of your clients install it.

Frequently Asked Questions

If you have read this far, you should be starting to get an understanding of how useful and feature rich Munki is. For readability I have chosen to tackle common queries I receive regarding Munki.

How does Munki know what is already installed?
Any applications installed by simply dragging and dropping them into Applications are detected by Munki. If a user deletes a drag and drop app from Applications Munki will notice its absence and reinstall it.

With package files, Munki indirectly checks for the existence of receipt files, therefore deleting the associated .plist and .bom files of a package in /var/db/receipts will cause Munki to reinstall that package.

Managed Software Center keeps attempting to install the same package over and over. What’s going wrong?
If MSC loops on a package, compare the receipts listed in the pkginfo file to the receipts present in the '/var/db/receipts/' directory. Once you figure out the missing receipt(s) mark them as optional (ignored).

You can also use Terminal’s ‘pkgutil’ command to search for installed receipts. In the example below I am searching for receipts containing the word xerox, the (?i) part ignores case and .* are wildcards.

Can we customise the banners in Managed Software Center?
Absolutely! You can even customise the sidebar and footer links. The official Munki wiki does a great job covering this in detail here.

How frequently does Munki check for updates?
After ten seconds of inactivity at the login window Munki will automatically install any locally cached updates.

By default a launch daemon is set to run ‘/usr/local/munki/supervisor’ ten minutes past every hour. The supervisor generates a random delay of up to sixty minutes to help stagger clients contacting the Munki repository. Once the delay is over supervisor triggers ‘/usr/local/munki/managedsoftwareupdate’, if there are new updates the logged in user is notified by Managed Software Center.

Note: Munki is also capable of installing software without any user intervention. This is achieved  by enabling 'Unattended install' in MunkiAdmin.

Will Managed Software Center work outside of the organisation?
As long as the web server hosting the Munki repository is externally accessible MSC will also work externally. If you plan on hosting a Munki repository on a public web server you should also configure SSL Client Certificates to ensure access to the repository is limited to permitted clients. 

How can I remotely trigger Munki clients to check for updates?
Using Apple Remote Desktop you can trigger groups of Macs to instantly check the Munki repository for updates and install.

Trigger Munki instantly regardless of whether a user is logged in:

/usr/local/munki/managedsoftwareupdate;/usr/local/munki/managedsoftwareupdate --installonly

Trigger Munki to run the moment the current user logs out or if nobody is currently logged in:

touch /Users/Shared/.com.googlecode.munki.checkandinstallatstartup

Tip: You can save those commands as Unix command templates in ARD.

How do I go about troubleshooting a Munki issue?
Since the Munki repository is just a bunch of files served out by a web server, almost all troubleshooting is performed from Munki clients.

On a client open Terminal and run:

sudo managedsoftwareupdate

This will immediately display any issues with the repository. You can also check the client log files stored in ‘/Library/Managed Installs/Logs/‘.

How do we update the version of Munki Tools running on clients?
AutoPkg makes it easy to keep your Munki clients up-to-date with frequently updated software (e.g. Flash Player, Java, etc.). You can quickly set up AutoPkg by following my guide here. There is a munkitools2.munki.recipe override included in my collection of recipe overrides. This will automatically import the latest release of Munki Tools into your Munki repository, as four separate packages:
munkitools_core.pkg: The required core command-line tools used by Munki.
munkitools_admin.pkg: The optional admin command-line tools for managing Munki repositories.
munkitools_app.pkg: The user-friendly Managed Software Center application.
munkitools_launchd.pkg: The launchd items to automate checking for updates.

The only package that should be assigned to a manifest is the munkitools_app, the rest are either marked as ‘required’ or ‘update for’ packages that would be installed regardless.

4 Comments

Capturing Package Files with PkgKeeper

2 Comments

Capturing Package Files with PkgKeeper

Deploying software via Munki is an excellent asset to sites managing fleets of Macs. Sometimes however, a package will not be listed directly on Apple's Support website and also may not be taking advantage of OS X Server's Caching Service. This is why I created the script PkgKeeper. The script works by monitoring filesystem access and if a pkg or dmg file is detected a hard link of the file is created on the user’s desktop.

At this point you may be asking yourself “what is a hard link?” Every unique file on a Unix (the foundation of OS X) filesystem has an inode (index node). One of the attributes of an inode is ‘link count.’ The link count is the number of hard links to a file.

Normally a file has a link count of just one, but when a new hard link is created that link count is incremented by one. Naturally, removing a file decrements the link count by one. It is not until the link count reaches zero that the inode is removed and the space is marked as available for use.

Under normal circumstances once an update package is installed and the package is removed the file's link count goes from one to zero. However, PkgKeeper creates another hard link of the file while it is still in use setting the file's link count to two. This stops the file from hitting a link count of zero and being completely removed.

 

Using The Script

Open Terminal and paste the following to download the script:

curl -O https://raw.githubusercontent.com/Error-freeIT/PkgKeeper/master/pkgkeeper.sh

Make the script executable:

chmod +x pkgkeeper.sh

Run the script:

sudo ./pkgkeeper.sh

Start downloading an update and watch as the script captures the package file.

Note for OS X 10.11 users: El Capitan's System Integrity Protection prevents this script from working. To temporally disable SIP boot into a recovery partition or 10.11 USB installer, open Terminal and type 'csrutil enable --without dtrace'.

Bonus Tips

In Terminal you can view a file's link count with the command:

stat -f '%l' FILE_NAME

The inode also contains the User ID, Group ID and file mode attributes of the file. Therefore all hard links will have the same user, group ownership and access permissions.

Once the update is installed the original process deletes its hard link to the file. This means it is no longer accessing the file and we are safe to edit the file's ownership. The easiest way to do this is by editing the 'Sharing & Permissions' section in the 'Get Info' window.

2 Comments

Creating OS X Package Files (.pkg) In Terminal

6 Comments

Creating OS X Package Files (.pkg) In Terminal

2018 Update

Everything below still works, but for the past few years I have been using munkipkg for the generation of all my packages. Although Munki is in the name, it is just a nice command-line tool by Greg Neagle for creating packages.

OS X includes a handy Terminal tool called ‘pkgbuild’ for compiling package installer files.

To demonstrate pkgbuild I will use my 'Enable ARD' (Apple Remote Desktop) package.

This package places an enableard.sh script into /Library/Scripts/Enable ARD/ and creates a LaunchDaemon to run that script on boot. The enableard.sh script simply removes all users from Remote Management (ARD) and then gives full access to a specified username, ensuring that user has remote access.

Structure

To keep things organised when creating a package, I create a directory consisting of the following files and folders:

build.sh: Includes the package name, versioning information and is used to compile the package.

complied: Is where the product of build.sh is written.

files: Contains the files the package will copy into place.

scripts: Can contain preinstall and/or postinstall scripts. A preinstall script is run before the contents of files is copied into place, whereas postinstall is after. It is important not to give these script files an extension.

Contents of build.sh:

#!/bin/bash

# Name of the package.
NAME="enableard"

# Once installed the identifier is used as the filename for a receipt files in /var/db/receipts/.
IDENTIFIER="au.com.errorfreeit.$NAME"

# Package version number.
VERSION="1.0"

# The location to copy the contents of files.
INSTALL_LOCATION="/Library/Scripts/Enable ARD"


# Remove any unwanted .DS_Store files.
find files/ -name '*.DS_Store' -type f -delete

# Set full read, write, execute permissions for owner and just read and execute permissions for group and other.
/bin/chmod -R 755 files

# Remove any extended attributes (ACEs).
/usr/bin/xattr -rc files

# Build package.
/usr/bin/pkgbuild \
    --root files/ \
    --install-location "$INSTALL_LOCATION" \
    --scripts scripts/ \
    --identifier "$IDENTIFIER" \
    --version "$VERSION" \
    "compiled/$NAME-$VERSION.pkg"

 

Contents of scripts/postinstall:

#!/bin/bash

# Filename of script.
NAME="enableard.sh"

# Path to script.
PATH="/Library/Scripts/Enable ARD"

# Script identifier (same as package identifier).
IDENTIFIER="au.com.errorfreeit.enableard"


LAUNCH_DAEMON_PLIST="/Library/LaunchDaemons/$IDENTIFIER.plist"

# Write LaunchDaemon plist file.
echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>'$IDENTIFIER'</string>
    <key>ProgramArguments</key>
    <array>
        <string>'$PATH/$NAME'</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>' > "$LAUNCH_DAEMON_PLIST"

# Load the new LaunchDaemon.
/bin/launchctl load "$LAUNCH_DAEMON_PLIST"

# Check LaunchDaemon is loaded.
STATUS=`/bin/launchctl list | /usr/bin/grep $IDENTIFIER | /usr/bin/awk '{print $3}'`

if [ "$STATUS" = "$IDENTIFIER" ]
then
        echo "Success: LaunchDaemon loaded."
        exit 0      
else
        echo "Error: LaunchDaemon not loaded."      
        exit 1
fi

 

Contents of files/enableard.sh:

#!/bin/bash

# Username of account used for ARD access.
USER="ardadmin"

# Revoke ARD access for all users.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -off

# Assign full privileges to an ARD Administrator account.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -users $USER -privs -all -restart -agent -menu

# Set Remote Management to only accept the user specified.
/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -allowAccessFor -specifiedUsers

Ready To Compile

To compile a package:

Open Terminal,

type 'cd ' (change directory),

drag the folder containing build.sh into Terminal and hit return,

type 'chmod +x build.sh' to make it executable,

lastly type ‘./build.sh’ and hit return.

You should now have a new package file in the compiled directory.

Bonus Tips

Use Full Paths

When writing scripts it is important to include the full path to any binaries used. You can easily find the full path of a binary with the ‘which’ command.

Check Your Packages

Sometimes I want to know what a package would do without running it. This is where the Finder QuickLook plug-in called ‘Suspicious Package’ comes in handy, as it shows where files would be copied and the contents of any preinstall and postinstall scripts. I also like to use Suspicious Package on my own package files to ensure files are being copied into the correct directory and any scripts are present.

Read The Manual

My example build.sh script does not take advantage of pkgbuild’s complete feature-set, for example packages can also be signed to prove authenticity. If you want to know more about pkgbuild simply read the man (manual) file, by typing ‘man pkgbuild’ into Terminal.

6 Comments