mirror of
https://github.com/certbot/certbot.git
synced 2026-01-23 07:20:55 +03:00
Merge branch 'master' into apache_failed_vhost
Conflicts: letsencrypt_apache/configurator.py letsencrypt_apache/dvsni.py
This commit is contained in:
@@ -82,7 +82,7 @@ required-attributes=
|
||||
bad-functions=map,filter,apply,input,file
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=f,i,j,k,ex,Run,_,fd
|
||||
good-names=f,i,j,k,ex,Run,_,fd,logger
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
@@ -173,7 +173,7 @@ notes=FIXME,XXX,TODO
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
logging-modules=logging,logger
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
@@ -15,6 +15,8 @@ from acme import jws
|
||||
from acme import messages
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning
|
||||
requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3()
|
||||
|
||||
@@ -54,7 +56,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
"""
|
||||
dumps = obj.json_dumps()
|
||||
logging.debug('Serialized JSON: %s', dumps)
|
||||
logger.debug('Serialized JSON: %s', dumps)
|
||||
return jws.JWS.sign(
|
||||
payload=dumps, key=self.key, alg=self.alg, nonce=nonce).json_dumps()
|
||||
|
||||
@@ -77,8 +79,8 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
:raises .ClientError: In case of other networking errors.
|
||||
|
||||
"""
|
||||
logging.debug('Received response %s (headers: %s): %r',
|
||||
response, response.headers, response.content)
|
||||
logger.debug('Received response %s (headers: %s): %r',
|
||||
response, response.headers, response.content)
|
||||
|
||||
response_ct = response.headers.get('Content-Type')
|
||||
try:
|
||||
@@ -91,7 +93,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
if not response.ok:
|
||||
if jobj is not None:
|
||||
if response_ct != cls.JSON_ERROR_CONTENT_TYPE:
|
||||
logging.debug(
|
||||
logger.debug(
|
||||
'Ignoring wrong Content-Type (%r) for JSON Error',
|
||||
response_ct)
|
||||
try:
|
||||
@@ -104,7 +106,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
raise errors.ClientError(response)
|
||||
else:
|
||||
if jobj is not None and response_ct != cls.JSON_CONTENT_TYPE:
|
||||
logging.debug(
|
||||
logger.debug(
|
||||
'Ignoring wrong Content-Type (%r) for JSON decodable '
|
||||
'response', response_ct)
|
||||
|
||||
@@ -121,7 +123,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
:rtype: `requests.Response`
|
||||
|
||||
"""
|
||||
logging.debug('Sending GET request to %s', uri)
|
||||
logger.debug('Sending GET request to %s', uri)
|
||||
kwargs.setdefault('verify', self.verify_ssl)
|
||||
try:
|
||||
response = requests.get(uri, **kwargs)
|
||||
@@ -135,7 +137,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
nonce = response.headers[self.REPLAY_NONCE_HEADER]
|
||||
error = jws.Header.validate_nonce(nonce)
|
||||
if error is None:
|
||||
logging.debug('Storing nonce: %r', nonce)
|
||||
logger.debug('Storing nonce: %r', nonce)
|
||||
self._nonces.add(nonce)
|
||||
else:
|
||||
raise errors.ClientError('Invalid nonce ({0}): {1}'.format(
|
||||
@@ -147,7 +149,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
def _get_nonce(self, uri):
|
||||
if not self._nonces:
|
||||
logging.debug('Requesting fresh nonce by sending HEAD to %s', uri)
|
||||
logger.debug('Requesting fresh nonce by sending HEAD to %s', uri)
|
||||
self._add_nonce(requests.head(uri))
|
||||
return self._nonces.pop()
|
||||
|
||||
@@ -164,7 +166,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
"""
|
||||
data = self._wrap_in_jws(obj, self._get_nonce(uri))
|
||||
logging.debug('Sending POST data to %s: %s', uri, data)
|
||||
logger.debug('Sending POST data to %s: %s', uri, data)
|
||||
kwargs.setdefault('verify', self.verify_ssl)
|
||||
try:
|
||||
response = requests.post(uri, data=data, **kwargs)
|
||||
@@ -394,7 +396,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
"""
|
||||
assert authzrs, "Authorizations list is empty"
|
||||
logging.debug("Requesting issuance...")
|
||||
logger.debug("Requesting issuance...")
|
||||
|
||||
# TODO: assert len(authzrs) == number of SANs
|
||||
req = messages.CertificateRequest(
|
||||
@@ -458,7 +460,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
||||
now = datetime.datetime.now()
|
||||
if when > now:
|
||||
seconds = (when - now).seconds
|
||||
logging.debug('Sleeping for %d seconds', seconds)
|
||||
logger.debug('Sleeping for %d seconds', seconds)
|
||||
time.sleep(seconds)
|
||||
|
||||
# Note that we poll with the latest updated Authorization
|
||||
|
||||
@@ -18,6 +18,9 @@ from acme.jose import interfaces
|
||||
from acme.jose import util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Field(object):
|
||||
"""JSON object field.
|
||||
|
||||
@@ -233,7 +236,7 @@ class JSONObjectWithFields(util.ImmutableMap, interfaces.JSONDeSerializable):
|
||||
slot, value, error))
|
||||
if omitted:
|
||||
# pylint: disable=star-args
|
||||
logging.debug('Omitted empty fields: %s', ', '.join(
|
||||
logger.debug('Omitted empty fields: %s', ', '.join(
|
||||
'{0!s}={1!r}'.format(*field) for field in omitted))
|
||||
return jobj
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ import Crypto.PublicKey.RSA
|
||||
from acme import jose
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Signature(jose.JSONObjectWithFields):
|
||||
"""ACME signature.
|
||||
|
||||
@@ -54,7 +57,7 @@ class Signature(jose.JSONObjectWithFields):
|
||||
|
||||
msg_with_nonce = nonce + msg
|
||||
sig = alg.sign(key, nonce + msg)
|
||||
logging.debug('%s signed as %s', msg_with_nonce, sig)
|
||||
logger.debug('%s signed as %s', msg_with_nonce, sig)
|
||||
|
||||
return cls(alg=alg, sig=sig, nonce=nonce,
|
||||
jwk=alg.kty(key=key.publickey()))
|
||||
|
||||
@@ -16,6 +16,9 @@ from letsencrypt import le_util
|
||||
from letsencrypt.display import util as display_util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Account(object):
|
||||
"""ACME protocol registration.
|
||||
|
||||
@@ -226,5 +229,5 @@ class Account(object):
|
||||
if cls.EMAIL_REGEX.match(email):
|
||||
return not email.startswith(".") and ".." not in email
|
||||
else:
|
||||
logging.warn("Invalid email address: %s.", email)
|
||||
logger.warn("Invalid email address: %s.", email)
|
||||
return False
|
||||
|
||||
@@ -14,6 +14,9 @@ from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AuthHandler(object):
|
||||
"""ACME Authorization Handler for a client.
|
||||
|
||||
@@ -76,7 +79,7 @@ class AuthHandler(object):
|
||||
# While there are still challenges remaining...
|
||||
while self.dv_c or self.cont_c:
|
||||
cont_resp, dv_resp = self._solve_challenges()
|
||||
logging.info("Waiting for verification...")
|
||||
logger.info("Waiting for verification...")
|
||||
|
||||
# Send all Responses - this modifies dv_c and cont_c
|
||||
self._respond(cont_resp, dv_resp, best_effort)
|
||||
@@ -89,7 +92,7 @@ class AuthHandler(object):
|
||||
|
||||
def _choose_challenges(self, domains):
|
||||
"""Retrieve necessary challenges to satisfy server."""
|
||||
logging.info("Performing the following challenges:")
|
||||
logger.info("Performing the following challenges:")
|
||||
for dom in domains:
|
||||
path = gen_challenge_path(
|
||||
self.authzr[dom].body.challenges,
|
||||
@@ -112,8 +115,8 @@ class AuthHandler(object):
|
||||
dv_resp = self.dv_auth.perform(self.dv_c)
|
||||
# This will catch both specific types of errors.
|
||||
except errors.AuthorizationError:
|
||||
logging.critical("Failure in setting up challenges.")
|
||||
logging.info("Attempting to clean up outstanding challenges...")
|
||||
logger.critical("Failure in setting up challenges.")
|
||||
logger.info("Attempting to clean up outstanding challenges...")
|
||||
self._cleanup_challenges()
|
||||
raise
|
||||
|
||||
@@ -261,7 +264,7 @@ class AuthHandler(object):
|
||||
If achall_list is not provided, cleanup all achallenges.
|
||||
|
||||
"""
|
||||
logging.info("Cleaning up challenges")
|
||||
logger.info("Cleaning up challenges")
|
||||
|
||||
if achall_list is None:
|
||||
dv_c = self.dv_c
|
||||
@@ -342,7 +345,7 @@ def challb_to_achall(challb, key, domain):
|
||||
|
||||
"""
|
||||
chall = challb.chall
|
||||
logging.info("%s challenge for %s", chall.typ, domain)
|
||||
logger.info("%s challenge for %s", chall.typ, domain)
|
||||
|
||||
if isinstance(chall, challenges.DVSNI):
|
||||
return achallenges.DVSNI(
|
||||
@@ -432,7 +435,7 @@ def _find_smart_path(challbs, preferences, combinations):
|
||||
if not best_combo:
|
||||
msg = ("Client does not support any combination of challenges that "
|
||||
"will satisfy the CA.")
|
||||
logging.fatal(msg)
|
||||
logger.fatal(msg)
|
||||
raise errors.AuthorizationError(msg)
|
||||
|
||||
return best_combo
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
import argparse
|
||||
import atexit
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import configargparse
|
||||
import zope.component
|
||||
@@ -69,10 +71,10 @@ More detailed help:
|
||||
|
||||
|
||||
|
||||
def _account_init(args, config):
|
||||
le_util.make_or_verify_dir(
|
||||
config.config_dir, constants.CONFIG_DIRS_MODE, os.geteuid())
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _account_init(args, config):
|
||||
# Prepare for init of Client
|
||||
if args.email is None:
|
||||
return client.determine_account(config)
|
||||
@@ -112,7 +114,8 @@ def _init_acme(config, acc, authenticator, installer):
|
||||
if acc.regr is None:
|
||||
try:
|
||||
acme.register()
|
||||
except errors.LetsEncryptClientError:
|
||||
except errors.LetsEncryptClientError as error:
|
||||
logger.debug(error)
|
||||
sys.exit("Unable to register an account with ACME server")
|
||||
|
||||
return acme
|
||||
@@ -235,11 +238,11 @@ def config_changes(unused_args, config, unused_plugins):
|
||||
|
||||
def plugins_cmd(args, config, plugins): # TODO: Use IDiplay rathern than print
|
||||
"""List server software plugins."""
|
||||
logging.debug("Expected interfaces: %s", args.ifaces)
|
||||
logger.debug("Expected interfaces: %s", args.ifaces)
|
||||
|
||||
ifaces = [] if args.ifaces is None else args.ifaces
|
||||
filtered = plugins.ifaces(ifaces)
|
||||
logging.debug("Filtered plugins: %r", filtered)
|
||||
logger.debug("Filtered plugins: %r", filtered)
|
||||
|
||||
if not args.init and not args.prepare:
|
||||
print str(filtered)
|
||||
@@ -247,7 +250,7 @@ def plugins_cmd(args, config, plugins): # TODO: Use IDiplay rathern than print
|
||||
|
||||
filtered.init(config)
|
||||
verified = filtered.verify(ifaces)
|
||||
logging.debug("Verified plugins: %r", verified)
|
||||
logger.debug("Verified plugins: %r", verified)
|
||||
|
||||
if not args.prepare:
|
||||
print str(verified)
|
||||
@@ -255,7 +258,7 @@ def plugins_cmd(args, config, plugins): # TODO: Use IDiplay rathern than print
|
||||
|
||||
verified.prepare()
|
||||
available = verified.available()
|
||||
logging.debug("Prepared plugins: %s", available)
|
||||
logger.debug("Prepared plugins: %s", available)
|
||||
print str(available)
|
||||
|
||||
|
||||
@@ -558,6 +561,8 @@ def _paths_parser(helpful):
|
||||
help=config_help("config_dir"))
|
||||
add("paths", "--work-dir", default=flag_default("work_dir"),
|
||||
help=config_help("work_dir"))
|
||||
add("paths", "--logs-dir", default=flag_default("logs_dir"),
|
||||
help="Path to a directory where logs are stored.")
|
||||
add("paths", "--backup-dir", default=flag_default("backup_dir"),
|
||||
help=config_help("backup_dir"))
|
||||
add("paths", "--key-dir", default=flag_default("key_dir"),
|
||||
@@ -572,11 +577,48 @@ def _paths_parser(helpful):
|
||||
help=config_help("server"))
|
||||
|
||||
|
||||
def main(args=sys.argv[1:]):
|
||||
def _setup_logging(args):
|
||||
level = -args.verbose_count * 10
|
||||
fmt = "%(asctime)s:%(levelname)s:%(name)s:%(message)s"
|
||||
if args.text_mode:
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter(fmt))
|
||||
else:
|
||||
handler = log.DialogHandler()
|
||||
# dialog box is small, display as less as possible
|
||||
handler.setFormatter(logging.Formatter("%(message)s"))
|
||||
handler.setLevel(level)
|
||||
|
||||
# TODO: use fileConfig?
|
||||
|
||||
# unconditionally log to file for debugging purposes
|
||||
# TODO: change before release?
|
||||
log_file_name = os.path.join(args.logs_dir, 'letsencrypt.log')
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
log_file_name, maxBytes=2**20, backupCount=10)
|
||||
# rotate on each invocation, rollover only possible when maxBytes
|
||||
# is nonzero and backupCount is nonzero, so we set maxBytes as big
|
||||
# as possible not to overrun in single CLI invocation (1MB).
|
||||
file_handler.doRollover() # TODO: creates empty letsencrypt.log.1 file
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler_formatter = logging.Formatter(fmt=fmt)
|
||||
file_handler_formatter.converter = time.gmtime # don't use localtime
|
||||
file_handler.setFormatter(file_handler_formatter)
|
||||
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.DEBUG) # send all records to handlers
|
||||
root_logger.addHandler(handler)
|
||||
root_logger.addHandler(file_handler)
|
||||
|
||||
logger.debug("Root logging level set at %d", level)
|
||||
logger.info("Saving debug log to %s", log_file_name)
|
||||
|
||||
|
||||
def main(cli_args=sys.argv[1:]):
|
||||
"""Command line argument parsing and main script execution."""
|
||||
# note: arg parser internally handles --help (and exits afterwards)
|
||||
plugins = plugins_disco.PluginsRegistry.find_all()
|
||||
args = create_parser(plugins, args).parse_args(args)
|
||||
args = create_parser(plugins, cli_args).parse_args(cli_args)
|
||||
config = configuration.NamespaceConfig(args)
|
||||
|
||||
# Displayer
|
||||
@@ -586,23 +628,25 @@ def main(args=sys.argv[1:]):
|
||||
displayer = display_util.NcursesDisplay()
|
||||
zope.component.provideUtility(displayer)
|
||||
|
||||
for directory in config.config_dir, config.work_dir:
|
||||
le_util.make_or_verify_dir(
|
||||
directory, constants.CONFIG_DIRS_MODE, os.geteuid())
|
||||
# TODO: logs might contain sensitive data such as contents of the
|
||||
# private key! #525
|
||||
le_util.make_or_verify_dir(args.logs_dir, 0o700, os.geteuid())
|
||||
|
||||
_setup_logging(args)
|
||||
# do not log `args`, as it contains sensitive data (e.g. revoke --key)!
|
||||
logger.debug("Arguments: %r", cli_args)
|
||||
logger.debug("Discovered plugins: %r", plugins)
|
||||
|
||||
# Reporter
|
||||
report = reporter.Reporter()
|
||||
zope.component.provideUtility(report)
|
||||
atexit.register(report.atexit_print_messages)
|
||||
|
||||
# Logging
|
||||
level = -args.verbose_count * 10
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(level)
|
||||
logging.debug("Logging level set at %d", level)
|
||||
if not args.text_mode:
|
||||
logger.addHandler(log.DialogHandler())
|
||||
|
||||
logging.debug("Discovered plugins: %r", plugins)
|
||||
|
||||
if not os.geteuid() == 0:
|
||||
logging.warning(
|
||||
logger.warning(
|
||||
"Root (sudo) is required to run most of letsencrypt functionality.")
|
||||
# check must be done after arg parsing as --help should work
|
||||
# w/o root; on the other hand, e.g. "letsencrypt run
|
||||
|
||||
@@ -28,6 +28,9 @@ from letsencrypt.display import ops as display_ops
|
||||
from letsencrypt.display import enhancements
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""ACME protocol client.
|
||||
|
||||
@@ -145,12 +148,12 @@ class Client(object):
|
||||
if self.auth_handler is None:
|
||||
msg = ("Unable to obtain certificate because authenticator is "
|
||||
"not set.")
|
||||
logging.warning(msg)
|
||||
logger.warning(msg)
|
||||
raise errors.Error(msg)
|
||||
if self.account.regr is None:
|
||||
raise errors.Error("Please register with the ACME server first.")
|
||||
|
||||
logging.debug("CSR: %s, domains: %s", csr, domains)
|
||||
logger.debug("CSR: %s, domains: %s", csr, domains)
|
||||
|
||||
authzr = self.auth_handler.get_authorizations(domains)
|
||||
certr = self.network.request_issuance(
|
||||
@@ -238,7 +241,7 @@ class Client(object):
|
||||
|
||||
if (cli_config.config_dir != constants.CLI_DEFAULTS["config_dir"] or
|
||||
cli_config.work_dir != constants.CLI_DEFAULTS["work_dir"]):
|
||||
logging.warning(
|
||||
logger.warning(
|
||||
"Non-standard path(s), might not work with crontab installed "
|
||||
"by your operating system package manager")
|
||||
|
||||
@@ -308,8 +311,8 @@ class Client(object):
|
||||
cert_file.write(cert_pem)
|
||||
finally:
|
||||
cert_file.close()
|
||||
logging.info("Server issued certificate; certificate written to %s",
|
||||
act_cert_path)
|
||||
logger.info("Server issued certificate; certificate written to %s",
|
||||
act_cert_path)
|
||||
|
||||
if chain_cert is not None:
|
||||
chain_file, act_chain_path = le_util.unique_file(
|
||||
@@ -321,7 +324,7 @@ class Client(object):
|
||||
finally:
|
||||
chain_file.close()
|
||||
|
||||
logging.info("Cert chain written to %s", act_chain_path)
|
||||
logger.info("Cert chain written to %s", act_chain_path)
|
||||
|
||||
# This expects a valid chain file
|
||||
cert_chain_abspath = os.path.abspath(act_chain_path)
|
||||
@@ -338,8 +341,8 @@ class Client(object):
|
||||
|
||||
"""
|
||||
if self.installer is None:
|
||||
logging.warning("No installer specified, client is unable to deploy"
|
||||
"the certificate")
|
||||
logger.warning("No installer specified, client is unable to deploy"
|
||||
"the certificate")
|
||||
raise errors.Error("No installer available")
|
||||
|
||||
chain_path = None if chain_path is None else os.path.abspath(chain_path)
|
||||
@@ -374,8 +377,8 @@ class Client(object):
|
||||
|
||||
"""
|
||||
if self.installer is None:
|
||||
logging.warning("No installer is specified, there isn't any "
|
||||
"configuration to enhance.")
|
||||
logger.warning("No installer is specified, there isn't any "
|
||||
"configuration to enhance.")
|
||||
raise errors.Error("No installer available")
|
||||
|
||||
if redirect is None:
|
||||
@@ -395,7 +398,7 @@ class Client(object):
|
||||
try:
|
||||
self.installer.enhance(dom, "redirect")
|
||||
except errors.ConfiguratorError:
|
||||
logging.warn("Unable to perform redirect for %s", dom)
|
||||
logger.warn("Unable to perform redirect for %s", dom)
|
||||
|
||||
self.installer.save("Add Redirects")
|
||||
self.installer.restart()
|
||||
|
||||
@@ -15,6 +15,7 @@ CLI_DEFAULTS = dict(
|
||||
rollback_checkpoints=0,
|
||||
config_dir="/etc/letsencrypt",
|
||||
work_dir="/var/lib/letsencrypt",
|
||||
logs_dir="/var/log/letsencrypt",
|
||||
no_verify_ssl=False,
|
||||
dvsni_port=challenges.DVSNI.PORT,
|
||||
cert_path="./cert.pem",
|
||||
|
||||
@@ -18,6 +18,9 @@ import OpenSSL
|
||||
from letsencrypt import le_util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# High level functions
|
||||
def init_save_key(key_size, key_dir, keyname="key-letsencrypt.pem"):
|
||||
"""Initializes and saves a privkey.
|
||||
@@ -40,7 +43,7 @@ def init_save_key(key_size, key_dir, keyname="key-letsencrypt.pem"):
|
||||
try:
|
||||
key_pem = make_key(key_size)
|
||||
except ValueError as err:
|
||||
logging.exception(err)
|
||||
logger.exception(err)
|
||||
raise err
|
||||
|
||||
# Save file
|
||||
@@ -50,7 +53,7 @@ def init_save_key(key_size, key_dir, keyname="key-letsencrypt.pem"):
|
||||
key_f.write(key_pem)
|
||||
key_f.close()
|
||||
|
||||
logging.info("Generating key (%d bits): %s", key_size, key_path)
|
||||
logger.info("Generating key (%d bits): %s", key_size, key_path)
|
||||
|
||||
return le_util.Key(key_path, key_pem)
|
||||
|
||||
@@ -78,7 +81,7 @@ def init_save_csr(privkey, names, path, csrname="csr-letsencrypt.pem"):
|
||||
csr_f.write(csr_pem)
|
||||
csr_f.close()
|
||||
|
||||
logging.info("Creating CSR: %s", csr_filename)
|
||||
logger.info("Creating CSR: %s", csr_filename)
|
||||
|
||||
return le_util.CSR(csr_filename, csr_der, "der")
|
||||
|
||||
@@ -275,7 +278,7 @@ def _get_sans_from_cert_or_req(
|
||||
try:
|
||||
cert_or_req = load_func(typ, cert_or_req_str)
|
||||
except OpenSSL.crypto.Error as error:
|
||||
logging.exception(error)
|
||||
logger.exception(error)
|
||||
raise
|
||||
return _pyopenssl_cert_or_req_san(cert_or_req)
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ from letsencrypt import interfaces
|
||||
from letsencrypt.display import util as display_util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Define a helper function to avoid verbose code
|
||||
util = zope.component.getUtility # pylint: disable=invalid-name
|
||||
|
||||
@@ -28,7 +30,7 @@ def ask(enhancement):
|
||||
# Call the appropriate function based on the enhancement
|
||||
return DISPATCH[enhancement]()
|
||||
except KeyError:
|
||||
logging.error("Unsupported enhancement given to ask(): %s", enhancement)
|
||||
logger.error("Unsupported enhancement given to ask(): %s", enhancement)
|
||||
raise errors.Error("Unsupported Enhancement")
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ from letsencrypt import interfaces
|
||||
from letsencrypt.display import util as display_util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Define a helper function to avoid verbose code
|
||||
util = zope.component.getUtility # pylint: disable=invalid-name
|
||||
|
||||
@@ -70,7 +72,7 @@ def pick_plugin(config, default, plugins, question, ifaces):
|
||||
prepared = verified.available()
|
||||
|
||||
if len(prepared) > 1:
|
||||
logging.debug("Multiple candidate plugins: %s", prepared)
|
||||
logger.debug("Multiple candidate plugins: %s", prepared)
|
||||
plugin_ep = choose_plugin(prepared.values(), question)
|
||||
if plugin_ep is None:
|
||||
return None
|
||||
@@ -78,10 +80,10 @@ def pick_plugin(config, default, plugins, question, ifaces):
|
||||
return plugin_ep.init()
|
||||
elif len(prepared) == 1:
|
||||
plugin_ep = prepared.values()[0]
|
||||
logging.debug("Single candidate plugin: %s", plugin_ep)
|
||||
logger.debug("Single candidate plugin: %s", plugin_ep)
|
||||
return plugin_ep.init()
|
||||
else:
|
||||
logging.debug("No candidate plugin")
|
||||
logger.debug("No candidate plugin")
|
||||
return None
|
||||
|
||||
|
||||
@@ -143,7 +145,7 @@ def choose_names(installer):
|
||||
|
||||
"""
|
||||
if installer is None:
|
||||
logging.debug("No installer, picking names manually")
|
||||
logger.debug("No installer, picking names manually")
|
||||
return _choose_names_manually()
|
||||
|
||||
names = list(installer.get_all_names())
|
||||
|
||||
@@ -37,7 +37,7 @@ class DialogHandler(logging.Handler): # pylint: disable=too-few-public-methods
|
||||
lines.
|
||||
|
||||
"""
|
||||
for line in record.getMessage().splitlines():
|
||||
for line in self.format(record).splitlines():
|
||||
# check for lines that would wrap
|
||||
cur_out = line
|
||||
while len(cur_out) > self.width:
|
||||
|
||||
@@ -10,6 +10,9 @@ from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginEntryPoint(object):
|
||||
"""Plugin entry point."""
|
||||
|
||||
@@ -70,7 +73,7 @@ class PluginEntryPoint(object):
|
||||
zope.interface.verify.verifyObject(iface, self.init())
|
||||
except zope.interface.exceptions.BrokenImplementation:
|
||||
if iface.implementedBy(self.plugin_cls):
|
||||
logging.debug(
|
||||
logger.debug(
|
||||
"%s implements %s but object does "
|
||||
"not verify", self.plugin_cls, iface.__name__)
|
||||
return False
|
||||
@@ -80,7 +83,7 @@ class PluginEntryPoint(object):
|
||||
def prepared(self):
|
||||
"""Has the plugin been prepared already?"""
|
||||
if not self.initialized:
|
||||
logging.debug(".prepared called on uninitialized %r", self)
|
||||
logger.debug(".prepared called on uninitialized %r", self)
|
||||
return self._prepared is not None
|
||||
|
||||
def prepare(self):
|
||||
@@ -90,10 +93,10 @@ class PluginEntryPoint(object):
|
||||
try:
|
||||
self._initialized.prepare()
|
||||
except errors.MisconfigurationError as error:
|
||||
logging.debug("Misconfigured %r: %s", self, error)
|
||||
logger.debug("Misconfigured %r: %s", self, error)
|
||||
self._prepared = error
|
||||
except errors.NoInstallationError as error:
|
||||
logging.debug("No installation (%r): %s", self, error)
|
||||
logger.debug("No installation (%r): %s", self, error)
|
||||
self._prepared = error
|
||||
else:
|
||||
self._prepared = True
|
||||
@@ -149,7 +152,7 @@ class PluginsRegistry(collections.Mapping):
|
||||
if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):
|
||||
plugins[plugin_ep.name] = plugin_ep
|
||||
else: # pragma: no cover
|
||||
logging.warning(
|
||||
logger.warning(
|
||||
"%r does not provide IPluginFactory, skipping", plugin_ep)
|
||||
return cls(plugins)
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ from letsencrypt import interfaces
|
||||
from letsencrypt.plugins import common
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ManualAuthenticator(common.Plugin):
|
||||
"""Manual Authenticator.
|
||||
|
||||
@@ -120,17 +123,17 @@ binary for temporary key/certificate generation.""".replace("\n", "")
|
||||
|
||||
def _verify(self, achall, chall_response): # pylint: disable=no-self-use
|
||||
uri = chall_response.uri(achall.domain)
|
||||
logging.debug("Verifying %s...", uri)
|
||||
logger.debug("Verifying %s...", uri)
|
||||
try:
|
||||
response = requests.get(uri, verify=False)
|
||||
except requests.exceptions.ConnectionError as error:
|
||||
logging.exception(error)
|
||||
logger.exception(error)
|
||||
return False
|
||||
|
||||
ret = response.text == achall.token
|
||||
if not ret:
|
||||
logging.error("Unable to verify %s! Expected: %r, returned: %r.",
|
||||
uri, achall.token, response.text)
|
||||
logger.error("Unable to verify %s! Expected: %r, returned: %r.",
|
||||
uri, achall.token, response.text)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -106,6 +106,9 @@ def _paths_parser(parser):
|
||||
help=cli.config_help("config_dir"))
|
||||
add("--work-dir", default=cli.flag_default("work_dir"),
|
||||
help=cli.config_help("work_dir"))
|
||||
add("--logs-dir", default=cli.flag_default("logs_dir"),
|
||||
help="Path to a directory where logs are stored.")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ import zope.interface
|
||||
from letsencrypt import interfaces
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Reporter(object):
|
||||
"""Collects and displays information to the user.
|
||||
|
||||
@@ -48,7 +51,7 @@ class Reporter(object):
|
||||
"""
|
||||
assert self.HIGH_PRIORITY <= priority <= self.LOW_PRIORITY
|
||||
self.messages.put(self._msg_type(priority, msg, on_crash))
|
||||
logging.info("Reporting to user: %s", msg)
|
||||
logger.info("Reporting to user: %s", msg)
|
||||
|
||||
def atexit_print_messages(self, pid=os.getpid()):
|
||||
"""Function to be registered with atexit to print messages.
|
||||
|
||||
@@ -14,6 +14,9 @@ from letsencrypt import le_util
|
||||
from letsencrypt.display import util as display_util
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Reverter(object):
|
||||
"""Reverter Class - save and revert configuration checkpoints.
|
||||
|
||||
@@ -38,8 +41,8 @@ class Reverter(object):
|
||||
self._recover_checkpoint(self.config.temp_checkpoint_dir)
|
||||
except errors.ReverterError:
|
||||
# We have a partial or incomplete recovery
|
||||
logging.fatal("Incomplete or failed recovery for %s",
|
||||
self.config.temp_checkpoint_dir)
|
||||
logger.fatal("Incomplete or failed recovery for %s",
|
||||
self.config.temp_checkpoint_dir)
|
||||
raise errors.ReverterError("Unable to revert temporary config")
|
||||
|
||||
def rollback_checkpoints(self, rollback=1):
|
||||
@@ -56,26 +59,26 @@ class Reverter(object):
|
||||
try:
|
||||
rollback = int(rollback)
|
||||
except ValueError:
|
||||
logging.error("Rollback argument must be a positive integer")
|
||||
logger.error("Rollback argument must be a positive integer")
|
||||
raise errors.ReverterError("Invalid Input")
|
||||
# Sanity check input
|
||||
if rollback < 0:
|
||||
logging.error("Rollback argument must be a positive integer")
|
||||
logger.error("Rollback argument must be a positive integer")
|
||||
raise errors.ReverterError("Invalid Input")
|
||||
|
||||
backups = os.listdir(self.config.backup_dir)
|
||||
backups.sort()
|
||||
|
||||
if len(backups) < rollback:
|
||||
logging.warning("Unable to rollback %d checkpoints, only %d exist",
|
||||
rollback, len(backups))
|
||||
logger.warning("Unable to rollback %d checkpoints, only %d exist",
|
||||
rollback, len(backups))
|
||||
|
||||
while rollback > 0 and backups:
|
||||
cp_dir = os.path.join(self.config.backup_dir, backups.pop())
|
||||
try:
|
||||
self._recover_checkpoint(cp_dir)
|
||||
except errors.ReverterError:
|
||||
logging.fatal("Failed to load checkpoint during rollback")
|
||||
logger.fatal("Failed to load checkpoint during rollback")
|
||||
raise errors.ReverterError(
|
||||
"Unable to load checkpoint during rollback")
|
||||
rollback -= 1
|
||||
@@ -93,8 +96,8 @@ class Reverter(object):
|
||||
backups.sort(reverse=True)
|
||||
|
||||
if not backups:
|
||||
logging.info("The Let's Encrypt client has not saved any backups "
|
||||
"of your configuration")
|
||||
logger.info("The Let's Encrypt client has not saved any backups "
|
||||
"of your configuration")
|
||||
return
|
||||
# Make sure there isn't anything unexpected in the backup folder
|
||||
# There should only be timestamped (float) directories
|
||||
@@ -177,7 +180,7 @@ class Reverter(object):
|
||||
if filename not in existing_filepaths:
|
||||
# Tag files with index so multiple files can
|
||||
# have the same filename
|
||||
logging.debug("Creating backup of %s", filename)
|
||||
logger.debug("Creating backup of %s", filename)
|
||||
try:
|
||||
shutil.copy2(filename, os.path.join(
|
||||
cp_dir, os.path.basename(filename) + "_" + str(idx)))
|
||||
@@ -185,7 +188,7 @@ class Reverter(object):
|
||||
# http://stackoverflow.com/questions/4726260/effective-use-of-python-shutil-copy2
|
||||
except IOError:
|
||||
op_fd.close()
|
||||
logging.error(
|
||||
logger.error(
|
||||
"Unable to add file %s to checkpoint %s",
|
||||
filename, cp_dir)
|
||||
raise errors.ReverterError(
|
||||
@@ -234,7 +237,7 @@ class Reverter(object):
|
||||
os.path.basename(path) + "_" + str(idx)), path)
|
||||
except (IOError, OSError):
|
||||
# This file is required in all checkpoints.
|
||||
logging.error("Unable to recover files from %s", cp_dir)
|
||||
logger.error("Unable to recover files from %s", cp_dir)
|
||||
raise errors.ReverterError(
|
||||
"Unable to recover files from %s" % cp_dir)
|
||||
|
||||
@@ -244,7 +247,7 @@ class Reverter(object):
|
||||
try:
|
||||
shutil.rmtree(cp_dir)
|
||||
except OSError:
|
||||
logging.error("Unable to remove directory: %s", cp_dir)
|
||||
logger.error("Unable to remove directory: %s", cp_dir)
|
||||
raise errors.ReverterError(
|
||||
"Unable to remove directory: %s" % cp_dir)
|
||||
|
||||
@@ -318,7 +321,7 @@ class Reverter(object):
|
||||
if path not in ex_files:
|
||||
new_fd.write("{0}{1}".format(path, os.linesep))
|
||||
except (IOError, OSError):
|
||||
logging.error("Unable to register file creation(s) - %s", files)
|
||||
logger.error("Unable to register file creation(s) - %s", files)
|
||||
raise errors.ReverterError(
|
||||
"Unable to register file creation(s) - {0}".format(files))
|
||||
finally:
|
||||
@@ -344,9 +347,9 @@ class Reverter(object):
|
||||
self._recover_checkpoint(self.config.in_progress_dir)
|
||||
except errors.ReverterError:
|
||||
# We have a partial or incomplete recovery
|
||||
logging.fatal("Incomplete or failed recovery for IN_PROGRESS "
|
||||
"checkpoint - %s",
|
||||
self.config.in_progress_dir)
|
||||
logger.fatal("Incomplete or failed recovery for IN_PROGRESS "
|
||||
"checkpoint - %s",
|
||||
self.config.in_progress_dir)
|
||||
raise errors.ReverterError(
|
||||
"Incomplete or failed recovery for IN_PROGRESS checkpoint "
|
||||
"- %s" % self.config.in_progress_dir)
|
||||
@@ -376,12 +379,12 @@ class Reverter(object):
|
||||
if os.path.lexists(path):
|
||||
os.remove(path)
|
||||
else:
|
||||
logging.warning(
|
||||
logger.warning(
|
||||
"File: %s - Could not be found to be deleted%s"
|
||||
"LE probably shut down unexpectedly",
|
||||
os.linesep, path)
|
||||
except (IOError, OSError):
|
||||
logging.fatal(
|
||||
logger.fatal(
|
||||
"Unable to remove filepaths contained within %s", file_list)
|
||||
raise errors.ReverterError(
|
||||
"Unable to remove filepaths contained within "
|
||||
@@ -422,7 +425,7 @@ class Reverter(object):
|
||||
|
||||
shutil.move(changes_since_tmp_path, changes_since_path)
|
||||
except (IOError, OSError):
|
||||
logging.error("Unable to finalize checkpoint - adding title")
|
||||
logger.error("Unable to finalize checkpoint - adding title")
|
||||
raise errors.ReverterError("Unable to add title")
|
||||
|
||||
self._timestamp_progress_dir()
|
||||
@@ -445,7 +448,7 @@ class Reverter(object):
|
||||
cur_time += .01
|
||||
|
||||
# After 10 attempts... something is probably wrong here...
|
||||
logging.error(
|
||||
logger.error(
|
||||
"Unable to finalize checkpoint, %s -> %s",
|
||||
self.config.in_progress_dir, final_dir)
|
||||
raise errors.ReverterError(
|
||||
|
||||
@@ -26,6 +26,9 @@ from letsencrypt.display import util as display_util
|
||||
from letsencrypt.display import revocation
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Revoker(object):
|
||||
"""A revocation class for LE.
|
||||
|
||||
@@ -97,7 +100,7 @@ class Revoker(object):
|
||||
if certs:
|
||||
self._safe_revoke(certs)
|
||||
else:
|
||||
logging.info("No certificates using the authorized key were found.")
|
||||
logger.info("No certificates using the authorized key were found.")
|
||||
|
||||
def revoke_from_cert(self, cert_path):
|
||||
"""Revoke a certificate by specifying a file path.
|
||||
@@ -121,7 +124,7 @@ class Revoker(object):
|
||||
self._safe_revoke([cert])
|
||||
return
|
||||
|
||||
logging.info("Associated ACME certificate was not found.")
|
||||
logger.info("Associated ACME certificate was not found.")
|
||||
|
||||
def revoke_from_menu(self):
|
||||
"""List trusted Let's Encrypt certificates."""
|
||||
@@ -143,7 +146,7 @@ class Revoker(object):
|
||||
else:
|
||||
return
|
||||
else:
|
||||
logging.info(
|
||||
logger.info(
|
||||
"There are not any trusted Let's Encrypt "
|
||||
"certificates for this server.")
|
||||
return
|
||||
@@ -219,7 +222,7 @@ class Revoker(object):
|
||||
self._acme_revoke(cert)
|
||||
except errors.Error:
|
||||
# TODO: Improve error handling when networking is set...
|
||||
logging.error(
|
||||
logger.error(
|
||||
"Unable to revoke cert:%s%s", os.linesep, str(cert))
|
||||
success_list.append(cert)
|
||||
revocation.success_revocation(cert)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
"""Tests for letsencrypt.cli."""
|
||||
import itertools
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
@@ -8,10 +11,19 @@ import mock
|
||||
class CLITest(unittest.TestCase):
|
||||
"""Tests for different commands."""
|
||||
|
||||
@classmethod
|
||||
def _call(cls, args):
|
||||
def setUp(self):
|
||||
self.tmp_dir = tempfile.mkdtemp()
|
||||
self.config_dir = os.path.join(self.tmp_dir, 'config')
|
||||
self.work_dir = os.path.join(self.tmp_dir, 'work')
|
||||
self.logs_dir = os.path.join(self.tmp_dir, 'logs')
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
|
||||
def _call(self, args):
|
||||
from letsencrypt import cli
|
||||
args = ['--text'] + args
|
||||
args = ['--text', '--config-dir', self.config_dir,
|
||||
'--work-dir', self.work_dir, '--logs-dir', self.logs_dir] + args
|
||||
with mock.patch('letsencrypt.cli.sys.stdout') as stdout:
|
||||
with mock.patch('letsencrypt.cli.sys.stderr') as stderr:
|
||||
with mock.patch('letsencrypt.cli.client') as client:
|
||||
|
||||
@@ -175,7 +175,7 @@ class ReverterCheckpointLocalTest(unittest.TestCase):
|
||||
self.assertRaises(
|
||||
errors.ReverterError, self.reverter.revert_temporary_config)
|
||||
|
||||
@mock.patch("letsencrypt.reverter.logging.warning")
|
||||
@mock.patch("letsencrypt.reverter.logger.warning")
|
||||
def test_recover_checkpoint_missing_new_files(self, mock_warn):
|
||||
self.reverter.register_file_creation(
|
||||
True, os.path.join(self.dir1, "missing_file.txt"))
|
||||
@@ -303,10 +303,10 @@ class TestFullCheckpointsReverter(unittest.TestCase):
|
||||
self.assertRaises(
|
||||
errors.ReverterError, self.reverter.finalize_checkpoint, "Title")
|
||||
|
||||
@mock.patch("letsencrypt.reverter.logging")
|
||||
def test_rollback_too_many(self, mock_logging):
|
||||
@mock.patch("letsencrypt.reverter.logger")
|
||||
def test_rollback_too_many(self, mock_logger):
|
||||
self.reverter.rollback_checkpoints(1)
|
||||
self.assertEqual(mock_logging.warning.call_count, 1)
|
||||
self.assertEqual(mock_logger.warning.call_count, 1)
|
||||
|
||||
def test_multi_rollback(self):
|
||||
config3 = self._setup_three_checkpoints()
|
||||
@@ -327,10 +327,10 @@ class TestFullCheckpointsReverter(unittest.TestCase):
|
||||
# Make sure notification is output
|
||||
self.assertEqual(mock_output().notification.call_count, 1)
|
||||
|
||||
@mock.patch("letsencrypt.reverter.logging")
|
||||
def test_view_config_changes_no_backups(self, mock_logging):
|
||||
@mock.patch("letsencrypt.reverter.logger")
|
||||
def test_view_config_changes_no_backups(self, mock_logger):
|
||||
self.reverter.view_config_changes()
|
||||
self.assertTrue(mock_logging.info.call_count > 0)
|
||||
self.assertTrue(mock_logger.info.call_count > 0)
|
||||
|
||||
def test_view_config_changes_bad_backups_dir(self):
|
||||
# There shouldn't be any "in progess directories when this is called
|
||||
|
||||
@@ -162,7 +162,7 @@ class RevokerTest(RevokerBase):
|
||||
self.assertEqual(mock_net.call_count, 1)
|
||||
self.assertEqual(mock_display.more_info_cert.call_count, 1)
|
||||
|
||||
@mock.patch("letsencrypt.revoker.logging")
|
||||
@mock.patch("letsencrypt.revoker.logger")
|
||||
@mock.patch("letsencrypt.network.Network.revoke")
|
||||
@mock.patch("letsencrypt.revoker.revocation")
|
||||
def test_revoke_by_menu_delete_all(self, mock_display, mock_net, mock_log):
|
||||
@@ -183,7 +183,7 @@ class RevokerTest(RevokerBase):
|
||||
|
||||
@mock.patch("letsencrypt.revoker.revocation")
|
||||
@mock.patch("letsencrypt.revoker.Revoker._acme_revoke")
|
||||
@mock.patch("letsencrypt.revoker.logging")
|
||||
@mock.patch("letsencrypt.revoker.logger")
|
||||
def test_safe_revoke_acme_fail(self, mock_log, mock_revoke, mock_display):
|
||||
# pylint: disable=protected-access
|
||||
mock_revoke.side_effect = errors.Error
|
||||
|
||||
@@ -6,6 +6,8 @@ import augeas
|
||||
from letsencrypt import reverter
|
||||
from letsencrypt.plugins import common
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AugeasConfigurator(common.Plugin):
|
||||
"""Base Augeas Configurator class.
|
||||
@@ -52,7 +54,7 @@ class AugeasConfigurator(common.Plugin):
|
||||
lens_path = self.aug.get(path + "/lens")
|
||||
# As aug.get may return null
|
||||
if lens_path and lens in lens_path:
|
||||
logging.error(
|
||||
logger.error(
|
||||
"There has been an error in parsing the file (%s): %s",
|
||||
# Strip off /augeas/files and /error
|
||||
path[13:len(path) - 6], self.aug.get(path + "/message"))
|
||||
@@ -121,11 +123,11 @@ class AugeasConfigurator(common.Plugin):
|
||||
"""
|
||||
# Check for the root of save problems
|
||||
new_errs = self.aug.match("/augeas//error")
|
||||
# logging.error("During Save - %s", mod_conf)
|
||||
logging.error("Unable to save files: %s. Attempted Save Notes: %s",
|
||||
", ".join(err[13:len(err) - 6] for err in new_errs
|
||||
# Only new errors caused by recent save
|
||||
if err not in ex_errs), self.save_notes)
|
||||
# logger.error("During Save - %s", mod_conf)
|
||||
logger.error("Unable to save files: %s. Attempted Save Notes: %s",
|
||||
", ".join(err[13:len(err) - 6] for err in new_errs
|
||||
# Only new errors caused by recent save
|
||||
if err not in ex_errs), self.save_notes)
|
||||
|
||||
# Wrapper functions for Reverter class
|
||||
def recovery_routine(self):
|
||||
|
||||
@@ -27,6 +27,9 @@ from letsencrypt_apache import obj
|
||||
from letsencrypt_apache import parser
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO: Augeas sections ie. <VirtualHost>, <IfModule> beginning and closing
|
||||
# tags need to be the same case, otherwise Augeas doesn't recognize them.
|
||||
# This is not able to be completely remedied by regular expressions because
|
||||
@@ -186,13 +189,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
if not path["cert_path"] or not path["cert_key"]:
|
||||
# Throw some can't find all of the directives error"
|
||||
logging.warn(
|
||||
logger.warn(
|
||||
"Cannot find a cert or key directive in %s. "
|
||||
"VirtualHost was not modified", vhost.path)
|
||||
# Presumably break here so that the virtualhost is not modified
|
||||
return False
|
||||
|
||||
logging.info("Deploying Certificate to VirtualHost %s", vhost.filep)
|
||||
logger.info("Deploying Certificate to VirtualHost %s", vhost.filep)
|
||||
|
||||
self.aug.set(path["cert_path"][0], cert_path)
|
||||
self.aug.set(path["cert_key"][0], key_path)
|
||||
@@ -257,7 +260,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
if vhost is not None:
|
||||
self.assoc[target_name] = vhost
|
||||
else:
|
||||
logging.error(
|
||||
logger.error(
|
||||
"No vhost exists with servername or alias of: %s. "
|
||||
"No vhost was selected. Please specify servernames "
|
||||
"in the Apache config", target_name)
|
||||
@@ -421,15 +424,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
"""
|
||||
if not self.mod_loaded("ssl_module"):
|
||||
logging.info("Loading mod_ssl into Apache Server")
|
||||
logger.info("Loading mod_ssl into Apache Server")
|
||||
self.enable_mod("ssl")
|
||||
|
||||
# Check for Listen 443
|
||||
# Note: This could be made to also look for ip:443 combo
|
||||
# TODO: Need to search only open directives and IfMod mod_ssl.c
|
||||
if len(self.parser.find_dir(parser.case_i("Listen"), "443")) == 0:
|
||||
logging.debug("No Listen 443 directive found. Setting the "
|
||||
"Apache Server to Listen on port 443")
|
||||
logger.debug("No Listen 443 directive found. Setting the "
|
||||
"Apache Server to Listen on port 443")
|
||||
path = self.parser.add_dir_to_ifmodssl(
|
||||
parser.get_aug_path(self.parser.loc["listen"]), "Listen", "443")
|
||||
self.save_notes += "Added Listen 443 directive to %s\n" % path
|
||||
@@ -450,15 +453,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
for addr in vhost.addrs:
|
||||
if addr.get_addr() == "_default_":
|
||||
if not self.is_name_vhost(default_addr):
|
||||
logging.debug("Setting all VirtualHosts on %s to be "
|
||||
"name based vhosts", default_addr)
|
||||
logger.debug("Setting all VirtualHosts on %s to be "
|
||||
"name based vhosts", default_addr)
|
||||
self.add_name_vhost(default_addr)
|
||||
|
||||
# No default addresses... so set each one individually
|
||||
for addr in vhost.addrs:
|
||||
if not self.is_name_vhost(addr):
|
||||
logging.debug("Setting VirtualHost at %s to be a name "
|
||||
"based virtual host", addr)
|
||||
logger.debug("Setting VirtualHost at %s to be a name "
|
||||
"based virtual host", addr)
|
||||
self.add_name_vhost(addr)
|
||||
|
||||
def make_vhost_ssl(self, nonssl_vhost): # pylint: disable=too-many-locals
|
||||
@@ -499,7 +502,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
new_file.write(line)
|
||||
new_file.write("</IfModule>\n")
|
||||
except IOError:
|
||||
logging.fatal("Error writing/reading to file in make_vhost_ssl")
|
||||
logger.fatal("Error writing/reading to file in make_vhost_ssl")
|
||||
sys.exit(49)
|
||||
|
||||
self.aug.load()
|
||||
@@ -522,8 +525,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" %
|
||||
(ssl_fp, parser.case_i("VirtualHost")))
|
||||
if len(vh_p) != 1:
|
||||
logging.error("Error: should only be one vhost in %s", avail_fp)
|
||||
raise errors.ConfiguratorError
|
||||
logger.error("Error: should only be one vhost in %s", avail_fp)
|
||||
raise errors.ConfiguratorError("Only one vhost per file is allowed")
|
||||
|
||||
self.parser.add_dir(vh_p[0], "SSLCertificateFile",
|
||||
"/etc/ssl/certs/ssl-cert-snakeoil.pem")
|
||||
@@ -532,7 +535,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
self.parser.add_dir(vh_p[0], "Include", self.parser.loc["ssl_options"])
|
||||
|
||||
# Log actions and create save notes
|
||||
logging.info("Created an SSL vhost at %s", ssl_fp)
|
||||
logger.info("Created an SSL vhost at %s", ssl_fp)
|
||||
self.save_notes += "Created ssl vhost at %s\n" % ssl_fp
|
||||
self.save()
|
||||
|
||||
@@ -551,7 +554,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
if (ssl_vhost.filep != vhost.filep and addr in vhost.addrs and
|
||||
not self.is_name_vhost(addr)):
|
||||
self.add_name_vhost(addr)
|
||||
logging.info("Enabling NameVirtualHosts on %s", addr)
|
||||
logger.info("Enabling NameVirtualHosts on %s", addr)
|
||||
need_to_save = True
|
||||
|
||||
if need_to_save:
|
||||
@@ -581,7 +584,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
raise errors.ConfiguratorError(
|
||||
"Unsupported enhancement: {}".format(enhancement))
|
||||
except errors.ConfiguratorError:
|
||||
logging.warn("Failed %s for %s", enhancement, domain)
|
||||
logger.warn("Failed %s for %s", enhancement, domain)
|
||||
|
||||
def _enable_redirect(self, ssl_vhost, unused_options):
|
||||
"""Redirect all equivalent HTTP traffic to ssl_vhost.
|
||||
@@ -612,7 +615,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
general_v = self._general_vhost(ssl_vhost)
|
||||
if general_v is None:
|
||||
# Add virtual_server with redirect
|
||||
logging.debug(
|
||||
logger.debug(
|
||||
"Did not find http version of ssl virtual host... creating")
|
||||
return self._create_redirect_vhost(ssl_vhost)
|
||||
else:
|
||||
@@ -620,12 +623,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
exists, code = self._existing_redirect(general_v)
|
||||
if exists:
|
||||
if code == 0:
|
||||
logging.debug("Redirect already added")
|
||||
logging.info(
|
||||
logger.debug("Redirect already added")
|
||||
logger.info(
|
||||
"Configuration is already redirecting traffic to HTTPS")
|
||||
return
|
||||
else:
|
||||
logging.info("Unknown redirect exists for this vhost")
|
||||
logger.info("Unknown redirect exists for this vhost")
|
||||
raise errors.ConfiguratorError(
|
||||
"Unknown redirect already exists "
|
||||
"in {}".format(general_v.filep))
|
||||
@@ -637,8 +640,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
(general_v.filep, ssl_vhost.filep))
|
||||
self.save()
|
||||
|
||||
logging.info("Redirecting vhost in %s to ssl vhost in %s",
|
||||
general_v.filep, ssl_vhost.filep)
|
||||
logger.info("Redirecting vhost in %s to ssl vhost in %s",
|
||||
general_v.filep, ssl_vhost.filep)
|
||||
|
||||
def _existing_redirect(self, vhost):
|
||||
"""Checks to see if existing redirect is in place.
|
||||
@@ -748,7 +751,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
# Write out file
|
||||
with open(redirect_filepath, "w") as redirect_fd:
|
||||
redirect_fd.write(redirect_file)
|
||||
logging.info("Created redirect file: %s", redirect_filename)
|
||||
logger.info("Created redirect file: %s", redirect_filename)
|
||||
|
||||
self.aug.load()
|
||||
# Make a new vhost data structure and add it to the lists
|
||||
@@ -862,8 +865,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
|
||||
# Can be removed once find directive can return ordered results
|
||||
if len(cert_path) != 1 or len(key_path) != 1:
|
||||
logging.error("Too many cert or key directives in vhost %s",
|
||||
vhost.filep)
|
||||
logger.error("Too many cert or key directives in vhost %s",
|
||||
vhost.filep)
|
||||
sys.exit(40)
|
||||
|
||||
cert = os.path.abspath(self.aug.get(cert_path[0]))
|
||||
@@ -913,7 +916,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
self.reverter.register_file_creation(False, enabled_path)
|
||||
os.symlink(vhost.filep, enabled_path)
|
||||
vhost.enabled = True
|
||||
logging.info("Enabling available site: %s", vhost.filep)
|
||||
logger.info("Enabling available site: %s", vhost.filep)
|
||||
self.save_notes += "Enabled site %s\n" % vhost.filep
|
||||
return True
|
||||
return False
|
||||
@@ -934,7 +937,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
stderr=open("/dev/null", "w"))
|
||||
apache_restart(self.conf("init"))
|
||||
except (OSError, subprocess.CalledProcessError):
|
||||
logging.exception("Error enabling mod_%s", mod_name)
|
||||
logger.exception("Error enabling mod_%s", mod_name)
|
||||
sys.exit(1)
|
||||
|
||||
def mod_loaded(self, module):
|
||||
@@ -955,12 +958,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
stdout, stderr = proc.communicate()
|
||||
|
||||
except (OSError, ValueError):
|
||||
logging.error(
|
||||
logger.error(
|
||||
"Error accessing %s for loaded modules!", self.conf("ctl"))
|
||||
raise errors.ConfiguratorError("Error accessing loaded modules")
|
||||
# Small errors that do not impede
|
||||
if proc.returncode != 0:
|
||||
logging.warn("Error in checking loaded module list: %s", stderr)
|
||||
logger.warn("Error in checking loaded module list: %s", stderr)
|
||||
raise errors.MisconfigurationError(
|
||||
"Apache is unable to check whether or not the module is "
|
||||
"loaded because Apache is misconfigured.")
|
||||
@@ -992,12 +995,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
except (OSError, ValueError):
|
||||
logging.fatal("Unable to run /usr/sbin/apache2ctl configtest")
|
||||
logger.fatal("Unable to run /usr/sbin/apache2ctl configtest")
|
||||
sys.exit(1)
|
||||
|
||||
if proc.returncode != 0:
|
||||
# Enter recovery routine...
|
||||
logging.error("Configtest failed\n%s\n%s", stdout, stderr)
|
||||
logger.error("Configtest failed\n%s\n%s", stdout, stderr)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -1131,11 +1134,11 @@ def apache_restart(apache_init_script):
|
||||
|
||||
if proc.returncode != 0:
|
||||
# Enter recovery routine...
|
||||
logging.error("Apache Restart Failed!\n%s\n%s", stdout, stderr)
|
||||
logger.error("Apache Restart Failed!\n%s\n%s", stdout, stderr)
|
||||
return False
|
||||
|
||||
except (OSError, ValueError):
|
||||
logging.fatal(
|
||||
logger.fatal(
|
||||
"Apache Restart Failed - Please Check the Configuration")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ class ApacheParser(object):
|
||||
# validChars = re.compile("[a-zA-Z0-9.*?_-/]*")
|
||||
# matchObj = validChars.match(arg)
|
||||
# if matchObj.group() != arg:
|
||||
# logging.error("Error: Invalid regexp characters in %s", arg)
|
||||
# logger.error("Error: Invalid regexp characters in %s", arg)
|
||||
# return []
|
||||
|
||||
# Standardize the include argument based on server root
|
||||
|
||||
@@ -26,6 +26,9 @@ from letsencrypt_nginx import obj
|
||||
from letsencrypt_nginx import parser
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NginxConfigurator(common.Plugin):
|
||||
# pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||
"""Nginx configurator.
|
||||
@@ -128,10 +131,10 @@ class NginxConfigurator(common.Plugin):
|
||||
try:
|
||||
self.parser.add_server_directives(vhost.filep, vhost.names,
|
||||
directives, True)
|
||||
logging.info("Deployed Certificate to VirtualHost %s for %s",
|
||||
vhost.filep, vhost.names)
|
||||
logger.info("Deployed Certificate to VirtualHost %s for %s",
|
||||
vhost.filep, vhost.names)
|
||||
except errors.MisconfigurationError:
|
||||
logging.warn(
|
||||
logger.warn(
|
||||
"Cannot find a cert or key directive in %s for %s. "
|
||||
"VirtualHost was not modified.", vhost.filep, vhost.names)
|
||||
# Presumably break here so that the virtualhost is not modified
|
||||
@@ -320,7 +323,7 @@ class NginxConfigurator(common.Plugin):
|
||||
raise errors.ConfiguratorError(
|
||||
"Unsupported enhancement: {0}".format(enhancement))
|
||||
except errors.ConfiguratorError:
|
||||
logging.warn("Failed %s for %s", enhancement, domain)
|
||||
logger.warn("Failed %s for %s", enhancement, domain)
|
||||
|
||||
######################################
|
||||
# Nginx server management (IInstaller)
|
||||
@@ -348,12 +351,12 @@ class NginxConfigurator(common.Plugin):
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
except (OSError, ValueError):
|
||||
logging.fatal("Unable to run nginx config test")
|
||||
logger.fatal("Unable to run nginx config test")
|
||||
sys.exit(1)
|
||||
|
||||
if proc.returncode != 0:
|
||||
# Enter recovery routine...
|
||||
logging.error("Config test failed\n%s\n%s", stdout, stderr)
|
||||
logger.error("Config test failed\n%s\n%s", stdout, stderr)
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -566,11 +569,11 @@ def nginx_restart(nginx_ctl):
|
||||
|
||||
if nginx_proc.returncode != 0:
|
||||
# Enter recovery routine...
|
||||
logging.error("Nginx Restart Failed!\n%s\n%s", stdout, stderr)
|
||||
logger.error("Nginx Restart Failed!\n%s\n%s", stdout, stderr)
|
||||
return False
|
||||
|
||||
except (OSError, ValueError):
|
||||
logging.fatal("Nginx Restart Failed - Please Check the Configuration")
|
||||
logger.fatal("Nginx Restart Failed - Please Check the Configuration")
|
||||
sys.exit(1)
|
||||
|
||||
return True
|
||||
|
||||
@@ -10,6 +10,9 @@ from letsencrypt_nginx import obj
|
||||
from letsencrypt_nginx import nginxparser
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NginxDvsni(common.Dvsni):
|
||||
"""Class performs DVSNI challenges within the Nginx configurator.
|
||||
|
||||
@@ -49,7 +52,7 @@ class NginxDvsni(common.Dvsni):
|
||||
for achall in self.achalls:
|
||||
vhost = self.configurator.choose_vhost(achall.domain)
|
||||
if vhost is None:
|
||||
logging.error(
|
||||
logger.error(
|
||||
"No nginx vhost exists with server_name matching: %s. "
|
||||
"Please specify server_names in the Nginx config.",
|
||||
achall.domain)
|
||||
|
||||
@@ -11,6 +11,9 @@ from letsencrypt_nginx import obj
|
||||
from letsencrypt_nginx import nginxparser
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NginxParser(object):
|
||||
"""Class handles the fine details of parsing the Nginx Configuration.
|
||||
|
||||
@@ -161,9 +164,9 @@ class NginxParser(object):
|
||||
self.parsed[item] = parsed
|
||||
trees.append(parsed)
|
||||
except IOError:
|
||||
logging.warn("Could not open file: %s", item)
|
||||
logger.warn("Could not open file: %s", item)
|
||||
except pyparsing.ParseException:
|
||||
logging.debug("Could not parse file: %s", item)
|
||||
logger.debug("Could not parse file: %s", item)
|
||||
return trees
|
||||
|
||||
def _set_locations(self, ssl_options):
|
||||
@@ -213,7 +216,7 @@ class NginxParser(object):
|
||||
with open(filename, 'w') as _file:
|
||||
nginxparser.dump(tree, _file)
|
||||
except IOError:
|
||||
logging.error("Could not open file for writing: %s", filename)
|
||||
logger.error("Could not open file for writing: %s", filename)
|
||||
|
||||
def _has_server_names(self, entry, names):
|
||||
"""Checks if a server block has the given set of server_names. This
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
root="$(mktemp -d)"
|
||||
echo "\nRoot integration tests directory: $root"
|
||||
store_flags="--config-dir $root/conf --work-dir $root/work"
|
||||
store_flags="$store_flags --logs-dir $root/logs"
|
||||
|
||||
common() {
|
||||
# first three flags required, rest is handy defaults
|
||||
|
||||
Reference in New Issue
Block a user