Commit e71d2f63 authored by Jon Pugh's avatar Jon Pugh

Merge branch '4.x-services' of git.drupal.org:project/provision into 4.x-services

parents d2f9a63a 44c9546f
<?php
/**
* @file
* Provision configuration generation classes.
*/
namespace Aegir\Provision;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
/**
* Class Configuration
*
* @package Aegir\Provision
*/
class Configuration {
/**
* Provision 4.x
*/
/**
* A \Aegir\Provision\Context object this configuration relates to.
*
* @var \Aegir\Provision\Context
*/
public $context = NULL;
/**
* A \Aegir\Provision\Service object this configuration relates to.
*
* @var \Aegir\Provision\Service
*/
public $service = NULL;
/**
* @var Filesystem
*/
public $fs;
/**
* LEGACY
*/
/**
* Template file, a PHP file which will have access to $this and variables
* as defined in $data.
*/
public $template = NULL;
/**
* Associate array of variables to make available to the template.
*/
public $data = array();
/**
* If set, replaces file name in log messages.
*/
public $description = NULL;
/**
* Octal Unix mode for permissons of the created file.
*/
protected $mode = NULL;
/**
* Unix group name for the created file.
*/
protected $group = NULL;
/**
* An optional data store class to instantiate for this config.
*/
protected $data_store_class = NULL;
/**
* The data store.
*/
public $store = NULL;
/**
* Forward $this->... to $this->context->...
* object.
*/
function __get($name) {
if (isset($this->context)) {
return $this->context->$name;
}
}
/**
* Constructor, overriding not recommended.
*
* @param $context
* An alias name for d(), the Provision_Context that this configuration
* is relevant to.
* @param $data
* An associative array to potentially manipulate in process() and make
* available as variables to the template.
*/
function __construct($context, $service, $data = array()) {
if (is_null($this->template)) {
throw new Exception(dt("No template specified for: %class", array('%class' => get_class($this))));
}
// Accept both a reference and an alias name for the context.
$this->context = $context;
$this->service = $service;
$this->fs = new Filesystem();
if (sizeof($data)) {
$this->data = $data;
}
if (!is_null($this->data_store_class) && class_exists($this->data_store_class)) {
$class = $this->data_store_class;
$this->store = new $class($context, $data);
}
}
/**
* Process and add to $data before writing the configuration.
*
* This is a stub to be implemented by subclasses.
*/
function process() {
if (is_object($this->store)) {
$this->data['records'] = array_filter(array_merge($this->store->loaded_records, $this->store->records));
}
return TRUE;
}
/**
* The filename where the configuration is written.
*
* This is a stub to be implemented by subclasses.
*/
function filename() {
return FALSE;
}
/**
* Load template from filename().
*
* @see hook_provision_config_load_templates()
* @see hook_provision_config_load_templates_alter()
*/
private function load_template() {
return file_get_contents(__DIR__ . '/Service/' . ucfirst($this->service->getName()) . '/' . ucfirst($this->service->getType()) . '/Configuration/' . $this->template);
// Allow other Drush commands to change the template used first.
// $templates = drush_command_invoke_all('provision_config_load_templates', $this);
// // Ensure that templates is at least an array.
// if (!is_array($templates)) {
// $templates = array();
// }
// // Allow other Drush commands to alter the templates from other commands.
//// drush_command_invoke_all_ref('provision_config_load_templates_alter', $templates, $this);
// if (!empty($templates) && is_array($templates)) {
// foreach ($templates as $file) {
// if (is_readable($file)) {
// drush_log(dt('Template loaded from hook(s): :file', array(
// ':file' => $file,
// )));
// return file_get_contents($file);
// }
// }
// }
//
// // If we've got this far, then try to find a template from this class or
// // one of its parents.
// if (isset($this->template)) {
// $class_name = get_class($this);
// while ($class_name) {
// // Iterate through the config file's parent classes until we
// // find the template file to use.
// $base_dir = provision_class_directory($class_name);
// $file = $base_dir . '/' . $this->template;
//
// if (is_readable($file)) {
// drush_log(dt('Template loaded from Provision Config class :class_name: :file', array(
// ':class_name' => $class_name,
// ':file' => $file,
// )));
// return file_get_contents($file);
// }
//
// $class_name = get_parent_class($class_name);
// }
// }
//
// // We've failed to find a template if we've reached this far.
// drush_log(dt('No template found for Provision Config class: ', array(':class' => get_class($this))), 'warning');
// return FALSE;
}
/**
* Render template, making variables available from $variables associative
* array.
*/
private function render_template($template, $variables) {
// Allow modules to alter the variables before writing to the template.
// @see hook_provision_config_variables_alter()
// drush_command_invoke_all_ref('provision_config_variables_alter', $variables, $template, $this);
// drush_errors_off();
extract($variables, EXTR_SKIP); // Extract the variables to a local namespace
ob_start(); // Start output buffering
eval('?>' . $template); // Generate content
$contents = ob_get_contents(); // Get the contents of the buffer
ob_end_clean(); // End buffering and discard
// drush_errors_on();
return $contents; // Return the contents
}
/**
* Write out this configuration.
*
* 1. Make sure parent directory exists and is writable.
* 2. Load template with load_template().
* 3. Process $data with process().
* 4. Make existing file writable if necessary and possible.
* 5. Render template with $this and $data and write out to filename().
* 6. If $mode and/or $group are set, apply them for the new file.
*/
function write() {
// Make directory structure if it does not exist.
$filename = $this->filename();
if ($filename && !$this->fs->exists([dirname($filename)])) {
try {
$this->fs->mkdir([dirname($filename)]);
}
catch (IOException $e) {
throw new \Exception("Could not create directory " . dirname($filename) . ": " . $e->getMessage());
}
}
$status = FALSE;
if ($filename && is_writeable(dirname($filename))) {
// manipulate data before passing to template.
$this->process();
if ($template = $this->load_template()) {
// Make sure we can write to the file
if (!is_null($this->mode) && !($this->mode & 0200) && $this->fs->exists(($filename))) {
try {
$this->fs->chmod([$filename], $this->mode);
}
catch (IOException $e) {
throw new \Exception('Could not change permissions of ' . $filename . ' to ' . $this->mode);
}
}
try {
$this->fs->dumpFile($filename, $this->render_template($template, $this->data));
}
catch (IOException $e) {
throw new \Exception('Could not write file to ' . $filename);
}
// Change the permissions of the file if needed
if (!is_null($this->mode)) {
try {
$this->fs->chmod([$filename], $this->mode);
}
catch (IOException $e) {
throw new \Exception('Could not change permissions of ' . $filename . ' to ' . $this->mode);
}
}
if (!is_null($this->group)) {
try {
$this->fs->chgrp([$filename], $this->group);
}
catch (IOException $e) {
throw new \Exception('Could not change group ownership of ' . $filename . ' to ' . $this->group);
}
}
}
}
return $status;
}
// allow overriding w.r.t locking
function file_put_contents($filename, $text) {
provision_file()->file_put_contents($filename, $text)
->succeed('Generated config in file_put_contents()' . (empty($this->description) ? $filename : $this->description), 'success');
}
/**
* Remove configuration file as specified by filename().
*/
function unlink() {
return provision_file()->unlink($this->filename())->status();
}
}
......@@ -145,7 +145,12 @@ class Context
* @return array
*/
public function getProperty($name) {
return $this->properties[$name];
if (isset($this->properties[$name])) {
return $this->properties[$name];
}
else {
return NULL;
}
}
/**
......
......@@ -40,7 +40,22 @@ class ServerContext extends Context implements ConfigurationInterface
{
parent::__construct($name, $console_config, $options);
if (isset($this->config['services'])) {
$this->services = $this->config['services'];
$this->prepareServices();
}
else {
$this->services = [];
}
}
/**
* Load Service classes from config into Context..
*/
protected function prepareServices() {
foreach ($this->config['services'] as $service_name => $service) {
$service_name = ucfirst($service_name);
$service_type = ucfirst($service['type']);
$service_class = "\\Aegir\\Provision\\Service\\{$service_name}\\{$service_name}{$service_type}Service";
$this->services[strtolower($service_name)] = new $service_class($service, $this);
}
}
......@@ -191,7 +206,11 @@ class ServerContext extends Context implements ConfigurationInterface
public function verify() {
// parent::verify();
// Run verify method on all services.
foreach ($this->getServices() as $service) {
$service->verify();
}
return "Server Context Verified: " . $this->name;
}
......@@ -202,11 +221,11 @@ class ServerContext extends Context implements ConfigurationInterface
if (!empty($this->getServices())) {
$rows = [];
foreach ($this->getServices() as $name => $service) {
$rows[] = [$name, $service['type']];
$rows[] = [$name, $service->type];
// Show all properties.
if (!empty($service['properties'] )) {
foreach ($service['properties'] as $name => $value) {
if (!empty($service->properties )) {
foreach ($service->properties as $name => $value) {
$rows[] = [' ' . $name, $value];
}
}
......
......@@ -11,7 +11,59 @@ namespace Aegir\Provision;
//require_once DRUSH_BASE_PATH . '/commands/core/rsync.core.inc';
class Service {
public $type;
public $properties;
function __construct($service_config, $context) {
$this->context = $context;
$this->type = $service_config['type'];
$this->properties = $service_config['properties'];
}
/**
* React to the `provision verify` command.
*/
function verify() {
$this->writeConfigurations();
}
/**
* Write this service's configurations.
*/
protected function writeConfigurations() {
foreach ($this->getConfigurations()[$this->context->type] as $configuration_class) {
$config = new $configuration_class($this->context, $this);
$config->write();
}
}
/**
* Stub for this services configurations.
*/
protected function getConfigurations() {
return [];
}
/**
* Return the SERVICE_TYPE
* @return mixed
*/
public function getType() {
return $this::SERVICE_TYPE;
}
/**
* Return the SERVICE_TYPE
* @return mixed
*/
public function getName() {
return $this::SERVICE;
}
/**
* LEGACY
*/
/**
* The server this service is associated to
*/
......@@ -62,9 +114,9 @@ class Service {
* This is used so that we can create methods for drush commands, and
* can fail safely.
*/
function __call($name, $args = array()) {
return provision::method_invoke($this, $name, $args);
}
// function __call($name, $args = array()) {
// return provision::method_invoke($this, $name, $args);
// }
function init() {
......@@ -316,10 +368,6 @@ class Service {
return FALSE;
}
function __construct($server) {
$this->server = is_object($server) ? $server : d($server);
}
/**
* Set the currently active context of the service.
*
......@@ -344,10 +392,10 @@ class Service {
function fetch($path = NULL) {
return $this->server->fetch($path);
}
function verify() {
return TRUE;
}
//
// function verify() {
// return TRUE;
// }
/**
* Return service-specific configuration options for help.
......
<?php
/**
* @file Server.php
*
* Apache Configuration for Server Context.
* @see \Provision_Config_Apache_Server
* @see \Provision_Config_Http_Server
* @see \Provision_Config_Http_Server
*/
namespace Aegir\Provision\Service\Http\Apache\Configuration;
use Aegir\Provision\Configuration;
class PlatformConfiguration extends Configuration {
const SERVICE_TYPE = 'apache';
public $template = 'server.tpl.php';
public $description = 'web server configuration file';
function filename() {
if (isset($this->data['application_name'])) {
$file = $this->data['application_name'] . '.conf';
return $this->data['server']->config_path . '/' . $file;
}
else {
return FALSE;
}
}
}
\ No newline at end of file
<?php
/**
* @file Server.php
*
* Apache Configuration for Server Context.
*
* This class represents the file at /var/aegir/config/apache.conf.
*
*
* @see \Provision_Config_Apache_Server
* @see \Provision_Config_Http_Server
* @see \Provision_Config_Http_Server
*/
namespace Aegir\Provision\Service\Http\Apache\Configuration;
use Aegir\Provision\Configuration;
class ServerConfiguration extends Configuration {
const SERVICE_TYPE = 'apache';
public $template = 'server.tpl.php';
public $description = 'web server configuration file';
function filename() {
if ($this->service->getType()) {
$file = $this->service->getType() . '.conf';
return $this->context->console_config['config_path'] . '/' . $this->context->name . '/' . $file;
}
else {
return FALSE;
}
}
function process()
{
$app_dir = $this->context->console_config['config_path'] . '/' . $this->service->getType();
$this->data['http_port'] = $this->service->properties['http_port'];
$this->data['include_statement'] = '# INCLUDE STATEMENT';
$this->data['http_pred_path'] = "{$app_dir}/pre.d";
$this->data['http_postd_path'] = "{$app_dir}/post.d";
$this->data['http_platformd_path'] = "{$app_dir}/platform.d";
$this->data['http_vhostd_path'] = "{$app_dir}/vhost.d";
$this->data['extra_config'] = "";
return parent::process();
}
}
\ No newline at end of file
<?php
/**
* @file Site.php
*
* Apache Configuration for Server Context.
* @see \Provision_Config_Apache_Site
* @see \Provision_Config_Http_Site
*/
namespace Aegir\Provision\Service\Http\Apache\Configuration;
use Aegir\Provision\Configuration;
class SiteConfiguration extends Configuration {
const SERVICE_TYPE = 'apache';
public $template = 'vhost.tpl.php';
// The template file to use when the site has been disabled.
public $disabled_template = 'vhost_disabled.tpl.php';
public $description = 'virtual host configuration file';
function filename() {
if (drush_get_option('provision_apache_conf_suffix', FALSE)) {
return $this->data['http_vhostd_path'] . '/' . $this->uri . '.conf';
}
else {
return $this->data['http_vhostd_path'] . '/' . $this->uri;
}
}
function process() {
parent::process();
if ($this->aliases && !is_array($this->aliases)) {
$this->aliases = explode(",", $this->aliases);
}
$this->aliases = array_filter($this->aliases, 'trim');
if ($this->drush_aliases && !is_array($this->drush_aliases)) {
$this->drush_aliases = explode(",", $this->drush_aliases);
}
$this->drush_aliases = array_filter($this->drush_aliases, 'trim');
if (!$this->site_enabled) {
$this->template = $this->disabled_template;
}
}
}
\ No newline at end of file
# Aegir web server configuration file
NameVirtualHost *:<?php print $http_port; ?>
<VirtualHost *:<?php print $http_port; ?>>
ServerName default
Redirect 404 /
</VirtualHost>
<IfModule !env_module>
LoadModule env_module modules/mod_env.so
</IfModule>
<IfModule !rewrite_module>
LoadModule rewrite_module modules/mod_rewrite.so
</IfModule>
<?php
//if (drush_get_option('provision_apache_conf_suffix', FALSE)) {
// $include_statement = 'IncludeOptional ';
// $include_suffix = '/*.conf';
//}
//else {
$include_statement = 'Include ';
$include_suffix = '';
//}
?>
# other configuration, not touched by aegir
# this allows you to override aegir configuration, as it is included before
<?php print $include_statement . $http_pred_path . $include_suffix ?>
# virtual hosts
<?php print $include_statement . $http_vhostd_path . $include_suffix ?>
# platforms
<?php print $include_statement . $http_platformd_path . $include_suffix ?>
# other configuration, not touched by aegir
# this allows to have default (for example during migrations) that are eventually overriden by aegir
<?php print $include_statement . $http_postd_path . $include_suffix ?>
<?php print $extra_config; ?>
......@@ -19,4 +19,27 @@ class HttpApacheService extends HttpService
{
const SERVICE_TYPE = 'apache';
const SERVICE_TYPE_NAME = 'Apache';
/**
* Returns array of Configuration classes for this service.
*
* @see Provision_Service_http_apache::init_server();
*
* @return array
*/
public function getConfigurations()
{
$configs['server'][] = '\Aegir\Provision\Service\Http\Apache\Configuration\ServerConfiguration';
$configs['platform'][] = '\Aegir\Provision\Service\Http\Apache\Configuration\PlatformConfiguration';
$configs['site'][] = '\Aegir\Provision\Service\Http\Apache\Configuration\SiteConfiguration';
return $configs;
}
/**
* Respond to the `provision verify` command.
*/
public function verify() {
// print "VERIFY APACHE SERVER!";
parent::verify();
}
}
......@@ -26,6 +26,9 @@ class HttpService extends Service {
static function option_documentation() {
return array(
'http_port' => 'The port which the web service is running on.',
'http_platformd_path' => 'The path to store platforms.',
'http_postd_path' => 'The path to store post configuration.',
'web_group' => 'server with http: OS group for permissions; working default will be attempted',
'web_disable_url' => 'server with http: URL disabled sites are redirected to; default {master_url}/hosting/disabled',
'web_maintenance_url' => 'server with http: URL maintenance sites are redirected to; default {master_url}/hosting/maintenance',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment