Merge pull request #1603 from letsencrypt/reload

Use reload in Apache (fixes #954) [needs minor extension]
This commit is contained in:
Peter Eckersley
2015-11-24 08:20:01 -08:00
@@ -8,6 +8,7 @@ import re
import shutil import shutil
import socket import socket
import subprocess import subprocess
import time
import zope.interface import zope.interface
@@ -96,7 +97,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
help="Path to the Apache 'a2enmod' binary.") help="Path to the Apache 'a2enmod' binary.")
add("init-script", default=constants.CLI_DEFAULTS["init_script"], add("init-script", default=constants.CLI_DEFAULTS["init_script"],
help="Path to the Apache init script (used for server " help="Path to the Apache init script (used for server "
"reload/restart).") "reload).")
add("le-vhost-ext", default=constants.CLI_DEFAULTS["le_vhost_ext"], add("le-vhost-ext", default=constants.CLI_DEFAULTS["le_vhost_ext"],
help="SSL vhost configuration extension.") help="SSL vhost configuration extension.")
add("server-root", default=constants.CLI_DEFAULTS["server_root"], add("server-root", default=constants.CLI_DEFAULTS["server_root"],
@@ -1012,7 +1013,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return False return False
def enable_site(self, vhost): def enable_site(self, vhost):
"""Enables an available site, Apache restart required. """Enables an available site, Apache reload required.
.. note:: Does not make sure that the site correctly works or that all .. note:: Does not make sure that the site correctly works or that all
modules are enabled appropriately. modules are enabled appropriately.
@@ -1047,7 +1048,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
def enable_mod(self, mod_name, temp=False): def enable_mod(self, mod_name, temp=False):
"""Enables module in Apache. """Enables module in Apache.
Both enables and restarts Apache so module is active. Both enables and reloads Apache so module is active.
:param str mod_name: Name of the module to enable. (e.g. 'ssl') :param str mod_name: Name of the module to enable. (e.g. 'ssl')
:param bool temp: Whether or not this is a temporary action. :param bool temp: Whether or not this is a temporary action.
@@ -1089,7 +1090,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Modules can enable additional config files. Variables may be defined # Modules can enable additional config files. Variables may be defined
# within these new configuration sections. # within these new configuration sections.
# Restart is not necessary as DUMP_RUN_CFG uses latest config. # Reload is not necessary as DUMP_RUN_CFG uses latest config.
self.parser.update_runtime_variables(self.conf("ctl")) self.parser.update_runtime_variables(self.conf("ctl"))
def _add_parser_mod(self, mod_name): def _add_parser_mod(self, mod_name):
@@ -1112,16 +1113,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
le_util.run_script([self.conf("enmod"), mod_name]) le_util.run_script([self.conf("enmod"), mod_name])
def restart(self): def restart(self):
"""Restarts apache server. """Reloads apache server.
.. todo:: This function will be converted to using reload .. todo:: This function will be converted to using reload
:raises .errors.MisconfigurationError: If unable to restart due :raises .errors.MisconfigurationError: If unable to reload due
to a configuration problem, or if the restart subprocess to a configuration problem, or if the reload subprocess
cannot be run. cannot be run.
""" """
return apache_restart(self.conf("init-script")) return apache_reload(self.conf("init-script"))
def config_test(self): # pylint: disable=no-self-use def config_test(self): # pylint: disable=no-self-use
"""Check the configuration of Apache for errors. """Check the configuration of Apache for errors.
@@ -1196,11 +1197,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
sni_response = apache_dvsni.perform() sni_response = apache_dvsni.perform()
if sni_response: if sni_response:
# Must restart in order to activate the challenges. # Must reload in order to activate the challenges.
# Handled here because we may be able to load up other challenge # Handled here because we may be able to load up other challenge
# types # types
self.restart() self.restart()
# TODO: Remove this dirty hack. We need to determine a reliable way
# of identifying when the new configuration is being used.
time.sleep(3)
# Go through all of the challenges and assign them to the proper # Go through all of the challenges and assign them to the proper
# place in the responses return value. All responses must be in the # place in the responses return value. All responses must be in the
# same order as the original challenges. # same order as the original challenges.
@@ -1239,42 +1244,42 @@ def _get_mod_deps(mod_name):
return deps.get(mod_name, []) return deps.get(mod_name, [])
def apache_restart(apache_init_script): def apache_reload(apache_init_script):
"""Restarts the Apache Server. """Reloads the Apache Server.
:param str apache_init_script: Path to the Apache init script. :param str apache_init_script: Path to the Apache init script.
.. todo:: Try to use reload instead. (This caused timing problems before) .. todo:: Try to use reload instead. (This caused timing problems before)
.. todo:: On failure, this should be a recovery_routine call with another .. todo:: On failure, this should be a recovery_routine call with another
restart. This will confuse and inhibit developers from testing code reload. This will confuse and inhibit developers from testing code
though. This change should happen after though. This change should happen after
the ApacheConfigurator has been thoroughly tested. The function will the ApacheConfigurator has been thoroughly tested. The function will
need to be moved into the class again. Perhaps need to be moved into the class again. Perhaps
this version can live on... for testing purposes. this version can live on... for testing purposes.
:raises .errors.MisconfigurationError: If unable to restart due to a :raises .errors.MisconfigurationError: If unable to reload due to a
configuration problem, or if the restart subprocess cannot be run. configuration problem, or if the reload subprocess cannot be run.
""" """
try: try:
proc = subprocess.Popen([apache_init_script, "restart"], proc = subprocess.Popen([apache_init_script, "reload"],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
except (OSError, ValueError): except (OSError, ValueError):
logger.fatal( logger.fatal(
"Unable to restart the Apache process with %s", apache_init_script) "Unable to reload the Apache process with %s", apache_init_script)
raise errors.MisconfigurationError( raise errors.MisconfigurationError(
"Unable to restart Apache process with %s" % apache_init_script) "Unable to reload Apache process with %s" % apache_init_script)
stdout, stderr = proc.communicate() stdout, stderr = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0:
# Enter recovery routine... # Enter recovery routine...
logger.error("Apache Restart Failed!\n%s\n%s", stdout, stderr) logger.error("Apache Reload Failed!\n%s\n%s", stdout, stderr)
raise errors.MisconfigurationError( raise errors.MisconfigurationError(
"Error while restarting Apache:\n%s\n%s" % (stdout, stderr)) "Error while reloading Apache:\n%s\n%s" % (stdout, stderr))
def get_file_path(vhost_path): def get_file_path(vhost_path):