py3: Allow percentages in configs

Previously, configs like

    fallocate_reserve = 1%

would cause a py3 backend server to fail to start, complaining like

    configparser.InterpolationSyntaxError: Error in file
    /etc/swift/object-server/1.conf.d: '%' must be followed
    by '%' or '(', found: '%'

This could also come up in proxy-server configs, with things like
percent signs in tempauth password.

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". On py2, we didn't really have to think about
it, since values like "1%" would pass through just fine. (It would blow
up a SafeConfigParser, but a normal ConfigParser only does replacements
when there's something like a "%(opt)s" in the value.)

On py3, SafeConfigParser became ConfigParser, and the old interpolation
mode (AFAICT) doesn't exist.

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.

Change-Id: I0f9cecd11f00b522a8486972551cb30af151ce32
Closes-Bug: #1844368
This commit is contained in:
Tim Burke 2019-09-27 11:04:43 -07:00
parent 2d87ad6333
commit 9a33365f06
2 changed files with 25 additions and 1 deletions

View File

@ -32,6 +32,7 @@ from eventlet.green import socket, ssl, os as green_os
import six
from six import BytesIO
from six import StringIO
from six.moves import configparser
from swift.common import utils, constraints
from swift.common.storage_policy import BindPortsCache
@ -55,6 +56,23 @@ 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

View File

@ -70,6 +70,7 @@ class TestWSGI(unittest.TestCase):
config = """
[DEFAULT]
swift_dir = TEMPDIR
fallocate_reserve = 1%
[pipeline:main]
pipeline = proxy-server
@ -122,6 +123,7 @@ class TestWSGI(unittest.TestCase):
'__file__': conf_file,
'here': os.path.dirname(conf_file),
'conn_timeout': '0.2',
'fallocate_reserve': '1%',
'swift_dir': t,
'__name__': 'proxy-server'
}
@ -2064,6 +2066,7 @@ class TestPipelineModification(unittest.TestCase):
[filter:tempauth]
use = egg:swift#tempauth
user_test_tester = t%%sting .admin
[filter:copy]
use = egg:swift#copy
@ -2090,7 +2093,10 @@ class TestPipelineModification(unittest.TestCase):
for version, pipeline, expected in to_test:
conf_file = os.path.join(t, 'proxy-server.conf')
with open(conf_file, 'w') as f:
f.write(contents % (t, pipeline))
to_write = contents % (t, pipeline)
# Sanity check that the password only has one % in it
self.assertIn('t%sting', to_write)
f.write(to_write)
app = wsgi.loadapp(conf_file, global_conf={})
actual = ' '.join(m.rsplit('.', 1)[1]