mirror of
https://github.com/ansible/awx.git
synced 2026-03-07 03:31:10 -03:30
remove facts_latest in favor of ansible_facts
* Closer align our facts data structure with ansible facts data structure for purposes of ... wait for it ... 2-way fact caching
This commit is contained in:
@@ -1157,7 +1157,7 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
ad_hoc_commands = self.reverse('api:host_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
|
ad_hoc_commands = self.reverse('api:host_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
|
||||||
ad_hoc_command_events = self.reverse('api:host_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
|
ad_hoc_command_events = self.reverse('api:host_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
|
||||||
fact_versions = self.reverse('api:host_fact_versions_list', kwargs={'pk': obj.pk}),
|
fact_versions = self.reverse('api:host_fact_versions_list', kwargs={'pk': obj.pk}),
|
||||||
facts_latest = self.reverse('api:host_facts_latest_list', kwargs={'pk': obj.pk}),
|
ansible_facts = self.reverse('api:host_ansible_facts_detail', kwargs={'pk': obj.pk}),
|
||||||
))
|
))
|
||||||
if obj.inventory:
|
if obj.inventory:
|
||||||
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
|
||||||
@@ -1237,6 +1237,14 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleFactsSerializer(BaseSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Host
|
||||||
|
|
||||||
|
def to_representation(self, obj):
|
||||||
|
return obj.ansible_facts
|
||||||
|
|
||||||
|
|
||||||
class GroupSerializer(BaseSerializerWithVariables):
|
class GroupSerializer(BaseSerializerWithVariables):
|
||||||
inventory_source = serializers.SerializerMethodField(
|
inventory_source = serializers.SerializerMethodField(
|
||||||
help_text=_('Dedicated inventory source for the group, will be removed in 3.3.'))
|
help_text=_('Dedicated inventory source for the group, will be removed in 3.3.'))
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ host_urls = patterns('awx.api.views',
|
|||||||
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'host_single_fact_view'),
|
#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_versions/$', 'host_fact_versions_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/fact_view/$', 'host_fact_compare_view'),
|
url(r'^(?P<pk>[0-9]+)/fact_view/$', 'host_fact_compare_view'),
|
||||||
url(r'^(?P<pk>[0-9]+)/facts_latest/$', 'host_facts_latest_list'),
|
url(r'^(?P<pk>[0-9]+)/ansible_facts/$', 'host_ansible_facts_detail'),
|
||||||
)
|
)
|
||||||
|
|
||||||
group_urls = patterns('awx.api.views',
|
group_urls = patterns('awx.api.views',
|
||||||
|
|||||||
@@ -1725,6 +1725,13 @@ class HostDetail(RetrieveUpdateDestroyAPIView):
|
|||||||
serializer_class = HostSerializer
|
serializer_class = HostSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class HostAnsibleFactsDetail(RetrieveAPIView):
|
||||||
|
|
||||||
|
model = Host
|
||||||
|
serializer_class = AnsibleFactsSerializer
|
||||||
|
new_in_320 = True
|
||||||
|
|
||||||
|
|
||||||
class InventoryHostsList(SubListCreateAttachDetachAPIView):
|
class InventoryHostsList(SubListCreateAttachDetachAPIView):
|
||||||
|
|
||||||
model = Host
|
model = Host
|
||||||
@@ -1842,15 +1849,6 @@ class HostFactCompareView(SystemTrackingEnforcementMixin, SubDetailAPIView):
|
|||||||
return Response(self.serializer_class(instance=fact_entry).data)
|
return Response(self.serializer_class(instance=fact_entry).data)
|
||||||
|
|
||||||
|
|
||||||
class HostFactsLatestList(SubListAPIView):
|
|
||||||
|
|
||||||
model = FactLatest
|
|
||||||
parent_model = Host
|
|
||||||
relationship = 'facts_latest'
|
|
||||||
serializer_class = FactSerializer
|
|
||||||
new_in_320 = True
|
|
||||||
|
|
||||||
|
|
||||||
class GroupList(ListCreateAPIView):
|
class GroupList(ListCreateAPIView):
|
||||||
|
|
||||||
model = Group
|
model = Group
|
||||||
|
|||||||
@@ -2274,14 +2274,6 @@ class RoleAccess(BaseAccess):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class FactLatestAccess(BaseAccess):
|
|
||||||
|
|
||||||
model = FactLatest
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return FactLatest.objects.distinct()
|
|
||||||
|
|
||||||
|
|
||||||
register_access(User, UserAccess)
|
register_access(User, UserAccess)
|
||||||
register_access(Organization, OrganizationAccess)
|
register_access(Organization, OrganizationAccess)
|
||||||
register_access(Inventory, InventoryAccess)
|
register_access(Inventory, InventoryAccess)
|
||||||
@@ -2314,4 +2306,3 @@ register_access(WorkflowJobTemplateNode, WorkflowJobTemplateNodeAccess)
|
|||||||
register_access(WorkflowJobNode, WorkflowJobNodeAccess)
|
register_access(WorkflowJobNode, WorkflowJobNodeAccess)
|
||||||
register_access(WorkflowJobTemplate, WorkflowJobTemplateAccess)
|
register_access(WorkflowJobTemplate, WorkflowJobTemplateAccess)
|
||||||
register_access(WorkflowJob, WorkflowJobAccess)
|
register_access(WorkflowJob, WorkflowJobAccess)
|
||||||
register_access(FactLatest, FactLatestAccess)
|
|
||||||
|
|||||||
@@ -2,14 +2,15 @@
|
|||||||
# Python
|
# Python
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
# Psycopg2
|
||||||
|
from psycopg2.extensions import AsIs
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
from psycopg2.extensions import AsIs
|
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
import awx.main.fields
|
import awx.main.fields
|
||||||
from awx.main.models import FactLatest
|
from awx.main.models import Host
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@@ -36,27 +37,18 @@ class Migration(migrations.Migration):
|
|||||||
field=models.ForeignKey(related_name='inventory_sources', default=None, to='main.Inventory', null=True),
|
field=models.ForeignKey(related_name='inventory_sources', default=None, to='main.Inventory', null=True),
|
||||||
),
|
),
|
||||||
|
|
||||||
# Facts Latest
|
# Facts
|
||||||
migrations.CreateModel(
|
|
||||||
name='FactLatest',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
|
||||||
('timestamp', models.DateTimeField(default=None, help_text='Date and time of the corresponding fact scan gathering time.', editable=False)),
|
|
||||||
('module', models.CharField(max_length=128)),
|
|
||||||
('facts', awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True)),
|
|
||||||
('host', models.ForeignKey(related_name='facts_latest', to='main.Host', help_text='Host for the facts that the fact scan captured.')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='fact',
|
model_name='fact',
|
||||||
name='facts',
|
name='facts',
|
||||||
field=awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True),
|
field=awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True),
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
migrations.AddField(
|
||||||
name='factlatest',
|
model_name='host',
|
||||||
index_together=set([('timestamp', 'module', 'host')]),
|
name='ansible_facts',
|
||||||
|
field=awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of most recent ansible_facts, per-host.', blank=True),
|
||||||
),
|
),
|
||||||
migrations.RunSQL([("CREATE INDEX fact_latest_facts_default_gin ON %s USING gin"
|
migrations.RunSQL([("CREATE INDEX host_ansible_facts_default_gin ON %s USING gin"
|
||||||
"(facts jsonb_path_ops);", [AsIs(FactLatest._meta.db_table)])],
|
"(ansible_facts jsonb_path_ops);", [AsIs(Host._meta.db_table)])],
|
||||||
[('DROP INDEX fact_latest_facts_default_gin;', None)]),
|
[('DROP INDEX host_ansible_facts_default_gin;', None)]),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,43 +1,17 @@
|
|||||||
# Copyright (c) 2016 Ansible, Inc.
|
# Copyright (c) 2016 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from awx.main.fields import JSONBField
|
from awx.main.fields import JSONBField
|
||||||
|
from awx.main.models import Host
|
||||||
|
|
||||||
__all__ = ('Fact', 'FactLatest')
|
__all__ = ('Fact',)
|
||||||
|
|
||||||
|
logger = logging.getLogger('awx.main.models.fact')
|
||||||
class FactLatest(models.Model):
|
|
||||||
host = models.ForeignKey(
|
|
||||||
'Host',
|
|
||||||
related_name='facts_latest',
|
|
||||||
db_index=True,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
help_text=_('Host for the facts that the fact scan captured.'),
|
|
||||||
)
|
|
||||||
timestamp = models.DateTimeField(
|
|
||||||
default=None,
|
|
||||||
editable=False,
|
|
||||||
help_text=_('Date and time of the corresponding fact scan gathering time.')
|
|
||||||
)
|
|
||||||
module = models.CharField(max_length=128)
|
|
||||||
facts = JSONBField(blank=True, default={}, help_text=_('Arbitrary JSON structure of module facts captured at timestamp for a single host.'))
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
app_label = 'main'
|
|
||||||
index_together = [
|
|
||||||
["timestamp", "module", "host"],
|
|
||||||
]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def add_fact(host_id, module, timestamp, facts):
|
|
||||||
qs = FactLatest.objects.filter(host_id=host_id, module=module)
|
|
||||||
qs.delete()
|
|
||||||
|
|
||||||
fact_obj = FactLatest.objects.create(host_id=host_id, module=module, timestamp=timestamp, facts=facts)
|
|
||||||
return fact_obj
|
|
||||||
|
|
||||||
|
|
||||||
class Fact(models.Model):
|
class Fact(models.Model):
|
||||||
@@ -91,7 +65,13 @@ class Fact(models.Model):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_fact(host_id, module, timestamp, facts):
|
def add_fact(host_id, module, timestamp, facts):
|
||||||
FactLatest.add_fact(host_id=host_id, module=module, timestamp=timestamp, facts=facts)
|
try:
|
||||||
|
host = Host.objects.get(id=host_id)
|
||||||
|
except Host.DoesNotExist as e:
|
||||||
|
logger.warn("Host with id %s not found while trying to update latest fact set." % host_id)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
host.update_ansible_facts(module=module, facts=facts, timestamp=timestamp)
|
||||||
|
|
||||||
fact_obj = Fact.objects.create(host_id=host_id, module=module, timestamp=timestamp, facts=facts)
|
fact_obj = Fact.objects.create(host_id=host_id, module=module, timestamp=timestamp, facts=facts)
|
||||||
fact_obj.save()
|
fact_obj.save()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from django.utils.timezone import now
|
|||||||
# AWX
|
# AWX
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.constants import CLOUD_PROVIDERS
|
from awx.main.constants import CLOUD_PROVIDERS
|
||||||
from awx.main.fields import ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField, JSONBField
|
||||||
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
|
||||||
from awx.main.models.unified_jobs import * # noqa
|
from awx.main.models.unified_jobs import * # noqa
|
||||||
@@ -382,6 +382,11 @@ class Host(CommonModelNameNotUnique):
|
|||||||
editable=False,
|
editable=False,
|
||||||
help_text=_('Inventory source(s) that created or modified this host.'),
|
help_text=_('Inventory source(s) that created or modified this host.'),
|
||||||
)
|
)
|
||||||
|
ansible_facts = JSONBField(
|
||||||
|
blank=True,
|
||||||
|
default={},
|
||||||
|
help_text=_('Arbitrary JSON structure of most recent ansible_facts, per-host.'),
|
||||||
|
)
|
||||||
|
|
||||||
objects = HostManager()
|
objects = HostManager()
|
||||||
|
|
||||||
@@ -444,6 +449,16 @@ class Host(CommonModelNameNotUnique):
|
|||||||
# Use .job_host_summaries.all() to get jobs affecting this host.
|
# Use .job_host_summaries.all() to get jobs affecting this host.
|
||||||
# Use .job_events.all() to get events affecting this host.
|
# Use .job_events.all() to get events affecting this host.
|
||||||
|
|
||||||
|
'''
|
||||||
|
We don't use timestamp, but we may in the future.
|
||||||
|
'''
|
||||||
|
def update_ansible_facts(self, module, facts, timestamp=None):
|
||||||
|
if module == "ansible":
|
||||||
|
self.ansible_facts.update(facts)
|
||||||
|
else:
|
||||||
|
self.ansible_facts[module] = facts
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
class Group(CommonModelNameNotUnique):
|
class Group(CommonModelNameNotUnique):
|
||||||
'''
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user