Safer Drupal development with custom settings

Safer Drupal development with custom settings

Safer Drupal development with custom settings

In a development situation with an increasing number of developers involved and site is live long ago, it is becoming ever more important to draw a clear separation line between a developer environment & the main production environment. All Drupal developers are still more or less human (will there ever be a module for that?), so there will always be room for mistakes. One of the situations mistakes can happen is where you believe you are completely isolated, when developing locally.

Say you are creating a new part of an existing site on your local Unix/Win/Whatever machine, and want to test whatever you've currently implemented. You browse pages, search for stuff and click some buttons. This is a big site, and without knowing all the structure behind the site you click around like an elephant stepping into an egg salad. Without even noticing, you accidentially sent some mails to all the managers, updated some webservices with new shiny .tld addresses and corrupted some search results on prod. Let alone triggered Cron, and updated a bunch of non-existing-on-prod commerce orders on a remote service now sending out all those lederhosen to someone named Dsdsfsfd in Iceland. All when sitting inside your local bubble. Dsdsfsfd is of course happy, store manager not so much. :)

Stuff to consider

In our company we do a great deal of work on commerce sites, and in that relation, keeping production isolated from everything else is a total must. The local environment should be completely testable, without affecting live. So while developing or deploying new modules & implementations, there are a few issues one needs to have in mind:

  • How will these implementations interact on production?
    Determine if your implementation does anything that affect stuff outside the main database.
  • Does it call any external services?
    Of course, querying for a weather forecast via public service is a no-brainer, but when integrating and communicating with external services we need to really stop and think.
  • Are any service provider's data affected by your calls?
    Google analytics is an excellent example where data can be directly affected from local dev, not to mention search api indexes & order systems.
  • Does everybody else in my team know what I'm implementing??
    If something new is implemented and it can have implications when not on prod, you have the option to inform everybody "don't do this and configure that". But you can also just try to think "this will be used locally, do I need to prevent anything bad from happening by making it aware of what environment it is triggered in?".
  • Can the designed workflow be followed / emulated effectively on local development without affecting production?
    Stuff like proprietary maps and such just stops working when not having an API key. That's not affecting production, but it is an inconvenience when maps stop working on local every time you pull a fresh database from production to work with. One more automated local transformation = 1 less dev headache.

There should always be a measure in place to separate prod & stg. Relying on all other devs knowing as good as yourself what exactly you are doing is mistakes in the making. For example, passwords to extarnal services usually tag allong when dumping a production database, making it trying to log into the services exacly the same way. If there's no immediate ip blocking, it will succeed.

Customize that settings file

The settings file has a well-known powerful way of defining variable overrides for any settings variable. With setting $conf['myvar'], all calls to variable_get('myvar') will fetch that variable instead of the default one or the one in db. To get an overview of what power that holds, just search for 'variable_set(' in your IDE for a given module / tree structure on your site. Here are some examples of fixable things:

  1. When local environment is not set up as secure, the securepages module will redirect to prod when going to secure.
  2. Error level on production are often set to 0 (no error display).
  3. We most often don't need any cache on local environments, but always on production.
  4. The same goes for page, css & js compression
  5. There might be different temporary folder setups for production server.

$conf['securepages_enable'] = 0;
$conf['https'] = FALSE;
$conf['error_level'] = ERROR_REPORTING_DISPLAY_ALL;
$conf['cache'] = 0;
$conf['preprocess_css'] = 0;
$conf['preprocess_js'] = 0;$conf['site_name'] = "Mysite LOCAL";

Add this to local settings file, and problems solved.

PS: In Drupal 8, we will have settings files where every setting is available as files deployable using git. That's a definitive step forward in awesomeness. See this article for more information. However, in Drupal 8, this approach will still work as a master override.

Handle those test emails

Some prefer to have dev emails sent to gmail for max emulation of live site, and some just use the local mailbox. Either way, it is useful to direct all emails to the same email, ignoring the original reciepent. The module reroute_emails is great for that. It basically has 2 settings, enable and destination mail. If enabled, adding this to $conf will setup the redirect:

$conf['reroute_email_enable'] = 1;
$conf['reroute_email_enable_message'] = 0;
$conf['reroute_email_address'] = 'test@localhost.com';

..and rerouting is magically working.

Add that environment variable

To make this as painless as possible for new devs, you can keep these settings laying around in git. Using a separate file, like local.settings.php you can:

  1. Make a small modification to the settings.php
  2. Include the file local.settings.php
  3. Add any differentiating settings to this new file
  4. If you want, force a siteload fail if environment variable is not set. We do not want prod to ever quietly think it's dev.

Let's say we have 3 different environments:

  • Local -> 'loc' - Streamlined for low performance
  • Staging -> 'stage' - Some integrations live
  • Production -> 'prod' - All integrations live

We add 3 lines to settings.php. These lines are automatically added in Drupal 8, but we still need them in 7.x.

if (file_exists(DRUPAL_ROOT . '/' . $conf_path . '/local.settings.php'))
{ include DRUPAL_ROOT . '/' . $conf_path . '/local.settings.php'; }

 

And then we add something like this in our local.settings.php:

<?php switch ($conf['environment']) {

  case "prod":
    // Any special production-only cases
    break;
  case "stage":
    $conf['cache'] = 0;
    $conf['preprocess_css'] = 0;
    $conf['preprocess_js'] = 0;
  case "dev" :
  default:
    $conf['securepages_enable'] = 0;
    $conf['https'] = FALSE;
    $conf['error_level'] = ERROR_REPORTING_DISPLAY_ALL;
    $conf['cache'] = 0;
    $conf['preprocess_css'] = 0;
    $conf['preprocess_js'] = 0;
    $conf['site_name'] = "Mysite LOCAL";
    break;
};?>

When anything new is needed, add here & commit to git, and everybody's set to go.

Disabling / enabling those modules

Enabling and disabling devel and testing modules can be a pain, but automating the process is not a very big hassle. Usually we make a custom module for each site to hold custom code not fitting in anywhere else. Adding the following will handle any enabling / disabling of modules based on the environment variable.

function hook_init(){
  // If we're on local, enable devel.
  if (variable_get('environment', 'loc') == 'loc' && !module_exists('devel')) {
    module_enable(array('devel'));
  }
}

Managing that ruleset with environments in mind

Almost all medium complex Drupal 7 sites rely on Rules at some level to manage both automated and manually triggered processes. The rules should be built with the same approach in mind.

  • Keep critical things from running wild on local
  • Try to emulate behavior locally

We talked about the $conf['environment'] variable. We can drag this variable into rules.

  • Expose as a global token
  • Create a rule checker

By having it exposed, we can approach rules creation with development in mind, making it easier for ourselves at the time when the site is on production and new stuff is launched.

With this, we can create separate rulesets for stage and prod, which enables us to fire events differently when on local or stage. For example, on commerce sites, we can have two different payment solutions, one for development (test) and one for production (live).

 

Bottom line

This is some approaches for making the migration between environments easier. The settings file, together with rules and eventual extra code can make the development process easier, both in terms of security and efficiency. Making all envs work out of the box is like an ultimate utopia, and with these steps you can reach a bit closer.  Happy env hacking!