varnish.module in Varnish 5
Same filename and directory in other branches
varnish.module Provide drupal hooks for integration with the Varnish control layer.
File
varnish.moduleView source
<?php
// $Id:
define(VARNISH_NO_CLEAR, 0);
define(VARNISH_DEFAULT_CLEAR, 1);
define(VARNISH_SELECTIVE_CLEAR, 2);
/**
* @file varnish.module
* Provide drupal hooks for integration with the Varnish control layer.
*/
/**
* Implementation of hook_menu()
*
* Set up admin settings callbacks, etc.
*/
function varnish_menu() {
$items = array();
$items[] = array(
'path' => 'admin/settings/varnish',
'title' => 'Varnish settings',
'description' => 'Configure your varnish integration.',
'callback' => 'drupal_get_form',
'callback arguments' => array(
'varnish_admin_settings_form',
),
'access' => user_access('administer varnish'),
);
$items[] = array(
'path' => 'admin/reports/varnish',
'title' => 'Varnish status',
'description' => 'Configure your varnish integration.',
'callback' => 'varnish_admin_reports_page',
'access' => user_access('administer varnish'),
);
$items[] = array(
'path' => 'admin/settings/varnish/cache-clear',
'title' => 'Clear Varnish cache',
'description' => 'Clear your varnish integration.',
'callback' => 'varnish_flush_cache_manually',
'access' => user_access('administer varnish'),
);
return $items;
}
/**
* Implemetation of hook_perm()
*
* Allows admins to control access to varnish settings.
*/
function varnish_perm() {
return array(
'administer varnish',
);
}
/**
* Implementation of hook_requirements()
*
* Insure that varnish's connection is good.
*/
function varnish_requirements($phase) {
if ($phase == 'runtime') {
$requirements = array(
'varnish',
);
$requirements['varnish']['title'] = t('Varnish status');
// try a varnish admin connect, report results
$status = _varnish_terminal_run('status', 300);
if (strpos($status, 'Child in state running') === FALSE) {
$requirements['varnish']['value'] = t('Varnish connection broken');
$requirements['varnish']['severity'] = REQUIREMENT_ERROR;
$requirements['varnish']['description'] = t('The Varnish control terminal is not responding at %server on port %port.', array(
'%server' => variable_get('varnish_control_terminal_server', '127.0.0.1'),
'%port' => variable_get('varnish_control_terminal_port', '6082'),
));
}
else {
$requirements['varnish']['value'] = t('Varnish running. Observe more detailed statistics !link.', array(
'!link' => l(t('here'), 'admin/reports/varnish'),
));
}
return $requirements;
}
}
/**
* Implementation of hook_nodeapi()
*
* Used to pick up cache_clearing events
*/
function varnish_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
if ($op == 'insert' || $op == 'update') {
// We've probably just run through node_save, and normally this is where
// Drupal calls a cache_clear_all().
switch (variable_get('varnish_cache_clear', VARNISH_DEFAULT_CLEAR)) {
case VARNISH_DEFAULT_CLEAR:
varnish_purge_all_pages();
break;
}
}
}
/**
* Implementation of hook_comment()
*
* Used to pick up cache_clearing events
*/
function varnish_comment($comment, $op) {
switch ($op) {
case 'insert':
case 'update':
case 'publish':
case 'unpublish':
case 'delete':
if (variable_get('varnish_cache_clear', VARNISH_DEFAULT_CLEAR) == VARNISH_DEFAULT_CLEAR) {
varnish_purge_all_pages();
}
break;
}
}
/**
* Implementation of hook_form_alter()
*
* Add our submit callback to the "clear caches" button.
*/
function varnish_form_alter($form_id, &$form) {
if ($form_id == 'system_performance_settings') {
$form['#submit']['varnish_purge_all_pages'] = array();
}
}
/**
* Implementation of hook_flush_caches()
*
* Flush caches on events like cron.
*
* This borrows logic from cache_clear_all() to respect cache_lifetime.
*/
function varnish_flush_cache_manually() {
$destination = referer_uri();
varnish_purge_all_pages();
drupal_set_message('Varnish cache cleared.');
drupal_goto($destination);
}
/**
* Implementation of hook_cron
*/
function varnish_cron() {
if (variable_get('varnish_flush_cron', 0)) {
if (variable_get('cache_lifetime', 0)) {
$cache_flush = variable_get('cache_flush_varnish', 0);
if ($cache_flush == 0) {
// This is the first request to clear the cache, start a timer.
variable_set('cache_flush_varnish', time());
}
else {
if (time() > $cache_flush + variable_get('cache_lifetime', 0)) {
variable_set('cache_flush_varnish', 0);
varnish_purge_all_pages();
}
}
}
else {
varnish_purge_all_pages();
}
}
}
/**
* Helper function to quickly flush all caches for the current site.
*/
function varnish_purge_all_pages() {
$path = base_path();
$host = _varnish_get_host();
_varnish_terminal_run("purge req.http.host ~ {$host} && req.url ~ ^{$path}");
}
/**
* Help[er function to parse the host from the global $base_url
*/
function _varnish_get_host() {
global $base_url;
$parts = parse_url($base_url);
return $parts['host'];
}
/**
* Extensible logic function to get other urls to clear.
*
* TODO: Merge this with boost logic.
*/
function varnish_get_active_urls($node) {
$urls = array();
$urls[] = 'node/' . $node->nid;
if ($node->type == 'blog') {
$urls[] = 'blog';
$urls[] = 'blog/' . $node->uid;
}
// lots more here...
foreach ($urls as $url) {
$alias = drupal_get_path_alias($url);
// TODO: languages?
if ($alias != $url) {
$urls[] = $alias;
}
}
return $urls;
}
/**
* Helper function that sends commands to Varnish
*
* Utilizes sockets to talk to varnish terminal.
*/
function _varnish_terminal_run($command, $returnlength = 1000) {
if (!extension_loaded('sockets')) {
drupal_set_message(t('Sockets extension not enabled. Varnish terminal communication aborted.'), 'error');
return FALSE;
}
$server = variable_get('varnish_control_terminal_server', '127.0.0.1');
$port = variable_get('varnish_control_terminal_port', '6082');
$client = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
if (!socket_connect($client, $server, $port)) {
watchdog('varnish', t('Unable to connect to server socket !server:!port', array(
'!server' => $server,
'!port' => $port,
)));
return FALSE;
}
socket_write($client, "{$command}\n");
$code = socket_read($client, 3, PHP_BINARY_READ);
if ($code != 200) {
$error = socket_read($client, 3000, PHP_BINARY_READ);
watchdog('varnish', t('Recieved status code !code running !command. Full response text: !error', array(
'!code' => $code,
'!command' => $command,
'!error' => $error,
)));
$ret = FALSE;
}
else {
// successful connection
$ret = socket_read($client, $returnlength, PHP_BINARY_READ);
}
socket_close($client);
return $ret;
}
/**
* Menu callback for varnish admin settings.
*/
function varnish_admin_settings_form() {
$form = array();
// Decide whether or not to flush caches on cron runs.
$form['varnish_flush_cron'] = array(
'#type' => 'radios',
'#title' => t('Flush page cache on cron?'),
'#options' => array(
0 => t('Disabled'),
1 => t('Enabled (with respect for cache_lifetime)'),
),
'#default_value' => variable_get('varnish_flush_cron', 0),
'#description' => t('Internally Drupal will attempt to flush its page cache every time cron.php runs. This can mean too-frequent cache flushes if you have cron running frequently. NOTE: this cache flush is global!'),
);
if (!extension_loaded('sockets')) {
drupal_set_message(t('Sockets extension not enabled. Varnish terminal communication configuration skipped.'), 'error');
return system_settings_form($form);
}
// Begin socket-dependent configuration.
$form['varnish_control_terminal_server'] = array(
'#type' => 'textfield',
'#title' => t('Varnish Control Terminal Server'),
'#default_value' => variable_get('varnish_control_terminal_server', '127.0.0.1'),
'#required' => TRUE,
'#description' => t('Set this to the server IP or hostname that varnish runs on. This must be configured for Drupal to talk to Varnish.'),
);
$form['varnish_control_terminal_port'] = array(
'#type' => 'textfield',
'#title' => t('Varnish Control Terminal Server'),
'#default_value' => variable_get('varnish_control_terminal_port', '6082'),
'#required' => TRUE,
'#description' => t('Set this to the port on which your varnish control terminal runs. This must be configured for Drupal to talk to Varnish.'),
);
$form['varnish_control_key'] = array(
'#type' => 'textfield',
'#title' => t('Varnish Control Key'),
'#default_value' => variable_get('varnish_control_key', ''),
'#description' => t('Optional: if you have established a secret key for control terminal access, please put it here.'),
);
$form['varnish_cache_clear'] = array(
'#type' => 'radios',
'#title' => t('Varnish Cache Clearing'),
'#options' => array(
VARNISH_DEFAULT_CLEAR => t('Drupal Default'),
VARNISH_NO_CLEAR => t('None'),
),
'#default_value' => variable_get('varnish_cache_clear', VARNISH_DEFAULT_CLEAR),
'#description' => t('What kind of cache clearing Varnish should utilize. "Drupal Default" will clear the entire Varnish page cache on node updates, comment updates/additions, and/or other cache flush events. "None" will allow stale pages to persist when nodes and comments are added, and all other Drupal-based cache clearing events (except for cron run varnish cache clearing if you have that enabled).'),
);
$form['varnish_stats'] = array(
'#type' => 'fieldset',
'#collapsible' => FALSE,
'#title' => t('Stats'),
);
if ($_GET['stats'] == 1) {
$status = _varnish_terminal_run('stats', 50000);
$form['varnish_stats']['#collapsed'] = FALSE;
}
else {
$status = l(t('Fetch stats'), 'admin/settings/varnish', array(), 'stats=1');
$form['varnish_stats']['#collapsed'] = TRUE;
}
$form['varnish_stats']['data'] = array(
'#type' => 'markup',
'#prefix' => '<pre>',
'#suffic' => '</pre>',
'#value' => $status,
);
return system_settings_form($form);
}
/**
* Menu callback for varnish admin settings.
*/
function varnish_admin_reports_page() {
// connect to varnish and do a full status report
$status = _varnish_terminal_run('stats', 50000);
return "<pre>{$status}</pre>";
}
Functions
Name | Description |
---|---|
varnish_admin_reports_page | Menu callback for varnish admin settings. |
varnish_admin_settings_form | Menu callback for varnish admin settings. |
varnish_comment | Implementation of hook_comment() |
varnish_cron | Implementation of hook_cron |
varnish_flush_cache_manually | Implementation of hook_flush_caches() |
varnish_form_alter | Implementation of hook_form_alter() |
varnish_get_active_urls | Extensible logic function to get other urls to clear. |
varnish_menu | Implementation of hook_menu() |
varnish_nodeapi | Implementation of hook_nodeapi() |
varnish_perm | Implemetation of hook_perm() |
varnish_purge_all_pages | Helper function to quickly flush all caches for the current site. |
varnish_requirements | Implementation of hook_requirements() |
_varnish_get_host | Help[er function to parse the host from the global $base_url |
_varnish_terminal_run | Helper function that sends commands to Varnish |