mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
Initial removal of InventorySource.group
This commit is contained in:
@@ -1270,8 +1270,6 @@ class GroupSerializer(BaseSerializerWithVariables):
|
|||||||
))
|
))
|
||||||
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})
|
||||||
if obj.inventory_source:
|
|
||||||
res['inventory_source'] = self.reverse('api:inventory_source_detail', kwargs={'pk': obj.inventory_source.pk})
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_name(self, value):
|
def validate_name(self, value):
|
||||||
@@ -1432,10 +1430,10 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventorySource
|
model = InventorySource
|
||||||
fields = ('*', 'inventory', 'group', 'update_on_launch',
|
fields = ('*', 'inventory', 'update_on_launch',
|
||||||
'update_cache_timeout') + \
|
'update_cache_timeout') + \
|
||||||
('last_update_failed', 'last_updated') # Backwards compatibility.
|
('last_update_failed', 'last_updated') # Backwards compatibility.
|
||||||
read_only_fields = ('*', 'name', 'inventory', 'group')
|
read_only_fields = ('*', 'name', 'inventory')
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = super(InventorySourceSerializer, self).get_related(obj)
|
res = super(InventorySourceSerializer, self).get_related(obj)
|
||||||
|
|||||||
@@ -346,10 +346,6 @@ class BaseAccess(object):
|
|||||||
elif display_method == 'copy' and isinstance(obj, WorkflowJobTemplate) and obj.organization_id is None:
|
elif display_method == 'copy' and isinstance(obj, WorkflowJobTemplate) and obj.organization_id is None:
|
||||||
user_capabilities[display_method] = self.user.is_superuser
|
user_capabilities[display_method] = self.user.is_superuser
|
||||||
continue
|
continue
|
||||||
elif display_method in ['start', 'schedule'] and isinstance(obj, Group):
|
|
||||||
if obj.inventory_source and not obj.inventory_source._can_update():
|
|
||||||
user_capabilities[display_method] = False
|
|
||||||
continue
|
|
||||||
elif display_method in ['start', 'schedule'] and isinstance(obj, (Project)):
|
elif display_method in ['start', 'schedule'] and isinstance(obj, (Project)):
|
||||||
if obj.scm_type == '':
|
if obj.scm_type == '':
|
||||||
user_capabilities[display_method] = False
|
user_capabilities[display_method] = False
|
||||||
@@ -725,9 +721,8 @@ class GroupAccess(BaseAccess):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def can_start(self, obj, validate_license=True):
|
def can_start(self, obj, validate_license=True):
|
||||||
# Used as another alias to inventory_source start access for user_capabilities
|
if obj and obj.inventory:
|
||||||
if obj and obj.inventory_source:
|
return self.user.can_access(Inventory, 'start', obj.inventory, validate_license=validate_license)
|
||||||
return self.user.can_access(InventorySource, 'start', obj.inventory_source, validate_license=validate_license)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -747,9 +742,7 @@ class InventorySourceAccess(BaseAccess):
|
|||||||
Q(group__inventory_id__in=inventory_ids))
|
Q(group__inventory_id__in=inventory_ids))
|
||||||
|
|
||||||
def can_read(self, obj):
|
def can_read(self, obj):
|
||||||
if obj and obj.group:
|
if obj and obj.inventory:
|
||||||
return self.user.can_access(Group, 'read', obj.group)
|
|
||||||
elif obj and obj.inventory:
|
|
||||||
return self.user.can_access(Inventory, 'read', obj.inventory)
|
return self.user.can_access(Inventory, 'read', obj.inventory)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -760,9 +753,9 @@ class InventorySourceAccess(BaseAccess):
|
|||||||
|
|
||||||
def can_change(self, obj, data):
|
def can_change(self, obj, data):
|
||||||
# Checks for admin or change permission on group.
|
# Checks for admin or change permission on group.
|
||||||
if obj and obj.group:
|
if obj and obj.inventory:
|
||||||
return (
|
return (
|
||||||
self.user.can_access(Group, 'change', obj.group, None) and
|
self.user.can_access(Inventory, 'change', obj.inventory, None) and
|
||||||
self.check_related('credential', Credential, data, obj=obj, role_field='use_role')
|
self.check_related('credential', Credential, data, obj=obj, role_field='use_role')
|
||||||
)
|
)
|
||||||
# Can't change inventory sources attached to only the inventory, since
|
# Can't change inventory sources attached to only the inventory, since
|
||||||
@@ -771,9 +764,7 @@ class InventorySourceAccess(BaseAccess):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def can_start(self, obj, validate_license=True):
|
def can_start(self, obj, validate_license=True):
|
||||||
if obj and obj.group:
|
if obj and obj.inventory:
|
||||||
return obj.can_update and self.user in obj.group.inventory.update_role
|
|
||||||
elif obj and obj.inventory:
|
|
||||||
return obj.can_update and self.user in obj.inventory.update_role
|
return obj.can_update and self.user in obj.inventory.update_role
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Python
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
# Django
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
from psycopg2.extensions import AsIs
|
|
||||||
|
|
||||||
# AWX
|
|
||||||
import awx.main.fields
|
|
||||||
from awx.main.models import FactLatest
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('main', '0036_v311_insights'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
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(
|
|
||||||
model_name='fact',
|
|
||||||
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),
|
|
||||||
),
|
|
||||||
migrations.AlterIndexTogether(
|
|
||||||
name='factlatest',
|
|
||||||
index_together=set([('timestamp', 'module', 'host')]),
|
|
||||||
),
|
|
||||||
migrations.RunSQL([("CREATE INDEX fact_latest_facts_default_gin ON %s USING gin"
|
|
||||||
"(facts jsonb_path_ops);", [AsIs(FactLatest._meta.db_table)])],
|
|
||||||
[('DROP INDEX fact_latest_facts_default_gin;', None)]),
|
|
||||||
]
|
|
||||||
18
awx/main/migrations/0037_v320_release.py
Normal file
18
awx/main/migrations/0037_v320_release.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0036_v311_insights'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventorysource',
|
||||||
|
name='group',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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 AutoOneToOneField, ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField
|
||||||
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
|
||||||
@@ -1063,14 +1063,6 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
|
|||||||
editable=False,
|
editable=False,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
group = AutoOneToOneField(
|
|
||||||
'Group',
|
|
||||||
related_name='inventory_source',
|
|
||||||
null=True,
|
|
||||||
default=None,
|
|
||||||
editable=False,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
)
|
|
||||||
update_on_launch = models.BooleanField(
|
update_on_launch = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
@@ -1092,20 +1084,12 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
|
|||||||
# If update_fields has been specified, add our field names to it,
|
# If update_fields has been specified, add our field names to it,
|
||||||
# if it hasn't been specified, then we're just doing a normal save.
|
# if it hasn't been specified, then we're just doing a normal save.
|
||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
# Update inventory from group (if available).
|
|
||||||
if self.group and not self.inventory:
|
|
||||||
self.inventory = self.group.inventory
|
|
||||||
if 'inventory' not in update_fields:
|
|
||||||
update_fields.append('inventory')
|
|
||||||
# Set name automatically. Include PK (or placeholder) to make sure the names are always unique.
|
# Set name automatically. Include PK (or placeholder) to make sure the names are always unique.
|
||||||
replace_text = '__replace_%s__' % now()
|
replace_text = '__replace_%s__' % now()
|
||||||
old_name_re = re.compile(r'^inventory_source \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*?$')
|
old_name_re = re.compile(r'^inventory_source \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*?$')
|
||||||
if not self.name or old_name_re.match(self.name) or '__replace_' in self.name:
|
if not self.name or old_name_re.match(self.name) or '__replace_' in self.name:
|
||||||
if self.inventory and self.group and self.pk:
|
if self.inventory and self.pk:
|
||||||
self.name = '%s (%s - %s)' % (self.group.name, self.inventory.name, self.pk)
|
|
||||||
elif self.inventory and self.group:
|
|
||||||
self.name = '%s (%s - %s)' % (self.group.name, self.inventory.name, replace_text)
|
|
||||||
elif self.inventory and self.pk:
|
|
||||||
self.name = '%s (%s)' % (self.inventory.name, self.pk)
|
self.name = '%s (%s)' % (self.inventory.name, self.pk)
|
||||||
elif self.inventory:
|
elif self.inventory:
|
||||||
self.name = '%s (%s)' % (self.inventory.name, replace_text)
|
self.name = '%s (%s)' % (self.inventory.name, replace_text)
|
||||||
@@ -1237,10 +1221,7 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin):
|
|||||||
update_fields = kwargs.get('update_fields', [])
|
update_fields = kwargs.get('update_fields', [])
|
||||||
inventory_source = self.inventory_source
|
inventory_source = self.inventory_source
|
||||||
if inventory_source.inventory and self.name == inventory_source.name:
|
if inventory_source.inventory and self.name == inventory_source.name:
|
||||||
if inventory_source.group:
|
self.name = inventory_source.inventory.name
|
||||||
self.name = '%s (%s)' % (inventory_source.group.name, inventory_source.inventory.name)
|
|
||||||
else:
|
|
||||||
self.name = inventory_source.inventory.name
|
|
||||||
if 'name' not in update_fields:
|
if 'name' not in update_fields:
|
||||||
update_fields.append('name')
|
update_fields.append('name')
|
||||||
super(InventoryUpdate, self).save(*args, **kwargs)
|
super(InventoryUpdate, self).save(*args, **kwargs)
|
||||||
|
|||||||
@@ -372,9 +372,6 @@ model_serializer_mapping = {
|
|||||||
|
|
||||||
def activity_stream_create(sender, instance, created, **kwargs):
|
def activity_stream_create(sender, instance, created, **kwargs):
|
||||||
if created and activity_stream_enabled:
|
if created and activity_stream_enabled:
|
||||||
# Skip recording any inventory source directly associated with a group.
|
|
||||||
if isinstance(instance, InventorySource) and instance.group:
|
|
||||||
return
|
|
||||||
object1 = camelcase_to_underscore(instance.__class__.__name__)
|
object1 = camelcase_to_underscore(instance.__class__.__name__)
|
||||||
changes = model_to_dict(instance, model_serializer_mapping)
|
changes = model_to_dict(instance, model_serializer_mapping)
|
||||||
# Special case where Job survey password variables need to be hidden
|
# Special case where Job survey password variables need to be hidden
|
||||||
|
|||||||
@@ -343,7 +343,8 @@ def group(inventory):
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def inventory_source(group, inventory):
|
def inventory_source(group, inventory):
|
||||||
return InventorySource.objects.create(name=group.name, group=group,
|
group.inventory = inventory
|
||||||
|
return InventorySource.objects.create(name=group.name,
|
||||||
inventory=inventory, source='gce')
|
inventory=inventory, source='gce')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import pytest
|
|||||||
|
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.models.notifications import NotificationTemplate, Notification
|
from awx.main.models.notifications import NotificationTemplate, Notification
|
||||||
from awx.main.models.inventory import Inventory, Group
|
from awx.main.models.inventory import Inventory, InventorySource
|
||||||
from awx.main.models.jobs import JobTemplate
|
from awx.main.models.jobs import JobTemplate
|
||||||
|
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ def test_inherited_notification_templates(get, post, user, organization, project
|
|||||||
notification_templates.append(response.data['id'])
|
notification_templates.append(response.data['id'])
|
||||||
i = Inventory.objects.create(name='test', organization=organization)
|
i = Inventory.objects.create(name='test', organization=organization)
|
||||||
i.save()
|
i.save()
|
||||||
g = Group.objects.create(name='test', inventory=i)
|
isrc = InventorySource.objects.create(name='test', inventory=i)
|
||||||
g.save()
|
isrc.save()
|
||||||
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
|
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
|
||||||
jt.save()
|
jt.save()
|
||||||
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
|
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
|
||||||
@@ -99,7 +99,7 @@ def test_inherited_notification_templates(get, post, user, organization, project
|
|||||||
assert response.status_code == 204
|
assert response.status_code == 204
|
||||||
assert len(jt.notification_templates['any']) == 3
|
assert len(jt.notification_templates['any']) == 3
|
||||||
assert len(project.notification_templates['any']) == 2
|
assert len(project.notification_templates['any']) == 2
|
||||||
assert len(g.inventory_source.notification_templates['any']) == 1
|
assert len(isrc.notification_templates['any']) == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
Reference in New Issue
Block a user