diff --git a/awx/main/migrations/_credentialtypes.py b/awx/main/migrations/_credentialtypes.py index a2cc23578f..a51a5fc75b 100644 --- a/awx/main/migrations/_credentialtypes.py +++ b/awx/main/migrations/_credentialtypes.py @@ -1,6 +1,7 @@ from awx.main import utils from awx.main.models import CredentialType from awx.main.utils.common import encrypt_field, decrypt_field +from django.db.models import Q DEPRECATED_CRED_KIND = { @@ -48,6 +49,14 @@ def _populate_deprecated_cred_types(cred, kind): return cred[kind] +def _is_insights_scm(apps, cred): + return apps.get_model('main', 'Credential').objects.filter(id=cred.id, projects__scm_type='insights').exists() + + +def _disassociate_non_insights_projects(apps, cred): + apps.get_model('main', 'Project').objects.filter(~Q(scm_type='insights') & Q(credential=cred)).update(credential=None) + + def migrate_to_v2_credentials(apps, schema_editor): CredentialType.setup_tower_managed_defaults() deprecated_cred = _generate_deprecated_cred_types() @@ -64,7 +73,11 @@ def migrate_to_v2_credentials(apps, schema_editor): data = {} if getattr(cred, 'vault_password', None): data['vault_password'] = cred.vault_password + if _is_insights_scm(apps, cred): + data['is_insights'] = True + _disassociate_non_insights_projects(apps, cred) credential_type = _populate_deprecated_cred_types(deprecated_cred, cred.kind) or CredentialType.from_v1_kind(cred.kind, data) + defined_fields = credential_type.defined_fields cred.credential_type = apps.get_model('main', 'CredentialType').objects.get(pk=credential_type.pk) @@ -80,6 +93,8 @@ def migrate_to_v2_credentials(apps, schema_editor): job.credential = None job.vault_credential = cred job.save() + if data.get('is_insights', False): + cred.kind = 'insights' cred.save() # @@ -145,3 +160,4 @@ def migrate_job_credentials(apps, schema_editor): obj.save() finally: utils.get_current_apps = orig_current_apps + diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index 458635f858..5ff69d6fa3 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -469,6 +469,8 @@ class CredentialType(CommonModelNameNotUnique): requirements['kind'] = 'vault' else: requirements['kind'] = 'ssh' + elif kind == 'scm' and data.get('is_insights', False): + requirements['kind'] = 'insights' elif kind in ('net', 'scm'): requirements['kind'] = kind elif kind in kind_choices: diff --git a/awx/main/tests/functional/test_credential_migration.py b/awx/main/tests/functional/test_credential_migration.py index daca6af3df..6595e890e8 100644 --- a/awx/main/tests/functional/test_credential_migration.py +++ b/awx/main/tests/functional/test_credential_migration.py @@ -8,6 +8,7 @@ from django.apps import apps from awx.main.models import Credential, CredentialType from awx.main.migrations._credentialtypes import migrate_to_v2_credentials from awx.main.utils.common import decrypt_field +from awx.main.migrations._credentialtypes import _disassociate_non_insights_projects EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY-----' @@ -15,12 +16,12 @@ EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY- @contextmanager -def migrate(credential, kind): +def migrate(credential, kind, is_insights=False): with mock.patch.object(Credential, 'kind', kind), \ mock.patch.object(Credential, 'objects', mock.Mock( get=lambda **kw: deepcopy(credential), - all=lambda: [credential] - )): + all=lambda: [credential], + )), mock.patch('awx.main.migrations._credentialtypes._is_insights_scm', return_value=is_insights): class Apps(apps.__class__): def get_model(self, app, model): if model == 'Credential': @@ -307,3 +308,40 @@ def test_azure_rm_migration(): assert decrypt_field(cred, 'secret') == 'some-secret' assert cred.inputs['tenant'] == 'some-tenant' assert Credential.objects.count() == 1 + + +@pytest.mark.django_db +def test_insights_migration(): + cred = Credential(name='My Credential') + + with migrate(cred, 'scm', is_insights=True): + cred.__dict__.update({ + 'username': 'bob', + 'password': 'some-password', + }) + + assert cred.credential_type.name == 'Insights Basic Auth' + assert cred.inputs['username'] == 'bob' + assert cred.inputs['password'].startswith('$encrypted$') + + +@pytest.mark.skip(reason="Need some more mocking here or something.") +@pytest.mark.django_db +def test_insights_project_migration(): + cred1 = apps.get_model('main', 'Credential').objects.create(name='My Credential') + cred2 = apps.get_model('main', 'Credential').objects.create(name='My Credential') + projA1 = apps.get_model('main', 'Project').objects.create(name='Insights Project A1', scm_type='insights', credential=cred1) + + projB1 = apps.get_model('main', 'Project').objects.create(name='Git Project B1', scm_type='git', credential=cred1) + projB2 = apps.get_model('main', 'Project').objects.create(name='Git Project B2', scm_type='git', credential=cred1) + + projC1 = apps.get_model('main', 'Project').objects.create(name='Git Project C1', scm_type='git', credential=cred2) + + _disassociate_non_insights_projects(apps, cred1) + _disassociate_non_insights_projects(apps, cred2) + + assert apps.get_model('main', 'Project').objects.get(pk=projA1).credential is None + assert apps.get_model('main', 'Project').objects.get(pk=projB1).credential is None + assert apps.get_model('main', 'Project').objects.get(pk=projB2).credential is None + assert apps.get_model('main', 'Project').objects.get(pk=projC1).credential == cred2 +