In the previous post we looked into Pantheon hosting and how we can use it to easily create a suite of similar websites without having to build them individually each time. Often the requirement isn’t only easily creating new sites, but having to maintain them easily as well. When you have dozens or hundreds of websites that need changes applied to them, managing each one individually through Pantheon’s dashboard becomes a bottleneck. Fortunately Pantheon offers a command line interface that allows developers to automate much of that maintenance. In this post we’ll take a look at using Terminus to manage our sites.
Understanding Pantheon’s Framework
Before we can start rolling out features to multiple sites, it is helpful to understand how Pantheon groups the websites it hosts. Websites can be first grouped into an Organization. Within that, they can be tagged in any manner that makes sense for your needs. Both the organization and the tags can be used to filter sites into more targeted groups.
Each site then gets three environments;
live are their machine names. Those machine names are important, as we’ll need to know which environment we’re targeting when we do our deployments. A single site also gets a machine name, like
my-awesome-site. The combination of site name and environment name create a single instance identifier, which we use in our Terminus commands. For example, to clear Drupal’s cache on a live environment we’d run:
[geshifilter-]terminus remote:drush my-awesome-site.live -- cache-rebuild[/geshifilter-]
A deployment on Pantheon has to follow a specific process, whether done via the dashboard or through Terminus. First, code must be deployed to the
dev environment. Normally this is done with Git by pushing new code into the
master branch on Pantheon’s repo. For features we’re deploying to multiple sites, the code must be pushed to the Upstream and then pulled from there. In the dashboard, this takes the form of a button that appears to alert you to new changes. In Terminus, you’d run the following command. Note, the
--updatedb flag ensures any Drupal database updates get run as well.
[geshifilter-]terminus upstream:updates:apply my-awesome-site.dev --updatedb[/geshifilter-]
Second, we have to move those updates to testing and then to production. Again, the dashboard provides a button on those environments when there are updates that can be made to them. In Terminus, this is done with:
[geshifilter-]terminus env:deploy my-awesome-site.test --updatedb --cc --note=”Deployed new feature.”[/geshifilter-]
--updatedb runs the database updates,
--cc rebuilds Drupal’s cache, and
--note is the description of the updates that gets added to the Pantheon dashboard.
There are many other actions you can handle with Terminus. Their documentation covers the full list. However, out of the box Terminus has the same limitation that the dashboard has. You can only run a command on one site at a time. Thankfully, Terminus has additional plugins that solve this problem for us.
New Commands with Terminus Plugins
Terminus is built on PHP and managed with Composer. This allows for new commands to be built and distributed on Pantheon’s Terminus Plugin Library. We’ll need to install two plugins to run Terminus commands on multiple sites at once: Terminus Mass Update and Terminus Mass Run. Mass Update is created by Pantheon and runs the
upstream:updates:apply command on a list of sites that get piped into it. Mass Run builds on that idea, by using the same piping logic and implements it onto more commands. With it you can run Drush commands, create site backups, and deploy code among other things.
To get the list of sites, we’ll use the
org:site:list command. We could also use
site:list, however since Custom Upstreams are an Organization level feature we’ll more than likely want to filter by Organization;
org:site:list takes the name of the organization we want to filter by. To get a list of the Organizations you have access to, run
terminus org:list. This returns both the machine name and the ID number of the Organizations, either will work for
terminus org:site:list aten will return a table of all sites in Aten’s Organization account. However, we still might only want a subset of those sites. This is where tagging comes in. Adding the
--tag flag to our command lets us get only sites we’ve tagged with whatever is passed in. To see all sites tagged with “US” our command becomes
terminus org:site:list aten --tag=US. This gets us closer, however it still returns a table of all site information. We only need the site ID numbers as a list for our Mass Run and Mass Update commands. To get this list we’ll add
--format=list to our command, making the entire thing:
[geshifilter-]terminus org:site:list aten --tag=US --format=list[/geshifilter-]
Now that we have a list of the site IDs we want to update, all we need to do is pipe that list into our plugin commands. To deploy a new feature from our upstream, we’d run:
[geshifilter-]terminus org:site:list aten --tag=US --format=list | terminus site:mass-update:apply --updatedb[/geshifilter-]
Moving that feature through Pantheon’s environments is:
[geshifilter-]terminus org:site:list aten --tag=US --format=list | terminus env:mass:deploy --sync-content --cc --updatedb --env=test --note="Updated Drupal Core."[/geshifilter-]
Removing a user from all sites they exist on becomes:
[geshifilter-]terminus org:site:list aten --tag=US --format=list | terminus remote:mass:drush --env=live -- ucan bad-user[/geshifilter-]
Long Commands, Amazing Results
At this point you’ve probably noticed the commands we’re using have become very verbose. This is one downside of this approach: the commands themselves are not intuitive at first glance. For common tasks creating aliases can help simplify this. Leveraging the terminal’s history to bring up past commands and then modifying them speeds up more one-off tasks. But the ability to manage our websites en masse becomes a huge time saver over clicking our way through the dashboard for dozens of sites.