From 83ee39cabdbc38fef01d544b20416787559f6e26 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Wed, 13 Nov 2019 09:26:03 -0500 Subject: [PATCH] remove a number of unnecessary 3.2 migrations --- awx/conf/migrations/0004_v320_reencrypt.py | 6 +- awx/conf/migrations/_reencrypt.py | 54 +------- .../migrations/0007_v320_data_migrations.py | 22 +--- .../0010_v322_add_ovirt4_tower_inventory.py | 2 - .../0011_v322_encrypt_survey_passwords.py | 8 +- .../migrations/0012_v322_update_cred_types.py | 10 +- awx/main/migrations/_azure_credentials.py | 15 --- awx/main/migrations/_credentialtypes.py | 22 ---- awx/main/migrations/_inventory_source.py | 59 --------- awx/main/migrations/_reencrypt.py | 119 +----------------- awx/main/migrations/_scan_jobs.py | 80 ------------ .../test_inventory_source_migration.py | 42 ------- .../functional/test_scan_jobs_migration.py | 100 --------------- 13 files changed, 18 insertions(+), 521 deletions(-) delete mode 100644 awx/main/migrations/_azure_credentials.py delete mode 100644 awx/main/tests/functional/test_scan_jobs_migration.py diff --git a/awx/conf/migrations/0004_v320_reencrypt.py b/awx/conf/migrations/0004_v320_reencrypt.py index 4a68ccd088..99fcd7ffce 100644 --- a/awx/conf/migrations/0004_v320_reencrypt.py +++ b/awx/conf/migrations/0004_v320_reencrypt.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from django.db import migrations -from awx.conf.migrations import _reencrypt class Migration(migrations.Migration): @@ -12,5 +11,8 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(_reencrypt.replace_aesecb_fernet), + # This list is intentionally empty. + # Tower 3.2 included several data migrations that are no longer + # necessary (this list is now empty because Tower 3.2 is past EOL and + # cannot be directly upgraded to modern versions of Tower) ] diff --git a/awx/conf/migrations/_reencrypt.py b/awx/conf/migrations/_reencrypt.py index b45e69bceb..d8f06c0305 100644 --- a/awx/conf/migrations/_reencrypt.py +++ b/awx/conf/migrations/_reencrypt.py @@ -1,30 +1,13 @@ import base64 import hashlib -from django.utils.encoding import smart_str - from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import ECB -from awx.conf import settings_registry - -__all__ = ['replace_aesecb_fernet', 'get_encryption_key', 'encrypt_field', - 'decrypt_value', 'decrypt_value', 'should_decrypt_field'] - - -def replace_aesecb_fernet(apps, schema_editor): - from awx.main.utils.encryption import encrypt_field - Setting = apps.get_model('conf', 'Setting') - - for setting in Setting.objects.filter().order_by('pk'): - if settings_registry.is_setting_encrypted(setting.key): - if should_decrypt_field(setting.value): - setting.value = decrypt_field(setting, 'value') - setting.value = encrypt_field(setting, 'value') - setting.save() +__all__ = ['get_encryption_key', 'decrypt_field'] def get_encryption_key(field_name, pk=None): @@ -76,38 +59,3 @@ def decrypt_field(instance, field_name, subfield=None): key = get_encryption_key(field_name, getattr(instance, 'pk', None)) return decrypt_value(key, value) - - -def encrypt_field(instance, field_name, ask=False, subfield=None, skip_utf8=False): - ''' - Return content of the given instance and field name encrypted. - ''' - value = getattr(instance, field_name) - if isinstance(value, dict) and subfield is not None: - value = value[subfield] - if not value or value.startswith('$encrypted$') or (ask and value == 'ASK'): - return value - if skip_utf8: - utf8 = False - else: - utf8 = type(value) == str - value = smart_str(value) - key = get_encryption_key(field_name, getattr(instance, 'pk', None)) - encryptor = Cipher(AES(key), ECB(), default_backend()).encryptor() - block_size = 16 - while len(value) % block_size != 0: - value += '\x00' - encrypted = encryptor.update(value) + encryptor.finalize() - b64data = base64.b64encode(encrypted) - tokens = ['$encrypted', 'AES', b64data] - if utf8: - # If the value to encrypt is utf-8, we need to add a marker so we - # know to decode the data when it's decrypted later - tokens.insert(1, 'UTF8') - return '$'.join(tokens) - - -def should_decrypt_field(value): - if hasattr(value, 'startswith'): - return value.startswith('$encrypted$') and '$AESCBC$' not in value - return False diff --git a/awx/main/migrations/0007_v320_data_migrations.py b/awx/main/migrations/0007_v320_data_migrations.py index e8ede86ba9..d639c3efb6 100644 --- a/awx/main/migrations/0007_v320_data_migrations.py +++ b/awx/main/migrations/0007_v320_data_migrations.py @@ -7,12 +7,6 @@ from django.db import migrations, models # AWX from awx.main.migrations import ActivityStreamDisabledMigration -from awx.main.migrations import _inventory_source as invsrc -from awx.main.migrations import _migration_utils as migration_utils -from awx.main.migrations import _reencrypt as reencrypt -from awx.main.migrations import _scan_jobs as scan_jobs -from awx.main.migrations import _credentialtypes as credentialtypes -from awx.main.migrations import _azure_credentials as azurecreds import awx.main.fields @@ -23,16 +17,8 @@ class Migration(ActivityStreamDisabledMigration): ] operations = [ - # Inventory Refresh - migrations.RunPython(migration_utils.set_current_apps_for_migrations), - migrations.RunPython(invsrc.remove_rax_inventory_sources), - migrations.RunPython(azurecreds.remove_azure_credentials), - migrations.RunPython(invsrc.remove_azure_inventory_sources), - migrations.RunPython(invsrc.remove_inventory_source_with_no_inventory_link), - migrations.RunPython(invsrc.rename_inventory_sources), - migrations.RunPython(reencrypt.replace_aesecb_fernet), - migrations.RunPython(scan_jobs.migrate_scan_job_templates), - - migrations.RunPython(credentialtypes.migrate_to_v2_credentials), - migrations.RunPython(credentialtypes.migrate_job_credentials), + # This list is intentionally empty. + # Tower 3.2 included several data migrations that are no longer + # necessary (this list is now empty because Tower 3.2 is past EOL and + # cannot be directly upgraded to modern versions of Tower) ] diff --git a/awx/main/migrations/0010_v322_add_ovirt4_tower_inventory.py b/awx/main/migrations/0010_v322_add_ovirt4_tower_inventory.py index ea8b91c7d4..68933162c9 100644 --- a/awx/main/migrations/0010_v322_add_ovirt4_tower_inventory.py +++ b/awx/main/migrations/0010_v322_add_ovirt4_tower_inventory.py @@ -15,8 +15,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(migration_utils.set_current_apps_for_migrations), - migrations.RunPython(credentialtypes.create_rhv_tower_credtype), migrations.AlterField( model_name='inventorysource', name='source', diff --git a/awx/main/migrations/0011_v322_encrypt_survey_passwords.py b/awx/main/migrations/0011_v322_encrypt_survey_passwords.py index 0d797ae5e1..9fe757a9f5 100644 --- a/awx/main/migrations/0011_v322_encrypt_survey_passwords.py +++ b/awx/main/migrations/0011_v322_encrypt_survey_passwords.py @@ -3,8 +3,6 @@ from __future__ import unicode_literals from django.db import migrations from awx.main.migrations import ActivityStreamDisabledMigration -from awx.main.migrations import _reencrypt as reencrypt -from awx.main.migrations import _migration_utils as migration_utils class Migration(ActivityStreamDisabledMigration): @@ -14,6 +12,8 @@ class Migration(ActivityStreamDisabledMigration): ] operations = [ - migrations.RunPython(migration_utils.set_current_apps_for_migrations), - migrations.RunPython(reencrypt.encrypt_survey_passwords), + # This list is intentionally empty. + # Tower 3.2 included several data migrations that are no longer + # necessary (this list is now empty because Tower 3.2 is past EOL and + # cannot be directly upgraded to modern versions of Tower) ] diff --git a/awx/main/migrations/0012_v322_update_cred_types.py b/awx/main/migrations/0012_v322_update_cred_types.py index b1e77fd810..1b3a5ce4a6 100644 --- a/awx/main/migrations/0012_v322_update_cred_types.py +++ b/awx/main/migrations/0012_v322_update_cred_types.py @@ -1,10 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -# AWX -from awx.main.migrations import _migration_utils as migration_utils -from awx.main.migrations import _credentialtypes as credentialtypes - from django.db import migrations @@ -15,6 +11,8 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(migration_utils.set_current_apps_for_migrations), - migrations.RunPython(credentialtypes.add_azure_cloud_environment_field), + # This list is intentionally empty. + # Tower 3.2 included several data migrations that are no longer + # necessary (this list is now empty because Tower 3.2 is past EOL and + # cannot be directly upgraded to modern versions of Tower) ] diff --git a/awx/main/migrations/_azure_credentials.py b/awx/main/migrations/_azure_credentials.py deleted file mode 100644 index 93981ea8f9..0000000000 --- a/awx/main/migrations/_azure_credentials.py +++ /dev/null @@ -1,15 +0,0 @@ -import logging - -from django.db.models import Q - -logger = logging.getLogger('awx.main.migrations') - - -def remove_azure_credentials(apps, schema_editor): - '''Azure is not supported as of 3.2 and greater. Instead, azure_rm is - supported. - ''' - Credential = apps.get_model('main', 'Credential') - logger.debug("Removing all Azure Credentials from database.") - Credential.objects.filter(kind='azure').delete() - diff --git a/awx/main/migrations/_credentialtypes.py b/awx/main/migrations/_credentialtypes.py index d4d1416be5..98eb62c5c4 100644 --- a/awx/main/migrations/_credentialtypes.py +++ b/awx/main/migrations/_credentialtypes.py @@ -1,6 +1,4 @@ -from awx.main import utils from awx.main.models import CredentialType -from awx.main.utils.encryption import encrypt_field, decrypt_field from django.db.models import Q @@ -61,16 +59,6 @@ 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): - # TODO: remove once legacy/EOL'd Towers no longer support this upgrade path - pass - - -def migrate_job_credentials(apps, schema_editor): - # TODO: remove once legacy/EOL'd Towers no longer support this upgrade path - pass - - def add_vault_id_field(apps, schema_editor): # this is no longer necessary; schemas are defined in code pass @@ -81,21 +69,11 @@ def remove_vault_id_field(apps, schema_editor): pass -def create_rhv_tower_credtype(apps, schema_editor): - # this is no longer necessary; schemas are defined in code - pass - - def add_tower_verify_field(apps, schema_editor): # this is no longer necessary; schemas are defined in code pass -def add_azure_cloud_environment_field(apps, schema_editor): - # this is no longer necessary; schemas are defined in code - pass - - def remove_become_methods(apps, schema_editor): # this is no longer necessary; schemas are defined in code pass diff --git a/awx/main/migrations/_inventory_source.py b/awx/main/migrations/_inventory_source.py index 6378a83463..c532ab33f5 100644 --- a/awx/main/migrations/_inventory_source.py +++ b/awx/main/migrations/_inventory_source.py @@ -1,6 +1,5 @@ import logging -from django.db.models import Q from django.utils.encoding import smart_text from awx.main.utils.common import parse_yaml_or_json @@ -8,64 +7,6 @@ from awx.main.utils.common import parse_yaml_or_json logger = logging.getLogger('awx.main.migrations') -def remove_manual_inventory_sources(apps, schema_editor): - '''Previously we would automatically create inventory sources after - Group creation and we would use the parent Group as our interface for the user. - During that process we would create InventorySource that had a source of "manual". - ''' - # TODO: use this in the 3.3 data migrations - InventorySource = apps.get_model('main', 'InventorySource') - # see models/inventory.py SOURCE_CHOICES - ('', _('Manual')) - logger.debug("Removing all Manual InventorySource from database.") - InventorySource.objects.filter(source='').delete() - - -def remove_rax_inventory_sources(apps, schema_editor): - '''Rackspace inventory sources are not supported since 3.2, remove them. - ''' - InventorySource = apps.get_model('main', 'InventorySource') - logger.debug("Removing all Rackspace InventorySource from database.") - InventorySource.objects.filter(source='rax').delete() - - -def rename_inventory_sources(apps, schema_editor): - '''Rename existing InventorySource entries using the following format. - {{ inventory_source.name }} - {{ inventory.module }} - {{ number }} - The number will be incremented for each InventorySource for the organization. - ''' - Organization = apps.get_model('main', 'Organization') - InventorySource = apps.get_model('main', 'InventorySource') - - for org in Organization.objects.iterator(): - for i, invsrc in enumerate(InventorySource.objects.filter(Q(inventory__organization=org) | - Q(deprecated_group__inventory__organization=org)).distinct().all()): - - inventory = invsrc.deprecated_group.inventory if invsrc.deprecated_group else invsrc.inventory - name = '{0} - {1} - {2}'.format(invsrc.name, inventory.name, i) - logger.debug("Renaming InventorySource({0}) {1} -> {2}".format( - invsrc.pk, invsrc.name, name - )) - invsrc.name = name - invsrc.save() - - -def remove_inventory_source_with_no_inventory_link(apps, schema_editor): - '''If we cannot determine the Inventory for which an InventorySource exists - we can safely remove it. - ''' - InventorySource = apps.get_model('main', 'InventorySource') - logger.debug("Removing all InventorySource that have no link to an Inventory from database.") - InventorySource.objects.filter(Q(inventory__organization=None) & Q(deprecated_group__inventory=None)).delete() - - -def remove_azure_inventory_sources(apps, schema_editor): - '''Azure inventory sources are not supported since 3.2, remove them. - ''' - InventorySource = apps.get_model('main', 'InventorySource') - logger.debug("Removing all Azure InventorySource from database.") - InventorySource.objects.filter(source='azure').delete() - - def _get_instance_id(from_dict, new_id, default=''): '''logic mostly duplicated with inventory_import command Command._get_instance_id frozen in time here, for purposes of migrations diff --git a/awx/main/migrations/_reencrypt.py b/awx/main/migrations/_reencrypt.py index 29ebf25a08..1789ee31e3 100644 --- a/awx/main/migrations/_reencrypt.py +++ b/awx/main/migrations/_reencrypt.py @@ -1,79 +1,12 @@ import logging -import json -from django.utils.translation import ugettext_lazy as _ from awx.conf.migrations._reencrypt import ( decrypt_field, - should_decrypt_field, ) -from awx.main.utils.encryption import encrypt_field - -from awx.main.notifications.email_backend import CustomEmailBackend -from awx.main.notifications.slack_backend import SlackBackend -from awx.main.notifications.twilio_backend import TwilioBackend -from awx.main.notifications.pagerduty_backend import PagerDutyBackend -from awx.main.notifications.hipchat_backend import HipChatBackend -from awx.main.notifications.mattermost_backend import MattermostBackend -from awx.main.notifications.webhook_backend import WebhookBackend -from awx.main.notifications.irc_backend import IrcBackend logger = logging.getLogger('awx.main.migrations') -__all__ = ['replace_aesecb_fernet'] - - -NOTIFICATION_TYPES = [('email', _('Email'), CustomEmailBackend), - ('slack', _('Slack'), SlackBackend), - ('twilio', _('Twilio'), TwilioBackend), - ('pagerduty', _('Pagerduty'), PagerDutyBackend), - ('hipchat', _('HipChat'), HipChatBackend), - ('mattermost', _('Mattermost'), MattermostBackend), - ('webhook', _('Webhook'), WebhookBackend), - ('irc', _('IRC'), IrcBackend)] - - -PASSWORD_FIELDS = ('password', 'security_token', 'ssh_key_data', 'ssh_key_unlock', - 'become_password', 'vault_password', 'secret', 'authorize_password') - - -def replace_aesecb_fernet(apps, schema_editor): - _notification_templates(apps) - _credentials(apps) - _unified_jobs(apps) - - -def _notification_templates(apps): - NotificationTemplate = apps.get_model('main', 'NotificationTemplate') - for nt in NotificationTemplate.objects.all(): - CLASS_FOR_NOTIFICATION_TYPE = dict([(x[0], x[2]) for x in NOTIFICATION_TYPES]) - notification_class = CLASS_FOR_NOTIFICATION_TYPE[nt.notification_type] - for field in filter(lambda x: notification_class.init_parameters[x]['type'] == "password", - notification_class.init_parameters): - if should_decrypt_field(nt.notification_configuration[field]): - nt.notification_configuration[field] = decrypt_field(nt, 'notification_configuration', subfield=field) - nt.notification_configuration[field] = encrypt_field(nt, 'notification_configuration', subfield=field) - nt.save() - - -def _credentials(apps): - for credential in apps.get_model('main', 'Credential').objects.all(): - for field_name in PASSWORD_FIELDS: - value = getattr(credential, field_name) - if should_decrypt_field(value): - value = decrypt_field(credential, field_name) - setattr(credential, field_name, value) - setattr(credential, field_name, encrypt_field(credential, field_name)) - credential.save() - - -def _unified_jobs(apps): - UnifiedJob = apps.get_model('main', 'UnifiedJob') - for uj in UnifiedJob.objects.all(): - if uj.start_args is not None: - if should_decrypt_field(uj.start_args): - uj.start_args = decrypt_field(uj, 'start_args') - uj.start_args = encrypt_field(uj, 'start_args') - uj.save() +__all__ = [] def blank_old_start_args(apps, schema_editor): @@ -91,53 +24,3 @@ def blank_old_start_args(apps, schema_editor): logger.debug('Blanking job args for %s', uj.pk) uj.start_args = '' uj.save() - - -def encrypt_survey_passwords(apps, schema_editor): - _encrypt_survey_passwords( - apps.get_model('main', 'Job'), - apps.get_model('main', 'JobTemplate'), - apps.get_model('main', 'WorkflowJob'), - apps.get_model('main', 'WorkflowJobTemplate'), - ) - - -def _encrypt_survey_passwords(Job, JobTemplate, WorkflowJob, WorkflowJobTemplate): - from awx.main.utils.encryption import encrypt_value - for _type in (JobTemplate, WorkflowJobTemplate): - for jt in _type.objects.exclude(survey_spec={}): - changed = False - if jt.survey_spec.get('spec', []): - for field in jt.survey_spec['spec']: - if field.get('type') == 'password' and field.get('default', ''): - default = field['default'] - if default.startswith('$encrypted$'): - if default == '$encrypted$': - # If you have a survey_spec with a literal - # '$encrypted$' as the default, you have - # encountered a known bug in awx/Tower - # https://github.com/ansible/ansible-tower/issues/7800 - logger.error( - '{}.pk={} survey_spec has ambiguous $encrypted$ default for {}, needs attention...'.format(jt, jt.pk, field['variable']) - ) - field['default'] = '' - changed = True - continue - field['default'] = encrypt_value(field['default'], pk=None) - changed = True - if changed: - jt.save() - - for _type in (Job, WorkflowJob): - for job in _type.objects.defer('result_stdout_text').exclude(survey_passwords={}).iterator(): - changed = False - for key in job.survey_passwords: - if key in job.extra_vars: - extra_vars = json.loads(job.extra_vars) - if not extra_vars.get(key, '') or extra_vars[key].startswith('$encrypted$'): - continue - extra_vars[key] = encrypt_value(extra_vars[key], pk=None) - job.extra_vars = json.dumps(extra_vars) - changed = True - if changed: - job.save() diff --git a/awx/main/migrations/_scan_jobs.py b/awx/main/migrations/_scan_jobs.py index 5b96f79599..994297bbcb 100644 --- a/awx/main/migrations/_scan_jobs.py +++ b/awx/main/migrations/_scan_jobs.py @@ -1,89 +1,9 @@ import logging -from django.utils.timezone import now -from django.utils.text import slugify - -from awx.main.models.base import PERM_INVENTORY_SCAN, PERM_INVENTORY_DEPLOY -from awx.main import utils - logger = logging.getLogger('awx.main.migrations') -def _create_fact_scan_project(ContentType, Project, org): - ct = ContentType.objects.get_for_model(Project) - name = u"Tower Fact Scan - {}".format(org.name if org else "No Organization") - proj = Project(name=name, - scm_url='https://github.com/ansible/awx-facts-playbooks', - scm_type='git', - scm_update_on_launch=True, - scm_update_cache_timeout=86400, - organization=org, - created=now(), - modified=now(), - polymorphic_ctype=ct) - proj.save() - - slug_name = slugify(str(name)).replace(u'-', u'_') - proj.local_path = u'_%d__%s' % (int(proj.pk), slug_name) - - proj.save() - return proj - - -def _create_fact_scan_projects(ContentType, Project, orgs): - return {org.id : _create_fact_scan_project(ContentType, Project, org) for org in orgs} - - -def _get_tower_scan_job_templates(JobTemplate): - return JobTemplate.objects.filter(job_type=PERM_INVENTORY_SCAN, project__isnull=True) \ - .prefetch_related('inventory__organization') - - -def _get_orgs(Organization, job_template_ids): - return Organization.objects.filter(inventories__jobtemplates__in=job_template_ids).distinct() - - -def _migrate_scan_job_templates(apps): - JobTemplate = apps.get_model('main', 'JobTemplate') - Organization = apps.get_model('main', 'Organization') - ContentType = apps.get_model('contenttypes', 'ContentType') - Project = apps.get_model('main', 'Project') - - project_no_org = None - - # A scan job template with a custom project will retain the custom project. - JobTemplate.objects.filter(job_type=PERM_INVENTORY_SCAN, project__isnull=False).update(use_fact_cache=True, job_type=PERM_INVENTORY_DEPLOY) - - # Scan jobs templates using Tower's default scan playbook will now point at - # the same playbook but in a github repo. - jts = _get_tower_scan_job_templates(JobTemplate) - if jts.count() == 0: - return - - orgs = _get_orgs(Organization, jts.values_list('id')) - if orgs.count() == 0: - return - - org_proj_map = _create_fact_scan_projects(ContentType, Project, orgs) - for jt in jts: - if jt.inventory and jt.inventory.organization: - jt.project_id = org_proj_map[jt.inventory.organization.id].id - # Job Templates without an Organization; through related Inventory - else: - if not project_no_org: - project_no_org = _create_fact_scan_project(ContentType, Project, None) - jt.project_id = project_no_org.id - jt.job_type = PERM_INVENTORY_DEPLOY - jt.playbook = "scan_facts.yml" - jt.use_fact_cache = True - jt.save() - - -def migrate_scan_job_templates(apps, schema_editor): - _migrate_scan_job_templates(apps) - - def remove_scan_type_nodes(apps, schema_editor): WorkflowJobTemplateNode = apps.get_model('main', 'WorkflowJobTemplateNode') WorkflowJobNode = apps.get_model('main', 'WorkflowJobNode') diff --git a/awx/main/tests/functional/test_inventory_source_migration.py b/awx/main/tests/functional/test_inventory_source_migration.py index ade2329de5..739b922322 100644 --- a/awx/main/tests/functional/test_inventory_source_migration.py +++ b/awx/main/tests/functional/test_inventory_source_migration.py @@ -2,52 +2,10 @@ import pytest from unittest import mock from awx.main.migrations import _inventory_source as invsrc -from awx.main.models import InventorySource from django.apps import apps -@pytest.mark.django_db -def test_inv_src_manual_removal(inventory_source): - inventory_source.source = '' - inventory_source.save() - - assert InventorySource.objects.filter(pk=inventory_source.pk).exists() - invsrc.remove_manual_inventory_sources(apps, None) - assert not InventorySource.objects.filter(pk=inventory_source.pk).exists() - - -@pytest.mark.django_db -def test_rax_inv_src_removal(inventory_source): - inventory_source.source = 'rax' - inventory_source.save() - - assert InventorySource.objects.filter(pk=inventory_source.pk).exists() - invsrc.remove_rax_inventory_sources(apps, None) - assert not InventorySource.objects.filter(pk=inventory_source.pk).exists() - - -@pytest.mark.django_db -def test_inv_src_rename(inventory_source_factory): - inv_src01 = inventory_source_factory('t1') - - invsrc.rename_inventory_sources(apps, None) - - inv_src01.refresh_from_db() - # inv-is-t1 is generated in the inventory_source_factory - assert inv_src01.name == 't1 - inv-is-t1 - 0' - - -@pytest.mark.django_db -def test_azure_inv_src_removal(inventory_source): - inventory_source.source = 'azure' - inventory_source.save() - - assert InventorySource.objects.filter(pk=inventory_source.pk).exists() - invsrc.remove_azure_inventory_sources(apps, None) - assert not InventorySource.objects.filter(pk=inventory_source.pk).exists() - - @pytest.mark.parametrize('vars,id_var,result', [ ({'foo': {'bar': '1234'}}, 'foo.bar', '1234'), ({'cat': 'meow'}, 'cat', 'meow'), diff --git a/awx/main/tests/functional/test_scan_jobs_migration.py b/awx/main/tests/functional/test_scan_jobs_migration.py deleted file mode 100644 index 8582bd10c6..0000000000 --- a/awx/main/tests/functional/test_scan_jobs_migration.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2017 Ansible, Inc. -# All Rights Reserved. -import pytest - -from django.apps import apps - -from awx.main.models.base import PERM_INVENTORY_SCAN, PERM_INVENTORY_DEPLOY -from awx.main.models import ( - JobTemplate, - Project, - Inventory, - Organization, -) - -from awx.main.migrations._scan_jobs import _migrate_scan_job_templates - - -@pytest.fixture -def organizations(): - return [Organization.objects.create(name=u"org-\xe9-{}".format(x)) for x in range(3)] - - -@pytest.fixture -def inventories(organizations): - return [Inventory.objects.create(name=u"inv-\xe9-{}".format(x), - organization=organizations[x]) for x in range(3)] - - -@pytest.fixture -def job_templates_scan(inventories): - return [JobTemplate.objects.create(name=u"jt-\xe9-scan-{}".format(x), - job_type=PERM_INVENTORY_SCAN, - inventory=inventories[x]) for x in range(3)] - - -@pytest.fixture -def job_templates_deploy(inventories): - return [JobTemplate.objects.create(name=u"jt-\xe9-deploy-{}".format(x), - job_type=PERM_INVENTORY_DEPLOY, - inventory=inventories[x]) for x in range(3)] - - -@pytest.fixture -def project_custom(organizations): - return Project.objects.create(name=u"proj-\xe9-scan_custom", - scm_url='https://giggity.com', - organization=organizations[0]) - - -@pytest.fixture -def job_templates_custom_scan_project(project_custom): - return [JobTemplate.objects.create(name=u"jt-\xe9-scan-custom-{}".format(x), - project=project_custom, - job_type=PERM_INVENTORY_SCAN) for x in range(3)] - - -@pytest.fixture -def job_template_scan_no_org(): - return JobTemplate.objects.create(name=u"jt-\xe9-scan-no-org", - job_type=PERM_INVENTORY_SCAN) - - -@pytest.mark.django_db -def test_scan_jobs_migration(job_templates_scan, job_templates_deploy, job_templates_custom_scan_project, project_custom, job_template_scan_no_org): - _migrate_scan_job_templates(apps) - - # Ensure there are no scan job templates after the migration - assert 0 == JobTemplate.objects.filter(job_type=PERM_INVENTORY_SCAN).count() - - # Ensure special No Organization proj created - # And No Organization project is associated with correct jt - proj = Project.objects.get(name="Tower Fact Scan - No Organization") - assert proj.id == JobTemplate.objects.get(id=job_template_scan_no_org.id).project.id - - # Ensure per-org projects were created - projs = Project.objects.filter(name__startswith="Tower Fact Scan") - assert projs.count() == 4 - - # Ensure scan job templates with Tower project are migrated - for i, jt_old in enumerate(job_templates_scan): - jt = JobTemplate.objects.get(id=jt_old.id) - assert PERM_INVENTORY_DEPLOY == jt.job_type - assert jt.use_fact_cache is True - assert projs[i] == jt.project - - # Ensure scan job templates with custom projects are migrated - for jt_old in job_templates_custom_scan_project: - jt = JobTemplate.objects.get(id=jt_old.id) - assert PERM_INVENTORY_DEPLOY == jt.job_type - assert jt.use_fact_cache is True - assert project_custom == jt.project - - # Ensure other job template aren't touched - for jt_old in job_templates_deploy: - jt = JobTemplate.objects.get(id=jt_old.id) - assert PERM_INVENTORY_DEPLOY == jt.job_type - assert jt.project is None -