From f972cf19d37d6fc7197567699fbd1e3acfd73cac Mon Sep 17 00:00:00 2001 From: Nav Date: Thu, 12 Nov 2015 15:34:00 +0200 Subject: [PATCH 01/11] Adding storage logging --- letsencrypt/storage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index 52be94f68..87e6a5cce 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -7,6 +7,9 @@ import configobj import parsedatetime import pytz +import logging +import logging.handlers + from letsencrypt import constants from letsencrypt import crypto_util from letsencrypt import errors From cec5bb8b8400f709bd64f21f52444b34f01dc417 Mon Sep 17 00:00:00 2001 From: Nav Date: Thu, 12 Nov 2015 21:31:00 +0200 Subject: [PATCH 02/11] Adding logging for _consistent --- letsencrypt/storage.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index 87e6a5cce..ef4f502ac 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -16,6 +16,8 @@ from letsencrypt import errors from letsencrypt import error_handler from letsencrypt import le_util +logger = logging.getLogger(__name__) + ALL_FOUR = ("cert", "privkey", "chain", "fullchain") @@ -141,11 +143,13 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Each element must be referenced with an absolute path if any(not os.path.isabs(x) for x in (self.cert, self.privkey, self.chain, self.fullchain)): + logger.debug("Element is not reference with an absolute file") return False # Each element must exist and be a symbolic link if any(not os.path.islink(x) for x in (self.cert, self.privkey, self.chain, self.fullchain)): + logger.debug("Element is not a symbolic link") return False for kind in ALL_FOUR: link = getattr(self, kind) @@ -160,16 +164,23 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes self.cli_config.archive_dir, self.lineagename) if not os.path.samefile(os.path.dirname(target), desired_directory): + #TODO: Split next line correctly + logger.debug("Element does not point within the cert " + "lineage's directory within the official " + "archive directory") return False # The link must point to a file that exists if not os.path.exists(target): + logger.debug("File does not exist") return False # The link must point to a file that follows the archive # naming convention pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind)) if not pattern.match(os.path.basename(target)): + logger.debug("Files does not follow the archive naming " + "convention") return False # It is NOT required that the link's target be a regular From 6760355a239068d8b744ecd785503c2df5f6559e Mon Sep 17 00:00:00 2001 From: Nav Date: Fri, 13 Nov 2015 11:44:10 +0200 Subject: [PATCH 03/11] Added more logging --- letsencrypt/storage.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index ef4f502ac..83aeb628b 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -265,6 +265,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes raise errors.CertStorageError("unknown kind of item") link = getattr(self, kind) if not os.path.exists(link): + logger.debug("File does not exist") return None target = os.readlink(link) if not os.path.isabs(target): @@ -289,11 +290,13 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind)) target = self.current_target(kind) if target is None or not os.path.exists(target): + logger.debug("File does not exist") target = "" matches = pattern.match(os.path.basename(target)) if matches: return int(matches.groups()[0]) else: + logger.debug("No matches") return None def version(self, kind, version): @@ -543,6 +546,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Renewals on the basis of revocation if self.ocsp_revoked(self.latest_common_version()): + logger.debug("Should renew, certificate is revoked") return True # Renewals on the basis of expiry time @@ -551,6 +555,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes "cert", self.latest_common_version())) now = pytz.UTC.fromutc(datetime.datetime.utcnow()) if expiry < add_time_interval(now, interval): + logger.debug("Should renew, certificate is expired") return True return False From 062b4722e238471d53bef20b54f573959b8b1801 Mon Sep 17 00:00:00 2001 From: Nav Date: Mon, 16 Nov 2015 15:01:45 +0200 Subject: [PATCH 04/11] Adding even more logging to storage.py --- letsencrypt/storage.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index 83aeb628b..d1c8a8314 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -164,7 +164,6 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes self.cli_config.archive_dir, self.lineagename) if not os.path.samefile(os.path.dirname(target), desired_directory): - #TODO: Split next line correctly logger.debug("Element does not point within the cert " "lineage's directory within the official " "archive directory") @@ -607,6 +606,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes cli_config.live_dir): if not os.path.exists(i): os.makedirs(i, 0700) + logger.debug("Creating CLI config directories") config_file, config_filename = le_util.unique_lineage_name( cli_config.renewal_configs_dir, lineagename) if not config_filename.endswith(".conf"): @@ -627,6 +627,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes "live directory exists for " + lineagename) os.mkdir(archive) os.mkdir(live_dir) + logger.debug("Archive and live directories created") relative_archive = os.path.join("..", "..", "archive", lineagename) # Put the data into the appropriate files on disk @@ -636,15 +637,19 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes os.symlink(os.path.join(relative_archive, kind + "1.pem"), target[kind]) with open(target["cert"], "w") as f: + logger.debug("Writing certificate") f.write(cert) with open(target["privkey"], "w") as f: + logger.debug("Writing private key") f.write(privkey) # XXX: Let's make sure to get the file permissions right here with open(target["chain"], "w") as f: + logger.debug("Writing chain") f.write(chain) with open(target["fullchain"], "w") as f: # assumes that OpenSSL.crypto.dump_certificate includes # ending newline character + logger.debug("Writing full chain") f.write(cert + chain) # Document what we've done in a new renewal config file @@ -659,6 +664,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes " in the renewal process"] # TODO: add human-readable comments explaining other available # parameters + logger.debug("Writing new config") new_config.write() return cls(new_config.filename, cli_config) @@ -712,13 +718,17 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes os.symlink(old_privkey, target["privkey"]) else: with open(target["privkey"], "w") as f: + logger.debug("Writing new private key") f.write(new_privkey) # Save everything else with open(target["cert"], "w") as f: + logger.debug("Writing certificate") f.write(new_cert) with open(target["chain"], "w") as f: + logger.debug("Writing chain") f.write(new_chain) with open(target["fullchain"], "w") as f: + logger.debug("Writing full chain") f.write(new_cert + new_chain) return target_version From 9fd1b1f38ad65e346c79d118eed703c41a753695 Mon Sep 17 00:00:00 2001 From: Nav Date: Tue, 17 Nov 2015 11:06:12 +0200 Subject: [PATCH 05/11] Fixes #1176 --- letsencrypt/plugins/manual.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/letsencrypt/plugins/manual.py b/letsencrypt/plugins/manual.py index 07f06ccec..62d754e0b 100644 --- a/letsencrypt/plugins/manual.py +++ b/letsencrypt/plugins/manual.py @@ -90,6 +90,8 @@ s.serve_forever()" """ def add_parser_arguments(cls, add): add("test-mode", action="store_true", help="Test mode. Executes the manual command in subprocess.") + add("public-ip-logging-ok", action="store_true", + help="Automatically allows public IP logging.") def prepare(self): # pylint: disable=missing-docstring,no-self-use pass # pragma: no cover @@ -164,9 +166,10 @@ s.serve_forever()" """ if self._httpd.poll() is not None: raise errors.Error("Couldn't execute manual command") else: - if not zope.component.getUtility(interfaces.IDisplay).yesno( - self.IP_DISCLAIMER, "Yes", "No"): - raise errors.PluginError("Must agree to IP logging to proceed") + if not self.conf("public-ip-logging-ok"): + if not zope.component.getUtility(interfaces.IDisplay).yesno( + self.IP_DISCLAIMER, "Yes", "No"): + raise errors.PluginError("Must agree to IP logging to proceed") self._notify_and_wait(self.MESSAGE_TEMPLATE.format( validation=validation, response=response, From 569962b40d884d1f8b277f1694b253890c9b4042 Mon Sep 17 00:00:00 2001 From: Nav Date: Tue, 17 Nov 2015 11:50:32 +0200 Subject: [PATCH 06/11] Fixing manual authenticator tests --- letsencrypt/plugins/manual_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/plugins/manual_test.py b/letsencrypt/plugins/manual_test.py index a9281902f..4afd44cac 100644 --- a/letsencrypt/plugins/manual_test.py +++ b/letsencrypt/plugins/manual_test.py @@ -23,7 +23,7 @@ class AuthenticatorTest(unittest.TestCase): def setUp(self): from letsencrypt.plugins.manual import Authenticator self.config = mock.MagicMock( - http01_port=8080, manual_test_mode=False) + http01_port=8080, manual_test_mode=False, manual_public_ip_logging_ok=False) self.auth = Authenticator(config=self.config, name="manual") self.achalls = [achallenges.KeyAuthorizationAnnotatedChallenge( challb=acme_util.HTTP01_P, domain="foo.com", account_key=KEY)] From 678fb555c0e9b96203da872f9909f5cf82d8113d Mon Sep 17 00:00:00 2001 From: Nav Date: Wed, 18 Nov 2015 12:39:43 +0200 Subject: [PATCH 07/11] Improving content of logging messages --- letsencrypt/storage.py | 55 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index d1c8a8314..bc6e49124 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -143,13 +143,14 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Each element must be referenced with an absolute path if any(not os.path.isabs(x) for x in (self.cert, self.privkey, self.chain, self.fullchain)): - logger.debug("Element is not reference with an absolute file") + logger.debug("Element %s is not referenced with an " + "absolute file.", x) return False # Each element must exist and be a symbolic link if any(not os.path.islink(x) for x in (self.cert, self.privkey, self.chain, self.fullchain)): - logger.debug("Element is not a symbolic link") + logger.debug("Element %s is not a symbolic link.", x) return False for kind in ALL_FOUR: link = getattr(self, kind) @@ -164,22 +165,24 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes self.cli_config.archive_dir, self.lineagename) if not os.path.samefile(os.path.dirname(target), desired_directory): - logger.debug("Element does not point within the cert " - "lineage's directory within the official " - "archive directory") + logger.debug("Element's link does not point within the " + "cert lineage's directory within the " + "official archive directory. Link: %s, " + "archive directory: %s.", + os.path.dirname(target), desired_directory) return False # The link must point to a file that exists if not os.path.exists(target): - logger.debug("File does not exist") + logger.debug("Link %s points to a file that does not exist.", target) return False # The link must point to a file that follows the archive # naming convention pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind)) if not pattern.match(os.path.basename(target)): - logger.debug("Files does not follow the archive naming " - "convention") + logger.debug("Link %s does not follow the archive naming " + "convention.", os.path.basename(target)) return False # It is NOT required that the link's target be a regular @@ -264,7 +267,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes raise errors.CertStorageError("unknown kind of item") link = getattr(self, kind) if not os.path.exists(link): - logger.debug("File does not exist") + logger.debug("Target %s of kind %s does not exist.", link, kind) return None target = os.readlink(link) if not os.path.isabs(target): @@ -289,13 +292,14 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind)) target = self.current_target(kind) if target is None or not os.path.exists(target): - logger.debug("File does not exist") + logger.debug("Current-version target for %s " + "does not exist at %s.", kind, target) target = "" matches = pattern.match(os.path.basename(target)) if matches: return int(matches.groups()[0]) else: - logger.debug("No matches") + logger.debug("No matches for target %s.", kind) return None def version(self, kind, version): @@ -545,7 +549,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Renewals on the basis of revocation if self.ocsp_revoked(self.latest_common_version()): - logger.debug("Should renew, certificate is revoked") + logger.debug("Should renew, certificate is revoked.") return True # Renewals on the basis of expiry time @@ -554,7 +558,9 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes "cert", self.latest_common_version())) now = pytz.UTC.fromutc(datetime.datetime.utcnow()) if expiry < add_time_interval(now, interval): - logger.debug("Should renew, certificate is expired") + logger.debug("Should renew, certificate " + "has expired since %s.", + expiry.strftime("%Y-%m-%d %H:%M:%S %Z")) return True return False @@ -606,7 +612,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes cli_config.live_dir): if not os.path.exists(i): os.makedirs(i, 0700) - logger.debug("Creating CLI config directories") + logger.debug("Creating CLI config directory %s.", i) config_file, config_filename = le_util.unique_lineage_name( cli_config.renewal_configs_dir, lineagename) if not config_filename.endswith(".conf"): @@ -627,7 +633,8 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes "live directory exists for " + lineagename) os.mkdir(archive) os.mkdir(live_dir) - logger.debug("Archive and live directories created") + logger.debug("Archive directory %s and live " + "directory %s created.", archive, live_dir) relative_archive = os.path.join("..", "..", "archive", lineagename) # Put the data into the appropriate files on disk @@ -637,19 +644,19 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes os.symlink(os.path.join(relative_archive, kind + "1.pem"), target[kind]) with open(target["cert"], "w") as f: - logger.debug("Writing certificate") + logger.debug("Writing certificate.") f.write(cert) with open(target["privkey"], "w") as f: - logger.debug("Writing private key") + logger.debug("Writing private key.") f.write(privkey) # XXX: Let's make sure to get the file permissions right here with open(target["chain"], "w") as f: - logger.debug("Writing chain") + logger.debug("Writing chain.") f.write(chain) with open(target["fullchain"], "w") as f: # assumes that OpenSSL.crypto.dump_certificate includes # ending newline character - logger.debug("Writing full chain") + logger.debug("Writing full chain.") f.write(cert + chain) # Document what we've done in a new renewal config file @@ -664,7 +671,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes " in the renewal process"] # TODO: add human-readable comments explaining other available # parameters - logger.debug("Writing new config") + logger.debug("Writing new config %s.", config_filename) new_config.write() return cls(new_config.filename, cli_config) @@ -718,17 +725,17 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes os.symlink(old_privkey, target["privkey"]) else: with open(target["privkey"], "w") as f: - logger.debug("Writing new private key") + logger.debug("Writing new private key.") f.write(new_privkey) # Save everything else with open(target["cert"], "w") as f: - logger.debug("Writing certificate") + logger.debug("Writing certificate.") f.write(new_cert) with open(target["chain"], "w") as f: - logger.debug("Writing chain") + logger.debug("Writing chain.") f.write(new_chain) with open(target["fullchain"], "w") as f: - logger.debug("Writing full chain") + logger.debug("Writing full chain.") f.write(new_cert + new_chain) return target_version From 24e5e3d8e59e9af4b706f76030a4d12dc115c384 Mon Sep 17 00:00:00 2001 From: Nav Date: Wed, 18 Nov 2015 12:49:06 +0200 Subject: [PATCH 08/11] Fixing tests broken by including the variable x in the logger debug messages --- letsencrypt/storage.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index bc6e49124..b04536c1c 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -141,17 +141,17 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes """ # Each element must be referenced with an absolute path - if any(not os.path.isabs(x) for x in - (self.cert, self.privkey, self.chain, self.fullchain)): - logger.debug("Element %s is not referenced with an " - "absolute file.", x) - return False + for x in (self.cert, self.privkey, self.chain, self.fullchain): + if not os.path.isabs(x): + logger.debug("Element %s is not referenced with an " + "absolute file.", x) + return False # Each element must exist and be a symbolic link - if any(not os.path.islink(x) for x in - (self.cert, self.privkey, self.chain, self.fullchain)): - logger.debug("Element %s is not a symbolic link.", x) - return False + for x in (self.cert, self.privkey, self.chain, self.fullchain): + if not os.path.islink(x): + logger.debug("Element %s is not a symbolic link.", x) + return False for kind in ALL_FOUR: link = getattr(self, kind) where = os.path.dirname(link) From 25e6502aac7fcb7370cc331bba451dbe8a95ef9d Mon Sep 17 00:00:00 2001 From: Nav Date: Wed, 18 Nov 2015 21:28:57 +0200 Subject: [PATCH 09/11] Adding paths to cert and chain logging messages --- letsencrypt/storage.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index b04536c1c..cc7ab4313 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -644,19 +644,19 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes os.symlink(os.path.join(relative_archive, kind + "1.pem"), target[kind]) with open(target["cert"], "w") as f: - logger.debug("Writing certificate.") + logger.debug("Writing certificate to %s.", target["cert"]) f.write(cert) with open(target["privkey"], "w") as f: - logger.debug("Writing private key.") + logger.debug("Writing private key to %s.", target["privkey"]) f.write(privkey) # XXX: Let's make sure to get the file permissions right here with open(target["chain"], "w") as f: - logger.debug("Writing chain.") + logger.debug("Writing chain to %s.", target["chain"]) f.write(chain) with open(target["fullchain"], "w") as f: # assumes that OpenSSL.crypto.dump_certificate includes # ending newline character - logger.debug("Writing full chain.") + logger.debug("Writing full chain to %s.", target["fullchain"]) f.write(cert + chain) # Document what we've done in a new renewal config file @@ -722,20 +722,21 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes old_privkey = os.readlink(old_privkey) else: old_privkey = "privkey{0}.pem".format(prior_version) + logger.debug("Writing symlink to old private key, %s.", old_privkey) os.symlink(old_privkey, target["privkey"]) else: with open(target["privkey"], "w") as f: - logger.debug("Writing new private key.") + logger.debug("Writing new private key to %s.", target["privkey"]) f.write(new_privkey) # Save everything else with open(target["cert"], "w") as f: - logger.debug("Writing certificate.") + logger.debug("Writing certificate to %s.", target["cert"]) f.write(new_cert) with open(target["chain"], "w") as f: - logger.debug("Writing chain.") + logger.debug("Writing chain to %s.", target["chain"]) f.write(new_chain) with open(target["fullchain"], "w") as f: - logger.debug("Writing full chain.") + logger.debug("Writing full chain to %s.", target["fullchain"]) f.write(new_cert + new_chain) return target_version From 5667acc558b1ab1492d86d42bf46e8b4c3932e41 Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 21 Nov 2015 17:57:03 +0200 Subject: [PATCH 10/11] Refining importing libraries --- letsencrypt/storage.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index cc7ab4313..71550e855 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -1,5 +1,6 @@ """Renewable certificates storage.""" import datetime +import logging import os import re @@ -7,9 +8,6 @@ import configobj import parsedatetime import pytz -import logging -import logging.handlers - from letsencrypt import constants from letsencrypt import crypto_util from letsencrypt import errors From b42b5d0f08d82825f0a359e9ffd9692f4f0b2f5e Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 21 Nov 2015 18:07:59 +0200 Subject: [PATCH 11/11] Refining content of logging messages --- letsencrypt/storage.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index 71550e855..7e2802b14 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -142,7 +142,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes for x in (self.cert, self.privkey, self.chain, self.fullchain): if not os.path.isabs(x): logger.debug("Element %s is not referenced with an " - "absolute file.", x) + "absolute path.", x) return False # Each element must exist and be a symbolic link @@ -166,21 +166,23 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes logger.debug("Element's link does not point within the " "cert lineage's directory within the " "official archive directory. Link: %s, " + "target directory: %s, " "archive directory: %s.", - os.path.dirname(target), desired_directory) + link, os.path.dirname(target), desired_directory) return False # The link must point to a file that exists if not os.path.exists(target): - logger.debug("Link %s points to a file that does not exist.", target) + logger.debug("Link %s points to file %s that does not exist.", + link, target) return False # The link must point to a file that follows the archive # naming convention pattern = re.compile(r"^{0}([0-9]+)\.pem$".format(kind)) if not pattern.match(os.path.basename(target)): - logger.debug("Link %s does not follow the archive naming " - "convention.", os.path.basename(target)) + logger.debug("%s does not follow the archive naming " + "convention.", target) return False # It is NOT required that the link's target be a regular @@ -265,7 +267,8 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes raise errors.CertStorageError("unknown kind of item") link = getattr(self, kind) if not os.path.exists(link): - logger.debug("Target %s of kind %s does not exist.", link, kind) + logger.debug("Expected symlink %s for %s does not exist.", + link, kind) return None target = os.readlink(link) if not os.path.isabs(target): @@ -557,7 +560,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes now = pytz.UTC.fromutc(datetime.datetime.utcnow()) if expiry < add_time_interval(now, interval): logger.debug("Should renew, certificate " - "has expired since %s.", + "has been expired since %s.", expiry.strftime("%Y-%m-%d %H:%M:%S %Z")) return True return False @@ -610,7 +613,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes cli_config.live_dir): if not os.path.exists(i): os.makedirs(i, 0700) - logger.debug("Creating CLI config directory %s.", i) + logger.debug("Creating directory %s.", i) config_file, config_filename = le_util.unique_lineage_name( cli_config.renewal_configs_dir, lineagename) if not config_filename.endswith(".conf"):