hosting.module in Hosting 5
Same filename and directory in other branches
Hosting module
Contains just about all the interface magic of hostmaster.
File
hosting.moduleView source
<?php
/**
* @file Hosting module
*
* Contains just about all the interface magic of hostmaster.
*/
/**
* Not split for performance reasons. Just to keep code together.
*/
include_once 'hosting_help.inc';
include_once 'hosting.wizard.inc';
include_once 'hosting.queues.inc';
include_once 'hosting.features.inc';
/**
* Implementation of hook_menu()
*/
function hosting_menu($may_cache = true) {
global $user;
$items = array();
hosting_wizard_menu($may_cache, $items);
if ($may_cache) {
$items[] = array(
'path' => 'hosting/disabled',
'title' => t('Site disabled'),
'callback' => 'hosting_disabled_site',
'access' => TRUE,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'hosting/maintenance',
'title' => t('Site maintenance'),
'callback' => 'hosting_site_maintenance',
'access' => TRUE,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/help/provision/requirements',
'title' => t('Provisioning requirements'),
'description' => t("Information of how to configure the provisioning system."),
'callback' => 'hosting_help_requirements',
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/hosting',
'title' => t('Hosting'),
'description' => t('Configure and manage the hosting system'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'hosting_features_form',
),
'access' => user_access('administer hosting'),
'type' => MENU_NORMAL_ITEM,
);
$items[] = array(
'path' => 'admin/hosting/features',
'title' => t('Features'),
'description' => t('Configure the exposed functionality of the Hosting system'),
'weight' => -100,
'callback' => 'drupal_get_form',
'callback arguments' => array(
'hosting_features_form',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'access' => user_access('administer hosting features'),
);
$items[] = array(
'path' => 'admin/hosting/queues',
'title' => t('Queues'),
'description' => t('Configure the frequency that cron, backup and task events are process'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'hosting_queues_configure',
),
'type' => MENU_LOCAL_TASK,
'access' => user_access('administer hosting queues'),
);
// Kludge : Replace node/add page to hide functionality.
$items[] = array(
'path' => 'node/add',
'title' => t('Create content'),
'callback' => '_hosting_node_add',
'access' => user_access('access content'),
'type' => MENU_ITEM_GROUPING,
'weight' => 1,
);
// Queue page & task lists
$items[] = array(
'path' => 'hosting/queues',
'callback' => 'hosting_queues',
'type' => MENU_CALLBACK,
'access' => user_access('access task logs'),
);
// Disable unsupported features.
$features = hosting_get_features();
$types = node_get_types();
foreach ($features as $type => $feature) {
if (isset($feature['node'])) {
$type_url_str = str_replace('_', '-', $feature['node']);
$items[] = array(
'path' => 'node/add/' . $type_url_str,
'title' => drupal_ucfirst($types[$feature['node']]->name),
'access' => ($user->uid == 1 || user_access('create ' . $feature['node'])) && hosting_feature($type) != HOSTING_FEATURE_DISABLED,
);
}
}
}
else {
drupal_add_css(drupal_get_path('module', 'hosting') . '/hosting.css');
}
return $items;
}
function hosting_disabled_site($url) {
drupal_set_breadcrumb(array());
return t("!url has been disabled by the site administrators", array(
'!url' => $url,
));
}
function hosting_site_maintenance($url) {
drupal_set_breadcrumb(array());
return t("!url has being worked on presently. Check back later.", array(
'!url' => $url,
));
}
/**
* Implementation of hook_nodeapi
*
* This function redirects to hosting_nodeapi_$nodetype_$op calls, to save ourselves
* from an incessant amount of intricately nested code, and allow easier extension / maintenance.
*/
function hosting_nodeapi(&$node, $op, $teaser) {
$func = "hosting_nodeapi_" . $node->type . "_" . str_replace(" ", "_", $op);
if (function_exists($func)) {
$func($node, $op, $teaser);
}
}
/**
* Implementation of hook_perm
*/
function hosting_perm() {
return array(
'access hosting wizard',
'administer hosting queues',
'administer hosting features',
'administer hosting',
);
}
/**
* Implementation of hook_init
*/
function hosting_init() {
// Definitions for the default platforms, clients etc.
// Done to avoid using 'magic numbers'
define('HOSTING_DEFAULT_CLIENT', variable_get('hosting_default_client', 1));
define('HOSTING_DEFAULT_DB_SERVER', variable_get('hosting_default_db_server', 2));
define('HOSTING_DEFAULT_WEB_SERVER', variable_get('hosting_default_web_server', 3));
define('HOSTING_DEFAULT_PLATFORM', variable_get('hosting_default_platform', 6));
define('HOSTING_OWN_DB_SERVER', variable_get('hosting_own_db_server', 2));
define('HOSTING_OWN_WEB_SERVER', variable_get('hosting_own_web_server', 3));
define('HOSTING_OWN_PLATFORM', variable_get('hosting_own_platform', 6));
// These defaults could be temporary.
$info = posix_getgrgid(posix_getgid());
define('HOSTING_DEFAULT_WEB_GROUP', $info['name']);
$user = get_current_user();
if ($user == 'root') {
$user = 'aegir';
# a better default than root
}
define('HOSTING_DEFAULT_SCRIPT_USER', $user);
define('HOSTING_DEFAULT_RESTART_CMD', _hosting_default_restart_cmd());
$path = $_SERVER['PWD'] ? $_SERVER['PWD'] : $_SERVER['DOCUMENT_ROOT'];
define('HOSTING_DEFAULT_DOCROOT_PATH', rtrim($path, '/'));
$parts = explode("/", rtrim($path, '/'));
array_pop($parts);
define('HOSTING_DEFAULT_PARENT_PATH', rtrim(implode("/", $parts), '/'));
define('HOSTING_DEFAULT_BACKUP_PATH', HOSTING_DEFAULT_PARENT_PATH . '/backups');
define('HOSTING_DEFAULT_CONFIG_PATH', HOSTING_DEFAULT_PARENT_PATH . '/config');
define('HOSTING_DEFAULT_VHOST_PATH', HOSTING_DEFAULT_CONFIG_PATH . '/vhost.d');
}
/**
* This function should not have to be duplicated between hosting/provision
*/
function _hosting_default_restart_cmd() {
$command = '/usr/sbin/apachectl';
# a proper default for most of the world
foreach (explode(':', $_SERVER['PATH']) as $path) {
$options[] = "{$path}/apache2ctl";
$options[] = "{$path}/apachectl";
}
# try to detect the apache restart command
$options[] = '/usr/local/sbin/apachectl';
# freebsd
$options[] = '/usr/sbin/apache2ctl';
# debian + apache2
$options[] = $command;
foreach ($options as $test) {
if (is_executable($test)) {
$command = $test;
break;
}
}
return "sudo {$command} graceful";
}
function _hosting_node_link($nid, $title = null) {
if (is_null($nid)) {
return t("None");
}
$node = node_load($nid);
$title = !is_null($title) ? $title : filter_xss($node->title);
if ($node->nid) {
return node_access('view', $node) ? l($title, "node/" . $node->nid) : filter_xss($node->title);
}
}
function hosting_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks['hosting_summary'] = array(
'info' => t('Hosting summary'),
'enabled' => 1,
'region' => 'left',
'weight' => 10,
);
$blocks['hosting_queues'] = array(
'info' => t('Hosting queues'),
'enabled' => 1,
'region' => 'right',
'weight' => 0,
);
$blocks['hosting_queues_summary'] = array(
'info' => t('Hosting queues summary'),
'enabled' => 1,
'region' => 'right',
'weight' => 1,
);
return $blocks;
case 'view':
switch ($delta) {
case 'hosting_summary':
return array(
'title' => t('Summary'),
'content' => hosting_summary_block(),
);
break;
case 'hosting_queues':
return array(
'title' => t('Queues'),
'content' => hosting_queue_block(),
);
break;
case 'hosting_queues_summary':
return array(
'title' => t('Queues summary'),
'content' => hosting_queue_summary_block(),
);
break;
}
}
}
function hosting_queue_summary_block() {
if (user_access('administer hosting queues')) {
$queues = hosting_get_queues();
$output = '';
foreach ($queues as $queue => $info) {
$disp = array();
# special case
if (!$info['enabled']) {
$disp[] = t('Status: disabled');
continue;
}
$disp[] = t('Status: enabled');
foreach (array(
'description' => t('Description'),
'frequency' => t('Frequency'),
'items' => t('Items per run'),
'total_items' => t('Items in queue'),
'last_run' => t('Last run'),
) as $key => $title) {
if ($key == 'last_run') {
$info[$key] = hosting_format_interval($info[$key]);
}
elseif ($key == 'frequency') {
$info[$key] = t('every @interval', array(
'@interval' => format_interval($info[$key]),
));
}
$disp[] = $title . ": " . $info[$key];
}
$output .= theme('item_list', $disp, $info['name']);
/* to print all stats of the queue... */
#$lambda = create_function('$k,$v', 'return "$k: $v";');
#$output .= theme('item_list', array_map($lambda, array_keys($info), $info), $info['name']);
}
return $output;
}
}
function hosting_queue_block() {
if (user_access('access task logs')) {
$queues = hosting_get_queues();
$output = '';
foreach ($queues as $queue => $info) {
$func = 'hosting_' . $info['singular'] . '_summary';
if (function_exists($func)) {
$output .= $func();
}
}
return $output;
}
}
function hosting_summary_block() {
if (user_access('administer hosting')) {
return theme('hosting_summary_block', module_invoke_all('hosting_summary'));
}
}
function theme_hosting_summary_block($components) {
foreach ($components as $component) {
$output .= $component;
}
return $output;
}
/**
* Check if a hostname provided is an ip address
*/
function _hosting_valid_ip($hostname) {
//TODO : provide IPv6 support
$parts = explode('.', $hostname);
if (sizeof($parts) != 4) {
return false;
}
foreach ($parts as $part) {
if ((int) $part < 0 || (int) $part > 255) {
return false;
}
}
return true;
}
/**
* Check if the FQDN provided is valid.
*/
function _hosting_valid_fqdn($fqdn) {
# regex is an implementation of RFC1035
return preg_match("/^([a-z0-9]([a-z0-9-]*[a-z0-9])?\\.?)+\$/i", $fqdn);
}
function hosting_format_interval($ts) {
if ($ts == mktime()) {
return t('Now');
}
if (!$ts) {
//Treats EPOCH as never
return t('Never');
}
return t("@interval ago", array(
"@interval" => format_interval(mktime() - $ts, 1),
));
}
function hosting_setup() {
variable_set('hosting_dispatch_enabled', FALSE);
## attempting to run the dispatch command, to make sure it runs without the queue being
## enabled.
variable_set('hosting_dispatch_enabled', TRUE);
print _hosting_dispatch_cmd();
exec(_hosting_dispatch_cmd(), $return, $code);
variable_set('hosting_dispatch_enabled', FALSE);
$return = join("\n", $return);
$data = unserialize($return);
if ($code == DRUSH_SUCCESS) {
variable_set('hosting_dispatch_enabled', TRUE);
drush_log(t("Dispatch command was run successfully"), 'success');
_hosting_setup_cron();
}
else {
drush_set_error('DRUSH_FRAMEWORK_ERROR', dt("Dispatch command could not be run. Returned: \n@return", array(
'@return' => $return,
)));
}
if (drush_get_error()) {
print "\nThe command did not complete successfully, please fix the issues and re-run this script.";
}
}
function _hosting_setup_cron() {
$existing = FALSE;
exec('crontab -l 2> /dev/null', $cron);
variable_set('hosting_cron_backup', $cron);
if (sizeof($cron)) {
foreach ($cron as $line => $entry) {
if (preg_match('/hosting dispatch/', $entry)) {
$pattern = "+(.*)'(.*)/drush.php'(.*)--root='(.*)'.*+";
$replace = sprintf("\$1 '%s' --root='\$4' \$3 > /dev/null)", DRUSH_COMMAND);
$cron[$line] = preg_replace($pattern, $replace, $entry);
drush_log(dt("Existing hosting dispatch cron entry was found. Replacing"));
$existing = TRUE;
break;
}
}
}
else {
drush_log("message", t("No existing crontab was found"));
}
if (!$existing) {
$cron[] = hosting_queues_cron_cmd();
}
$tmpnam = tempnam('hostmaster', 'hm.cron');
$fp = fopen($tmpnam, "w");
foreach ($cron as $line) {
fwrite($fp, $line . "\n");
}
fclose($fp);
system(sprintf('crontab %s', escapeshellarg($tmpnam)));
unlink($tmpnam);
drush_log("Notice", t("Installed hosting dispatch cron entry to run every minute"));
}
/**
* Replacement node/add page.
*
* Major kludge to remove the hidden node types from node/add page
*
* Copied from node.module
*/
function _hosting_node_add($type = '') {
global $user;
$types = node_get_types();
$type = $type ? str_replace('-', '_', $type) : NULL;
// If a node type has been specified, validate its existence.
if (isset($types[$type]) && user_access('create ' . $type) && hosting_feature($type) !== HOSTING_FEATURE_DISABLED) {
// Initialize settings:
$node = array(
'uid' => $user->uid,
'name' => $user->name,
'type' => $type,
);
drupal_set_title(t('Submit @name', array(
'@name' => $types[$type]->name,
)));
$output = drupal_get_form($type . '_node_form', $node);
}
else {
// If no (valid) node type has been provided, display a node type overview.
foreach ($types as $type) {
if (function_exists($type->module . '_form') && user_access('create ' . $type->type) && hosting_feature($type->type) !== HOSTING_FEATURE_DISABLED) {
$type_url_str = str_replace('_', '-', $type->type);
$title = t('Add a new @s.', array(
'@s' => $type->name,
));
$out = '<dt>' . l(drupal_ucfirst($type->name), "node/add/{$type_url_str}", array(
'title' => $title,
)) . '</dt>';
$out .= '<dd>' . filter_xss_admin($type->description) . '</dd>';
$item[$type->name] = $out;
}
}
if (isset($item)) {
uksort($item, 'strnatcasecmp');
$output = t('Choose the appropriate item from the list:') . '<dl>' . implode('', $item) . '</dl>';
}
else {
$output = t('No content types available.');
}
}
return $output;
}
/**
* List queues or tasks in a queue if a key is provided
*/
function hosting_queues($key = '') {
$queues = hosting_get_queues();
if ($queues[$key]) {
if ($queues[$key]['name']) {
$output .= "<h1>" . $queues[$key]['name'] . "</h1>";
}
$func = 'hosting_' . $queues[$key]['singular'] . '_list';
if (function_exists($func)) {
$output .= $func();
}
}
else {
foreach ($queues as $key => $queue) {
$item[] = l($queue['name'], 'hosting/queues/' . $key);
}
$output .= theme('item_list', $item, t('Queues'));
}
return $output;
}
/**
* Generate context sensitive breadcrumbs
*/
function hosting_set_breadcrumb($node) {
$breadcrumbs[] = l(t('Home'), NULL);
switch ($node->type) {
case 'task':
$breadcrumbs[] = _hosting_node_link($node->rid);
break;
case 'platform':
$breadcrumbs[] = _hosting_node_link($node->web_server);
break;
case 'site':
$breadcrumbs[] = _hosting_node_link($node->platform);
break;
}
drupal_set_breadcrumb($breadcrumbs);
}
/**
* Page callback
*
* Configure the frequency of tasks.
*/
function hosting_queues_configure() {
drupal_add_css(drupal_get_path('module', 'hosting') . '/hosting.css');
$units = array(
strtotime("1 second", 0) => t("Seconds"),
strtotime("1 minute", 0) => t("Minutes"),
strtotime("1 hour", 0) => t("Hours"),
strtotime("1 day", 0) => t("Days"),
strtotime("1 week", 0) => t("Weeks"),
);
$queues = hosting_get_queues();
$form['#tree'] = TRUE;
foreach ($queues as $queue => $info) {
$form[$queue]['description'] = array(
'#type' => 'item',
'#value' => $info['name'],
'#description' => $info['description'],
);
$form[$queue]["enabled"] = array(
'#type' => 'checkbox',
'#default_value' => $info['enabled'],
);
$form[$queue]["last_run"] = array(
'#value' => hosting_format_interval(variable_get('hosting_queue_' . $queue . '_last_run', false)),
);
$form[$queue]['frequency']['#prefix'] = "<div class='hosting-queue-frequency'>";
$form[$queue]['frequency']['#suffix'] = "</div>";
if ($info['type'] == 'batch') {
$form[$queue]['frequency']['items'] = array(
'#value' => t('%count %items every ', array(
"%count" => $info['total_items'],
"%items" => format_plural($info['total_items'], $info['singular'], $info['plural']),
)),
);
}
else {
$form[$queue]['frequency']['items'] = array(
'#type' => 'textfield',
'#size' => 3,
'#maxlength' => 3,
'#default_value' => $info['items'],
'#suffix' => t(' %items every ', array(
'%items' => $info['plural'],
)),
);
}
foreach (array_reverse(array_keys($units)) as $length) {
$unit = $units[$length];
if (!($info['frequency'] % $length)) {
$frequency_ticks = $info['frequency'] / $length;
$frequency_length = $length;
break;
}
}
$form[$queue]['frequency']["ticks"] = array(
'#type' => 'textfield',
'#default_value' => $frequency_ticks,
'#maxlength' => 5,
'#size' => 5,
);
$form[$queue]['frequency']["unit"] = array(
'#type' => 'select',
'#options' => $units,
'#default_value' => $frequency_length,
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
);
return $form;
}
function theme_hosting_queues_configure($form) {
$queues = hosting_get_queues();
$rows = array();
$header = array(
'',
t('Description'),
array(
'data' => t('Frequency'),
'class' => 'hosting-queue-frequency-head',
),
t('Last run'),
);
foreach ($queues as $key => $info) {
$row = array();
$row[] = drupal_render($form[$key]['enabled']);
$row[] = drupal_render($form[$key]['description']);
$row[] = drupal_render($form[$key]['frequency']);
$row[] = drupal_render($form[$key]['last_run']);
$rows[] = $row;
}
$output = theme('table', $header, $rows);
$output .= drupal_render($form['submit']);
$output .= drupal_render($form);
return $output;
}
function hosting_queues_configure_submit($form_id, $values) {
foreach (hosting_get_queues() as $queue => $info) {
if ($values[$queue]) {
variable_set("hosting_queue_" . $queue . "_enabled", $values[$queue]['enabled']);
variable_set("hosting_queue_" . $queue . "_frequency", $values[$queue]['frequency']['ticks'] * $values[$queue]['frequency']['unit']);
if ($info['type'] == 'serial') {
variable_set("hosting_queue_" . $queue . "_items", $values[$queue]['frequency']['items']);
}
}
}
}
Functions
Name | Description |
---|---|
hosting_block | |
hosting_disabled_site | |
hosting_format_interval | |
hosting_init | Implementation of hook_init |
hosting_menu | Implementation of hook_menu() |
hosting_nodeapi | Implementation of hook_nodeapi |
hosting_perm | Implementation of hook_perm |
hosting_queues | List queues or tasks in a queue if a key is provided |
hosting_queues_configure | Page callback |
hosting_queues_configure_submit | |
hosting_queue_block | |
hosting_queue_summary_block | |
hosting_setup | |
hosting_set_breadcrumb | Generate context sensitive breadcrumbs |
hosting_site_maintenance | |
hosting_summary_block | |
theme_hosting_queues_configure | |
theme_hosting_summary_block | |
_hosting_default_restart_cmd | This function should not have to be duplicated between hosting/provision |
_hosting_node_add | Replacement node/add page. |
_hosting_node_link | |
_hosting_setup_cron | |
_hosting_valid_fqdn | Check if the FQDN provided is valid. |
_hosting_valid_ip | Check if a hostname provided is an ip address |