From 4ec880f36ac90b5919e1e12b06fc81eb7508a239 Mon Sep 17 00:00:00 2001 From: Webslice <webslice@bixels.nl> Date: Mon, 14 Jan 2019 20:16:44 +0100 Subject: [PATCH] Add incron_plugin, fixes #5218 --- .../plugins-available/incron_plugin.inc.php | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 server/plugins-available/incron_plugin.inc.php diff --git a/server/plugins-available/incron_plugin.inc.php b/server/plugins-available/incron_plugin.inc.php new file mode 100644 index 0000000000..eddcee169a --- /dev/null +++ b/server/plugins-available/incron_plugin.inc.php @@ -0,0 +1,162 @@ +<?php + +/** + * If your websites use PHP-FPM and you have incron installed, you can use this plugin to automatically add incron + * configuration which will take care of reloading the php-fpm pool when the file /private/php-fpm.reload is touched. + * Projects which use deployment tools can use this to reload php-fpm to clear the opcache at deploy time, without + * requiring superuser privileges. + */ +class incron_plugin { + + var $plugin_name = 'incron_plugin'; + var $class_name = 'incron_plugin'; + + function onInstall() { + global $conf; + + if ($conf['services']['web'] !== true) { + return false; + } + + if ($this->isIncronAvailable() === false) { + return false; + } + + return true; + } + + function onLoad() { + global $app; + + $app->plugins->registerEvent('web_domain_insert', $this->plugin_name, 'incronInsert'); + $app->plugins->registerEvent('web_domain_update', $this->plugin_name, 'incronUpdate'); + $app->plugins->registerEvent('web_domain_delete', $this->plugin_name, 'incronDelete'); + } + + function incronInsert($eventName, $data) { + $this->setup($data['new']); + } + + function incronUpdate($eventName, $data) { + global $app; + + if ($data['new']['document_root'] === $data['old']['document_root']) { + $app->log('Document root unchanged. Not updating incron configuration.', LOGLEVEL_DEBUG); + + return; + } + + $this->teardown($data['old']); + $this->setup($data['new']); + } + + function incronDelete($eventName, $data) { + $this->teardown($data['old']); + } + + private function setup($data) + { + $triggerFile = $this->getTriggerFilePath($data['document_root']); + + $this->createTriggerFile($triggerFile, $data['system_user'], $data['system_group']); + $this->createIncronConfiguration( + $triggerFile, + $data['system_user'], + $data['fastcgi_php_version'] + ); + + $this->restartIncronService(); + } + + private function teardown($data) { + $this->deleteIncronConfiguration($data['system_user']); + $this->deleteTriggerFile($this->getTriggerFilePath($data['document_root'])); + + $file = sprintf('/etc/incron.d/%s.conf', $data['system_user']); + + @unlink($file); + + $this->restartIncronService(); + } + + private function isIncronAvailable() { + exec('which incrond', $output, $retval); + + return $retval === 0; + } + + private function createIncronConfiguration($triggerFile, $systemUser, $fastcgiPhpVersion) { + global $app; + + $phpService = $this->getPhpService($fastcgiPhpVersion); + $configFile = $this->getIncronConfigurationFilePath($systemUser); + + $content = sprintf( + '%s %s %s', + $triggerFile, + 'IN_CLOSE_WRITE', + $app->system->getinitcommand($phpService, 'reload') + ); + + file_put_contents($configFile, $content); + + $app->log(sprintf('Created incron configuration "%s"', $configFile), LOGLEVEL_DEBUG); + } + + private function createTriggerFile($triggerFile, $systemUser, $systemGroup) { + global $app; + + if (!file_exists($triggerFile)) { + exec(sprintf('touch %s', $triggerFile)); + } + + exec(sprintf('chown %s:%s %s', $systemUser, $systemGroup, $triggerFile)); + + $app->log(sprintf('Ensured incron trigger file "%s"', $triggerFile), LOGLEVEL_DEBUG); + } + + private function deleteIncronConfiguration($systemUser) { + global $app; + + $configFile = $this->getIncronConfigurationFilePath($systemUser); + unlink($configFile); + + $app->log(sprintf('Deleted incron configuration "%s"', $configFile), LOGLEVEL_DEBUG); + } + + private function deleteTriggerFile($triggerFile) { + global $app; + + unlink($triggerFile); + + $app->log(sprintf('Deleted incron trigger file "%s"', $triggerFile), LOGLEVEL_DEBUG); + } + + private function getTriggerFilePath($documentRoot) { + return sprintf('%s/private/php-fpm.reload', $documentRoot); + } + + private function getIncronConfigurationFilePath($systemUser) { + return sprintf('/etc/incron.d/%s.conf', $systemUser); + } + + private function getPhpService($fastcgiPhpVersion) { + $phpInfo = explode(':', $fastcgiPhpVersion); + if (empty($phpInfo)) { + return null; + } + + $phpService = $phpInfo[1]; + if (empty($phpService)) { + return null; + } + + return $phpService; + } + + private function restartIncronService() { + global $app; + + exec($app->system->getinitcommand('incrond', 'restart')); + } +} \ No newline at end of file -- GitLab