From 8f252411705bc89e6d4097e25be364a4e69c1cf0 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 18 May 2015 15:57:12 -0700 Subject: [PATCH] Introduce proper renewer config via constants.py --- letsencrypt/constants.py | 13 +++++++++++++ letsencrypt/renewer.py | 15 +++++++++------ letsencrypt/storage.py | 24 +++++++++++++++--------- letsencrypt/tests/renewer_test.py | 7 +++---- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/letsencrypt/constants.py b/letsencrypt/constants.py index 4eba69f20..c05d8828e 100644 --- a/letsencrypt/constants.py +++ b/letsencrypt/constants.py @@ -1,4 +1,5 @@ """Let's Encrypt constants.""" +import configobj import logging from acme import challenges @@ -25,6 +26,18 @@ CLI_DEFAULTS = dict( """Defaults for CLI flags and `.IConfig` attributes.""" +RENEWER_DEFAULTS = configobj.ConfigObj(dict( + renewer_config_file="/etc/letsencrypt/renewer.conf", + renewal_configs_dir="/etc/letsencrypt/configs", + archive_dir="/etc/letsencrypt/archive", + live_dir="/etc/letsencrypt/live", + renewer_enabled="yes", + renew_before_expiry="30 days", + deploy_before_expiry="20 days", +)) +"""Defaults for renewer script.""" + + EXCLUSIVE_CHALLENGES = frozenset([frozenset([ challenges.DVSNI, challenges.SimpleHTTPS])]) """Mutually exclusive challenges.""" diff --git a/letsencrypt/renewer.py b/letsencrypt/renewer.py index 0ff9d2c75..79a489b05 100644 --- a/letsencrypt/renewer.py +++ b/letsencrypt/renewer.py @@ -11,17 +11,13 @@ import os import configobj from letsencrypt import configuration +from letsencrypt import constants from letsencrypt import client from letsencrypt import crypto_util from letsencrypt import notify from letsencrypt import storage from letsencrypt.plugins import disco as plugins_disco -DEFAULTS = configobj.ConfigObj("renewal.conf") -DEFAULTS["renewal_configs_dir"] = "/tmp/etc/letsencrypt/configs" -DEFAULTS["official_archive_dir"] = "/tmp/etc/letsencrypt/archive" -DEFAULTS["live_dir"] = "/tmp/etc/letsencrypt/live" - class AttrDict(dict): """A trick to allow accessing dictionary keys as object @@ -91,13 +87,20 @@ def renew(cert, old_version): # (where fewer than all names were renewed) -def main(config=DEFAULTS): +def main(config=constants.RENEWER_DEFAULTS): """main function for autorenewer script.""" # TODO: Distinguish automated invocation from manual invocation, # perhaps by looking at sys.argv[0] and inhibiting automated # invocations if /etc/letsencrypt/renewal.conf defaults have # turned it off. (The boolean parameter should probably be # called renewer_enabled.) + + # This attempts to read the renewer config file and augment or replace + # the renewer defaults with any options contained in that file. If + # renewer_config_file is undefined or if the file is nonexistent or + # empty, this .merge() will have no effect. + config.merge(configobj.ConfigObj(config.get("renewer_config_file", ""))) + for i in os.listdir(config["renewal_configs_dir"]): print "Processing", i if not i.endswith(".conf"): diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index b30c7077a..bdea23f7f 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -13,12 +13,9 @@ import parsedatetime import pytz import pyrfc3339 +from letsencrypt import constants from letsencrypt import le_util -DEFAULTS = configobj.ConfigObj("renewal.conf") -DEFAULTS["renewal_configs_dir"] = "/tmp/etc/letsencrypt/configs" -DEFAULTS["official_archive_dir"] = "/tmp/etc/letsencrypt/archive" -DEFAULTS["live_dir"] = "/tmp/etc/letsencrypt/live" ALL_FOUR = ("cert", "privkey", "chain", "fullchain") @@ -81,7 +78,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes and/or systemwide defaults. :type configuration: :class:`configobj.ConfigObj`""" - def __init__(self, configfile, defaults=DEFAULTS): + def __init__(self, configfile, defaults=constants.RENEWER_DEFAULTS): """Instantiate a RenewableCert object from an existing lineage. :param :class:`configobj.ConfigObj` configfile: an already-parsed @@ -109,6 +106,9 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # systemwide renewal configuration; self.configfile should be # used to make and save changes. self.configfile = configfile + # TODO: Do we actually use anything from defaults and do we want to + # read further defaults from the systemwide renewal configuration + # file at this stage? self.configuration = copy.deepcopy(defaults) self.configuration.merge(self.configfile) @@ -147,7 +147,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Each element's link must point within the cert lineage's # directory within the official archive directory desired_directory = os.path.join( - self.configuration["official_archive_dir"], self.lineagename) + self.configuration["archive_dir"], self.lineagename) if not os.path.samefile(os.path.dirname(target), desired_directory): return False @@ -479,7 +479,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes @classmethod def new_lineage(cls, lineagename, cert, privkey, chain, - renewalparams=None, config=DEFAULTS): + renewalparams=None, config=constants.RENEWER_DEFAULTS): # pylint: disable=too-many-locals,too-many-arguments """Create a new certificate lineage. @@ -511,9 +511,15 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes :returns: the newly-created RenewalCert object :rtype: :class:`storage.renewableCert`""" + # This attempts to read the renewer config file and augment or replace + # the renewer defaults with any options contained in that file. If + # renewer_config_file is undefined or if the file is nonexistent or + # empty, this .merge() will have no effect. + config.merge(configobj.ConfigObj(config.get("renewer_config_file", ""))) + # Examine the configuration and find the new lineage's name configs_dir = config["renewal_configs_dir"] - archive_dir = config["official_archive_dir"] + archive_dir = config["archive_dir"] live_dir = config["live_dir"] for i in (configs_dir, archive_dir, live_dir): if not os.path.exists(i): @@ -594,7 +600,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Figure out what the new version is and hence where to save things target_version = self.next_free_version() - archive = self.configuration["official_archive_dir"] + archive = self.configuration["archive_dir"] prefix = os.path.join(archive, self.lineagename) target = dict( [(kind, diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 0486c75e9..4f1fe6bfc 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -38,8 +38,7 @@ class RenewableCertTests(unittest.TestCase): os.makedirs(os.path.join(self.tempdir, "configs")) defaults = configobj.ConfigObj() defaults["live_dir"] = os.path.join(self.tempdir, "live") - defaults["official_archive_dir"] = os.path.join(self.tempdir, - "archive") + defaults["archive_dir"] = os.path.join(self.tempdir, "archive") defaults["renewal_configs_dir"] = os.path.join(self.tempdir, "configs") config = configobj.ConfigObj() @@ -461,7 +460,7 @@ class RenewableCertTests(unittest.TestCase): """Test for new_lineage() class method.""" from letsencrypt import storage config_dir = self.defaults["renewal_configs_dir"] - archive_dir = self.defaults["official_archive_dir"] + archive_dir = self.defaults["archive_dir"] live_dir = self.defaults["live_dir"] result = storage.RenewableCert.new_lineage("the-lineage.com", "cert", "privkey", "chain", None, @@ -500,7 +499,7 @@ class RenewableCertTests(unittest.TestCase): """Test that directories can be created if they don't exist.""" from letsencrypt import storage config_dir = self.defaults["renewal_configs_dir"] - archive_dir = self.defaults["official_archive_dir"] + archive_dir = self.defaults["archive_dir"] live_dir = self.defaults["live_dir"] shutil.rmtree(config_dir) shutil.rmtree(archive_dir)