Merge pull request #324 from letsencrypt/plugins_dir

Move IAuthenticators and IInstallers to plugins directory
This commit is contained in:
James Kasten 2015-03-27 15:51:11 -07:00
commit 60a52943f6
62 changed files with 288 additions and 236 deletions

View file

@ -1,29 +0,0 @@
:mod:`letsencrypt.client.apache`
--------------------------------
.. automodule:: letsencrypt.client.apache
:members:
:mod:`letsencrypt.client.apache.configurator`
=============================================
.. automodule:: letsencrypt.client.apache.configurator
:members:
:mod:`letsencrypt.client.apache.dvsni`
=============================================
.. automodule:: letsencrypt.client.apache.dvsni
:members:
:mod:`letsencrypt.client.apache.obj`
====================================
.. automodule:: letsencrypt.client.apache.obj
:members:
:mod:`letsencrypt.client.apache.parser`
=======================================
.. automodule:: letsencrypt.client.apache.parser
:members:

View file

@ -0,0 +1,29 @@
:mod:`letsencrypt.client.plugins.apache`
----------------------------------------
.. automodule:: letsencrypt.client.plugins.apache
:members:
:mod:`letsencrypt.client.plugins.apache.configurator`
=====================================================
.. automodule:: letsencrypt.client.plugins.apache.configurator
:members:
:mod:`letsencrypt.client.plugins.apache.dvsni`
==============================================
.. automodule:: letsencrypt.client.plugins.apache.dvsni
:members:
:mod:`letsencrypt.client.plugins.apache.obj`
============================================
.. automodule:: letsencrypt.client.plugins.apache.obj
:members:
:mod:`letsencrypt.client.plugins.apache.parser`
===============================================
.. automodule:: letsencrypt.client.plugins.apache.parser
:members:

View file

@ -0,0 +1,11 @@
:mod:`letsencrypt.client.plugins.standalone`
--------------------------------------------
.. automodule:: letsencrypt.client.plugins.standalone
:members:
:mod:`letsencrypt.client.plugins.standalone.authenticator`
==========================================================
.. automodule:: letsencrypt.client.plugins.standalone.authenticator
:members:

View file

@ -1,5 +0,0 @@
:mod:`letsencrypt.client.standalone_authenticator`
--------------------------------------------------
.. automodule:: letsencrypt.client.standalone_authenticator
:members:

View file

@ -14,3 +14,5 @@ class Authenticator(object):
# Implement all methods from IAuthenticator, remembering to add
# "self" as first argument, e.g. def prepare(self)...
# For full examples, see letsencrypt.client.plugins

View file

@ -1 +0,0 @@
"""Let's Encrypt client.apache."""

View file

@ -18,7 +18,7 @@ from letsencrypt.client import network
from letsencrypt.client import reverter
from letsencrypt.client import revoker
from letsencrypt.client.apache import configurator
from letsencrypt.client.plugins.apache import configurator
from letsencrypt.client.display import ops as display_ops
from letsencrypt.client.display import enhancements

View file

@ -31,7 +31,7 @@ List of expected options parameters:
APACHE_MOD_SSL_CONF = pkg_resources.resource_filename(
"letsencrypt.client.apache", "options-ssl.conf")
"letsencrypt.client.plugins.apache", "options-ssl.conf")
"""Path to the Apache mod_ssl config file found in the Let's Encrypt
distribution."""

View file

@ -0,0 +1 @@
"""Let's Encrypt client.plugins."""

View file

@ -0,0 +1 @@
"""Let's Encrypt client.plugins.apache."""

View file

@ -18,9 +18,9 @@ from letsencrypt.client import errors
from letsencrypt.client import interfaces
from letsencrypt.client import le_util
from letsencrypt.client.apache import dvsni
from letsencrypt.client.apache import obj
from letsencrypt.client.apache import parser
from letsencrypt.client.plugins.apache import dvsni
from letsencrypt.client.plugins.apache import obj
from letsencrypt.client.plugins.apache import parser
# TODO: Augeas sections ie. <VirtualHost>, <IfModule> beginning and closing
@ -68,11 +68,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:type config: :class:`~letsencrypt.client.interfaces.IConfig`
:ivar parser: Handles low level parsing
:type parser: :class:`letsencrypt.client.apache.parser`
:type parser: :class:`~letsencrypt.client.plugins.apache.parser`
:ivar tup version: version of Apache
:ivar list vhosts: All vhosts found in the configuration
(:class:`list` of :class:`letsencrypt.client.apache.obj.VirtualHost`)
(:class:`list` of
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`)
:ivar dict assoc: Mapping between domains and vhosts
@ -164,7 +165,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
parser.case_i("SSLCertificateChainFile"), None, vhost.path)
if len(path["cert_file"]) == 0 or len(path["cert_key"]) == 0:
# Throw some "can't find all of the directives error"
# Throw some can't find all of the directives error"
logging.warn(
"Cannot find a cert or key directive in %s", vhost.path)
logging.warn("VirtualHost was not modified")
@ -203,7 +204,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str target_name: domain name
:returns: ssl vhost associated with name
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
:rtype: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
"""
# Allows for domain names to be associated with a virtual host
@ -223,7 +224,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.assoc[target_name] = vhost
return vhost
# Check for non ssl vhosts with servernames/aliases == 'name'
# Check for non ssl vhosts with servernames/aliases == "name"
for vhost in self.vhosts:
if not vhost.ssl and target_name in vhost.names:
vhost = self.make_vhost_ssl(vhost)
@ -244,7 +245,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str domain: domain name to associate
:param vhost: virtual host to associate with domain
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type vhost: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
"""
self.assoc[domain] = vhost
@ -281,15 +282,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Helper function for get_virtual_hosts().
:param host: In progress vhost whose names will be added
:type host: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type host: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
"""
name_match = self.aug.match(("%s//*[self::directive=~regexp('%s')] | "
"%s//*[self::directive=~regexp('%s')]" %
(host.path,
parser.case_i('ServerName'),
parser.case_i("ServerName"),
host.path,
parser.case_i('ServerAlias'))))
parser.case_i("ServerAlias"))))
for name in name_match:
args = self.aug.match(name + "/*")
@ -302,7 +303,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str path: Augeas path to virtual host
:returns: newly created vhost
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
:rtype: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
"""
addrs = set()
@ -326,7 +327,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Returns list of virtual hosts found in the Apache configuration.
:returns: List of
:class:`letsencrypt.client.apache.obj.VirtualHost` objects
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost` objects
found in configuration
:rtype: list
@ -334,7 +335,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Search sites-available, httpd.conf for possible virtual hosts
paths = self.aug.match(
("/files%s/sites-available//*[label()=~regexp('%s')]" %
(self.parser.root, parser.case_i('VirtualHost'))))
(self.parser.root, parser.case_i("VirtualHost"))))
vhs = []
for path in paths:
@ -404,7 +405,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Checks to see if the server is ready for SNI challenges.
:param vhost: VirtualHost to check SNI compatibility
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type vhost: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:param str default_addr: TODO - investigate function further
@ -436,10 +437,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. note:: This function saves the configuration
:param nonssl_vhost: Valid VH that doesn't have SSLEngine on
:type nonssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type nonssl_vhost:
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: SSL vhost
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost`
:rtype: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
"""
avail_fp = nonssl_vhost.filep
@ -454,8 +456,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.reverter.register_file_creation(False, ssl_fp)
try:
with open(avail_fp, 'r') as orig_file:
with open(ssl_fp, 'w') as new_file:
with open(avail_fp, "r") as orig_file:
with open(ssl_fp, "w") as new_file:
new_file.write("<IfModule mod_ssl.c>\n")
for line in orig_file:
new_file.write(line)
@ -471,7 +473,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# change address to address:443
addr_match = "/files%s//* [label()=~regexp('%s')]/arg"
ssl_addr_p = self.aug.match(
addr_match % (ssl_fp, parser.case_i('VirtualHost')))
addr_match % (ssl_fp, parser.case_i("VirtualHost")))
for addr in ssl_addr_p:
old_addr = obj.Addr.fromstring(
@ -482,7 +484,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Add directives
vh_p = self.aug.match("/files%s//* [label()=~regexp('%s')]" %
(ssl_fp, parser.case_i('VirtualHost')))
(ssl_fp, parser.case_i("VirtualHost")))
if len(vh_p) != 1:
logging.error("Error: should only be one vhost in %s", avail_fp)
sys.exit(1)
@ -495,7 +497,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Log actions and create save notes
logging.info("Created an SSL vhost at %s", ssl_fp)
self.save_notes += 'Created ssl vhost at %s\n' % ssl_fp
self.save_notes += "Created ssl vhost at %s\n" % ssl_fp
self.save()
# We know the length is one because of the assertion above
@ -559,13 +561,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. note:: This function saves the configuration
:param ssl_vhost: Destination of traffic, an ssl enabled vhost
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type ssl_vhost:
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:param unused_options: Not currently used
:type unused_options: Not Available
:returns: Success, general_vhost (HTTP vhost)
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
:rtype: (bool,
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`)
"""
if not mod_loaded("rewrite_module", self.config.apache_ctl):
@ -596,7 +600,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.parser.add_dir(general_v.path, "RewriteEngine", "On")
self.parser.add_dir(general_v.path, "RewriteRule",
constants.APACHE_REWRITE_HTTPS_ARGS)
self.save_notes += ('Redirecting host in %s to ssl vhost in %s\n' %
self.save_notes += ("Redirecting host in %s to ssl vhost in %s\n" %
(general_v.filep, ssl_vhost.filep))
self.save()
@ -617,7 +621,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
-1 is also returned in case of no redirection/rewrite directives
:param vhost: vhost to check
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type vhost: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: Success, code value... see documentation
:rtype: bool, int
@ -649,10 +653,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
:param ssl_vhost: ssl vhost
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type ssl_vhost:
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: Success, vhost
:rtype: (bool, :class:`letsencrypt.client.apache.obj.VirtualHost`)
:returns: tuple of the form
(`success`,
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`)
:rtype: tuple
"""
# Consider changing this to a dictionary check
@ -700,7 +707,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
redirect_filename = "le-redirect-%s.conf" % ssl_vhost.names[0]
redirect_filepath = os.path.join(
self.parser.root, 'sites-available', redirect_filename)
self.parser.root, "sites-available", redirect_filename)
# Register the new file that will be created
# Note: always register the creation before writing to ensure file will
@ -708,7 +715,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.reverter.register_file_creation(False, redirect_filepath)
# Write out file
with open(redirect_filepath, 'w') as redirect_fd:
with open(redirect_filepath, "w") as redirect_fd:
redirect_fd.write(redirect_file)
logging.info("Created redirect file: %s", redirect_filename)
@ -718,8 +725,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.vhosts.append(new_vhost)
# Finally create documentation for the change
self.save_notes += ('Created a port 80 vhost, %s, for redirection to '
'ssl vhost %s\n' %
self.save_notes += ("Created a port 80 vhost, %s, for redirection to "
"ssl vhost %s\n" %
(new_vhost.filep, ssl_vhost.filep))
def _conflicting_host(self, ssl_vhost):
@ -734,7 +741,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if not conflict: returns space separated list of new host addrs
:param ssl_vhost: SSL Vhost to check for possible port 80 redirection
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type ssl_vhost:
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: TODO
:rtype: TODO
@ -767,10 +775,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Consider changing this into a dict check
:param ssl_vhost: ssl vhost to check
:type ssl_vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type ssl_vhost:
:class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: HTTP vhost or None if unsuccessful
:rtype: :class:`letsencrypt.client.apache.obj.VirtualHost` or None
:rtype: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
or None
"""
# _default_:443 check
@ -860,7 +870,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
.. todo:: Make sure link is not broken...
:param vhost: vhost to enable
:type vhost: :class:`letsencrypt.client.apache.obj.VirtualHost`
:type vhost: :class:`~letsencrypt.client.plugins.apache.obj.VirtualHost`
:returns: Success
:rtype: bool
@ -876,7 +886,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
os.symlink(vhost.filep, enabled_path)
vhost.enabled = True
logging.info("Enabling available site: %s", vhost.filep)
self.save_notes += 'Enabled site %s\n' % vhost.filep
self.save_notes += "Enabled site %s\n" % vhost.filep
return True
return False
@ -898,7 +908,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
proc = subprocess.Popen(
['sudo', self.config.apache_ctl, 'configtest'], # TODO: sudo?
["sudo", self.config.apache_ctl, "configtest"], # TODO: sudo?
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
@ -942,7 +952,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
proc = subprocess.Popen(
[self.config.apache_ctl, '-v'],
[self.config.apache_ctl, "-v"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
text = proc.communicate()[0]
@ -957,7 +967,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
raise errors.LetsEncryptConfiguratorError(
"Unable to find Apache version")
return tuple([int(i) for i in matches[0].split('.')])
return tuple([int(i) for i in matches[0].split(".")])
def more_info(self):
"""Human-readable string to help understand the module"""
@ -1032,8 +1042,8 @@ def enable_mod(mod_name, apache_init_script, apache_enmod):
# Use check_output so the command will finish before reloading
# TODO: a2enmod is debian specific...
subprocess.check_call(["sudo", apache_enmod, mod_name], # TODO: sudo?
stdout=open("/dev/null", 'w'),
stderr=open("/dev/null", 'w'))
stdout=open("/dev/null", "w"),
stderr=open("/dev/null", "w"))
apache_restart(apache_init_script)
except (OSError, subprocess.CalledProcessError) as err:
logging.error("Error enabling mod_%s", mod_name)
@ -1055,7 +1065,7 @@ def mod_loaded(module, apache_ctl):
"""
try:
proc = subprocess.Popen(
[apache_ctl, '-M'],
[apache_ctl, "-M"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
@ -1093,7 +1103,7 @@ def apache_restart(apache_init_script):
"""
try:
proc = subprocess.Popen([apache_init_script, 'restart'],
proc = subprocess.Popen([apache_init_script, "restart"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()

View file

@ -2,20 +2,19 @@
import logging
import os
from letsencrypt.client.apache import parser
from letsencrypt.client.plugins.apache import parser
class ApacheDvsni(object):
"""Class performs DVSNI challenges within the Apache configurator.
:ivar configurator: ApacheConfigurator object
:type configurator:
:class:`letsencrypt.client.apache.configurator.ApacheConfigurator`
:type configurator: :class:`~apache.configurator.ApacheConfigurator`
:ivar list achalls: Annotated :class:`~letsencrypt.client.achallenges.DVSNI`
challenges.
:param list indicies: Meant to hold indices of challenges in a
:param list indices: Meant to hold indices of challenges in a
larger array. ApacheDvsni is capable of solving many challenges
at once which causes an indexing issue within ApacheConfigurator
who must return all responses in order. Imagine ApacheConfigurator
@ -118,7 +117,7 @@ class ApacheDvsni(object):
cert_pem, response = achall.gen_cert_and_response(s)
# Write out challenge cert
with open(cert_path, 'w') as cert_chall_fd:
with open(cert_path, "w") as cert_chall_fd:
cert_chall_fd.write(cert_pem)
return response
@ -129,7 +128,7 @@ class ApacheDvsni(object):
Result: Apache config includes virtual servers for issued challs
:param list ll_addrs: list of list of
:class:`letsencrypt.client.apache.obj.Addr` to apply
:class:`letsencrypt.client.plugins.apache.obj.Addr` to apply
"""
# TODO: Use ip address of existing vhost instead of relying on FQDN
@ -142,7 +141,7 @@ class ApacheDvsni(object):
self.configurator.reverter.register_file_creation(
True, self.challenge_conf)
with open(self.challenge_conf, 'w') as new_conf:
with open(self.challenge_conf, "w") as new_conf:
new_conf.write(config_text)
def _conf_include_check(self, main_config):
@ -168,7 +167,7 @@ class ApacheDvsni(object):
:type achall: :class:`letsencrypt.client.achallenges.DVSNI`
:param list ip_addrs: addresses of challenged domain
:class:`list` of type :class:`letsencrypt.client.apache.obj.Addr`
:class:`list` of type :class:`~apache.obj.Addr`
:returns: virtual host configuration text
:rtype: str
@ -180,13 +179,13 @@ class ApacheDvsni(object):
# TODO: Python docs is not clear how mutliline string literal
# newlines are parsed on different platforms. At least on
# Linux (Debian sid), when source file uses CRLF, Python still
# parses it as '\n'... c.f.:
# parses it as "\n"... c.f.:
# https://docs.python.org/2.7/reference/lexical_analysis.html
return self.VHOST_TEMPLATE.format(
vhost=ips, server_name=achall.nonce_domain,
ssl_options_conf_path=self.configurator.parser.loc["ssl_options"],
cert_path=self.get_cert_file(achall), key_path=achall.key.file,
document_root=document_root).replace('\n', os.linesep)
document_root=document_root).replace("\n", os.linesep)
def get_cert_file(self, achall):
"""Returns standardized name for challenge certificate.

View file

@ -1,4 +1,4 @@
"""Test for letsencrypt.client.apache.configurator."""
"""Test for letsencrypt.client.plugins.apache.configurator."""
import os
import re
import shutil
@ -12,11 +12,11 @@ from letsencrypt.client import achallenges
from letsencrypt.client import errors
from letsencrypt.client import le_util
from letsencrypt.client.apache import configurator
from letsencrypt.client.apache import obj
from letsencrypt.client.apache import parser
from letsencrypt.client.plugins.apache import configurator
from letsencrypt.client.plugins.apache import obj
from letsencrypt.client.plugins.apache import parser
from letsencrypt.client.tests.apache import util
from letsencrypt.client.plugins.apache.tests import util
class TwoVhost80Test(util.ApacheTest):
@ -25,7 +25,7 @@ class TwoVhost80Test(util.ApacheTest):
def setUp(self):
super(TwoVhost80Test, self).setUp()
with mock.patch("letsencrypt.client.apache.configurator."
with mock.patch("letsencrypt.client.plugins.apache.configurator."
"mod_loaded") as mock_load:
mock_load.return_value = True
self.config = util.get_apache_configurator(
@ -43,9 +43,15 @@ class TwoVhost80Test(util.ApacheTest):
def test_get_all_names(self):
names = self.config.get_all_names()
self.assertEqual(names, set(
['letsencrypt.demo', 'encryption-example.demo', 'ip-172-30-0-17']))
["letsencrypt.demo", "encryption-example.demo", "ip-172-30-0-17"]))
def test_get_virtual_hosts(self):
"""Make sure all vhosts are being properly found.
.. note:: If test fails, only finding 1 Vhost... it is likely that
it is a problem with is_enabled.
"""
vhs = self.config.get_virtual_hosts()
self.assertEqual(len(vhs), 4)
found = 0
@ -59,6 +65,14 @@ class TwoVhost80Test(util.ApacheTest):
self.assertEqual(found, 4)
def test_is_site_enabled(self):
"""Test if site is enabled.
.. note:: This test currently fails for hard links
(which may happen if you move dirs incorrectly)
.. warning:: This test does not work when running using the
unittest.main() function. It incorrectly copies symlinks.
"""
self.assertTrue(self.config.is_site_enabled(self.vh_truth[0].filep))
self.assertFalse(self.config.is_site_enabled(self.vh_truth[1].filep))
self.assertTrue(self.config.is_site_enabled(self.vh_truth[2].filep))
@ -134,9 +148,9 @@ class TwoVhost80Test(util.ApacheTest):
self.assertEqual(len(self.config.vhosts), 5)
@mock.patch("letsencrypt.client.apache.configurator."
@mock.patch("letsencrypt.client.plugins.apache.configurator."
"dvsni.ApacheDvsni.perform")
@mock.patch("letsencrypt.client.apache.configurator."
@mock.patch("letsencrypt.client.plugins.apache.configurator."
"ApacheConfigurator.restart")
def test_perform(self, mock_restart, mock_dvsni_perform):
# Only tests functionality specific to configurator.perform
@ -166,7 +180,7 @@ class TwoVhost80Test(util.ApacheTest):
self.assertEqual(mock_restart.call_count, 1)
@mock.patch("letsencrypt.client.apache.configurator."
@mock.patch("letsencrypt.client.plugins.apache.configurator."
"subprocess.Popen")
def test_get_version(self, mock_popen):
mock_popen().communicate.return_value = (
@ -183,7 +197,7 @@ class TwoVhost80Test(util.ApacheTest):
errors.LetsEncryptConfiguratorError, self.config.get_version)
mock_popen().communicate.return_value = (
"Server Version: Apache/2.3\n Apache/2.4.7", "")
"Server Version: Apache/2.3{0} Apache/2.4.7".format(os.linesep), "")
self.assertRaises(
errors.LetsEncryptConfiguratorError, self.config.get_version)
@ -192,5 +206,5 @@ class TwoVhost80Test(util.ApacheTest):
errors.LetsEncryptConfiguratorError, self.config.get_version)
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View file

@ -1,4 +1,4 @@
"""Test for letsencrypt.client.apache.dvsni."""
"""Test for letsencrypt.client.plugins.apache.dvsni."""
import pkg_resources
import unittest
import shutil
@ -10,9 +10,9 @@ from letsencrypt.acme import challenges
from letsencrypt.client import achallenges
from letsencrypt.client import le_util
from letsencrypt.client.apache.obj import Addr
from letsencrypt.client.plugins.apache.obj import Addr
from letsencrypt.client.tests.apache import util
from letsencrypt.client.plugins.apache.tests import util
class DvsniPerformTest(util.ApacheTest):
@ -21,20 +21,20 @@ class DvsniPerformTest(util.ApacheTest):
def setUp(self):
super(DvsniPerformTest, self).setUp()
with mock.patch("letsencrypt.client.apache.configurator."
with mock.patch("letsencrypt.client.plugins.apache.configurator."
"mod_loaded") as mock_load:
mock_load.return_value = True
config = util.get_apache_configurator(
self.config_path, self.config_dir, self.work_dir,
self.ssl_options)
from letsencrypt.client.apache import dvsni
from letsencrypt.client.plugins.apache import dvsni
self.sni = dvsni.ApacheDvsni(config)
rsa256_file = pkg_resources.resource_filename(
"letsencrypt.client.tests", 'testdata/rsa256_key.pem')
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
rsa256_pem = pkg_resources.resource_string(
"letsencrypt.client.tests", 'testdata/rsa256_key.pem')
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
auth_key = le_util.Key(rsa256_file, rsa256_pem)
self.achalls = [
@ -74,7 +74,7 @@ class DvsniPerformTest(util.ApacheTest):
nonce_domain=self.achalls[0].nonce_domain)
achall.gen_cert_and_response.return_value = ("pem", response)
with mock.patch("letsencrypt.client.apache.dvsni.open",
with mock.patch("letsencrypt.client.plugins.apache.dvsni.open",
m_open, create=True):
# pylint: disable=protected-access
self.assertEqual(response, self.sni._setup_challenge_cert(
@ -82,7 +82,7 @@ class DvsniPerformTest(util.ApacheTest):
self.assertTrue(m_open.called)
self.assertEqual(
m_open.call_args[0], (self.sni.get_cert_file(achall), 'w'))
m_open.call_args[0], (self.sni.get_cert_file(achall), "w"))
self.assertEqual(m_open().write.call_args[0][0], "pem")
def test_perform1(self):
@ -166,5 +166,5 @@ class DvsniPerformTest(util.ApacheTest):
set([self.achalls[1].nonce_domain]))
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View file

@ -1,11 +1,11 @@
"""Test the helper objects in apache.obj.py."""
"""Test the helper objects in letsencrypt.client.plugins.apache.obj."""
import unittest
class AddrTest(unittest.TestCase):
"""Test the Addr class."""
def setUp(self):
from letsencrypt.client.apache.obj import Addr
from letsencrypt.client.plugins.apache.obj import Addr
self.addr1 = Addr.fromstring("192.168.1.1")
self.addr2 = Addr.fromstring("192.168.1.1:*")
self.addr3 = Addr.fromstring("192.168.1.1:80")
@ -34,7 +34,7 @@ class AddrTest(unittest.TestCase):
self.assertFalse(self.addr1 == 3333)
def test_set_inclusion(self):
from letsencrypt.client.apache.obj import Addr
from letsencrypt.client.plugins.apache.obj import Addr
set_a = set([self.addr1, self.addr2])
addr1b = Addr.fromstring("192.168.1.1")
addr2b = Addr.fromstring("192.168.1.1:*")
@ -46,15 +46,15 @@ class AddrTest(unittest.TestCase):
class VirtualHostTest(unittest.TestCase):
"""Test the VirtualHost class."""
def setUp(self):
from letsencrypt.client.apache.obj import VirtualHost
from letsencrypt.client.apache.obj import Addr
from letsencrypt.client.plugins.apache.obj import VirtualHost
from letsencrypt.client.plugins.apache.obj import Addr
self.vhost1 = VirtualHost(
"filep", "vh_path",
set([Addr.fromstring("localhost")]), False, False)
def test_eq(self):
from letsencrypt.client.apache.obj import Addr
from letsencrypt.client.apache.obj import VirtualHost
from letsencrypt.client.plugins.apache.obj import Addr
from letsencrypt.client.plugins.apache.obj import VirtualHost
vhost1b = VirtualHost(
"filep", "vh_path",
set([Addr.fromstring("localhost")]), False, False)

View file

@ -1,4 +1,4 @@
"""Tests the ApacheParser class."""
"""Tests for letsencrypt.client.plugins.apache.parser."""
import os
import shutil
import sys
@ -11,7 +11,7 @@ import zope.component
from letsencrypt.client import errors
from letsencrypt.client.display import util as display_util
from letsencrypt.client.tests.apache import util
from letsencrypt.client.plugins.apache.tests import util
class ApacheParserTest(util.ApacheTest):
@ -22,7 +22,7 @@ class ApacheParserTest(util.ApacheTest):
zope.component.provideUtility(display_util.FileDisplay(sys.stdout))
from letsencrypt.client.apache.parser import ApacheParser
from letsencrypt.client.plugins.apache.parser import ApacheParser
self.aug = augeas.Augeas(flags=augeas.Augeas.NONE)
self.parser = ApacheParser(self.aug, self.config_path, self.ssl_options)
@ -32,19 +32,19 @@ class ApacheParserTest(util.ApacheTest):
shutil.rmtree(self.work_dir)
def test_root_normalized(self):
from letsencrypt.client.apache.parser import ApacheParser
from letsencrypt.client.plugins.apache.parser import ApacheParser
path = os.path.join(self.temp_dir, "debian_apache_2_4/////"
"two_vhost_80/../two_vhost_80/apache2")
parser = ApacheParser(self.aug, path, None)
self.assertEqual(parser.root, self.config_path)
def test_root_absolute(self):
from letsencrypt.client.apache.parser import ApacheParser
from letsencrypt.client.plugins.apache.parser import ApacheParser
parser = ApacheParser(self.aug, os.path.relpath(self.config_path), None)
self.assertEqual(parser.root, self.config_path)
def test_root_no_trailing_slash(self):
from letsencrypt.client.apache.parser import ApacheParser
from letsencrypt.client.plugins.apache.parser import ApacheParser
parser = ApacheParser(self.aug, self.config_path + os.path.sep, None)
self.assertEqual(parser.root, self.config_path)
@ -67,7 +67,7 @@ class ApacheParserTest(util.ApacheTest):
self.assertTrue(matches)
def test_find_dir(self):
from letsencrypt.client.apache.parser import case_i
from letsencrypt.client.plugins.apache.parser import case_i
test = self.parser.find_dir(case_i("Listen"), "443")
# This will only look in enabled hosts
test2 = self.parser.find_dir(case_i("documentroot"))
@ -92,7 +92,7 @@ class ApacheParserTest(util.ApacheTest):
Path must be valid before attempting to add to augeas
"""
from letsencrypt.client.apache.parser import get_aug_path
from letsencrypt.client.plugins.apache.parser import get_aug_path
self.parser.add_dir_to_ifmodssl(
get_aug_path(self.parser.loc["default"]),
"FakeDirective", "123")
@ -103,11 +103,11 @@ class ApacheParserTest(util.ApacheTest):
self.assertTrue("IfModule" in matches[0])
def test_get_aug_path(self):
from letsencrypt.client.apache.parser import get_aug_path
from letsencrypt.client.plugins.apache.parser import get_aug_path
self.assertEqual("/files/etc/apache", get_aug_path("/etc/apache"))
def test_set_locations(self):
with mock.patch("letsencrypt.client.apache.parser."
with mock.patch("letsencrypt.client.plugins.apache.parser."
"os.path") as mock_path:
mock_path.isfile.return_value = False
@ -125,5 +125,5 @@ class ApacheParserTest(util.ApacheTest):
self.assertEqual(results["default"], results["name"])
if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()

View file

@ -1,4 +1,4 @@
"""Common utilities for letsencrypt.client.apache."""
"""Common utilities for letsencrypt.client.plugins.apache."""
import os
import pkg_resources
import shutil
@ -8,8 +8,8 @@ import unittest
import mock
from letsencrypt.client import constants
from letsencrypt.client.apache import configurator
from letsencrypt.client.apache import obj
from letsencrypt.client.plugins.apache import configurator
from letsencrypt.client.plugins.apache import obj
class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
@ -26,9 +26,9 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
self.temp_dir, "debian_apache_2_4/two_vhost_80/apache2")
self.rsa256_file = pkg_resources.resource_filename(
"letsencrypt.client.tests", 'testdata/rsa256_key.pem')
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
self.rsa256_pem = pkg_resources.resource_string(
"letsencrypt.client.tests", 'testdata/rsa256_key.pem')
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
def dir_setup(test_dir="debian_apache_2_4/two_vhost_80"):
@ -38,7 +38,7 @@ def dir_setup(test_dir="debian_apache_2_4/two_vhost_80"):
work_dir = tempfile.mkdtemp("work")
test_configs = pkg_resources.resource_filename(
"letsencrypt.client.tests", "testdata/%s" % test_dir)
"letsencrypt.client.plugins.apache.tests", "testdata/%s" % test_dir)
shutil.copytree(
test_configs, os.path.join(temp_dir, test_dir), symlinks=True)
@ -59,7 +59,7 @@ def get_apache_configurator(
backups = os.path.join(work_dir, "backups")
with mock.patch("letsencrypt.client.apache.configurator."
with mock.patch("letsencrypt.client.plugins.apache.configurator."
"subprocess.Popen") as mock_popen:
# This just states that the ssl module is already loaded
mock_popen().communicate.return_value = ("ssl_module", "")

View file

@ -0,0 +1 @@
"""Let's Encrypt client.plugins.standalone."""

View file

@ -0,0 +1 @@
"""Let's Encrypt Standalone Tests"""

View file

@ -1,4 +1,4 @@
"""Tests for letsencrypt.client.standalone_authenticator."""
"""Tests for letsencrypt.client.plugins.standalone.authenticator."""
import os
import pkg_resources
import psutil
@ -49,7 +49,7 @@ class CallableExhausted(Exception):
class ChallPrefTest(unittest.TestCase):
"""Tests for chall_pref() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
@ -61,11 +61,11 @@ class ChallPrefTest(unittest.TestCase):
class SNICallbackTest(unittest.TestCase):
"""Tests for sni_callback() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem")
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
key = le_util.Key("foo", test_key)
self.cert = achallenges.DVSNI(
chall=challenges.DVSNI(r="x"*32, nonce="abcdef"),
@ -104,7 +104,7 @@ class SNICallbackTest(unittest.TestCase):
class ClientSignalHandlerTest(unittest.TestCase):
"""Tests for client_signal_handler() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
self.authenticator.tasks = {"foononce.acme.invalid": "stuff"}
@ -133,15 +133,15 @@ class ClientSignalHandlerTest(unittest.TestCase):
class SubprocSignalHandlerTest(unittest.TestCase):
"""Tests for subproc_signal_handler() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
self.authenticator.tasks = {"foononce.acme.invalid": "stuff"}
self.authenticator.child_pid = 12345
self.authenticator.parent_pid = 23456
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.standalone_authenticator.sys.exit")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.sys.exit")
def test_subproc_signal_handler(self, mock_exit, mock_kill):
self.authenticator.ssl_conn = mock.MagicMock()
self.authenticator.connection = mock.MagicMock()
@ -155,8 +155,8 @@ class SubprocSignalHandlerTest(unittest.TestCase):
self.authenticator.parent_pid, signal.SIGUSR1)
mock_exit.assert_called_once_with(0)
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.standalone_authenticator.sys.exit")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.sys.exit")
def test_subproc_signal_handler_trouble(self, mock_exit, mock_kill):
"""Test attempting to shut down a non-existent connection.
@ -185,14 +185,15 @@ class SubprocSignalHandlerTest(unittest.TestCase):
class AlreadyListeningTest(unittest.TestCase):
"""Tests for already_listening() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator.psutil."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.psutil."
"net_connections")
@mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"psutil.Process")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_race_condition(self, mock_get_utility, mock_process, mock_net):
# This tests a race condition, or permission problem, or OS
@ -200,14 +201,14 @@ class AlreadyListeningTest(unittest.TestCase):
# found to match the identified listening PID.
from psutil._common import sconn
conns = [
sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30),
raddr=(), status='LISTEN', pid=None),
sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783),
raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234),
sconn(fd=-1, family=10, type=1, laddr=('::1', 54321),
raddr=('::1', 111), status='CLOSE_WAIT', pid=None),
sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17),
raddr=(), status='LISTEN', pid=4416)]
sconn(fd=-1, family=2, type=1, laddr=("0.0.0.0", 30),
raddr=(), status="LISTEN", pid=None),
sconn(fd=3, family=2, type=1, laddr=("192.168.5.10", 32783),
raddr=("20.40.60.80", 22), status="ESTABLISHED", pid=1234),
sconn(fd=-1, family=10, type=1, laddr=("::1", 54321),
raddr=("::1", 111), status="CLOSE_WAIT", pid=None),
sconn(fd=3, family=2, type=1, laddr=("0.0.0.0", 17),
raddr=(), status="LISTEN", pid=4416)]
mock_net.return_value = conns
mock_process.side_effect = psutil.NoSuchProcess("No such PID")
# We simulate being unable to find the process name of PID 4416,
@ -216,42 +217,44 @@ class AlreadyListeningTest(unittest.TestCase):
self.assertEqual(mock_get_utility.generic_notification.call_count, 0)
mock_process.assert_called_once_with(4416)
@mock.patch("letsencrypt.client.standalone_authenticator.psutil."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.psutil."
"net_connections")
@mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"psutil.Process")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_not_listening(self, mock_get_utility, mock_process, mock_net):
from psutil._common import sconn
conns = [
sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30),
raddr=(), status='LISTEN', pid=None),
sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783),
raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234),
sconn(fd=-1, family=10, type=1, laddr=('::1', 54321),
raddr=('::1', 111), status='CLOSE_WAIT', pid=None)]
sconn(fd=-1, family=2, type=1, laddr=("0.0.0.0", 30),
raddr=(), status="LISTEN", pid=None),
sconn(fd=3, family=2, type=1, laddr=("192.168.5.10", 32783),
raddr=("20.40.60.80", 22), status="ESTABLISHED", pid=1234),
sconn(fd=-1, family=10, type=1, laddr=("::1", 54321),
raddr=("::1", 111), status="CLOSE_WAIT", pid=None)]
mock_net.return_value = conns
mock_process.name.return_value = "inetd"
self.assertFalse(self.authenticator.already_listening(17))
self.assertEqual(mock_get_utility.generic_notification.call_count, 0)
self.assertEqual(mock_process.call_count, 0)
@mock.patch("letsencrypt.client.standalone_authenticator.psutil."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.psutil."
"net_connections")
@mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"psutil.Process")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_listening_ipv4(self, mock_get_utility, mock_process, mock_net):
from psutil._common import sconn
conns = [
sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30),
raddr=(), status='LISTEN', pid=None),
sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783),
raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234),
sconn(fd=-1, family=10, type=1, laddr=('::1', 54321),
raddr=('::1', 111), status='CLOSE_WAIT', pid=None),
sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17),
raddr=(), status='LISTEN', pid=4416)]
sconn(fd=-1, family=2, type=1, laddr=("0.0.0.0", 30),
raddr=(), status="LISTEN", pid=None),
sconn(fd=3, family=2, type=1, laddr=("192.168.5.10", 32783),
raddr=("20.40.60.80", 22), status="ESTABLISHED", pid=1234),
sconn(fd=-1, family=10, type=1, laddr=("::1", 54321),
raddr=("::1", 111), status="CLOSE_WAIT", pid=None),
sconn(fd=3, family=2, type=1, laddr=("0.0.0.0", 17),
raddr=(), status="LISTEN", pid=4416)]
mock_net.return_value = conns
mock_process.name.return_value = "inetd"
result = self.authenticator.already_listening(17)
@ -259,24 +262,25 @@ class AlreadyListeningTest(unittest.TestCase):
self.assertEqual(mock_get_utility.call_count, 1)
mock_process.assert_called_once_with(4416)
@mock.patch("letsencrypt.client.standalone_authenticator.psutil."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.psutil."
"net_connections")
@mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"psutil.Process")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_listening_ipv6(self, mock_get_utility, mock_process, mock_net):
from psutil._common import sconn
conns = [
sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30),
raddr=(), status='LISTEN', pid=None),
sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783),
raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234),
sconn(fd=-1, family=10, type=1, laddr=('::1', 54321),
raddr=('::1', 111), status='CLOSE_WAIT', pid=None),
sconn(fd=3, family=10, type=1, laddr=('::', 12345), raddr=(),
status='LISTEN', pid=4420),
sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17),
raddr=(), status='LISTEN', pid=4416)]
sconn(fd=-1, family=2, type=1, laddr=("0.0.0.0", 30),
raddr=(), status="LISTEN", pid=None),
sconn(fd=3, family=2, type=1, laddr=("192.168.5.10", 32783),
raddr=("20.40.60.80", 22), status="ESTABLISHED", pid=1234),
sconn(fd=-1, family=10, type=1, laddr=("::1", 54321),
raddr=("::1", 111), status="CLOSE_WAIT", pid=None),
sconn(fd=3, family=10, type=1, laddr=("::", 12345), raddr=(),
status="LISTEN", pid=4420),
sconn(fd=3, family=2, type=1, laddr=("0.0.0.0", 17),
raddr=(), status="LISTEN", pid=4416)]
mock_net.return_value = conns
mock_process.name.return_value = "inetd"
result = self.authenticator.already_listening(12345)
@ -288,12 +292,12 @@ class AlreadyListeningTest(unittest.TestCase):
class PerformTest(unittest.TestCase):
"""Tests for perform() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem")
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
self.key = le_util.Key("something", test_key)
self.achall1 = achallenges.DVSNI(
@ -365,13 +369,13 @@ class PerformTest(unittest.TestCase):
class StartListenerTest(unittest.TestCase):
"""Tests for start_listener() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"Crypto.Random.atfork")
@mock.patch("letsencrypt.client.standalone_authenticator.os.fork")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.fork")
def test_start_listener_fork_parent(self, mock_fork, mock_atfork):
self.authenticator.do_parent_process = mock.Mock()
self.authenticator.do_parent_process.return_value = True
@ -384,9 +388,9 @@ class StartListenerTest(unittest.TestCase):
self.authenticator.do_parent_process.assert_called_once_with(1717)
mock_atfork.assert_called_once_with()
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"Crypto.Random.atfork")
@mock.patch("letsencrypt.client.standalone_authenticator.os.fork")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.fork")
def test_start_listener_fork_child(self, mock_fork, mock_atfork):
self.authenticator.do_parent_process = mock.Mock()
self.authenticator.do_child_process = mock.Mock()
@ -400,12 +404,13 @@ class StartListenerTest(unittest.TestCase):
class DoParentProcessTest(unittest.TestCase):
"""Tests for do_parent_process() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
@mock.patch("letsencrypt.client.standalone_authenticator.signal.signal")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"signal.signal")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_do_parent_process_ok(self, mock_get_utility, mock_signal):
self.authenticator.subproc_state = "ready"
@ -414,8 +419,9 @@ class DoParentProcessTest(unittest.TestCase):
self.assertEqual(mock_get_utility.call_count, 1)
self.assertEqual(mock_signal.call_count, 3)
@mock.patch("letsencrypt.client.standalone_authenticator.signal.signal")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"signal.signal")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_do_parent_process_inuse(self, mock_get_utility, mock_signal):
self.authenticator.subproc_state = "inuse"
@ -424,8 +430,9 @@ class DoParentProcessTest(unittest.TestCase):
self.assertEqual(mock_get_utility.call_count, 1)
self.assertEqual(mock_signal.call_count, 3)
@mock.patch("letsencrypt.client.standalone_authenticator.signal.signal")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"signal.signal")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_do_parent_process_cantbind(self, mock_get_utility, mock_signal):
self.authenticator.subproc_state = "cantbind"
@ -434,8 +441,9 @@ class DoParentProcessTest(unittest.TestCase):
self.assertEqual(mock_get_utility.call_count, 1)
self.assertEqual(mock_signal.call_count, 3)
@mock.patch("letsencrypt.client.standalone_authenticator.signal.signal")
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"signal.signal")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"zope.component.getUtility")
def test_do_parent_process_timeout(self, mock_get_utility, mock_signal):
# Normally times out in 5 seconds and returns False. We can
@ -450,11 +458,11 @@ class DoParentProcessTest(unittest.TestCase):
class DoChildProcessTest(unittest.TestCase):
"""Tests for do_child_process() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
test_key = pkg_resources.resource_string(
__name__, "testdata/rsa256_key.pem")
"letsencrypt.client.tests", "testdata/rsa256_key.pem")
key = le_util.Key("foo", test_key)
self.key = key
self.cert = achallenges.DVSNI(
@ -466,9 +474,10 @@ class DoChildProcessTest(unittest.TestCase):
self.authenticator.tasks = {"abcdef.acme.invalid": self.cert}
self.authenticator.parent_pid = 12345
@mock.patch("letsencrypt.client.standalone_authenticator.socket.socket")
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.standalone_authenticator.sys.exit")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"socket.socket")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.sys.exit")
def test_do_child_process_cantbind1(
self, mock_exit, mock_kill, mock_socket):
mock_exit.side_effect = IndentationError("subprocess would exit here")
@ -488,9 +497,10 @@ class DoChildProcessTest(unittest.TestCase):
mock_exit.assert_called_once_with(1)
mock_kill.assert_called_once_with(12345, signal.SIGUSR2)
@mock.patch("letsencrypt.client.standalone_authenticator.socket.socket")
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.standalone_authenticator.sys.exit")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"socket.socket")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.sys.exit")
def test_do_child_process_cantbind2(self, mock_exit, mock_kill,
mock_socket):
mock_exit.side_effect = IndentationError("subprocess would exit here")
@ -504,7 +514,8 @@ class DoChildProcessTest(unittest.TestCase):
mock_exit.assert_called_once_with(1)
mock_kill.assert_called_once_with(12345, signal.SIGUSR1)
@mock.patch("letsencrypt.client.standalone_authenticator.socket.socket")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"socket.socket")
def test_do_child_process_cantbind3(self, mock_socket):
"""Test case where attempt to bind socket results in an unhandled
socket error. (The expected behavior is arguably wrong because it
@ -517,10 +528,11 @@ class DoChildProcessTest(unittest.TestCase):
self.assertRaises(
socket.error, self.authenticator.do_child_process, 1717, self.key)
@mock.patch("letsencrypt.client.standalone_authenticator."
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"OpenSSL.SSL.Connection")
@mock.patch("letsencrypt.client.standalone_authenticator.socket.socket")
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"socket.socket")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
def test_do_child_process_success(
self, mock_kill, mock_socket, mock_connection):
sample_socket = mock.MagicMock()
@ -543,7 +555,7 @@ class DoChildProcessTest(unittest.TestCase):
class CleanupTest(unittest.TestCase):
"""Tests for cleanup() method."""
def setUp(self):
from letsencrypt.client.standalone_authenticator import \
from letsencrypt.client.plugins.standalone.authenticator import \
StandaloneAuthenticator
self.authenticator = StandaloneAuthenticator(None)
self.achall = achallenges.DVSNI(
@ -552,8 +564,9 @@ class CleanupTest(unittest.TestCase):
self.authenticator.tasks = {self.achall.nonce_domain: "stuff"}
self.authenticator.child_pid = 12345
@mock.patch("letsencrypt.client.standalone_authenticator.os.kill")
@mock.patch("letsencrypt.client.standalone_authenticator.time.sleep")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator.os.kill")
@mock.patch("letsencrypt.client.plugins.standalone.authenticator."
"time.sleep")
def test_cleanup(self, mock_sleep, mock_kill):
mock_sleep.return_value = None
mock_kill.return_value = None
@ -573,7 +586,7 @@ class CleanupTest(unittest.TestCase):
class MoreInfoTest(unittest.TestCase):
"""Tests for more_info() method. (trivially)"""
def setUp(self):
from letsencrypt.client.standalone_authenticator import (
from letsencrypt.client.plugins.standalone.authenticator import (
StandaloneAuthenticator)
self.authenticator = StandaloneAuthenticator(None)
@ -585,7 +598,7 @@ class MoreInfoTest(unittest.TestCase):
class InitTest(unittest.TestCase):
"""Tests for more_info() method. (trivially)"""
def setUp(self):
from letsencrypt.client.standalone_authenticator import (
from letsencrypt.client.plugins.standalone.authenticator import (
StandaloneAuthenticator)
self.authenticator = StandaloneAuthenticator(None)

View file

@ -8,8 +8,9 @@ from letsencrypt.client import errors
class DetermineAuthenticatorTest(unittest.TestCase):
def setUp(self):
from letsencrypt.client.apache.configurator import ApacheConfigurator
from letsencrypt.client.standalone_authenticator import (
from letsencrypt.client.plugins.apache.configurator import (
ApacheConfigurator)
from letsencrypt.client.plugins.standalone.authenticator import (
StandaloneAuthenticator)
self.mock_stand = mock.MagicMock(
@ -65,7 +66,8 @@ class DetermineAuthenticatorTest(unittest.TestCase):
class RollbackTest(unittest.TestCase):
"""Test the rollback function."""
def setUp(self):
from letsencrypt.client.apache.configurator import ApacheConfigurator
from letsencrypt.client.plugins.apache.configurator import (
ApacheConfigurator)
self.m_install = mock.MagicMock(spec=ApacheConfigurator)
@classmethod

View file

@ -10,7 +10,7 @@ import mock
from letsencrypt.client import errors
from letsencrypt.client import le_util
from letsencrypt.client.apache import configurator
from letsencrypt.client.plugins.apache import configurator
from letsencrypt.client.display import util as display_util

View file

@ -96,10 +96,13 @@ setup(
'letsencrypt.acme',
'letsencrypt.acme.jose',
'letsencrypt.client',
'letsencrypt.client.apache',
'letsencrypt.client.display',
'letsencrypt.client.plugins',
'letsencrypt.client.plugins.apache',
'letsencrypt.client.plugins.apache.tests',
'letsencrypt.client.plugins.standalone',
'letsencrypt.client.plugins.standalone.tests',
'letsencrypt.client.tests',
'letsencrypt.client.tests.apache',
'letsencrypt.client.tests.display',
'letsencrypt.scripts',
],
@ -120,9 +123,9 @@ setup(
'jws = letsencrypt.acme.jose.jws:CLI.run',
],
'letsencrypt.authenticators': [
'apache = letsencrypt.client.apache.configurator'
'apache = letsencrypt.client.plugins.apache.configurator'
':ApacheConfigurator',
'standalone = letsencrypt.client.standalone_authenticator'
'standalone = letsencrypt.client.plugins.standalone.authenticator'
':StandaloneAuthenticator',
],
},