CrashPlan 6.5 stuck on Connecting… and never times out

We had a couple of clients who would just never do an initial connection to CrashPlan after the upgrade from CrashPlan 4 to CrashPlan 6.5. But they would never time out or give an error message either.

Restarting the CrashPlan service didn't help. Restarting the computer didn't help. Uninstalling and reinstalling the client didn't help.

Turns out it if the detect-a-user script can't find a CP_USER_HOME, it will just keep trying to connect instead of erroring out. We modified our script, and now those clients are good (we did have to uninstall and reinstall the client after modifying the script, though).

P.S. Someone pointed out that I don't actually share the original or modified script. The point of this blog post isn't to say "Here's a script that works." There are lots of scripts that work. The point is more that if you're experiencing this issue ("connecting" and never timing out or providing an error message), you likely need to fix your script to output a CP_USER_HOME).

Considerations when upgrading CrashPlan with Munki

I had a great workflow for installing CrashPlan with Munki for older versions of CrashPlan (we were on versions 3 and 4 before).

We recently made the jump to CrashPlan 6.5, though, and that workflow no longer applies. Now you have to use a deploy.properties file instead of custom.properties and userInfo.sh files.

We had some added complications to our "upgrade" process, because our new CrashPlan server is a completely different server, and we weren't migrating everyone at once, so we couldn't just change the DNS to point to the new server. I'm not sure a jump from 4 to 6.5 would have been possible as just an installation upgrade anyhow.

So what were those complications?

  • We couldn't use an installs array any more to tell Munki whether CrashPlan was installed or not. Keeping the installs array would (without managed_updates) prompt users to upgrade to CrashPlan 6.5 or, worse, just upgrade them automatically (with managed_updates). So I changed CrashPlan 4 and 6.5 to use an installcheck_script instead.
  • Since CrashPlan 6.5 isn't just an update but an actual upgrade for us (think Microsoft Office 2016 vs. Microsoft Office 2011), it's a separate item in Munki altogether, which means we also had to remove the old version from the client's SelfServeManifest before installing the new version (otherwise, the old version would just reinstall).
  • Likewise, as part of the preinstall_script for 6.5, we had to invoke the /Library/Application Support/CrashPlan/Uninstall.app/Contents/Resources/uninstall.sh script to remove 4 first.
  • Lastly, we had to have a temporary place to hold the deploy.properties file before copying it to /Library/Application Support/CrashPlan—otherwise, the old installation of CrashPlan would somehow make it disappear or be unusable by the new installer. Not sure exactly what was happening, but it wasn't being recognized when just being delivered there directly as a payload. We also tried including the deploy.properties file in the .dmg itself, but that didn't work either (prompted for server and registration key).
  • Annoyingly, if you choose not to use SSO, you can't fully automate user account creation or sign-in, so some user interaction for the upgrade is required.

Ours may be a very niche scenario (upgrading from CrashPlan 4 to CrashPlan 6.5 and not using single sign-on), but in case anyone else is in that same situation and using Munki, maybe this blog entry can save you some time in planning your rollout.

Freeing up licenses from deactivated users in CrashPlan

If you have CrashPlan PROe licensed for a certain number of users at your organization, but then you run out of licenses, you may think you can just deactivate users, and that's all good, but in Deactivating & Reactivating Users & Devices, Code42 is a little vague on how long it will take for the licenses to free up:

Deactivation stops backup and causes associated archives to be placed into cold storage and eventually deleted. Licenses are not immediately freed by deactivation.
Apparently (thanks, Sean, from the Mac Admins Slack), you have to purge the cold storage (CrashPlan's version of the Trash can or Recycle Bin) in order for the licenses of the deactivated accounts to be freed up. More details at Purging Cold Storage.

Changing the CrashPlan primary server by terminal commands on a Mac

We recently wanted to change the primary server for our CrashPlan clients from an IP-based one to a DNS-based one. Unfortunately, CrashPlan doesn't have a .plist file you can just run a defaults write command on.

So apart from going into every machine and manually changing it from the menu bar, there is a way to script it. Thanks to ahbeng's GitHub port change script for inspiration on this, but we also got confirmation directly from Code42 that this would work.

Basically, you just want to stop the CrashPlan engine, tweak the text file, and then restart the engine. This works on CrashPlan PROe 4.2. You may have to look for a slightly different file if you're running a different version of CrashPlan PROe.

#!/bin/bash
# Unload CrashPlan's engine, substitute the new string in, and then load the engine back again
sudo launchctl unload /Library/LaunchDaemons/com.crashplan.engine.plist && sudo sed -i '' -e "s/IPADDRESS/SUBDOMAINANDDOMAINNAME/g" /Library/Application\ Support/CrashPlan/conf/my.service.xml && sudo launchctl load /Library/LaunchDaemons/com.crashplan.engine.plist && open /Applications/CrashPlan.app/Contents/Helpers/CrashPlan\ menu\ bar.app
Obviously, substitute in your IP address for IPADDRESS and your actual FQDN for SUBDOMAINANDDOMAINNAME.

Nota bene: If you have deployed your CrashPlan with a custom.properties file, you may have to modify that file as well. Just throw in a

sudo sed -i '' -e "s/IPADDRESS/SUBDOMAINANDDOMAINNAME/g" /Library/Application\ Support/CrashPlan/conf/custom.properties
as well when you've stopped the CrashPlan engine

Packaging CrashPlan PROe for Munki

Update

This no longer applies for CrashPlan 6.5 and above. For more details, see Considerations when upgrading CrashPlan with Munki.

Why the official deployment method won't work for Munki

Code42 has a guide for Preparing The Crashplan App For Deployment. It basically downloads (from your CrashPlan PROe server) a .zip file of some tools to customize your installation. To prepare for Munki, though, you shouldn't run the custom.sh script. What that script does is create a .Custom directory inside the disk image (.dmg) for CrashPlan, which it expects to be mounted at /Volumes/CrashPlanPROe. So if you run that script, and then you try to import the disk image into Munki using munkiimport, none of your customizations will take, because Munki will mount the disk image elsewhere (not /Volumes/CrashPlanPROe).

Tweaking the userInfo.sh Script

As you can see from Code42's official documentation, the two files you want to modify are custom.properties and userInfo.sh. I seem to be the only one who's run into this issue, but I kept getting the user as root with the default settings (because I'm installing the CrashPlan .pkg as sudo presumably, but that's how the .pkg file works). If you run into this issue, there's a trick to get the currently-logged-in user, even though you're essentially running the .pkg as root. There appears to be another way to get the most-recently-logged-in user (which is probably also the currently-logged-in user), too. I actually use a combination of the two, because I ran into a situation in which one method gave me _mbsetupuser, even though I was clearly logged in as another user.

So the middle section of my userInfo.sh looks like this:

# Find actually logged-in user (not root)
login_state=$(defaults read /Library/Preferences/com.apple.loginwindow.plist lastUser)

if [ "$login_state" == "loggedIn" ]; then

# If the user is logged in, the most reliable way to get the actual user is from this command
actual_user=$(ls -l /dev/console | awk '/ / { print $3 }')

else

actual_user=$(defaults read /Library/Preferences/com.apple.loginwindow.plist lastUserName)

fi
CP_USER_HOME="/Users/$actual_user"
user="$actual_user"

but I prefer the first method, because it will work for the most-recently-logged-in-user even if you're logged out. This comes in handy if you're installing CrashPlan along with a bunch of other Munki packages that require a logout or reboot. If you use the first method, you're going with the last actually logged in user. If you use the second method and at the login screen, you'll get root.

Tweaking the pkginfo .plist for CrashPlan

Once you've imported CrashPlan into Munki, you may have to do the following (I did). First, you may have to put in an installs array. Before I put that in, Munki kept considering CrashPlan not to be installed and then got into an infinite reinstall loop.

To get the proper installs array (thanks, commenter Dan), run this command on a system that has CrashPlan and Munki installed:

/usr/local/munki/makepkginfo -f /Applications/CrashPlan.app
and you should see in the output something like this:
<key>installs</key>
<array>
<dict>
<key>CFBundleIdentifier</key>
<string>com.backup42.desktop</string>
<key>CFBundleName</key>
<string>CrashPlan</string>
<key>CFBundleShortVersionString</key>
<string>3.6.5</string>
<key>CFBundleVersion</key>
<string>3.6.5</string>
<key>path</key>
<string>/Applications/CrashPlan.app</string>
<key>type</key>
<string>application</string>
<key>version_comparison_key</key>
<string>CFBundleShortVersionString</string>
</dict>
</array>
Put that into your pkginfo .plist for CrashPlan, and the install loop will no longer happen.

For uninstalling, make the uninstall method in the .pkginfo (or .plist) this:

<key>uninstall_method</key>
<string>/Library/Application Support/CrashPlan/Uninstall.app/Contents/Resources/uninstall.sh</string>

Munki-fying CrashPlan custom settings (Method #1)

Greg Neagle (the author of Munki) has proposed making CrashPlan require a settings package for CrashPlan that puts the custom.properties and userInfo.sh files in /Library/Application Support/CrashPlan/custom. I would try that first, to see if it works for you. For some reason, it hasn't worked for me (and I've tried custom, Custom, and .Custom).

Munki-fying CrashPlan custom settings (Method #2)

What worked for me is a similar method that's a bit more convoluted. So I created a package that delivers a payload of the custom.properties and userInfo.sh files to /Library/Application Support/CrashPlan/.Custom, and then I have a preinstall script for CrashPlan temporarily copy those to /Volumes/CrashPlanPROe, as if the disk image were really mounted there. Then, when the installation is done, I have a postinstall script delete the files from the fake disk image.

Here's the preinstall script:

#!/bin/bash

# Copy over custom settings if they exist
if [ -d /Library/siprep/.Custom ]; then

# Make a temp directory
mkdir -p /Volumes/CrashPlanPROe/Custom

# Copy over the custom settings
cp -R /Library/siprep/.Custom/* /Volumes/CrashPlanPROe/Custom/

# Rename the Custom directory
mv /Volumes/CrashPlanPROe/Custom /Volumes/CrashPlanPROe/.Custom

fi
You may be thinking, "Uh, why don't you just copy .Custom instead of making a directory and then renaming it?" That's what I used to do, but something in Sierra broke that approach and gave Operation not permitted as an error—I'm assuming it has to do with copying a hidden directory.

Here's the postinstall script:

#!/bin/bash

# If there is the temporary /Volumes directory, then delete it

if [ -d /Volumes/CrashPlanPROe/.Custom ] && [ ! -d /Volumes/CrashPlanPROe/Install\ CrashPlanPROe.pkg ]; then

rm -r /Volumes/CrashPlanPROe

fi
Your mileage may vary. I'd definitely start with Greg Neagle's suggestion first and use my shoddy workaround only if you need to.