Keep Mac laptop carts up-to-date with Munki and NoSleep

What's the problem?
NoSleep nuances
A work-in-progress solution

What's the problem?

Munki is a great tool for keeping laptops and desktops up to date. For normal laptops, I basically have Munki check in every hour or so (as it does by default) but not bother the user for 14 days. So unattended installs can happen in the background and then twice a month users can take care of logout/reboot updates. For desktops, I have a substitute Launch Daemon run once a day before school starts to keep those machines up to date and then not bother the users throughout the day.

The problem comes with laptop carts. The machines in those carts usually have their lids shut and don't get used often enough or long enough to get all the updates via Munki. The other half of that problem is Apple making it so laptops always go to sleep when the lid is closed (unless the laptop is plugged into an external monitor).

I've done a lot of research and experimentation, and this is the best thing I could come up with (haven't had any luck with Munki Overnight and don't want to use InsomniaX while they're still figuring out licensing/distribution). Since I haven't found any working, step-by-step tutorials on how to do this, I figure it's better to have something than nothing. If I get a more streamlined process, I'll update this post or create a new post.

NoSleep nuances

Some nuances I've discovered about NoSleep based on research and trial/error:

  • It isn't optimized for El Capitan, because it still writes the extension to /System/Library/Extensions instead of just /Library/Extensions. Apparently, that's okay according to OS X 10.11 El Capitan: The Ars Technica Review (you can add and remove your own custom extensions but can't touch the ones that are already in there) and my own testing, but it's still good practice to avoid that directory altogether. In production, I'm running this on only Yosemite clients, so I don't know if NoSleep actually functions well in El Capitan. It runs fine on El Capitan clients.
  • In addition to preventing sleep, it also appears to prevent scheduled shutdowns. Manual reboots seem to work.
  • When NoSleep is active, closing the laptop lid will still turn off the laptop screen (I believe so anyway, based on the lighted Apple logo turning off) even though the laptop is still on. I'm hoping (but haven't done extensive testing yet) this will stop the laptop from overheating (since it's on but inactive and with the screen not on). The laptops seem to heat up a bit, but not too much. Definitely no overheating issues.
  • There's an optional command-line utility you can install when you go through the install wizard, but it doesn't seem to have options to enable NoSleep the same way you can through point-and-click on the taskbar icon. (I futzed around with the CLI tool... maybe I'm missing something?) Honestly, I don't mind manually enabling it on a bunch of laptops if it means I don't have to manually periodically run Munki on them.
tl;dr version: you may have to manually enable NoSleep once on each client, but it will still save you time in the long run.

A work-in-progress solution

Download the latest release of NoSleep, which is a kernel extension that can prevent the Mac laptop from going to sleep when the lid is closed. Import its package into Munki to distribute out to client machines in the laptop carts.

enablenosleep01 On each laptop (haven't found a way to automate this yet), launch up and enable NoSleep.

Once NoSleep is working, the laptop is basically just on all the time (with the screen off when the lid is closed), so you can create a modified version (keep the original but just unload it) of the roughly-once-an-hour Launch Daemon so it runs once a day.

Here's an example /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.revised.plist you can package up and distribute out to clients:

<?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>com.googlecode.munki.managedsoftwareupdate-check.revised</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/munki/supervisor</string>
<string>--delayrandom</string>
<string>900</string>
<string>--timeout</string>
<string>43200</string>
<string>--</string>
<string>/usr/local/munki/managedsoftwareupdate</string>
<string>--auto</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>6</integer>
<key>Minute</key>
<integer>10</integer>
</dict>
</dict>
</plist>
This basically tells the laptop to run Munki once in the morning some time after 6:10am.

Unload the original:

sudo launchctl unload -w /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist
and load up your revised one:
sudo launchctl load -w /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.revised.plist

You may also want to install some kind of auto-logout script (that nopkg .plist will log out normal users after 5 minutes of inactivity, but you can tweak the logout time). If you need to force a logout (for example, with a guest user account), you can use this command:

osascript -e 'tell application "loginwindow" to «event aevtrlgo»'

With your laptops not going to sleep and then checking in with Munki once in the morning at the login screen, they should be good and updated.

P.S. I haven't had a chance to test this out extensively yet, but Greg Neagle (primary author of Munki) has confirmed that (as of this writing) invoking managedsoftwarecenter from the command line does not check for battery life (Managed Software Center will prompt the user about whether to continue or not on low battery), so I've toyed around with using a modified version of the MunkiOvernight script to check the battery before running the update.

P.P.S. Upgrades from Yosemite to El Capitan don't often happen smoothly with the lid shut and the NoSleep extension activated. I would highly recommend doing that upgrade with the lid open.

Updating Mac laptop carts with closed lids

What's the problem?

So Mac laptops have this thing where they sleep when their lids are shut. That's how Apple designed them. That's how they work. Most of the time, that's fine. However, if you administer laptop carts for a school, that can definitely get in the way of keeping them updated. Even if you have, say, 20 laptops in a cart, manually opening each one and updating each one (even with an automated tool like Munki) can be a pain (and a time suck).

So far, I've come across several possible solutions, which I'll outline below. I'm leaning toward NoSleep, but I don't have a step-by-step tutorial ready just yet and won't until I can test it extensively.

Possible Solutions

Wake-on-LAN

I haven't seen a lot of mention about this, but it doesn't seem like a terribly viable option. It's certainly a lot of extra steps to get people who use a laptop cart, in addition to plugging in the power, to also plug in a wired ethernet connection (especially because new Mac laptops are ditching ethernet ports for Thunderbolt, which would require an adapter).

Apparently, you can do this wirelessly, but reading about Wake-on-Demand and sleep proxy makes my head hurt. May be a good fallback to explore if the NoSleep option doesn't work out.

Fake an external monitor connection

I don't have the link handy right now, but I did stumble at one point on to some adapter that fakes have an external monitor plugged in. That involves purchasing the adapters and then making sure they're always plugged in. Doesn't seem worth the effort/cost.

Extensions that prevent sleep-on-lid-close

Right now this seems the best option. There are extensions that essential disable on the kernel level sleeping when the lid is closed. One is InsomniaX. Another is NoSleep.

InsomniaX is still figuring out its licensing (For the time being this project is deemed to be "private code" and is not available for sharing, redistribution, inclusion in other works), so I'm leaning more toward NoSleep at this time.

My hope is that with the laptop never sleeping, I can still have it scheduled to shut down when school is not in session (e.g., shut down between 8pm and 6am), check for Munki updates at 6am, and then just stay on (but with the lid shut) for the rest of the school day until the next evening.

If, after thorough testing, I get a good workflow, I'll post up a step-by-step tutorial...