mirror of
https://github.com/certbot/certbot.git
synced 2026-05-28 04:34:11 -04:00
Merge branch 'master' into revert-2492-unbreak-le-auto
This commit is contained in:
commit
0c345cb8d3
51 changed files with 2551 additions and 259 deletions
|
|
@ -30,10 +30,9 @@ matrix:
|
|||
env: TOXENV=py26 BOULDER_INTEGRATION=1
|
||||
- python: "2.6"
|
||||
env: TOXENV=py26-oldest BOULDER_INTEGRATION=1
|
||||
# Disabled for now due to requiring sudo -> causing more boulder integration
|
||||
# DNS timeouts :(
|
||||
# - python: "2.7"
|
||||
# env: TOXENV=apacheconftest
|
||||
- python: "2.7"
|
||||
env: TOXENV=apacheconftest
|
||||
sudo: required
|
||||
- python: "2.7"
|
||||
env: TOXENV=py27 BOULDER_INTEGRATION=1
|
||||
- python: "2.7"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""ACME client API."""
|
||||
import collections
|
||||
import datetime
|
||||
from email.utils import parsedate_tz
|
||||
import heapq
|
||||
import logging
|
||||
import time
|
||||
|
|
@ -11,7 +12,6 @@ from six.moves import http_client # pylint: disable=import-error
|
|||
import OpenSSL
|
||||
import requests
|
||||
import sys
|
||||
import werkzeug
|
||||
|
||||
from acme import errors
|
||||
from acme import jose
|
||||
|
|
@ -248,6 +248,9 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||
def retry_after(cls, response, default):
|
||||
"""Compute next `poll` time based on response ``Retry-After`` header.
|
||||
|
||||
Handles integers and various datestring formats per
|
||||
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37
|
||||
|
||||
:param requests.Response response: Response from `poll`.
|
||||
:param int default: Default value (in seconds), used when
|
||||
``Retry-After`` header is not present or invalid.
|
||||
|
|
@ -260,12 +263,16 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||
try:
|
||||
seconds = int(retry_after)
|
||||
except ValueError:
|
||||
# pylint: disable=no-member
|
||||
decoded = werkzeug.parse_date(retry_after) # RFC1123
|
||||
if decoded is None:
|
||||
seconds = default
|
||||
else:
|
||||
return decoded
|
||||
# The RFC 2822 parser handles all of RFC 2616's cases in modern
|
||||
# environments (primarily HTTP 1.1+ but also py27+)
|
||||
when = parsedate_tz(retry_after)
|
||||
if when is not None:
|
||||
try:
|
||||
tz_secs = datetime.timedelta(when[-1] if when[-1] else 0)
|
||||
return datetime.datetime(*when[:7]) - tz_secs
|
||||
except (ValueError, OverflowError):
|
||||
pass
|
||||
seconds = default
|
||||
|
||||
return datetime.datetime.now() + datetime.timedelta(seconds=seconds)
|
||||
|
||||
|
|
@ -357,7 +364,7 @@ class Client(object): # pylint: disable=too-many-instance-attributes
|
|||
attempts = collections.defaultdict(int)
|
||||
exhausted = set()
|
||||
|
||||
# priority queue with datetime (based on Retry-After) as key,
|
||||
# priority queue with datetime.datetime (based on Retry-After) as key,
|
||||
# and original Authorization Resource as value
|
||||
waiting = [(datetime.datetime.now(), authzr) for authzr in authzrs]
|
||||
# mapping between original Authorization Resource and the most
|
||||
|
|
|
|||
|
|
@ -222,6 +222,17 @@ class ClientTest(unittest.TestCase):
|
|||
datetime.datetime(2015, 3, 27, 0, 0, 10),
|
||||
self.client.retry_after(response=self.response, default=10))
|
||||
|
||||
@mock.patch('acme.client.datetime')
|
||||
def test_retry_after_overflow(self, dt_mock):
|
||||
dt_mock.datetime.now.return_value = datetime.datetime(2015, 3, 27)
|
||||
dt_mock.timedelta = datetime.timedelta
|
||||
dt_mock.datetime.side_effect = datetime.datetime
|
||||
|
||||
self.response.headers['Retry-After'] = "Tue, 116 Feb 2016 11:50:00 MST"
|
||||
self.assertEqual(
|
||||
datetime.datetime(2015, 3, 27, 0, 0, 10),
|
||||
self.client.retry_after(response=self.response, default=10))
|
||||
|
||||
@mock.patch('acme.client.datetime')
|
||||
def test_retry_after_seconds(self, dt_mock):
|
||||
dt_mock.datetime.now.return_value = datetime.datetime(2015, 3, 27)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ install_requires = [
|
|||
'requests',
|
||||
'setuptools', # pkg_resources
|
||||
'six',
|
||||
'werkzeug',
|
||||
]
|
||||
|
||||
# env markers in extras_require cause problems with older pip: #517
|
||||
|
|
|
|||
|
|
@ -429,6 +429,12 @@ If you don't want to use the Apache plugin, you can omit the
|
|||
|
||||
Packages for Debian Jessie are coming in the next few weeks.
|
||||
|
||||
**Fedora**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo dnf install letsencrypt
|
||||
|
||||
**Gentoo**
|
||||
|
||||
The official Let's Encrypt client is available in Gentoo Portage. If you
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ from letsencrypt import interfaces
|
|||
from letsencrypt.plugins import common
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Authenticator(common.Plugin):
|
||||
"""Example Authenticator."""
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Example Authenticator plugin"
|
||||
|
||||
|
|
@ -20,10 +20,10 @@ class Authenticator(common.Plugin):
|
|||
# "self" as first argument, e.g. def prepare(self)...
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IInstaller)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Installer(common.Plugin):
|
||||
"""Example Installer."""
|
||||
zope.interface.implements(interfaces.IInstaller)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Example Installer plugin"
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ autoload xfm
|
|||
let dels (s:string) = del s s
|
||||
|
||||
(* deal with continuation lines *)
|
||||
let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "
|
||||
|
||||
let sep_osp = Sep.opt_space
|
||||
let sep_spc = del /([ \t]+|[ \t]*\\\\\r?\n[ \t]*)/ " "
|
||||
let sep_osp = del /([ \t]*|[ \t]*\\\\\r?\n[ \t]*)/ ""
|
||||
let sep_eq = del /[ \t]*=[ \t]*/ "="
|
||||
|
||||
let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/
|
||||
|
|
@ -60,7 +59,7 @@ let indent = Util.indent
|
|||
|
||||
(* borrowed from shellvars.aug *)
|
||||
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'/
|
||||
let char_arg_sec = /[^ '"\t\r\n>]|\\\\"|\\\\'/
|
||||
let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'/
|
||||
let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
|
||||
|
||||
let cdot = /\\\\./
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ logger = logging.getLogger(__name__)
|
|||
# sites-available doesn't allow immediate find_dir search even with save()
|
||||
# and load()
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator, interfaces.IInstaller)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
# pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||
"""Apache configurator.
|
||||
|
|
@ -80,8 +82,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
:ivar dict assoc: Mapping between domains and vhosts
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IAuthenticator, interfaces.IInstaller)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Apache Web Server - Alpha"
|
||||
|
||||
|
|
@ -1075,7 +1075,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
# even with save() and load()
|
||||
if not self._is_rewrite_engine_on(general_vh):
|
||||
self.parser.add_dir(general_vh.path, "RewriteEngine", "on")
|
||||
|
||||
names = ssl_vhost.get_names()
|
||||
for idx, name in enumerate(names):
|
||||
args = ["%{SERVER_NAME}", "={0}".format(name), "[OR]"]
|
||||
if idx == len(names) - 1:
|
||||
args.pop()
|
||||
self.parser.add_dir(general_vh.path, "RewriteCond", args)
|
||||
if self.get_version() >= (2, 3, 9):
|
||||
self.parser.add_dir(general_vh.path, "RewriteRule",
|
||||
constants.REWRITE_HTTPS_ARGS_WITH_END)
|
||||
|
|
@ -1245,6 +1250,10 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
for http_vh in candidate_http_vhs:
|
||||
if http_vh.same_server(ssl_vhost):
|
||||
return http_vh
|
||||
# Third filter - if none with same names, return generic
|
||||
for http_vh in candidate_http_vhs:
|
||||
if http_vh.same_server(ssl_vhost, generic=True):
|
||||
return http_vh
|
||||
|
||||
return None
|
||||
|
||||
|
|
@ -1431,7 +1440,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
|||
|
||||
"""
|
||||
self.config_test()
|
||||
logger.debug(self.reverter.view_config_changes(for_logging=True))
|
||||
self._reload()
|
||||
|
||||
def _reload(self):
|
||||
|
|
|
|||
|
|
@ -189,22 +189,28 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
|
|||
return True
|
||||
return False
|
||||
|
||||
def same_server(self, vhost):
|
||||
def same_server(self, vhost, generic=False):
|
||||
"""Determines if the vhost is the same 'server'.
|
||||
|
||||
Used in redirection - indicates whether or not the two virtual hosts
|
||||
serve on the exact same IP combinations, but different ports.
|
||||
The generic flag indicates that that we're trying to match to a
|
||||
default or generic vhost
|
||||
|
||||
.. todo:: Handle _default_
|
||||
|
||||
"""
|
||||
|
||||
if vhost.get_names() != self.get_names():
|
||||
return False
|
||||
if not generic:
|
||||
if vhost.get_names() != self.get_names():
|
||||
return False
|
||||
|
||||
# If equal and set is not empty... assume same server
|
||||
if self.name is not None or self.aliases:
|
||||
return True
|
||||
# If equal and set is not empty... assume same server
|
||||
if self.name is not None or self.aliases:
|
||||
return True
|
||||
# If we're looking for a generic vhost, don't return one with a ServerName
|
||||
elif self.name:
|
||||
return False
|
||||
|
||||
# Both sets of names are empty.
|
||||
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ class ApacheParser(object):
|
|||
# Note: This works for augeas globs, ie. *.conf
|
||||
if use_new:
|
||||
inc_test = self.aug.match(
|
||||
"/augeas/load/Httpd/incl [. ='%s']" % filepath)
|
||||
"/augeas/load/Httpd['%s' =~ glob(incl)]" % filepath)
|
||||
if not inc_test:
|
||||
# Load up files
|
||||
# This doesn't seem to work on TravisCI
|
||||
|
|
|
|||
|
|
@ -0,0 +1,284 @@
|
|||
|
||||
NameVirtualHost 0.0.0.0:7080
|
||||
NameVirtualHost [00000:000:000:000::0]:7080
|
||||
NameVirtualHost 0.0.0.0:7080
|
||||
|
||||
NameVirtualHost 127.0.0.1:7080
|
||||
NameVirtualHost 0.0.0.0:7081
|
||||
NameVirtualHost [0000:000:000:000::2]:7081
|
||||
NameVirtualHost 0.0.0.0:7081
|
||||
|
||||
NameVirtualHost 127.0.0.1:7081
|
||||
|
||||
ServerName "example.com"
|
||||
ServerAdmin "srv@example.com"
|
||||
|
||||
DocumentRoot /tmp
|
||||
|
||||
<IfModule mod_logio.c>
|
||||
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
|
||||
</IfModule>
|
||||
<IfModule !mod_logio.c>
|
||||
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" plesklog
|
||||
</IfModule>
|
||||
|
||||
TraceEnable off
|
||||
|
||||
ServerTokens ProductOnly
|
||||
|
||||
<Directory "/var/www/vhosts">
|
||||
AllowOverride "All"
|
||||
Options SymLinksIfOwnerMatch
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine off
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine off
|
||||
</IfModule>
|
||||
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/lib/mailman">
|
||||
AllowOverride "All"
|
||||
Options SymLinksIfOwnerMatch
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine off
|
||||
</IfModule>
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine off
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
Header add X-Powered-By PleskLin
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_security2.c>
|
||||
SecRuleEngine DetectionOnly
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 134217728
|
||||
SecResponseBodyAccess Off
|
||||
SecResponseBodyLimit 524288
|
||||
SecAuditEngine On
|
||||
SecAuditLog "/var/log/modsec_audit.log"
|
||||
SecAuditLogType serial
|
||||
</IfModule>
|
||||
|
||||
#Include "/etc/httpd/conf/plesk.conf.d/ip_default/*.conf"
|
||||
|
||||
<VirtualHost \
|
||||
0.0.0.0:7080 \
|
||||
[00000:000:000:0000::2]:7080 \
|
||||
0.0.0.0:7080 \
|
||||
127.0.0.1:7080 \
|
||||
>
|
||||
ServerName "default"
|
||||
UseCanonicalName Off
|
||||
DocumentRoot /tmp
|
||||
ScriptAlias "/cgi-bin/" "/var/www/vhosts/default/cgi-bin"
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
SSLEngine off
|
||||
</IfModule>
|
||||
|
||||
<Directory "/var/www/vhosts/default/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
<Directory "/var/www/vhosts/default/htdocs">
|
||||
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
|
||||
<VirtualHost \
|
||||
0.0.0.0:7081 \
|
||||
127.0.0.1:7081 \
|
||||
>
|
||||
ServerName "default-0_0_0_0"
|
||||
UseCanonicalName Off
|
||||
DocumentRoot /tmp
|
||||
ScriptAlias "/cgi-bin/" "/var/www/vhosts/default/cgi-bin"
|
||||
|
||||
SSLEngine on
|
||||
SSLVerifyClient none
|
||||
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
|
||||
<Directory "/var/www/vhosts/default/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
<Directory "/var/www/vhosts/default/htdocs">
|
||||
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
<VirtualHost \
|
||||
[00000:000:000:000::2]:7081 \
|
||||
127.0.0.1:7081 \
|
||||
>
|
||||
ServerName "default-0000_000_000_00000__2"
|
||||
UseCanonicalName Off
|
||||
DocumentRoot /tmp
|
||||
ScriptAlias "/cgi-bin/" "/var/www/vhosts/default/cgi-bin"
|
||||
|
||||
SSLEngine on
|
||||
SSLVerifyClient none
|
||||
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
|
||||
<Directory "/var/www/vhosts/default/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
<Directory "/var/www/vhosts/default/htdocs">
|
||||
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
<VirtualHost \
|
||||
0.0.0.0:7081 \
|
||||
127.0.0.1:7081 \
|
||||
>
|
||||
ServerName "default-0_0_0_0"
|
||||
UseCanonicalName Off
|
||||
DocumentRoot /tmp
|
||||
ScriptAlias "/cgi-bin/" "/var/www/vhosts/default/cgi-bin"
|
||||
|
||||
SSLEngine on
|
||||
SSLVerifyClient none
|
||||
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
|
||||
#SSLCACertificateFile "/usr/local/psa/var/certificates/cert-nLy6Z1"
|
||||
|
||||
<Directory "/var/www/vhosts/default/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
<Directory "/var/www/vhosts/default/htdocs">
|
||||
|
||||
<IfModule sapi_apache2.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_php5.c>
|
||||
php_admin_flag engine on
|
||||
</IfModule>
|
||||
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
</IfModule>
|
||||
|
||||
<VirtualHost \
|
||||
0.0.0.0:7080 \
|
||||
[0000:000:000:000::2]:7080 \
|
||||
0.0.0.0:7080 \
|
||||
127.0.0.1:7080 \
|
||||
>
|
||||
DocumentRoot /tmp
|
||||
ServerName lists
|
||||
ServerAlias lists.*
|
||||
UseCanonicalName Off
|
||||
|
||||
ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
|
||||
|
||||
Alias "/icons/" "/var/www/icons/"
|
||||
Alias "/pipermail/" "/var/lib/mailman/archives/public/"
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
SSLEngine off
|
||||
</IfModule>
|
||||
|
||||
<Directory "/var/lib/mailman/archives/">
|
||||
Options FollowSymLinks
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost \
|
||||
0.0.0.0:7081 \
|
||||
[00000:000:000:0000::2]:7081 \
|
||||
0.0.0.0:7081 \
|
||||
127.0.0.1:7081 \
|
||||
>
|
||||
DocumentRoot /tmp
|
||||
ServerName lists
|
||||
ServerAlias lists.*
|
||||
UseCanonicalName Off
|
||||
|
||||
ScriptAlias "/mailman/" "/usr/lib/mailman/cgi-bin/"
|
||||
|
||||
Alias "/icons/" "/var/www/icons/"
|
||||
Alias "/pipermail/" "/var/lib/mailman/archives/public/"
|
||||
|
||||
SSLEngine on
|
||||
SSLVerifyClient none
|
||||
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
|
||||
<Directory "/var/lib/mailman/archives/">
|
||||
Options FollowSymLinks
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_rpaf.c>
|
||||
RPAFproxy_ips 0.0.0.0 [00000:000:000:00000::2] 0.0.0.0
|
||||
</IfModule>
|
||||
<IfModule mod_rpaf-2.0.c>
|
||||
RPAFproxy_ips 0.0.0.0 [0000:000:000:0000::2] 0.0.0.0
|
||||
</IfModule>
|
||||
<IfModule mod_remoteip.c>
|
||||
RemoteIPInternalProxy 0.0.0.0 [0000:000:000:0000::2] 0.0.0.0
|
||||
RemoteIPHeader X-Forwarded-For
|
||||
</IfModule>
|
||||
|
|
@ -746,9 +746,9 @@ class TwoVhost80Test(util.ApacheTest):
|
|||
self.config.parser.modules.add("rewrite_module")
|
||||
mock_exe.return_value = True
|
||||
ssl_vh = obj.VirtualHost(
|
||||
"fp", "ap", set([obj.Addr(("*", "443")),
|
||||
obj.Addr(("satoshi.com",))]),
|
||||
"fp", "ap", set([obj.Addr(("*", "443"))]),
|
||||
True, False)
|
||||
ssl_vh.name = "satoshi.com"
|
||||
self.config.vhosts.append(ssl_vh)
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# Depends: dav_svn
|
||||
<IfModule !mod_dav_svn.c>
|
||||
Include mods-enabled/dav_svn.load
|
||||
</IfModule>
|
||||
LoadModule authz_svn_module /usr/lib/apache2/modules/mod_authz_svn.so
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<IfModule !mod_dav.c>
|
||||
LoadModule dav_module /usr/lib/apache2/modules/mod_dav.so
|
||||
</IfModule>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# dav_svn.conf - Example Subversion/Apache configuration
|
||||
#
|
||||
# For details and further options see the Apache user manual and
|
||||
# the Subversion book.
|
||||
#
|
||||
# NOTE: for a setup with multiple vhosts, you will want to do this
|
||||
# configuration in /etc/apache2/sites-available/*, not here.
|
||||
|
||||
# <Location URL> ... </Location>
|
||||
# URL controls how the repository appears to the outside world.
|
||||
# In this example clients access the repository as http://hostname/svn/
|
||||
# Note, a literal /svn should NOT exist in your document root.
|
||||
#<Location /svn>
|
||||
|
||||
# Uncomment this to enable the repository
|
||||
#DAV svn
|
||||
|
||||
# Set this to the path to your repository
|
||||
#SVNPath /var/lib/svn
|
||||
# Alternatively, use SVNParentPath if you have multiple repositories under
|
||||
# under a single directory (/var/lib/svn/repo1, /var/lib/svn/repo2, ...).
|
||||
# You need either SVNPath and SVNParentPath, but not both.
|
||||
#SVNParentPath /var/lib/svn
|
||||
|
||||
# Access control is done at 3 levels: (1) Apache authentication, via
|
||||
# any of several methods. A "Basic Auth" section is commented out
|
||||
# below. (2) Apache <Limit> and <LimitExcept>, also commented out
|
||||
# below. (3) mod_authz_svn is a svn-specific authorization module
|
||||
# which offers fine-grained read/write access control for paths
|
||||
# within a repository. (The first two layers are coarse-grained; you
|
||||
# can only enable/disable access to an entire repository.) Note that
|
||||
# mod_authz_svn is noticeably slower than the other two layers, so if
|
||||
# you don't need the fine-grained control, don't configure it.
|
||||
|
||||
# Basic Authentication is repository-wide. It is not secure unless
|
||||
# you are using https. See the 'htpasswd' command to create and
|
||||
# manage the password file - and the documentation for the
|
||||
# 'auth_basic' and 'authn_file' modules, which you will need for this
|
||||
# (enable them with 'a2enmod').
|
||||
#AuthType Basic
|
||||
#AuthName "Subversion Repository"
|
||||
#AuthUserFile /etc/apache2/dav_svn.passwd
|
||||
|
||||
# To enable authorization via mod_authz_svn (enable that module separately):
|
||||
#<IfModule mod_authz_svn.c>
|
||||
#AuthzSVNAccessFile /etc/apache2/dav_svn.authz
|
||||
#</IfModule>
|
||||
|
||||
# The following three lines allow anonymous read, but make
|
||||
# committers authenticate themselves. It requires the 'authz_user'
|
||||
# module (enable it with 'a2enmod').
|
||||
#<LimitExcept GET PROPFIND OPTIONS REPORT>
|
||||
#Require valid-user
|
||||
#</LimitExcept>
|
||||
|
||||
#</Location>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Depends: dav
|
||||
<IfModule !mod_dav_svn.c>
|
||||
<IfModule !mod_dav.c>
|
||||
Include mods-enabled/dav.load
|
||||
</IfModule>
|
||||
LoadModule dav_svn_module /usr/lib/apache2/modules/mod_dav_svn.so
|
||||
</IfModule>
|
||||
|
|
@ -0,0 +1 @@
|
|||
../mods-available/authz_svn.load
|
||||
|
|
@ -0,0 +1 @@
|
|||
../mods-available/dav.load
|
||||
|
|
@ -0,0 +1 @@
|
|||
../mods-available/dav_svn.conf
|
||||
|
|
@ -0,0 +1 @@
|
|||
../mods-available/dav_svn.load
|
||||
|
|
@ -62,7 +62,7 @@ class ApacheTlsSni01(common.TLSSNI01):
|
|||
return []
|
||||
# Save any changes to the configuration as a precaution
|
||||
# About to make temporary changes to the config
|
||||
self.configurator.save()
|
||||
self.configurator.save("Changes before challenge setup", True)
|
||||
|
||||
# Prepare the server for HTTPS
|
||||
self.configurator.prepare_server_https(
|
||||
|
|
@ -108,7 +108,7 @@ class ApacheTlsSni01(common.TLSSNI01):
|
|||
self.configurator.reverter.register_file_creation(
|
||||
True, self.challenge_conf)
|
||||
|
||||
logger.debug("writing a config file with text: %s", config_text)
|
||||
logger.debug("writing a config file with text:\n %s", config_text)
|
||||
with open(self.challenge_conf, "w") as new_conf:
|
||||
new_conf.write(config_text)
|
||||
|
||||
|
|
@ -144,6 +144,8 @@ class ApacheTlsSni01(common.TLSSNI01):
|
|||
if len(self.configurator.parser.find_dir(
|
||||
parser.case_i("Include"), self.challenge_conf)) == 0:
|
||||
# print "Including challenge virtual host(s)"
|
||||
logger.debug("Adding Include %s to %s",
|
||||
self.challenge_conf, parser.get_aug_path(main_config))
|
||||
self.configurator.parser.add_dir(
|
||||
parser.get_aug_path(main_config),
|
||||
"Include", self.challenge_conf)
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
letsencrypt-auto-source/letsencrypt-auto
|
||||
1809
letsencrypt-auto
Executable file
1809
letsencrypt-auto
Executable file
File diff suppressed because it is too large
Load diff
|
|
@ -168,7 +168,7 @@ BootstrapDebCommon() {
|
|||
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
|
||||
fi
|
||||
|
||||
sudo sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO apt-get update
|
||||
fi
|
||||
fi
|
||||
|
|
@ -307,10 +307,11 @@ BootstrapArchCommon() {
|
|||
pkg-config
|
||||
"
|
||||
|
||||
missing=$("$SUDO" pacman -T $deps)
|
||||
# pacman -T exits with 127 if there are missing dependencies
|
||||
missing=$($SUDO pacman -T $deps) || true
|
||||
|
||||
if [ "$missing" ]; then
|
||||
"$SUDO" pacman -S --needed $missing
|
||||
$SUDO pacman -S --needed $missing
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -327,19 +328,19 @@ BootstrapGentooCommon() {
|
|||
|
||||
case "$PACKAGE_MANAGER" in
|
||||
(paludis)
|
||||
"$SUDO" cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
$SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
;;
|
||||
(pkgcore)
|
||||
"$SUDO" pmerge --noreplace --oneshot $PACKAGES
|
||||
$SUDO pmerge --noreplace --oneshot $PACKAGES
|
||||
;;
|
||||
(portage|*)
|
||||
"$SUDO" emerge --noreplace --oneshot $PACKAGES
|
||||
$SUDO emerge --noreplace --oneshot $PACKAGES
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
BootstrapFreeBsd() {
|
||||
"$SUDO" pkg install -Ay \
|
||||
$SUDO pkg install -Ay \
|
||||
python \
|
||||
py27-virtualenv \
|
||||
augeas \
|
||||
|
|
@ -362,8 +363,8 @@ BootstrapMac() {
|
|||
brew install dialog
|
||||
fi
|
||||
|
||||
if ! hash pip 2>/dev/null; then
|
||||
echo "pip not installed.\nInstalling python from Homebrew..."
|
||||
if [ -z "$(brew list --versions python)" ]; then
|
||||
echo "python not installed.\nInstalling python from Homebrew..."
|
||||
brew install python
|
||||
fi
|
||||
|
||||
|
|
@ -620,10 +621,6 @@ traceback2==1.4.0
|
|||
# sha256: IogqDkGMKE4fcYqCKzsCKUTVPS2QjhaQsxmp0-ssBXk
|
||||
unittest2==1.1.0
|
||||
|
||||
# sha256: aUkbUwUVfDxuDwSnAZhNaud_1yn8HJrNJQd_HfOFMms
|
||||
# sha256: 619wCpv8lkILBVY1r5AC02YuQ9gMP_0x8iTCW8DV9GI
|
||||
Werkzeug==0.11.3
|
||||
|
||||
# sha256: KCwRK1XdjjyGmjVx-GdnwVCrEoSprOK97CJsWSrK-Bo
|
||||
zope.component==4.2.2
|
||||
|
||||
|
|
@ -756,6 +753,7 @@ except ImportError:
|
|||
from pip.util import url_to_path # 0.7.0
|
||||
except ImportError:
|
||||
from pip.util import url_to_filename as url_to_path # 0.6.2
|
||||
from pip.exceptions import InstallationError
|
||||
from pip.index import PackageFinder, Link
|
||||
try:
|
||||
from pip.log import logger
|
||||
|
|
@ -774,7 +772,7 @@ except ImportError:
|
|||
|
||||
DownloadProgressBar = DownloadProgressSpinner = NullProgressBar
|
||||
|
||||
__version__ = 3, 0, 0
|
||||
__version__ = 3, 1, 1
|
||||
|
||||
try:
|
||||
from pip.index import FormatControl # noqa
|
||||
|
|
@ -792,6 +790,7 @@ ITS_FINE_ITS_FINE = 0
|
|||
SOMETHING_WENT_WRONG = 1
|
||||
# "Traditional" for command-line errors according to optparse docs:
|
||||
COMMAND_LINE_ERROR = 2
|
||||
UNHANDLED_EXCEPTION = 3
|
||||
|
||||
ARCHIVE_EXTENSIONS = ('.tar.bz2', '.tar.gz', '.tgz', '.tar', '.zip')
|
||||
|
||||
|
|
@ -1554,7 +1553,7 @@ def peep_install(argv):
|
|||
first_every_last(buckets[SatisfiedReq], *printers)
|
||||
|
||||
return ITS_FINE_ITS_FINE
|
||||
except (UnsupportedRequirementError, DownloadError) as exc:
|
||||
except (UnsupportedRequirementError, InstallationError, DownloadError) as exc:
|
||||
out(str(exc))
|
||||
return SOMETHING_WENT_WRONG
|
||||
finally:
|
||||
|
|
@ -1574,16 +1573,23 @@ def peep_port(paths):
|
|||
print('Please specify one or more requirements files so I have '
|
||||
'something to port.\n')
|
||||
return COMMAND_LINE_ERROR
|
||||
|
||||
comes_from = None
|
||||
for req in chain.from_iterable(
|
||||
_parse_requirements(path, package_finder(argv)) for path in paths):
|
||||
req_path, req_line = path_and_line(req)
|
||||
hashes = [hexlify(urlsafe_b64decode((hash + '=').encode('ascii'))).decode('ascii')
|
||||
for hash in hashes_above(*path_and_line(req))]
|
||||
for hash in hashes_above(req_path, req_line)]
|
||||
if req_path != comes_from:
|
||||
print()
|
||||
print('# from %s' % req_path)
|
||||
print()
|
||||
comes_from = req_path
|
||||
|
||||
if not hashes:
|
||||
print(req.req)
|
||||
elif len(hashes) == 1:
|
||||
print('%s --hash=sha256:%s' % (req.req, hashes[0]))
|
||||
else:
|
||||
print('%s' % req.req, end='')
|
||||
print('%s' % (req.link if getattr(req, 'link', None) else req.req), end='')
|
||||
for hash in hashes:
|
||||
print(' \\')
|
||||
print(' --hash=sha256:%s' % hash, end='')
|
||||
|
|
@ -1628,7 +1634,7 @@ if __name__ == '__main__':
|
|||
exit(main())
|
||||
except Exception:
|
||||
exception_handler(*sys.exc_info())
|
||||
exit(SOMETHING_WENT_WRONG)
|
||||
exit(UNHANDLED_EXCEPTION)
|
||||
|
||||
UNLIKELY_EOF
|
||||
# -------------------------------------------------------------------------
|
||||
|
|
@ -1810,12 +1816,21 @@ UNLIKELY_EOF
|
|||
# future Windows compatibility.
|
||||
"$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
|
||||
|
||||
# Install new copy of letsencrypt-auto. This preserves permissions and
|
||||
# ownership from the old copy.
|
||||
# Install new copy of letsencrypt-auto.
|
||||
# TODO: Deal with quotes in pathnames.
|
||||
echo "Replacing letsencrypt-auto..."
|
||||
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$0"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$0"
|
||||
# Clone permissions with cp. chmod and chown don't have a --reference
|
||||
# option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
|
||||
echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
# Using mv rather than cp leaves the old file descriptor pointing to the
|
||||
# original copy so the shell can continue to read it unmolested. mv across
|
||||
# filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
|
||||
# cp is unlikely to fail (esp. under sudo) if the rm doesn't.
|
||||
echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
# TODO: Clean up temp dir safely, even if it has quotes in its path.
|
||||
rm -rf "$TEMP_DIR"
|
||||
fi # A newer version is available.
|
||||
|
|
|
|||
|
|
@ -254,12 +254,21 @@ UNLIKELY_EOF
|
|||
# future Windows compatibility.
|
||||
"$LE_PYTHON" "$TEMP_DIR/fetch.py" --le-auto-script "v$REMOTE_VERSION"
|
||||
|
||||
# Install new copy of letsencrypt-auto. This preserves permissions and
|
||||
# ownership from the old copy.
|
||||
# Install new copy of letsencrypt-auto.
|
||||
# TODO: Deal with quotes in pathnames.
|
||||
echo "Replacing letsencrypt-auto..."
|
||||
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$0"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$0"
|
||||
# Clone permissions with cp. chmod and chown don't have a --reference
|
||||
# option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
|
||||
echo " " $SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp -p "$0" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
echo " " $SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
$SUDO cp "$TEMP_DIR/letsencrypt-auto" "$TEMP_DIR/letsencrypt-auto.permission-clone"
|
||||
# Using mv rather than cp leaves the old file descriptor pointing to the
|
||||
# original copy so the shell can continue to read it unmolested. mv across
|
||||
# filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
|
||||
# cp is unlikely to fail (esp. under sudo) if the rm doesn't.
|
||||
echo " " $SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
$SUDO mv -f "$TEMP_DIR/letsencrypt-auto.permission-clone" "$0"
|
||||
# TODO: Clean up temp dir safely, even if it has quotes in its path.
|
||||
rm -rf "$TEMP_DIR"
|
||||
fi # A newer version is available.
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ BootstrapArchCommon() {
|
|||
pkg-config
|
||||
"
|
||||
|
||||
missing=$("$SUDO" pacman -T $deps)
|
||||
# pacman -T exits with 127 if there are missing dependencies
|
||||
missing=$($SUDO pacman -T $deps) || true
|
||||
|
||||
if [ "$missing" ]; then
|
||||
"$SUDO" pacman -S --needed $missing
|
||||
$SUDO pacman -S --needed $missing
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ BootstrapDebCommon() {
|
|||
/bin/echo '(Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
|
||||
fi
|
||||
|
||||
sudo sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
|
||||
$SUDO apt-get update
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
BootstrapFreeBsd() {
|
||||
"$SUDO" pkg install -Ay \
|
||||
$SUDO pkg install -Ay \
|
||||
python \
|
||||
py27-virtualenv \
|
||||
augeas \
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ BootstrapGentooCommon() {
|
|||
|
||||
case "$PACKAGE_MANAGER" in
|
||||
(paludis)
|
||||
"$SUDO" cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
$SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
|
||||
;;
|
||||
(pkgcore)
|
||||
"$SUDO" pmerge --noreplace --oneshot $PACKAGES
|
||||
$SUDO pmerge --noreplace --oneshot $PACKAGES
|
||||
;;
|
||||
(portage|*)
|
||||
"$SUDO" emerge --noreplace --oneshot $PACKAGES
|
||||
$SUDO emerge --noreplace --oneshot $PACKAGES
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ BootstrapMac() {
|
|||
brew install dialog
|
||||
fi
|
||||
|
||||
if ! hash pip 2>/dev/null; then
|
||||
echo "pip not installed.\nInstalling python from Homebrew..."
|
||||
if [ -z "$(brew list --versions python)" ]; then
|
||||
echo "python not installed.\nInstalling python from Homebrew..."
|
||||
brew install python
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -172,10 +172,6 @@ traceback2==1.4.0
|
|||
# sha256: IogqDkGMKE4fcYqCKzsCKUTVPS2QjhaQsxmp0-ssBXk
|
||||
unittest2==1.1.0
|
||||
|
||||
# sha256: aUkbUwUVfDxuDwSnAZhNaud_1yn8HJrNJQd_HfOFMms
|
||||
# sha256: 619wCpv8lkILBVY1r5AC02YuQ9gMP_0x8iTCW8DV9GI
|
||||
Werkzeug==0.11.3
|
||||
|
||||
# sha256: KCwRK1XdjjyGmjVx-GdnwVCrEoSprOK97CJsWSrK-Bo
|
||||
zope.component==4.2.2
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ except ImportError:
|
|||
from pip.util import url_to_path # 0.7.0
|
||||
except ImportError:
|
||||
from pip.util import url_to_filename as url_to_path # 0.6.2
|
||||
from pip.exceptions import InstallationError
|
||||
from pip.index import PackageFinder, Link
|
||||
try:
|
||||
from pip.log import logger
|
||||
|
|
@ -104,7 +105,7 @@ except ImportError:
|
|||
|
||||
DownloadProgressBar = DownloadProgressSpinner = NullProgressBar
|
||||
|
||||
__version__ = 3, 0, 0
|
||||
__version__ = 3, 1, 1
|
||||
|
||||
try:
|
||||
from pip.index import FormatControl # noqa
|
||||
|
|
@ -122,6 +123,7 @@ ITS_FINE_ITS_FINE = 0
|
|||
SOMETHING_WENT_WRONG = 1
|
||||
# "Traditional" for command-line errors according to optparse docs:
|
||||
COMMAND_LINE_ERROR = 2
|
||||
UNHANDLED_EXCEPTION = 3
|
||||
|
||||
ARCHIVE_EXTENSIONS = ('.tar.bz2', '.tar.gz', '.tgz', '.tar', '.zip')
|
||||
|
||||
|
|
@ -884,7 +886,7 @@ def peep_install(argv):
|
|||
first_every_last(buckets[SatisfiedReq], *printers)
|
||||
|
||||
return ITS_FINE_ITS_FINE
|
||||
except (UnsupportedRequirementError, DownloadError) as exc:
|
||||
except (UnsupportedRequirementError, InstallationError, DownloadError) as exc:
|
||||
out(str(exc))
|
||||
return SOMETHING_WENT_WRONG
|
||||
finally:
|
||||
|
|
@ -904,16 +906,23 @@ def peep_port(paths):
|
|||
print('Please specify one or more requirements files so I have '
|
||||
'something to port.\n')
|
||||
return COMMAND_LINE_ERROR
|
||||
|
||||
comes_from = None
|
||||
for req in chain.from_iterable(
|
||||
_parse_requirements(path, package_finder(argv)) for path in paths):
|
||||
req_path, req_line = path_and_line(req)
|
||||
hashes = [hexlify(urlsafe_b64decode((hash + '=').encode('ascii'))).decode('ascii')
|
||||
for hash in hashes_above(*path_and_line(req))]
|
||||
for hash in hashes_above(req_path, req_line)]
|
||||
if req_path != comes_from:
|
||||
print()
|
||||
print('# from %s' % req_path)
|
||||
print()
|
||||
comes_from = req_path
|
||||
|
||||
if not hashes:
|
||||
print(req.req)
|
||||
elif len(hashes) == 1:
|
||||
print('%s --hash=sha256:%s' % (req.req, hashes[0]))
|
||||
else:
|
||||
print('%s' % req.req, end='')
|
||||
print('%s' % (req.link if getattr(req, 'link', None) else req.req), end='')
|
||||
for hash in hashes:
|
||||
print(' \\')
|
||||
print(' --hash=sha256:%s' % hash, end='')
|
||||
|
|
@ -958,4 +967,4 @@ if __name__ == '__main__':
|
|||
exit(main())
|
||||
except Exception:
|
||||
exception_handler(*sys.exc_info())
|
||||
exit(SOMETHING_WENT_WRONG)
|
||||
exit(UNHANDLED_EXCEPTION)
|
||||
|
|
|
|||
|
|
@ -34,11 +34,10 @@ SHARED_MODULES = {
|
|||
"vhost_alias"}
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IConfiguratorProxy)
|
||||
class Proxy(apache_common.Proxy):
|
||||
"""Wraps the ApacheConfigurator for Apache 2.4 tests"""
|
||||
|
||||
zope.interface.implements(interfaces.IConfiguratorProxy)
|
||||
|
||||
def __init__(self, args):
|
||||
"""Initializes the plugin with the given command line args"""
|
||||
super(Proxy, self).__init__(args)
|
||||
|
|
|
|||
|
|
@ -19,12 +19,11 @@ APACHE_VERSION_REGEX = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
|
|||
APACHE_COMMANDS = ["apachectl", "a2enmod", "a2dismod"]
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IConfiguratorProxy)
|
||||
class Proxy(configurators_common.Proxy):
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
"""A common base for Apache test configurators"""
|
||||
|
||||
zope.interface.implements(interfaces.IConfiguratorProxy)
|
||||
|
||||
def __init__(self, args):
|
||||
"""Initializes the plugin with the given command line args"""
|
||||
super(Proxy, self).__init__(args)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ from letsencrypt import interfaces
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IValidator)
|
||||
class Validator(object):
|
||||
# pylint: disable=no-self-use
|
||||
"""Collection of functions to test a live webserver's configuration"""
|
||||
zope.interface.implements(interfaces.IValidator)
|
||||
|
||||
def certificate(self, cert, name, alt_host=None, port=443):
|
||||
"""Verifies the certificate presented at name is cert"""
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ from letsencrypt_nginx import parser
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator, interfaces.IInstaller)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class NginxConfigurator(common.Plugin):
|
||||
# pylint: disable=too-many-instance-attributes,too-many-public-methods
|
||||
"""Nginx configurator.
|
||||
|
|
@ -52,8 +54,6 @@ class NginxConfigurator(common.Plugin):
|
|||
:ivar tup version: version of Nginx
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IAuthenticator, interfaces.IInstaller)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Nginx Web Server - currently doesn't work"
|
||||
|
||||
|
|
|
|||
|
|
@ -230,23 +230,23 @@ class NginxParserTest(util.NginxTest):
|
|||
|
||||
def test_parse_server_ssl(self):
|
||||
server = parser.parse_server([
|
||||
['listen', '443']
|
||||
])
|
||||
['listen', '443']
|
||||
])
|
||||
self.assertFalse(server['ssl'])
|
||||
|
||||
server = parser.parse_server([
|
||||
['listen', '443 ssl']
|
||||
])
|
||||
['listen', '443 ssl']
|
||||
])
|
||||
self.assertTrue(server['ssl'])
|
||||
|
||||
server = parser.parse_server([
|
||||
['listen', '443'], ['ssl', 'off']
|
||||
])
|
||||
['listen', '443'], ['ssl', 'off']
|
||||
])
|
||||
self.assertFalse(server['ssl'])
|
||||
|
||||
server = parser.parse_server([
|
||||
['listen', '443'], ['ssl', 'on']
|
||||
])
|
||||
['listen', '443'], ['ssl', 'on']
|
||||
])
|
||||
self.assertTrue(server['ssl'])
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -983,10 +983,6 @@ def renew(config, unused_plugins):
|
|||
"renew specific certificates, use the certonly "
|
||||
"command. The renew verb may provide other options "
|
||||
"for selecting certificates to renew in the future.")
|
||||
if config.csr is not None:
|
||||
raise errors.Error("Currently, the renew verb cannot be used when "
|
||||
"specifying a CSR file. Please try the certonly "
|
||||
"command instead.")
|
||||
renewer_config = configuration.RenewerConfiguration(config)
|
||||
renew_successes = []
|
||||
renew_failures = []
|
||||
|
|
@ -1030,6 +1026,12 @@ def renew(config, unused_plugins):
|
|||
_renew_describe_results(config, renew_successes, renew_failures,
|
||||
renew_skipped, parse_failures)
|
||||
|
||||
if renew_failures or parse_failures:
|
||||
raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
|
||||
len(renew_failures), len(parse_failures)))
|
||||
else:
|
||||
logger.debug("no renewal failures")
|
||||
|
||||
|
||||
def revoke(config, unused_plugins): # TODO: coop with renewal config
|
||||
"""Revoke a previously obtained certificate."""
|
||||
|
|
@ -1244,6 +1246,12 @@ class HelpfulArgumentParser(object):
|
|||
Process a --csr flag. This needs to happen early enough that the
|
||||
webroot plugin can know about the calls to _process_domain
|
||||
"""
|
||||
if parsed_args.verb != "certonly":
|
||||
raise errors.Error("Currently, a CSR file may only be specified "
|
||||
"when obtaining a new or replacement "
|
||||
"via the certonly command. Please try the "
|
||||
"certonly command instead.")
|
||||
|
||||
try:
|
||||
csr = le_util.CSR(file=parsed_args.csr[0], data=parsed_args.csr[1], form="der")
|
||||
typ = OpenSSL.crypto.FILETYPE_ASN1
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from letsencrypt import interfaces
|
|||
from letsencrypt import le_util
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IConfig)
|
||||
class NamespaceConfig(object):
|
||||
"""Configuration wrapper around :class:`argparse.Namespace`.
|
||||
|
||||
|
|
@ -32,7 +33,6 @@ class NamespaceConfig(object):
|
|||
:type namespace: :class:`argparse.Namespace`
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IConfig)
|
||||
|
||||
def __init__(self, namespace):
|
||||
self.namespace = namespace
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from letsencrypt import interfaces
|
|||
from letsencrypt import proof_of_possession
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
class ContinuityAuthenticator(object):
|
||||
"""IAuthenticator for
|
||||
:const:`~acme.challenges.ContinuityChallenge` class challenges.
|
||||
|
|
@ -18,7 +19,6 @@ class ContinuityAuthenticator(object):
|
|||
:class:`letsencrypt.proof_of_possession.Proof_of_Possession`
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
|
||||
# This will have an installer soon for get_key/cert purposes
|
||||
def __init__(self, config, installer): # pylint: disable=unused-argument
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ def make_csr(key_str, domains):
|
|||
value=", ".join("DNS:%s" % d for d in domains)
|
||||
),
|
||||
])
|
||||
req.set_version(2)
|
||||
req.set_pubkey(pkey)
|
||||
req.sign(pkey, "sha256")
|
||||
return tuple(OpenSSL.crypto.dump_certificate_request(method, req)
|
||||
|
|
|
|||
|
|
@ -36,11 +36,10 @@ def _wrap_lines(msg):
|
|||
fixed_l.append(textwrap.fill(line, 80))
|
||||
return os.linesep.join(fixed_l)
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
class NcursesDisplay(object):
|
||||
"""Ncurses-based display."""
|
||||
|
||||
zope.interface.implements(interfaces.IDisplay)
|
||||
|
||||
def __init__(self, width=WIDTH, height=HEIGHT):
|
||||
super(NcursesDisplay, self).__init__()
|
||||
self.dialog = dialog.Dialog()
|
||||
|
|
@ -176,11 +175,10 @@ class NcursesDisplay(object):
|
|||
message, width=self.width, height=self.height, choices=choices)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
class FileDisplay(object):
|
||||
"""File-based display."""
|
||||
|
||||
zope.interface.implements(interfaces.IDisplay)
|
||||
|
||||
def __init__(self, outfile):
|
||||
super(FileDisplay, self).__init__()
|
||||
self.outfile = outfile
|
||||
|
|
@ -411,11 +409,10 @@ class FileDisplay(object):
|
|||
|
||||
return OK, selection
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
class NoninteractiveDisplay(object):
|
||||
"""An iDisplay implementation that never asks for interactive user input"""
|
||||
|
||||
zope.interface.implements(interfaces.IDisplay)
|
||||
|
||||
def __init__(self, outfile):
|
||||
super(NoninteractiveDisplay, self).__init__()
|
||||
self.outfile = outfile
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ hostname_regex = re.compile(
|
|||
r"^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*[a-z]+$", re.IGNORECASE)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IPlugin)
|
||||
class Plugin(object):
|
||||
"""Generic plugin."""
|
||||
zope.interface.implements(interfaces.IPlugin)
|
||||
# classProvides is not inherited, subclasses must define it on their own
|
||||
#zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
# provider is not inherited, subclasses must define it on their own
|
||||
# @zope.interface.provider(interfaces.IPluginFactory)
|
||||
|
||||
def __init__(self, config, name):
|
||||
self.config = config
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ from letsencrypt.plugins import common
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Authenticator(common.Plugin):
|
||||
"""Manual Authenticator.
|
||||
|
||||
|
|
@ -34,8 +36,6 @@ class Authenticator(common.Plugin):
|
|||
.. todo:: Support for `~.challenges.TLSSNI01`.
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
hidden = True
|
||||
|
||||
description = "Manually configure an HTTP server"
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ from letsencrypt.plugins import common
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IInstaller)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Installer(common.Plugin):
|
||||
"""Null installer."""
|
||||
zope.interface.implements(interfaces.IInstaller)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Null Installer"
|
||||
hidden = True
|
||||
|
|
|
|||
|
|
@ -135,6 +135,8 @@ def supported_challenges_validator(data):
|
|||
return data
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Authenticator(common.Plugin):
|
||||
"""Standalone Authenticator.
|
||||
|
||||
|
|
@ -143,8 +145,6 @@ class Authenticator(common.Plugin):
|
|||
challenges from the certificate authority. Therefore, it does not
|
||||
rely on any existing server program.
|
||||
"""
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Automatically use a temporary webserver"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ from letsencrypt.plugins import common
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||
@zope.interface.provider(interfaces.IPluginFactory)
|
||||
class Authenticator(common.Plugin):
|
||||
"""Webroot Authenticator."""
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
||||
description = "Webroot Authenticator"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from letsencrypt import le_util
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IReporter)
|
||||
class Reporter(object):
|
||||
"""Collects and displays information to the user.
|
||||
|
||||
|
|
@ -24,7 +25,6 @@ class Reporter(object):
|
|||
the user.
|
||||
|
||||
"""
|
||||
zope.interface.implements(interfaces.IReporter)
|
||||
|
||||
HIGH_PRIORITY = 0
|
||||
"""High priority constant. See `add_message`."""
|
||||
|
|
|
|||
|
|
@ -356,6 +356,15 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self._call,
|
||||
['-d', '204.11.231.35'])
|
||||
|
||||
def test_run_with_csr(self):
|
||||
# This is an error because you can only use --csr with certonly
|
||||
try:
|
||||
self._call(['--csr', CSR])
|
||||
except errors.Error as e:
|
||||
assert "Please try the certonly" in e.message
|
||||
return
|
||||
assert False, "Expected supplying --csr to fail with default verb"
|
||||
|
||||
def _get_argument_parser(self):
|
||||
plugins = disco.PluginsRegistry.find_all()
|
||||
return functools.partial(cli.prepare_and_parse_args, plugins)
|
||||
|
|
@ -540,8 +549,8 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self._certonly_new_request_common, mock_client)
|
||||
|
||||
def _test_renewal_common(self, due_for_renewal, extra_args, log_out=None,
|
||||
args=None, renew=True):
|
||||
# pylint: disable=too-many-locals
|
||||
args=None, renew=True, error_expected=False):
|
||||
# pylint: disable=too-many-locals,too-many-arguments
|
||||
cert_path = 'letsencrypt/tests/testdata/cert.pem'
|
||||
chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem'
|
||||
mock_lineage = mock.MagicMock(cert=cert_path, fullchain=chain_path)
|
||||
|
|
@ -567,11 +576,17 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
args = ['-d', 'isnot.org', '-a', 'standalone', 'certonly']
|
||||
if extra_args:
|
||||
args += extra_args
|
||||
self._call(args)
|
||||
|
||||
if log_out:
|
||||
with open(os.path.join(self.logs_dir, "letsencrypt.log")) as lf:
|
||||
self.assertTrue(log_out in lf.read())
|
||||
try:
|
||||
ret, _, _, _ = self._call(args)
|
||||
if ret:
|
||||
print "Returned", ret
|
||||
raise AssertionError(ret)
|
||||
assert not error_expected, "renewal should have errored"
|
||||
except: # pylint: disable=bare-except
|
||||
if not error_expected:
|
||||
raise AssertionError(
|
||||
"Unexpected renewal error:\n" +
|
||||
traceback.format_exc())
|
||||
|
||||
if renew:
|
||||
mock_client.obtain_certificate.assert_called_once_with(['isnot.org'])
|
||||
|
|
@ -580,6 +595,10 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
except:
|
||||
self._dump_log()
|
||||
raise
|
||||
finally:
|
||||
if log_out:
|
||||
with open(os.path.join(self.logs_dir, "letsencrypt.log")) as lf:
|
||||
self.assertTrue(log_out in lf.read())
|
||||
|
||||
return mock_lineage, mock_get_utility
|
||||
|
||||
|
|
@ -625,11 +644,13 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self._test_renewal_common(True, [], args=args, renew=True)
|
||||
|
||||
def test_renew_verb_empty_config(self):
|
||||
renewer_configs_dir = os.path.join(self.config_dir, 'renewal')
|
||||
os.makedirs(renewer_configs_dir)
|
||||
with open(os.path.join(renewer_configs_dir, 'empty.conf'), 'w'):
|
||||
rd = os.path.join(self.config_dir, 'renewal')
|
||||
if not os.path.exists(rd):
|
||||
os.makedirs(rd)
|
||||
with open(os.path.join(rd, 'empty.conf'), 'w'):
|
||||
pass # leave the file empty
|
||||
self.test_renew_verb()
|
||||
args = ["renew", "--dry-run", "-tvv"]
|
||||
self._test_renewal_common(False, [], args=args, renew=False, error_expected=True)
|
||||
|
||||
def _make_dummy_renewal_config(self):
|
||||
renewer_configs_dir = os.path.join(self.config_dir, 'renewal')
|
||||
|
|
@ -637,7 +658,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
with open(os.path.join(renewer_configs_dir, 'test.conf'), 'w') as f:
|
||||
f.write("My contents don't matter")
|
||||
|
||||
def _test_renew_common(self, renewalparams=None,
|
||||
def _test_renew_common(self, renewalparams=None, error_expected=False,
|
||||
names=None, assert_oc_called=None):
|
||||
self._make_dummy_renewal_config()
|
||||
with mock.patch('letsencrypt.storage.RenewableCert') as mock_rc:
|
||||
|
|
@ -649,7 +670,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
mock_lineage.names.return_value = names
|
||||
mock_rc.return_value = mock_lineage
|
||||
with mock.patch('letsencrypt.cli.obtain_cert') as mock_obtain_cert:
|
||||
self._test_renewal_common(True, None,
|
||||
self._test_renewal_common(True, None, error_expected=error_expected,
|
||||
args=['renew'], renew=False)
|
||||
if assert_oc_called is not None:
|
||||
if assert_oc_called:
|
||||
|
|
@ -658,21 +679,22 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
self.assertFalse(mock_obtain_cert.called)
|
||||
|
||||
def test_renew_no_renewalparams(self):
|
||||
self._test_renew_common(assert_oc_called=False)
|
||||
self._test_renew_common(assert_oc_called=False, error_expected=True)
|
||||
|
||||
def test_renew_no_authenticator(self):
|
||||
self._test_renew_common(renewalparams={}, assert_oc_called=False)
|
||||
self._test_renew_common(renewalparams={}, assert_oc_called=False,
|
||||
error_expected=True)
|
||||
|
||||
def test_renew_with_bad_int(self):
|
||||
renewalparams = {'authenticator': 'webroot',
|
||||
'rsa_key_size': 'over 9000'}
|
||||
self._test_renew_common(renewalparams=renewalparams,
|
||||
self._test_renew_common(renewalparams=renewalparams, error_expected=True,
|
||||
assert_oc_called=False)
|
||||
|
||||
def test_renew_with_bad_domain(self):
|
||||
renewalparams = {'authenticator': 'webroot'}
|
||||
names = ['*.example.com']
|
||||
self._test_renew_common(renewalparams=renewalparams,
|
||||
self._test_renew_common(renewalparams=renewalparams, error_expected=True,
|
||||
names=names, assert_oc_called=False)
|
||||
|
||||
def test_renew_plugin_config_restoration(self):
|
||||
|
|
@ -686,7 +708,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
# pylint: disable=protected-access
|
||||
with mock.patch('letsencrypt.cli._reconstitute') as mock_reconstitute:
|
||||
mock_reconstitute.side_effect = Exception
|
||||
self._test_renew_common(assert_oc_called=False)
|
||||
self._test_renew_common(assert_oc_called=False, error_expected=True)
|
||||
|
||||
def test_renew_obtain_cert_error(self):
|
||||
self._make_dummy_renewal_config()
|
||||
|
|
@ -698,15 +720,14 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods
|
|||
'renewalparams': {'authenticator': 'webroot'}}
|
||||
with mock.patch('letsencrypt.cli.obtain_cert') as mock_obtain_cert:
|
||||
mock_obtain_cert.side_effect = Exception
|
||||
self._test_renewal_common(True, None,
|
||||
self._test_renewal_common(True, None, error_expected=True,
|
||||
args=['renew'], renew=False)
|
||||
|
||||
def test_renew_with_bad_cli_args(self):
|
||||
self.assertRaises(errors.Error, self._test_renewal_common, True, None,
|
||||
args='renew -d example.com'.split(), renew=False)
|
||||
self.assertRaises(errors.Error, self._test_renewal_common, True, None,
|
||||
args='renew --csr {0}'.format(CSR).split(),
|
||||
renew=False)
|
||||
self._test_renewal_common(True, None, args='renew -d example.com'.split(),
|
||||
renew=False, error_expected=True)
|
||||
self._test_renewal_common(True, None, args='renew --csr {0}'.format(CSR).split(),
|
||||
renew=False, error_expected=True)
|
||||
|
||||
@mock.patch('letsencrypt.cli.zope.component.getUtility')
|
||||
@mock.patch('letsencrypt.cli._treat_as_renewal')
|
||||
|
|
|
|||
|
|
@ -83,6 +83,14 @@ class RegisterTest(unittest.TestCase):
|
|||
self._call()
|
||||
mock_logger.warn.assert_called_once_with(mock.ANY)
|
||||
|
||||
def test_unsupported_error(self):
|
||||
from acme import messages
|
||||
msg = "Test"
|
||||
mx_err = messages.Error(detail=msg, typ="malformed", title="title")
|
||||
with mock.patch("letsencrypt.client.acme_client.Client") as mock_client:
|
||||
mock_client().register.side_effect = [mx_err, mock.MagicMock()]
|
||||
self.assertRaises(messages.Error, self._call)
|
||||
|
||||
class ClientTest(unittest.TestCase):
|
||||
"""Tests for letsencrypt.client.Client."""
|
||||
|
||||
|
|
@ -119,12 +127,16 @@ class ClientTest(unittest.TestCase):
|
|||
self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr)
|
||||
|
||||
# FIXME move parts of this to test_cli.py...
|
||||
@mock.patch("letsencrypt.client.logger")
|
||||
@mock.patch("letsencrypt.cli._process_domain")
|
||||
def test_obtain_certificate_from_csr(self, mock_process_domain):
|
||||
def test_obtain_certificate_from_csr(self, mock_process_domain, mock_logger):
|
||||
self._mock_obtain_certificate()
|
||||
from letsencrypt import cli
|
||||
test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
|
||||
mock_parsed_args = mock.MagicMock()
|
||||
# The CLI should believe that this is a certonly request, because
|
||||
# a CSR would not be allowed with other kinds of requests!
|
||||
mock_parsed_args.verb = "certonly"
|
||||
with mock.patch("letsencrypt.client.le_util.CSR") as mock_CSR:
|
||||
mock_CSR.return_value = test_csr
|
||||
mock_parsed_args.domains = self.eg_domains[:]
|
||||
|
|
@ -145,6 +157,14 @@ class ClientTest(unittest.TestCase):
|
|||
# and that the cert was obtained correctly
|
||||
self._check_obtain_certificate()
|
||||
|
||||
# Test for no auth_handler
|
||||
self.client.auth_handler = None
|
||||
self.assertRaises(
|
||||
errors.Error,
|
||||
self.client.obtain_certificate_from_csr,
|
||||
self.eg_domains,
|
||||
test_csr)
|
||||
mock_logger.warning.assert_called_once_with(mock.ANY)
|
||||
|
||||
@mock.patch("letsencrypt.client.crypto_util")
|
||||
def test_obtain_certificate(self, mock_crypto_util):
|
||||
|
|
|
|||
|
|
@ -333,6 +333,55 @@ def create_client_instances(targetlist):
|
|||
print()
|
||||
return instances
|
||||
|
||||
|
||||
def test_client_process(inqueue, outqueue):
|
||||
cur_proc = mp.current_process()
|
||||
for inreq in iter(inqueue.get, SENTINEL):
|
||||
ii, target = inreq
|
||||
|
||||
#save all stdout to log file
|
||||
sys.stdout = open(LOGDIR+'/'+'%d_%s.log'%(ii,target['name']), 'w')
|
||||
|
||||
print("[%s : client %d %s %s]" % (cur_proc.name, ii, target['ami'], target['name']))
|
||||
instances[ii] = block_until_instance_ready(instances[ii])
|
||||
print("server %s at %s"%(instances[ii], instances[ii].public_ip_address))
|
||||
env.host_string = "%s@%s"%(target['user'], instances[ii].public_ip_address)
|
||||
print(env.host_string)
|
||||
|
||||
try:
|
||||
install_and_launch_letsencrypt(instances[ii], boulder_url, target)
|
||||
outqueue.put((ii, target, 'pass'))
|
||||
print("%s - %s SUCCESS"%(target['ami'], target['name']))
|
||||
except:
|
||||
outqueue.put((ii, target, 'fail'))
|
||||
print("%s - %s FAIL"%(target['ami'], target['name']))
|
||||
pass
|
||||
|
||||
# append server letsencrypt.log to each per-machine output log
|
||||
print("\n\nletsencrypt.log\n" + "-"*80 + "\n")
|
||||
try:
|
||||
execute(grab_letsencrypt_log)
|
||||
except:
|
||||
print("log fail\n")
|
||||
pass
|
||||
|
||||
|
||||
def cleanup(cl_args, instances, targetlist):
|
||||
print('Logs in ', LOGDIR)
|
||||
if not cl_args.saveinstances:
|
||||
print('Terminating EC2 Instances and Cleaning Dangling EBS Volumes')
|
||||
if cl_args.killboulder:
|
||||
boulder_server.terminate()
|
||||
terminate_and_clean(instances)
|
||||
else:
|
||||
# print login information for the boxes for debugging
|
||||
for ii, target in enumerate(targetlist):
|
||||
print(target['name'],
|
||||
target['ami'],
|
||||
"%s@%s"%(target['user'], instances[ii].public_ip_address))
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# SCRIPT BEGINS
|
||||
#-------------------------------------------------------------------------------
|
||||
|
|
@ -413,124 +462,85 @@ else:
|
|||
#machine_type='t2.medium',
|
||||
security_groups=['letsencrypt_test'])
|
||||
|
||||
if not cl_args.boulderonly:
|
||||
instances = create_client_instances(targetlist)
|
||||
try:
|
||||
if not cl_args.boulderonly:
|
||||
instances = create_client_instances(targetlist)
|
||||
|
||||
# Configure and launch boulder server
|
||||
#-------------------------------------------------------------------------------
|
||||
print("Waiting on Boulder Server")
|
||||
boulder_server = block_until_instance_ready(boulder_server)
|
||||
print(" server %s"%boulder_server)
|
||||
# Configure and launch boulder server
|
||||
#-------------------------------------------------------------------------------
|
||||
print("Waiting on Boulder Server")
|
||||
boulder_server = block_until_instance_ready(boulder_server)
|
||||
print(" server %s"%boulder_server)
|
||||
|
||||
|
||||
# env.host_string defines the ssh user and host for connection
|
||||
env.host_string = "ubuntu@%s"%boulder_server.public_ip_address
|
||||
print("Boulder Server at (SSH):", env.host_string)
|
||||
if not boulder_preexists:
|
||||
print("Configuring and Launching Boulder")
|
||||
config_and_launch_boulder(boulder_server)
|
||||
# blocking often unnecessary, but cheap EC2 VMs can get very slow
|
||||
block_until_http_ready('http://%s:4000'%boulder_server.public_ip_address,
|
||||
wait_time=10, timeout=500)
|
||||
# env.host_string defines the ssh user and host for connection
|
||||
env.host_string = "ubuntu@%s"%boulder_server.public_ip_address
|
||||
print("Boulder Server at (SSH):", env.host_string)
|
||||
if not boulder_preexists:
|
||||
print("Configuring and Launching Boulder")
|
||||
config_and_launch_boulder(boulder_server)
|
||||
# blocking often unnecessary, but cheap EC2 VMs can get very slow
|
||||
block_until_http_ready('http://%s:4000'%boulder_server.public_ip_address,
|
||||
wait_time=10, timeout=500)
|
||||
|
||||
boulder_url = "http://%s:4000/directory"%boulder_server.private_ip_address
|
||||
print("Boulder Server at (public ip): http://%s:4000/directory"%boulder_server.public_ip_address)
|
||||
print("Boulder Server at (EC2 private ip): %s"%boulder_url)
|
||||
boulder_url = "http://%s:4000/directory"%boulder_server.private_ip_address
|
||||
print("Boulder Server at (public ip): http://%s:4000/directory"%boulder_server.public_ip_address)
|
||||
print("Boulder Server at (EC2 private ip): %s"%boulder_url)
|
||||
|
||||
if cl_args.boulderonly:
|
||||
sys.exit(0)
|
||||
if cl_args.boulderonly:
|
||||
sys.exit(0)
|
||||
|
||||
# Install and launch client scripts in parallel
|
||||
#-------------------------------------------------------------------------------
|
||||
print("Uploading and running test script in parallel: %s"%cl_args.test_script)
|
||||
print("Output routed to log files in %s"%LOGDIR)
|
||||
# (Advice: always use Manager.Queue, never regular multiprocessing.Queue
|
||||
# the latter has implementation flaws that deadlock it in some circumstances)
|
||||
manager = Manager()
|
||||
outqueue = manager.Queue()
|
||||
inqueue = manager.Queue()
|
||||
SENTINEL = None #queue kill signal
|
||||
# Install and launch client scripts in parallel
|
||||
#-------------------------------------------------------------------------------
|
||||
print("Uploading and running test script in parallel: %s"%cl_args.test_script)
|
||||
print("Output routed to log files in %s"%LOGDIR)
|
||||
# (Advice: always use Manager.Queue, never regular multiprocessing.Queue
|
||||
# the latter has implementation flaws that deadlock it in some circumstances)
|
||||
manager = Manager()
|
||||
outqueue = manager.Queue()
|
||||
inqueue = manager.Queue()
|
||||
SENTINEL = None #queue kill signal
|
||||
|
||||
# launch as many processes as clients to test
|
||||
num_processes = len(targetlist)
|
||||
jobs = [] #keep a reference to current procs
|
||||
# launch as many processes as clients to test
|
||||
num_processes = len(targetlist)
|
||||
jobs = [] #keep a reference to current procs
|
||||
|
||||
def test_client_process(inqueue, outqueue):
|
||||
cur_proc = mp.current_process()
|
||||
for inreq in iter(inqueue.get, SENTINEL):
|
||||
ii, target = inreq
|
||||
|
||||
#save all stdout to log file
|
||||
sys.stdout = open(LOGDIR+'/'+'%d_%s.log'%(ii,target['name']), 'w')
|
||||
# initiate process execution
|
||||
for i in range(num_processes):
|
||||
p = mp.Process(target=test_client_process, args=(inqueue, outqueue))
|
||||
jobs.append(p)
|
||||
p.daemon = True # kills subprocesses if parent is killed
|
||||
p.start()
|
||||
|
||||
print("[%s : client %d %s %s]" % (cur_proc.name, ii, target['ami'], target['name']))
|
||||
instances[ii] = block_until_instance_ready(instances[ii])
|
||||
print("server %s at %s"%(instances[ii], instances[ii].public_ip_address))
|
||||
env.host_string = "%s@%s"%(target['user'], instances[ii].public_ip_address)
|
||||
print(env.host_string)
|
||||
|
||||
try:
|
||||
install_and_launch_letsencrypt(instances[ii], boulder_url, target)
|
||||
outqueue.put((ii, target, 'pass'))
|
||||
print("%s - %s SUCCESS"%(target['ami'], target['name']))
|
||||
except:
|
||||
outqueue.put((ii, target, 'fail'))
|
||||
print("%s - %s FAIL"%(target['ami'], target['name']))
|
||||
pass
|
||||
|
||||
# append server letsencrypt.log to each per-machine output log
|
||||
print("\n\nletsencrypt.log\n" + "-"*80 + "\n")
|
||||
try:
|
||||
execute(grab_letsencrypt_log)
|
||||
except:
|
||||
print("log fail\n")
|
||||
pass
|
||||
|
||||
# initiate process execution
|
||||
for i in range(num_processes):
|
||||
p = mp.Process(target=test_client_process, args=(inqueue, outqueue))
|
||||
jobs.append(p)
|
||||
p.daemon = True # kills subprocesses if parent is killed
|
||||
p.start()
|
||||
|
||||
# fill up work queue
|
||||
for ii, target in enumerate(targetlist):
|
||||
inqueue.put((ii, target))
|
||||
|
||||
# add SENTINELs to end client processes
|
||||
for i in range(num_processes):
|
||||
inqueue.put(SENTINEL)
|
||||
# wait on termination of client processes
|
||||
for p in jobs:
|
||||
p.join()
|
||||
# add SENTINEL to output queue
|
||||
outqueue.put(SENTINEL)
|
||||
|
||||
# clean up
|
||||
execute(local_repo_clean)
|
||||
|
||||
# print and save summary results
|
||||
results_file = open(LOGDIR+'/results', 'w')
|
||||
outputs = [outq for outq in iter(outqueue.get, SENTINEL)]
|
||||
outputs.sort(key=lambda x: x[0])
|
||||
for outq in outputs:
|
||||
ii, target, status = outq
|
||||
print('%d %s %s'%(ii, target['name'], status))
|
||||
results_file.write('%d %s %s\n'%(ii, target['name'], status))
|
||||
results_file.close()
|
||||
|
||||
if not cl_args.saveinstances:
|
||||
print('Logs in ', LOGDIR)
|
||||
print('Terminating EC2 Instances and Cleaning Dangling EBS Volumes')
|
||||
if cl_args.killboulder:
|
||||
boulder_server.terminate()
|
||||
terminate_and_clean(instances)
|
||||
else:
|
||||
# print login information for the boxes for debugging
|
||||
# fill up work queue
|
||||
for ii, target in enumerate(targetlist):
|
||||
print(target['name'],
|
||||
target['ami'],
|
||||
"%s@%s"%(target['user'], instances[ii].public_ip_address))
|
||||
inqueue.put((ii, target))
|
||||
|
||||
# kill any connections
|
||||
fabric.network.disconnect_all()
|
||||
# add SENTINELs to end client processes
|
||||
for i in range(num_processes):
|
||||
inqueue.put(SENTINEL)
|
||||
# wait on termination of client processes
|
||||
for p in jobs:
|
||||
p.join()
|
||||
# add SENTINEL to output queue
|
||||
outqueue.put(SENTINEL)
|
||||
|
||||
# clean up
|
||||
execute(local_repo_clean)
|
||||
|
||||
# print and save summary results
|
||||
results_file = open(LOGDIR+'/results', 'w')
|
||||
outputs = [outq for outq in iter(outqueue.get, SENTINEL)]
|
||||
outputs.sort(key=lambda x: x[0])
|
||||
for outq in outputs:
|
||||
ii, target, status = outq
|
||||
print('%d %s %s'%(ii, target['name'], status))
|
||||
results_file.write('%d %s %s\n'%(ii, target['name'], status))
|
||||
results_file.close()
|
||||
|
||||
finally:
|
||||
cleanup(cl_args, instances, targetlist)
|
||||
|
||||
# kill any connections
|
||||
fabric.network.disconnect_all()
|
||||
|
|
|
|||
|
|
@ -171,7 +171,10 @@ while ! openssl dgst -sha256 -verify $RELEASE_OPENSSL_PUBKEY -signature \
|
|||
read -p "Please correctly sign letsencrypt-auto with offline-signrequest.sh"
|
||||
done
|
||||
|
||||
git add letsencrypt-auto-source
|
||||
# copy leauto to the root, overwriting the previous release version
|
||||
cp -p letsencrypt-auto-source/letsencrypt-auto letsencrypt-auto
|
||||
|
||||
git add letsencrypt-auto letsencrypt-auto-source
|
||||
git diff --cached
|
||||
git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"
|
||||
git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag"
|
||||
|
|
|
|||
Loading…
Reference in a new issue