diff --git a/certbot/cli.py b/certbot/cli.py index 8e599cfda..ff1827cb1 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -1215,6 +1215,10 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis " one will be run.") helpful.add("renew", "--renew-hook", action=_RenewHookAction, help=argparse.SUPPRESS) + helpful.add( + "renew", "--no-random-sleep-on-renew", action="store_false", + default=flag_default("random_sleep_on_renew"), dest="random_sleep_on_renew", + help=argparse.SUPPRESS) helpful.add( "renew", "--deploy-hook", action=_DeployHookAction, help='Command to be run in a shell once for each successfully' diff --git a/certbot/constants.py b/certbot/constants.py index eb4105f82..7d0e0c879 100644 --- a/certbot/constants.py +++ b/certbot/constants.py @@ -68,6 +68,7 @@ CLI_DEFAULTS = dict( directory_hooks=True, reuse_key=False, disable_renew_updates=False, + random_sleep_on_renew=True, eab_hmac_key=None, eab_kid=None, diff --git a/certbot/main.py b/certbot/main.py index b24c5c622..ac639bc80 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -4,9 +4,7 @@ from __future__ import print_function import functools import logging.handlers import os -import random import sys -import time import configobj import josepy as jose @@ -1269,16 +1267,6 @@ def renew(config, unused_plugins): :rtype: None """ - if not sys.stdin.isatty(): - # Noninteractive renewals include a random delay in order to spread - # out the load on the certificate authority servers, even if many - # users all pick the same time for renewals. This delay precedes - # running any hooks, so that side effects of the hooks (such as - # shutting down a web service) aren't prolonged unnecessarily. - sleep_time = random.randint(1, 60*8) - logger.info("Non-interactive renewal: random delay of %s seconds", sleep_time) - time.sleep(sleep_time) - try: renewal.handle_renewal_request(config) finally: diff --git a/certbot/renewal.py b/certbot/renewal.py index 5b2e00740..4c592b27f 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -5,6 +5,9 @@ import itertools import logging import os import traceback +import sys +import time +import random import six import zope.component @@ -372,7 +375,7 @@ def _renew_describe_results(config, renew_successes, renew_failures, disp.notification("\n".join(out), wrap=False) -def handle_renewal_request(config): +def handle_renewal_request(config): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """Examine each lineage; renew if due and report results""" # This is trivially False if config.domains is empty @@ -396,6 +399,14 @@ def handle_renewal_request(config): renew_failures = [] renew_skipped = [] parse_failures = [] + + # Noninteractive renewals include a random delay in order to spread + # out the load on the certificate authority servers, even if many + # users all pick the same time for renewals. This delay precedes + # running any hooks, so that side effects of the hooks (such as + # shutting down a web service) aren't prolonged unnecessarily. + apply_random_sleep = not sys.stdin.isatty() and config.random_sleep_on_renew + for renewal_file in conf_files: disp = zope.component.getUtility(interfaces.IDisplay) disp.notification("Processing " + renewal_file, pause=False) @@ -424,6 +435,15 @@ def handle_renewal_request(config): from certbot import main plugins = plugins_disco.PluginsRegistry.find_all() if should_renew(lineage_config, renewal_candidate): + # Apply random sleep upon first renewal if needed + if apply_random_sleep: + sleep_time = random.randint(1, 60 * 8) + logger.info("Non-interactive renewal: random delay of %s seconds", + sleep_time) + time.sleep(sleep_time) + # We will sleep only once this day, folks. + apply_random_sleep = False + # domains have been restored into lineage_config by reconstitute # but they're unnecessary anyway because renew_cert here # will just grab them from the certificate