Fix Werkzeug 2.2.0 compatability

Werkzeug 2.2.0 included a major rewrite[0] of the rule matching logic
which was to improve performance. Unfortunately it necessitates a
few minor changes to our logic.

This is sort of similar to the sushy-tools[1] change, except in this
case ironic-inspector utilizes it's own internal decorator to register
URLs. In this case, we needed to make it a little smarter to handle
the possible version path interaction.

[0]: https://github.com/pallets/werkzeug/pull/2433/files
[1]: https://review.opendev.org/c/openstack/sushy-tools/+/851162

Change-Id: Ia0f7ec9b4ce01967c06b64dc29e25c2e43e8a8b9
Story: 2010190
Task: 45892
This commit is contained in:
Julia Kreger 2022-07-27 08:53:29 -07:00
parent 9a1123dad0
commit 97f4e98d0b

View File

@ -285,9 +285,18 @@ def api(path, is_public_api=False, rule=None, verb_to_rule_map=None,
and strings to format the 'rule' string with
:param kwargs: all the rest kwargs are passed to flask app.route
"""
# Force uniform behavior with regards to trailing slashes
if not path.endswith('/'):
if (not path.endswith('/')
and path == ''
and 'endpoint' not in flask_kwargs):
# NOTE(TheJulia): With rule matching changes in later
# versions of Werkzeug, we don't need to add slashes
# to the end of every path. Some explicitly don't need
# slashes to properly match. Where as if your using an
# endpoint to support other rules, you explicitly cannot
# add a tailing slash because the rule needs to be able
# to match in both possible ways the URL may be requested.
path = path + '/'
flask_kwargs['strict_slashes'] = False
def outer(func):
@ -309,7 +318,7 @@ def api(path, is_public_api=False, rule=None, verb_to_rule_map=None,
return outer
@api('/', rule='introspection', is_public_api=True, methods=['GET'])
@api('', rule='introspection', is_public_api=True, methods=['GET'])
def api_root():
versions = [
{
@ -325,11 +334,15 @@ def api_root():
return flask.jsonify(versions=versions)
# NOTE(TheJulia): We need routes registered for with, and without
# a slash on this special endpoint because it is used in other
# requests.
@api('/<version>', rule='introspection:version', is_public_api=True,
methods=['GET'])
methods=['GET'], endpoint='/<version>')
@api('/<version>/', rule='introspection:version', is_public_api=True,
methods=['GET'], endpoint='/<version>/')
def version_root(version):
pat = re.compile(r'^\/%s\/[^\/]*?/?$' % version)
resources = []
for url in _app.url_map.iter_rules():
if pat.match(str(url)):