Skip to content
Commits on Source (48)
......@@ -54,7 +54,7 @@ if ($debug){
}
try {
$application = new Application();
$application = new Application($input, $output);
$application->run();
}
catch (\Exception $e) {
......
......@@ -6,7 +6,9 @@
"type": "library",
"license": "GPL-2.0+",
"require": {
"consolidation/annotated-command": "~2",
"drupal/console-core": "1.0.2",
"psr/log": "^1.0",
"psy/psysh": "^0.8.11",
"symfony/console": "^3.3",
"symfony/yaml": "^3.3"
......
......@@ -4,8 +4,108 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "835ca80eb26b4d7e438015632aaeaaa2",
"content-hash": "25f4161ac19dde865bcef9fa9d341b03",
"packages": [
{
"name": "consolidation/annotated-command",
"version": "2.8.1",
"source": {
"type": "git",
"url": "https://github.com/consolidation/annotated-command.git",
"reference": "7f94009d732922d61408536f9228aca8f22e9135"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/consolidation/annotated-command/zipball/7f94009d732922d61408536f9228aca8f22e9135",
"reference": "7f94009d732922d61408536f9228aca8f22e9135",
"shasum": ""
},
"require": {
"consolidation/output-formatters": "^3.1.12",
"php": ">=5.4.0",
"psr/log": "^1",
"symfony/console": "^2.8|~3",
"symfony/event-dispatcher": "^2.5|^3",
"symfony/finder": "^2.5|^3"
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "^2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Consolidation\\AnnotatedCommand\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Greg Anderson",
"email": "greg.1.anderson@greenknowe.org"
}
],
"description": "Initialize Symfony Console commands from annotated command class methods.",
"time": "2017-10-17T01:48:51+00:00"
},
{
"name": "consolidation/output-formatters",
"version": "3.1.12",
"source": {
"type": "git",
"url": "https://github.com/consolidation/output-formatters.git",
"reference": "88ef346a1cefb92aab8b57a3214a6d5fc63f5d2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/consolidation/output-formatters/zipball/88ef346a1cefb92aab8b57a3214a6d5fc63f5d2a",
"reference": "88ef346a1cefb92aab8b57a3214a6d5fc63f5d2a",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"symfony/console": "^2.8|~3",
"symfony/finder": "~2.5|~3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"satooshi/php-coveralls": "^1.0",
"squizlabs/php_codesniffer": "^2.7",
"victorjonsson/markdowndocs": "^1.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Consolidation\\OutputFormatters\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Greg Anderson",
"email": "greg.1.anderson@greenknowe.org"
}
],
"description": "Format text by applying transformations provided by plug-in formatters.",
"time": "2017-10-12T19:38:03+00:00"
},
{
"name": "dflydev/dot-access-configuration",
"version": "v1.0.2",
......
......@@ -8,11 +8,14 @@ use Aegir\Provision\Command\ShellCommand;
use Aegir\Provision\Command\StatusCommand;
use Aegir\Provision\Command\VerifyCommand;
use Aegir\Provision\Console\Config;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Application as BaseApplication;
......@@ -49,10 +52,26 @@ class Application extends BaseApplication
* @var string
*/
const DEFAULT_TIMEZONE = 'America/New_York';
public function __construct()
/**
* @var LoggerInterface
*/
public $logger;
/**
* Application constructor.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @throws \Exception
*/
public function __construct(InputInterface $input, OutputInterface $output)
{
$this->logger = new ConsoleLogger($output,
[LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL]
);
// If no timezone is set, set Default.
if (empty(ini_get('date.timezone'))) {
date_default_timezone_set($this::DEFAULT_TIMEZONE);
......@@ -105,7 +124,7 @@ class Application extends BaseApplication
$commands[] = new ListCommand();
$commands[] = new SaveCommand();
$commands[] = new ServicesCommand();
$commands[] = new ShellCommand();
// $commands[] = new ShellCommand();
$commands[] = new StatusCommand();
$commands[] = new VerifyCommand();
......@@ -137,16 +156,22 @@ class Application extends BaseApplication
*
* @return array
*/
function getAllContexts() {
function getAllContexts($name = '') {
$contexts = [];
$finder = new \Symfony\Component\Finder\Finder();
$finder->files()->name('*.yml')->in($this->config->get('config_path') . '/provision');
$finder->files()->name('*' . $name . '.yml')->in($this->config->get('config_path') . '/provision');
foreach ($finder as $file) {
list($context_type, $context_name) = explode('.', $file->getFilename());
$class = '\Aegir\Provision\Context\\' . ucfirst($context_type) . "Context";
$contexts[$context_name] = new $class($context_name, $this->config->all());
$contexts[$context_name] = new $class($context_name, $this->config->all(), $this);
}
if ($name) {
return $contexts[$name];
}
else {
return $contexts;
}
return $contexts;
}
/**
......@@ -158,9 +183,50 @@ class Application extends BaseApplication
* @throws \Exception
*/
function getContext($name) {
if (empty($this->getAllContexts()[$name])) {
if (empty($this->getAllContexts($name))) {
throw new \Exception('Context not found with name: ' . $name);
}
return $this->getAllContexts()[$name];
return $this->getAllContexts($name);
}
/**
* Load all server contexts.
*
* @param null $service
* @return mixed
* @throws \Exception
*/
public function getAllServers($service = NULL) {
$servers = [];
$contexts = $this->getAllContexts();
if (empty($contexts)) {
throw new \Exception('No contexts found. Use `provision save` to create one.');
}
foreach ($contexts as $name => &$context) {
if ($context->type == 'server') {
$servers[$name] = $context;
}
}
return $servers;
}
/**
* Get a simple array of all servers, optionally specifying the the service_type to filter by ("http", "db" etc.)
* @param string $service_type
* @return array
*/
public function getServerOptions($service_type = '') {
$servers = [];
foreach ($this->getAllServers() as $server) {
if ($service_type && !empty($server->config['services'][$service_type])) {
$servers[$server->name] = $server->name . ': ' . $server->config['services'][$service_type]['type'];
}
elseif ($service_type == '') {
$servers[$server->name] = $server->name . ': ' . $server->config['services'][$service_type]['type'];
}
}
return $servers;
}
}
......@@ -3,9 +3,11 @@
namespace Aegir\Provision;
use Drupal\Console\Core\Style\DrupalStyle;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Drupal\Console\Core\Command\Shared\CommandTrait;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;
/**
......
......@@ -68,7 +68,7 @@ class SaveCommand extends Command
);
// Load all Aegir\Provision\Context and inject their options.
// @TODO: Figure out a way to do discovery to include all classes that inherit Aegir\Provision\Context
// @TODO: Use CommandFileDiscovery to include all classes that inherit Aegir\Provision\Context
$contexts[] = SiteContext::option_documentation();
$contexts[] = PlatformContext::option_documentation();
$contexts[] = ServerContext::option_documentation();
......@@ -113,7 +113,7 @@ class SaveCommand extends Command
}
$properties = $this->askForContextProperties();
$class = Context::getClassName($this->input->getOption('context_type'));
$this->context = new $class($input->getArgument('context_name'), $this->getApplication()->getConfig()->all(), $properties);
$this->context = new $class($input->getArgument('context_name'), $this->getApplication()->getConfig()->all(), $this->getApplication(), $properties);
}
// Delete context config.
......@@ -144,11 +144,6 @@ class SaveCommand extends Command
$this->io->error("Unable to save configuration to {$this->context->config_path}. ");
}
}
$output->writeln(
"Context Object: ".print_r($this->context,1)
);
// $command = 'drush provision-save '.$input->getArgument('context_name');
// $this->process($command);
}
......
......@@ -7,6 +7,8 @@ use Aegir\Provision\Context;
use Aegir\Provision\Context\PlatformContext;
use Aegir\Provision\Context\ServerContext;
use Aegir\Provision\Context\SiteContext;
use Consolidation\AnnotatedCommand\CommandFileDiscovery;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputDefinition;
......@@ -80,9 +82,9 @@ class ServicesCommand extends Command
$input,
$output
);
if (isset($this->context->type) && $this->context->type != 'server') {
throw new \Exception('Context must be a server.');
}
// if (isset($this->context->type) && $this->context->type != 'server') {
// throw new \Exception('Context must be a server.');
// }
$this->sub_command = $input->getArgument('sub_command');
}
......@@ -109,4 +111,90 @@ class ServicesCommand extends Command
$this->io->comment("List Services");
$this->context->showServices($this->io);
}
/**
* Add a new service to a server.
*/
protected function execute_add(InputInterface $input, OutputInterface $output)
{
// Ask which service.
$this->io->comment("Add Services");
$service = $this->io->choice('Which service?', $this->context->getServiceOptions());
// If server, ask which service type.
if ($this->context->type == 'server') {
if (empty($this->context->getServiceTypeOptions($service))) {
throw new \Exception("There was no class found for service $service. Create one named \\Aegir\\Provision\\Service\\{$service}Service");
}
$service_type = $this->io->choice('Which service type?', $this->context->getServiceTypeOptions($service));
// Then ask for all options.
$properties = $this->askForServiceProperties($service);
$this->io->info("Adding $service service $service_type...");
$services_key = 'services';
$service_info = [
'type' => $service_type,
];
}
// All other context types are associating with servers that provide the service.
else {
if (empty($this->getApplication()->getServerOptions($service))) {
throw new \Exception("No servers providing $service service were found. Create one with `provision save` or use `provision services` to add to an existing server.");
}
$server = $this->io->choice('Which server?', $this->getApplication()->getServerOptions($service));
// Then ask for all options.
$server_context = $this->getApplication()->getContext($server);
$properties = $this->askForServiceProperties($service);
$this->io->info("Using $service service from server $server...");
$services_key = 'service_subscriptions';
$service_info = [
'server' => $server,
];
}
try {
$this->context->config[$services_key][$service] = $service_info;
if (!empty($properties)) {
$this->context->config[$services_key][$service]['properties'] = $properties;
}
$this->context->save();
$this->io->success('Service saved to Context!');
}
catch (\Exception $e) {
throw new \Exception("Something went wrong when saving the context: " . $e->getMessage());
}
}
/**
* Loop through this context type's option_documentation() method and ask for each property.
*
* @return array
*/
private function askForServiceProperties($service) {
$class = $this->context->getAvailableServices($service);
$method = "{$this->context->type}_options";
$options = $class::{$method}();
$properties = [];
foreach ($options as $name => $description) {
// If option does not exist, ask for it.
if (!empty($this->input->hasOption($name))) {
$properties[$name] = $this->input->getOption($name);
$this->io->comment("Using option {$name}={$properties[$name]}");
}
else {
$properties[$name] = $this->io->ask("$name ($description)");
}
}
return $properties;
}
}
<?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 (!empty($this->context->getProperties())) {
$this->data = $this->context->getProperties();
}
// @TODO: Remove legacy code.
// 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();
}
}
......@@ -6,6 +6,9 @@
namespace Aegir\Provision;
use Consolidation\AnnotatedCommand\CommandFileDiscovery;
use Drupal\Console\Core\Style\DrupalStyle;
use Psr\Log\LoggerInterface;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Filesystem\Exception\IOException;
......@@ -49,6 +52,22 @@ class Context
*/
protected $properties = [];
/**
* @var array
* A list of services associated with this context.
*/
protected $services = [];
/**
* @var \Aegir\Provision\Application;
*/
public $application;
/**
* @var LoggerInterface
*/
public $logger;
/**
* Context constructor.
*
......@@ -56,10 +75,12 @@ class Context
* @param $console_config
* @param array $options
*/
function __construct($name, $console_config, $options = [])
function __construct($name, $console_config, Application $application, $options = [])
{
$this->name = $name;
$this->application = $application;
$this->loadContextConfig($console_config, $options);
$this->prepareServices();
}
/**
......@@ -99,13 +120,142 @@ class Context
}
}
/**
* Load Service classes from config into Context..
*/
protected function prepareServices() {
if (isset($this->config['services'])) {
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);
}
}
elseif (isset($this->config['service_subscriptions'])) {
foreach ($this->config['service_subscriptions'] as $service_name => $service) {
$this->servers[$service_name] = $server = $this->application->getContext($service['server']);
$this->services[$service_name] = new ServiceSubscription($this, $server, $service_name);
}
}
else {
$this->services = [];
}
}
/**
* Loads all available \Aegir\Provision\Service classes
*
* @return array
*/
public function getAvailableServices($service = '') {
// Load all service classes
$classes = [];
$discovery = new CommandFileDiscovery();
$discovery->setSearchPattern('*Service.php');
$servicesFiles = $discovery->discover(__DIR__ .'/Service', '\Aegir\Provision\Service');
foreach ($servicesFiles as $serviceClass) {
// If this is a server, show all services. If it is not, but service allows this type of context, load it.
if ($this->type == 'server' || in_array($this->type, $serviceClass::allowedContexts())) {
$classes[$serviceClass::SERVICE] = $serviceClass;
}
}
if ($service && isset($classes[$service])) {
return $classes[$service];
}
elseif ($service && !isset($classes[$service])) {
throw new \Exception("No service with name $service was found.");
}
else {
return $classes;
}
}
/**
* Lists all available services as a simple service => name array.
* @return array
*/
public function getServiceOptions() {
$options = [];
$services = $this->getAvailableServices();
foreach ($services as $service => $class) {
$options[$service] = $class::SERVICE_NAME;
}
return $options;
}
/**
* @return array
*/
protected function getAvailableServiceTypes($service, $service_type = NULL) {
// Load all service classes
$classes = [];
$discovery = new CommandFileDiscovery();
$discovery->setSearchPattern(ucfirst($service) . '*Service.php');
$serviceTypesFiles = $discovery->discover(__DIR__ .'/Service/' . ucfirst($service), '\Aegir\Provision\Service\\' . ucfirst($service));
foreach ($serviceTypesFiles as $serviceTypeClass) {
$classes[$serviceTypeClass::SERVICE_TYPE] = $serviceTypeClass;
}
if ($service_type && isset($classes[$service_type])) {
return $classes[$service_type];
}
elseif ($service_type && !isset($classes[$service_type])) {
throw new \Exception("No service type with name $service_type was found.");
}
else {
return $classes;
}
}
/**
* Lists all available services as a simple service => name array.
* @return array
*/
public function getServiceTypeOptions($service) {
$options = [];
$service_types = $this->getAvailableServiceTypes($service);
foreach ($service_types as $service_type => $class) {
$options[$service_type] = $class::SERVICE_TYPE_NAME;
}
return $options;
}
/**
* Return all services for this context.
*
* @return array
*/
public function getServices() {
return $this->services;
}
/**
* Return all services for this context.
*
* @return array
*/
public function getService($type) {
if (isset($this->services[$type])) {
return $this->services[$type];
}
else {
throw new \Exception("Service '$type' does not exist.");
}
}
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$tree_builder = new TreeBuilder();
$root_node = $tree_builder->root('server');
$root_node = $tree_builder->root($this->type);
$root_node
->children()
->scalarNode('name')
......@@ -113,6 +263,28 @@ class Context
->end()
->end();
// Load Services
if ($this->type == 'server') {
$services_key = 'services';
$services_property = 'type';
}
else {
$services_key = 'service_subscriptions';
$services_property = 'server';
}
$root_node
->children()
->arrayNode($services_key)
->prototype('array')
->children()
->scalarNode($services_property)
->isRequired(true)
->end()
->append($this->addServiceProperties($services_key))
->end()
->end();
// @TODO: Figure out how we can let other classes add to Context properties.
foreach ($this->option_documentation() as $name => $description) {
$root_node
......@@ -130,6 +302,77 @@ class Context
return $tree_builder;
}
/**
* Append Service class options_documentation to config tree.
*/
public function addServiceProperties($property_name = 'services')
{
$builder = new TreeBuilder();
$node = $builder->root('properties');
// Load config tree from Service type classes
if (!empty($this->getProperty($property_name)) && !empty($this->getProperty($property_name))) {
foreach ($this->getProperty($property_name) as $service => $info) {
// If type is empty, it's because it's in the ServerContext
if (empty($info['type'])) {
$server = $this->application->getContext($info['server']);
$service_type = ucfirst($server->getService($service)->type);
}
else {
$service_type = ucfirst($info['type']);
}
$service = ucfirst($service);
$class = "\Aegir\Provision\Service\\{$service}\\{$service}{$service_type}Service";
$method = "{$this->type}_options";
foreach ($class::{$method}() as $name => $description) {
$node
->children()
->scalarNode($name)->end()
->end()
->end();
}
}
}
return $node;
}
/**
* Output a list of all services for this context.
*/
public function showServices(DrupalStyle $io) {
if (!empty($this->getServices())) {
$is_server = $this->type == 'server';
$rows = [];
$headers = $is_server?
['Services']:
['Service', 'Server', 'Type'];
foreach ($this->getServices() as $name => $service) {
if ($is_server) {
$rows[] = [$name, $service->type];
}
else {
$rows[] = [
$name,
$service->server->name,
$service->server->getService($name)->type
];
}
// Show all properties.
if (!empty($service->properties )) {
foreach ($service->properties as $name => $value) {
$rows[] = [' ' . $name, $value];
}
}
}
$io->table($headers, $rows);
}
}
/**
* Return all properties for this context.
*
......@@ -145,7 +388,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;
}
}
/**
......@@ -189,7 +437,23 @@ class Context
return '\Aegir\Provision\Context\\' . ucfirst($type) . "Context";
}
// public function verify() {
// return "Provision Context";
// }
/**
* Verify this context.
*
* Running `provision verify CONTEXT` triggers this method.
*
* Collect all services for the context and run the verify() method on them
*/
public function verify() {
return "Provision Context";
// Run verify method on all services.
foreach ($this->getServices() as $service) {
$service->verify();
}
}
}
......@@ -2,7 +2,9 @@
namespace Aegir\Provision\Context;
use Aegir\Provision\Application;
use Aegir\Provision\Context;
use Aegir\Provision\Service\Http\Apache\Configuration\PlatformConfiguration;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
......@@ -18,7 +20,35 @@ class PlatformContext extends Context implements ConfigurationInterface
* @var string
*/
public $type = 'platform';
/**
* @var \Aegir\Provision\Context\ServerContext;
*/
public $web_server;
/**
* PlatformContext constructor.
*
* @param $name
* @param $console_config
* @param Application $application
* @param array $options
*/
function __construct($name, $console_config, Application $application, array $options = [])
{
parent::__construct($name, $console_config, $application, $options);
// Load "web_server" context.
if (isset($this->config['web_server'])) {
$this->web_server = $application->getContext($this->config['web_server']);
$this->web_server->logger = $application->logger;
}
else {
throw new \Exception('No web_server found.');
}
}
static function option_documentation()
{
$options = [
......@@ -31,4 +61,11 @@ class PlatformContext extends Context implements ConfigurationInterface
return $options;
}
// @TODO: Remove. This should be handled by Services now.
// public function verify() {
// parent::verify();
// $this->logger->info('Verifying Web Server...');
// $this->web_server->verify();
// }
}
......@@ -2,7 +2,9 @@
namespace Aegir\Provision\Context;
use Aegir\Provision\Application;
use Aegir\Provision\Context;
use Consolidation\AnnotatedCommand\CommandFileDiscovery;
use Drupal\Console\Core\Style\DrupalStyle;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
......@@ -22,27 +24,6 @@ class ServerContext extends Context implements ConfigurationInterface
*/
public $type = 'server';
/**
* @var array
* A list of services needed for this context.
*/
protected $services = [];
/**
* ServerContext constructor.
*
* @param $name
* @param $console_config
* @param array $options
*/
function __construct($name, $console_config, array $options = [])
{
parent::__construct($name, $console_config, $options);
if (isset($this->config['services'])) {
$this->services = $this->config['services'];
}
}
static function option_documentation()
{
$options = [
......@@ -55,48 +36,4 @@ class ServerContext extends Context implements ConfigurationInterface
return $options;
}
/**
* Return all services for this context.
*
* @return array
*/
public function getServices() {
return $this->services;
}
/**
* {@inheritdoc}
*/
public function configTreeBuilder(&$root_node)
{
$root_node
->children()
->arrayNode('services')
->prototype('array')
->children()
->scalarNode('name')
->isRequired(true)
->end()
->end()
->end();
}
public function verify() {
// parent::verify();
return "Server Context Verified: " . $this->name;
}
/**
* Output a list of all services for this service.
*/
public function showServices(DrupalStyle $io) {
if (!empty($this->getServices())) {
$rows = [];
foreach ($this->getServices() as $name => $service) {
$rows[] = [$name, $service['name']];
}
$io->table(['Services'], $rows);
}
}
}
......@@ -2,6 +2,7 @@
namespace Aegir\Provision\Context;
use Aegir\Provision\Application;
use Aegir\Provision\Context;
use Symfony\Component\Config\Definition\ConfigurationInterface;
......@@ -19,6 +20,33 @@ class SiteContext extends Context implements ConfigurationInterface
*/
public $type = 'site';
/**
* PlatformContext constructor.
*
* @param $name
* @param $console_config
* @param Application $application
* @param array $options
*/
function __construct($name, $console_config, Application $application, array $options = [])
{
parent::__construct($name, $console_config, $application, $options);
// Load "db_server" context.
// if (isset($this->config['service_subscriptions']['db'])) {
// $this->db_server = $application->getContext($this->config['service_subscriptions']['db']['server']);
// }
$this->logger = $application->logger;
if (isset($this->config['platform'])) {
$this->platform = $application->getContext(
$this->config['platform']
);
}
}
static function option_documentation()
{
return [
......@@ -35,6 +63,16 @@ class SiteContext extends Context implements ConfigurationInterface
];
}
public function verify() {
parent::verify();
// $this->db_server->service('db')->verify();
// $this->platform->verify();
// return "Site Context Verified: " . $this->name;
}
// /**
// * Write out this named context to an alias file.
// */
......
......@@ -11,7 +11,103 @@ 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();
}
/**
* List context types that are allowed to subscribe to this service.
* @return array
*/
static function allowedContexts() {
return [];
}
/**
* Write this service's configurations.
*/
protected function writeConfigurations() {
if (empty($this->getConfigurations()[$this->context->type])) {
return;
}
$this->context->application->logger->info('CONTEXT ' . $this->context->type);
foreach ($this->getConfigurations()[$this->context->type] as $configuration_class) {
$config = new $configuration_class($this->context, $this);
$config->write();
$this->context->application->logger->info('Wrote ' . $config->description . ' to ' . $config->filename());
}
}
/**
* 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;
}
/**
* Return a list of user configurable options that this service provides to Server Context objects.
*/
static function server_options() {
return [];
// return [
// 'http_port' => 'The port which the web service is running on.',
// 'web_group' => 'server with http: OS group for permissions; working default will be attempted',
// ];
}
/**
* Return a list of user configurable options that this service provides to Platform Context objects.
*/
static function platform_options() {
return [];
// return [
// 'platform_extra_config' => 'Extra lines of configuration to add to this platform.',
// ];
}
/**
* Return a list of user configurable options that this service provides to Site Context objects.
*/
static function site_options() {
return [];
// return [
// 'site_mail' => 'The email address to use for the ServerAdmin configuration.',
// ];
}
/**
* LEGACY
*/
/**
* The server this service is associated to
*/
......@@ -28,7 +124,19 @@ class Service {
*/
public $context;
protected $service = NULL;
/**
* @var string
* The machine name of the service. ie. http, db
*/
const SERVICE = 'service';
/**
* @var string
* A descriptive name of the service. ie. Web Server
*/
const SERVICE_NAME = 'Service Name';
protected $application_name = NULL;
protected $has_restart_cmd = FALSE;
......@@ -50,9 +158,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() {
......@@ -304,10 +412,6 @@ class Service {
return FALSE;
}
function __construct($server) {
$this->server = is_object($server) ? $server : d($server);
}
/**
* Set the currently active context of the service.
*
......@@ -332,20 +436,10 @@ class Service {
function fetch($path = NULL) {
return $this->server->fetch($path);
}
function verify() {
return TRUE;
}
/**
* Return service-specific configuration options for help.
*
* @return
* array('option' => 'description')
*/
static function option_documentation() {
return array();
}
//
// function verify() {
// return TRUE;
// }
/**
* Save symlink for this server from /var/aegir/config/APPLICATION_NAME.conf -> /var/aegir/config/SERVER/APPLICATION_NAME.conf
......
<?php
/**
* @file
* The Provision HttpNginxService class.
*
* @see \Provision_Service_http_Nginx
*/
namespace Aegir\Provision\Service\Db;
use Aegir\Provision\Service\DbService;
/**
* Class DbMysqlService
*
* @package Aegir\Provision\Service\Db
*/
class DbMysqlService extends DbService
{
const SERVICE_TYPE = 'mysql';
const SERVICE_TYPE_NAME = 'MySQL';
}
<?php
/**
* @file
* The base Provision DbService class.
*
* @see \Provision_Service_db
*/
namespace Aegir\Provision\Service;
//require_once DRUSH_BASE_PATH . '/commands/core/rsync.core.inc';
use Aegir\Provision\Service;
/**
* Class DbService
*
* @package Aegir\Provision\Service
*/
class DbService extends Service
{
const SERVICE = 'db';
const SERVICE_NAME = 'Database Server';
/**
* Implements Service::server_options()
*
* @return array
*/
static function server_options()
{
return [
'master_db' => 'server with db: Master database connection info, {type}://{user}:{password}@{host}',
'db_grant_all_hosts' => 'Grant access to site database users from any web host. If set to TRUE, any host will be allowed to connect to MySQL site databases on this server using the generated username and password. If set to FALSE, web hosts will be granted access by their detected IP address.',
];
}
/**
* List context types that are allowed to subscribe to this service.
* @return array
*/
static function allowedContexts() {
return [
'site'
];
}
/**
* Implements Service::server_options()
*
* @return array
*/
static function site_options()
{
return [
'db_name' => 'The name of the database. Default: Automatically generated.',
'db_user' => 'The username used to access the database. Default: Automatically generated.',
'db_password' => 'The password used to access the database. Default: Automatically generated.',
];
}
/**
* Register the db handler for sites, based on the db_server option.
*/
static function subscribe_site($context)
{
$context->setProperty('db_server', '@server_master');
$context->is_oid('db_server');
$context->service_subscribe('db', $context->db_server->name);
}
function init_server()
{
parent::init_server();
$this->server->setProperty('master_db');
$this->server->setProperty('db_grant_all_hosts', false);
$this->server->setProperty('utf8mb4_is_supported', false);
$this->creds = array_map(
'urldecode',
parse_url($this->server->master_db)
);
return true;
}
function save_server()
{
// Check database 4 byte UTF-8 support and save it for later.
$this->server->utf8mb4_is_supported = $this->utf8mb4_is_supported();
}
/**
* Verifies database connection and commands
*/
function verify_server_cmd()
{
if ($this->connect()) {
if ($this->can_create_database()) {
drush_log(dt('Provision can create new databases.'), 'success');
} else {
drush_set_error('PROVISION_CREATE_DB_FAILED');
}
if ($this->can_grant_privileges()) {
drush_log(
dt('Provision can grant privileges on database users.'),
'success'
);;
} else {
drush_set_error('PROVISION_GRANT_DB_USER_FAILED');
}
if ($this->server->utf8mb4_is_supported) {
drush_log(
dt(
'Provision can activate multi-byte UTF-8 support on Drupal 7 sites.'
),
'success'
);
} else {
drush_log(
dt(
'Multi-byte UTF-8 for Drupal 7 is not supported on your system. See the <a href="@url">documentation on adding 4 byte UTF-8 support</a> for more information.',
['@url' => 'https://www.drupal.org/node/2754539']
),
'warning'
);
}
} else {
drush_set_error('PROVISION_CONNECT_DB_FAILED');
}
}
/**
* Find a viable database name, based on the site's uri.
*/
function suggest_db_name()
{
$uri = $this->context->uri;
$suggest_base = substr(
str_replace(['.', '-'], '', preg_replace('/^www\./', '', $uri)),
0,
16
);
if (!$this->database_exists($suggest_base)) {
return $suggest_base;
}
for ($i = 0; $i < 100; $i++) {
$option = sprintf(
"%s_%d",
substr($suggest_base, 0, 15 - strlen((string)$i)),
$i
);
if (!$this->database_exists($option)) {
return $option;
}
}
drush_set_error(
'PROVISION_CREATE_DB_FAILED',
dt("Could not find a free database names after 100 attempts")
);
return false;
}
/**
* Generate a new mysql database and user account for the specified
* credentials
*/
function create_site_database($creds = [])
{
if (!sizeof($creds)) {
$creds = $this->generate_site_credentials();
}
extract($creds);
if (drush_get_error() || !$this->can_create_database()) {
drush_set_error('PROVISION_CREATE_DB_FAILED');
drush_log("Database could not be created.", 'error');
return false;
}
foreach ($this->grant_host_list() as $db_grant_host) {
drush_log(
dt(
"Granting privileges to %user@%client on %database",
[
'%user' => $db_user,
'%client' => $db_grant_host,
'%database' => $db_name,
]
)
);
if (!$this->grant($db_name, $db_user, $db_passwd, $db_grant_host)) {
drush_set_error(
'PROVISION_CREATE_DB_FAILED',
dt(
"Could not create database user @user",
['@user' => $db_user]
)
);
}
drush_log(
dt(
"Granted privileges to %user@%client on %database",
[
'%user' => $db_user,
'%client' => $db_grant_host,
'%database' => $db_name,
]
),
'success'
);
}
$this->create_database($db_name);
$status = $this->database_exists($db_name);
if ($status) {
drush_log(
dt('Created @name database', ["@name" => $db_name]),
'success'
);
} else {
drush_set_error(
'PROVISION_CREATE_DB_FAILED',
dt("Could not create @name database", ["@name" => $db_name])
);
}
return $status;
}
/**
* Remove the database and user account for the supplied credentials
*/
function destroy_site_database($creds = [])
{
if (!sizeof($creds)) {
$creds = $this->fetch_site_credentials();
}
extract($creds);
if ($this->database_exists($db_name)) {
drush_log(dt("Dropping database @dbname", ['@dbname' => $db_name]));
if (!$this->drop_database($db_name)) {
drush_log(
dt(
"Failed to drop database @dbname",
['@dbname' => $db_name]
),
'warning'
);
}
}
if ($this->database_exists($db_name)) {
drush_set_error('PROVISION_DROP_DB_FAILED');
return false;
}
foreach ($this->grant_host_list() as $db_grant_host) {
drush_log(
dt(
"Revoking privileges of %user@%client from %database",
[
'%user' => $db_user,
'%client' => $db_grant_host,
'%database' => $db_name,
]
)
);
if (!$this->revoke($db_name, $db_user, $db_grant_host)) {
drush_log(dt("Failed to revoke user privileges"), 'warning');
}
}
}
function import_site_database($dump_file = null, $creds = [])
{
if (is_null($dump_file)) {
$dump_file = d()->site_path.'/database.sql';
}
if (!sizeof($creds)) {
$creds = $this->fetch_site_credentials();
}
$exists = provision_file()->exists($dump_file)
->succeed('Found database dump at @path.')
->fail(
'No database dump was found at @path.',
'PROVISION_DB_DUMP_NOT_FOUND'
)
->status();
if ($exists) {
$readable = provision_file()->readable($dump_file)
->succeed('Database dump at @path is readable')
->fail(
'The database dump at @path could not be read.',
'PROVISION_DB_DUMP_NOT_READABLE'
)
->status();
if ($readable) {
$this->import_dump($dump_file, $creds);
}
}
}
function generate_site_credentials()
{
$creds = [];
// replace with service type
$db_type = drush_get_option(
'db_type',
function_exists('mysqli_connect') ? 'mysqli' : 'mysql'
);
// As of Drupal 7 there is no more mysqli type
if (drush_drupal_major_version() >= 7) {
$db_type = ($db_type == 'mysqli') ? 'mysql' : $db_type;
}
//TODO - this should not be here at all
$creds['db_type'] = drush_set_option('db_type', $db_type, 'site');
$creds['db_host'] = drush_set_option(
'db_host',
$this->server->remote_host,
'site'
);
$creds['db_port'] = drush_set_option(
'db_port',
$this->server->db_port,
'site'
);
$creds['db_passwd'] = drush_set_option(
'db_passwd',
provision_password(),
'site'
);
$creds['db_name'] = drush_set_option(
'db_name',
$this->suggest_db_name(),
'site'
);
$creds['db_user'] = drush_set_option(
'db_user',
$creds['db_name'],
'site'
);
return $creds;
}
function fetch_site_credentials()
{
$creds = [];
$keys = [
'db_type',
'db_port',
'db_user',
'db_name',
'db_host',
'db_passwd',
];
foreach ($keys as $key) {
$creds[$key] = drush_get_option($key, '', 'site');
}
return $creds;
}
function database_exists($name)
{
return false;
}
function drop_database($name)
{
return false;
}
function create_database($name)
{
return false;
}
function can_create_database()
{
return false;
}
function can_grant_privileges()
{
return false;
}
function grant($name, $username, $password, $host = '')
{
return false;
}
function revoke($name, $username, $host = '')
{
return false;
}
function import_dump($dump_file, $creds)
{
return false;
}
function generate_dump()
{
return false;
}
/**
* Return a list of hosts, as seen by the db server, which should be granted
* access to the site database. If server property 'db_grant_all_hosts' is
* TRUE, use the MySQL wildcard '%' instead of
*/
function grant_host_list()
{
if ($this->server->db_grant_all_hosts) {
return ['%'];
} else {
return array_unique(
array_map(
[$this, 'grant_host'],
$this->context->service('http')->grant_server_list()
)
);
}
}
/**
* Return a hostname suitable for database grants from a server object.
*/
function grant_host(Provision_Context_server $server)
{
return $server->remote_host;
}
/**
* Checks whether utf8mb4 support is available on the current database
* system.
*
* @return bool
*/
function utf8mb4_is_supported()
{
// By default we assume that the database backend may not support 4 byte
// UTF-8.
return false;
}
}
<?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 = 'platform.tpl.php';
public $description = 'platform configuration file';
function filename() {
return $this->service->properties['http_platformd_path'] . '/' . ltrim($this->context->name, '@') . '.conf';
}
}
\ 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()
{
parent::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'] = "";
}
}
\ 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() {
$file = $this->uri . '.conf';
// return $this->service->properties['http_platformd_path'] . '/' . ltrim($this->context->name, '@') . '.conf';
return $this->context->console_config['config_path'] . '/' . $this->context->name . '/' . $file;
// return $this->context->config['config_path'];
// 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;
}
$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['extra_config'] = "";
$this->data['http_vhostd_path'] = "{$app_dir}/vhost.d";
}
}
\ 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; ?>
<VirtualHost *:<?php print $http_port; ?>>
<?php if ($this->site_mail) : ?>
ServerAdmin <?php print $this->site_mail; ?>
<?php endif;?>
<?php
$aegir_root = drush_get_option('aegir_root');
if (!$aegir_root && $server->aegir_root) {
$aegir_root = $server->aegir_root;
}
?>
DocumentRoot <?php print $this->root; ?>
ServerName <?php print $this->uri; ?>
SetEnv db_type <?php print urlencode($db_type); ?>
SetEnv db_name <?php print urlencode($db_name); ?>
SetEnv db_user <?php print urlencode($db_user); ?>
SetEnv db_passwd <?php print urlencode($db_passwd); ?>
SetEnv db_host <?php print urlencode($db_host); ?>
SetEnv db_port <?php print urlencode($db_port); ?>
<?php
if (sizeof($this->aliases)) {
foreach ($this->aliases as $alias) {
print " ServerAlias " . $alias . "\n";
}
}
?>
<IfModule mod_rewrite.c>
RewriteEngine on
<?php
if ($this->redirection || $ssl_redirection) {
if ($ssl_redirection && !$this->redirection) {
print " # Redirect aliases in non-ssl to the same alias on ssl.\n";
print " RewriteRule ^/*(.*)$ https://%{HTTP_HOST}/$1 [NE,L,R=301]\n";
}
elseif ($ssl_redirection && $this->redirection) {
print " # Redirect all aliases + main uri to the main https uri.\n";
print " RewriteRule ^/*(.*)$ https://{$this->uri}/$1 [NE,L,R=301]\n";
}
elseif (!$ssl_redirection && $this->redirection) {
print " # Redirect all aliases to the main http url.\n";
print " RewriteCond %{HTTP_HOST} !^{$this->redirection}$ [NC]\n";
print " RewriteRule ^/*(.*)$ http://{$this->redirection}/$1 [NE,L,R=301]\n";
}
}
?>
RewriteRule ^/files/(.*)$ /sites/<?php print $this->uri; ?>/files/$1 [L]
RewriteCond <?php print $this->site_path; ?>/files/robots.txt -f
RewriteRule ^/robots.txt /sites/<?php print $this->uri; ?>/files/robots.txt [L]
</IfModule>
<?php print $extra_config; ?>
# Error handler for Drupal > 4.6.7
<Directory ~ "sites/.*/files">
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
# Prevent direct reading of files in the private dir.
# This is for Drupal7 compatibility, which would normally drop
# a .htaccess in those directories, but we explicitly ignore those
<Directory "<?php print $this->site_path; ?>/private/" >
<Files *>
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Files>
Deny from all
Options None
Options +FollowSymLinks
# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
php_flag engine off
</IfModule>
</Directory>
<?php
$if_subsite = $this->data['http_subdird_path'] . '/' . $this->uri;
if (provision_hosting_feature_enabled('subdirs') && provision_file()->exists($if_subsite)->status()) {
print " Include " . $if_subsite . "/*.conf\n";
}
?>
</VirtualHost>