make a global "managed by AWX/Tower" Credential to represent Galaxy

This commit is contained in:
Ryan Petrello
2020-08-05 07:57:27 -04:00
parent e5552b547b
commit 011822b1f0
7 changed files with 46 additions and 20 deletions

View File

@@ -2537,10 +2537,11 @@ class CredentialTypeSerializer(BaseSerializer):
class CredentialSerializer(BaseSerializer): class CredentialSerializer(BaseSerializer):
show_capabilities = ['edit', 'delete', 'copy', 'use'] show_capabilities = ['edit', 'delete', 'copy', 'use']
capabilities_prefetch = ['admin', 'use'] capabilities_prefetch = ['admin', 'use']
managed_by_tower = serializers.ReadOnlyField()
class Meta: class Meta:
model = Credential model = Credential
fields = ('*', 'organization', 'credential_type', 'inputs', 'kind', 'cloud', 'kubernetes') fields = ('*', 'organization', 'credential_type', 'managed_by_tower', 'inputs', 'kind', 'cloud', 'kubernetes')
extra_kwargs = { extra_kwargs = {
'credential_type': { 'credential_type': {
'label': _('Credential Type'), 'label': _('Credential Type'),
@@ -2604,6 +2605,13 @@ class CredentialSerializer(BaseSerializer):
return summary_dict return summary_dict
def validate(self, attrs):
if self.instance and self.instance.managed_by_tower:
raise PermissionDenied(
detail=_("Modifications not allowed for managed credentials")
)
return super(CredentialSerializer, self).validate(attrs)
def get_validation_exclusions(self, obj=None): def get_validation_exclusions(self, obj=None):
ret = super(CredentialSerializer, self).get_validation_exclusions(obj) ret = super(CredentialSerializer, self).get_validation_exclusions(obj)
for field in ('credential_type', 'inputs'): for field in ('credential_type', 'inputs'):

View File

@@ -1356,6 +1356,13 @@ class CredentialDetail(RetrieveUpdateDestroyAPIView):
model = models.Credential model = models.Credential
serializer_class = serializers.CredentialSerializer serializer_class = serializers.CredentialSerializer
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.managed_by_tower:
raise PermissionDenied(detail=_("Deletion not allowed for managed credentials"))
return super(CredentialDetail, self).destroy(request, *args, **kwargs)
class CredentialActivityStreamList(SubListAPIView): class CredentialActivityStreamList(SubListAPIView):

View File

@@ -1103,11 +1103,6 @@ class CredentialTypeAccess(BaseAccess):
def can_use(self, obj): def can_use(self, obj):
return True return True
def get_method_capability(self, method, obj, parent_obj):
if obj.managed_by_tower:
return False
return super(CredentialTypeAccess, self).get_method_capability(method, obj, parent_obj)
def filtered_queryset(self): def filtered_queryset(self):
return self.model.objects.all() return self.model.objects.all()
@@ -1182,6 +1177,8 @@ class CredentialAccess(BaseAccess):
def get_user_capabilities(self, obj, **kwargs): def get_user_capabilities(self, obj, **kwargs):
user_capabilities = super(CredentialAccess, self).get_user_capabilities(obj, **kwargs) user_capabilities = super(CredentialAccess, self).get_user_capabilities(obj, **kwargs)
user_capabilities['use'] = self.can_use(obj) user_capabilities['use'] = self.can_use(obj)
if getattr(obj, 'managed_by_tower', False) is True:
user_capabilities['edit'] = user_capabilities['delete'] = False
return user_capabilities return user_capabilities

View File

@@ -42,5 +42,10 @@ class Migration(migrations.Migration):
name='galaxy_credentials', name='galaxy_credentials',
field=awx.main.fields.OrderedManyToManyField(blank=True, related_name='organization_galaxy_credentials', through='main.OrganizationGalaxyCredentialMembership', to='main.Credential'), field=awx.main.fields.OrderedManyToManyField(blank=True, related_name='organization_galaxy_credentials', through='main.OrganizationGalaxyCredentialMembership', to='main.Credential'),
), ),
migrations.AddField(
model_name='credential',
name='managed_by_tower',
field=models.BooleanField(default=False, editable=False),
),
migrations.RunPython(galaxy.migrate_galaxy_settings) migrations.RunPython(galaxy.migrate_galaxy_settings)
] ]

View File

@@ -32,6 +32,18 @@ def migrate_galaxy_settings(apps, schema_editor):
# ...UNLESS this behavior was explicitly disabled via this setting # ...UNLESS this behavior was explicitly disabled via this setting
public_galaxy_enabled = False public_galaxy_enabled = False
public_galaxy_credential = Credential(
created=now(),
modified=now(),
name='Ansible Galaxy',
managed_by_tower=True,
credential_type=galaxy_type,
inputs = {
'url': 'https://galaxy.ansible.com/'
}
)
public_galaxy_credential.save()
for org in Organization.objects.all(): for org in Organization.objects.all():
if private_galaxy_url and private_galaxy_url.value: if private_galaxy_url and private_galaxy_url.value:
# If a setting exists for a private Galaxy URL, make a credential for it # If a setting exists for a private Galaxy URL, make a credential for it
@@ -106,16 +118,5 @@ def migrate_galaxy_settings(apps, schema_editor):
org.galaxy_credentials.add(cred) org.galaxy_credentials.add(cred)
if public_galaxy_enabled: if public_galaxy_enabled:
# If public Galaxy was enabled, make a credential for it # If public Galaxy was enabled, associate it to the org
cred = Credential( org.galaxy_credentials.add(public_galaxy_credential)
created=now(),
modified=now(),
name='Ansible Galaxy',
organization=org,
credential_type=galaxy_type,
inputs = {
'url': 'https://galaxy.ansible.com/'
}
)
cred.save()
org.galaxy_credentials.add(cred)

View File

@@ -96,6 +96,10 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
help_text=_('Specify the type of credential you want to create. Refer ' help_text=_('Specify the type of credential you want to create. Refer '
'to the Ansible Tower documentation for details on each type.') 'to the Ansible Tower documentation for details on each type.')
) )
managed_by_tower = models.BooleanField(
default=False,
editable=False
)
organization = models.ForeignKey( organization = models.ForeignKey(
'Organization', 'Organization',
null=True, null=True,

View File

@@ -4,7 +4,7 @@ from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
import pytest import pytest
from awx.main.models import Organization from awx.main.models import Credential, Organization
from awx.conf.models import Setting from awx.conf.models import Setting
from awx.main.migrations import _galaxy as galaxy from awx.main.migrations import _galaxy as galaxy
@@ -78,6 +78,10 @@ def test_multiple_galaxies():
assert creds[1].name == 'Ansible Galaxy' assert creds[1].name == 'Ansible Galaxy'
assert creds[1].inputs['url'] == 'https://galaxy.ansible.com/' assert creds[1].inputs['url'] == 'https://galaxy.ansible.com/'
public_galaxy_creds = Credential.objects.filter(name='Ansible Galaxy')
assert public_galaxy_creds.count() == 1
assert public_galaxy_creds.first().managed_by_tower is True
@pytest.mark.django_db @pytest.mark.django_db
def test_fallback_galaxies(): def test_fallback_galaxies():