diff --git a/Provision/Config.php b/Provision/Config.php index 4264f6cbacb1043ad53ce1e81db55d9c56246d5a..d2b6353c910e911fbdf0487969e4236e7b4c87bb 100644 --- a/Provision/Config.php +++ b/Provision/Config.php @@ -110,11 +110,33 @@ class Provision_Config { /** * Load template from filename(). + * + * @see hook_provision_config_load_templates() + * @see hook_provision_config_load_templates_alter() */ private function load_template() { - $class_name = get_class($this); + // 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 (file_exists($file) && is_readable($file)) { + drush_log("Template loaded: $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. @@ -131,6 +153,7 @@ class Provision_Config { } } + // We've failed to find a template if we've reached this far. return FALSE; } diff --git a/Provision/Service.php b/Provision/Service.php index b8c2398e79b5affd2dba8cd2d926ac101d29add7..d0278e1027da67fe5562ba28fcd7d2523f2d0045 100644 --- a/Provision/Service.php +++ b/Provision/Service.php @@ -238,13 +238,15 @@ class Provision_Service extends Provision_ChainedState { * * This method will fetch the class to instantiate from the internal * $this->configs control array. + * + * @return the return value of unlink(), which is usually the file object */ function delete_config($config, $data = array()) { - $this->config($config, $data)->unlink(); + return $this->config($config, $data)->unlink(); } /** - * Fetch extra information the service wants to pass to he config file classes. + * Fetch extra information the service wants to pass to the config file classes. */ function config_data($config = NULL, $class = NULL) { $data = array(); diff --git a/debian/aegir-cluster-slave.config b/debian/aegir-cluster-slave2.config similarity index 100% rename from debian/aegir-cluster-slave.config rename to debian/aegir-cluster-slave2.config diff --git a/debian/aegir-cluster-slave.dirs b/debian/aegir-cluster-slave2.dirs similarity index 100% rename from debian/aegir-cluster-slave.dirs rename to debian/aegir-cluster-slave2.dirs diff --git a/debian/aegir-cluster-slave.examples b/debian/aegir-cluster-slave2.examples similarity index 100% rename from debian/aegir-cluster-slave.examples rename to debian/aegir-cluster-slave2.examples diff --git a/debian/aegir-cluster-slave.postinst b/debian/aegir-cluster-slave2.postinst similarity index 97% rename from debian/aegir-cluster-slave.postinst rename to debian/aegir-cluster-slave2.postinst index e4700b0f0eb56343b84067f0b1da49128103593e..448e31ad8b52dfd9516e5b2bd93cef46b699084a 100644 --- a/debian/aegir-cluster-slave.postinst +++ b/debian/aegir-cluster-slave2.postinst @@ -41,7 +41,7 @@ case "$1" in adduser --quiet aegir www-data if [ -d /etc/sudoers.d ]; then - ucf --debconf-ok /usr/share/doc/aegir-cluster-slave/examples/example.sudoers /etc/sudoers.d/aegir + ucf --debconf-ok /usr/share/doc/aegir-cluster-slave2/examples/example.sudoers /etc/sudoers.d/aegir ucfr aegir-provision /etc/sudoers.d/aegir chmod 440 /etc/sudoers.d/aegir else diff --git a/debian/aegir-cluster-slave.postrm b/debian/aegir-cluster-slave2.postrm similarity index 100% rename from debian/aegir-cluster-slave.postrm rename to debian/aegir-cluster-slave2.postrm diff --git a/debian/aegir-cluster-slave.prerm b/debian/aegir-cluster-slave2.prerm similarity index 100% rename from debian/aegir-cluster-slave.prerm rename to debian/aegir-cluster-slave2.prerm diff --git a/debian/aegir-cluster-slave.templates b/debian/aegir-cluster-slave2.templates similarity index 100% rename from debian/aegir-cluster-slave.templates rename to debian/aegir-cluster-slave2.templates diff --git a/debian/aegir-hostmaster.config b/debian/aegir-hostmaster2.config similarity index 97% rename from debian/aegir-hostmaster.config rename to debian/aegir-hostmaster2.config index 3989ff7439cce74457eebd68b371a27a6a18a4bc..cc8b7e84b8e7f121eb9a6334660470ddeda6de8d 100644 --- a/debian/aegir-hostmaster.config +++ b/debian/aegir-hostmaster2.config @@ -5,7 +5,7 @@ set -e # Source debconf library. . /usr/share/debconf/confmodule -if [ "$DPKG_DEBUG" = "developer" ] || [ ! -z "$DEBUG" ]; then +if [ "$DPKG_DEBUG" = "developer" ]; then set -x fi diff --git a/debian/aegir-hostmaster.hosting-queued.init b/debian/aegir-hostmaster2.hosting-queued.init similarity index 98% rename from debian/aegir-hostmaster.hosting-queued.init rename to debian/aegir-hostmaster2.hosting-queued.init index 38be240394d08fca8d8abbe446be92e5a52588fd..cc0eaf40d2f6b1d5beda59b8f9945ce992528119 100755 --- a/debian/aegir-hostmaster.hosting-queued.init +++ b/debian/aegir-hostmaster2.hosting-queued.init @@ -1,8 +1,8 @@ #!/bin/sh ### BEGIN INIT INFO # Provides: hosting-queued -# Required-Start: $network $local_fs -# Required-Stop: +# Required-Start: $network $remote_fs +# Required-Stop: $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Queue runner daemon for Aegir diff --git a/debian/aegir-hostmaster.postinst b/debian/aegir-hostmaster2.postinst similarity index 86% rename from debian/aegir-hostmaster.postinst rename to debian/aegir-hostmaster2.postinst index a726ae93594f1c1437d394e0f1b70f9b6cd54e01..0b79c3abc43061c9fa8ede8c71815599b4e46ef6 100644 --- a/debian/aegir-hostmaster.postinst +++ b/debian/aegir-hostmaster2.postinst @@ -20,7 +20,7 @@ set -e # Source debconf library. . /usr/share/debconf/confmodule -if [ "$DPKG_DEBUG" = "developer" ] || [ ! -z "$DEBUG" ]; then +if [ "$DPKG_DEBUG" = "developer" ]; then set -x fi @@ -34,7 +34,7 @@ case "$1" in VERSION=`sed -n '/^version/{s/^.*= *//;p}' /usr/share/drush/commands/provision/provision.info` FLAGS="--yes" - if [ "$DPKG_DEBUG" = "developer" ] || [ ! -z "$DEBUG" ]; then + if [ "$DPKG_DEBUG" = "developer" ]; then FLAGS="$FLAGS --debug" fi db_get "aegir/makefile" @@ -65,9 +65,16 @@ case "$1" in echo "it seems to be the same version as the one we're trying to install, not upgrading" else echo "upgrading the frontend from $drupal_root to $NEW_PLATFORM" + if su -s /bin/sh aegir -c 'drush @hostmaster pm-list --status=enabled --pipe' | grep -q hosting_queued; then + service hosting-queued stop + fi cd "$drupal_root" su -s /bin/sh aegir -c "drush hostmaster-migrate $FLAGS '$site_uri' '$NEW_PLATFORM'" echo "upgrade finished, old platform left in $drupal_root" + # restart daemon if enabled + if su -s /bin/sh aegir -c 'drush @hostmaster pm-list --status=enabled --pipe' | grep -q hosting_queued; then + service hosting-queued start + fi fi else # fresh install @@ -106,6 +113,10 @@ case "$1" in "client_email": "$EMAIL" } EOF + # on new installs, we default to having the daemon enabled + echo 'Enabling hosting-queued daemon' + su aegir -c 'drush @hostmaster pm-enable hosting-queued' + service hosting-queued start fi rm -f $TEMPFILE # this will ensure that this script aborts if the site can't be bootstrapped diff --git a/debian/aegir-hostmaster.templates b/debian/aegir-hostmaster2.templates similarity index 100% rename from debian/aegir-hostmaster.templates rename to debian/aegir-hostmaster2.templates diff --git a/debian/aegir-provision.dirs b/debian/aegir-provision2.dirs similarity index 100% rename from debian/aegir-provision.dirs rename to debian/aegir-provision2.dirs diff --git a/debian/aegir-provision.docs b/debian/aegir-provision2.docs similarity index 100% rename from debian/aegir-provision.docs rename to debian/aegir-provision2.docs diff --git a/debian/aegir-provision.examples b/debian/aegir-provision2.examples similarity index 100% rename from debian/aegir-provision.examples rename to debian/aegir-provision2.examples diff --git a/debian/aegir-provision.lintian b/debian/aegir-provision2.lintian similarity index 100% rename from debian/aegir-provision.lintian rename to debian/aegir-provision2.lintian diff --git a/debian/aegir-provision.postinst b/debian/aegir-provision2.postinst similarity index 89% rename from debian/aegir-provision.postinst rename to debian/aegir-provision2.postinst index b5fda076e199c173f2ad4b2d06f96532489b3e68..fb224a6aa53e8a670ae004472ab9ea139276a889 100644 --- a/debian/aegir-provision.postinst +++ b/debian/aegir-provision2.postinst @@ -20,7 +20,7 @@ set -e # Source debconf library. . /usr/share/debconf/confmodule -if [ "$DPKG_DEBUG" = "developer" ] || [ ! -z "$DEBUG" ]; then +if [ "$DPKG_DEBUG" = "developer" ]; then set -x fi @@ -40,12 +40,12 @@ case "$1" in adduser --quiet aegir www-data if [ -d /etc/sudoers.d ]; then - ucf --debconf-ok /usr/share/doc/aegir-provision/examples/example.sudoers /etc/sudoers.d/aegir + ucf --debconf-ok /usr/share/doc/aegir-provision2/examples/example.sudoers /etc/sudoers.d/aegir ucfr aegir-provision /etc/sudoers.d/aegir chmod 440 /etc/sudoers.d/aegir else echo "running an older version of sudo" - echo "copy content of /usr/share/doc/aegir-provision/examples/example.sudoers into /etc/sudoers for aegir to run properly" + echo "copy content of /usr/share/doc/aegir-provision2/examples/example.sudoers into /etc/sudoers for aegir to run properly" fi # fix permissions on installed directories diff --git a/debian/aegir-provision.postrm b/debian/aegir-provision2.postrm similarity index 96% rename from debian/aegir-provision.postrm rename to debian/aegir-provision2.postrm index e63a85fe53fc03395365020fe1f0254bae1e221d..8f4630647da4d9acde0a6c01944434dddf83908d 100644 --- a/debian/aegir-provision.postrm +++ b/debian/aegir-provision2.postrm @@ -18,7 +18,7 @@ set -e # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package -if [ "$DPKG_DEBUG" = "developer" ] || [ ! -z "$DEBUG" ]; then +if [ "$DPKG_DEBUG" = "developer" ]; then set -x fi diff --git a/debian/aegir-provision.preinst b/debian/aegir-provision2.preinst similarity index 94% rename from debian/aegir-provision.preinst rename to debian/aegir-provision2.preinst index fffb20f1c0ce134e52e599ed64a6a81caae49f9d..457f88e197eb227d82765b6ff48f0446cb5da44f 100644 --- a/debian/aegir-provision.preinst +++ b/debian/aegir-provision2.preinst @@ -26,7 +26,7 @@ case "$1" in exit 1 fi if [ -d $VARLIB/.drush/provision ]; then - echo "existing provision install in $VARLIB/.drush/drush_make detected" + echo "existing provision install in $VARLIB/.drush/provision detected" echo "this needs to be removed or moved away for the install to be completed" echo "try: rm -rf $VARLIB/.drush/provision" exit 1 diff --git a/debian/changelog b/debian/changelog index 043fbac7f02bee9d534a511944fb5b056d3f20f5..ed3a2a84021c53c360f7cb6e902973b50ecb340e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +aegir-provision2 (2.0~alpha1) unstable; urgency=low + + * first alpha release of the 2.x branch, release notes too long to + document here: http://community.aegirproject.org/2.0-alpha1 + + -- Antoine Beaupré Thu, 07 Feb 2013 16:52:49 -0500 + aegir-provision (2.0~0.0alpha0) UNRELEASED; urgency=low * switch to a native package diff --git a/debian/control b/debian/control index 5d95dfad3cc4ca270b4117a09f4de722d6056d0a..72345c334497c6d7b8b60c930952f128aca75e88 100644 --- a/debian/control +++ b/debian/control @@ -1,4 +1,4 @@ -Source: aegir-provision +Source: aegir-provision2 Section: admin Priority: optional Maintainer: Antoine Beaupré @@ -9,11 +9,13 @@ Homepage: http://aegirproject.org/ Vcs-git: http://git.drupal.org/project/provision.git Vcs-browser: http://drupalcode.org/project/provision.git -Package: aegir-provision +Package: aegir-provision2 Architecture: all -Depends: ${misc:Depends}, drush (>= 5.5), php5-mysql, mysql-client, sudo, mail-transport-agent, apache2 | nginx, adduser, ucf +Depends: ${misc:Depends}, drush (>= 5.5), php5-mysql, mysql-client, sudo, postfix | mail-transport-agent, apache2 | nginx, adduser, ucf Recommends: mysql-server, rsync Suggests: drush-make +Conflicts: aegir-provision +Replaces: aegir-provision Description: mass Drupal hosting system - backend A set of contributed modules for Drupal that aims to solve the problem of managing a large number of Drupal sites. It does this by @@ -27,10 +29,12 @@ Description: mass Drupal hosting system - backend files. It can be installed standalone although it is usually installed with the hostmaster frontend. -Package: aegir-hostmaster +Package: aegir-hostmaster2 Architecture: all -Depends: ${misc:Depends}, drush (>= 5.5), php5-mysql, apache2 | nginx, libapache2-mod-php5 | php5-fpm, aegir-provision (>= ${source:Version}), git-core, unzip, lsb-base (>= 3.0-6) +Depends: ${misc:Depends}, drush (>= 5.5), php5-mysql, apache2 | nginx, libapache2-mod-php5 | php5-fpm, aegir-provision2 (>= ${source:Version}), git-core, unzip, lsb-base (>= 3.0-6) Recommends: php5-gd, php5 +Conflicts: aegir-hostmaster +Replaces: aegir-hostmaster Description: mass Drupal hosting system - frontend A set of contributed modules for Drupal that aims to solve the problem of managing a large number of Drupal sites. It does this by @@ -47,9 +51,11 @@ Description: mass Drupal hosting system - frontend and provision and as such doesn't bundle any files itself. Everything is downloaded on the fly during the install. -Package: aegir +Package: aegir2 Architecture: all -Depends: ${misc:Depends}, aegir-provision (>= ${source:Version}), aegir-hostmaster (>= ${source:Version}) +Depends: ${misc:Depends}, aegir-provision2 (>= ${source:Version}), aegir-hostmaster2 (>= ${source:Version}) +Conflicts: aegir +Replaces: aegir Description: mass Drupal hosting system A set of contributed modules for Drupal that aims to solve the problem of managing a large number of Drupal sites. It does this by @@ -61,10 +67,12 @@ Description: mass Drupal hosting system This meta-package will install both the frontend (aegir-hostmaster) and the backend (aegir-provision). -Package: aegir-cluster-slave +Package: aegir-cluster-slave2 Architecture: all Depends: ${misc:Depends}, php5-mysql, sudo, apache2, adduser, ucf, libapache2-mod-php5, rsync, nfs-client, mysql-client Recommends: php5-gd, php5 +Conflicts: aegir-cluster-slave +Replaces: aegir-cluster-slave Description: web frontend for the Aegir hosting system Configuration of lightweight slave servers for the Aegir "pack" clustering system. diff --git a/debian/rules b/debian/rules index dd5fe27d81f4884aaacfa59f860779db975d9338..dfe4012cf32276b81111d8fd063adebfbe5a2f3e 100755 --- a/debian/rules +++ b/debian/rules @@ -8,13 +8,13 @@ dh $@ override_dh_install: - cp -r "$(CURDIR)/db/" "$(CURDIR)/dns/" "$(CURDIR)/http/" "$(CURDIR)/aegir.make" "$(CURDIR)/platform/" "$(CURDIR)/Provision/" "$(CURDIR)/Symfony/" "$(CURDIR)"/*.inc "$(CURDIR)"/*.php "$(CURDIR)"/*.info "$(CURDIR)/debian/aegir-provision/usr/share/drush/commands/provision/" + cp -r "$(CURDIR)/db/" "$(CURDIR)/dns/" "$(CURDIR)/http/" "$(CURDIR)/aegir.make" "$(CURDIR)/platform/" "$(CURDIR)/Provision/" "$(CURDIR)/Symfony/" "$(CURDIR)"/*.inc "$(CURDIR)"/*.php "$(CURDIR)"/*.info "$(CURDIR)/debian/aegir-provision2/usr/share/drush/commands/provision/" # We need this nasty hack, because we added a directory. # TODO: this is really lame, there must be a better way to do this? - if [ -d "$(CURDIR)/provision-tests" ]; then cp -r "$(CURDIR)/provision-tests/" "$(CURDIR)/debian/aegir-provision/usr/share/drush/commands/provision/"; fi + if [ -d "$(CURDIR)/provision-tests" ]; then cp -r "$(CURDIR)/provision-tests/" "$(CURDIR)/debian/aegir-provision2/usr/share/drush/commands/provision/"; fi - cp "$(CURDIR)/debian/aegir-provision.lintian" "$(CURDIR)/debian/aegir-provision/usr/share/lintian/overrides/aegir-provision" + cp "$(CURDIR)/debian/aegir-provision2.lintian" "$(CURDIR)/debian/aegir-provision2/usr/share/lintian/overrides/aegir-provision" override_dh_installinit: dh_installinit --name=hosting-queued @@ -27,14 +27,24 @@ KEY?="-kjenkins@$(DOMAIN)" jenkins-build-official: git-buildpackage -b --git-upstream-branch=origin/upstream --git-debian-branch=origin/debian --git-ignore-branch -kjenkins@ci.aegirproject.org -version=2.0~$(shell git log -n 1 --oneline | sed 's/ .*$$//') +# the version from the changelog, add the git hash +version=$(shell sed -ne 's/^[^(]*(\([^)]*\)).*/\1/;1p' debian/changelog) +commit=$(shell git log -n 1 --oneline | sed 's/ .*$$//') + +# the version we're building with jenkins +jenkins_version=${version}+${BUILD_NUMBER}.${commit} + +# debug for the above +show-version: + @echo ${version} # this builds a debian package but first updates the branches to follow the latest 2.x branch # this assumes you are on a "debian" branch (of course) jenkins-build-auto: - dch -D unstable -v ${version} "automatic jenkins build ${BUILD_TAG}" + dch -D unstable -v ${jenkins_version} "automatic jenkins build ${BUILD_TAG} for commit ${commit}" git commit -m"dummy commit for jenkins ${BUILD_TAG} autobuild" debian/changelog git-buildpackage -b ${KEY} -show-version: - @echo ${version} +# helper to debug the above +show-jenkins-build-auto: + @echo would build version ${jenkins_version} with key ${KEY} diff --git a/dns/Provision/Config/Dns.php b/dns/Provision/Config/Dns.php index 83cd3aeef0634ca6d812c5a98ac5c242665f1b7e..76081393ab4afcb565575fce7395bc05b329f7d1 100644 --- a/dns/Provision/Config/Dns.php +++ b/dns/Provision/Config/Dns.php @@ -11,7 +11,8 @@ class Provision_Config_Dns extends Provision_Config { } function unlink() { - parent::unlink(); + $result = parent::unlink(); $this->data['server']->sync($this->filename()); + return $result; } } diff --git a/dns/Provision/Config/Dnsmasq/host.tpl.php b/dns/Provision/Config/Dnsmasq/host.tpl.php index 93effe3df2b40e13a81af546364d2c420530d632..f9004d104f6a2f33c1faa4f226b5d47a7ca420ff 100644 --- a/dns/Provision/Config/Dnsmasq/host.tpl.php +++ b/dns/Provision/Config/Dnsmasq/host.tpl.php @@ -1,5 +1,5 @@ $ip) { +foreach ($ip_addresses as $server => $ip) { print "{$ip}\t {$this->uri}\n"; } ?> diff --git a/dns/Provision/Service/dns.php b/dns/Provision/Service/dns.php index 8567a6b295403f5ce95539d127361d7f98e19f78..b95f2e550721a1ec5b794ca9095c851906f80dac 100644 --- a/dns/Provision/Service/dns.php +++ b/dns/Provision/Service/dns.php @@ -136,7 +136,13 @@ class Provision_Service_dns extends Provision_Service { } if ($config == 'host') { - $data['site_ip_addresses'] = drush_get_option('site_ip_addresses', array(), 'site'); + // get the IP explicitely allocate to this site + $ips = drush_get_option('ip_address', array(), 'site'); + // .. or the server IPs if none is allocated + if (count($ips) < 1) { + $ips = $this->server->ip_addresses; + } + $data['ip_address'] = $ips; } return $data; @@ -244,7 +250,7 @@ class Provision_Service_dns extends Provision_Service { return $status; } - /** + /** * Create a host in DNS. * * This can do a lot of things, create a zonefile, add a record to a @@ -270,18 +276,13 @@ class Provision_Service_dns extends Provision_Service { return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create"); } - $ips = drush_get_option('site_ip_addresses', array(), 'site'); + $ips = drush_get_option('ip_address', array(), 'site'); if (!$ips && count($ips) < 1) { drush_log(dt("no IP found for server, trying loopback")); $ips = array('127.0.0.1'); } - // XXX: kill me? - if (!is_array($ips)) { - $ips = array($ips); // backward compatibility? - } - $this->config('zone', $zone)->record_set($sub, array('A' => $ips)); foreach ($aliases as $alias) { if ($this->guess_zone($alias) == $zone) { diff --git a/http/Provision/Config/Http/Site.php b/http/Provision/Config/Http/Site.php index cd992a9e17960951075838a4f6926b8d3d0e2468..3b59ad1eb6f3ccb2202c42f32f3b40f309597562 100644 --- a/http/Provision/Config/Http/Site.php +++ b/http/Provision/Config/Http/Site.php @@ -14,32 +14,6 @@ class Provision_Config_Http_Site extends Provision_Config_Http { return $this->data['http_vhostd_path'] . '/' . $this->uri; } - function write() { - parent::write(); - - // We also leave a record of this IP in the site's drushrc.php - // This way we can pass the info back to the front end. - $ip_addresses = drush_get_option('site_ip_addresses', array(), 'site'); - - if ($this->data['ip_address'] != '*') { - $ip_addresses[$this->data['server']->name] = $this->data['ip_address']; - } - elseif (isset($context['site_ip_addresses'][$this->data['server']->name])) { - unset($ip_addresses[$this->data['server']->name]); - } - drush_set_option('site_ip_addresses', $ip_addresses, 'site'); - } - - function unlink() { - parent::unlink(); - - // We also remove the record of this IP in the site's drushrc.php - // This way we can pass the info back to the front end. - $ip_addresses = drush_get_option('site_ip_addresses', array(), 'site'); - unset($ip_addresses[$this->data['server']->name]); - drush_set_option('site_ip_addresses', $ip_addresses, 'site'); - } - function process() { parent::process(); diff --git a/http/Provision/Config/Http/Ssl/Site.php b/http/Provision/Config/Http/Ssl/Site.php index 13086bcaba0212b8a0a7d35cca52294baa09392e..7d4aa98e03e2a2770ac5e8b7523e7746256a1e4d 100644 --- a/http/Provision/Config/Http/Ssl/Site.php +++ b/http/Provision/Config/Http/Ssl/Site.php @@ -15,7 +15,6 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site { function write() { parent::write(); - $ip_addresses = drush_get_option('site_ip_addresses', array(), 'site'); if ($this->ssl_enabled && $this->ssl_key) { $path = dirname($this->data['ssl_cert']); // Make sure the ssl.d directory in the server ssl.d exists. @@ -26,7 +25,9 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site { )), 0700); // Touch a file in the server's copy of this key, so that it knows the key is in use. - touch("{$path}/{$this->uri}.receipt"); + // XXX: test. data structure may not be sound. try d($this->uri) + // if $this fails + Provision_Service_http_ssl::assign_certificate_site($this->ssl_key, $this); // Copy the certificates to the server's ssl.d directory. provision_file()->copy( @@ -49,10 +50,9 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site { 'exclude' => "{$path}/*.receipt", // Don't need to synch the receipts )); } - elseif ($ip = $ip_addresses[$this->data['server']->name]) { - if ($ssl_key = Provision_Service_http_ssl::get_ip_certificate($ip, $this->data['server'])) { - $this->clear_certs($ssl_key); - } + else { + // XXX: to be tested, not sure the data structure is sound + Provision_Service_http_ssl::free_certificate_site($this->ssl_key, $this); } } @@ -62,45 +62,18 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site { function unlink() { parent::unlink(); - $ip_addresses = drush_get_option('site_ip_addresses', array(), 'site'); - - if ($this->ssl_enabled && $this->ssl_key) { - $this->clear_certs($this->ssl_key); - } - elseif ($ip = $ip_addresses[$this->data['server']->name]) { - if ($ssl_key = Provision_Service_http_ssl::get_ip_certificate($ip, $this->data['server'])) { - $this->clear_certs($ssl_key); - } - } - + // XXX: to be tested, not sure the data structure is sound + Provision_Service_http_ssl::free_certificate_site($this->ssl_key, $this); } /** * Small utility function to stop code duplication. + * + * @deprecated unused + * @see Provision_Service_http_ssl::free_certificate_site() */ - private function clear_certs($ssl_key) { - $path = $this->data['server']->http_ssld_path . "/$ssl_key"; - - // Remove the file system reciept we left for this file - provision_file()->unlink("{$path}/{$this->uri}.receipt")-> - succeed(dt("Deleted SSL Certificate association stub for %site on %server", array( - '%site' => $this->uri, - '%server' => $this->data['server']->remote_host))); - - $used = Provision_Service_http_ssl::certificate_in_use($ssl_key, $this->data['server']); - - if (!$used) { - // we can remove the certificate from the server ssl.d directory. - _provision_recursive_delete($path); - // remove the file from the remote server too. - $this->data['server']->sync($path); - - // Most importantly, we remove the hold this cert had on the IP address. - Provision_Service_http_ssl::free_certificate_ip($ssl_key, $this->data['server']); - } + return FALSE; } - - } diff --git a/http/Provision/Service/http/ssl.php b/http/Provision/Service/http/ssl.php index 61f9371a1a440b187811192ec81004f94e3550d0..03f39773a0d17222d1f3c620ca7077f6633b0b2b 100644 --- a/http/Provision/Service/http/ssl.php +++ b/http/Provision/Service/http/ssl.php @@ -38,6 +38,7 @@ class Provision_Service_http_ssl extends Provision_Service_http_public { $this->context->setProperty('ssl_enabled', 0); $this->context->setProperty('ssl_key', NULL); + $this->context->setProperty('ip_address', '*'); } @@ -55,23 +56,8 @@ class Provision_Service_http_ssl extends Provision_Service_http_public { if ($ssl_key = $this->context->ssl_key) { // Retrieve the paths to the cert and key files. // they are generated if not found. - $certs = $this->get_certificates($ssl_key); $data = array_merge($data, $certs); - - // assign ip address based on ssl_key - $ip = Provision_Service_http_ssl::assign_certificate_ip($ssl_key, $this->server); - - if (!$ip) { - drush_set_error("SSL_IP_FAILURE", dt("There are no more IP addresses available on %server for the %ssl_key certificate.", array( - "%server" => $this->server->remote_host, - "%ssl_key" => $ssl_key, - ))); - } - else { - $data['ip_address'] = $ip; - - } } } @@ -148,6 +134,51 @@ class Provision_Service_http_ssl extends Provision_Service_http_public { } } + /** + * Assign the given site to a certificate to mark its usage. + * + * This is necessary for the backend to figure out when it's okay to + * remove certificates. + * + * Should never fail unless the receipt file cannot be created. + * + * @return the path to the receipt file if allocation succeeded + */ + static function assign_certificate_site($ssl_key, $site) { + $path = $site->platform->server->http_ssld_path . "/" . $ssl_key . "/" . $site->uri . ".receipt"; + drush_log(dt("registering site %site with SSL certificate %key with receipt file %path", array("%site" => $site->uri, "%key" => $ssl_key, "%path" => $path))); + if (touch($path)) { + return $path; + } + else { + return FALSE; + } + } + + /** + * Unallocate this certificate from that site. + * + * @return the path to the receipt file if removal was successful + */ + static function free_certificate_site($ssl_key, $site) { + $ssl_dir = $site->platform->server->http_ssld_path . "/" . $ssl_key . "/"; + // Remove the file system reciept we left for this file + if (provision_file()->unlink($ssl_dir . $site->uri . ".receipt")-> + succeed(dt("Deleted SSL Certificate association receipt for %site on %server", array( + '%site' => $site->uri, + '%server' => $site->server->remote_host)))->status()) { + if (!Provision_Service_http_ssl::certificate_in_use($ssl_key, $site->server)) { + drush_log(dt("Deleting unused SSL directory: %dir", array('%dir' => $ssl_dir))); + _provision_recursive_delete($ssl_dir); + $site->server->sync($path); + } + return $path; + } + else { + return FALSE; + } + } + /** * Assign the certificate it's own distinct IP address for this server. * @@ -156,51 +187,26 @@ class Provision_Service_http_ssl extends Provision_Service_http_public { * * This code uses the filesystem by touching a reciept file in the * server's ssl.d directory. + * + * @deprecated this is now based the site URI + * @see assign_certificate_site() */ static function assign_certificate_ip($ssl_key, $server) { - $path = $server->http_ssld_path; - - $pattern = "{$path}/{$ssl_key}__*.receipt"; - $files = glob($pattern); - if (sizeof($files) == 1) { - $pattern = "/^{$ssl_key}__(.*)\.receipt$/"; - preg_match($pattern, basename($files[0]), $matches); - if (in_array($matches[1], $server->ip_addresses)) { - // Return an existing match. - return $matches[1]; - } - - // This is a stale match, remove it. - // Any sites using it will either find a new - // IP on the next verify task, or fail. - unlink($files[0]); - } - - // try to assign one - foreach ($server->ip_addresses as $ip) { - if (!Provision_Service_http_ssl::get_ip_certificate($ip, $server)) { - touch("{$path}/{$ssl_key}__{$ip}.receipt"); - return $ip; - } - } - - return FALSE; // generate error + return FALSE; } - /** * Remove the certificate's lock on the server's public IP. * * This function will delete the receipt file left behind by * the assign_certificate_ip script, allowing the IP to be used * by other certificates. + * + * @deprecated this is now based on the site URI + * @see free_certificate_site() */ static function free_certificate_ip($ssl_key, $server) { - $ip = Provision_Service_http_ssl::assign_certificate_ip($ssl_key, $server); - $file = "{$server->http_ssld_path}/{$ssl_key}__{$ip}.receipt"; - if (file_exists($file)) { - unlink($file); - } + return FALSE; } @@ -222,18 +228,10 @@ class Provision_Service_http_ssl extends Provision_Service_http_public { /** * Check for an existing record for this IP address. + * + * @deprecated we only use the URI-based allocation now */ static function get_ip_certificate($ip, $server) { - $path = $server->http_ssld_path; - - $pattern = "{$path}/*__{$ip}.receipt"; - $files = glob($pattern); - if (sizeof($files) == 1) { - $pattern = "/^(.*)__{$ip}\.receipt$/"; - preg_match($pattern, basename($files[0]), $matches); - return $matches[1]; - } - return FALSE; } diff --git a/http/delete.provision.inc b/http/delete.provision.inc index 22260ee81ebd7a90b0acbff968e9be77db4f6304..c5b5f1d16239fd16f641893d005b94523f66d0b8 100644 --- a/http/delete.provision.inc +++ b/http/delete.provision.inc @@ -2,14 +2,18 @@ function drush_http_provision_delete() { if (d()->type === 'site') { - d()->service('http')->delete_config('site'); + d()->service('http')->delete_config('site') + ->succeed('Deleted platform configuration file', 'success') + ->fail('Failed to delete platform configuration file', 'DRUSH_PERM_ERROR'); } if (d()->type === 'platform') { if (!drush_get_option('force', FALSE) && drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_ROOT) && provision_drupal_find_sites()) { drush_set_error(dt('Existing sites were found on this platform. These sites will need to be deleted before this platform can be deleted.')); } else { - d()->service('http')->delete_config('platform'); + d()->service('http')->delete_config('platform') + ->succeed('Deleted platform configuration file', 'success') + ->fail('Failed to delete platform configuration file', 'DRUSH_PERM_ERROR'); } } d()->service('http')->parse_configs(); diff --git a/install.hostmaster.inc b/install.hostmaster.inc index b5b81bab96c1a99c72541bc73be937334526748b..e349b719313ac0f2dfd351c9a8d3900c03a4af64 100644 --- a/install.hostmaster.inc +++ b/install.hostmaster.inc @@ -98,7 +98,7 @@ The following settings will be used: ))); if (!drush_confirm(dt('Do you really want to proceed with the install'))) { - return drush_set_error('PROVISION_CANCEL_INSTALL', dt('Installation aborted by user')); + return drush_set_error('PROVISION_CANCEL_INSTALL', dt('Installation aborted')); } return TRUE; diff --git a/migrate.hostmaster.inc b/migrate.hostmaster.inc index 5628cbd24f71f9fc42d67087e6791534103e908b..13a5393ee6e0567f931bdda3eb17df8d1d76bc5b 100644 --- a/migrate.hostmaster.inc +++ b/migrate.hostmaster.inc @@ -148,8 +148,6 @@ We are making the following assumptions: function drush_provision_pre_hostmaster_migrate($site, $platform) { // wipe out cron entry exec('crontab -r'); - // we can't rely on update.php to run that because it will run too late. this can be removed in 0.5 and above - provision_backend_invoke(drush_get_option('site_name'), 'sqlq', array("UPDATE {system} SET weight = 0 WHERE type='module' AND name='hosting';")); } function drush_provision_hostmaster_migrate($site, $platform) { diff --git a/platform/backup.provision.inc b/platform/backup.provision.inc index 2e94eb08c8fd256922cab16debcf01cffa7491de..1698f0e53a650f4077c80c07c2c89d7fe853030d 100644 --- a/platform/backup.provision.inc +++ b/platform/backup.provision.inc @@ -39,6 +39,7 @@ function drush_provision_drupal_provision_backup_validate($backup_file = NULL) { $suggested = d()->platform->server->backup_path . '/' . d()->uri . '-' . date("Ymd.His", time()) . '.tar.gz'; // Use format of mysite.com-2008-01-02, if already existing, add number. + $count = 0; while (is_file($suggested)) { $count++; $suggested = d()->platform->server->backup_path . '/' . d()->uri . '-' . date('Ymd.His', time()) . '_' . $count . '.tar.gz'; @@ -87,7 +88,7 @@ function drush_provision_drupal_provision_backup() { } if (substr($backup_file, -2) == 'gz') { // same as above: some do not support -z - $command = 'tar cpf - . | gzip --rsyncable -c > %s'; + $command = 'tar cpf - . | gzip -c > %s'; } else { $command = 'tar cpf %s .'; } diff --git a/platform/delete.provision.inc b/platform/delete.provision.inc index 4bdbc2e6536e1a08abb0696bed22be05ef6dc63f..b6f24b5f0ff3e9bbd1d3665b0042242bfc0ee4c4 100644 --- a/platform/delete.provision.inc +++ b/platform/delete.provision.inc @@ -19,6 +19,12 @@ function drush_provision_drupal_pre_provision_delete($backup_file = NULL) { function drush_provision_drupal_provision_delete() { if (d()->type === 'site') { drush_bootstrap(DRUSH_BOOTSTRAP_DRUPAL_ROOT); + + drush_invoke_process('@none', 'provision-save', array(d()->name), array('delete' => TRUE)); + + // Do not automatically save the drushrc at the end of the command. + drush_set_option('provision_save_config', false); + _provision_recursive_delete(d()->site_path); // we remove the aliases even if redirection is enabled as a precaution // if redirection is enabled, keep silent about errors diff --git a/platform/drupal/install_5.inc b/platform/drupal/install_5.inc index fd6157368eb4b6a1f4c52ad88c8e7518ca568d3e..cb5989a387449c9d81bb08c22c2d28987cb653e0 100644 --- a/platform/drupal/install_5.inc +++ b/platform/drupal/install_5.inc @@ -192,8 +192,8 @@ function install_main() { $account = install_create_admin_user($client_email); $onetime = user_pass_reset_url($account); // Store the one time login link in an option so the front end can direct the user to their new site. - drush_set_option('login_link', $onetime); - drush_log(t('Login url: !onetime', array('!onetime' => $onetime)), 'message'); + drush_set_option('login_link', $onetime . '/login'); + drush_log(t('Login url: !onetime', array('!onetime' => $onetime . '/login')), 'message'); if ($client_email) { install_send_welcome_mail($url, $account, $profile, $install_locale, $client_email, $onetime); diff --git a/platform/drupal/install_6.inc b/platform/drupal/install_6.inc index 06e0db9b555ac878a7720885f98bcc7c27d87c44..c2d90b8f0f0208598e4b9dc2cc3e87fea61507fb 100644 --- a/platform/drupal/install_6.inc +++ b/platform/drupal/install_6.inc @@ -353,8 +353,8 @@ function install_main() { $account = install_create_admin_user($client_email); $onetime = user_pass_reset_url($account); // Store the one time login link in an option so the front end can direct the user to their new site. - drush_set_option('login_link', $onetime); - drush_log(t('Login url: !onetime', array('!onetime' => $onetime)), 'message'); + drush_set_option('login_link', $onetime . '/login'); + drush_log(t('Login url: !onetime', array('!onetime' => $onetime . '/login')), 'message'); if ($client_email) { install_send_welcome_mail($url, $account, $profile, $install_locale, $client_email, $onetime); diff --git a/platform/drupal/install_7.inc b/platform/drupal/install_7.inc index 9c49c7858b41c7deaaaa6d281653f32ea7dae2be..26da8a8ebde84493935651c67ef308807429d781 100644 --- a/platform/drupal/install_7.inc +++ b/platform/drupal/install_7.inc @@ -157,8 +157,8 @@ function install_main() { $onetime = user_pass_reset_url($account); // Store the one time login link in an option so the front end can direct the user to their new site. - drush_set_option('login_link', $onetime); - drush_log(t('Login url: !onetime', array('!onetime' => $onetime)), 'message'); + drush_set_option('login_link', $onetime . '/login'); + drush_log(t('Login url: !onetime', array('!onetime' => $onetime . '/login')), 'message'); if ($client_email) { install_send_welcome_mail($url, $account, $install_locale, $client_email, $onetime); diff --git a/platform/install.provision.inc b/platform/install.provision.inc index b084901359fcec2944427b511c5e3287db3d1fc3..e0f56ae8e50188a6ba6926163f0dff3c046ff863 100644 --- a/platform/install.provision.inc +++ b/platform/install.provision.inc @@ -36,6 +36,7 @@ function drush_provision_drupal_pre_provision_install() { */ function drush_provision_drupal_pre_provision_install_rollback() { _provision_recursive_delete( d()->site_path ); + drush_invoke_process('@none', 'provision-save', array(d()->name), array('delete' => TRUE)); } diff --git a/platform/provision_drupal.drush.inc b/platform/provision_drupal.drush.inc index c5067749a722f134bbabc0d25ea0e409e4758e87..9828545de20e8ebe3d800aea2f7f1df59e79c6ac 100644 --- a/platform/provision_drupal.drush.inc +++ b/platform/provision_drupal.drush.inc @@ -788,6 +788,7 @@ function provision_reload_config($context, $file = NULL) { if (file_exists($file)) { drush_log("Reloading $context drushrc.php from $file"); include($file); + // $options will be defined by the config file included above. if (sizeof($options)) { $options = array_merge(drush_get_context($context, array()), $options); drush_set_context($context, $options); @@ -809,13 +810,44 @@ function _provision_client_create_symlink() { if (d()->client_name) { $sites_dir = d()->server->clients_path . '/' . d()->client_name; provision_file()->create_dir($sites_dir, dt('Client home directory for @client', array('@client' => d()->client_name)), 0751); - provision_file()->unlink($sites_dir . '/' . d()->uri); // deliberatly ignore errors + _provision_client_delete_old_symlink(); provision_file()->symlink(d()->site_path, $sites_dir . '/' . d()->uri) ->succeed('Created symlink @path to @target') ->fail('Could not create symlink @path to @target: @reason'); } } +/** + * Delete dangling symlinks for this site. + * + * This is a crude implementation, as we do not have the old client name so we + * need to iterate over the directories. We only remove the first entry we + * find to save some I/O. + */ +function _provision_client_delete_old_symlink() { + $previous = d()->server->clients_path . '/' . d()->client_name . '/' . d()->uri; + // this is necessary because unlink doesn't fail on missing files (!) + $found = (file_exists($previous) || is_link($previous)); + provision_file()->unlink($previous); + if (!$found) { + drush_log(dt("couldn't find previous client symlink, iterating through all sites")); + // only iterate if the symlink location changed + if ($dh = @opendir(d()->server->clients_path)) { + while (($file = readdir($dh)) !== false) { + if ($file != '.' && $file != '..') { + $path = d()->server->clients_path . '/' . $file . '/' . d()->uri; + if (file_exists($path) || is_link($path)) { + provision_file()->unlink($path); + drush_log(dt("removed previous symlink in @path", array("@path" => $path)), 'success'); + break; // found it + } + } + } + closedir($dh); + } + } +} + /** * Delete the site symlink within the client directory * diff --git a/platform/reset.login.provision.inc b/platform/reset.login.provision.inc index d1b31e8d7aa795af8ae30394f5c2ba5ee364a37d..910b7c1969cf60109d36160c504e3c9efd0ec0fb 100644 --- a/platform/reset.login.provision.inc +++ b/platform/reset.login.provision.inc @@ -26,7 +26,7 @@ function drush_provision_drupal_provision_login_reset() { if (empty($account)) { return drush_set_error('PROVISION_UNABLE_TO_LOAD_UID_1', 'Could not load the admin user with uid 1 on this site.'); } - $onetime = user_pass_reset_url($account); + $onetime = user_pass_reset_url($account) . '/login'; // pass the login link to the front end drush_set_option('login_link', $onetime); drush_log(t('Login url: !onetime', array('!onetime' => $onetime)), 'message'); diff --git a/provision-tests/provision_tests.drush.inc b/provision-tests/provision_tests.drush.inc index f123b46e2a10288fe31af304ddd89f15effc88d3..cba85eb7106c4802647d7e007dddb1497183e90b 100644 --- a/provision-tests/provision_tests.drush.inc +++ b/provision-tests/provision_tests.drush.inc @@ -236,7 +236,6 @@ function drush_provision_tests_en_module_on_site($module, $site) { drush_provision_tests_run_remaining_tasks(); } - /** * Helper function to change the data directory */ diff --git a/provision.api.php b/provision.api.php index 54881fda61ec86aa3f03aa6800b94e70a0a31df7..bef823e460d21e564d4cd967a0e949ad2f8fb410 100644 --- a/provision.api.php +++ b/provision.api.php @@ -90,3 +90,36 @@ function drush_hook_provision_apache_dir_config($data) { */ function drush_hook_provision_apache_vhost_config($uri, $data) { } + +/** + * Specify a different template for rendering a config file. + * + * @param $config + * The Provision_config object trying to find its template. + * + * @return + * A filename of a template to use for rendering. + * + * @see hook_provision_config_load_templates_alter() + */ +function hook_provision_config_load_templates($config) { + if (is_a($config, 'Provision_Config_Drupal_Settings')) { + $file = dirname(__FILE__) . '/custom-php-settings.tpl.php'; + return $file; + } +} + +/** + * Alter the templates suggested for rendering a config file. + * + * @param $templates + * The array of templates suggested by other Drush commands. + * @param $config + * The Provision_config object trying to find its template. + * + * @see hook_provision_config_load_templates() + */ +function hook_provision_config_load_templates_alter(&$templates, $config) { + // Don't let any custom templates be used. + $templates = array(); +} diff --git a/provision.drush.inc b/provision.drush.inc index 3a6832eaf7aa494f5553917c1d9defea980b2481..36d1e034b7d2fd878877d36893ea578be32b4a86 100644 --- a/provision.drush.inc +++ b/provision.drush.inc @@ -248,7 +248,8 @@ function provision_drush_command() { '/path/to/platform' => dt('The platform to migrate the site to.'), ), 'options' => array( - 'makefile' => dt('The optional makefile to use instead of aegir.') + 'http_service_type' => dt('Webserver type to configure (default: %webserver)', array('%webserver' => 'apache')), + 'makefile' => dt('The makefile used to create the hostmaster platform (default: %makefile)', array('%makefile' => dirname(__FILE__). '/aegir.make')), ), ); @@ -278,6 +279,15 @@ function provision_drush_command() { ), ); + $items['hostmaster-uninstall'] = array( + 'description' => dt('Uninstall the Hostmaster frontend.'), + 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE, + 'options' => array + ( + 'all' => dt('Destroy *ALL* sites managed by the Aegir frontend'), + ), + ); + $items['backend-parse'] = array( 'description' => dt('Parse the output of --backend commands to a human readable form'), 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, diff --git a/provision.inc b/provision.inc index 6aad782b41559fc0f8e7c49dbf1ea7d317b8fcda..18f4e451b7b648245e2d1595672a1386dc697e64 100644 --- a/provision.inc +++ b/provision.inc @@ -207,14 +207,16 @@ function _provision_recursive_delete($path) { // is_dir() follows symlinks, so it can return true on a symlink if (is_dir($path) && !is_link($path)) { $d = dir($path); - while (($entry = $d->read()) !== FALSE) { - if ($entry == '.' || $entry == '..') { - continue; + if (!empty($d)) { + while (($entry = $d->read()) !== FALSE) { + if ($entry == '.' || $entry == '..') { + continue; + } + $entry_path = $path . '/' . $entry; + $ret &= _provision_recursive_delete($entry_path); } - $entry_path = $path . '/' . $entry; - $ret &= _provision_recursive_delete($entry_path); + $d->close(); } - $d->close(); $rm = provision_file()->rmdir($path) ->succeed('Deleting @path directory successful.') @@ -417,285 +419,6 @@ function provision_backend_invoke($target, $command, $arguments = array(), $data return drush_invoke_process($context, $command, $arguments, $data, array('method' => $mode, 'integrate' => TRUE, 'dispatch-using-alias' => TRUE)); } -/** - * Invoke a command in a new process, targeting the site specified by - * the provided site alias record. - * - * Use this function instead of drush_backend_invoke_sitealias, - * drush_backend_invoke_args, or drush_backend_invoke_command - * (all obsolete in drush 5). - * - * @param array $site_alias_record - * The site record to execute the command on. Use '@self' to run on the current site. - * @param string $command_name - * The command to invoke. - * @param array $commandline_args - * The arguments to pass to the command. - * @param array $commandline_options - * The options (e.g. --select) to provide to the command. - * @param $backend_options - * - TRUE - integrate errors - * - FALSE - do not integrate errors - * - array - @see drush_backend_invoke_concurrent - * There are also several options that _only_ work when set in - * this parameter. They include: - * - 'invoke-multiple' - * If $site_alias_record represents a single site, then 'invoke-multiple' - * will cause the _same_ command with the _same_ arguments and options - * to be invoked concurrently (e.g. for running concurrent batch processes). - * - 'concurrency' - * Limits the number of concurrent processes that will run at the same time. - * Defaults to '4'. - * - 'override-simulated' - * Forces the command to run, even in 'simulated' mode. Useful for - * commands that do not change any state on the machine, e.g. to fetch - * database information for sql-sync via sql-conf. - * - 'interactive' - * Overrides the backend invoke process to run commands interactively. - * - 'fork' - * Overrides the backend invoke process to run non blocking commands in - * the background. Forks a new process by adding a '&' at the end of the - * command. The calling process does not receive any output from the child - * process. The fork option is used to spawn a process that outlives its - * parent. - * - * @return - * If the command could not be completed successfully, FALSE. - * If the command was completed, this will return an associative - * array containing the results of the API call. - * @see drush_backend_get_result() - * - * Do not change the signature of this function! drush_invoke_process - * is one of the key Drush APIs. See http://drupal.org/node/1152908 - */ -function _provision__drush_invoke_process($site_alias_record, $command_name, $commandline_args = array(), $commandline_options = array(), $backend_options = FALSE) { - if (is_array($site_alias_record) && array_key_exists('site-list', $site_alias_record)) { - $site_alias_records = drush_sitealias_resolve_sitespecs($site_alias_record['site-list']); - $site_alias_records = drush_sitealias_simplify_names($site_alias_records); - foreach ($site_alias_records as $alias_name => $alias_record) { - $invocations[] = array( - 'site' => $alias_record, - 'command' => $command_name, - 'args' => $commandline_args, - ); - } - } - else { - $invocations[] = array( - 'site' => $site_alias_record, - 'command' => $command_name, - 'args' => $commandline_args); - $invoke_multiple = drush_get_option_override($backend_options, 'invoke-multiple', 0); - if ($invoke_multiple) { - $invocations = array_fill(0, $invoke_multiple, $invocations[0]); - } - } - return _provison__drush_backend_invoke_concurrent($invocations, $commandline_options, $backend_options); -} - -/** - * Execute a new local or remote command in a new process. - * - * n.b. Prefer drush_invoke_process() to this function. - * - * @param invocations - * An array of command records to exacute. Each record should contain: - * - 'site': - * An array containing information used to generate the command. - * - 'remote-host' - * Optional. A remote host to execute the drush command on. - * - 'remote-user' - * Optional. Defaults to the current user. If you specify this, you can choose which module to send. - * - 'ssh-options' - * Optional. Defaults to "-o PasswordAuthentication=no" - * - 'path-aliases' - * Optional; contains paths to folders and executables useful to the command. - * - '%drush-script' - * Optional. Defaults to the current drush.php file on the local machine, and - * to simply 'drush' (the drush script in the current PATH) on remote servers. - * You may also specify a different drush.php script explicitly. You will need - * to set this when calling drush on a remote server if 'drush' is not in the - * PATH on that machine. - * - 'command': - * A defined drush command such as 'cron', 'status' or any of the available ones such as 'drush pm'. - * - 'args': - * An array of arguments for the command. - * - 'options' - * Optional. An array containing options to pass to the remote script. - * Array items with a numeric key are treated as optional arguments to the - * command. - * - 'backend-options': - * Optional. Additional parameters that control the operation of the invoke. - * - 'method' - * Optional. Defaults to 'GET'. - * If this parameter is set to 'POST', the $data array will be passed - * to the script being called as a JSON encoded string over the STDIN - * pipe of that process. This is preferable if you have to pass - * sensitive data such as passwords and the like. - * For any other value, the $data array will be collapsed down into a - * set of command line options to the script. - * - 'integrate' - * Optional. Defaults to TRUE. - * If TRUE, any error statuses will be integrated into the current - * process. This might not be what you want, if you are writing a - * command that operates on multiple sites. - * - 'log' - * Optional. Defaults to TRUE. - * If TRUE, any log messages will be integrated into the current - * process. - * - 'output' - * Optional. Defaults to TRUE. - * If TRUE, output from the command will be synchronously printed to - * stdout. - * - 'drush-script' - * Optional. Defaults to the current drush.php file on the local - * machine, and to simply 'drush' (the drush script in the current - * PATH) on remote servers. You may also specify a different drush.php - * script explicitly. You will need to set this when calling drush on - * a remote server if 'drush' is not in the PATH on that machine. - * @param common_options - * Optional. Merged in with the options for each invocation. - * @param backend_options - * Optional. Merged in with the backend options for each invocation. - * @param default_command - * Optional. Used as the 'command' for any invocation that does not - * define a command explicitly. - * @param default_site - * Optional. Used as the 'site' for any invocation that does not - * define a site explicitly. - * @param context - * Optional. Passed in to proc_open if provided. - * - * @return - * If the command could not be completed successfully, FALSE. - * If the command was completed, this will return an associative array containing the data from drush_backend_output(). - */ -function _provison__drush_backend_invoke_concurrent($invocations, $common_options = array(), $common_backend_options = array(), $default_command = NULL, $default_site = NULL, $context = NULL) { - $index = 0; - - // Slice and dice our options in preparation to build a command string - $invocation_options = array(); - foreach ($invocations as $invocation) { - $site_record = isset($invocation['site']) ? $invocation['site'] : $default_site; - // NULL is a synonym to '@self', although the latter is preferred. - if (!isset($site_record)) { - $site_record = '@self'; - } - // If the first parameter is not a site alias record, - // then presume it is an alias name, and try to look up - // the alias record. - if (!is_array($site_record)) { - $site_record = drush_sitealias_get_record($site_record); - } - $command = isset($invocation['command']) ? $invocation['command'] : $default_command; - $args = isset($invocation['args']) ? $invocation['args'] : array(); - $command_options = isset($invocation['options']) ? $invocation['options'] : array(); - $backend_options = isset($invocation['backend-options']) ? $invocation['backend-options'] : array(); - // If $backend_options is passed in as a bool, interpret that as the value for 'integrate' - if (!is_array($common_backend_options)) { - $integrate = (bool)$common_backend_options; - $common_backend_options = array('integrate' => $integrate); - } - - $command_options += $common_options; - $backend_options += $common_backend_options; - - $backend_options = _drush_backend_adjust_options($site_record, $command, $command_options, $backend_options); - - // Insure that contexts such as DRUSH_SIMULATE and NO_COLOR are included. - $command_options += _drush_backend_get_global_contexts($site_record); - - if (isset($site_record['#name'])) { - list($post_options, $commandline_options, $drush_global_options) = _drush_backend_classify_options(array(), $command_options, $backend_options); - $command = '@' . ltrim($site_record['#name'], '@') . ' ' . $command; - } - else { - list($post_options, $commandline_options, $drush_global_options) = _drush_backend_classify_options($site_record, $command_options, $backend_options); - } - $site_record += array('path-aliases' => array()); - $site_record['path-aliases'] += array( - '%drush-script' => NULL, - ); - - $site = (array_key_exists('#name', $site_record) && !array_key_exists($site_record['#name'], $invocation_options)) ? $site_record['#name'] : $index++; - $invocation_options[$site] = array( - 'site-record' => $site_record, - 'command' => $command, - 'args' => $args, - 'post-options' => $post_options, - 'drush-global-options' => $drush_global_options, - 'commandline-options' => $commandline_options, - 'command-options' => $command_options, - 'backend-options' => $backend_options, - ); - } - - // Calculate the length of the longest output label - $max_name_length = 0; - $label_separator = ''; - if (!array_key_exists('no-label', $common_options) && (count($invocation_options) > 1)) { - $label_separator = array_key_exists('#label-separator', $common_options) ? $common_options['#label-separator'] : ' >> '; - foreach ($invocation_options as $site => $item) { - $backend_options = $item['backend-options']; - if (!array_key_exists('#output-label', $backend_options)) { - if (is_numeric($site)) { - $backend_options['#output-label'] = ' * [@self.' . $site; - $label_separator = '] '; - } - else { - $backend_options['#output-label'] = $site; - } - $invocation_options[$site]['backend-options']['#output-label'] = $backend_options['#output-label']; - } - $name_len = strlen($backend_options['#output-label']); - if ($name_len > $max_name_length) { - $max_name_length = $name_len; - } - if (array_key_exists('#label-separator', $backend_options)) { - $label_separator = $backend_options['#label-separator']; - } - } - } - // Now pad out the output labels and add the label separator. - $reserve_margin = $max_name_length + strlen($label_separator); - foreach ($invocation_options as $site => $item) { - $backend_options = $item['backend-options'] + array('#output-label' => ''); - $invocation_options[$site]['backend-options']['#output-label'] = str_pad($backend_options['#output-label'], $max_name_length, " ") . $label_separator; - if ($reserve_margin) { - $invocation_options[$site]['drush-global-options']['reserve-margin'] = $reserve_margin; - } - } - - // Now take our prepared options and generate the command strings - $cmds = array(); - foreach ($invocation_options as $site => $item) { - $site_record = $item['site-record']; - $command = $item['command']; - $args = $item['args']; - $post_options = $item['post-options']; - $commandline_options = $item['commandline-options']; - $command_options = $item['command-options']; - $drush_global_options = $item['drush-global-options']; - $backend_options = $item['backend-options']; - $os = drush_os($site_record); - // If the caller did not pass in a specific path to drush, then we will - // use a default value. For commands that are being executed on the same - // machine, we will use DRUSH_COMMAND, which is the path to the drush.php - // that is running right now. For remote commands, we will run a wrapper - // script instead of drush.php -- drush.bat on Windows, or drush on Linux. - $drush_path = $site_record['path-aliases']['%drush-script']; - $drush_command_path = drush_build_drush_command($drush_path, array_key_exists('php', $command_options) ? $command_options['php'] : NULL, $os, array_key_exists('remote-host', $site_record)); - $cmd = _drush_backend_generate_command($site_record, $drush_command_path . " " . _drush_backend_argument_string($drush_global_options, $os) . " " . $command, $args, $commandline_options, $backend_options) . ' 2>&1'; - $cmds[$site] = array( - 'cmd' => $cmd, - 'post-options' => $post_options, - 'backend-options' => $backend_options, - ); - } - - return _drush_backend_invoke($cmds, $common_backend_options, $context); -} - /** * the aegir version of the backend * diff --git a/release.sh b/release.sh old mode 100644 new mode 100755 index 24c68cc03bdee690edfe8e24389130b65f1e96b3..23a13547df5ce92f440876aea5ccb7de5547b7c0 --- a/release.sh +++ b/release.sh @@ -29,7 +29,7 @@ if [ $# -lt 1 -o "$version" = "-h" ]; then cat < [] +Usage: $0 EOF exit 1 fi @@ -77,9 +77,7 @@ echo changing makefile to download tarball #sed -i'.tmp' -e'/^projects\[hostmaster\]\[download\]\[type\]/s/=.*$/ = "get"/' \ # -e'/^projects\[hostmaster\]\[download\]\[url\]/s#=.*$#= "http://ftp.drupal.org/files/projects/hostmaster-'$major-$version'.tgz"#' \ # -e'/^projects\[hostmaster\]\[download\]\[branch\].*/s/\[branch\] *=.*$/[directory_name] = "hostmaster"/' aegir.make && git add aegir.make && rm aegir.make.tmp -sed -i'.tmp' -e'/^projects\[hostmaster\]\[download\]\[type\]/s/=.*$/= "git"/' \ - -e'/^projects\[hostmaster\]\[download\]\[url\]/s#=.*$#= "http://git.drupal.org/project/hostmaster.git"#' \ - -e'/^projects\[hostmaster\]\[download\]\[branch\].*/s/\[branch\] *=.*$/[tag] = "'$major-$version'"/' aegir.make && git add aegir.make && rm aegir.make.tmp +sed -i'.tmp' -e'/^projects\[hostmaster\]\[download\]\[branch\].*/s/\[branch\] *=.*$/[tag] = "'$major-$version'"/' aegir.make && git add aegir.make && rm aegir.make.tmp echo changing provision.info version sed -i'.tmp' -e"s/version *=.*$/version=$major-$version/" provision.info @@ -91,7 +89,7 @@ sed -i'.tmp' -e"s/AEGIR_VERSION=.*$/AEGIR_VERSION=\"$major-$version\"/" upgrade. echo resulting changes to be committed: git diff --cached | cat -if prompt_yes_no "commit changes and tag release? (y/N) "; then +if prompt_yes_no "commit changes and tag release?"; then echo okay, committing... else echo 'aborting, leaving changes in git staging area' @@ -111,8 +109,7 @@ git reset --quiet HEAD 'debian/changelog' git checkout -- 'debian/changelog' git commit - -if prompt_yes_no "push tags and commits upstream? (y/N) "; then +if prompt_yes_no "push tags and commits upstream? "; then # this makes sure we push the commit *and* the tag git push --tags origin HEAD fi diff --git a/uninstall.hostmaster.inc b/uninstall.hostmaster.inc new file mode 100644 index 0000000000000000000000000000000000000000..813a675a81b94d11c5f4c203a0cd4570c96a4165 --- /dev/null +++ b/uninstall.hostmaster.inc @@ -0,0 +1,86 @@ + $resource->uri))); + $context = $resource->context; + if (!$context) { + drush_log(dt('Context missing for resource @resource, guessing', array('@resource' => $resource->uri)), 'warning'); + $context = $resource->uri; + } + provision_backend_invoke($context, 'provision-delete'); + } + + drush_log(dt('Destroying platforms'), 'info'); + $query = db_query("SELECT n.title AS uri, h.name AS context FROM {node} n INNER JOIN {hosting_platform} p LEFT JOIN {hosting_context} h ON h.nid = n.nid WHERE n.type = '%s' AND p.status != %d AND h.name != '%s'", 'platform', -2, d('@hostmaster')->platform->name); + while ($resource = db_fetch_object($query)) { + drush_log(dt("Destroying @resource", array('@resource' => $resource->uri))); + $context = $resource->context; + if (!$context) { + drush_log(dt('Context missing for platform @resource, ignoring', array('@resource' => $resource->uri)), 'warning'); + } else { + provision_backend_invoke($context, 'provision-delete'); + } + } + + drush_log(dt('Destroying servers'), 'info'); + $query = db_query("SELECT n.title AS uri, h.name AS context FROM {node} n LEFT JOIN {hosting_context} h ON h.nid = n.nid WHERE n.type = '%s' AND h.name != '%s' AND h.name != '%s'", 'server', d('@hostmaster')->server->name, d('@hostmaster')->db_server->name); + while ($resource = db_fetch_object($query)) { + drush_log(dt("Destroying @resource", array('@resource' => $resource->uri))); + $context = $resource->context; + if (!$context) { + drush_log(dt('Context missing for platform @resource, ignoring', array('@resource' => $resource->uri)), 'warning'); + } else { + provision_backend_invoke($context, 'provision-delete'); + } + } + } + + drush_log(dt('Destroying main hostmaster site'), 'info'); + provision_backend_invoke('@hostmaster', 'provision-delete'); + drush_log(dt('Removing crontab'), 'info'); + exec('crontab -r'); + drush_log(dt('Removing alias'), 'info'); + $config = new Provision_Config_Drushrc_Alias('@hostmaster'); + $config->unlink(); +}