Adobe Creative Cloud Deployment – Overview

EnterpriseApp_256.pngAdobe’s Creative Cloud licensing models add some new layers of complexity surrounding large-scale deployment in organizations. As I’ve been planning and testing our rollout in areas with managed, shared workstations I’m routinely uncovering new information, and the parts of this I think might be useful to others I will cover in several posts. There are several aspects here: 1) simply wrapping one’s head around the different licensing models, 2) understanding differences in the mechanisms with which these licenses can be deployed to machines, and 3) how to maintain all of all this using a software management system such as Munki or Casper. While I can only speak with experience with a subset of the licensing types and my management tool of choice (Munki), this may be useful if you have some of these in common, or you may also be able to port some specifics to another management system.

An additional preface to these posts: Having been looking into this for quite some time I still regularly feel like I’m stumbling in the dark, I cannot keep any of the license agreement acronyms in my head for more than several minutes and in general I usually feel like I’m doing this wrong. Lacking any better guidance, however, I’m documenting some of my findings. I expect to need to revise these strategies over time.

Thanks to Patrick Fergus, who provided some additional details and clarifications about the different license types. Some of the points below are his words verbatim. Patrick has also written a number of very detailed posts on subjects I’m covering in these posts.

First, let’s review some of the new subscription-based licensing models and how that affects the mechanisms used to deploy Creative Cloud.

There are two new axes along which we can categorize licenses:

  • A license agreement type of either Teams (including education-focused licenses) or Enterprise
  • A type of license, including “Named” and “Device” (for education) or “Serial Number” (for enterprise)

Named licenses require sign-in to use the software, and these sign-ins come in three different flavors:

  • Adobe IDs, which are owned by the user and authenticated by Adobe
  • Enterprise IDs, which are owned by the organization and authenticated by Adobe
  • Federated IDs, which are owned by the organization and authenticated by the organization via SAML

Non-sign-in licenses include:

  • Device licenses are “activated” to a machine and consume a license from a “pool” for as long as that machine is activated. Different pools will exist for different product collections.
  • Serial Number Licenses “activated” to a machine and do not report back to Adobe when they are used

Caveat: Because my organization doesn’t have an Enterprise agreement, I cannot speak with actual experience with that licensing model. The approaches I talk about with respect to the “Device License” should mostly apply to the “Serial Number” model used by Enterprise agreements, however.

Here’s a screenshot borrowed from one of Adobe’s help pages on the subject. Note how Education categories can be found in the Teams (top) and Enterprise (bottom) agreements:


Enterprise agreements have the benefit, besides apparently greatly reduced cost per license, of not needing to track individual device “activations” due to Adobe allowing “anonymous” serialized activation.

If you’ll be deploying device/serial licenses, you need some way to automate the installation of the license. Adobe offers two approaches, built around their Creative Cloud Packager application

  1. Create a device-licensed package, which will contain one or more apps and also deploy the activation when the package is installed. This process also creates an uninstaller that will remove the apps and deactivate that license.
  2. Create a license file, which allows us to “migrate previously deployed named user or trial packages to serial number licenses or device licenses”: This outputs four files, which Adobe calls a “package.” It is not – it is four files, created in a directory, with no accompanying explanation. Presumably we can use this to activate and deactivate a license? (Keep reading to find out!)


The first seems like a sane option; the application(s) and license are included as a single package bundled together. Munki even supports importing these in a single step along with the accompanying uninstaller package, and has special logic tailored to support uninstalling these, while still using Adobe’s provided uninstallers. This works well if you don’t anticipating mixing Named and Device/Serial licenses, and are doing all licenses from the same pool, or a small, manageable number of them.

If however, your org will also be using Named licenses, or you expect to find yourself handling device licenses in various pools and want to just treat the device license or serial separate from the actual application installers and manage them independently, option (2) (creating a device license file independent of the application) seems to make more sense.

Nick McSpadden and Patrick Fergus also discovered a critical problem with (1), if one creates multiple device license packages from the same pool, for example creating a separate Photoshop and After Effects package both from a “Complete” pool, or multiple serial number packages with the same serial number, removing any one of these licensed application packages will uninstall the license as well.

This is not an issue that would affect everyone – despite moving away from the “Creative Suite [X] Premium” product model, the “pools” (or serial numbers) are still logical collections of applications, so it’s possible that one might just build packages containing all the applications from a pool and not consider a need to add or remove individual applications from this pool on an ongoing basis.

It affects me, however: with many subscriptions to the Complete pool while still not needing half of the applications for many of our workstations, I’m instead opting to build individual application installers that I’d still like to be able to manage atomically without needing to worry that removing one product will cause another to cease functioning. An unlicensed Creative Cloud installation prompts a user with a completely hostile dialog prompt:


Karl Gibson of the Adobe IT Toolkit team has acknowledged that this is a bug, and it’s scheduled to be addressed in an upcoming update. Also, Nick McSpadden has documented his solution to this “overlapping” install/uninstall issue, which is to combine the licensed installer with the “Named” (ie. unlicensed) uninstaller, so that if a product is removed using the uninstall pkg, the machine remains licensed. For serial number installations this is perhaps more feasible because serial number installations are “anonymous,” and an active installation doesn’t consume a license from an (expensive) pool of licenses.

So, solution (2) it is for me, at least as of today. This is partly to mitigate this bug, and partly to offer a more flexible workflow as the deployment of Creative Cloud pans out. In my environment we’ll most likely be seeing use of both Named and Device licenses, so it is also helpful to be not building and tracking duplicate packages for the same applications.

In posts which will soon follow, I’ll cover the steps involved to build an OS X installer package from CCP’s “Device File Package [sic]”, a couple simple approaches to managing this license package using Munki, and some odds and ends.

Tagged , , | 1 Response

Upcoming conference talks for 2015

Pepijn Bruienne just posted a nice summary of the Apple administration-focused conferences coming up in 2015. I’m also happy to be a small part of several of those coming up:

Anthony Reimer has organized for its second year the MacDeployment workshop, hosted at the University of Calgary’s Integrated Arts Media Labs. I’m looking forward to visiting as the IAML seems similar to the environment I support at Concordia University’s Faculty of Fine Arts, and the Prairies are one of the only parts of Canada I’ve not yet visited.

Thanks to some great timing, one day later I’ll be speaking at the new MacDevOps YVR conference taking place at Simon Fraser University in Vancouver, organized by Mat X and Brian Warsing. Mat and Brian have recruited a great lineup of speakers, so it’s going to be a very packed day. I was born in BC but didn’t grow up there, and it will be almost exactly 15 years since I was last in Vancouver.

These two days (June 18-19) I’ll be giving an introduction to Python in the context of Mac administration.

Finally, I’m lucky to be returning to Göteborg, Sweden for MacSysAdmin 2015 on September 29 through October 2. It was an absolute pleasure last year to attend, speak and meet so many members of our community, thanks to Tycho – and I’m looking forward to traveling there again. This time I’ll be giving a tour and demoing some of my Mac sysadmin tools I maintain on GitHub.

Hope to see you at these great events!

Tagged | Leave a comment

Reclaiming inodes from Jenkins pet project I maintain is, a Jenkins instance that runs all AutoPkg recipes in the autopkg/recipes repo on a schedule, and reports any cases where recipes are failing. There are currently 126 jobs, for the 126 recipes in the repo.

These AutoPkg recipes must be run on OS X, so there is always at least one OS X slave connected to by the master, which runs Ubuntu on the cheapest Digital Ocean droplet available. Every time a job runs on a slave (currently about every eight hours), Jenkins logs the results on the master in a set of files on disk, known as a “build.” By default, when a new Jenkins job is created, it is configured for builds to be kept forever, even though they can be deleted manually. Builds may also include “artifacts” – binaries or other output from a job – but in my case a build is mostly just state and console output saved from the build run.

This service ran well enough for a year and a half before it suddenly reported having no free disk. And yet, df reported more than 50% of the 20GB volume being available. Using the -i option for df, however, revealed that while I had space available, I had zero file inodes left on the system:

$ df -i

Filesystem      Inodes   IUsed  IFree IUse% Mounted on
/dev/vda       1310720 1310720      0   65% /

Clearly I had way more files on disk than I had any use for, and this would be a good opportunity to prune them. In my case the builds are not useful for much except if one wants to see the history of success and failures of the recipes, and generally we only really care about whether the recipes work today, in their current state.

After a bit of digging in the job configuration, I found where one can restrict the number of builds that are kept – right near the top, “Discard Old Builds”:

Discard Old Builds job configuration

Discard Old Builds job configuration

Since each recipe is its own job and they are numerous, I use the Jenkins Job DSL plugin to generate these jobs programmatically. It may seem odd that this plugin gets invoked as a build step of a job – in other words, you run a job that builds other jobs – but it is quite powerful and is very actively developed.

All I really needed to do to configure these jobs to retain only the last 30 days’ worth of builds was add one line to my Groovy script invoked by the plugin.

Now that these jobs were all reconfigured to keep builds for a maximum of 30 days, what would happen to all the existing old builds? As documented towards the bottom of this issue, the log rotation will come into effect the next time a build is run, so each job would prune its old builds as each subsequent build is run. Or, as the original reporter documented, it’s possible to run a groovy statement in the console to prune all the jobs’ old builds immediately, which I confirmed worked as well.

For more details on how this “AutoPkg CI” jenkins instance is created, check out its configuration on GitHub.

Tagged , | Leave a comment