diff --git a/awx/api/generics.py b/awx/api/generics.py index c86639ab95..3371e0bc09 100644 --- a/awx/api/generics.py +++ b/awx/api/generics.py @@ -5,13 +5,11 @@ import inspect import logging import time -import uuid # Django from django.conf import settings from django.contrib.auth import views as auth_views from django.contrib.contenttypes.models import ContentType -from django.core.cache import cache from django.core.exceptions import FieldDoesNotExist from django.db import connection, transaction from django.db.models.fields.related import OneToOneRel @@ -967,16 +965,11 @@ class CopyAPIView(GenericAPIView): if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all(): new_obj.admin_role.members.add(request.user) if sub_objs: - # store the copied object dict into cache, because it's - # often too large for postgres' notification bus - # (which has a default maximum message size of 8k) - key = 'deep-copy-{}'.format(str(uuid.uuid4())) - cache.set(key, sub_objs, timeout=3600) permission_check_func = None if hasattr(type(self), 'deep_copy_permission_check_func'): permission_check_func = (type(self).__module__, type(self).__name__, 'deep_copy_permission_check_func') trigger_delayed_deep_copy( - self.model.__module__, self.model.__name__, obj.pk, new_obj.pk, request.user.pk, key, permission_check_func=permission_check_func + self.model.__module__, self.model.__name__, obj.pk, new_obj.pk, request.user.pk, permission_check_func=permission_check_func ) serializer = self._get_copy_return_serializer(new_obj) headers = {'Location': new_obj.get_absolute_url(request=request)} diff --git a/awx/main/tasks/system.py b/awx/main/tasks/system.py index 36fc266803..12b1981a85 100644 --- a/awx/main/tasks/system.py +++ b/awx/main/tasks/system.py @@ -893,15 +893,8 @@ def _reconstruct_relationships(copy_mapping): @task(queue=get_task_queuename) -def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, uuid, permission_check_func=None): - sub_obj_list = cache.get(uuid) - if sub_obj_list is None: - logger.error('Deep copy {} from {} to {} failed unexpectedly.'.format(model_name, obj_pk, new_obj_pk)) - return - +def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, permission_check_func=None): logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk)) - from awx.api.generics import CopyAPIView - from awx.main.signals import disable_activity_stream model = getattr(importlib.import_module(model_module), model_name, None) if model is None: @@ -913,6 +906,28 @@ def deep_copy_model_obj(model_module, model_name, obj_pk, new_obj_pk, user_pk, u except ObjectDoesNotExist: logger.warning("Object or user no longer exists.") return + + o2m_to_preserve = {} + fields_to_preserve = set(getattr(model, 'FIELDS_TO_PRESERVE_AT_COPY', [])) + + for field in model._meta.get_fields(): + if field.name in fields_to_preserve: + if field.one_to_many: + try: + field_val = getattr(obj, field.name) + except AttributeError: + continue + o2m_to_preserve[field.name] = field_val + + sub_obj_list = [] + for o2m in o2m_to_preserve: + for sub_obj in o2m_to_preserve[o2m].all(): + sub_model = type(sub_obj) + sub_obj_list.append((sub_model.__module__, sub_model.__name__, sub_obj.pk)) + + from awx.api.generics import CopyAPIView + from awx.main.signals import disable_activity_stream + with transaction.atomic(), ignore_inventory_computed_fields(), disable_activity_stream(): copy_mapping = {} for sub_obj_setup in sub_obj_list: