Drupal 7 tip: How to automate and control your go live checklist

Posted by: 
Dominique De Cooman

This post will give you a list what to check when you go live with a drupal 7 website and how you can control it and automate it. You need to check this go live checklist each time you keep integrating new stuff during deployment to test if everything is still working. To save time this task can be automated.

Intro
When in development a lot of settings are turned off or are configured differently. Why? Because different environments might use different services and for some settings it is more convienent to develop with certain config. When going live you dont want your dev settings to be active. This post will explain how you can keep things under control and automate some parts of it so you dont have to check everything manualy every time.

Environment specific settings
Lets see which settings should be checked when deploying to test and live. Normaly when using a local - dev - test - live workflow, most of the local settings and dev settings should be the same and also most of test and live settings should be same. Since the client first checks the test version before going live the two environments should be the same except for the environment specific settings of course.

The easiest way to control settings is to keep a settings file per environment. In this settings file it is possible to set your environment specific settings. For example we can set following settings:

In settings.php (local/dev environment)

<?php
  $conf
['error_level'] = '2';
  
$conf['preprocess_css'] = '0';
  
$conf['preprocess_js'] = '0';
  
$conf['cache'] = '0';
  
$conf['page_compression'] = '0';
  
$conf['block_cache'] = '0';
?>

In settings.php (test/live)

<?php 
  $conf
['error_level'] = '0';
  
$conf['preprocess_css'] = '1'
  
$conf['preprocess_js'] = '1';
  
$conf['cache'] = '1';
  
$conf['page_compression'] = '1';
  
$conf['block_cache'] = '1';
?>

So what we did was turn off error reporting, turn on preprocessing of css and js, enable page cache and enable block cache. These are some of the typical go live settings.

A typical site has some other environment specific settings depending on the functionality enabled. So one way to be sure your live settings stay the same is to keep them in the settings file. Note: this will make it impossible to change them in your live site.

<?php
$conf
['so_env'] = 'local';
$conf['so_host_solr'] = '46.137.--.---';
$conf['so_port_solr'] = '8986';
$conf['so_path_solr'] = '/solr';

$conf['googlemap_api_key'] = 'ABQIAAAAfYxov8LBTzY0GIIX9zA54hS8rtsh0fmHD----------';
$conf['windows_live_login_client_id'] = '000000---------';
$conf['windows_live_login_client_secret'] = 'JMuzw----------------------------';
?>

We have a site with a solr and have a different instance for all of our environments so we can fill in the settings here, we can do the same for our other env dependent settings like the maps api key etc...

Now all this is working just fine but what if you want to enable error reporting on the test instance? Some error is manifesting its self and you are not able to check it because you cannot change the setting. What this means is that this setting should not be configured the hard way in settings.php but you dont want to check this setting on every deploy you make.

Shell script
Create a shell script and execute your shell script each time you deploy. This script, like your settings file will live in your version control system so you actualy keep track of your go live list.

An example of such a script can be:

<?php
#!/bin/sh

#D7

#vars
drush vset --yes preprocess_css 1
drush vset 
--yes preprocess_js 1
drush vset 
--yes cache 1
drush vset 
--yes block_cache 1
drush vset 
--yes page_compression 1
drush vset 
--yes error_level 0

#dis contrib
drush dis devel views_ui -y

#dis core
drush dis update syslog dblog field_ui -y

#system
drush updb 
drush cc all

#execute go live tests
drush test-run --uri=<a href="http://example.com/">http://example.com/</a> --xml=~/var/drupal/tests GoLiveTest
?>

To use it create a file called update_live.sh. Make it executable chmod u+x update_live.sh and execute it ./update_live.sh

A you can see you will need drush (http://drupal.org/project/drush) to be installed on your webserver. Now you can still change these settings but each deploy they will be reverted to the settings for this environment.

You can use a CI server like Jenkins (http://jenkins-ci.org/) to automate this task. Each environment has its own script so you can actualy control how your site is deployed to each environment. What you can do is configure a job that excute a shell script each time you do a deploy. If you dont know how to setup drupal and jenkins stay tuned for later blog posts I will explain this.

Automate testing
The next thing you can do to automate the testing if everything is setup, is to run tests. Using the simple test module during deployment can verify a lot of things. Generaly it is not recommend to run tests against a live instance. But if you know what you are doing it can help you verify all your settings during deployment. Know what you are doing means:

  • Make sure your tests dont cause any performance issues.
  • Make sure you cleanup everything your tests are doing.
  • Only test environment dependent functinality. All the other functionality you can test when deploying to dev - test
  • Make sure you disable the simpletest module when done.

Note some settings are indeed hard to check using simpletest so this requires you to use some additional tools to monitor other parts of your infrastructure. You can decide for your self how far you want to go. Not everything should be automated, manual checking for some stuff is ok if it doesnt require you to do it often. If automating saves you time do it otherwise dont.

Checklist

Here is the complete checklist of stuff we check when going live.

Performance

  • Set Preprocessing js and css
  • Set Page cache
  • Set Block cache
  • Set Page compression
  • Set Error level
  • Install PHP accelerator like APC etc
  • Disable some core and contrib modules like for example update, syslog, dblog, field_ui, devel, views_ui, ... Logs and stats should be disabled you can use other tools on the server to monitor errors in a more performant way.

Security

  • Upgrade Drupal and the Contirb module to the Latest Version
  • Schedule back up of database
  • Protect Admin password
  • Enable Google Analytics
  • Use captcha or mollom for all forms
  • Double check user registration settings.
  • Double check all permissions.
  • Check the watchdog for errors and warnings, and fix these
  • Check input format

Seo
Use the drupal seo checklist to make sure everything is enabled as it should be. You can also check all settings using a script. (http://drupal.org/project/seo_checklist)

Email

  • Site SMTP settings
  • Contact module settings, webform and/or others that require email.

Test content
Keep a list of test nodes. Typically when you build your instance you know what content is test content, so you can delete this or build your site without it.

Misc
Schedule cron

Optional

Conclusion
Set everything environment specific that doesnt require an occasional change in settings.php.
Set the other environment specific settings by a shell script each deploy.
Keeping both the script and different settings.php files ensure you can keep track of your go live requirements.
Use a golive simple test test to check if everything is working as it should be.

If you think of something else to check post it in the comments below and I will add it to the list.

Comments

Drupal 7 tip: How to automate and control your go live checklist

Nice post Dominique!

Drupal 7 tip: How to automate and control your go live checklist

Hey Dominique

Isn't it easier to put your settings.php under version control and use a server variable instead of using the shell script.

That way you only have to clear cache / run update.php after deploying.

Also, when working on a project and you have to sync the DB from live to local, you have no automated way of changing the settings to the dev settings, unless you create a second shell script, or one for each environment...

When you set a environment variable in apache:

SetEnv ENVIRONMENT development
SetEnv ENVIRONMENT staging
SetEnv ENVIRONMENT production

<?php
 
switch ($_SERVER['ENVIRONMENT']) {
  case 'development':
    $conf['error_level'] = '2';
    // Other config
    break;
case 'production':
    $conf['error_level'] = '0';
    // Other config
    break;
}
 
?>

We also set URLs for language negotation this way, so you could also use this to enable / disable modules, based on the environment. only thing you have to do after a deploy is clear the cache or run update.php.

Grts

Tim

Drupal 7 tip: How to automate and control your go live checklist

You still have the apache error logs and access logs to check everything. But you are right if you want to see what is going on inside drupal in a more convenient way then enabling syslog is ok. Here is how to set it up: http://drupal.org/documentation/modules/syslog

Drupal 7 tip: How to automate and control your go live checklist

The problem with doing env vars via apache is that they will not be used by drush scripts run via the cli.
Doing the 'everything in files' + the automated deploy per environment is still my preferred way.

Drupal 7 tip: How to automate and control your go live checklist

Tim. Can you elaborate on how you would change Dominique's method? I have struggled for a long time with how to use Git to maintain my entire site (dev - test - live). Dominique's suggestions got me a bit closer, but I would prefer to eliminate shell scripts.

Thanks.

Drupal 7 tip: How to automate and control your go live checklist

Hey Howard

First of, there is not one right way, everyone should puzzle a way that works best for him/her :-)

I used to be anti "let's put settings.php in svn", however, putting settings.php in svn and working with server variables has convinced me.

When creating the virtual host for your project, you can declare server variables in apache/nginx,...

So every environment has his own vhost / location

in apache for example: http://httpd.apache.org/docs/2.2/mod/mod_env.html
So in your vhost files set:


SetEnv ENVIRONMENT development


SetEnv ENVIRONMENT staging


SetEnv ENVIRONMENT production

Then in your settings.php file, that is under version control svn/git/...

put a switch on the $_SERVER['ENVIRONMENT'] variable

for example:

<?php
 
// modules that should differ based on environment
$env_modules = array('views_ui', 'devel');
 
switch ($_SERVER['ENVIRONMENT']) {
  case 'development':
 
    // for example Set Drupal variables
    $conf['error_level'] = ERROR_REPORTING_DISPLAY_ALL;
    $conf['preprocess_css'] = '0';
    $conf['preprocess_js'] = '0';
    $conf['cache'] = '0';
    $conf['page_compression'] = '0';
    $conf['block_cache'] = '0';
 
    // For example Set variables
    $conf['fbconnect_appid'] = "01170439996401826";
    // Other contrib module keys / config based on evironment
 
    // Declare variables for connecting to custom API's (url dev/staging/live) in custom modules
    // make sure every environment connects to the correct external API
    $conf['webservice_connect_url'] = '<a href="http://dev.webservice-connect-url.com';
 
">http://dev.webservice-connect-url.com';
 
</a>    // Set i18n URLs
    $i18n_url_nl = '<a href="http://dev.www.mysite.be';
">http://dev.www.mysite.be';
</a>    $i18n_url_en = '<a href="http://dev.www.mysite.com';
 
">http://dev.www.mysite.com';
 
</a>    // db settings
    $databases = array(
      'default' => array(
        'default' => array(
          'database' => 'mydb',
          'username' => 'root',
          'password' => 'root',
          'host' => 'localhost',
          'port' => '',
          'driver' => 'mysql',
          'prefix' => '',
        ),
      ),
    );
 
    // Enable module if not enabled
    // Not tested, but should work
    require_once('./includes/module.inc');
    foreach ($env_modules as $value) {
      if (!module_exists($value)) {
        module_enable(array($value))
      }
    }
 
    break;
  case 'production':
    $conf['error_level'] = ERROR_REPORTING_HIDE;
    $conf['preprocess_css'] = '1';
    $conf['preprocess_js'] = '1';
    $conf['cache'] = '1';
    $conf['page_compression'] = '1';
    $conf['block_cache'] = '1';
 
    // For example Set variables
    $conf['fbconnect_appid'] = "9874339996401826";
    // Other contrib module keys / config based on evironment
 
    // Declare variables for connecting to custom API's (url dev/staging/live) in custom modules
    // make sure every environment connects to the correct external API
    $conf['webservice_connect_url'] = '<a href="http://webservice-connect-url.com';
 
">http://webservice-connect-url.com';
 
</a>    // Set i18n URLs
    $i18n_url_nl = '<a href="http://www.mysite.be';
">http://www.mysite.be';
</a>    $i18n_url_en = '<a href="http://www.mysite.com';
 
">http://www.mysite.com';
 
</a>    // db settings
    $databases = array(
      'default' => array(
        'default' => array(
          'database' => 'production_mydb',
          'username' => 'root',
          'password' => 'production_pwd',
          'host' => 'localhost',
          'port' => '',
          'driver' => 'mysql',
          'prefix' => '',
        ),
      ),
    );
 
    // Disable module if enabled
    // Not tested, but should work
    // Put in loop for multiple module
    require_once('./includes/module.inc');
    foreach ($env_modules as $value) {
      if (module_exists($value)) {
        module_disable(array($value))
      }
    }
 
    break;
 
}
 
// Set urls for language negotiation
require_once('./includes/database/database.inc');
db_update('languages')->fields(array('domain' => $i18n_url_nl))->condition('language', 'nl')->execute();
db_update('languages')->fields(array('domain' => $i18n_url_en))->condition('language', 'en')->execute();

In this example you set drupal, contrib and custom variables based on your evironment
In custom functions you can then use your variables like this

function my_custom_module() {
  global $conf;
  // Use custom webservice URL
  $soap = new SoapClient($conf['webservice_connect_url'], $options);
}

You set i18n language negotation urls based on the evironment
and you enable / disable modules based on the current environment

settings.php in only loaded after clearing the registry so there are no real performance issues in my opinion.

the only thing needed after a deploy is running update.php (which clears cache) or just clear cache if no DB updates are needed, when using code driven development, normally you should run update.php anyway ;-)

You could automate this (update.php / clearing cache) by using jenkins, and running drush scripts from jenkins or with post update hooks from svn or git.

Hope i could help you a bit further...

Greets

TimLeytens

Drupal 7 tip: How to automate and control your go live checklist

Our settings files reside outside the trunk/docroot in trunk/etc/drupal_settings and with jenkins we copy them as part of the job.

rsync '/var/lib/hudson/jobs/[instance]/workspace/etc/drupal settings/settings_devbuild.php' <a href="mailto:user@server">user@server</a>:/home/[instance]/public_html/sites/default/settings.php

Drupal 7 tip: How to automate and control your go live checklist

1% That does contribute to our healthcare costs, but
yeah, no. That's what culinary memoirs physician know thyself writing covers in
addition to age. Fluctuating blood pressure, and supressed immune system, make your skin look much better and
that these individuals rightfully belong on panels involved in creating CPGs.
Noni Supplement Health BenefitsNoni benefits has therapeutic properties which
can physician know thyself help treat diarrhea, chron's disease,
and one is reproductive and sexual health amongst many others.
Alternative healing has been around for at least forty minutes in
an acidic marinade.

Drupal 7 tip: How to automate and control your go live checklist

Hey Dominique

Better than deleting CHANGELOG.txt, .... is to deny acces to those file on a webserver level, deleting them, would only cause extra work everytime you update drupal core, you would have to delete those files again and again...

For the error reporting example , you should consider using php constants instead of the numeric values they represent...

Grts

TimLeytens

Drupal 7 tip: How to automate and control your go live checklist

Excluding them when jenkins deploys a build is also a possibility. So a typical part of the job would be:

rsync -a --delete --exclude=CHANGELOG.txt --exclude=[...] '/var/lib/hudson/jobs/[instance]/workspace/docroot/' <a href="mailto:user@server">user@server</a>:public_html/

Php constants is a good idea.

Drupal 7 tip: How to automate and control your go live checklist

I recommend keeping block caching enabled on dev sites. If you don't then you may run into some pretty nasty surprises when you deploy new code to production that didn't think about block caching.

Also removing text files (or even hiding them) is not recommended. This offers absolutely no security benefit. Anyone can tell what version of Drupal you are running with very minimal effort. There's automated browser plugins that will do this for you "This site is made with Drupal 6.14". These sorts of tools don't rely on the text files to figure it out.

Also if disabling watchdog brings you a performance improvement you have bigger issues to deal with. IMO dblog should not be disabled. Sure you could route errors to syslog instead, but no one will ever look at them. Better to keep things visible.

I also agree with the other posters that suggest managing these sorts of settings in environment-specific settings.php files rather than using scripts. You can't change them in the UI, but that's the point. You don't want to allow someone to enable error reporting on production. Just look in the logs.

Drupal 7 tip: How to automate and control your go live checklist

Hey Dominique

I have to make 2 small corrections to my previous post...

First off, the use of constants in settings.php... that will never work, constants aren't yet defined in that bootstrap phase...

Then, i always thought that settings.php got cached somewhere... turns out it gets included on every page load, so it's a dumb mistake to put DB queries based on the environment in there (module en/disabling, settings language negotation urls,... ) I've placed these DB queries now in a hook_flush_caches in a glue module based on the $_SERVER[’environment’] variable, also don't find it the cleanest solutions, but hey...

Greets

TimLeytens

Drupal 7 tip: How to automate and control your go live checklist

Hi I am so glad I foud your blog, I really found you
by accident, while I was looiing on Google for something else, Anyways
I am here now and would just like too say thanks a lot
for a fantastic post and a all round thrilling
blog (I also lpve the theme/design), I don’t have ime to go through it all aat the minute but I have book-marked it and also included your RSS
feeds, soo when I have time I will be back to read much more, Pleaqse do
keep up the fantastic work.

Drupal 7 tip: How to automate and control your go live checklist

I'm getting this error message on the checkout review page. How do i troubleshoot this?

• Notice: Undefined index: path in template_preprocess_entity() (line 172 of/home/a1911/public_html/lovetribevibes/profiles/commerce_kickstart/modules/entity/theme/entity.theme.inc).
• Notice: Undefined index: path in template_preprocess_entity() (line 180 of/home/a1911/public_html/lovetribevibes/profiles/commerce_kickstart/modules/entity/theme/entity.theme.inc).

big thanks in advance

Add new comment