diff --git a/awx/conf/migrations/0001_initial.py b/awx/conf/migrations/0001_initial.py index b239f5e143..ffde1c4bd6 100644 --- a/awx/conf/migrations/0001_initial.py +++ b/awx/conf/migrations/0001_initial.py @@ -4,6 +4,8 @@ from __future__ import unicode_literals from django.db import migrations, models from django.conf import settings +import awx.main.fields + class Migration(migrations.Migration): @@ -17,7 +19,7 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(default=None, editable=False)), ('modified', models.DateTimeField(default=None, editable=False)), ('key', models.CharField(max_length=255)), - ('value', models.JSONField(null=True)), + ('value', awx.main.fields.JSONBlob(null=True)), ( 'user', models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True), diff --git a/awx/conf/migrations/0003_v310_JSONField_changes.py b/awx/conf/migrations/0003_v310_JSONField_changes.py index d312c40b1d..6c0b5cba98 100644 --- a/awx/conf/migrations/0003_v310_JSONField_changes.py +++ b/awx/conf/migrations/0003_v310_JSONField_changes.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations + +import awx.main.fields class Migration(migrations.Migration): dependencies = [('conf', '0002_v310_copy_tower_settings')] - operations = [migrations.AlterField(model_name='setting', name='value', field=models.JSONField(null=True))] + operations = [migrations.AlterField(model_name='setting', name='value', field=awx.main.fields.JSONBlob(null=True))] diff --git a/awx/conf/models.py b/awx/conf/models.py index 05162436d1..79bc572d57 100644 --- a/awx/conf/models.py +++ b/awx/conf/models.py @@ -8,6 +8,7 @@ import json from django.db import models # AWX +from awx.main.fields import JSONBlob from awx.main.models.base import CreatedModifiedModel, prevent_search from awx.main.utils import encrypt_field from awx.conf import settings_registry @@ -18,7 +19,7 @@ __all__ = ['Setting'] class Setting(CreatedModifiedModel): key = models.CharField(max_length=255) - value = models.JSONField(null=True) + value = JSONBlob(null=True) user = prevent_search(models.ForeignKey('auth.User', related_name='settings', default=None, null=True, editable=False, on_delete=models.CASCADE)) def __str__(self): diff --git a/awx/main/fields.py b/awx/main/fields.py index 83ab57f37d..3372627f91 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -43,7 +43,6 @@ from rest_framework import serializers from awx.main.utils.filters import SmartFilter from awx.main.utils.encryption import encrypt_value, decrypt_value, get_encryption_key from awx.main.validators import validate_ssh_private_key -from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role, ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR from awx.main.constants import ENV_BLOCKLIST from awx.main import utils @@ -130,6 +129,9 @@ def is_implicit_parent(parent_role, child_role): the model definition. This does not include any role parents that might have been set by the user. """ + # Avoid circular import + from awx.main.models.rbac import ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR + if child_role.content_object is None: # The only singleton implicit parent is the system admin being # a parent of the system auditor role @@ -286,6 +288,9 @@ class ImplicitRoleField(models.ForeignKey): Model = utils.get_current_apps().get_model('main', instance.__class__.__name__) latest_instance = Model.objects.get(pk=instance.pk) + # Avoid circular import + from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role + with batch_role_ancestor_rebuilding(): # Create any missing role objects missing_roles = [] @@ -340,6 +345,10 @@ class ImplicitRoleField(models.ForeignKey): Role_ = utils.get_current_apps().get_model('main', 'Role') child_ids = [x for x in Role_.parents.through.objects.filter(to_role_id__in=role_ids).distinct().values_list('from_role_id', flat=True)] Role_.objects.filter(id__in=role_ids).delete() + + # Avoid circular import + from awx.main.models.rbac import Role + Role.rebuild_role_ancestor_list([], child_ids) diff --git a/awx/main/migrations/0001_initial.py b/awx/main/migrations/0001_initial.py index c3dcbe36b7..aa78bdca16 100644 --- a/awx/main/migrations/0001_initial.py +++ b/awx/main/migrations/0001_initial.py @@ -622,7 +622,7 @@ class Migration(migrations.Migration): ('dtend', models.DateTimeField(default=None, null=True, editable=False)), ('rrule', models.CharField(max_length=255)), ('next_run', models.DateTimeField(default=None, null=True, editable=False)), - ('extra_data', models.JSONField(default=dict, null=True, blank=True)), + ('extra_data', awx.main.fields.JSONBlob(default=dict, blank=True)), ( 'created_by', models.ForeignKey( @@ -750,7 +750,7 @@ class Migration(migrations.Migration): ('elapsed', models.DecimalField(editable=False, max_digits=12, decimal_places=3)), ('job_args', models.TextField(default='', editable=False, blank=True)), ('job_cwd', models.CharField(default='', max_length=1024, editable=False, blank=True)), - ('job_env', models.JSONField(default=dict, editable=False, null=True, blank=True)), + ('job_env', awx.main.fields.JSONBlob(default=dict, editable=False, blank=True)), ('job_explanation', models.TextField(default='', editable=False, blank=True)), ('start_args', models.TextField(default='', editable=False, blank=True)), ('result_stdout_text', models.TextField(default='', editable=False, blank=True)), @@ -1034,7 +1034,7 @@ class Migration(migrations.Migration): ('host_config_key', models.CharField(default='', max_length=1024, blank=True)), ('ask_variables_on_launch', models.BooleanField(default=False)), ('survey_enabled', models.BooleanField(default=False)), - ('survey_spec', models.JSONField(default=dict, blank=True)), + ('survey_spec', awx.main.fields.JSONBlob(default=dict, blank=True)), ], options={ 'ordering': ('name',), diff --git a/awx/main/migrations/0002_squashed_v300_release.py b/awx/main/migrations/0002_squashed_v300_release.py index 5f23ed566f..8093de7175 100644 --- a/awx/main/migrations/0002_squashed_v300_release.py +++ b/awx/main/migrations/0002_squashed_v300_release.py @@ -198,7 +198,7 @@ class Migration(migrations.Migration): ), ('recipients', models.TextField(default='', editable=False, blank=True)), ('subject', models.TextField(default='', editable=False, blank=True)), - ('body', models.JSONField(default=dict, null=True, blank=True)), + ('body', awx.main.fields.JSONBlob(default=dict, blank=True)), ], options={ 'ordering': ('pk',), @@ -229,7 +229,7 @@ class Migration(migrations.Migration): ], ), ), - ('notification_configuration', models.JSONField(default=dict)), + ('notification_configuration', awx.main.fields.JSONBlob(default=dict)), ( 'created_by', models.ForeignKey( diff --git a/awx/main/migrations/0004_squashed_v310_release.py b/awx/main/migrations/0004_squashed_v310_release.py index c0ac0d4a04..b1d45d10d6 100644 --- a/awx/main/migrations/0004_squashed_v310_release.py +++ b/awx/main/migrations/0004_squashed_v310_release.py @@ -220,7 +220,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobnode', name='char_prompts', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AddField( model_name='workflowjobnode', @@ -259,7 +259,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobtemplatenode', name='char_prompts', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AddField( model_name='workflowjobtemplatenode', @@ -307,12 +307,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='job', name='artifacts', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AddField( model_name='workflowjobnode', name='ancestor_artifacts', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), # Job timeout settings migrations.AddField( @@ -380,7 +380,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name='project', name='playbook_files', - field=models.JSONField(default=list, help_text='List of playbooks found in the project', verbose_name='Playbook Files', editable=False, blank=True), + field=awx.main.fields.JSONBlob( + default=list, help_text='List of playbooks found in the project', verbose_name='Playbook Files', editable=False, blank=True + ), ), # Job events to stdout migrations.AddField( @@ -536,7 +538,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjob', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AddField( model_name='workflowjobtemplate', @@ -546,7 +548,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobtemplate', name='survey_spec', - field=models.JSONField(default=dict, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), # JSON field changes migrations.AlterField( @@ -557,12 +559,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='job', name='artifacts', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AlterField( model_name='job', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AlterField( model_name='jobevent', @@ -572,57 +574,59 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='jobtemplate', name='survey_spec', - field=models.JSONField(default=dict, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AlterField( model_name='notification', name='body', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AlterField( model_name='notificationtemplate', name='notification_configuration', - field=models.JSONField(default=dict), + field=awx.main.fields.JSONBlob(default=dict), ), migrations.AlterField( model_name='project', name='playbook_files', - field=models.JSONField(default=list, help_text='List of playbooks found in the project', verbose_name='Playbook Files', editable=False, blank=True), + field=awx.main.fields.JSONBlob( + default=list, help_text='List of playbooks found in the project', verbose_name='Playbook Files', editable=False, blank=True + ), ), migrations.AlterField( model_name='schedule', name='extra_data', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AlterField( model_name='unifiedjob', name='job_env', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AlterField( model_name='workflowjob', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AlterField( model_name='workflowjobnode', name='ancestor_artifacts', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AlterField( model_name='workflowjobnode', name='char_prompts', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AlterField( model_name='workflowjobtemplate', name='survey_spec', - field=models.JSONField(default=dict, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AlterField( model_name='workflowjobtemplatenode', name='char_prompts', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), # Job Project Update migrations.AddField( diff --git a/awx/main/migrations/0006_v320_release.py b/awx/main/migrations/0006_v320_release.py index c05bee3eec..0f88577baa 100644 --- a/awx/main/migrations/0006_v320_release.py +++ b/awx/main/migrations/0006_v320_release.py @@ -175,7 +175,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='project', name='inventory_files', - field=models.JSONField( + field=awx.main.fields.JSONBlob( default=list, help_text='Suggested list of content that could be Ansible inventory in the project', verbose_name='Inventory Files', diff --git a/awx/main/migrations/0009_v322_add_setting_field_for_activity_stream.py b/awx/main/migrations/0009_v322_add_setting_field_for_activity_stream.py index 56c86b19a8..f90e5a966b 100644 --- a/awx/main/migrations/0009_v322_add_setting_field_for_activity_stream.py +++ b/awx/main/migrations/0009_v322_add_setting_field_for_activity_stream.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.db import migrations, models +from django.db import migrations + +import awx.main.fields class Migration(migrations.Migration): @@ -14,6 +16,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='activitystream', name='setting', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), ] diff --git a/awx/main/migrations/0014_v330_saved_launchtime_configs.py b/awx/main/migrations/0014_v330_saved_launchtime_configs.py index 38c5d2b2f6..fdefdcaed8 100644 --- a/awx/main/migrations/0014_v330_saved_launchtime_configs.py +++ b/awx/main/migrations/0014_v330_saved_launchtime_configs.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='schedule', name='char_prompts', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AddField( model_name='schedule', @@ -37,7 +37,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='schedule', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AddField( model_name='workflowjobnode', @@ -47,12 +47,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobnode', name='extra_data', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AddField( model_name='workflowjobnode', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), migrations.AddField( model_name='workflowjobtemplatenode', @@ -62,12 +62,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobtemplatenode', name='extra_data', - field=models.JSONField(default=dict, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, blank=True), ), migrations.AddField( model_name='workflowjobtemplatenode', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), # Run data migration before removing the old credential field migrations.RunPython(migration_utils.set_current_apps_for_migrations, migrations.RunPython.noop), @@ -85,9 +85,9 @@ class Migration(migrations.Migration): name='JobLaunchConfig', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('extra_data', models.JSONField(blank=True, null=True, default=dict)), - ('survey_passwords', models.JSONField(blank=True, null=True, default=dict, editable=False)), - ('char_prompts', models.JSONField(blank=True, null=True, default=dict)), + ('extra_data', awx.main.fields.JSONBlob(blank=True, default=dict)), + ('survey_passwords', awx.main.fields.JSONBlob(blank=True, default=dict, editable=False)), + ('char_prompts', awx.main.fields.JSONBlob(blank=True, default=dict)), ('credentials', models.ManyToManyField(related_name='joblaunchconfigs', to='main.Credential')), ( 'inventory', diff --git a/awx/main/migrations/0020_v330_instancegroup_policies.py b/awx/main/migrations/0020_v330_instancegroup_policies.py index 0577f14ee9..a6275d4820 100644 --- a/awx/main/migrations/0020_v330_instancegroup_policies.py +++ b/awx/main/migrations/0020_v330_instancegroup_policies.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +from decimal import Decimal from django.db import migrations, models -from decimal import Decimal + +import awx.main.fields class Migration(migrations.Migration): @@ -15,7 +17,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='instancegroup', name='policy_instance_list', - field=models.JSONField( + field=awx.main.fields.JSONBlob( default=list, help_text='List of exact-match Instances that will always be automatically assigned to this group', blank=True ), ), diff --git a/awx/main/migrations/0038_v330_add_deleted_activitystream_actor.py b/awx/main/migrations/0038_v330_add_deleted_activitystream_actor.py index 504fa14eb3..6e921a9b40 100644 --- a/awx/main/migrations/0038_v330_add_deleted_activitystream_actor.py +++ b/awx/main/migrations/0038_v330_add_deleted_activitystream_actor.py @@ -2,7 +2,9 @@ # Generated by Django 1.11.11 on 2018-05-21 19:51 from __future__ import unicode_literals -from django.db import models, migrations +from django.db import migrations + +import awx.main.fields class Migration(migrations.Migration): @@ -15,6 +17,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='activitystream', name='deleted_actor', - field=models.JSONField(null=True), + field=awx.main.fields.JSONBlob(null=True), ), ] diff --git a/awx/main/migrations/0053_v340_workflow_inventory.py b/awx/main/migrations/0053_v340_workflow_inventory.py index e3dd56a3b2..7e4b7590ec 100644 --- a/awx/main/migrations/0053_v340_workflow_inventory.py +++ b/awx/main/migrations/0053_v340_workflow_inventory.py @@ -2,10 +2,11 @@ # Generated by Django 1.11.11 on 2018-09-27 19:50 from __future__ import unicode_literals -import awx.main.fields from django.db import migrations, models import django.db.models.deletion +import awx.main.fields + class Migration(migrations.Migration): @@ -17,7 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjob', name='char_prompts', - field=models.JSONField(blank=True, null=True, default=dict), + field=awx.main.fields.JSONBlob(blank=True, default=dict), ), migrations.AddField( model_name='workflowjob', diff --git a/awx/main/migrations/0085_v360_add_notificationtemplate_messages.py b/awx/main/migrations/0085_v360_add_notificationtemplate_messages.py index c2c69bb440..7e34b87ffe 100644 --- a/awx/main/migrations/0085_v360_add_notificationtemplate_messages.py +++ b/awx/main/migrations/0085_v360_add_notificationtemplate_messages.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals from django.db import migrations, models +import awx.main.fields import awx.main.models.notifications @@ -17,7 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='notificationtemplate', name='messages', - field=models.JSONField( + field=awx.main.fields.JSONBlob( default=awx.main.models.notifications.NotificationTemplate.default_messages, help_text='Optional custom messages for notification template.', null=True, diff --git a/awx/main/migrations/0090_v360_WFJT_prompts.py b/awx/main/migrations/0090_v360_WFJT_prompts.py index fdc3b85fcc..d8b4a06073 100644 --- a/awx/main/migrations/0090_v360_WFJT_prompts.py +++ b/awx/main/migrations/0090_v360_WFJT_prompts.py @@ -24,7 +24,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='workflowjobtemplate', name='char_prompts', - field=models.JSONField(blank=True, null=True, default=dict), + field=awx.main.fields.JSONBlob(blank=True, default=dict), ), migrations.AlterField( model_name='joblaunchconfig', diff --git a/awx/main/migrations/_squashed_30.py b/awx/main/migrations/_squashed_30.py index 90c2dd061b..c63e9915ec 100644 --- a/awx/main/migrations/_squashed_30.py +++ b/awx/main/migrations/_squashed_30.py @@ -29,7 +29,7 @@ SQUASHED_30 = { migrations.AddField( model_name='job', name='survey_passwords', - field=models.JSONField(default=dict, editable=False, null=True, blank=True), + field=awx.main.fields.JSONBlob(default=dict, editable=False, blank=True), ), ], '0031_v302_migrate_survey_passwords': [ diff --git a/awx/main/models/activity_stream.py b/awx/main/models/activity_stream.py index aa0ab9d9d6..fad08377fd 100644 --- a/awx/main/models/activity_stream.py +++ b/awx/main/models/activity_stream.py @@ -3,6 +3,7 @@ # AWX from awx.api.versioning import reverse +from awx.main.fields import JSONBlob from awx.main.models.base import accepts_json # Django @@ -35,7 +36,7 @@ class ActivityStream(models.Model): operation = models.CharField(max_length=13, choices=OPERATION_CHOICES) timestamp = models.DateTimeField(auto_now_add=True) changes = accepts_json(models.TextField(blank=True)) - deleted_actor = models.JSONField(null=True) + deleted_actor = JSONBlob(null=True) action_node = models.CharField( blank=True, default='', @@ -83,7 +84,7 @@ class ActivityStream(models.Model): o_auth2_application = models.ManyToManyField("OAuth2Application", blank=True) o_auth2_access_token = models.ManyToManyField("OAuth2AccessToken", blank=True) - setting = models.JSONField(default=dict, null=True, blank=True) + setting = JSONBlob(default=dict, blank=True) def __str__(self): operation = self.operation if 'operation' in self.__dict__ else '_delayed_' diff --git a/awx/main/models/ha.py b/awx/main/models/ha.py index a9dc9b887d..a7dfe7c0ab 100644 --- a/awx/main/models/ha.py +++ b/awx/main/models/ha.py @@ -18,6 +18,7 @@ from solo.models import SingletonModel from awx import __version__ as awx_application_version from awx.api.versioning import reverse +from awx.main.fields import JSONBlob from awx.main.managers import InstanceManager, InstanceGroupManager, UUID_DEFAULT from awx.main.constants import JOB_FOLDER_PREFIX from awx.main.models.base import BaseModel, HasEditsMixin, prevent_search @@ -327,7 +328,7 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin): ) policy_instance_percentage = models.IntegerField(default=0, help_text=_("Percentage of Instances to automatically assign to this group")) policy_instance_minimum = models.IntegerField(default=0, help_text=_("Static minimum number of Instances to automatically assign to this group")) - policy_instance_list = models.JSONField( + policy_instance_list = JSONBlob( default=list, blank=True, help_text=_("List of exact-match Instances that will always be automatically assigned to this group") ) diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index 3b22ecd02c..60bd15db02 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -44,7 +44,7 @@ from awx.main.models.notifications import ( JobNotificationMixin, ) from awx.main.utils import parse_yaml_or_json, getattr_dne, NullablePromptPseudoField -from awx.main.fields import ImplicitRoleField, AskForField +from awx.main.fields import ImplicitRoleField, AskForField, JSONBlob from awx.main.models.mixins import ( ResourceMixin, SurveyJobTemplateMixin, @@ -546,9 +546,8 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana editable=False, through='JobHostSummary', ) - artifacts = models.JSONField( + artifacts = JSONBlob( default=dict, - null=True, blank=True, editable=False, ) @@ -886,7 +885,7 @@ class LaunchTimeConfigBase(BaseModel): ) # All standard fields are stored in this dictionary field # This is a solution to the nullable CharField problem, specific to prompting - char_prompts = models.JSONField(default=dict, null=True, blank=True) + char_prompts = JSONBlob(default=dict, blank=True) def prompts_dict(self, display=False): data = {} @@ -939,12 +938,11 @@ class LaunchTimeConfig(LaunchTimeConfigBase): abstract = True # Special case prompting fields, even more special than the other ones - extra_data = models.JSONField(default=dict, null=True, blank=True) + extra_data = JSONBlob(default=dict, blank=True) survey_passwords = prevent_search( - models.JSONField( + JSONBlob( default=dict, editable=False, - null=True, blank=True, ) ) diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py index 94e737859b..bc45a21ccf 100644 --- a/awx/main/models/mixins.py +++ b/awx/main/models/mixins.py @@ -24,7 +24,7 @@ from awx.main.utils import parse_yaml_or_json, get_custom_venv_choices, get_lice from awx.main.utils.execution_environments import get_default_execution_environment from awx.main.utils.encryption import decrypt_value, get_encryption_key, is_encrypted from awx.main.utils.polymorphic import build_polymorphic_ctypes_map -from awx.main.fields import AskForField +from awx.main.fields import AskForField, JSONBlob from awx.main.constants import ACTIVE_STATES @@ -103,7 +103,7 @@ class SurveyJobTemplateMixin(models.Model): survey_enabled = models.BooleanField( default=False, ) - survey_spec = prevent_search(models.JSONField(default=dict, blank=True)) + survey_spec = prevent_search(JSONBlob(default=dict, blank=True)) ask_variables_on_launch = AskForField(blank=True, default=False, allows_field='extra_vars') def survey_password_variables(self): @@ -365,10 +365,9 @@ class SurveyJobMixin(models.Model): abstract = True survey_passwords = prevent_search( - models.JSONField( + JSONBlob( default=dict, editable=False, - null=True, blank=True, ) ) diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py index 9bfd1bc6b5..fb8af5b5f0 100644 --- a/awx/main/models/notifications.py +++ b/awx/main/models/notifications.py @@ -17,6 +17,7 @@ from jinja2.exceptions import TemplateSyntaxError, UndefinedError, SecurityError # AWX from awx.api.versioning import reverse +from awx.main.fields import JSONBlob from awx.main.models.base import CommonModelNameNotUnique, CreatedModifiedModel, prevent_search from awx.main.utils import encrypt_field, decrypt_field, set_environ from awx.main.notifications.email_backend import CustomEmailBackend @@ -69,12 +70,12 @@ class NotificationTemplate(CommonModelNameNotUnique): choices=NOTIFICATION_TYPE_CHOICES, ) - notification_configuration = prevent_search(models.JSONField(default=dict)) + notification_configuration = prevent_search(JSONBlob(default=dict)) def default_messages(): return {'started': None, 'success': None, 'error': None, 'workflow_approval': None} - messages = models.JSONField(null=True, blank=True, default=default_messages, help_text=_('Optional custom messages for notification template.')) + messages = JSONBlob(null=True, blank=True, default=default_messages, help_text=_('Optional custom messages for notification template.')) def has_message(self, condition): potential_template = self.messages.get(condition, {}) @@ -236,7 +237,7 @@ class Notification(CreatedModifiedModel): default='', editable=False, ) - body = models.JSONField(default=dict, null=True, blank=True) + body = JSONBlob(default=dict, blank=True) def get_absolute_url(self, request=None): return reverse('api:notification_detail', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index 385674d7ab..43f7fcb9ca 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -33,7 +33,7 @@ from awx.main.models.mixins import ResourceMixin, TaskManagerProjectUpdateMixin, from awx.main.utils import update_scm_url, polymorphic from awx.main.utils.ansible import skip_directory, could_be_inventory, could_be_playbook from awx.main.utils.execution_environments import get_control_plane_execution_environment -from awx.main.fields import ImplicitRoleField +from awx.main.fields import ImplicitRoleField, JSONBlob from awx.main.models.rbac import ( ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR, @@ -293,7 +293,7 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn help_text=_('The last revision fetched by a project update'), ) - playbook_files = models.JSONField( + playbook_files = JSONBlob( default=list, blank=True, editable=False, @@ -301,7 +301,7 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn help_text=_('List of playbooks found in the project'), ) - inventory_files = models.JSONField( + inventory_files = JSONBlob( default=list, blank=True, editable=False, diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index 65804c97b0..e89243de55 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -54,7 +54,7 @@ from awx.main.utils import polymorphic from awx.main.constants import ACTIVE_STATES, CAN_CANCEL from awx.main.redact import UriCleaner, REPLACE_STR from awx.main.consumers import emit_channel_notification -from awx.main.fields import AskForField, OrderedManyToManyField +from awx.main.fields import AskForField, OrderedManyToManyField, JSONBlob __all__ = ['UnifiedJobTemplate', 'UnifiedJob', 'StdoutMaxBytesExceeded'] @@ -653,9 +653,8 @@ class UnifiedJob( editable=False, ) job_env = prevent_search( - models.JSONField( + JSONBlob( default=dict, - null=True, blank=True, editable=False, ) diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index 197951ea05..30a2574748 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -28,7 +28,7 @@ from awx.main.models import prevent_search, accepts_json, UnifiedJobTemplate, Un from awx.main.models.notifications import NotificationTemplate, JobNotificationMixin from awx.main.models.base import CreatedModifiedModel, VarsDictProperty from awx.main.models.rbac import ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR -from awx.main.fields import ImplicitRoleField, AskForField +from awx.main.fields import ImplicitRoleField, AskForField, JSONBlob from awx.main.models.mixins import ( ResourceMixin, SurveyJobTemplateMixin, @@ -231,9 +231,8 @@ class WorkflowJobNode(WorkflowNodeBase): default=None, on_delete=models.CASCADE, ) - ancestor_artifacts = models.JSONField( + ancestor_artifacts = JSONBlob( default=dict, - null=True, blank=True, editable=False, )