provision_apache.module 12 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
<?php
/**
 * @file
 * Apache provisioning module
 * This module simply serves to generate the virtual host entry, and make sure apache gets reloaded properly.
 * Because Drupal is running via the command line for the entirety of this process, it is only necessary to make
 * it available online once everything has been completed.
 *
 * This module still requires configuration and sanity checks. Need to figure out a way to inspect the apache configuration, 
 * to ensure that the sites are getting loaded up correctly.
 */

function provision_apache_provision_service() {
  return array( "web_server" => t("Web Server"));
}

/**
 * Implementation of hook_help().
 */
function provision_apache_help($section) {
  switch ($section) {
    case 'admin/help/provision#requirements':
23 24 25
      $output .= _provision_requirements('config_path');
      $output .= _provision_requirements('httpd_conf');
      $output .= _provision_requirements('visudo');
26 27 28 29 30
      return $output;
      break;
  }
}

31
function _provision_config_path_requirements() {
32 33 34 35 36 37
  $username = PROVISION_SCRIPT_USER;
  $group = PROVISION_WEB_GROUP;
  $vhost_path = PROVISION_VHOST_PATH;
  $mkdir_cmd['@vhost_path'] = $vhost_path;
  $mkdir_cmd['@provision_link'] = url('admin/settings/provision');
  $mkdir_cmd['@mkdir_cmd'] = <<<EOF
38
    [$username@hm2 ~]$ mkdir -p $vhost_path
39 40 41 42
    [$username@hm2 ~]$ chown $username:$username $vhost_path
    [$username@hm2 ~]$ chmod 0700 $vhost_path
EOF;

43 44 45 46 47 48
  $help['title'] = t('Web server inaccessible directory to store Virtual Host information.');
  $help['summary'] = t('The provision framework takes special care to make sure that the file permissions of the 
                       hosted sites are always as safe as can be, especially to make sure that the web server does 
                       not have the ability to modify the code of the site, therefor this information is required 
                       to assure that safety while keeping the sites accessible. 
                       The recommended path is directly above your platform path, but it can be anywhere.');
49

50 51 52
  $help['configuration'][] = t('Based on your server configuration we have determined that your path should be <code>@vhost_path</code>, 
    but you can change it change them in the <a href="@provision_link">provisioning section</a>.', $mkdir_cmd);
  $help['configuration'][] = t(' please enter the following commands : <pre>@mkdir_cmd</pre>',$mkdir_cmd);
53

54 55 56 57 58 59 60 61 62
  return $help;

}

function _provision_httpd_conf_requirements() {
  $vhost_path = PROVISION_VHOST_PATH;
  $vhost_line = <<<EOF
    Include $vhost_path
EOF;
63 64 65 66
  $help['title'] = t('Access to the server\'s httpd.conf file.');
  $help['summary'] = t('You are required to add a single line to the httpd.conf file, which allows 
                        the system to load the additional virtual hosts that are generated.</p>
                        The location of this file differs between distributions, 
67
                        but is most commonly found in <code>/etc/httpd</code> or <code>/etc/apache</code>.');
68

69 70
  $help['configuration'] = t('Once you have determined the location of your httpd.conf file, add the following line to it :
                            <pre>@vhost_line</pre>', array('@vhost_line' => $vhost_line));
71 72 73 74 75 76

  return $help;
}

function _provision_visudo_requirements() {
  $username = PROVISION_SCRIPT_USER;
77 78
  $cmd = trim(str_replace("sudo", '', PROVISION_RESTART_CMD));
  $cmd = substr($cmd, 0, strpos($cmd, " "));
79 80 81 82 83 84
  $visudo_cmd['@visudo_cmd'] = <<<EOF
    [$username@hm2 ~]$ sudo su -
    password:
    [root@hm2 ~]$ visudo
EOF;
  $visudo_cmd['@visudo_line'] = <<<EOF
85
    $username ALL=NOPASSWD: $cmd
86 87
EOF;

88 89 90 91 92 93 94 95
  $help['title'] = t('Permission to restart the httpd daemon as the user the script is running as');
  $help['summary'] = t('As the provisioning framework should not be run as root,
                         and the web server group should not be allowed access to the 
                         functionality to stop/start the web server, it is required that you provide access
                         to the Apache restart command for the user account the script will be running as. 
                         If this is not configured, every command will ask for a sudo password when restarting the server.');
  $help['configuration'] = t('Run the visudo command: <pre>@visudo_cmd</pre>
                             Then add the following line to the file: <pre>@visudo_line</pre>', 
96 97
                             $visudo_cmd);
  return $help;
98

99
}
100

101 102 103 104
/**
 * Hook into central configuration form for provisioning framework.
 */
function provision_apache_provision_configure($node = null) {
105
  // We need to define form elements for the node's title and body.
106 107
  $form['restart_cmd'] = array(
      '#type' => 'textfield',
108
      '#title' => t('Restart command'),
109
      '#required' => TRUE,
110
      '#description' => t('The command to run to restart the for new changes to take effect. This is required for the new site to become live'),
111
      '#default_value' => ($node->restart_cmd) ? $node->restart_cmd : PROVISION_RESTART_CMD,
112 113
      '#size' => 40,
      '#maxlength' => 255,
114
      '#weight' => -20,
115 116
  );

117 118 119 120
  $form['script_user'] = array(
    '#type' => 'textfield',
    '#title' => t('System account'),
    '#required' => TRUE,
121
    '#description' => t('The system account that the hosted files will belong to, for security reasons.<br />This should be a different to the account the web server is running as.'),
122
    '#default_value' => ($node->script_user) ? $node->script_user : PROVISION_SCRIPT_USER,
123
    '#size' => 20,
124
    '#maxlength' => 255,
125
    '#weight' => -15,
126
  );
127
   
128 129 130 131
  $form['web_group'] = array(
    '#type' => 'textfield',
    '#title' => t('Web server group'),
    '#required' => TRUE,
132
    '#description' => t('The group that the hosted files will belong to.<br />This should be the group the web server is running as.'),
133
    '#default_value' => ($node->web_group) ? $node->web_group : PROVISION_WEB_GROUP,
134 135
    '#size' => 20,
    '#maxlength' => 75,
136
    '#validate' => array('provision_apache_validate_web_group' => array()),
137
    '#weight' => -10,
138 139 140 141 142 143 144
  );
  
  $form['config_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Configuration path'),
    '#required' => TRUE,
    '#size' => 40,
145
    '#default_value' => ($node->config_path) ? $node->config_path : PROVISION_CONFIG_PATH,
146
    '#description' => t("The path on the server where configuration files will be stored.<br />
147 148
        It is essential that this directory should not be accessible via a web browser."),
    '#maxlength' => 255,
149
    '#weight' => -10,
150 151 152 153 154 155 156
  );
  
  $form['backup_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Backup path'),
    '#required' => TRUE,
    '#size' => 40,
157
    '#default_value' => ($node->backup_path) ? $node->backup_path : PROVISION_BACKUP_PATH,
158
    '#description' => t("The path on the server where backups will be stored.<br />
159 160
        It is essential that this directory should not be accessible via a web browser."),
    '#maxlength' => 255,
161
    '#weight' => -10,
162 163 164 165 166
  );
  
  return $form;
}

167
function provision_apache_validate_web_group($element) {
168 169
  $user = $element['#post']['script_user'];
  $group = $element['#post']['web_group'];
170 171
  if ($user && $group) {
    if (!provision_user_in_group($user, $group)) {
172
       form_set_error('web_group', t("The %user user is not in the %group group. For information on how to fix this, please check the !link.", 
173 174 175 176
         array('%user' => $user, '%group' =>  $group, '!link' => l(t("provisioning requirements"), "admin/help/provision/requirements") )));
    }
  }
}
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/**
 * Implementation of hook_provision_templates
 */
function provision_apache_provision_templates() {
  $form['vhost_template'] = array(
    '#type' => 'textarea',
    '#title' => t('Virtual Host configuration template'),
    '#description' => t('The text to use when generating a virtual host configuration file for apache'),
    '#default_value' => variable_get('provision_apache_vhost_template', _provision_apache_default_template()),
    '#cols' => 60,
    '#rows' => 5,
  );
  return $form; 
}

/**
 * The default template provided for the virtual host configuration
 */
function _provision_apache_default_template() {
197
  return file_get_contents(drupal_get_path('module', 'provision_apache') . "/provision_apache_vhost.tpl.php");
198 199
}

200 201 202 203 204 205 206
/**
 * The default template for disabled sites
 */
function _provision_apache_redirect_template() {
  return file_get_contents(drupal_get_path('module', 'provision_apache') . "/provision_apache_vhost_redirect.tpl.php");
}

207 208 209 210 211 212 213 214 215 216 217 218 219 220
/**
 * Implementation of hook_provision_pre_install
 */
function provision_apache_provision_pre_install($url, &$data) {
  return _provision_apache_create_vhost_config($url, $data);
}

/**
 * Implementation of hook_provision_post_install
 */
function provision_apache_provision_post_install($url, &$data) {
  return _provision_apache_restart_apache();  
}

221 222 223 224
function provision_apache_provision_delete($url, &$data) {
  return _provision_apache_delete_vhost_config($url, $data);
}

225 226 227 228 229 230 231 232 233 234 235 236
/**
 * Implementation of hook_provision_enable
 */
function provision_apache_provision_enable($url, &$data) {
  _provision_apache_create_vhost_config($url, $data);
  _provision_apache_restart_apache();
}

/**
 * Implementation of hook_provision_disable
 */
function provision_apache_provision_disable($url, &$data) {
237
  $data['redirect_url'] = PROVISION_WEB_DISABLE_URL;
238
  _provision_apache_create_vhost_config($url, $data, _provision_apache_redirect_template());
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
  _provision_apache_restart_apache();
}

/**
 * Implementation of hook_provision_sync
 */
function provision_apache_provision_synch($url, &$data) {
  _provision_apache_create_vhost_config($url, $data);
  _provision_apache_restart_apache();
}

/**
 * Delete virtual host file
 */
function _provision_apache_delete_vhost_config($url, $data) {
254
  provision_path("unlink", PROVISION_VHOST_PATH . "/$url", true, t("Removed apache virtual host configuration"));
255 256 257 258 259
}

/**
 * Generate virtual host file
 */
260 261 262 263 264
function _provision_apache_create_vhost_config($url, $data, $template = null) {
  if (is_null($template)) {
    $template = variable_get('provision_apache_vhost_template', _provision_apache_default_template());
  }
  provision_log("Notice", t("Generate virtual host configuration file."));
265 266
  $writable = provision_path("writable", PROVISION_VHOST_PATH, true , '',
      t("Virtual host configuration path @path is not writable."), 
267 268
      PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
  if ($writable) {
269
    $file = fopen(PROVISION_VHOST_PATH . '/' . $url, "w");
270
    $text = provision_render_config($template, $data);
271 272 273 274 275 276 277 278 279 280
    fwrite($file, $text);
    fclose($file);
  }
}
 
/**
 * Restart Apache
 */
function _provision_apache_restart_apache() {
  # This is required to be configurable, due to the fact that different hosts might need to do this differently.
281
  # TODO : test for this instead of relying on a configuration setting?
282
  $return = drush_shell_exec(escapeshellcmd(PROVISION_RESTART_CMD));
283 284 285 286 287 288 289
  if (!$return) {
    provision_set_error(PROVISION_WEB_ERROR);
    provision_log("error", "Web server could not be restarted. Changes might not be available until this has been done.");
  }
}

function provision_apache_provision_verify() {
290
  $exists = _provision_create_dir(PROVISION_VHOST_PATH, t("Virtual host configuration"), 0700);
291
}
292 293 294 295 296

/**
 * Implementation of hook_provision_pre_restore
 */
function provision_apache_provision_pre_restore($url, &$data) {
297
  $data['redirect_url'] = PROVISION_WEB_MAINTENANCE_URL;
298 299 300 301
  _provision_apache_create_vhost_config($url, $data, _provision_apache_redirect_template());
  _provision_apache_restart_apache();
}

302 303 304 305 306 307
function provision_apache_provision_pre_restore_rollback($url, $data) {
  _provision_apache_create_vhost_config($url, $data);
  _provision_apache_restart_apache();
  _provision_recursive_delete(PROVISION_SITES_PATH . "/$url.restore");
}

308 309 310 311
function provision_apache_provision_post_restore($url, &$data) {
  _provision_apache_create_vhost_config($url, $data);
  _provision_apache_restart_apache();
}
312 313 314 315 316

// The old db details should have been switched back by the mysql rollback at this point.
function provision_apache_provision_post_restore_rollback($url, &$data) {
  provision_apache_provision_post_restore($url, $data);
}