diff --git a/.travis.yml b/.travis.yml index 243d57450..c20b7c3c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ branches: env: global: - - AEGIR_HOSTING_VERSION=7.x-3.x + - AEGIR_HOSTING_VERSION=feature/quick-review - AEGIR_TESTS_VERSION=master #env: diff --git a/Provision/Service.php b/Provision/Service.php index 58b97bfa8..73ee64a36 100644 --- a/Provision/Service.php +++ b/Provision/Service.php @@ -336,4 +336,23 @@ function verify() { static function option_documentation() { return array(); } + + /** + * Save symlink for this server from /var/aegir/config/APPLICATION_NAME.conf -> /var/aegir/config/SERVER/APPLICATION_NAME.conf + */ + function symlink_service() { + $file = $this->application_name . '.conf'; + // We link the app_name.conf file on the remote server to the right version. + $cmd = sprintf('ln -sf %s %s', + escapeshellarg($this->server->config_path . '/' . $file), + escapeshellarg($this->server->aegir_root . '/config/' . $file) + ); + + if ($this->server->shell_exec($cmd)) { + drush_log(dt("Created symlink for %file on %server", array( + '%file' => $file, + '%server' => $this->server->remote_host, + ))); + }; + } } diff --git a/aegir.make b/aegir.make index d1357cc84..e81e9d52f 100644 --- a/aegir.make +++ b/aegir.make @@ -5,6 +5,6 @@ projects[drupal][type] = "core" projects[hostmaster][type] = "profile" projects[hostmaster][download][type] = "git" -projects[hostmaster][download][url] = "http://git.drupal.org/project/hostmaster.git" -projects[hostmaster][download][branch] = "7.x-3.x" +projects[hostmaster][download][url] = https://github.com/aegir-project/hostmaster.git +projects[hostmaster][download][branch] = "feature/quick-review" diff --git a/debian/aegir3-hostmaster.postinst b/debian/aegir3-hostmaster.postinst index 800db26dd..6c50be560 100644 --- a/debian/aegir3-hostmaster.postinst +++ b/debian/aegir3-hostmaster.postinst @@ -188,6 +188,7 @@ EOF ;; abort-upgrade|abort-remove|abort-deconfigure) + service hosting-queued start ;; *) diff --git a/http/Provision/Config/Apache/server.tpl.php b/http/Provision/Config/Apache/server.tpl.php index 621e7ac13..5efa19db8 100644 --- a/http/Provision/Config/Apache/server.tpl.php +++ b/http/Provision/Config/Apache/server.tpl.php @@ -17,18 +17,30 @@ LoadModule rewrite_module modules/mod_rewrite.so + + # other configuration, not touched by aegir # this allows you to override aegir configuration, as it is included before -Include + # virtual hosts -Include + # platforms -Include + # other configuration, not touched by aegir # this allows to have default (for example during migrations) that are eventually overriden by aegir -Include + diff --git a/http/Provision/Config/Http/Server.php b/http/Provision/Config/Http/Server.php index 14459d751..1a9fe5296 100644 --- a/http/Provision/Config/Http/Server.php +++ b/http/Provision/Config/Http/Server.php @@ -16,23 +16,6 @@ class Provision_Config_Http_Server extends Provision_Config_Http { function write() { parent::write(); - - if (isset($this->data['application_name'])) { - $file = $this->data['application_name'] . '.conf'; - // We link the app_name.conf file on the remote server to the right version. - $cmd = sprintf('ln -sf %s %s', - escapeshellarg($this->data['server']->config_path . '/' . $file), - escapeshellarg($this->data['server']->aegir_root . '/config/' . $file) - ); - - if ($this->data['server']->shell_exec($cmd)) { - drush_log(dt("Created symlink for %file on %server", array( - '%file' => $file, - '%server' => $this->data['server']->remote_host, - ))); - - }; - } } function filename() { diff --git a/http/Provision/Config/Http/Site.php b/http/Provision/Config/Http/Site.php index b3292342c..35c702625 100644 --- a/http/Provision/Config/Http/Site.php +++ b/http/Provision/Config/Http/Site.php @@ -11,7 +11,12 @@ class Provision_Config_Http_Site extends Provision_Config_Http { function filename() { - return $this->data['http_vhostd_path'] . '/' . $this->uri; + 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() { diff --git a/http/Provision/Service/http/public.php b/http/Provision/Service/http/public.php index d35a36187..4d85fdf93 100644 --- a/http/Provision/Service/http/public.php +++ b/http/Provision/Service/http/public.php @@ -57,10 +57,11 @@ function init_server() { $this->server->http_vhostd_path = "{$app_dir}/vhost.d"; $this->server->http_subdird_path = "{$app_dir}/subdir.d"; $this->server->http_platforms_path = "{$this->server->aegir_root}/platforms"; + + $this->symlink_service(); } } - static function option_documentation() { return array( 'web_group' => 'server with http: OS group for permissions; working default will be attempted', diff --git a/install.hostmaster.inc b/install.hostmaster.inc index 89b7e7976..4c7d137a4 100644 --- a/install.hostmaster.inc +++ b/install.hostmaster.inc @@ -277,6 +277,8 @@ function drush_provision_hostmaster_install($site = NULL) { drush_invoke_process('@none', 'cache-clear', array('drush')); provision_backend_invoke($site_name, 'hosting-setup'); + provision_backend_invoke($platform_name, 'provision-lock'); + drush_print(""); drush_print("=============================================================================="); drush_print(""); diff --git a/migrate.hostmaster.inc b/migrate.hostmaster.inc index 7e27b1981..03349870d 100644 --- a/migrate.hostmaster.inc +++ b/migrate.hostmaster.inc @@ -160,8 +160,7 @@ We are making the following assumptions: * Prepare the hostmaster site for migration */ function drush_provision_pre_hostmaster_migrate($site, $platform) { - // we ignore errors here through integrate = FALSE - provision_backend_invoke(drush_get_option('site_name'), 'hosting-pause', array(), array('#integrate' => FALSE)); + provision_backend_invoke(drush_get_option('site_name'), 'hosting-pause', array(), array()); } function drush_provision_hostmaster_migrate($site, $platform) { @@ -213,5 +212,8 @@ function drush_provision_post_hostmaster_migrate($site, $platform) { // We need to re-verify @server_master via frontend to re-generate // its drush alias and to update Nginx configuration files. provision_backend_invoke('@hostmaster', 'hosting-task', array(@server_master, 'verify'), array('force' => TRUE)); + + $new_platform = _provision_path_to_platform_alias($platform); + provision_backend_invoke($new_platform, 'provision-lock'); } diff --git a/platform/drupal/packages_6.inc b/platform/drupal/packages_6.inc index d70478772..49ee3d43a 100644 --- a/platform/drupal/packages_6.inc +++ b/platform/drupal/packages_6.inc @@ -193,3 +193,80 @@ function _provision_drupal_system_map() { drush_log(dt("Found !count themes", array('!count' => sizeof($packages['themes'])))); return $packages; } + +/** + * Find available profiles on this platform. + */ +function _provision_find_profiles() { + $profiles = array(); + + include_once('includes/install.inc'); + $profiles_subdirs[] = "./profiles"; + + foreach($profiles_subdirs as $profiles_subdir) { + if (!$dir = opendir($profiles_subdir)) { + drush_log(dt("Cannot find profiles directory"), 'error'); + return FALSE; + } + + while (FALSE !== ($name = readdir($dir))) { + $languages = array(); + if (($name == '..') || ($name == '.') || (!is_dir("$profiles_subdir/$name"))) { + continue; + } + + $profile = new stdClass(); + $profile->name = $name; + $profile->info = array(); + + $info_file = "$profiles_subdir/$name/$name.info"; + if (file_exists($info_file)) { + $profile->info = provision_parse_info_file($info_file); + // Skip hidden profiles + if (isset($profile->info['hidden']) && $profile->info['hidden'] == 1) { + continue; + } + } + $profile->filename = $info_file; + + // Include code from the profile. + if (file_exists($profile_file = "$profiles_subdir/$name/$name.profile")) { + require_once($profile_file); + } + + $func = $profile->name . "_profile_details"; + if (function_exists($func)) { + $profile->info = array_merge($profile->info, $func()); + } + + $profile_path = $profiles_subdir . '/' . $name; + $profile->info['languages'] = _provision_find_profile_languages($profile_path); + + $profiles[$name] = $profile; + drush_log(dt('Found install profile %name', array('%name' => $name))); + } + } + return $profiles; +} + +/** + * Retrieve a list of paths to search in a certain scope + */ +function _provision_drupal_search_paths($scope, $key = '', $type = 'modules') { + $searchpaths = array(); + $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); + switch ($scope) { + case 'base' : + $searchpaths[] = sprintf("%s/%s", $drupal_root, $type); + $searchpaths[] = sprintf("%s/sites/all/%s", $drupal_root, $type); + break; + default : + if ($key) { + $searchpaths[] = sprintf("%s/%s/%s/%s", $drupal_root, $scope, $key, $type); + } + break; + + } + return $searchpaths; +} + diff --git a/platform/drupal/packages_7.inc b/platform/drupal/packages_7.inc index b99502403..89517c4ac 100644 --- a/platform/drupal/packages_7.inc +++ b/platform/drupal/packages_7.inc @@ -204,3 +204,86 @@ function _provision_drupal_system_map() { drush_log(dt("Found !count themes", array('!count' => sizeof($packages['themes'])))); return $packages; } + +/** + * Find available profiles on this platform. + */ +function _provision_find_profiles() { + $profiles = array(); + + include_once('includes/install.inc'); + $profiles_subdirs[] = "./profiles"; + + foreach($profiles_subdirs as $profiles_subdir) { + if (!$dir = opendir($profiles_subdir)) { + drush_log(dt("Cannot find profiles directory"), 'error'); + return FALSE; + } + + while (FALSE !== ($name = readdir($dir))) { + $languages = array(); + if (($name == '..') || ($name == '.') || (!is_dir("$profiles_subdir/$name"))) { + continue; + } + + $profile = new stdClass(); + $profile->name = $name; + $profile->info = array(); + + $info_file = "$profiles_subdir/$name/$name.info"; + if (file_exists($info_file)) { + $profile->info = provision_parse_info_file($info_file); + // Skip hidden profiles + if (isset($profile->info['hidden']) && $profile->info['hidden'] == 1) { + continue; + } + } + $profile->filename = $info_file; + + // Include code from the profile. + if (file_exists($profile_file = "$profiles_subdir/$name/$name.profile")) { + require_once($profile_file); + } + + $func = $profile->name . "_profile_details"; + if (function_exists($func)) { + $profile->info = array_merge($profile->info, $func()); + } + + $profile_path = $profiles_subdir . '/' . $name; + $profile->info['languages'] = _provision_find_profile_languages($profile_path); + + // Drupal 7 renamed the default install profile to 'standard' + // Aegir now allows projects to specify an "old short name" to provide an upgrade path when projects get renamed. + if ($profile->name == 'standard') { + $profile->info['old_short_name'] = 'default'; + } + + $profiles[$name] = $profile; + drush_log(dt('Found install profile %name', array('%name' => $name))); + } + } + return $profiles; +} + +/** + * Retrieve a list of paths to search in a certain scope + */ +function _provision_drupal_search_paths($scope, $key = '', $type = 'modules') { + $searchpaths = array(); + $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); + switch ($scope) { + case 'base' : + $searchpaths[] = sprintf("%s/%s", $drupal_root, $type); + $searchpaths[] = sprintf("%s/sites/all/%s", $drupal_root, $type); + break; + default : + if ($key) { + $searchpaths[] = sprintf("%s/%s/%s/%s", $drupal_root, $scope, $key, $type); + } + break; + + } + return $searchpaths; +} + diff --git a/platform/drupal/packages_8.inc b/platform/drupal/packages_8.inc index 272c3a61a..aea1bcd17 100644 --- a/platform/drupal/packages_8.inc +++ b/platform/drupal/packages_8.inc @@ -113,3 +113,64 @@ function _provision_system_query($type) { return $packages; } + +/** + * Find available profiles on this platform. + */ +function _provision_find_profiles() { + $profile_dirs = array('./core/profiles', './profiles'); + + $profiles = array(); + foreach($profile_dirs as $profile_dir) { + if (!is_dir($profile_dir)) { + drush_log(dt("Cannot find profiles directory %dir", array('%dir' => $profile_dir)), 'error'); + return FALSE; + } + + $info_files = drush_scan_directory($profile_dir, "/\.info.yml$/"); + foreach ($info_files as $path => $info_file) { + $path = realpath($path); + $info = Symfony\Component\Yaml\Yaml::parse($path); + if ($info['type'] == 'profile' && (!isset($info['hidden']) || !$info['hidden'])) { + $profile = new stdClass(); + $profile->name = $info['name']; + $profile->info = $info; + $profile->filename = $path; + $profile->path = dirname($path); + $profile->info['languages'] = _provision_find_profile_languages($profile->path); + + $profiles[basename($profile->path)] = $profile; + drush_log(dt('Found install profile %name', array('%name' => $name))); + } + } + } + return $profiles; +} + +/** + * Retrieve a list of paths to search in a certain scope + */ +function _provision_drupal_search_paths($scope, $key = '', $type = 'modules') { + $searchpaths = array(); + $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); + switch ($scope) { + case 'base': + $searchpaths[] = sprintf("%s/%s", $drupal_root, $type); + $searchpaths[] = sprintf("%s/core/%s", $drupal_root, $type); + $searchpaths[] = sprintf("%s/sites/all/%s", $drupal_root, $type); + break; + case 'profiles': + foreach (_provision_find_profiles() as $profile) { + $searchpaths[] = $profile->path; + } + break; + default: + if ($key) { + $searchpaths[] = sprintf("%s/%s/%s/%s", $drupal_root, $scope, $key, $type); + } + break; + + } + return $searchpaths; +} + diff --git a/platform/install.provision.inc b/platform/install.provision.inc index 95559f0e9..97db86b30 100644 --- a/platform/install.provision.inc +++ b/platform/install.provision.inc @@ -87,14 +87,28 @@ function drush_provision_drupal_provision_install() { drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_SITE); - // call a backend task to do the actual installation. - $result = provision_backend_invoke(d()->name, "provision-install-backend", array(), array('client_email' => drush_get_option('client_email'))); - // pass the login link back to the front end. - drush_set_option('login_link', $result['context']['login_link']); + // Install site according to site_install_method. + drush_log(dt('Installing site with the "!method" method.', array( + '!method' => drush_get_option('site_install_method', 'profile'), + )), 'ok'); + + // Run Drupal installation if option was specified + if (drush_get_option('site_install_method', 'profile') == 'profile') { + + // call a backend task to do the actual installation. + $result = provision_backend_invoke(d()->name, "provision-install-backend", array(), array('client_email' => drush_get_option('client_email'))); + // pass the login link back to the front end. + drush_set_option('login_link', $result['context']['login_link']); + + drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL); + drush_set_option('installed', TRUE, 'site'); + } + elseif (drush_get_option('site_install_method', 'profile') == 'manual') { + drush_set_option('login_link', 'http://' . d()->uri . '/install.php'); + } - drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_FULL); - drush_set_option('installed', TRUE, 'site'); _provision_drupal_maintain_aliases(); + } /** @@ -102,10 +116,13 @@ function drush_provision_drupal_provision_install() { * any changes to things such as available modules/ themes can take affect. */ function drush_provision_drupal_post_provision_install() { - drush_set_option('installed', TRUE, 'site'); - _provision_drupal_rebuild_caches(); - drush_set_option('packages', _scrub_object(provision_drupal_system_map()), 'site'); - _provision_client_create_symlink(); - drush_include_engine('drupal', 'cron_key'); + + // If Drupal profile was installed, rebuild drupal caches and save enabled packages for aegir. + if (drush_get_option('installed', FALSE, 'site')) { + _provision_drupal_rebuild_caches(); + drush_set_option('packages', _scrub_object(provision_drupal_system_map()), 'site'); + _provision_client_create_symlink(); + drush_include_engine('drupal', 'cron_key'); + } } diff --git a/platform/provision_drupal.drush.inc b/platform/provision_drupal.drush.inc index 389486e1b..233d60f28 100644 --- a/platform/provision_drupal.drush.inc +++ b/platform/provision_drupal.drush.inc @@ -372,105 +372,6 @@ function _provision_drupal_rebuild_caches() { } } -/** - * Find available profiles on this platform. - */ -function _provision_find_profiles() { - $profiles = array(); - - if (drush_drupal_major_version() >= 8) { - include_once('core/includes/install.inc'); - $profiles_subdirs[] = "./core/profiles"; - $profiles_subdirs[] = "./profiles"; - } - else { - include_once('includes/install.inc'); - $profiles_subdirs[] = "./profiles"; - } - - foreach($profiles_subdirs as $profiles_subdir) { - if (!$dir = opendir($profiles_subdir)) { - drush_log(dt("Cannot find profiles directory"), 'error'); - return FALSE; - } - - while (FALSE !== ($name = readdir($dir))) { - $languages = array(); - if (($name == '..') || ($name == '.') || (!is_dir("$profiles_subdir/$name"))) { - continue; - } - - $profile = new stdClass(); - $profile->name = $name; - $profile->info = array(); - - if (drush_drupal_major_version() >= 8) { - $yaml_file = "$profiles_subdir/$name/$name.info.yml"; - if(!file_exists($yaml_file)) { - drush_log(dt("@name.info.yml not found.", array("@name" => $name)), 'notice'); - unset($files[$name]); - continue; - } - $profile->info = Symfony\Component\Yaml\Yaml::parse($yaml_file); - - // Skip hidden profiles. - if (isset($profile->info['hidden']) && $profile->info['hidden'] == 1) { - continue; - } - - if (!empty($profile->info['name'])) { - $profile->name = $profile->info['name']; - } - $profile->filename = $yaml_file; - } - else { - $info_file = "$profiles_subdir/$name/$name.info"; - if (file_exists($info_file)) { - $profile->info = provision_parse_info_file($info_file); - // Skip hidden profiles - if (isset($profile->info['hidden']) && $profile->info['hidden'] == 1) { - continue; - } - } - $profile->filename = $info_file; - } - - // Include code from the profile. - if (file_exists($profile_file = "$profiles_subdir/$name/$name.profile")) { - require_once($profile_file); - } - - $func = $profile->name . "_profile_details"; - if (function_exists($func)) { - $profile->info = array_merge($profile->info, $func()); - } - - $languages['en'] = 1; - // Find languages available - $files = array_keys(drush_scan_directory($profiles_subdir . '/' . $name . '/translations', '/\.po$/', array('.', '..', 'CVS'), 0, FALSE, 'filepath')); - $files = array_merge($files, array_keys(drush_scan_directory($profiles_subdir . '/' . $name , '/\.po$/', array('.', '..', 'CVS'), 0, FALSE, 'filepath'))); - if (is_array($files)) { - foreach ($files as $file) { - if (preg_match('!(/|\.)([^\./]+)\.po$!', $file, $langcode)) { - $languages[$langcode[2]] = 1; // use the language name as an index to weed out duplicates - } - } - } - $profile->info['languages'] = array_keys($languages); - - // Drupal 7 renamed the default install profile to 'standard' - // Aegir now allows projects to specify an "old short name" to provide an upgrade path when projects get renamed. - if ($profile->name == 'standard') { - $profile->info['old_short_name'] = 'default'; - } - - $profiles[$name] = $profile; - drush_log(dt('Found install profile %name', array('%name' => $name))); - } - } - return $profiles; -} - function provision_drupal_find_sites() { $sites = array(); if ($dir = opendir("./sites")) { @@ -640,28 +541,6 @@ function provision_drupal_system_map() { return _provision_drupal_system_map(); } -/** - * Retrieve a list of paths to search in a certain scope - */ -function _provision_drupal_search_paths($scope, $key = '', $type = 'modules') { - $searchpaths = array(); - $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'); - switch ($scope) { - case 'base' : - $searchpaths[] = sprintf("%s/%s", $drupal_root, $type); - $searchpaths[] = sprintf("%s/core/%s", $drupal_root, $type); - $searchpaths[] = sprintf("%s/sites/all/%s", $drupal_root, $type); - break; - default : - if ($key) { - $searchpaths[] = sprintf("%s/%s/%s/%s", $drupal_root, $scope, $key, $type); - } - break; - - } - return $searchpaths; -} - /** * Find modules in a certain scope. * @@ -847,3 +726,25 @@ function _provision_client_delete_symlink() { ->fail('Failed to delete symlink @path: @reason'); } } + +/** + * Find available languages for a profile. + */ +function _provision_find_profile_languages($profile_path) { + $languages = array(); + + // English is default. + $languages['en'] = 1; + + // Find languages available. + $files = array_keys(drush_scan_directory($profile_path . '/translations', '/\.po$/', array('.', '..', 'CVS'), 0, FALSE, 'filepath')); + $files = array_merge($files, array_keys(drush_scan_directory($profile_path, '/\.po$/', array('.', '..', 'CVS'), 0, FALSE, 'filepath'))); + if (is_array($files)) { + foreach ($files as $file) { + if (preg_match('!(/|\.)([^\./]+)\.po$!', $file, $langcode)) { + $languages[$langcode[2]] = 1; // use the language name as an index to weed out duplicates + } + } + } + return array_keys($languages); +} diff --git a/provision.api.php b/provision.api.php index 89f8eba10..50fd9e2d3 100644 --- a/provision.api.php +++ b/provision.api.php @@ -14,8 +14,15 @@ * $options['provision_backup_suffix'] = '.tar.bz2'; * * provision_verify_platforms_before_migrate - When migrating many sites turning this off can save time, default TRUE. + * * provision_backup_suffix - Method to set the compression used for backups... e.g. '.tar.bz2' or '.tar.', defaults to '.tar.gz'. * + * provision_apache_conf_suffix + * Set to TRUE to generate apache vhost files with a .conf suffix, default FALSE. + * This takes advantage of the IncludeOptional statment introduced in Apache 2.3.6. + * WARNING: After turning this on you need to re-verify all your sites, then then servers, + * and then cleanup the old configfiles (those without the .conf suffix). + * */ /**