provision.drush.inc 11.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
<?php
/**
 * Drush commands
 *
 *
 * This module provides a framework for a Drupal site to manage and install new Drupal sites, using the command line
 * Drush utility. 
 *
 * It allows for pluggable 'provisioning modules' that can extend and modify the tasks that are taken during installation.
 *
 * Each site has the following commands that can be run on it.
 *
 * Implemented : 
 *   install - Install a new Drupal site. The install command uses 3 separate hooks to do it's job, 
 *              namely hook_provision_pre_install(), hook_provision_install() and hook_provision_post_install()
 *   verify  - Recreate all configuration files, to be in synch with changes in the front end. And test that they are correct.
 *   stats   - Return an associated array of site statistics. (implemented in provision_stats module, is thus optional)
 *   import  - Import the details of an already existing site into the provisioning framework.
 *             This command inspects the settings.php and generates the site.php file that the framework uses for configuration.
 *   backup  - Generates a tarball containing the sites directory, the site data configuration and the database dump.
 *             This allows the tarball to act as a 'site package', which can be redeployed on other installations,
 *             or used for an upgrade.
 *   disable - Disable an installed Drupal site. Changes the virtual host config file so that it redirects to provision_disabled_site_redirect_url
 *   enable  - Re-enable a site that has already been disabled. Recreates the virtual host file.
 *   delete -  Generates a back up of the site, and then removes all references to it.
 *   restore - Revert to a previous backup of the site.
 *   cron - Run cron process for a site
 *
 * Not implemented yet :
 *   upgrade - Accepts a site package (backup) as argument, and redeploys it, running the upgrade processes on it.
 *             Uses hook_provision_pre_upgrade(), hook_provision_upgrade() and hook_provision_post_upgrade() hooks,
 *             and allows clean roll back if any errors occur. Will include stringent checking of module versions,
 *             and allow unit tests to be run.
 *   rename  - Change the url of a site. This requires moving of files, and numerous other issues.
 */

/**
 * @defgroup provisiondrush Command line interface for Provision.
 * @{
 */
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
include_once('provision.inc');
include_once('provision.path.inc');
provision_init();
/** 
 * Implementation of hook_init
 *
 * Provide defines for all the major paths and settings.
 * These are settings that must not be modified during the running of the
 * program, but are configurable.
 */
function provision_init() {
  // Do not allow the program to be run as the root user. ever
  $name = posix_getpwuid(posix_geteuid());
  if ($name['name'] == 'root') {
    provision_log('error', 'You are running the provision script as the root user. Exiting');
    provision_set_error(PROVISION_FRAMEWORK_ERROR);
    provision_output($url);
  }

  // Set up defines for platform
  $docroot = provision_get_option(array("r", "root"), $_SERVER['PWD']);
  $backend = provision_get_option(array('b', 'backend'), 0);
  define("PROVISION_DRUSH_BACKEND", $backend);
  
  define('PROVISION_DOMAIN', $_SERVER['HTTP_HOST']);
  // Paths
  $path =  ($docroot) ? $docroot : $_SERVER['DOCUMENT_ROOT'];
  define('PROVISION_DOCROOT_PATH', rtrim($path, '/'));
  define('PROVISION_SITES_PATH', rtrim($path, '/') .'/sites');
  define('PROVISION_DRUSH_PATH', './drush.php');
  $parts = explode("/", rtrim($path, '/'));
  array_pop($parts);
  define('PROVISION_PARENT_PATH', rtrim(implode("/" , $parts), '/'));
  define('PROVISION_BACKUP_PATH', 
    provision_get_option('backup_path', PROVISION_PARENT_PATH . '/backups'));
  define('PROVISION_CONFIG_PATH', 
    provision_get_option('config_path', PROVISION_PARENT_PATH .'/config'));
  define('PROVISION_VHOST_PATH', PROVISION_CONFIG_PATH .'/vhost.d');

  // Commands
  define('PROVISION_RESTART_CMD',
    provision_get_option('restart_cmd', _provision_default_restart_cmd()));

  // System account
  $info = posix_getgrgid(posix_getgid());
  define('PROVISION_WEB_GROUP', 
    provision_get_option('web_group', $info['name'] ));
  define('PROVISION_SCRIPT_USER', 
    provision_get_option('script_user', get_current_user() ));

  // Redirection urls
  define('PROVISION_MASTER_URL', 
    provision_get_option('master_url',  $GLOBALS['base_url']));
  define('PROVISION_WEB_DISABLE_URL', PROVISION_MASTER_URL .'/provision/disabled');
  define('PROVISION_WEB_MAINTENENCE_URL', PROVISION_MASTER_URL .'/provision/maintenance');

  // Database
  define('PROVISION_MASTER_DB', 
    provision_get_option('master_db', $GLOBALS['db_url']));
  $db = parse_url(PROVISION_MASTER_DB);
  define('PROVISION_DB_USER', $db['user']);
  define('PROVISION_DB_PASSWD', $db['pass']);
  define('PROVISION_DB_HOST', $db['host']);
 
105
  define('PROVISION_DB_TYPE', $db['scheme']);
106 107
}

108 109 110 111 112 113 114 115 116

/**
 * Implementation of hook_drush_command().
 */
function provision_drush_command() {
  
  $items['provision install'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('install'),
117 118
    'arguments' => array('domain.com' => dt('The domain of the site to install.')),
    'description' => dt('Provision a new site using the provided data.'),
119
    'bootstrap' => -1
120 121 122 123 124
  );

  $items['provision import'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('import'),
125 126
    'arguments' => array('domain.com' => dt('The domain of the site to import.')),
    'description' => dt('Turn an already running site into a provisioned site.'),
127
    'bootstrap' => -1
128 129 130 131 132
  );

  $items['provision update'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('update'),
133
    'arguments' => array('domain.com' => dt('The domain of the site to update.')),
134 135
    'description' => dt('Run any outstanding updates on the site.'),
    'bootstrap' => -1
136 137 138 139 140
  );
  
  $items['provision backup'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('backup'),
141 142
    'arguments' => array('domain.com' => dt('The domain of the site to back up.')),
    'optional arguments' => array('backup-file' => dt('The file to save the backup to. This will be a gzipped tarball.')),
143 144
    'description' => dt('Generate a back up for the site.'),
    'bootstrap' => -1
145 146 147 148 149
  );
  
  $items['provision enable'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('enable'), 
150
    'arguments' => array('domain.com' => dt('The domain of the site to enable (only if enabled).')),
151 152
    'description' => 'Enable a disabled site.',
    'bootstrap' => -1
153 154 155 156
  );
  $items['provision disable'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('disable'), 
157
    'arguments' => array('domain.com' => dt('The domain of the site to disable (only if disabled).')),    
158 159
    'description' => 'Disable a site.',
    'bootstrap' => -1
160 161 162 163 164
  );

  $items['provision verify'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('verify'),
165 166
    'arguments' => array('domain.com' => dt('The domain of the site to verify).')),    
    'description' => 'Verify that the provisioning framework is correctly installed.',
167
    'bootstrap' => -1
168 169 170 171 172 173
  );
 
  $items['provision restore'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('restore'),
    'description' => 'Restore the site to a previous backup. This will also generate a backup of the site as it was.',
174
    'arguments' => array('domain.com' => dt('The domain of the site to be restored'),
175 176 177 178 179 180 181 182 183 184
      'site_backup.tar.gz' => dt('The backup to restore the site to.')),
    'bootstrap' => -1
  );

  $items['provision deploy'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('deploy'),
    'description' => 'Deploy an existing backup to a new url.',
    'arguments' => array('domain.com' => dt('The domain to deploy the site package to.'),
      'site_backup.tar.gz' => dt('The backup to deploy.')),
185
    'bootstrap' => -1
186
  );
187 188 189 190 191 192 193 194 195

  $items['provision migrate'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('migrate'),
    'description' => 'Migrate a site between platforms.',
    'arguments' => array('domain.com' => dt('The domain to migrate. Any outstanding updates will be run.'),
      '/path/to/platform' => dt('The platform to migrate the site to.')),
    'bootstrap' => -1
  );
196 197 198 199
 
  $items['provision delete'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('delete'),
200 201
    'description' => 'Delete a site.',
    'bootstrap' => -1
202 203 204 205 206 207
  );

  $items['provision cron'] = array(
    'callback' => 'provision_command',
    'callback arguments' => array('cron'),
    'description' => 'Run cron process for site.',
208 209
    'arguments' => array('domain.com' => dt('The domain of the site to be processed')),
    'bootstrap' => -1
210 211 212 213 214 215
  );
 
  if (!function_exists('hosting_setup')) {
    $items['provision setup'] = array(
      'callback' => '_provision_setup_cmd',
      'description' => 'Initialize this platform to be able to create hosted sites.',
216
      'bootstrap' => -1
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    );
  }

  return $items;
}


/**
 * Initial setup of platform
 * 
 * Creates symlink to drush.php
 * Creates config path
 * Creates drushrc path
 *
 * This function is re-used by the hosting_setup command, as it is a superset of this functionality.
 */
function _provision_setup() {
  $success = TRUE;
235 236
  
  $drush_path = realpath($_SERVER['argv'][0]);
237 238

  $success &= provision_path('symlink', $drush_path, PROVISION_DOCROOT_PATH . '/drush.php', 
239 240
    dt('Created symlink for drush.php file'), 
    dt('Could not create symlink for drush.php'), 
241 242 243 244 245 246 247 248 249 250
    PROVISION_FRAMEWORK_ERROR);

  $success &= _provision_generate_config();
  return $success; 
}

/**
 * Drush command wrapper for the setup of the platform
 */
function _provision_setup_cmd() {
251
  _provision_setup();
252 253 254 255 256 257 258 259 260 261 262 263
 
  // @TODO use provision_output for this, but we need pretty print first.
  $logs = provision_get_log();
  foreach ($logs as $log) {
    print "$log[message]\n";
  }

  if (provision_get_error()) {
    print "\nThe command did not complete successfully, please fix the issues and re-run this script.";
  }
}

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

/**
 * Generate a provision.settings.php file to configure provision
 */
function _provision_generate_config() {
  provision_log('notice', dt("Generating drushrc.php file"));
  provision_path("chmod", PROVISION_DOCROOT_PATH . '/drushrc.php', 0600,
     dt('Changed permissions of drushrc.php to @confirm'),
      dt('Could not change permissions of drushrc.php to @confirm'));

  provision_save_platform_data();
  provision_path("chmod", PROVISION_DOCROOT_PATH . '/drushrc.php', 0400,
    dt('Changed permissions of drushrc.php to @confirm'),
    dt('Could not change permissions of drushrc.php to @confirm'));
  return TRUE;
}



function _provision_default_restart_cmd() {
  # try to detect the apache restart command
  $command = '/usr/sbin/apachectl'; # a proper default for most of the world
  foreach (array('/usr/local/sbin/apachectl', # freebsd
                 '/usr/sbin/apache2ctl', # debian + apache2
      $command) as $test) {
    if (is_executable($test)) {
      $command = $test;
    }
  }

  return "sudo $command graceful";
}