prevent field lookups on Host.ansible_facts keys (it doesn't work)

under the hood, Host.ansible_facts is a postgres jsonb field which
performs match operations using the JSON containment operator (@>)

this operator _only_ works on exact matches on containment (i.e.,
"does the `ansible_distribution` jsonb value contain _this exact_ JSON
structure"):

SELECT ...
FROM main_host
WHERE ansible_facts @> '{"ansible_distribution": "centos"}'

SELECT ...
FROM main_host
WHERE ansible_facts @> '{"packages": {"dnsmasq": [{"version": 2}]}}'

postgres does _not_ expose any operator for fuzzy or lookup-based
matches with this operator, so host filter values like these don't
really make sense (postgres can't _filter_ in the way intended in these
examples):

ansible_distribution__startswith=\"Cent\"
ansible_distribution__icontains=\"CentOS\"
ansible_facts__packages__dnsmasq[]__version__startswith=\"2\"
This commit is contained in:
Ryan Petrello
2019-02-04 21:28:50 -05:00
parent cab6b8b333
commit bb5312f4fc
4 changed files with 62 additions and 2 deletions

View File

@@ -47,7 +47,7 @@ from awx.main.constants import (
)
from awx.main.models import * # noqa
from awx.main.models.base import NEW_JOB_TYPE_CHOICES
from awx.main.fields import ImplicitRoleField
from awx.main.fields import ImplicitRoleField, JSONBField
from awx.main.utils import (
get_type_for_model, get_model_for_type, timestamp_apiformat,
camelcase_to_underscore, getattrd, parse_yaml_or_json,
@@ -1542,6 +1542,18 @@ class InventorySerializer(BaseSerializerWithVariables):
def validate_host_filter(self, host_filter):
if host_filter:
try:
for match in JSONBField.get_lookups().keys():
if match == 'exact':
# __exact is allowed
continue
match = '__{}'.format(match)
if re.match(
'ansible_facts[^=]+{}='.format(match),
host_filter
):
raise models.base.ValidationError({
'host_filter': 'ansible_facts does not support searching with {}'.format(match)
})
SmartFilter().query_from_string(host_filter)
except RuntimeError as e:
raise models.base.ValidationError(e)