mirror of
https://github.com/ansible/awx.git
synced 2024-10-27 17:55:10 +03:00
Add smart_inventories endpoint to Host
This commit is contained in:
parent
5232b70897
commit
e28cd97ffb
@ -1204,6 +1204,7 @@ class HostSerializer(BaseSerializerWithVariables):
|
||||
job_host_summaries = self.reverse('api:host_job_host_summaries_list', kwargs={'pk': obj.pk}),
|
||||
activity_stream = self.reverse('api:host_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||
inventory_sources = self.reverse('api:host_inventory_sources_list', kwargs={'pk': obj.pk}),
|
||||
smart_inventories = self.reverse('api:host_smart_inventories_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}),
|
||||
fact_versions = self.reverse('api:host_fact_versions_list', kwargs={'pk': obj.pk}),
|
||||
|
@ -115,6 +115,7 @@ host_urls = patterns('awx.api.views',
|
||||
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'host_job_host_summaries_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'host_activity_stream_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'host_inventory_sources_list'),
|
||||
url(r'^(?P<pk>[0-9]+)/smart_inventories/$', 'host_smart_inventories_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]+)/single_fact/$', 'host_single_fact_view'),
|
||||
|
@ -58,7 +58,7 @@ import ansiconv
|
||||
from social.backends.utils import load_backends
|
||||
|
||||
# AWX
|
||||
from awx.main.tasks import send_notifications
|
||||
from awx.main.tasks import send_notifications, update_host_smart_inventory_memberships
|
||||
from awx.main.access import get_user_queryset
|
||||
from awx.main.ha import is_ha_environment
|
||||
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
|
||||
@ -2006,6 +2006,22 @@ class HostInventorySourcesList(SubListAPIView):
|
||||
new_in_148 = True
|
||||
|
||||
|
||||
class HostSmartInventoriesList(SubListAPIView):
|
||||
model = Inventory
|
||||
serializer_class = InventorySerializer
|
||||
parent_model = Host
|
||||
relationship = 'smart_inventories'
|
||||
new_in_320 = True
|
||||
|
||||
def list(self, *args, **kwargs):
|
||||
try:
|
||||
if settings.AWX_REBUILD_SMART_MEMBERSHIP:
|
||||
update_host_smart_inventory_memberships.delay()
|
||||
return super(HostSmartInventoriesList, self).list(*args, **kwargs)
|
||||
except Exception as e:
|
||||
return Response(dict(error=_(unicode(e))), status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class HostActivityStreamList(ActivityStreamEnforcementMixin, SubListAPIView):
|
||||
|
||||
model = ActivityStream
|
||||
|
@ -36,6 +36,8 @@ class Migration(migrations.Migration):
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='inventory_sources', default=None, to='main.Inventory', null=True),
|
||||
),
|
||||
|
||||
# Smart Inventory
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='host_filter',
|
||||
@ -44,7 +46,28 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='kind',
|
||||
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.')]),
|
||||
field=models.CharField(default=b'', help_text='Kind of inventory being represented.', max_length=32, blank=True, choices=[(b'', 'Hosts have a direct link to this inventory.'), (b'smart', 'Hosts for inventory generated using the host_filter property.')]),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SmartInventoryMembership',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('host', models.ForeignKey(related_name='+', to='main.Host')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='smartinventorymembership',
|
||||
name='inventory',
|
||||
field=models.ForeignKey(related_name='+', to='main.Inventory'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='host',
|
||||
name='smart_inventories',
|
||||
field=models.ManyToManyField(related_name='_host_smart_inventories_+', through='main.SmartInventoryMembership', to='main.Inventory'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='smartinventorymembership',
|
||||
unique_together=set([('host', 'inventory')]),
|
||||
),
|
||||
|
||||
# Facts
|
||||
|
@ -36,7 +36,8 @@ from awx.main.models.notifications import (
|
||||
)
|
||||
from awx.main.utils import _inventory_updates
|
||||
|
||||
__all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'CustomInventoryScript']
|
||||
__all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate',
|
||||
'CustomInventoryScript', 'SmartInventoryMembership']
|
||||
|
||||
logger = logging.getLogger('awx.main.models.inventory')
|
||||
|
||||
@ -346,6 +347,19 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin):
|
||||
return self.groups.exclude(parents__pk__in=group_pks).distinct()
|
||||
|
||||
|
||||
class SmartInventoryMembership(BaseModel):
|
||||
'''
|
||||
A lookup table for Host membership in Smart Inventory
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
app_label = 'main'
|
||||
unique_together = (('host', 'inventory'),)
|
||||
|
||||
inventory = models.ForeignKey('Inventory', related_name='+', on_delete=models.CASCADE)
|
||||
host = models.ForeignKey('Host', related_name='+', on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class Host(CommonModelNameNotUnique):
|
||||
'''
|
||||
A managed node
|
||||
@ -361,6 +375,11 @@ class Host(CommonModelNameNotUnique):
|
||||
related_name='hosts',
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
smart_inventories = models.ManyToManyField(
|
||||
'Inventory',
|
||||
related_name='+',
|
||||
through='SmartInventoryMembership',
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
default=True,
|
||||
help_text=_('Is this host online and available for running jobs?'),
|
||||
|
@ -38,7 +38,7 @@ from celery.signals import celeryd_init, worker_process_init
|
||||
|
||||
# Django
|
||||
from django.conf import settings
|
||||
from django.db import transaction, DatabaseError
|
||||
from django.db import transaction, DatabaseError, IntegrityError
|
||||
from django.utils.timezone import now
|
||||
from django.utils.encoding import smart_str
|
||||
from django.core.mail import send_mail
|
||||
@ -62,8 +62,8 @@ from awx.main.utils.handlers import configure_external_logger
|
||||
from awx.main.consumers import emit_channel_notification
|
||||
|
||||
__all__ = ['RunJob', 'RunSystemJob', 'RunProjectUpdate', 'RunInventoryUpdate',
|
||||
'RunAdHocCommand', 'handle_work_error',
|
||||
'handle_work_success', 'update_inventory_computed_fields',
|
||||
'RunAdHocCommand', 'handle_work_error', 'handle_work_success',
|
||||
'update_inventory_computed_fields', 'update_host_smart_inventory_memberships',
|
||||
'send_notifications', 'run_administrative_checks', 'purge_old_stdout_files']
|
||||
|
||||
HIDDEN_PASSWORD = '**********'
|
||||
@ -321,6 +321,22 @@ def update_inventory_computed_fields(inventory_id, should_update_hosts=True):
|
||||
i.update_computed_fields(update_hosts=should_update_hosts)
|
||||
|
||||
|
||||
@task(queue='tower')
|
||||
def update_host_smart_inventory_memberships():
|
||||
try:
|
||||
with transaction.atomic():
|
||||
smart_inventories = Inventory.objects.filter(kind='smart', host_filter__isnull=False)
|
||||
SmartInventoryMembership.objects.all().delete()
|
||||
memberships = []
|
||||
for smart_inventory in smart_inventories:
|
||||
memberships.extend([SmartInventoryMembership(inventory_id=smart_inventory.id, host_id=host_id[0])
|
||||
for host_id in smart_inventory.hosts.values_list('id')])
|
||||
SmartInventoryMembership.objects.bulk_create(memberships)
|
||||
except IntegrityError as e:
|
||||
logger.error("Update Host Smart Inventory Memberships failed due to an exception: " + str(e))
|
||||
return
|
||||
|
||||
|
||||
class BaseTask(Task):
|
||||
name = None
|
||||
model = None
|
||||
|
@ -568,6 +568,9 @@ AWX_TASK_ENV = {}
|
||||
# Flag to enable/disable updating hosts M2M when saving job events.
|
||||
CAPTURE_JOB_EVENT_HOSTS = False
|
||||
|
||||
# Rebuild Host Smart Inventory memberships.
|
||||
AWX_REBUILD_SMART_MEMBERSHIP = False
|
||||
|
||||
# Enable bubblewrap support for running jobs (playbook runs only).
|
||||
# Note: This setting may be overridden by database settings.
|
||||
AWX_PROOT_ENABLED = True
|
||||
|
@ -23,10 +23,16 @@ in our _Smart Search_.
|
||||
* The `Inventory` model has a new field called `kind`. The default of this field will be blank
|
||||
for normal inventories and set to `smart` for smart inventories.
|
||||
|
||||
* `Inventory` model as a new field called `host_filter`. The default of this field will be blank
|
||||
* `Inventory` model has a new field called `host_filter`. The default of this field will be blank
|
||||
for normal inventories. When `host_filter` is set AND the inventory `kind` is set to `smart`
|
||||
is the combination that makes a _Smart Inventory_.
|
||||
|
||||
* `Host` model has a new field called `smart_inventories`. This field uses the `SmartInventoryMemberships`
|
||||
lookup table to provide a set of all of the _Smart Inventory_ a host is a part of. The memberships
|
||||
or generated by the `update_host_smart_inventory_memberships` task. This task is called when the view for
|
||||
`/api/v2/hosts/:id/smart_inventories` is materialized. NOTE: This task is only run if the
|
||||
`AWX_REBUILD_SMART_MEMBERSHIP` is set to True. It defaults to False.
|
||||
|
||||
### Smart Filter (host_filter)
|
||||
The `SmartFilter` class handles our translation of the smart search string. We store the
|
||||
filter value in the `host_filter` field for an inventory. This value should be expressed
|
||||
|
Loading…
Reference in New Issue
Block a user