diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 1fb0c493f9..266cb01191 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -43,7 +43,7 @@ from polymorphic.models import PolymorphicModel # AWX from awx.main.access import get_user_capabilities -from awx.main.constants import SCHEDULEABLE_PROVIDERS, ACTIVE_STATES, CENSOR_VALUE +from awx.main.constants import ACTIVE_STATES, CENSOR_VALUE from awx.main.models import ( ActivityStream, AdHocCommand, @@ -91,6 +91,7 @@ from awx.main.models import ( WorkflowJobTemplate, WorkflowJobTemplateNode, StdoutMaxBytesExceeded, + CLOUD_INVENTORY_SOURCES, ) from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator @@ -4761,7 +4762,7 @@ class ScheduleSerializer(LaunchConfigurationBaseSerializer, SchedulePreviewSeria return summary_fields def validate_unified_job_template(self, value): - if type(value) == InventorySource and value.source not in SCHEDULEABLE_PROVIDERS: + if type(value) == InventorySource and value.source not in CLOUD_INVENTORY_SOURCES: raise serializers.ValidationError(_('Inventory Source must be a cloud resource.')) elif type(value) == Project and value.scm_type == '': raise serializers.ValidationError(_('Manual Project cannot have a schedule set.')) diff --git a/awx/main/constants.py b/awx/main/constants.py index 6a44087c28..b2d62d5ec9 100644 --- a/awx/main/constants.py +++ b/awx/main/constants.py @@ -7,7 +7,6 @@ from django.utils.translation import ugettext_lazy as _ __all__ = [ 'CLOUD_PROVIDERS', - 'SCHEDULEABLE_PROVIDERS', 'PRIVILEGE_ESCALATION_METHODS', 'ANSI_SGR_PATTERN', 'CAN_CANCEL', @@ -16,10 +15,6 @@ __all__ = [ ] CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'rhv', 'satellite6', 'tower') -SCHEDULEABLE_PROVIDERS = CLOUD_PROVIDERS + ( - 'custom', - 'scm', -) PRIVILEGE_ESCALATION_METHODS = [ ('sudo', _('Sudo')), ('su', _('Su')), diff --git a/awx/main/migrations/0136_custom_inventory_scripts_removal_data.py b/awx/main/migrations/0136_custom_inventory_scripts_removal_data.py new file mode 100644 index 0000000000..7ade393641 --- /dev/null +++ b/awx/main/migrations/0136_custom_inventory_scripts_removal_data.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.16 on 2021-04-13 19:51 + +from django.db import migrations + +# AWX migration utils +from awx.main.migrations._rbac import delete_all_custom_script_roles +from awx.main.migrations._inventory_source import delete_custom_inv_source + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0135_schedule_sort_fallback_to_id'), + ] + + operations = [ + migrations.RunPython(delete_custom_inv_source), + migrations.RunPython(delete_all_custom_script_roles), + ] diff --git a/awx/main/migrations/0137_custom_inventory_scripts_removal.py b/awx/main/migrations/0137_custom_inventory_scripts_removal.py new file mode 100644 index 0000000000..10bfdc9484 --- /dev/null +++ b/awx/main/migrations/0137_custom_inventory_scripts_removal.py @@ -0,0 +1,81 @@ +# Generated by Django 2.2.16 on 2021-04-13 19:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0136_custom_inventory_scripts_removal_data'), + ] + + operations = [ + migrations.RemoveField( + model_name='activitystream', + name='custom_inventory_script', + ), + migrations.RemoveField( + model_name='inventorysource', + name='source_script', + ), + migrations.RemoveField( + model_name='inventoryupdate', + name='source_script', + ), + migrations.AlterField( + model_name='inventorysource', + name='source', + field=models.CharField( + choices=[ + ('file', 'File, Directory or Script'), + ('scm', 'Sourced from a Project'), + ('ec2', 'Amazon EC2'), + ('gce', 'Google Compute Engine'), + ('azure_rm', 'Microsoft Azure Resource Manager'), + ('vmware', 'VMware vCenter'), + ('satellite6', 'Red Hat Satellite 6'), + ('openstack', 'OpenStack'), + ('rhv', 'Red Hat Virtualization'), + ('tower', 'Ansible Tower'), + ], + default=None, + max_length=32, + ), + ), + migrations.AlterField( + model_name='inventoryupdate', + name='source', + field=models.CharField( + choices=[ + ('file', 'File, Directory or Script'), + ('scm', 'Sourced from a Project'), + ('ec2', 'Amazon EC2'), + ('gce', 'Google Compute Engine'), + ('azure_rm', 'Microsoft Azure Resource Manager'), + ('vmware', 'VMware vCenter'), + ('satellite6', 'Red Hat Satellite 6'), + ('openstack', 'OpenStack'), + ('rhv', 'Red Hat Virtualization'), + ('tower', 'Ansible Tower'), + ], + default=None, + max_length=32, + ), + ), + migrations.AlterUniqueTogether( + name='custominventoryscript', + unique_together=set(), + ), + migrations.RemoveField( + model_name='custominventoryscript', + name='admin_role', + ), + migrations.RemoveField( + model_name='custominventoryscript', + name='organization', + ), + migrations.RemoveField( + model_name='custominventoryscript', + name='read_role', + ), + ] diff --git a/awx/main/migrations/_inventory_source.py b/awx/main/migrations/_inventory_source.py index 40769a0cf9..b12cfa0918 100644 --- a/awx/main/migrations/_inventory_source.py +++ b/awx/main/migrations/_inventory_source.py @@ -90,3 +90,22 @@ def delete_cloudforms_inv_source(apps, schema_editor): if ct: ct.credentials.all().delete() ct.delete() + + +def delete_custom_inv_source(apps, schema_editor): + set_current_apps(apps) + InventorySource = apps.get_model('main', 'InventorySource') + InventoryUpdate = apps.get_model('main', 'InventoryUpdate') + ct, deletions = InventoryUpdate.objects.filter(source='custom').delete() + if ct: + logger.info('deleted {}'.format((ct, deletions))) + update_ct = deletions['main.InventoryUpdate'] + if update_ct: + logger.info('Deleted {} custom inventory script sources.'.format(update_ct)) + ct, deletions = InventorySource.objects.filter(source='custom').delete() + if ct: + logger.info('deleted {}'.format((ct, deletions))) + src_ct = deletions['main.InventorySource'] + if src_ct: + logger.info('Deleted {} custom inventory script updates.'.format(src_ct)) + logger.warning('Custom inventory scripts have been removed, see awx-manage XXXXX') diff --git a/awx/main/migrations/_rbac.py b/awx/main/migrations/_rbac.py index 07284b64cd..480fdd8929 100644 --- a/awx/main/migrations/_rbac.py +++ b/awx/main/migrations/_rbac.py @@ -47,6 +47,18 @@ def delete_all_user_roles(apps, schema_editor): role.delete() +def delete_all_custom_script_roles(apps, schema_editor): + ContentType = apps.get_model('contenttypes', "ContentType") + Role = apps.get_model('main', "Role") + cis_type = ContentType.objects.get(model='custominventoryscript') + role_ct = 0 + for role in Role.objects.filter(content_type=cis_type).iterator(): + role.delete() + role_ct += 1 + if role_ct: + logger.debug('Deleted roles corresponding to custom inventory sources.') + + UNIFIED_ORG_LOOKUPS = { # Job Templates had an implicit organization via their project 'jobtemplate': 'project', diff --git a/awx/main/models/activity_stream.py b/awx/main/models/activity_stream.py index 16e73bef56..e0eafbcfbb 100644 --- a/awx/main/models/activity_stream.py +++ b/awx/main/models/activity_stream.py @@ -74,8 +74,6 @@ class ActivityStream(models.Model): unified_job = models.ManyToManyField("UnifiedJob", blank=True, related_name='activity_stream_as_unified_job+') ad_hoc_command = models.ManyToManyField("AdHocCommand", blank=True) schedule = models.ManyToManyField("Schedule", blank=True) - # TODO: migrate away - custom_inventory_script = models.ManyToManyField("CustomInventoryScript", blank=True) execution_environment = models.ManyToManyField("ExecutionEnvironment", blank=True) notification_template = models.ManyToManyField("NotificationTemplate", blank=True) notification = models.ManyToManyField("Notification", blank=True) diff --git a/awx/main/models/base.py b/awx/main/models/base.py index e8c10f5fac..e39891f546 100644 --- a/awx/main/models/base.py +++ b/awx/main/models/base.py @@ -62,7 +62,7 @@ PROJECT_UPDATE_JOB_TYPE_CHOICES = [ (PERM_INVENTORY_CHECK, _('Check')), ] -CLOUD_INVENTORY_SOURCES = list(CLOUD_PROVIDERS) + ['scm', 'custom'] +CLOUD_INVENTORY_SOURCES = list(CLOUD_PROVIDERS) + ['scm'] VERBOSITY_CHOICES = [ (0, '0 (Normal)'), diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 58465ba78b..363544e0c6 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -821,7 +821,6 @@ class InventorySourceOptions(BaseModel): ('openstack', _('OpenStack')), ('rhv', _('Red Hat Virtualization')), ('tower', _('Ansible Tower')), - ('custom', _('Custom Script')), ] # From the options of the Django management base command @@ -845,14 +844,6 @@ class InventorySourceOptions(BaseModel): blank=True, default='', ) - # TODO: migrate away - source_script = models.ForeignKey( - 'CustomInventoryScript', - null=True, - default=None, - blank=True, - on_delete=models.SET_NULL, - ) source_vars = models.TextField( blank=True, default='', @@ -1329,7 +1320,6 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin, class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin): class Meta: app_label = 'main' - unique_together = [('name', 'organization')] ordering = ('name',) script = prevent_search( @@ -1339,21 +1329,6 @@ class CustomInventoryScript(CommonModelNameNotUnique, ResourceMixin): help_text=_('Inventory script contents'), ) ) - organization = models.ForeignKey( - 'Organization', - related_name='custom_inventory_scripts', - help_text=_('Organization owning this inventory script'), - blank=False, - null=True, - on_delete=models.SET_NULL, - ) - - admin_role = ImplicitRoleField( - parent_role='organization.admin_role', - ) - read_role = ImplicitRoleField( - parent_role=['organization.auditor_role', 'organization.member_role', 'admin_role'], - ) def get_absolute_url(self, request=None): return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request)