From b40f25f9e41dcd77a4768b781ffe59f483911c4e Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Tue, 9 Jun 2020 16:45:21 -0700 Subject: [PATCH] py3: (Better) fix percentages in configs We previously fixed a bunch of places, but not quite *all* the places; at the very least, some account-layer services (like the replicator and auditor IIRC) could still bomb out -- and it's important that replicators still respect fallocate_reserve! Now, do the NicerInterpolation thing every time we call readconf. Additionally, clean up the original fix to avoid globally monkey-patching configparser. Related-Bug: #1844368 Closes-Bug: #1872553 Change-Id: I4512e686cde37930f0482909f537220a57fef76b (cherry picked from commit 2854eddb4424327fc6dc9b7930fd2874b5b23df4) --- swift/common/utils.py | 26 +++++++++++++++++++++++++- swift/common/wsgi.py | 22 +++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/swift/common/utils.py b/swift/common/utils.py index 458652840b..c8c647aaef 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -75,6 +75,7 @@ if not six.PY2: utf16_decoder = codecs.getdecoder('utf-16') utf16_encoder = codecs.getencoder('utf-16') from six.moves import cPickle as pickle +from six.moves import configparser from six.moves.configparser import (ConfigParser, NoSectionError, NoOptionError, RawConfigParser) from six.moves import range, http_client @@ -2984,6 +2985,17 @@ def read_conf_dir(parser, conf_dir): return parser.read(sorted(conf_files)) +if six.PY2: + NicerInterpolation = None # just don't cause ImportErrors over in wsgi.py +else: + class NicerInterpolation(configparser.BasicInterpolation): + def before_get(self, parser, section, option, value, defaults): + if '%(' not in value: + return value + return super(NicerInterpolation, self).before_get( + parser, section, option, value, defaults) + + def readconf(conf_path, section_name=None, log_name=None, defaults=None, raw=False): """ @@ -3005,7 +3017,19 @@ def readconf(conf_path, section_name=None, log_name=None, defaults=None, if raw: c = RawConfigParser(defaults) else: - c = ConfigParser(defaults) + if six.PY2: + c = ConfigParser(defaults) + else: + # In general, we haven't really thought much about interpolation + # in configs. Python's default ConfigParser has always supported + # it, though, so *we* got it "for free". Unfortunatley, since we + # "supported" interpolation, we have to assume there are + # deployments in the wild that use it, and try not to break them. + # So, do what we can to mimic the py2 behavior of passing through + # values like "1%" (which we want to support for + # fallocate_reserve). + c = ConfigParser(defaults, interpolation=NicerInterpolation()) + if hasattr(conf_path, 'readline'): if hasattr(conf_path, 'seek'): conf_path.seek(0) diff --git a/swift/common/wsgi.py b/swift/common/wsgi.py index 06af18a377..535b01f891 100644 --- a/swift/common/wsgi.py +++ b/swift/common/wsgi.py @@ -36,7 +36,6 @@ from io import BytesIO import six from six import StringIO -from six.moves import configparser from swift.common import utils, constraints from swift.common.storage_policy import BindPortsCache @@ -45,7 +44,7 @@ from swift.common.swob import Request, wsgi_quote, wsgi_unquote, \ from swift.common.utils import capture_stdio, disable_fallocate, \ drop_privileges, get_logger, NullLogger, config_true_value, \ validate_configuration, get_hub, config_auto_int_value, \ - reiterate, clean_up_daemon_hygiene, systemd_notify + reiterate, clean_up_daemon_hygiene, systemd_notify, NicerInterpolation SIGNUM_TO_NAME = {getattr(signal, n): n for n in dir(signal) if n.startswith('SIG') and '_' not in n} @@ -61,23 +60,6 @@ except (ImportError, NotImplementedError): CPU_COUNT = 1 -if not six.PY2: - # In general, we haven't really thought much about interpolation in - # configs. Python's default ConfigParser has always supported it, though, - # so *we* got it "for free". Unfortunatley, since we "supported" - # interpolation, we have to assume there are deployments in the wild that - # use it, and try not to break them. So, do what we can to mimic the py2 - # behavior of passing through values like "1%" (which we want to support - # for fallocate_reserve). - class NicerInterpolation(configparser.BasicInterpolation): - def before_get(self, parser, section, option, value, defaults): - if '%(' not in value: - return value - return super(NicerInterpolation, self).before_get( - parser, section, option, value, defaults) - configparser.ConfigParser._DEFAULT_INTERPOLATION = NicerInterpolation() - - class NamedConfigLoader(loadwsgi.ConfigLoader): """ Patch paste.deploy's ConfigLoader so each context object will know what @@ -85,6 +67,8 @@ class NamedConfigLoader(loadwsgi.ConfigLoader): """ def get_context(self, object_type, name=None, global_conf=None): + if not six.PY2: + self.parser._interpolation = NicerInterpolation() context = super(NamedConfigLoader, self).get_context( object_type, name=name, global_conf=global_conf) context.name = name