mirror of
https://github.com/ansible/awx.git
synced 2026-02-15 02:00:01 -03:30
Dynamic -> Smart Inventory
This commit is contained in:
@@ -45,7 +45,7 @@ from awx.main.fields import ImplicitRoleField
|
|||||||
from awx.main.utils import (
|
from awx.main.utils import (
|
||||||
get_type_for_model, get_model_for_type, timestamp_apiformat,
|
get_type_for_model, get_model_for_type, timestamp_apiformat,
|
||||||
camelcase_to_underscore, getattrd, parse_yaml_or_json)
|
camelcase_to_underscore, getattrd, parse_yaml_or_json)
|
||||||
from awx.main.utils.filters import DynamicFilter
|
from awx.main.utils.filters import SmartFilter
|
||||||
|
|
||||||
from awx.main.validators import vars_validate_or_raise
|
from awx.main.validators import vars_validate_or_raise
|
||||||
|
|
||||||
@@ -1144,11 +1144,11 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
kind = attrs.get('kind', 'standard')
|
kind = attrs.get('kind', 'standard')
|
||||||
if kind == 'dynamic':
|
if kind == 'smart':
|
||||||
host_filter = attrs.get('host_filter')
|
host_filter = attrs.get('host_filter')
|
||||||
if host_filter is not None:
|
if host_filter is not None:
|
||||||
try:
|
try:
|
||||||
DynamicFilter().query_from_string(host_filter)
|
SmartFilter().query_from_string(host_filter)
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
raise models.base.ValidationError(e)
|
raise models.base.ValidationError(e)
|
||||||
return super(InventorySerializer, self).validate(attrs)
|
return super(InventorySerializer, self).validate(attrs)
|
||||||
@@ -3437,7 +3437,7 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
def get_instances(self, obj):
|
def get_instances(self, obj):
|
||||||
return obj.instances.count()
|
return obj.instances.count()
|
||||||
|
|
||||||
|
|
||||||
class ActivityStreamSerializer(BaseSerializer):
|
class ActivityStreamSerializer(BaseSerializer):
|
||||||
|
|
||||||
changes = serializers.SerializerMethodField()
|
changes = serializers.SerializerMethodField()
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ from awx.main.utils import * # noqa
|
|||||||
from awx.main.utils import (
|
from awx.main.utils import (
|
||||||
callback_filter_out_ansible_extra_vars
|
callback_filter_out_ansible_extra_vars
|
||||||
)
|
)
|
||||||
from awx.main.utils.filters import DynamicFilter
|
from awx.main.utils.filters import SmartFilter
|
||||||
|
|
||||||
from awx.api.permissions import * # noqa
|
from awx.api.permissions import * # noqa
|
||||||
from awx.api.renderers import * # noqa
|
from awx.api.renderers import * # noqa
|
||||||
@@ -554,7 +554,7 @@ class InstanceGroupDetail(RetrieveAPIView):
|
|||||||
serializer_class = InstanceGroupSerializer
|
serializer_class = InstanceGroupSerializer
|
||||||
new_in_320 = True
|
new_in_320 = True
|
||||||
|
|
||||||
|
|
||||||
class InstanceGroupUnifiedJobsList(SubListAPIView):
|
class InstanceGroupUnifiedJobsList(SubListAPIView):
|
||||||
|
|
||||||
view_name = _("Instance Group Running Jobs")
|
view_name = _("Instance Group Running Jobs")
|
||||||
@@ -1924,7 +1924,7 @@ class HostList(ListCreateAPIView):
|
|||||||
qs = super(HostList, self).get_queryset()
|
qs = super(HostList, self).get_queryset()
|
||||||
filter_string = self.request.query_params.get('host_filter', None)
|
filter_string = self.request.query_params.get('host_filter', None)
|
||||||
if filter_string:
|
if filter_string:
|
||||||
filter_qs = DynamicFilter.query_from_string(filter_string)
|
filter_qs = SmartFilter.query_from_string(filter_string)
|
||||||
qs &= filter_qs
|
qs &= filter_qs
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ from jsonfield import JSONField as upstream_JSONField
|
|||||||
from jsonbfield.fields import JSONField as upstream_JSONBField
|
from jsonbfield.fields import JSONField as upstream_JSONBField
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.utils.filters import DynamicFilter
|
from awx.main.utils.filters import SmartFilter
|
||||||
from awx.main.validators import validate_ssh_private_key
|
from awx.main.validators import validate_ssh_private_key
|
||||||
from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role
|
from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role
|
||||||
from awx.main import utils
|
from awx.main import utils
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['AutoOneToOneField', 'ImplicitRoleField', 'JSONField', 'DynamicFilterField']
|
__all__ = ['AutoOneToOneField', 'ImplicitRoleField', 'JSONField', 'SmartFilterField']
|
||||||
|
|
||||||
|
|
||||||
class JSONField(upstream_JSONField):
|
class JSONField(upstream_JSONField):
|
||||||
@@ -331,17 +331,17 @@ class ImplicitRoleField(models.ForeignKey):
|
|||||||
Role.rebuild_role_ancestor_list([], child_ids)
|
Role.rebuild_role_ancestor_list([], child_ids)
|
||||||
|
|
||||||
|
|
||||||
class DynamicFilterField(models.TextField):
|
class SmartFilterField(models.TextField):
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
# Change any false value to none.
|
# Change any false value to none.
|
||||||
# https://docs.python.org/2/library/stdtypes.html#truth-value-testing
|
# https://docs.python.org/2/library/stdtypes.html#truth-value-testing
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
DynamicFilter().query_from_string(value)
|
SmartFilter().query_from_string(value)
|
||||||
except RuntimeError, e:
|
except RuntimeError, e:
|
||||||
raise models.base.ValidationError(e)
|
raise models.base.ValidationError(e)
|
||||||
return super(DynamicFilterField, self).get_prep_value(value)
|
return super(SmartFilterField, self).get_prep_value(value)
|
||||||
|
|
||||||
|
|
||||||
class JSONSchemaField(JSONBField):
|
class JSONSchemaField(JSONBField):
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from django.utils.timezone import now
|
|||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from awx.main.utils.filters import DynamicFilter
|
from awx.main.utils.filters import SmartFilter
|
||||||
|
|
||||||
___all__ = ['HostManager', 'InstanceManager']
|
___all__ = ['HostManager', 'InstanceManager']
|
||||||
|
|
||||||
@@ -25,15 +25,15 @@ class HostManager(models.Manager):
|
|||||||
return len(set(self.values_list('name', flat=True)))
|
return len(set(self.values_list('name', flat=True)))
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""When the parent instance of the host query set has a `kind` of dynamic and a `host_filter`
|
"""When the parent instance of the host query set has a `kind=smart` and a `host_filter`
|
||||||
set. Use the `host_filter` to generate the queryset for the hosts.
|
set. Use the `host_filter` to generate the queryset for the hosts.
|
||||||
"""
|
"""
|
||||||
qs = super(HostManager, self).get_queryset()
|
qs = super(HostManager, self).get_queryset()
|
||||||
if (hasattr(self, 'instance') and
|
if (hasattr(self, 'instance') and
|
||||||
hasattr(self.instance, 'host_filter') and
|
hasattr(self.instance, 'host_filter') and
|
||||||
hasattr(self.instance, 'kind')):
|
hasattr(self.instance, 'kind')):
|
||||||
if self.instance.kind == 'dynamic' and self.instance.host_filter is not None:
|
if self.instance.kind == 'smart' and self.instance.host_filter is not None:
|
||||||
q = DynamicFilter.query_from_string(self.instance.host_filter)
|
q = SmartFilter.query_from_string(self.instance.host_filter)
|
||||||
# If we are using host_filters, disable the core_filters, this allows
|
# If we are using host_filters, disable the core_filters, this allows
|
||||||
# us to access all of the available Host entries, not just the ones associated
|
# us to access all of the available Host entries, not just the ones associated
|
||||||
# with a specific FK/relation.
|
# with a specific FK/relation.
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='inventory',
|
model_name='inventory',
|
||||||
name='host_filter',
|
name='host_filter',
|
||||||
field=awx.main.fields.DynamicFilterField(default=None, help_text='Filter that will be applied to the hosts of this inventory.', null=True, blank=True),
|
field=awx.main.fields.SmartFilterField(default=None, help_text='Filter that will be applied to the hosts of this inventory.', null=True, blank=True),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='inventory',
|
model_name='inventory',
|
||||||
name='kind',
|
name='kind',
|
||||||
field=models.CharField(default=b'standard', help_text='Kind of inventory being represented.', max_length=32, choices=[(b'standard', 'Hosts have a direct link to this inventory.'), (b'dynamic', 'Hosts for inventory generated using the host_filter property.')]),
|
field=models.CharField(default=b'', help_text='Kind of inventory being represented.', max_length=32, choices=[(b'', 'Hosts have a direct link to this inventory.'), (b'smart', 'Hosts for inventory generated using the host_filter property.')]),
|
||||||
),
|
),
|
||||||
|
|
||||||
# Facts
|
# Facts
|
||||||
@@ -236,7 +236,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.DeleteModel(
|
migrations.DeleteModel(
|
||||||
name='Permission',
|
name='Permission',
|
||||||
),
|
),
|
||||||
|
|
||||||
# Insights
|
# Insights
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='host',
|
model_name='host',
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from awx.main.constants import CLOUD_PROVIDERS
|
|||||||
from awx.main.fields import (
|
from awx.main.fields import (
|
||||||
ImplicitRoleField,
|
ImplicitRoleField,
|
||||||
JSONBField,
|
JSONBField,
|
||||||
DynamicFilterField,
|
SmartFilterField,
|
||||||
)
|
)
|
||||||
from awx.main.managers import HostManager
|
from awx.main.managers import HostManager
|
||||||
from awx.main.models.base import * # noqa
|
from awx.main.models.base import * # noqa
|
||||||
@@ -47,8 +47,8 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
KIND_CHOICES = [
|
KIND_CHOICES = [
|
||||||
('standard', _('Hosts have a direct link to this inventory.')),
|
('', _('Hosts have a direct link to this inventory.')),
|
||||||
('dynamic', _('Hosts for inventory generated using the host_filter property.')),
|
('smart', _('Hosts for inventory generated using the host_filter property.')),
|
||||||
]
|
]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -111,11 +111,11 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
|
|||||||
kind = models.CharField(
|
kind = models.CharField(
|
||||||
max_length=32,
|
max_length=32,
|
||||||
choices=KIND_CHOICES,
|
choices=KIND_CHOICES,
|
||||||
blank=False,
|
blank=True,
|
||||||
default='standard',
|
default='',
|
||||||
help_text=_('Kind of inventory being represented.'),
|
help_text=_('Kind of inventory being represented.'),
|
||||||
)
|
)
|
||||||
host_filter = DynamicFilterField(
|
host_filter = SmartFilterField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
default=None,
|
default=None,
|
||||||
|
|||||||
@@ -83,39 +83,39 @@ def setup_inventory_groups(inventory, group_factory):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
class TestHostManager:
|
class TestHostManager:
|
||||||
def test_host_filter_change(self, setup_ec2_gce, organization):
|
def test_host_filter_change(self, setup_ec2_gce, organization):
|
||||||
dynamic_inventory = Inventory(name='dynamic',
|
smart_inventory = Inventory(name='smart',
|
||||||
kind='dynamic',
|
kind='smart',
|
||||||
organization=organization,
|
organization=organization,
|
||||||
host_filter='inventory_sources__source=ec2')
|
host_filter='inventory_sources__source=ec2')
|
||||||
dynamic_inventory.save()
|
smart_inventory.save()
|
||||||
assert len(dynamic_inventory.hosts.all()) == 2
|
assert len(smart_inventory.hosts.all()) == 2
|
||||||
|
|
||||||
dynamic_inventory.host_filter = 'inventory_sources__source=gce'
|
smart_inventory.host_filter = 'inventory_sources__source=gce'
|
||||||
dynamic_inventory.save()
|
smart_inventory.save()
|
||||||
assert len(dynamic_inventory.hosts.all()) == 1
|
assert len(smart_inventory.hosts.all()) == 1
|
||||||
|
|
||||||
def test_host_filter_not_dynamic(self, setup_ec2_gce, organization):
|
def test_host_filter_not_smart(self, setup_ec2_gce, organization):
|
||||||
dynamic_inventory = Inventory(name='dynamic',
|
smart_inventory = Inventory(name='smart',
|
||||||
organization=organization,
|
organization=organization,
|
||||||
host_filter='inventory_sources__source=ec2')
|
host_filter='inventory_sources__source=ec2')
|
||||||
assert len(dynamic_inventory.hosts.all()) == 0
|
assert len(smart_inventory.hosts.all()) == 0
|
||||||
|
|
||||||
def test_host_objects_manager(self, setup_ec2_gce, organization):
|
def test_host_objects_manager(self, setup_ec2_gce, organization):
|
||||||
dynamic_inventory = Inventory(kind='dynamic',
|
smart_inventory = Inventory(kind='smart',
|
||||||
name='dynamic',
|
name='smart',
|
||||||
organization=organization,
|
organization=organization,
|
||||||
host_filter='inventory_sources__source=ec2')
|
host_filter='inventory_sources__source=ec2')
|
||||||
dynamic_inventory.save()
|
smart_inventory.save()
|
||||||
|
|
||||||
hosts = dynamic_inventory.hosts.all()
|
hosts = smart_inventory.hosts.all()
|
||||||
assert len(hosts) == 2
|
assert len(hosts) == 2
|
||||||
assert hosts[0].inventory_sources.first().source == 'ec2'
|
assert hosts[0].inventory_sources.first().source == 'ec2'
|
||||||
assert hosts[1].inventory_sources.first().source == 'ec2'
|
assert hosts[1].inventory_sources.first().source == 'ec2'
|
||||||
|
|
||||||
def test_host_objects_no_dupes(self, setup_inventory_groups, organization):
|
def test_host_objects_no_dupes(self, setup_inventory_groups, organization):
|
||||||
dynamic_inventory = Inventory(name='dynamic',
|
smart_inventory = Inventory(name='smart',
|
||||||
kind='dynamic',
|
kind='smart',
|
||||||
organization=organization,
|
organization=organization,
|
||||||
host_filter='groups__name=test_groupA or groups__name=test_groupB')
|
host_filter='groups__name=test_groupA or groups__name=test_groupB')
|
||||||
dynamic_inventory.save()
|
smart_inventory.save()
|
||||||
assert len(dynamic_inventory.hosts.all()) == 1
|
assert len(smart_inventory.hosts.all()) == 1
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import pytest
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.utils.filters import DynamicFilter
|
from awx.main.utils.filters import SmartFilter
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
@@ -22,7 +22,7 @@ class mockHost:
|
|||||||
|
|
||||||
|
|
||||||
@mock.patch('awx.main.utils.filters.get_host_model', return_value=mockHost())
|
@mock.patch('awx.main.utils.filters.get_host_model', return_value=mockHost())
|
||||||
class TestDynamicFilterQueryFromString():
|
class TestSmartFilterQueryFromString():
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
('facts__facts__blank=""', Q(**{u"facts__facts__blank": u""})),
|
('facts__facts__blank=""', Q(**{u"facts__facts__blank": u""})),
|
||||||
('"facts__facts__ space "="f"', Q(**{u"facts__facts__ space ": u"f"})),
|
('"facts__facts__ space "="f"', Q(**{u"facts__facts__ space ": u"f"})),
|
||||||
@@ -36,7 +36,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
])
|
])
|
||||||
def test_query_generated(self, mock_get_host_model, filter_string, q_expected):
|
def test_query_generated(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string", [
|
@pytest.mark.parametrize("filter_string", [
|
||||||
@@ -45,7 +45,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
])
|
])
|
||||||
def test_invalid_filter_strings(self, mock_get_host_model, filter_string):
|
def test_invalid_filter_strings(self, mock_get_host_model, filter_string):
|
||||||
with pytest.raises(RuntimeError) as e:
|
with pytest.raises(RuntimeError) as e:
|
||||||
DynamicFilter.query_from_string(filter_string)
|
SmartFilter.query_from_string(filter_string)
|
||||||
assert e.value.message == u"Invalid query " + filter_string
|
assert e.value.message == u"Invalid query " + filter_string
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
@@ -53,7 +53,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
(u'(ansible_facts__a=abc\u1F5E3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1F5E3def"}})),
|
(u'(ansible_facts__a=abc\u1F5E3def)', Q(**{u"ansible_facts__contains": {u"a": u"abc\u1F5E3def"}})),
|
||||||
])
|
])
|
||||||
def test_unicode(self, mock_get_host_model, filter_string, q_expected):
|
def test_unicode(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
@@ -67,7 +67,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
('a=b or a=d or a=e or a=z and b=h and b=i and b=j and b=k', Q(**{u"a": u"b"}) | Q(**{u"a": u"d"}) | Q(**{u"a": u"e"}) | Q(**{u"a": u"z"}) & Q(**{u"b": u"h"}) & Q(**{u"b": u"i"}) & Q(**{u"b": u"j"}) & Q(**{u"b": u"k"}))
|
('a=b or a=d or a=e or a=z and b=h and b=i and b=j and b=k', Q(**{u"a": u"b"}) | Q(**{u"a": u"d"}) | Q(**{u"a": u"e"}) | Q(**{u"a": u"z"}) & Q(**{u"b": u"h"}) & Q(**{u"b": u"i"}) & Q(**{u"b": u"j"}) & Q(**{u"b": u"k"}))
|
||||||
])
|
])
|
||||||
def test_boolean_parenthesis(self, mock_get_host_model, filter_string, q_expected):
|
def test_boolean_parenthesis(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
@@ -87,7 +87,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
])
|
])
|
||||||
def test_contains_query_generated(self, mock_get_host_model, filter_string, q_expected):
|
def test_contains_query_generated(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
@@ -97,7 +97,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
#('a__b\"__c="true"', Q(**{u"a__b\"__c": "true"})),
|
||||||
])
|
])
|
||||||
def test_contains_query_generated_unicode(self, mock_get_host_model, filter_string, q_expected):
|
def test_contains_query_generated_unicode(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
@pytest.mark.parametrize("filter_string,q_expected", [
|
@pytest.mark.parametrize("filter_string,q_expected", [
|
||||||
@@ -105,7 +105,7 @@ class TestDynamicFilterQueryFromString():
|
|||||||
('ansible_facts__c="null"', Q(**{u"ansible_facts__contains": {u"c": u"\"null\""}})),
|
('ansible_facts__c="null"', Q(**{u"ansible_facts__contains": {u"c": u"\"null\""}})),
|
||||||
])
|
])
|
||||||
def test_contains_query_generated_null(self, mock_get_host_model, filter_string, q_expected):
|
def test_contains_query_generated_null(self, mock_get_host_model, filter_string, q_expected):
|
||||||
q = DynamicFilter.query_from_string(filter_string)
|
q = SmartFilter.query_from_string(filter_string)
|
||||||
assert unicode(q) == unicode(q_expected)
|
assert unicode(q) == unicode(q_expected)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from pyparsing import (
|
|||||||
|
|
||||||
import django
|
import django
|
||||||
|
|
||||||
__all__ = ['DynamicFilter']
|
__all__ = ['SmartFilter']
|
||||||
|
|
||||||
unicode_spaces = [unichr(c) for c in xrange(sys.maxunicode) if unichr(c).isspace()]
|
unicode_spaces = [unichr(c) for c in xrange(sys.maxunicode) if unichr(c).isspace()]
|
||||||
unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
|
unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
|
||||||
@@ -35,7 +35,7 @@ def get_host_model():
|
|||||||
return django.apps.apps.get_model('main', 'host')
|
return django.apps.apps.get_model('main', 'host')
|
||||||
|
|
||||||
|
|
||||||
class DynamicFilter(object):
|
class SmartFilter(object):
|
||||||
SEARCHABLE_RELATIONSHIP = 'ansible_facts'
|
SEARCHABLE_RELATIONSHIP = 'ansible_facts'
|
||||||
|
|
||||||
class BoolOperand(object):
|
class BoolOperand(object):
|
||||||
@@ -68,20 +68,20 @@ class DynamicFilter(object):
|
|||||||
relationship refered to to see if it's a jsonb type.
|
relationship refered to to see if it's a jsonb type.
|
||||||
'''
|
'''
|
||||||
def _json_path_to_contains(self, k, v):
|
def _json_path_to_contains(self, k, v):
|
||||||
if not k.startswith(DynamicFilter.SEARCHABLE_RELATIONSHIP):
|
if not k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP):
|
||||||
v = self.strip_quotes_traditional_logic(v)
|
v = self.strip_quotes_traditional_logic(v)
|
||||||
return (k, v)
|
return (k, v)
|
||||||
|
|
||||||
# Strip off leading relationship key
|
# Strip off leading relationship key
|
||||||
if k.startswith(DynamicFilter.SEARCHABLE_RELATIONSHIP + '__'):
|
if k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP + '__'):
|
||||||
strip_len = len(DynamicFilter.SEARCHABLE_RELATIONSHIP) + 2
|
strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP) + 2
|
||||||
else:
|
else:
|
||||||
strip_len = len(DynamicFilter.SEARCHABLE_RELATIONSHIP)
|
strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP)
|
||||||
k = k[strip_len:]
|
k = k[strip_len:]
|
||||||
|
|
||||||
pieces = k.split(u'__')
|
pieces = k.split(u'__')
|
||||||
|
|
||||||
assembled_k = u'%s__contains' % (DynamicFilter.SEARCHABLE_RELATIONSHIP)
|
assembled_k = u'%s__contains' % (SmartFilter.SEARCHABLE_RELATIONSHIP)
|
||||||
assembled_v = None
|
assembled_v = None
|
||||||
|
|
||||||
last_v = None
|
last_v = None
|
||||||
|
|||||||
Reference in New Issue
Block a user