diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 7246cb1745..39ef37e829 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -2192,6 +2192,19 @@ class CredentialSerializer(BaseSerializer): _('You cannot change the credential type of the credential, as it may break the functionality' ' of the resources using it.'), ) + + # TODO: When this code lands in awx, these relationships won't exist + # anymore, so we need to remove this code and make sure the related + # tests still pass. + for cls in (JobTemplate, Job): + for rel in ('extra_credentials__id', 'vault_credential_id'): + if cls.objects.filter(**{ + rel: self.instance.pk + }).count() > 0: + raise ValidationError( + _('You cannot change the credential type of the credential, as it may break the functionality' + ' of the resources using it.'), + ) return credential_type diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index e26447deea..60aa1dfd28 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -1480,6 +1480,105 @@ def test_credential_type_mutability(patch, organization, admin, credentialtype_s assert response.status_code == 200 +@pytest.mark.django_db +def test_vault_credential_type_mutability(patch, organization, admin, credentialtype_ssh, + credentialtype_vault): + cred = Credential( + credential_type=credentialtype_vault, + name='Best credential ever', + organization=organization, + inputs={ + 'vault_password': u'some-vault', + } + ) + cred.save() + + jt = JobTemplate(vault_credential=cred) + jt.save() + + def _change_credential_type(): + return patch( + reverse('api:credential_detail', kwargs={'version': 'v2', 'pk': cred.pk}), + { + 'credential_type': credentialtype_ssh.pk, + 'inputs': { + 'username': u'jim', + 'password': u'pass' + } + }, + admin + ) + + response = _change_credential_type() + assert response.status_code == 400 + expected = ['You cannot change the credential type of the credential, ' + 'as it may break the functionality of the resources using it.'] + assert response.data['credential_type'] == expected + + response = patch( + reverse('api:credential_detail', kwargs={'version': 'v2', 'pk': cred.pk}), + {'name': 'Worst credential ever'}, + admin + ) + assert response.status_code == 200 + assert Credential.objects.get(pk=cred.pk).name == 'Worst credential ever' + + jt.delete() + response = _change_credential_type() + assert response.status_code == 200 + + +@pytest.mark.django_db +def test_cloud_credential_type_mutability(patch, organization, admin, credentialtype_ssh, + credentialtype_aws): + cred = Credential( + credential_type=credentialtype_aws, + name='Best credential ever', + organization=organization, + inputs={ + 'username': u'jim', + 'password': u'pass' + } + ) + cred.save() + + jt = JobTemplate() + jt.save() + jt.extra_credentials.add(cred) + jt.save() + + def _change_credential_type(): + return patch( + reverse('api:credential_detail', kwargs={'version': 'v2', 'pk': cred.pk}), + { + 'credential_type': credentialtype_ssh.pk, + 'inputs': { + 'username': u'jim', + 'password': u'pass' + } + }, + admin + ) + + response = _change_credential_type() + assert response.status_code == 400 + expected = ['You cannot change the credential type of the credential, ' + 'as it may break the functionality of the resources using it.'] + assert response.data['credential_type'] == expected + + response = patch( + reverse('api:credential_detail', kwargs={'version': 'v2', 'pk': cred.pk}), + {'name': 'Worst credential ever'}, + admin + ) + assert response.status_code == 200 + assert Credential.objects.get(pk=cred.pk).name == 'Worst credential ever' + + jt.delete() + response = _change_credential_type() + assert response.status_code == 200 + + @pytest.mark.django_db @pytest.mark.parametrize('version, params', [ ['v1', {