The Drupal 6 to 8 Upgrade Challenge - Part 2
Nathaniel Catchpole , the Drupal 8 release maintainer and Tag1 Senior Performance Engineer, suggested that Drupal shops everywhere could support the release of Drupal 8 by upgrading their own sites and addressing the issues they find along the way. This is part two of a series chronicling the journey from Drupal 6 to Drupal 8.
Part 2: Preparing to Migrate D6 to D8
Having concluded the readiness assessment, we turn next to migrating the content and configuration. In reality, there’s little chance that we would migrate anything but the blogs from our old site. For the sake of giving Migrate in Core a workout with real conditions, however, we’re going to upgrade with core’s Migrate Drupal module rather than rebuilding.
Migrate in core is pretty exciting!
It means that we can:
- Migrate content from the old site
- Build new functionality on the new site
- Continue to migrate content from the D6 site to the D8 site periodically
- Keep the sites side-by-side until we’re ready to make the new one live
Conceptually, then, the Migrate Drupal module is different than past major version upgrades. There’s no more running and rerunning the monolithic update.php! It means you need two databases, the D6 database and the D8 database.
There’s a lot of documentation on running Migrations available on Drupal.org. Here are some key entry points:
- Upgrading from Drupal 6 or 7 to Drupal 8
- Executing a Drupal 8 migration. This is part of the API handbook and is more developer-focused.
- Known issues with the Drupal 6 -> 8 migrate path
What follows is my specific journey and you should return to the main documentation when upgrading your own site.
Get the D8 Compatible Version of Drush
Full documentation for Drush is available at Read the Docs. My directions below are slightly different than the recommended install as I prefer to keep my source files in /usr/local/src, not a user home directory.
- Install Composer globally (if you haven’t already).
- Install Drush 7.x (dev) which is required for Drupal 8:
$ sudo mkdir /usr/local/src/drush // create the directory if it doesn't exist $ cd /usr/local/src/drush $ sudo composer require drush/drush:dev-master $ sudo ln -s /usr/local/src/drush/vendor/drush/drush/drush /usr/local/bin/drush $ sudo drush // one time only with root privileges
Prepare the D6 Site
Uninstall Disabled Modules
Although access to the legacy site is read-only, it’s not recommended that you run migrations against a production site, so I work from my local development copy with a fresh copy of the prod database.
The only real preparation necessary is uninstalling unused modules. Migrate will try to migrate all the content in the database, including things related to disabled modules.
drush pm-list --type=Module --status=disabled shows me what’s available to uninstall:
Package Name Version CCK Content Copy (content_copy) 6.x-2.9 Core - optional Book (book) 6.31 Core - optional Forum (forum) 6.31 Core - optional Poll (poll) 6.31 Core - optional Search (search) 6.31
I’ve uninstalled all of these to eliminate the chance of orphaned data causing an issue with the migration:
$ drush pm-uninstall book forum poll search content_copy -y
Delete Unwanted Content, Especially Spam
Many site owners prevent spam from being displayed, but they don’t always delete it. My first try at upgrading was taking a really long time on the comments migration. A quick peek showed me:
MariaDB [tag1dev]> select count(*), status from comments group by status; +----------+--------+ | count(*) | status | +----------+--------+ | 57 | 0 | | 173851 | 1 | | 1024 | 9 | +----------+--------+
Brief investigation told me that 0 is published, 1 is unpublished and 9 is unapproved. Everything not explicitly published appeared to be spam. I took them out with
delete from comments where status = 1 or status = 9; and sped up the migration considerably.
See if There’s Evaluated PHP in the Body of Blocks or Nodes
I was reminded of this, too, after running my first migration: There might be PHP in blocks, nodes, or comments that are best found and addressed before upgrading.
One way to do that is run the Security Review module. It’s only partly helpful, though. It will reveal any node with
<?php in it, which, if preceded by a
<pre> tag is not being interpreted. That sort of usage will cause Security Review to report some false positives. Still, there’s a lot of good information, and you may find other problems you’d like to correct either before or after migrating.
The good news, no untrusted roles were allowed to use the filter. In fact, no roles were. Still, because it was enabled, I did a quick check on blocks and nodes with these snippets from Wesley Tanaka:
MariaDB [tag1dev]> select bid, info from boxes where format in (select format from filters where module = 'php' and delta = 0); MariaDB [tag1dev]> select nid, vid from node_revisions where format in (select format from filters where module = 'php' and delta = 0);
They turned up two blocks as well as the one node I’d already found with Security Review. I removed the php prior to the migration and disabled the php filter since it’s not available for D8 and we wouldn’t want to use it if it were.
Prepare the D8 Site
I wanted to work with the dev branch of D8, not the beta, because I anticipated finding bugs and didn’t want to spend time troubleshooting a bug in beta that had already been fixed in dev. Note that at this point, there’s no upgrade path from D8 to D8, and I wouldn’t want to work with a Beta or consider this project for production deployment until that exists.
I added a new site to apache, eight, and updated /etc/hosts accordingly. You’d set up your localhost web server however you’d normally run a second site on your development machine.
The Dev branch
Since I was working with dev and I might need to submit patches back, I cloned from git. Drupal Core is big, so I just grabbed the development branch for now.
$ mkdir /var/www/eight $ cd /var/www/eight $ git clone --branch 8.0.x http://git.drupal.org/project/drupal.git --single-branch $ cd drupal
IMPORTANT: From here on out, all commands should be run in the root of your new Drupal 8 site! If you had installed like me, that means all the commands would be run from
/var/www/eight/drupal unless otherwise specified.
Install Drupal 8
I performed a standard installation following the directions in the
Prepare the Manifest
Currently, Drush provides the cleanest way to run a Migration. The Migrate user interface is still under development; you can follow along here: https://www.drupal.org/project/migrate_upgrade
- Enable Migrate Drupal and any modules that should be receiving data from your D6 site. I won’t need any contributed modules enabled.
$ drush en migrate_drupal, migrate -y
- Get the latest list of migrations available:
$ drush config-list | grep migrate
You’ll see output like the following, but more of it.
migrate.migration.d6_action_settings migrate.migration.d6_aggregator_feed migrate.migration.d6_aggregator_item migrate.migration.d6_aggregator_settings
IMPORTANT: If migrate and migrate_drupal are not enabled, you 'll see a message that Migrate is not installed instead.
- Make a
manifest.ymlfile. You can actually call this anything.yml that you want since you’ll be calling it by name when you run the migration. To include each of these individual migrations in the manifest, remove the
migrate.migration.and replace it with a dash followed by a space, so you’ll have
- d6_action_settings, for example. You can use the following to write the manifest file directly:
$ drush config-list | grep migrate | sed -e 's/migrate.migration./- /' > manifest.yml
I like to include all the migrations in the manifest and use a # symbol to comment out migrations I’m not running. For example, I don’t have anything related to aggregator on the D6 site. Migrate would tell me so if I left the aggregator migrations in the file, with a message like:
Running d6_aggregator_feed [ok] Invalid argument supplied for foreach() RequirementsException.php:63 [warning] Migration d6_aggregator_feed did not meet the requirements. Missing source provider aggregator [error]
I can disable individual migrations by commenting them out with
#, thereby avoiding cluttering its output with warnings. In addition, we’re not using book module, so I disabled it. The top of the manifest file looks like:
- d6_action_settings #- d6_aggregator_feed #- d6_aggregator_item #- d6_aggregator_settings - d6_block #- d6_book #- d6_book_settings - d6_cck_field_revision - d6_cck_field_values …
NOTE: In addition to unused modules and deleting spam, I also commented out the following to speed up the process:
# - d6_node_revision # - d6_cck_field_revision # - d6_term_node_revision
I plan to run all three of them once I've worked through any issues I encounter.