Compare commits

...

10 Commits

Author SHA1 Message Date
Brad Warren
d9a2612d21 Release 0.14.2 2017-05-25 14:23:35 -07:00
Brad Warren
fbd0325673 Fixes #4719 (#4737) (#4740)
* Automatically delete temp log file when not used.

This allows close() calls in logging.shutdown() to cause the file to be
deleted when no logging output has been written to the file.

* Make certbot.log.MemoryHandler.flush() a noop.

This causes MemoryHandler.flush() calls in logging.shutdown to be a noop,
allowing us to control when the handler is actually flushed. This prevents log
records from being sent to a temporary file handler for things like
`certbot --version`.

* Keep reference to certbot.log.MemoryHandler.target

In Python 2.7+, the logging module only keeps weak references to created
logging handlers. Because of this, the MemoryHandler's target will not be
properly flushed and closed when logging.shutdown() is called on program exit
unless we keep a reference to it in the MemoryHandler.

* Fixes #4719.

This completes the changes necessary to fix #4719. Now temporary log files are
not created if sys.exit() is called before logging is fully set up. These files
are still created if Certbot crashes for any other reason.

* Document pre_arg_parse_except_hook args.

(cherry picked from commit 93310fe67c)
2017-05-25 14:07:40 -07:00
Brad Warren
c5d11d333f Merge pull request #4674 from certbot/0.14.x+1
Release 0.14.1
2017-05-16 14:33:43 -07:00
Brad Warren
78e3bd6e8c Release 0.14.1 2017-05-16 10:03:51 -07:00
ohemorange
44ab49bcd6 Allow Nginx to insert include files with comments inside (#4666) (#4668)
* add failing test case

* allow include files to insert comments

* lint
2017-05-15 18:04:16 -07:00
Brad Warren
98905fd470 Merge pull request #4669 from certbot/0.14.x-stuff
0.14.x stuff
2017-05-15 17:00:15 -07:00
Brad Warren
8c313449f9 Make 42d07d7 more closely follow repo conventions
(cherry picked from commit d467295d2a)
2017-05-15 15:40:04 -07:00
Joona Hoikkala
b33669edac Force augeas file reload to recalculate span indicies
(cherry picked from commit f5b61d56bd)
2017-05-15 15:39:55 -07:00
Brad Warren
25d9fbd657 Modify special action types only once
(cherry picked from commit 65f7f3e12b)
2017-05-15 15:39:18 -07:00
Ryan Pineo
7cbbf20b0c support version 0.12.0 of configargparse
fixes #4648

(cherry picked from commit 42d07d756d)
2017-05-15 15:39:12 -07:00
22 changed files with 293 additions and 105 deletions

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
version = '0.14.0' version = '0.14.2'
# Please update tox.ini when modifying dependency version requirements # Please update tox.ini when modifying dependency version requirements
install_requires = [ install_requires = [

View File

@@ -120,8 +120,8 @@ class AugeasConfigurator(common.Plugin):
# If the augeas tree didn't change, no files were saved and a backup # If the augeas tree didn't change, no files were saved and a backup
# should not be created # should not be created
save_files = set()
if save_paths: if save_paths:
save_files = set()
for path in save_paths: for path in save_paths:
save_files.add(self.aug.get(path)[6:]) save_files.add(self.aug.get(path)[6:])
@@ -140,6 +140,12 @@ class AugeasConfigurator(common.Plugin):
self.save_notes = "" self.save_notes = ""
self.aug.save() self.aug.save()
# Force reload if files were modified
# This is needed to recalculate augeas directive span
if save_files:
for sf in save_files:
self.aug.remove("/files/"+sf)
self.aug.load()
if title and not temporary: if title and not temporary:
try: try:
self.reverter.finalize_checkpoint(title) self.reverter.finalize_checkpoint(title)

View File

@@ -1065,8 +1065,28 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
span_end = span_val[6] span_end = span_val[6]
with open(span_filep, 'r') as fh: with open(span_filep, 'r') as fh:
fh.seek(span_start) fh.seek(span_start)
vh_contents = fh.read(span_end-span_start) vh_contents = fh.read(span_end-span_start).split("\n")
return vh_contents.split("\n") self._remove_closing_vhost_tag(vh_contents)
return vh_contents
def _remove_closing_vhost_tag(self, vh_contents):
"""Removes the closing VirtualHost tag if it exists.
This method modifies vh_contents directly to remove the closing
tag. If the closing vhost tag is found, everything on the line
after it is also removed. Whether or not this tag is included
in the result of span depends on the Augeas version.
:param list vh_contents: VirtualHost block contents to check
"""
for offset, line in enumerate(reversed(vh_contents)):
if line:
line_index = line.lower().find("</virtualhost>")
if line_index != -1:
content_index = len(vh_contents) - offset - 1
vh_contents[content_index] = line[:line_index]
break
def _update_ssl_vhosts_addrs(self, vh_path): def _update_ssl_vhosts_addrs(self, vh_path):
ssl_addrs = set() ssl_addrs = set()

View File

@@ -597,6 +597,21 @@ class MultipleVhostsTest(util.ApacheTest):
# already listens to the correct port # already listens to the correct port
self.assertEqual(mock_add_dir.call_count, 0) self.assertEqual(mock_add_dir.call_count, 0)
def test_make_vhost_ssl_with_mock_span(self):
# span excludes the closing </VirtualHost> tag in older versions
# of Augeas
return_value = [self.vh_truth[0].filep, 1, 12, 0, 0, 0, 1142]
with mock.patch.object(self.config.aug, 'span') as mock_span:
mock_span.return_value = return_value
self.test_make_vhost_ssl()
def test_make_vhost_ssl_with_mock_span2(self):
# span includes the closing </VirtualHost> tag in newer versions
# of Augeas
return_value = [self.vh_truth[0].filep, 1, 12, 0, 0, 0, 1157]
with mock.patch.object(self.config.aug, 'span') as mock_span:
mock_span.return_value = return_value
self.test_make_vhost_ssl()
def test_make_vhost_ssl(self): def test_make_vhost_ssl(self):
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0]) ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
version = '0.14.0' version = '0.14.2'
# Please update tox.ini when modifying dependency version requirements # Please update tox.ini when modifying dependency version requirements
install_requires = [ install_requires = [

View File

@@ -28,7 +28,7 @@ if [ -z "$VENV_PATH" ]; then
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME" VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
fi fi
VENV_BIN="$VENV_PATH/bin" VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="0.14.0" LE_AUTO_VERSION="0.14.2"
BASENAME=$(basename $0) BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS] USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -860,18 +860,18 @@ letsencrypt==0.7.0 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.14.0 \ acme==0.14.2 \
--hash=sha256:fca8766a2596833e8886f7ef72cf82d1f6c6cffa895781a5676861c251b24b70 \ --hash=sha256:b3068d360beccd3b23a81d7cd2522437d847328811b573a5fe14eb04147667cf \
--hash=sha256:ce7d2bca31e85adac1030c944e0a9d96e8b0f85cdc616b78d40eb09c91803543 --hash=sha256:166b7f4858f5b144b03236b995b787a9da1e410121fb7dcac9c7d3b594bc6fcd
certbot==0.14.0 \ certbot==0.14.2 \
--hash=sha256:071790b1ec4e5b94aa1688f8a62a10905c28438cd55d990cdb8c9f733d3a4a41 \ --hash=sha256:525e15e43c833db9a9934308d69dcdd220fa799488cd84543748671c68aba73d \
--hash=sha256:98add3721e1edaedb404879a9d39bd49020e94fc8eedbc46032a00ada51d7741 --hash=sha256:5bc8547dcfc0fc587e15253e264f79d8397e48bfbc8697d5aca87eae978769ac
certbot-apache==0.14.0 \ certbot-apache==0.14.2 \
--hash=sha256:ab837efce7aa4c4e47a724a60dcbeacadb9dfe64bd1d32a4e854678c4fcd82a3 \ --hash=sha256:15647d424a5a7e4c44c684324ac07a457a2e0d61fce1acaa421c0b641941a350 \
--hash=sha256:bbcd21d9f3fd8cdc4453ef94d0cb6033c3a19f879dcd314231501ebb7180168f --hash=sha256:e5220d3e6ee5114b41b398110dfbd8f13bd1e8c7902758634449e0b4ae515b76
certbot-nginx==0.14.0 \ certbot-nginx==0.14.2 \
--hash=sha256:608b2f6f2b04ce93c503a95ffba4f0e0ca2e0cb9ea587a8376368fa621b388e4 \ --hash=sha256:231377fbdfb6303adddc73fe3f856b9fb6d0175db825650e39fe3dfd6a58f8ef \
--hash=sha256:86e964b2a7818cc165d913e27e504f2ef2f60750ab0db6d39bfb3465d54c30db --hash=sha256:529a18280acf41f5f7e0fe7d82c0a5d4d197d14f82742eaec54bb1d3f69c325a
UNLIKELY_EOF UNLIKELY_EOF
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
version = '0.14.0' version = '0.14.2'
install_requires = [ install_requires = [
'certbot', 'certbot',

View File

@@ -529,7 +529,10 @@ def _add_directive(block, directive, replace):
""" """
directive = nginxparser.UnspacedList(directive) directive = nginxparser.UnspacedList(directive)
if len(directive) == 0 or directive[0] == '#': def is_whitespace_or_comment(directive):
"""Is this directive either a whitespace or comment directive?"""
return len(directive) == 0 or directive[0] == '#'
if is_whitespace_or_comment(directive):
# whitespace or comment # whitespace or comment
block.append(directive) block.append(directive)
return return
@@ -574,7 +577,8 @@ def _add_directive(block, directive, replace):
for included_directive in included_directives: for included_directive in included_directives:
included_dir_loc = find_location(included_directive) included_dir_loc = find_location(included_directive)
included_dir_name = included_directive[0] included_dir_name = included_directive[0]
if not can_append(included_dir_loc, included_dir_name): if not is_whitespace_or_comment(included_directive) \
and not can_append(included_dir_loc, included_dir_name):
if block[included_dir_loc] != included_directive: if block[included_dir_loc] != included_directive:
raise errors.MisconfigurationError(err_fmt.format(included_directive, raise errors.MisconfigurationError(err_fmt.format(included_directive,
block[included_dir_loc])) block[included_dir_loc]))

View File

@@ -13,7 +13,7 @@ from certbot_nginx import parser
from certbot_nginx.tests import util from certbot_nginx.tests import util
class NginxParserTest(util.NginxTest): class NginxParserTest(util.NginxTest): #pylint: disable=too-many-public-methods
"""Nginx Parser Test.""" """Nginx Parser Test."""
def setUp(self): def setUp(self):
@@ -230,6 +230,33 @@ class NginxParserTest(util.NginxTest):
['ssl_certificate', '/etc/ssl/cert2.pem']], ['ssl_certificate', '/etc/ssl/cert2.pem']],
replace=False) replace=False)
def test_comment_is_repeatable(self):
nparser = parser.NginxParser(self.config_path)
example_com = nparser.abs_path('sites-enabled/example.com')
mock_vhost = obj.VirtualHost(example_com,
None, None, None,
set(['.example.com', 'example.*']),
None, [0])
nparser.add_server_directives(mock_vhost,
[['\n ', '#', ' ', 'what a nice comment']],
replace=False)
nparser.add_server_directives(mock_vhost,
[['\n ', 'include', ' ',
nparser.abs_path('comment_in_file.conf')]],
replace=False)
from certbot_nginx.parser import COMMENT
self.assertEqual(nparser.parsed[example_com],
[[['server'], [['listen', '69.50.225.155:9000'],
['listen', '127.0.0.1'],
['server_name', '.example.com'],
['server_name', 'example.*'],
['#', ' ', 'what a nice comment'],
[],
['include', nparser.abs_path('comment_in_file.conf')],
['#', COMMENT],
[]]]]
)
def test_replace_server_directives(self): def test_replace_server_directives(self):
nparser = parser.NginxParser(self.config_path) nparser = parser.NginxParser(self.config_path)
target = set(['.example.com', 'example.*']) target = set(['.example.com', 'example.*'])

View File

@@ -0,0 +1 @@
# a comment inside a file

View File

@@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages from setuptools import find_packages
version = '0.14.0' version = '0.14.2'
# Please update tox.ini when modifying dependency version requirements # Please update tox.ini when modifying dependency version requirements
install_requires = [ install_requires = [

View File

@@ -1,4 +1,4 @@
"""Certbot client.""" """Certbot client."""
# version number like 1.2.3a0, must have at least 2 parts, like 1.2 # version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '0.14.0' __version__ = '0.14.2'

View File

@@ -70,7 +70,8 @@ def pre_arg_parse_setup():
# close() are explicitly called # close() are explicitly called
util.atexit_register(logging.shutdown) util.atexit_register(logging.shutdown)
sys.excepthook = functools.partial( sys.excepthook = functools.partial(
except_hook, debug='--debug' in sys.argv, log_path=temp_handler.path) pre_arg_parse_except_hook, memory_handler,
debug='--debug' in sys.argv, log_path=temp_handler.path)
def post_arg_parse_setup(config): def post_arg_parse_setup(config):
@@ -103,8 +104,9 @@ def post_arg_parse_setup(config):
root_logger.removeHandler(memory_handler) root_logger.removeHandler(memory_handler)
temp_handler = memory_handler.target temp_handler = memory_handler.target
memory_handler.setTarget(file_handler) memory_handler.setTarget(file_handler)
memory_handler.flush(force=True)
memory_handler.close() memory_handler.close()
temp_handler.delete_and_close() temp_handler.close()
if config.quiet: if config.quiet:
level = constants.QUIET_LOGGING_LEVEL level = constants.QUIET_LOGGING_LEVEL
@@ -115,7 +117,7 @@ def post_arg_parse_setup(config):
logger.info('Saving debug log to %s', file_path) logger.info('Saving debug log to %s', file_path)
sys.excepthook = functools.partial( sys.excepthook = functools.partial(
except_hook, debug=config.debug, log_path=logs_dir) post_arg_parse_except_hook, debug=config.debug, log_path=logs_dir)
def setup_log_file_handler(config, logfile, fmt): def setup_log_file_handler(config, logfile, fmt):
@@ -194,8 +196,7 @@ class MemoryHandler(logging.handlers.MemoryHandler):
"""Buffers logging messages in memory until the buffer is flushed. """Buffers logging messages in memory until the buffer is flushed.
This differs from `logging.handlers.MemoryHandler` in that flushing This differs from `logging.handlers.MemoryHandler` in that flushing
only happens when it is done explicitly by calling flush() or only happens when flush(force=True) is called.
close().
""" """
def __init__(self, target=None): def __init__(self, target=None):
@@ -209,6 +210,33 @@ class MemoryHandler(logging.handlers.MemoryHandler):
else: else:
super(MemoryHandler, self).__init__(capacity, target=target) super(MemoryHandler, self).__init__(capacity, target=target)
def close(self):
"""Close the memory handler, but don't set the target to None."""
# This allows the logging module which may only have a weak
# reference to the target handler to properly flush and close it.
target = self.target
if sys.version_info < (2, 7): # pragma: no cover
logging.handlers.MemoryHandler.close(self)
else:
super(MemoryHandler, self).close()
self.target = target
def flush(self, force=False): # pylint: disable=arguments-differ
"""Flush the buffer if force=True.
If force=False, this call is a noop.
:param bool force: True if the buffer should be flushed.
"""
# This method allows flush() calls in logging.shutdown to be a
# noop so we can control when this handler is flushed.
if force:
if sys.version_info < (2, 7): # pragma: no cover
logging.handlers.MemoryHandler.flush(self)
else:
super(MemoryHandler, self).flush()
def shouldFlush(self, record): def shouldFlush(self, record):
"""Should the buffer be automatically flushed? """Should the buffer be automatically flushed?
@@ -224,7 +252,9 @@ class MemoryHandler(logging.handlers.MemoryHandler):
class TempHandler(logging.StreamHandler): class TempHandler(logging.StreamHandler):
"""Safely logs messages to a temporary file. """Safely logs messages to a temporary file.
The file is created with permissions 600. The file is created with permissions 600. If no log records are sent
to this handler, the temporary file is deleted when the handler is
closed.
:ivar str path: file system path to the temporary log file :ivar str path: file system path to the temporary log file
@@ -238,19 +268,26 @@ class TempHandler(logging.StreamHandler):
else: else:
super(TempHandler, self).__init__(stream) super(TempHandler, self).__init__(stream)
self.path = stream.name self.path = stream.name
self._delete = True
def delete_and_close(self): def emit(self, record):
"""Close the handler and delete the temporary log file.""" """Log the specified logging record.
self._close(delete=True)
:param logging.LogRecord record: Record to be formatted
"""
self._delete = False
# logging handlers use old style classes in Python 2.6 so
# super() cannot be used
if sys.version_info < (2, 7): # pragma: no cover
logging.StreamHandler.emit(self, record)
else:
super(TempHandler, self).emit(record)
def close(self): def close(self):
"""Close the handler and the temporary log file."""
self._close(delete=False)
def _close(self, delete):
"""Close the handler and the temporary log file. """Close the handler and the temporary log file.
:param bool delete: True if the log file should be deleted The temporary log file is deleted if it wasn't used.
""" """
self.acquire() self.acquire()
@@ -258,8 +295,9 @@ class TempHandler(logging.StreamHandler):
# StreamHandler.close() doesn't close the stream to allow a # StreamHandler.close() doesn't close the stream to allow a
# stream like stderr to be used # stream like stderr to be used
self.stream.close() self.stream.close()
if delete: if self._delete:
os.remove(self.path) os.remove(self.path)
self._delete = False
if sys.version_info < (2, 7): # pragma: no cover if sys.version_info < (2, 7): # pragma: no cover
logging.StreamHandler.close(self) logging.StreamHandler.close(self)
else: else:
@@ -268,7 +306,34 @@ class TempHandler(logging.StreamHandler):
self.release() self.release()
def except_hook(exc_type, exc_value, trace, debug, log_path): def pre_arg_parse_except_hook(memory_handler, *args, **kwargs):
"""A simple wrapper around post_arg_parse_except_hook.
The additional functionality provided by this wrapper is the memory
handler will be flushed before Certbot exits. This allows us to
write logging messages to a temporary file if we crashed before
logging was fully configured.
Since sys.excepthook isn't called on SystemExit exceptions, the
memory handler will not be flushed in this case which prevents us
from creating temporary log files when argparse exits because a
command line argument was invalid or -h, --help, or --version was
provided on the command line.
:param MemoryHandler memory_handler: memory handler to flush
:param tuple args: args for post_arg_parse_except_hook
:param dict kwargs: kwargs for post_arg_parse_except_hook
"""
try:
post_arg_parse_except_hook(*args, **kwargs)
finally:
# flush() is called here so messages logged during
# post_arg_parse_except_hook are also flushed.
memory_handler.flush(force=True)
def post_arg_parse_except_hook(exc_type, exc_value, trace, debug, log_path):
"""Logs fatal exceptions and reports them to the user. """Logs fatal exceptions and reports them to the user.
If debug is True, the full exception and traceback is shown to the If debug is True, the full exception and traceback is shown to the

View File

@@ -26,7 +26,7 @@ class PreArgParseSetupTest(unittest.TestCase):
return pre_arg_parse_setup(*args, **kwargs) return pre_arg_parse_setup(*args, **kwargs)
@mock.patch('certbot.log.sys') @mock.patch('certbot.log.sys')
@mock.patch('certbot.log.except_hook') @mock.patch('certbot.log.pre_arg_parse_except_hook')
@mock.patch('certbot.log.logging.getLogger') @mock.patch('certbot.log.logging.getLogger')
@mock.patch('certbot.log.util.atexit_register') @mock.patch('certbot.log.util.atexit_register')
def test_it(self, mock_register, mock_get, mock_except_hook, mock_sys): def test_it(self, mock_register, mock_get, mock_except_hook, mock_sys):
@@ -34,11 +34,6 @@ class PreArgParseSetupTest(unittest.TestCase):
mock_sys.version_info = sys.version_info mock_sys.version_info = sys.version_info
self._call() self._call()
mock_register.assert_called_once_with(logging.shutdown)
mock_sys.excepthook(1, 2, 3)
mock_except_hook.assert_called_once_with(
1, 2, 3, debug=True, log_path=mock.ANY)
mock_root_logger = mock_get() mock_root_logger = mock_get()
mock_root_logger.setLevel.assert_called_once_with(logging.DEBUG) mock_root_logger.setLevel.assert_called_once_with(logging.DEBUG)
self.assertEqual(mock_root_logger.addHandler.call_count, 2) self.assertEqual(mock_root_logger.addHandler.call_count, 2)
@@ -54,6 +49,11 @@ class PreArgParseSetupTest(unittest.TestCase):
self.assertTrue( self.assertTrue(
isinstance(memory_handler.target, logging.StreamHandler)) isinstance(memory_handler.target, logging.StreamHandler))
mock_register.assert_called_once_with(logging.shutdown)
mock_sys.excepthook(1, 2, 3)
mock_except_hook.assert_called_once_with(
memory_handler, 1, 2, 3, debug=True, log_path=mock.ANY)
class PostArgParseSetupTest(test_util.TempDirTestCase): class PostArgParseSetupTest(test_util.TempDirTestCase):
"""Tests for certbot.log.post_arg_parse_setup.""" """Tests for certbot.log.post_arg_parse_setup."""
@@ -88,7 +88,8 @@ class PostArgParseSetupTest(test_util.TempDirTestCase):
def test_common(self): def test_common(self):
with mock.patch('certbot.log.logging.getLogger') as mock_get_logger: with mock.patch('certbot.log.logging.getLogger') as mock_get_logger:
mock_get_logger.return_value = self.root_logger mock_get_logger.return_value = self.root_logger
with mock.patch('certbot.log.except_hook') as mock_except_hook: except_hook_path = 'certbot.log.post_arg_parse_except_hook'
with mock.patch(except_hook_path) as mock_except_hook:
with mock.patch('certbot.log.sys') as mock_sys: with mock.patch('certbot.log.sys') as mock_sys:
mock_sys.version_info = sys.version_info mock_sys.version_info = sys.version_info
self._call(self.config) self._call(self.config)
@@ -203,12 +204,13 @@ class MemoryHandlerTest(unittest.TestCase):
def test_flush(self): def test_flush(self):
self._test_log_debug() self._test_log_debug()
self.handler.flush() self.handler.flush(force=True)
self.assertEqual(self.stream.getvalue(), self.msg + '\n') self.assertEqual(self.stream.getvalue(), self.msg + '\n')
def test_not_flushed(self): def test_not_flushed(self):
# By default, logging.ERROR messages and higher are flushed # By default, logging.ERROR messages and higher are flushed
self.logger.critical(self.msg) self.logger.critical(self.msg)
self.handler.flush()
self.assertEqual(self.stream.getvalue(), '') self.assertEqual(self.stream.getvalue(), '')
def test_target_reset(self): def test_target_reset(self):
@@ -217,7 +219,7 @@ class MemoryHandlerTest(unittest.TestCase):
new_stream = six.StringIO() new_stream = six.StringIO()
new_stream_handler = logging.StreamHandler(new_stream) new_stream_handler = logging.StreamHandler(new_stream)
self.handler.setTarget(new_stream_handler) self.handler.setTarget(new_stream_handler)
self.handler.flush() self.handler.flush(force=True)
self.assertEqual(self.stream.getvalue(), '') self.assertEqual(self.stream.getvalue(), '')
self.assertEqual(new_stream.getvalue(), self.msg + '\n') self.assertEqual(new_stream.getvalue(), self.msg + '\n')
new_stream_handler.close() new_stream_handler.close()
@@ -234,31 +236,50 @@ class TempHandlerTest(unittest.TestCase):
self.handler = TempHandler() self.handler = TempHandler()
def tearDown(self): def tearDown(self):
if not self.closed: self.handler.close()
self.handler.delete_and_close()
def test_permissions(self): def test_permissions(self):
self.assertTrue( self.assertTrue(
util.check_permissions(self.handler.path, 0o600, os.getuid())) util.check_permissions(self.handler.path, 0o600, os.getuid()))
def test_delete(self): def test_delete(self):
self.handler.delete_and_close() self.handler.close()
self.closed = True
self.assertFalse(os.path.exists(self.handler.path)) self.assertFalse(os.path.exists(self.handler.path))
def test_no_delete(self): def test_no_delete(self):
self.handler.emit(mock.MagicMock())
self.handler.close() self.handler.close()
self.closed = True
self.assertTrue(os.path.exists(self.handler.path)) self.assertTrue(os.path.exists(self.handler.path))
os.remove(self.handler.path) os.remove(self.handler.path)
class ExceptHookTest(unittest.TestCase): class PreArgParseExceptHookTest(unittest.TestCase):
"""Tests for certbot.log.except_hook.""" """Tests for certbot.log.pre_arg_parse_except_hook."""
@classmethod @classmethod
def _call(cls, *args, **kwargs): def _call(cls, *args, **kwargs):
from certbot.log import except_hook from certbot.log import pre_arg_parse_except_hook
return except_hook(*args, **kwargs) return pre_arg_parse_except_hook(*args, **kwargs)
@mock.patch('certbot.log.post_arg_parse_except_hook')
def test_it(self, mock_post_arg_parse_except_hook):
# pylint: disable=star-args
memory_handler = mock.MagicMock()
args = ('some', 'args',)
kwargs = {'some': 'kwargs'}
self._call(memory_handler, *args, **kwargs)
mock_post_arg_parse_except_hook.assert_called_once_with(
*args, **kwargs)
memory_handler.flush.assert_called_once_with(force=True)
class PostArgParseExceptHookTest(unittest.TestCase):
"""Tests for certbot.log.post_arg_parse_except_hook."""
@classmethod
def _call(cls, *args, **kwargs):
from certbot.log import post_arg_parse_except_hook
return post_arg_parse_except_hook(*args, **kwargs)
def setUp(self): def setUp(self):
self.error_msg = 'test error message' self.error_msg = 'test error message'

View File

@@ -368,6 +368,29 @@ class AddDeprecatedArgumentTest(unittest.TestCase):
pass pass
self.assertTrue("--old-option" not in stdout.getvalue()) self.assertTrue("--old-option" not in stdout.getvalue())
def test_set_constant(self):
"""Test when ACTION_TYPES_THAT_DONT_NEED_A_VALUE is a set.
This variable is a set in configargparse versions < 0.12.0.
"""
self._test_constant_common(set)
def test_tuple_constant(self):
"""Test when ACTION_TYPES_THAT_DONT_NEED_A_VALUE is a tuple.
This variable is a tuple in configargparse versions >= 0.12.0.
"""
self._test_constant_common(tuple)
def _test_constant_common(self, typ):
with mock.patch("certbot.util.configargparse") as mock_configargparse:
mock_configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE = typ()
self._call("--old-option", 1)
self.assertEqual(
len(mock_configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE), 1)
class EnforceLeValidity(unittest.TestCase): class EnforceLeValidity(unittest.TestCase):
"""Test enforce_le_validity.""" """Test enforce_le_validity."""

View File

@@ -476,7 +476,13 @@ def add_deprecated_argument(add_argument, argument_name, nargs):
sys.stderr.write( sys.stderr.write(
"Use of {0} is deprecated.\n".format(option_string)) "Use of {0} is deprecated.\n".format(option_string))
configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add(ShowWarning) # In version 0.12.0 ACTION_TYPES_THAT_DONT_NEED_A_VALUE was changed from a
# set to a tuple.
if isinstance(configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE, set):
# pylint: disable=no-member
configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add(ShowWarning)
else:
configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE += (ShowWarning,)
add_argument(argument_name, action=ShowWarning, add_argument(argument_name, action=ShowWarning,
help=argparse.SUPPRESS, nargs=nargs) help=argparse.SUPPRESS, nargs=nargs)

View File

@@ -89,7 +89,7 @@ optional arguments:
case, and to know when to deprecate support for past case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/0.14.0 (certbot; "". (default: CertbotACMEClient/0.14.2 (certbot;
Ubuntu 16.04.2 LTS) Authenticator/XXX Installer/YYY Ubuntu 16.04.2 LTS) Authenticator/XXX Installer/YYY
(SUBCOMMAND; flags: FLAGS) Py/2.7.12). The flags (SUBCOMMAND; flags: FLAGS) Py/2.7.12). The flags
encoded in the user agent are: --duplicate, --force- encoded in the user agent are: --duplicate, --force-

View File

@@ -28,7 +28,7 @@ if [ -z "$VENV_PATH" ]; then
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME" VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
fi fi
VENV_BIN="$VENV_PATH/bin" VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="0.14.0" LE_AUTO_VERSION="0.14.2"
BASENAME=$(basename $0) BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS] USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -860,18 +860,18 @@ letsencrypt==0.7.0 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.14.0 \ acme==0.14.2 \
--hash=sha256:fca8766a2596833e8886f7ef72cf82d1f6c6cffa895781a5676861c251b24b70 \ --hash=sha256:b3068d360beccd3b23a81d7cd2522437d847328811b573a5fe14eb04147667cf \
--hash=sha256:ce7d2bca31e85adac1030c944e0a9d96e8b0f85cdc616b78d40eb09c91803543 --hash=sha256:166b7f4858f5b144b03236b995b787a9da1e410121fb7dcac9c7d3b594bc6fcd
certbot==0.14.0 \ certbot==0.14.2 \
--hash=sha256:071790b1ec4e5b94aa1688f8a62a10905c28438cd55d990cdb8c9f733d3a4a41 \ --hash=sha256:525e15e43c833db9a9934308d69dcdd220fa799488cd84543748671c68aba73d \
--hash=sha256:98add3721e1edaedb404879a9d39bd49020e94fc8eedbc46032a00ada51d7741 --hash=sha256:5bc8547dcfc0fc587e15253e264f79d8397e48bfbc8697d5aca87eae978769ac
certbot-apache==0.14.0 \ certbot-apache==0.14.2 \
--hash=sha256:ab837efce7aa4c4e47a724a60dcbeacadb9dfe64bd1d32a4e854678c4fcd82a3 \ --hash=sha256:15647d424a5a7e4c44c684324ac07a457a2e0d61fce1acaa421c0b641941a350 \
--hash=sha256:bbcd21d9f3fd8cdc4453ef94d0cb6033c3a19f879dcd314231501ebb7180168f --hash=sha256:e5220d3e6ee5114b41b398110dfbd8f13bd1e8c7902758634449e0b4ae515b76
certbot-nginx==0.14.0 \ certbot-nginx==0.14.2 \
--hash=sha256:608b2f6f2b04ce93c503a95ffba4f0e0ca2e0cb9ea587a8376368fa621b388e4 \ --hash=sha256:231377fbdfb6303adddc73fe3f856b9fb6d0175db825650e39fe3dfd6a58f8ef \
--hash=sha256:86e964b2a7818cc165d913e27e504f2ef2f60750ab0db6d39bfb3465d54c30db --hash=sha256:529a18280acf41f5f7e0fe7d82c0a5d4d197d14f82742eaec54bb1d3f69c325a
UNLIKELY_EOF UNLIKELY_EOF
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------

View File

@@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE----- -----BEGIN PGP SIGNATURE-----
Version: GnuPG v2 Version: GnuPG v2
iQEcBAABCAAGBQJZC76WAAoJEE0XyZXNl3XyXhcIAJ1+gPoWZmXjFcC4by2tDBoM iQEcBAABCAAGBQJZJ0tAAAoJEE0XyZXNl3Xyta0H/3+UZ1xeCc7CjZBMEMjb6IPm
Lkxf5BNxq8aq7qSohU8SqSo6ShDkWh9ci390n+jbOX1R503uQL1egGbEAJbziFYq h0KhptkLfwRR0/vGhTeIaOi8rzZYPuzZVwRvTuJ30oORI/zP+siGTOVW4Rt/3KI0
vym6j0AmqM+2/YcWmcj3J7RYtDOV1sUPKD2pgUxWtvQrd9iZ1235WMzBF/uBprzm IZidCJkdl3259jtJpSR9dWOXVp8bklZin8k6daQjbizq8Hl6z0aFLbHlqeSAZhUX
qAtFwF04V2H3kkC4e7+jAEkFzs1TJ8fYumqqqw0NgSwM6bikfurpRyf8qR2RVYWt ush94CQwB380OUBut+g3CYx4BxD0dgTODPIaVYzeG8lOX5SXAaBbH79BOAtCr9Hy
e3GOTxyBVbjhp2UPy/O8Xx7iBD3m+t9mJgsCJ9l8s7xKot6LF7+WrJkn0A3cfKcR sRfYjcBo4aL3rPCayPn+ETvQsYYo/Z7zqHjfShiKzZXNtW+RBGXAf8CGoEk7LKM4
LSTataKedsP3u1jOgP3y2ujumBlDlDRuXn6vK/YKNYNnHte5B9mstSzoDGgRvHE= jts6PxOpg2BFpArDKHn6JIWsHOphBAQ/qIIgvD1mKZj6P4hGBJv4+aZ3Q8uhHeg=
=3Jgs =56Pv
-----END PGP SIGNATURE----- -----END PGP SIGNATURE-----

View File

@@ -28,7 +28,7 @@ if [ -z "$VENV_PATH" ]; then
VENV_PATH="$XDG_DATA_HOME/$VENV_NAME" VENV_PATH="$XDG_DATA_HOME/$VENV_NAME"
fi fi
VENV_BIN="$VENV_PATH/bin" VENV_BIN="$VENV_PATH/bin"
LE_AUTO_VERSION="0.14.0" LE_AUTO_VERSION="0.14.2"
BASENAME=$(basename $0) BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS] USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -860,18 +860,18 @@ letsencrypt==0.7.0 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.14.0 \ acme==0.14.2 \
--hash=sha256:fca8766a2596833e8886f7ef72cf82d1f6c6cffa895781a5676861c251b24b70 \ --hash=sha256:b3068d360beccd3b23a81d7cd2522437d847328811b573a5fe14eb04147667cf \
--hash=sha256:ce7d2bca31e85adac1030c944e0a9d96e8b0f85cdc616b78d40eb09c91803543 --hash=sha256:166b7f4858f5b144b03236b995b787a9da1e410121fb7dcac9c7d3b594bc6fcd
certbot==0.14.0 \ certbot==0.14.2 \
--hash=sha256:071790b1ec4e5b94aa1688f8a62a10905c28438cd55d990cdb8c9f733d3a4a41 \ --hash=sha256:525e15e43c833db9a9934308d69dcdd220fa799488cd84543748671c68aba73d \
--hash=sha256:98add3721e1edaedb404879a9d39bd49020e94fc8eedbc46032a00ada51d7741 --hash=sha256:5bc8547dcfc0fc587e15253e264f79d8397e48bfbc8697d5aca87eae978769ac
certbot-apache==0.14.0 \ certbot-apache==0.14.2 \
--hash=sha256:ab837efce7aa4c4e47a724a60dcbeacadb9dfe64bd1d32a4e854678c4fcd82a3 \ --hash=sha256:15647d424a5a7e4c44c684324ac07a457a2e0d61fce1acaa421c0b641941a350 \
--hash=sha256:bbcd21d9f3fd8cdc4453ef94d0cb6033c3a19f879dcd314231501ebb7180168f --hash=sha256:e5220d3e6ee5114b41b398110dfbd8f13bd1e8c7902758634449e0b4ae515b76
certbot-nginx==0.14.0 \ certbot-nginx==0.14.2 \
--hash=sha256:608b2f6f2b04ce93c503a95ffba4f0e0ca2e0cb9ea587a8376368fa621b388e4 \ --hash=sha256:231377fbdfb6303adddc73fe3f856b9fb6d0175db825650e39fe3dfd6a58f8ef \
--hash=sha256:86e964b2a7818cc165d913e27e504f2ef2f60750ab0db6d39bfb3465d54c30db --hash=sha256:529a18280acf41f5f7e0fe7d82c0a5d4d197d14f82742eaec54bb1d3f69c325a
UNLIKELY_EOF UNLIKELY_EOF
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------

View File

@@ -171,15 +171,15 @@ letsencrypt==0.7.0 \
# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE.
acme==0.14.0 \ acme==0.14.2 \
--hash=sha256:fca8766a2596833e8886f7ef72cf82d1f6c6cffa895781a5676861c251b24b70 \ --hash=sha256:b3068d360beccd3b23a81d7cd2522437d847328811b573a5fe14eb04147667cf \
--hash=sha256:ce7d2bca31e85adac1030c944e0a9d96e8b0f85cdc616b78d40eb09c91803543 --hash=sha256:166b7f4858f5b144b03236b995b787a9da1e410121fb7dcac9c7d3b594bc6fcd
certbot==0.14.0 \ certbot==0.14.2 \
--hash=sha256:071790b1ec4e5b94aa1688f8a62a10905c28438cd55d990cdb8c9f733d3a4a41 \ --hash=sha256:525e15e43c833db9a9934308d69dcdd220fa799488cd84543748671c68aba73d \
--hash=sha256:98add3721e1edaedb404879a9d39bd49020e94fc8eedbc46032a00ada51d7741 --hash=sha256:5bc8547dcfc0fc587e15253e264f79d8397e48bfbc8697d5aca87eae978769ac
certbot-apache==0.14.0 \ certbot-apache==0.14.2 \
--hash=sha256:ab837efce7aa4c4e47a724a60dcbeacadb9dfe64bd1d32a4e854678c4fcd82a3 \ --hash=sha256:15647d424a5a7e4c44c684324ac07a457a2e0d61fce1acaa421c0b641941a350 \
--hash=sha256:bbcd21d9f3fd8cdc4453ef94d0cb6033c3a19f879dcd314231501ebb7180168f --hash=sha256:e5220d3e6ee5114b41b398110dfbd8f13bd1e8c7902758634449e0b4ae515b76
certbot-nginx==0.14.0 \ certbot-nginx==0.14.2 \
--hash=sha256:608b2f6f2b04ce93c503a95ffba4f0e0ca2e0cb9ea587a8376368fa621b388e4 \ --hash=sha256:231377fbdfb6303adddc73fe3f856b9fb6d0175db825650e39fe3dfd6a58f8ef \
--hash=sha256:86e964b2a7818cc165d913e27e504f2ef2f60750ab0db6d39bfb3465d54c30db --hash=sha256:529a18280acf41f5f7e0fe7d82c0a5d4d197d14f82742eaec54bb1d3f69c325a