mirror of
https://github.com/ansible/awx.git
synced 2026-05-17 22:37:41 -02:30
Initial implementation of fact api endpoints
This commit is contained in:
@@ -19,6 +19,11 @@ from rest_framework.filters import BaseFilterBackend
|
|||||||
# Ansible Tower
|
# Ansible Tower
|
||||||
from awx.main.utils import get_type_for_model, to_python_boolean
|
from awx.main.utils import get_type_for_model, to_python_boolean
|
||||||
|
|
||||||
|
class MongoFilterBackend(BaseFilterBackend):
|
||||||
|
|
||||||
|
def filter_queryset(self, request, queryset, view):
|
||||||
|
return queryset
|
||||||
|
|
||||||
class ActiveOnlyBackend(BaseFilterBackend):
|
class ActiveOnlyBackend(BaseFilterBackend):
|
||||||
'''
|
'''
|
||||||
Filter to show only objects where is_active/active is True.
|
Filter to show only objects where is_active/active is True.
|
||||||
@@ -61,7 +66,7 @@ class TypeFilterBackend(BaseFilterBackend):
|
|||||||
queryset = queryset.filter(polymorphic_ctype_id__in=types_pks)
|
queryset = queryset.filter(polymorphic_ctype_id__in=types_pks)
|
||||||
elif model_type in types:
|
elif model_type in types:
|
||||||
queryset = queryset
|
queryset = queryset
|
||||||
else:
|
else:
|
||||||
queryset = queryset.none()
|
queryset = queryset.none()
|
||||||
return queryset
|
return queryset
|
||||||
except FieldError, e:
|
except FieldError, e:
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ __all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
|
|||||||
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
|
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
|
||||||
'SubListCreateAttachDetachAPIView', 'RetrieveAPIView',
|
'SubListCreateAttachDetachAPIView', 'RetrieveAPIView',
|
||||||
'RetrieveUpdateAPIView', 'RetrieveDestroyAPIView',
|
'RetrieveUpdateAPIView', 'RetrieveDestroyAPIView',
|
||||||
'RetrieveUpdateDestroyAPIView', 'DestroyAPIView']
|
'RetrieveUpdateDestroyAPIView', 'DestroyAPIView',
|
||||||
|
'MongoAPIView', 'MongoListAPIView']
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.generics')
|
logger = logging.getLogger('awx.api.generics')
|
||||||
|
|
||||||
@@ -164,7 +165,6 @@ class APIView(views.APIView):
|
|||||||
ret['added_in_version'] = added_in_version
|
ret['added_in_version'] = added_in_version
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class GenericAPIView(generics.GenericAPIView, APIView):
|
class GenericAPIView(generics.GenericAPIView, APIView):
|
||||||
# Base class for all model-based views.
|
# Base class for all model-based views.
|
||||||
|
|
||||||
@@ -195,11 +195,13 @@ class GenericAPIView(generics.GenericAPIView, APIView):
|
|||||||
if not hasattr(self, 'format_kwarg'):
|
if not hasattr(self, 'format_kwarg'):
|
||||||
self.format_kwarg = 'format'
|
self.format_kwarg = 'format'
|
||||||
d = super(GenericAPIView, self).get_description_context()
|
d = super(GenericAPIView, self).get_description_context()
|
||||||
d.update({
|
if hasattr(self.model, "_meta"):
|
||||||
'model_verbose_name': unicode(self.model._meta.verbose_name),
|
if hasattr(self.model._meta, "verbose_name"):
|
||||||
'model_verbose_name_plural': unicode(self.model._meta.verbose_name_plural),
|
d.update({
|
||||||
'serializer_fields': self.get_serializer().metadata(),
|
'model_verbose_name': unicode(self.model._meta.verbose_name),
|
||||||
})
|
'model_verbose_name_plural': unicode(self.model._meta.verbose_name_plural),
|
||||||
|
})
|
||||||
|
d.update({'serializer_fields': self.get_serializer().metadata()})
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def metadata(self, request):
|
def metadata(self, request):
|
||||||
@@ -252,6 +254,27 @@ class GenericAPIView(generics.GenericAPIView, APIView):
|
|||||||
ret['search_fields'] = self.search_fields
|
ret['search_fields'] = self.search_fields
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
class MongoAPIView(GenericAPIView):
|
||||||
|
|
||||||
|
def get_parent_object(self):
|
||||||
|
parent_filter = {
|
||||||
|
self.lookup_field: self.kwargs.get(self.lookup_field, None),
|
||||||
|
}
|
||||||
|
return get_object_or_404(self.parent_model, **parent_filter)
|
||||||
|
|
||||||
|
def check_parent_access(self, parent=None):
|
||||||
|
parent = parent or self.get_parent_object()
|
||||||
|
parent_access = getattr(self, 'parent_access', 'read')
|
||||||
|
if parent_access in ('read', 'delete'):
|
||||||
|
args = (self.parent_model, parent_access, parent)
|
||||||
|
else:
|
||||||
|
args = (self.parent_model, parent_access, parent, None)
|
||||||
|
if not self.request.user.can_access(*args):
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
class MongoListAPIView(generics.ListAPIView, MongoAPIView):
|
||||||
|
pass
|
||||||
|
|
||||||
class SimpleListAPIView(generics.ListAPIView, GenericAPIView):
|
class SimpleListAPIView(generics.ListAPIView, GenericAPIView):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import logging
|
|||||||
from dateutil import rrule
|
from dateutil import rrule
|
||||||
from ast import literal_eval
|
from ast import literal_eval
|
||||||
|
|
||||||
|
import mongoengine
|
||||||
|
from rest_framework_mongoengine.serializers import MongoEngineModelSerializer
|
||||||
|
|
||||||
# PyYAML
|
# PyYAML
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@@ -36,6 +39,8 @@ from awx.main.models import * # noqa
|
|||||||
from awx.main.utils import get_type_for_model, get_model_for_type
|
from awx.main.utils import get_type_for_model, get_model_for_type
|
||||||
from awx.main.redact import REPLACE_STR
|
from awx.main.redact import REPLACE_STR
|
||||||
|
|
||||||
|
from awx.fact.models import * # noqa
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.serializers')
|
logger = logging.getLogger('awx.api.serializers')
|
||||||
|
|
||||||
# Fields that should be summarized regardless of object type.
|
# Fields that should be summarized regardless of object type.
|
||||||
@@ -1537,12 +1542,10 @@ class JobRelaunchSerializer(JobSerializer):
|
|||||||
obj = self.context.get('obj')
|
obj = self.context.get('obj')
|
||||||
if not obj.credential or obj.credential.active is False:
|
if not obj.credential or obj.credential.active is False:
|
||||||
raise serializers.ValidationError(dict(credential=["Credential not found or deleted."]))
|
raise serializers.ValidationError(dict(credential=["Credential not found or deleted."]))
|
||||||
|
|
||||||
if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active):
|
if obj.job_type != PERM_INVENTORY_SCAN and (obj.project is None or not obj.project.active):
|
||||||
raise serializers.ValidationError(dict(errors=["Job Template Project is missing or undefined"]))
|
raise serializers.ValidationError(dict(errors=["Job Template Project is missing or undefined"]))
|
||||||
if obj.inventory is None or not obj.inventory.active:
|
if obj.inventory is None or not obj.inventory.active:
|
||||||
raise serializers.ValidationError(dict(errors=["Job Template Inventory is missing or undefined"]))
|
raise serializers.ValidationError(dict(errors=["Job Template Inventory is missing or undefined"]))
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
class AdHocCommandSerializer(UnifiedJobSerializer):
|
class AdHocCommandSerializer(UnifiedJobSerializer):
|
||||||
@@ -2010,3 +2013,17 @@ class AuthTokenSerializer(serializers.Serializer):
|
|||||||
raise serializers.ValidationError('Unable to login with provided credentials.')
|
raise serializers.ValidationError('Unable to login with provided credentials.')
|
||||||
else:
|
else:
|
||||||
raise serializers.ValidationError('Must include "username" and "password"')
|
raise serializers.ValidationError('Must include "username" and "password"')
|
||||||
|
|
||||||
|
|
||||||
|
class FactVersionSerializer(MongoEngineModelSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = FactVersion
|
||||||
|
fields = ('module', 'timestamp',)
|
||||||
|
|
||||||
|
class FactSerializer(MongoEngineModelSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Fact
|
||||||
|
depth = 2
|
||||||
|
fields = ('timestamp', 'host', 'module', 'fact')
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ inventory_urls = patterns('awx.api.views',
|
|||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'inventory_activity_stream_list'),
|
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'inventory_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/scan_job_templates/$', 'inventory_scan_job_template_list'),
|
url(r'^(?P<pk>[0-9]+)/scan_job_templates/$', 'inventory_scan_job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'inventory_ad_hoc_commands_list'),
|
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'inventory_ad_hoc_commands_list'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/single_fact/$', 'inventory_single_fact_view'),
|
||||||
)
|
)
|
||||||
|
|
||||||
host_urls = patterns('awx.api.views',
|
host_urls = patterns('awx.api.views',
|
||||||
@@ -89,6 +90,9 @@ host_urls = patterns('awx.api.views',
|
|||||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'host_inventory_sources_list'),
|
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'host_inventory_sources_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'host_ad_hoc_commands_list'),
|
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'host_ad_hoc_commands_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', 'host_ad_hoc_command_events_list'),
|
url(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', 'host_ad_hoc_command_events_list'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/single_fact/$', 'host_single_fact_view'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/fact_versions/$', 'host_fact_versions_list'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/fact_view/$', 'host_fact_compare_view'),
|
||||||
)
|
)
|
||||||
|
|
||||||
group_urls = patterns('awx.api.views',
|
group_urls = patterns('awx.api.views',
|
||||||
@@ -104,6 +108,7 @@ group_urls = patterns('awx.api.views',
|
|||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'group_activity_stream_list'),
|
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'group_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'group_inventory_sources_list'),
|
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'group_inventory_sources_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'group_ad_hoc_commands_list'),
|
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'group_ad_hoc_commands_list'),
|
||||||
|
url(r'^(?P<pk>[0-9]+)/single_fact/$', 'group_single_fact_view'),
|
||||||
)
|
)
|
||||||
|
|
||||||
inventory_source_urls = patterns('awx.api.views',
|
inventory_source_urls = patterns('awx.api.views',
|
||||||
|
|||||||
118
awx/api/views.py
118
awx/api/views.py
@@ -46,6 +46,7 @@ from awx.main.access import get_user_queryset
|
|||||||
from awx.main.ha import is_ha_environment
|
from awx.main.ha import is_ha_environment
|
||||||
from awx.api.authentication import TaskAuthentication
|
from awx.api.authentication import TaskAuthentication
|
||||||
from awx.api.utils.decorators import paginated
|
from awx.api.utils.decorators import paginated
|
||||||
|
from awx.api.filters import MongoFilterBackend
|
||||||
from awx.api.generics import get_view_name
|
from awx.api.generics import get_view_name
|
||||||
from awx.api.generics import * # noqa
|
from awx.api.generics import * # noqa
|
||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
@@ -53,6 +54,7 @@ from awx.main.utils import * # noqa
|
|||||||
from awx.api.permissions import * # noqa
|
from awx.api.permissions import * # noqa
|
||||||
from awx.api.renderers import * # noqa
|
from awx.api.renderers import * # noqa
|
||||||
from awx.api.serializers import * # noqa
|
from awx.api.serializers import * # noqa
|
||||||
|
from awx.fact.models import * # noqa
|
||||||
|
|
||||||
def api_exception_handler(exc):
|
def api_exception_handler(exc):
|
||||||
'''
|
'''
|
||||||
@@ -922,6 +924,27 @@ class InventoryScanJobTemplateList(SubListAPIView):
|
|||||||
qs = self.request.user.get_queryset(self.model)
|
qs = self.request.user.get_queryset(self.model)
|
||||||
return qs.filter(job_type=PERM_INVENTORY_SCAN, inventory=parent)
|
return qs.filter(job_type=PERM_INVENTORY_SCAN, inventory=parent)
|
||||||
|
|
||||||
|
class InventorySingleFactView(MongoAPIView):
|
||||||
|
|
||||||
|
model = Fact
|
||||||
|
parent_model = Inventory
|
||||||
|
new_in_220 = True
|
||||||
|
serializer_class = FactSerializer
|
||||||
|
filter_backends = (MongoFilterBackend,)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
fact_key = request.QUERY_PARAMS.get("fact_key", None)
|
||||||
|
fact_value = request.QUERY_PARAMS.get("fact_value", None)
|
||||||
|
datetime_spec = request.QUERY_PARAMS.get("timestamp", None)
|
||||||
|
module_spec = request.QUERY_PARAMS.get("module", None)
|
||||||
|
|
||||||
|
if fact_key is None or fact_value is None or module_spec is None:
|
||||||
|
return Response({"error": "Missing fields"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
datetime_actual = dateutil.parser.parse(datetime_spec) if datetime_spec is not None else now()
|
||||||
|
inventory_obj = self.get_parent_object()
|
||||||
|
fact_data = Fact.get_single_facts([h.name for h in inventory_obj.hosts.all()], fact_key, fact_value, datetime_actual, module_spec)
|
||||||
|
return Response(FactSerializer(fact_data).data if fact_data is not None else {})
|
||||||
|
|
||||||
|
|
||||||
class HostList(ListCreateAPIView):
|
class HostList(ListCreateAPIView):
|
||||||
|
|
||||||
@@ -986,6 +1009,79 @@ class HostActivityStreamList(SubListAPIView):
|
|||||||
qs = self.request.user.get_queryset(self.model)
|
qs = self.request.user.get_queryset(self.model)
|
||||||
return qs.filter(Q(host=parent) | Q(inventory=parent.inventory))
|
return qs.filter(Q(host=parent) | Q(inventory=parent.inventory))
|
||||||
|
|
||||||
|
class HostFactVersionsList(MongoListAPIView):
|
||||||
|
|
||||||
|
serializer_class = FactVersionSerializer
|
||||||
|
parent_model = Host
|
||||||
|
new_in_220 = True
|
||||||
|
filter_backends = (MongoFilterBackend,)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
from_spec = self.request.QUERY_PARAMS.get('from', None)
|
||||||
|
to_spec = self.request.QUERY_PARAMS.get('to', None)
|
||||||
|
module_spec = self.request.QUERY_PARAMS.get('module', None)
|
||||||
|
|
||||||
|
host = self.get_parent_object()
|
||||||
|
self.check_parent_access(host)
|
||||||
|
|
||||||
|
try:
|
||||||
|
fact_host = FactHost.objects.get(hostname=host.name)
|
||||||
|
except FactHost.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
|
kv = {
|
||||||
|
'host': fact_host.id,
|
||||||
|
}
|
||||||
|
if module_spec is not None:
|
||||||
|
kv['module'] = module_spec
|
||||||
|
if from_spec is not None:
|
||||||
|
from_actual = dateutil.parser.parse(from_spec)
|
||||||
|
kv['timestamp__gt'] = from_actual
|
||||||
|
if from_spec is not None and to_spec is not None:
|
||||||
|
to_actual = dateutil.parser.parse(to_spec)
|
||||||
|
kv['timestamp__lte'] = to_actual
|
||||||
|
|
||||||
|
return FactVersion.objects.filter(**kv).order_by("-timestamp")
|
||||||
|
|
||||||
|
class HostSingleFactView(MongoAPIView):
|
||||||
|
|
||||||
|
model = Fact
|
||||||
|
parent_model = Host
|
||||||
|
new_in_220 = True
|
||||||
|
serializer_class = FactSerializer
|
||||||
|
filter_backends = (MongoFilterBackend,)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
fact_key = request.QUERY_PARAMS.get("fact_key", None)
|
||||||
|
fact_value = request.QUERY_PARAMS.get("fact_value", None)
|
||||||
|
datetime_spec = request.QUERY_PARAMS.get("timestamp", None)
|
||||||
|
module_spec = request.QUERY_PARAMS.get("module", None)
|
||||||
|
|
||||||
|
if fact_key is None or fact_value is None or module_spec is None:
|
||||||
|
return Response({"error": "Missing fields"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
datetime_actual = dateutil.parser.parse(datetime_spec) if datetime_spec is not None else now()
|
||||||
|
host_obj = self.get_parent_object()
|
||||||
|
fact_data = Fact.get_single_facts([host_obj.name], fact_key, fact_value, datetime_actual, module_spec)
|
||||||
|
return Response(FactSerializer(fact_data).data if fact_data is not None else {})
|
||||||
|
|
||||||
|
class HostFactCompareView(MongoAPIView):
|
||||||
|
|
||||||
|
new_in_220 = True
|
||||||
|
parent_model = Host
|
||||||
|
serializer_class = FactSerializer
|
||||||
|
filter_backends = (MongoFilterBackend,)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
datetime_spec = request.QUERY_PARAMS.get('datetime', None)
|
||||||
|
module_spec = request.QUERY_PARAMS.get('module', "ansible")
|
||||||
|
datetime_actual = dateutil.parser.parse(datetime_spec) if datetime_spec is not None else now()
|
||||||
|
|
||||||
|
host_obj = self.get_parent_object()
|
||||||
|
fact_entry = Fact.get_host_version(host_obj.name, datetime_actual, module_spec)
|
||||||
|
host_data = FactSerializer(fact_entry).data if fact_entry is not None else {}
|
||||||
|
|
||||||
|
return Response(host_data)
|
||||||
|
|
||||||
|
|
||||||
class GroupList(ListCreateAPIView):
|
class GroupList(ListCreateAPIView):
|
||||||
|
|
||||||
@@ -1125,6 +1221,28 @@ class GroupDetail(RetrieveUpdateDestroyAPIView):
|
|||||||
obj.mark_inactive_recursive()
|
obj.mark_inactive_recursive()
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSingleFactView(MongoAPIView):
|
||||||
|
|
||||||
|
model = Fact
|
||||||
|
parent_model = Group
|
||||||
|
new_in_220 = True
|
||||||
|
serializer_class = FactSerializer
|
||||||
|
filter_backends = (MongoFilterBackend,)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
fact_key = request.QUERY_PARAMS.get("fact_key", None)
|
||||||
|
fact_value = request.QUERY_PARAMS.get("fact_value", None)
|
||||||
|
datetime_spec = request.QUERY_PARAMS.get("timestamp", None)
|
||||||
|
module_spec = request.QUERY_PARAMS.get("module", None)
|
||||||
|
|
||||||
|
if fact_key is None or fact_value is None or module_spec is None:
|
||||||
|
return Response({"error": "Missing fields"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
datetime_actual = dateutil.parser.parse(datetime_spec) if datetime_spec is not None else now()
|
||||||
|
group_obj = self.get_parent_object()
|
||||||
|
fact_data = Fact.get_single_facts([h.name for h in group_obj.hosts.all()], fact_key, fact_value, datetime_actual, module_spec)
|
||||||
|
return Response(FactSerializer(fact_data).data if fact_data is not None else {})
|
||||||
|
|
||||||
class InventoryGroupsList(SubListCreateAttachDetachAPIView):
|
class InventoryGroupsList(SubListCreateAttachDetachAPIView):
|
||||||
|
|
||||||
model = Group
|
model = Group
|
||||||
|
|||||||
@@ -17,4 +17,4 @@ try:
|
|||||||
connect(settings.MONGO_DB)
|
connect(settings.MONGO_DB)
|
||||||
register_key_transform(get_db())
|
register_key_transform(get_db())
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
logger.warn('Failed to establish connect to MongDB "%s"' % (settings.MONGO_DB))
|
logger.warn('Failed to establish connect to MongoDB "%s"' % (settings.MONGO_DB))
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class Fact(Document):
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
facts = Fact.objects.filter(**kv)
|
facts = Fact.objects.filter(**kv).order_by("-timestamp")
|
||||||
if not facts:
|
if not facts:
|
||||||
return None
|
return None
|
||||||
return facts[0]
|
return facts[0]
|
||||||
@@ -97,7 +97,7 @@ class Fact(Document):
|
|||||||
'module': module,
|
'module': module,
|
||||||
}
|
}
|
||||||
|
|
||||||
return FactVersion.objects.filter(**kv).values_list('timestamp')
|
return FactVersion.objects.filter(**kv).order_by("-timestamp").values_list('timestamp')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_single_facts(hostnames, fact_key, fact_value, timestamp, module):
|
def get_single_facts(hostnames, fact_key, fact_value, timestamp, module):
|
||||||
@@ -126,6 +126,9 @@ class Fact(Document):
|
|||||||
}
|
}
|
||||||
fields = {
|
fields = {
|
||||||
'fact.%s.$' % fact_key : 1,
|
'fact.%s.$' % fact_key : 1,
|
||||||
|
'host': 1,
|
||||||
|
'timestamp': 1,
|
||||||
|
'module': 1,
|
||||||
}
|
}
|
||||||
facts = Fact._get_collection().find(kv, fields)
|
facts = Fact._get_collection().find(kv, fields)
|
||||||
#fact_objs = [Fact(**f) for f in facts]
|
#fact_objs = [Fact(**f) for f in facts]
|
||||||
@@ -136,11 +139,10 @@ class Fact(Document):
|
|||||||
fact_objs.append(Fact(**f))
|
fact_objs.append(Fact(**f))
|
||||||
return fact_objs
|
return fact_objs
|
||||||
|
|
||||||
|
|
||||||
class FactVersion(Document):
|
class FactVersion(Document):
|
||||||
timestamp = DateTimeField(required=True)
|
timestamp = DateTimeField(required=True)
|
||||||
host = ReferenceField(FactHost, required=True)
|
host = ReferenceField(FactHost, required=True)
|
||||||
module = StringField(max_length=50, required=True)
|
module = StringField(max_length=50, required=True)
|
||||||
fact = ReferenceField(Fact, required=True)
|
fact = ReferenceField(Fact, required=True)
|
||||||
# TODO: Consider using hashed index on module. django-mongo may not support this but
|
# TODO: Consider using hashed index on module. django-mongo may not support this but
|
||||||
# executing raw js will
|
# executing raw js will
|
||||||
@@ -150,4 +152,3 @@ class FactVersion(Document):
|
|||||||
'module'
|
'module'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user