mirror of
https://github.com/ansible/awx.git
synced 2026-05-10 02:47:36 -02:30
remove a number of unnecessary 3.2 migrations
This commit is contained in:
@@ -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)
|
||||
]
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user