Cinder - easy to hit RecursionError with complex config formulas
bartosz.rabiega at ovhcloud.com
bartosz.rabiega at ovhcloud.com
Mon Mar 28 09:20:28 UTC 2022
Hello,
I wanted to share something I've recently discovered - there is a
strange issue with cinder evaluating complex configuration formulas.
For example when using complex goodness_function it's quite easy to hit:
ERROR cinder.scheduler.weights.goodness maximum recursion depth
exceeded: RecursionError: maximum recursion depth exceeded
I did some tests to find the root cause. It seems that pyparsing module
does deep recursive parsing quite a lot (default recursion limit is 1000).
Not sure how to solve it but it would be nice to at least have a warning
in the docs.
Results and methodology below.
Tests were done using following code snippet
-------------------------------------------
from cinder.scheduler.evaluator.evaluator import evaluate
import sys
formulas = [
"1",
"1 + 1",
"max(1, 2, 3)",
"max(1 + (10 / 20), 2, 3)",
"(1 + max(1 + (10 / 20), 2, 3)) / 100",
"((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb",
"(((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb)
/ 100",
]
stats = {
'allocated_capacity_gb': 50000,
'total_capacity_gb': 60000,
'free_capacity_gb': 10000,
}
for f in formulas:
for i in range(10, 2000, 10):
sys.setrecursionlimit(i)
try:
res = evaluate(f, stats=stats)
print(f"{i}: {f}")
break
except RecursionError:
pass
Test results
--------------------------------
Cinder 14.3.1, pyparsing<3.0
210: 1
210: 1 + 1
450: max(1, 2, 3)
600: max(1 + (10 / 20), 2, 3)
790: (1 + max(1 + (10 / 20), 2, 3)) / 100
980: ((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb
1160: (((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb)
/ 100
Cinder 16.4.2, pyparsing<3.0
220: 1
220: 1 + 1
450: max(1, 2, 3)
610: max(1 + (10 / 20), 2, 3)
790: (1 + max(1 + (10 / 20), 2, 3)) / 100
980: ((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb
1170: (((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb)
/ 100
Cinder 19.1.0, pyparsing<3.0
220: 1
220: 1 + 1
450: max(1, 2, 3)
610: max(1 + (10 / 20), 2, 3)
790: (1 + max(1 + (10 / 20), 2, 3)) / 100
980: ((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb
1170: (((1 + max(1 + (10 / 20), 2, 3)) / 100) + stats.total_capacity_gb)
/ 100
BR
More information about the openstack-discuss
mailing list