You are here

hosting_web_server.module in Hosting 5

Web server node type is defined here.

File

web_server/hosting_web_server.module
View source
<?php

/**
 * @file Web server node type is defined here.
 */
function hosting_web_server_hosting_service() {
  return array(
    "web_server" => t("Web Server"),
  );
}

/**
 * Implementation of hook_help().
 */
function hosting_web_server_help($section) {
  switch ($section) {
    case 'admin/help/provision#requirements':
      $output .= _hosting_requirements('drush_path');
      $output .= _hosting_requirements('config_path');
      $output .= _hosting_requirements('httpd_conf');
      $output .= _hosting_requirements('visudo');
      return $output;
      break;
  }
}
function _hosting_config_path_requirements() {
  $username = HOSTING_DEFAULT_SCRIPT_USER;
  $group = HOSTING_DEFAULT_WEB_GROUP;
  $vhost_path = HOSTING_DEFAULT_CONFIG_PATH;
  $mkdir_cmd['@vhost_path'] = $vhost_path;
  $mkdir_cmd['@mkdir_cmd'] = <<<EOF
    mkdir -p {<span class="php-variable">$vhost_path</span>}
    chown {<span class="php-variable">$username</span>}:{<span class="php-variable">$username</span>} {<span class="php-variable">$vhost_path</span>}
    chmod 0700 {<span class="php-variable">$vhost_path</span>}
EOF;
  $help['title'] = t('Write access to a directory to store configuration 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, therefore 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.');
  $help['configuration'][] = t('Based on your server configuration we have determined that your path should be <code>@vhost_path</code>.', $mkdir_cmd);
  $help['configuration'][] = t(' please enter the following commands : <pre>@mkdir_cmd</pre>', $mkdir_cmd);
  return $help;
}
function _hosting_drush_path_requirements() {
  $help['title'] = t('Full path to the Drush installation on this server.');
  $help['summary'] = t('<a href="http://drupal.org/project/drush">Drush</a> is a command line script that is used to
                       interact with Drupal sites through the unix shell.<br />
                       To be able to use Aegir, you need to download Drush, and place it somewhere on your server
                       that is accessible by the script user (eg: <code>/home/!script_user/drush/drush.php</code>).<br />
                       Once Drush is installed, you are required to download <a href="http://drupal.org/project/provision">Provision</a>
                       and place it in the .drush folder of the script user\'s home directory.
                       (eg: <code>/home/!script_user/.drush/provision</code>).<br />', array(
    '!script_user' => HOSTING_DEFAULT_SCRIPT_USER,
  ));
  return $help;
}
function _hosting_httpd_conf_requirements() {
  $vhost_path = HOSTING_DEFAULT_VHOST_PATH;
  $vhost_line = <<<EOF
    Include {<span class="php-variable">$vhost_path</span>}
EOF;
  $help['title'] = t('Modify the server\'s httpd.conf file');
  $help['summary'] = t('To allow the system to load additional virtual hosts that are generated,
                        you are required to add a line to your httpd.conf file.</p>
                        The location of this file differs between distributions,
                        but is most commonly found in <code>/etc/httpd</code> or <code>/etc/apache</code>.');
  $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,
  ));
  return $help;
}
function _hosting_visudo_requirements() {
  $username = HOSTING_DEFAULT_SCRIPT_USER;
  $cmd = trim(str_replace("sudo", '', HOSTING_DEFAULT_RESTART_CMD));
  $cmd = substr($cmd, 0, strpos($cmd, " "));
  $visudo_cmd['@visudo_cmd'] = <<<EOF
    sudo visudo
EOF;
  $visudo_cmd['@visudo_line'] = <<<EOF
    {<span class="php-variable">$username</span>} ALL=NOPASSWD: {<span class="php-variable">$cmd</span>}
EOF;
  $help['title'] = t('Permission to restart the web server');
  $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>', $visudo_cmd);
  return $help;
}
function hosting_web_server_node_info() {
  $types["web_server"] = array(
    "type" => 'web_server',
    "name" => 'Web server',
    "module" => 'hosting_web_server',
    "has_title" => true,
    "title_label" => t('Host name'),
    "description" => hosting_node_help("web_server"),
    "has_body" => 0,
    "body_label" => '',
    "min_word_count" => 0,
  );
  return $types;
}
function hosting_web_server_hosting_feature() {
  $features['web_server'] = array(
    'title' => t('Web servers'),
    'description' => t('Allow for creation of multiple web server nodes, and for distributed management of sites.'),
    'status' => HOSTING_FEATURE_DISABLED,
    'node' => 'web_server',
    'group' => 'experimental',
  );
  return $features;
}
function hosting_web_server_perm() {
  return array(
    'create web server',
    'view web server',
    'edit web server',
    'delete web server',
  );
}
function hosting_web_server_access($op, $node) {
  if (!hosting_feature('web_server')) {
    return FALSE;
  }
  switch ($op) {
    case 'create':
      return user_access('create web server');
      break;
    case 'view':
      return user_access('view web server');
      break;
    case 'update':
      return user_access('edit web server');
      break;
    case 'delete':
      return user_access('delete web server');
      break;
    default:
      break;
  }
}

/**
 * Small helper function to get web servers.
*/
function _hosting_get_web_servers() {
  $return = array();
  $result = db_query("SELECT nid, title FROM {node} WHERE type='web_server' AND status=1");
  while ($server = db_fetch_object($result)) {
    $return[$server->nid] = $server->title;
  }
  return $return;
}

/**
 * Implementation of hook_form().
 */
function hosting_web_server_form(&$node) {
  $type = node_get_types('type', $node);
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Web server hostname'),
    '#required' => TRUE,
    '#default_value' => $node->title,
    '#description' => t('The host name of the server. This is the address that will be used by Hostmaster to connect to the web server to issue commands.<br /><strong>Be careful when changing the node title, it is used to create the SQL users if the IP address, below, is not set.</strong>'),
    '#weight' => -10,
  );

  #TODO : rename to db_ip_address, to avoid confusion
  $form['ip_address'] = array(
    '#type' => 'textfield',
    '#title' => t('IP address'),
    '#default_value' => $node->ip_address,
    '#size' => 15,
    '#maxlength' => 15,
    '#description' => t("The IP address the server can be accessed by. This will be used to create database grants, amongst other things.<br />If this is empty, Hostmaster will attempt to resolve the hostname to get the address.<br />If that fails, the hostname (ie. the node title) will be used instead."),
    '#weight' => -9,
  );
  $form['drush_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Drush path'),
    '#required' => TRUE,
    '#size' => 40,
    '#default_value' => $node->drush_path ? $node->drush_path : '',
    '#description' => t("The full path to the drush.php script on this server."),
    '#maxlength' => 255,
    '#weight' => -8,
  );
  $form['restart_cmd'] = array(
    '#type' => 'textfield',
    '#title' => t('Restart command'),
    '#required' => TRUE,
    '#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'),
    '#default_value' => $node->restart_cmd ? $node->restart_cmd : HOSTING_DEFAULT_RESTART_CMD,
    '#size' => 40,
    '#maxlength' => 255,
    '#weight' => -7,
  );
  $form['script_user'] = array(
    '#type' => 'textfield',
    '#title' => t('System account'),
    '#required' => TRUE,
    '#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.'),
    '#default_value' => $node->script_user ? $node->script_user : HOSTING_DEFAULT_SCRIPT_USER,
    '#size' => 20,
    '#maxlength' => 255,
    '#weight' => -6,
  );
  $form['web_group'] = array(
    '#type' => 'textfield',
    '#title' => t('Web server group'),
    '#required' => TRUE,
    '#description' => t('The group that the hosted files will belong to.<br />This should be the group the web server is running as.'),
    '#default_value' => $node->web_group ? $node->web_group : HOSTING_DEFAULT_WEB_GROUP,
    '#size' => 20,
    '#maxlength' => 75,
    '#weight' => -5,
  );
  $form['config_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Configuration path'),
    '#required' => TRUE,
    '#size' => 40,
    '#default_value' => $node->config_path ? $node->config_path : HOSTING_DEFAULT_CONFIG_PATH,
    '#description' => t("The path on the server where configuration files will be stored.<br />\n        It is essential that this directory should not be accessible via a web browser."),
    '#maxlength' => 255,
    '#weight' => -4,
  );
  $form['backup_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Backup path'),
    '#required' => TRUE,
    '#size' => 40,
    '#default_value' => $node->backup_path ? $node->backup_path : HOSTING_DEFAULT_BACKUP_PATH,
    '#description' => t("The path on the server where backups will be stored.<br />\n        It is essential that this directory should not be accessible via a web browser."),
    '#maxlength' => 255,
    '#weight' => -3,
  );
  return $form;
}

/**
 * Implementation of hook_validate().
 */
function hosting_web_server_validate(&$node, &$form) {
  if ($node->script_user == 'root') {
    form_set_error('script_user', t('For security reasons, you should not run drush commands as the root user. Please choose a different system account name.'));
  }
  if (!$node->ip_address) {
    if (!_hosting_valid_fqdn($node->title)) {
      form_set_error('title', t('Invalid valid domain name. Either choose a proper domain name or hardcode the IP address of the webserver.'));
    }
    $ip = gethostbyname($node->title);

    // setup IP only if resolution succeeded
    if ($ip != $node->title) {
      form_set_value($form['ip_address'], $ip);
      $node->ip_address = $ip;

      // required to fool the ip check below
      drupal_set_message(t('Initialized the webserver IP to %ip based on hostname %name', array(
        '%ip' => $ip,
        '%name' => $node->title,
      )), 'message');
    }
    else {
      form_set_error('title', t('Could not resolve IP address of webserver %name. Either set the web server name to a FQDN (Fully Qualified Domain Name) or hardcode the IP here.', array(
        '%name' => $node->title,
      )));
    }
  }
  if (!_hosting_valid_ip($node->ip_address)) {
    form_set_error('ip_address', t('Invalid IP address'));
  }
}

/**
 * Implementation of hook_insert().
 */
function hosting_web_server_insert($node) {
  db_query("INSERT INTO {hosting_web_server} (vid, nid, ip_address, script_user, web_group, config_path, backup_path, restart_cmd, drush_path) \n      VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $node->vid, $node->nid, $node->ip_address, $node->script_user, $node->web_group, $node->config_path, $node->backup_path, $node->restart_cmd, $node->drush_path);
}

/**
 * Implementation of hook_update().
 *
 * As an existing node is being updated in the database, we need to do our own
 * database updates.
 */
function hosting_web_server_update($node) {

  // if this is a new node or we're adding a new revision,
  if ($node->revision) {
    hosting_web_server_insert($node);
  }
  else {
    db_query("UPDATE {hosting_web_server} SET \n                  ip_address = '%s', script_user = '%s', web_group = '%s', \n                  config_path = '%s', backup_path = '%s', restart_cmd = '%s',\n                  drush_path = '%s'\n              WHERE \n                  vid = %d", $node->ip_address, $node->script_user, $node->web_group, $node->config_path, $node->backup_path, $node->restart_cmd, $node->drush_path, $node->vid);
  }
}
function hosting_nodeapi_web_server_delete_revision(&$node) {
  db_query('DELETE FROM {hosting_web_server} WHERE vid = %d', $node->vid);
}

/**
 * Implementation of hook_delete().
 */
function hosting_web_server_delete($node) {
  db_query('DELETE FROM {hosting_web_server} WHERE nid = %d', $node->nid);
}

/**
 * Implementation of hook_load().
 */
function hosting_web_server_load($node) {
  $additions = db_fetch_object(db_query('SELECT ip_address, script_user, web_group, config_path, backup_path, restart_cmd, drush_path FROM {hosting_web_server} WHERE vid = %d', $node->vid));
  return $additions;
}

/**
 * Implementation of hook_view().
 */
function hosting_web_server_view($node, $teaser = FALSE, $page = FALSE) {
  $node = node_prepare($node, $teaser);
  $node->content['info'] = array(
    '#prefix' => '<div id="hosting-webserver-info">',
    '#suffix' => '</div>',
  );
  if ($node->ip_address) {
    $node->content['info']['ip_address'] = array(
      '#type' => 'item',
      '#title' => t('IP address'),
      '#value' => filter_xss($node->ip_address),
    );
  }
  $node->content['info']['drush_path'] = array(
    '#type' => 'item',
    '#title' => t('Drush path'),
    '#value' => filter_xss($node->drush_path),
  );
  $node->content['info']['script_user'] = array(
    '#type' => 'item',
    '#title' => t('Script user'),
    '#value' => filter_xss($node->script_user),
  );
  $node->content['info']['web_group'] = array(
    '#type' => 'item',
    '#title' => t('Web server group'),
    '#value' => filter_xss($node->web_group),
  );
  $node->content['info']['config_path'] = array(
    '#type' => 'item',
    '#title' => t('Configuration path'),
    '#value' => filter_xss($node->config_path),
  );
  $node->content['info']['backup_path'] = array(
    '#type' => 'item',
    '#title' => t('Backup path'),
    '#value' => filter_xss($node->backup_path),
  );
  $node->content['info']['restart_cmd'] = array(
    '#type' => 'item',
    '#title' => t('Restart command'),
    '#value' => filter_xss($node->restart_cmd),
  );
  return $node;
}
function hosting_web_server_hosting_summary() {
  $summary = array();
  $web_servers = _hosting_get_web_servers();
  $summary['web_servers'] = theme('item_list', array_map('_hosting_node_link', array_keys($web_servers)), t('Web servers'));
  return $summary;
}
function hosting_web_server_form_alter($form_id, &$form) {
  switch ($form_id) {
    case 'web_server_node_form':
      if ($form['#post']['op'] == 'Preview' && !$form['#post']['ip_address']) {
        $ip = gethostbyname($form['#post']['title']);

        // setup IP only if resolution succeeded
        if ($ip != $node->title) {
          drupal_set_message(t('Initialized the webserver IP to %ip based on hostname %name', array(
            '%ip' => $ip,
            '%name' => $form['#post']['title'],
          )), 'message');
          $form['#post']['ip_address'] = $ip;
        }
      }
      break;
  }
}