diff --git a/awx/api/metadata.py b/awx/api/metadata.py
index 2d45f27f..f3546cef 100644
--- a/awx/api/metadata.py
+++ b/awx/api/metadata.py
@@ -153,7 +153,7 @@ def get_field_info(self, field):
pass
if field.field_name == 'type':
field_info['type'] = 'choice'
- elif field.field_name in ('url', 'custom_virtualenv', 'token'):
+ elif field.field_name in ('url', 'token'):
field_info['type'] = 'string'
elif field.field_name in ('related', 'summary_fields'):
field_info['type'] = 'object'
diff --git a/awx/api/serializers.py b/awx/api/serializers.py
index d987e181..b84a80e7 100644
--- a/awx/api/serializers.py
+++ b/awx/api/serializers.py
@@ -1321,8 +1321,8 @@ class OrganizationSerializer(BaseSerializer):
class Meta:
model = Organization
- fields = ('*', 'max_hosts', 'custom_virtualenv', 'default_environment')
- read_only_fields = ('*', 'custom_virtualenv')
+ fields = ('*', 'max_hosts', 'default_environment')
+ read_only_fields = ('*',)
def get_related(self, obj):
res = super(OrganizationSerializer, self).get_related(obj)
@@ -1490,14 +1490,13 @@ class Meta:
'scm_update_on_launch',
'scm_update_cache_timeout',
'allow_override',
- 'custom_virtualenv',
'default_environment',
'signature_validation_credential',
) + (
'last_update_failed',
'last_updated',
) # Backwards compatibility
- read_only_fields = ('*', 'custom_virtualenv')
+ read_only_fields = ('*',)
def get_related(self, obj):
res = super(ProjectSerializer, self).get_related(obj)
@@ -2359,12 +2358,11 @@ class Meta:
'host_filter',
'overwrite',
'overwrite_vars',
- 'custom_virtualenv',
'timeout',
'verbosity',
'limit',
)
- read_only_fields = ('*', 'custom_virtualenv')
+ read_only_fields = ('*',)
def get_related(self, obj):
res = super(InventorySourceOptionsSerializer, self).get_related(obj)
@@ -2568,8 +2566,6 @@ def validate(self, attrs):
class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSerializer):
- custom_virtualenv = serializers.ReadOnlyField()
-
class Meta:
model = InventoryUpdate
fields = (
@@ -2579,7 +2575,6 @@ class Meta:
'license_error',
'org_host_limit_error',
'source_project_update',
- 'custom_virtualenv',
'instance_group',
'scm_revision',
)
@@ -3288,13 +3283,12 @@ class Meta:
'become_enabled',
'diff_mode',
'allow_simultaneous',
- 'custom_virtualenv',
'job_slice_count',
'webhook_service',
'webhook_credential',
'prevent_instance_group_fallback',
)
- read_only_fields = ('*', 'custom_virtualenv')
+ read_only_fields = ('*',)
def get_related(self, obj):
res = super(JobTemplateSerializer, self).get_related(obj)
@@ -3461,11 +3455,10 @@ def get_summary_fields(self, obj):
class JobDetailSerializer(JobSerializer):
playbook_counts = serializers.SerializerMethodField(help_text=_('A count of all plays and tasks for the job run.'))
- custom_virtualenv = serializers.ReadOnlyField()
class Meta:
model = Job
- fields = ('*', 'host_status_counts', 'playbook_counts', 'custom_virtualenv')
+ fields = ('*', 'host_status_counts', 'playbook_counts')
def get_playbook_counts(self, obj):
task_count = obj.get_event_queryset().filter(event='playbook_on_task_start').count()
diff --git a/awx/api/templates/api/api_v2_config_view.md b/awx/api/templates/api/api_v2_config_view.md
index 725669bd..65d043a7 100644
--- a/awx/api/templates/api/api_v2_config_view.md
+++ b/awx/api/templates/api/api_v2_config_view.md
@@ -11,8 +11,6 @@ the following fields (some fields may not be visible to all users):
* `time_zone`: The configured time zone for the server.
* `license_info`: Information about the current license.
* `version`: Version of Ansible Tower package installed.
-* `custom_virtualenvs`: Deprecated venv locations from before migration to
- execution environments. Export tooling is in `awx-manage` commands.
* `eula`: The current End-User License Agreement
{% endifmeth %}
diff --git a/awx/api/views/root.py b/awx/api/views/root.py
index 65f3e0e1..f4d5a1c4 100644
--- a/awx/api/views/root.py
+++ b/awx/api/views/root.py
@@ -25,11 +25,11 @@
from awx.conf.registry import settings_registry
from awx.main.analytics import all_collectors
from awx.main.ha import is_ha_environment
-from awx.main.utils import get_awx_version, get_custom_venv_choices
+from awx.main.utils import get_awx_version
from awx.main.utils.licensing import validate_entitlement_manifest
from awx.api.versioning import reverse, drf_reverse
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS
-from awx.main.models import Project, Organization, Instance, InstanceGroup, JobTemplate
+from awx.main.models import Project, Organization, Instance, InstanceGroup
from awx.main.utils import set_environ
from awx.main.utils.licensing import get_licenser
@@ -314,11 +314,8 @@ def get(self, request, format=None):
dict(
project_base_dir=settings.PROJECTS_ROOT,
project_local_paths=Project.get_local_path_choices(),
- custom_virtualenvs=get_custom_venv_choices(),
)
)
- elif JobTemplate.accessible_objects(request.user, 'admin_role').exists():
- data['custom_virtualenvs'] = get_custom_venv_choices()
return Response(data)
diff --git a/awx/main/access.py b/awx/main/access.py
index c768e74c..30238e05 100644
--- a/awx/main/access.py
+++ b/awx/main/access.py
@@ -1664,7 +1664,6 @@ def changes_are_non_sensitive(self, obj, data):
'ask_inventory_on_launch',
'ask_credential_on_launch',
'survey_enabled',
- 'custom_virtualenv',
'diff_mode',
'timeout',
'job_slice_count',
diff --git a/awx/main/conf.py b/awx/main/conf.py
index 7c9d1f9e..e8cb2c1e 100644
--- a/awx/main/conf.py
+++ b/awx/main/conf.py
@@ -222,15 +222,6 @@
category_slug='system',
)
-register(
- 'CUSTOM_VENV_PATHS',
- field_class=fields.StringListPathField,
- label=_('Custom virtual environment paths'),
- help_text=_('Paths where Tower will look for custom virtual environments (in addition to /var/lib/awx/venv/). Enter one path per line.'),
- category=_('System'),
- category_slug='system',
- default=[],
-)
register(
'AD_HOC_COMMANDS',
diff --git a/awx/main/management/commands/custom_venv_associations.py b/awx/main/management/commands/custom_venv_associations.py
deleted file mode 100644
index 736dfe25..00000000
--- a/awx/main/management/commands/custom_venv_associations.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (c) 2021 Ansible, Inc.
-# All Rights Reserved
-
-from django.core.management.base import BaseCommand
-from awx.main.utils.common import get_custom_venv_choices
-from awx.main.models import Organization, InventorySource, JobTemplate, Project
-import yaml
-
-
-class Command(BaseCommand):
- """Returns the pip freeze from the path passed in the argument"""
-
- def add_arguments(self, parser):
- parser.add_argument(
- 'path',
- type=str,
- nargs=1,
- default='',
- help='run this with a path to a virtual environment as an argument to see the associated Job Templates, Organizations, Projects, and Inventory Sources.',
- )
- parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
-
- def handle(self, *args, **options):
- # look organiztions and unified job templates (which include JTs, workflows, and Inventory updates)
- super(Command, self).__init__()
- results = {}
- path = options.get('path')
- if path:
- all_venvs = get_custom_venv_choices()
- if path[0] in all_venvs: # verify this is a valid path
- path = path[0]
- orgs = [{"name": org.name, "id": org.id} for org in Organization.objects.filter(custom_virtualenv=path)]
- jts = [{"name": jt.name, "id": jt.id} for jt in JobTemplate.objects.filter(custom_virtualenv=path)]
- proj = [{"name": proj.name, "id": proj.id} for proj in Project.objects.filter(custom_virtualenv=path)]
- invsrc = [{"name": inv.name, "id": inv.id} for inv in InventorySource.objects.filter(custom_virtualenv=path)]
- results["organizations"] = orgs
- results["job_templates"] = jts
- results["projects"] = proj
- results["inventory_sources"] = invsrc
- if not options.get('q'):
- msg = [
- '# Virtual Environments Associations:',
- yaml.dump(results),
- '- To list all (now deprecated) custom virtual environments run:',
- 'awx-manage list_custom_venvs',
- '',
- '- To export the contents of a (deprecated) virtual environment, run the following command while supplying the path as an argument:',
- 'awx-manage export_custom_venv /path/to/venv',
- '',
- '- Run these commands with `-q` to remove tool tips.',
- '',
- ]
- print('\n'.join(msg))
- else:
- print(yaml.dump(results))
-
- else:
- print('\n', '# Incorrect path, verify your path is from the following list:')
- print('\n'.join(all_venvs), '\n')
diff --git a/awx/main/management/commands/export_custom_venv.py b/awx/main/management/commands/export_custom_venv.py
deleted file mode 100644
index 82065b78..00000000
--- a/awx/main/management/commands/export_custom_venv.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (c) 2021 Ansible, Inc.
-# All Rights Reserved
-
-from awx.main.utils.common import get_custom_venv_pip_freeze, get_custom_venv_choices
-from django.core.management.base import BaseCommand
-
-
-class Command(BaseCommand):
- """Returns the pip freeze from the path passed in the argument"""
-
- def add_arguments(self, parser):
- parser.add_argument(
- 'path',
- type=str,
- nargs=1,
- default='',
- help='run this with a path to a virtual environment as an argument to see the pip freeze data',
- )
- parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
-
- def handle(self, *args, **options):
- super(Command, self).__init__()
- if options.get('path'):
- path = options.get('path')
- all_venvs = get_custom_venv_choices()
- if path[0] in all_venvs:
- pip_data = get_custom_venv_pip_freeze(options.get('path')[0])
- if pip_data:
- if not options.get('q'):
- msg = [
- '# Virtual environment contents:',
- pip_data,
- '- To list all (now deprecated) custom virtual environments run:',
- 'awx-manage list_custom_venvs',
- '',
- '- To view the connections a (deprecated) virtual environment had in the database, run the following command while supplying the path as an argument:',
- 'awx-manage custom_venv_associations /path/to/venv',
- '',
- '- Run these commands with `-q` to remove tool tips.',
- '',
- ]
- print('\n'.join(msg))
- else:
- print(pip_data)
-
- else:
- print('\n', '# Incorrect path, verify your path is from the following list:')
- print('\n'.join(all_venvs))
diff --git a/awx/main/management/commands/list_custom_venvs.py b/awx/main/management/commands/list_custom_venvs.py
deleted file mode 100644
index 0df98c47..00000000
--- a/awx/main/management/commands/list_custom_venvs.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2021 Ansible, Inc.
-# All Rights Reserved
-import sys
-
-from awx.main.utils.common import get_custom_venv_choices
-from django.core.management.base import BaseCommand
-from django.conf import settings
-
-
-class Command(BaseCommand):
- """Returns a list of custom venv paths from the path passed in the argument"""
-
- def add_arguments(self, parser):
- parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
-
- def handle(self, *args, **options):
- super(Command, self).__init__()
- venvs = get_custom_venv_choices()
- if venvs:
- if not options.get('q'):
- msg = [
- '# Discovered Virtual Environments:',
- '\n'.join(venvs),
- '',
- '- To export the contents of a (deprecated) virtual environment, run the following command while supplying the path as an argument:',
- 'awx-manage export_custom_venv /path/to/venv',
- '',
- '- To view the connections a (deprecated) virtual environment had in the database, run the following command while supplying the path as an argument:',
- 'awx-manage custom_venv_associations /path/to/venv',
- '',
- '- Run these commands with `-q` to remove tool tips.',
- '',
- ]
- print('\n'.join(msg))
- else:
- print('\n'.join(venvs), '\n')
- else:
- msg = ["No custom virtual environments detected in:", settings.BASE_VENV_PATH]
-
- for path in settings.CUSTOM_VENV_PATHS:
- msg.append(path)
-
- print('\n'.join(msg), file=sys.stderr)
diff --git a/awx/main/migrations/0195_remove_custom_virtualenv.py b/awx/main/migrations/0195_remove_custom_virtualenv.py
new file mode 100644
index 00000000..a3936693
--- /dev/null
+++ b/awx/main/migrations/0195_remove_custom_virtualenv.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Generated for custom venv removal
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ('main', '0194_add_github_app_credential'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='inventorysource',
+ name='custom_virtualenv',
+ ),
+ migrations.RemoveField(
+ model_name='inventoryupdate',
+ name='custom_virtualenv',
+ ),
+ migrations.RemoveField(
+ model_name='job',
+ name='custom_virtualenv',
+ ),
+ migrations.RemoveField(
+ model_name='jobtemplate',
+ name='custom_virtualenv',
+ ),
+ migrations.RemoveField(
+ model_name='organization',
+ name='custom_virtualenv',
+ ),
+ migrations.RemoveField(
+ model_name='project',
+ name='custom_virtualenv',
+ ),
+ ]
diff --git a/awx/main/models/__init__.py b/awx/main/models/__init__.py
index 3148f44f..fadff9fd 100644
--- a/awx/main/models/__init__.py
+++ b/awx/main/models/__init__.py
@@ -65,7 +65,6 @@
ROLE_SINGLETON_SYSTEM_AUDITOR,
)
from awx.main.models.mixins import ( # noqa
- CustomVirtualEnvMixin,
ExecutionEnvironmentMixin,
ResourceMixin,
SurveyJobMixin,
diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py
index bf7b86c7..1fe9af0c 100644
--- a/awx/main/models/inventory.py
+++ b/awx/main/models/inventory.py
@@ -47,7 +47,6 @@
ResourceMixin,
TaskManagerInventoryUpdateMixin,
RelatedJobsMixin,
- CustomVirtualEnvMixin,
)
from awx.main.models.notifications import (
NotificationTemplate,
@@ -1093,7 +1092,7 @@ def credential(self):
source_vars_dict = VarsDictProperty('source_vars')
-class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualEnvMixin, RelatedJobsMixin):
+class InventorySource(UnifiedJobTemplate, InventorySourceOptions, RelatedJobsMixin):
SOFT_UNIQUE_TOGETHER = [('polymorphic_ctype', 'name', 'inventory')]
class Meta:
@@ -1269,7 +1268,7 @@ def _get_related_jobs(self):
return InventoryUpdate.objects.filter(inventory_source=self)
-class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin, TaskManagerInventoryUpdateMixin, CustomVirtualEnvMixin):
+class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin, TaskManagerInventoryUpdateMixin):
"""
Internal job for tracking inventory updates from external sources.
"""
diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py
index 7bd52d44..f2f08c73 100644
--- a/awx/main/models/jobs.py
+++ b/awx/main/models/jobs.py
@@ -47,7 +47,6 @@
SurveyJobTemplateMixin,
SurveyJobMixin,
TaskManagerJobMixin,
- CustomVirtualEnvMixin,
RelatedJobsMixin,
WebhookMixin,
WebhookTemplateMixin,
@@ -192,7 +191,7 @@ def passwords_needed_to_start(self):
return needed
-class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin, WebhookTemplateMixin):
+class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, ResourceMixin, RelatedJobsMixin, WebhookTemplateMixin):
"""
A job template is a reusable job definition for applying a project (with
playbook) to an inventory source with a given credential.
@@ -553,7 +552,7 @@ def _get_related_jobs(self):
return UnifiedJob.objects.filter(unified_job_template=self)
-class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskManagerJobMixin, CustomVirtualEnvMixin, WebhookMixin):
+class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskManagerJobMixin, WebhookMixin):
"""
A job applies a project (with playbook) to an inventory source with a given
credential. It represents a single invocation of ansible-playbook with the
diff --git a/awx/main/models/mixins.py b/awx/main/models/mixins.py
index b8547225..ca12330d 100644
--- a/awx/main/models/mixins.py
+++ b/awx/main/models/mixins.py
@@ -2,7 +2,6 @@
from copy import copy, deepcopy
import json
import logging
-import os
import requests
@@ -10,7 +9,6 @@
from django.apps import apps
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.query import QuerySet
from django.utils.crypto import get_random_string
@@ -20,7 +18,7 @@
# AWX
from awx.main.models.rbac import Role, RoleAncestorEntry
-from awx.main.utils import parse_yaml_or_json, get_custom_venv_choices, get_licenser, polymorphic
+from awx.main.utils import parse_yaml_or_json, get_licenser, polymorphic
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
@@ -40,7 +38,6 @@
'TaskManagerProjectUpdateMixin',
'TaskManagerInventoryUpdateMixin',
'ExecutionEnvironmentMixin',
- 'CustomVirtualEnvMixin',
]
@@ -523,23 +520,6 @@ def resolve_execution_environment(self):
return get_default_execution_environment()
-class CustomVirtualEnvMixin(models.Model):
- class Meta:
- abstract = True
-
- custom_virtualenv = models.CharField(
- blank=True, null=True, default=None, max_length=100, help_text=_('Local absolute file path containing a custom Python virtualenv to use')
- )
-
- def clean_custom_virtualenv(self):
- value = self.custom_virtualenv
- if value and os.path.join(value, '') not in get_custom_venv_choices():
- raise ValidationError(_('{} is not a valid virtualenv in {}').format(value, settings.BASE_VENV_PATH))
- if value:
- return os.path.join(value, '')
- return None
-
-
class RelatedJobsMixin(object):
"""
This method is intended to be overwritten.
diff --git a/awx/main/models/notifications.py b/awx/main/models/notifications.py
index 77f8032c..87db1834 100644
--- a/awx/main/models/notifications.py
+++ b/awx/main/models/notifications.py
@@ -280,7 +280,6 @@ class JobNotificationMixin(object):
'diff_mode',
'job_slice_number',
'job_slice_count',
- 'custom_virtualenv',
'approval_status',
'approval_node_name',
'workflow_url',
@@ -327,7 +326,6 @@ def context_stub(cls):
'artifacts': {},
'controller_node': 'foo_controller',
'created': datetime.datetime(2018, 11, 13, 6, 4, 0, 0, tzinfo=datetime.timezone.utc),
- 'custom_virtualenv': 'my_venv',
'description': 'Sample job description',
'diff_mode': False,
'elapsed': 0.403018,
diff --git a/awx/main/models/organization.py b/awx/main/models/organization.py
index 5e90c51a..7b97f5db 100644
--- a/awx/main/models/organization.py
+++ b/awx/main/models/organization.py
@@ -20,12 +20,12 @@
ROLE_SINGLETON_SYSTEM_AUDITOR,
)
from awx.main.models.unified_jobs import UnifiedJob
-from awx.main.models.mixins import ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin
+from awx.main.models.mixins import ResourceMixin, RelatedJobsMixin
__all__ = ['Organization', 'Team', 'Profile', 'UserSessionMembership']
-class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin):
+class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, RelatedJobsMixin):
"""
An organization is the basic unit of multi-tenancy divisions
"""
diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py
index e81fd578..0879df32 100644
--- a/awx/main/models/projects.py
+++ b/awx/main/models/projects.py
@@ -32,7 +32,7 @@
UnifiedJobTemplate,
)
from awx.main.models.jobs import Job
-from awx.main.models.mixins import ResourceMixin, TaskManagerProjectUpdateMixin, CustomVirtualEnvMixin, RelatedJobsMixin
+from awx.main.models.mixins import ResourceMixin, TaskManagerProjectUpdateMixin, RelatedJobsMixin
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
@@ -249,7 +249,7 @@ def get_lock_file(self):
return proj_path + '.lock'
-class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEnvMixin, RelatedJobsMixin):
+class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, RelatedJobsMixin):
"""
A project represents a playbook git repo that can access a set of inventories
"""
diff --git a/awx/main/tests/functional/models/test_notifications.py b/awx/main/tests/functional/models/test_notifications.py
index 2c1d6022..39fb6fe5 100644
--- a/awx/main/tests/functional/models/test_notifications.py
+++ b/awx/main/tests/functional/models/test_notifications.py
@@ -14,7 +14,6 @@ class TestJobNotificationMixin(object):
'job': {
'allow_simultaneous': bool,
'artifacts': {},
- 'custom_virtualenv': str,
'controller_node': str,
'created': datetime.datetime,
'description': str,
diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py
index 81c64066..915314a3 100644
--- a/awx/main/utils/common.py
+++ b/awx/main/utils/common.py
@@ -10,7 +10,6 @@
import time
import psycopg
import os
-import subprocess
import re
import stat
import sys
@@ -80,7 +79,6 @@
'has_model_field_prefetched',
'set_environ',
'IllegalArgumentError',
- 'get_custom_venv_choices',
'ScheduleTaskManager',
'ScheduleDependencyManager',
'ScheduleWorkflowManager',
@@ -1011,35 +1009,6 @@ def get_current_apps():
return current_apps
-def get_custom_venv_choices():
- from django.conf import settings
-
- all_venv_paths = settings.CUSTOM_VENV_PATHS + [settings.BASE_VENV_PATH]
- custom_venv_choices = []
-
- for venv_path in all_venv_paths:
- if os.path.exists(venv_path):
- for d in os.listdir(venv_path):
- if venv_path == settings.BASE_VENV_PATH and d == 'awx':
- continue
-
- if os.path.exists(os.path.join(venv_path, d, 'bin', 'pip')):
- custom_venv_choices.append(os.path.join(venv_path, d))
-
- return custom_venv_choices
-
-
-def get_custom_venv_pip_freeze(venv_path):
- pip_path = os.path.join(venv_path, 'bin', 'pip')
-
- try:
- freeze_data = subprocess.run([pip_path, "freeze"], capture_output=True)
- pip_data = (freeze_data.stdout).decode('UTF-8')
- return pip_data
- except Exception:
- logger.exception("Encountered an error while trying to run 'pip freeze' for custom virtual environments:")
-
-
def is_ansible_variable(key):
return key.startswith('ansible_')
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index 9120a707..2bb51ca3 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -179,7 +179,6 @@
# If this setting is an empty list (the default), we will only trust ourself
CSRF_TRUSTED_ORIGINS = []
-CUSTOM_VENV_PATHS = []
# Warning: this is a placeholder for a database setting
# This should not be set via a file.
diff --git a/awx/settings/development.py b/awx/settings/development.py
index df6676c6..9240a061 100644
--- a/awx/settings/development.py
+++ b/awx/settings/development.py
@@ -59,10 +59,6 @@
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
INSTALL_UUID = '00000000-0000-0000-0000-000000000000'
-# Ansible base virtualenv paths and enablement
-# only used for deprecated fields and management commands for them
-BASE_VENV_PATH = os.path.realpath("/var/lib/awx/venv")
-
CLUSTER_HOST_ID = socket.gethostname()
AWX_CALLBACK_PROFILE = True
diff --git a/awx/settings/production.py b/awx/settings/production.py
index fa74bc7f..e6b1c8c6 100644
--- a/awx/settings/production.py
+++ b/awx/settings/production.py
@@ -30,10 +30,6 @@
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
-# Ansible base virtualenv paths and enablement
-# only used for deprecated fields and management commands for them
-BASE_VENV_PATH = os.path.realpath("/var/lib/awx/venv")
-
# Very important that this is editable (not read_only) in the API
AWX_ISOLATION_SHOW_PATHS = [
'/etc/pki/ca-trust:/etc/pki/ca-trust:O',
diff --git a/awx/ui/CONTRIBUTING.md b/awx/ui/CONTRIBUTING.md
index e3f09090..26167d8e 100644
--- a/awx/ui/CONTRIBUTING.md
+++ b/awx/ui/CONTRIBUTING.md
@@ -309,16 +309,13 @@ If you want to stub the value of a context, or assert actions taken on it, you c
```javascript
const config = {
- custom_virtualenvs: ['foo', 'bar'],
+ isDev: true,
};
mountWithContexts(, {
context: { config },
});
```
-Now that these custom virtual environments are available in this `OrganizationForm` test we can assert that the component that displays
-them is rendering properly.
-
The object containing context values looks for five known contexts, identified by the keys `linguiPublisher`, `router`, `config`, `network`, and `dialog` — the latter three each referring to the contexts defined in `src/contexts`. You can pass `false` for any of these values, and the corresponding context will be omitted from your test. For example, this will mount your component without the dialog context:
```javascript
diff --git a/awx/ui/src/components/AppContainer/AppContainer.test.js b/awx/ui/src/components/AppContainer/AppContainer.test.js
index 7c5a9ee8..4d0b0e67 100644
--- a/awx/ui/src/components/AppContainer/AppContainer.test.js
+++ b/awx/ui/src/components/AppContainer/AppContainer.test.js
@@ -64,7 +64,6 @@ describe('', () => {
config: {
analytics_status: 'detailed',
ansible_version: null,
- custom_virtualenvs: [],
version: '9000',
me: { is_superuser: true },
toJSON: () => '/config/',
@@ -109,7 +108,6 @@ describe('', () => {
config: {
analytics_status: 'detailed',
ansible_version: null,
- custom_virtualenvs: [],
version: '9000',
me: { is_superuser: true },
toJSON: () => '/config/',
@@ -132,7 +130,6 @@ describe('', () => {
config: {
analytics_status: 'off',
ansible_version: null,
- custom_virtualenvs: [],
version: '9000',
me: { is_superuser: true },
toJSON: () => '/config/',
diff --git a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js b/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js
index a0e84e68..84e6471c 100644
--- a/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js
+++ b/awx/ui/src/components/ExecutionEnvironmentDetail/ExecutionEnvironmentDetail.test.js
@@ -11,8 +11,6 @@ const mockExecutionEnvironment = {
description: '',
};
-const virtualEnvironment = 'var/lib/awx/custom_env';
-
describe('', () => {
test('should display execution environment detail', async () => {
const wrapper = mountWithContexts(
@@ -30,37 +28,6 @@ describe('', () => {
);
});
- test('should display execution environment detail even with a previous virtual env present', async () => {
- const wrapper = mountWithContexts(
-
- );
- const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail');
- expect(executionEnvironment).toHaveLength(1);
- expect(executionEnvironment.find('dt').text()).toEqual(
- 'Execution Environment'
- );
- expect(executionEnvironment.find('dd').text()).toEqual(
- mockExecutionEnvironment.name
- );
- });
-
- test('should display warning missing execution environment', async () => {
- const wrapper = mountWithContexts(
-
- );
- const executionEnvironment = wrapper.find('ExecutionEnvironmentDetail');
- expect(executionEnvironment).toHaveLength(1);
- expect(executionEnvironment.find('dt').text()).toEqual(
- 'Execution Environment'
- );
- expect(executionEnvironment.find('dd').text()).toEqual('Missing resource');
- expect(wrapper.find('ExclamationTrianglePopover').length).toBe(1);
- expect(wrapper.find('Popover').length).toBe(1);
- });
-
test('should display warning deleted execution environment', async () => {
const wrapper = mountWithContexts(
diff --git a/awx/ui/src/components/PromptDetail/PromptInventorySourceDetail.js b/awx/ui/src/components/PromptDetail/PromptInventorySourceDetail.js
index ba1705ce..f29d05e0 100644
--- a/awx/ui/src/components/PromptDetail/PromptInventorySourceDetail.js
+++ b/awx/ui/src/components/PromptDetail/PromptInventorySourceDetail.js
@@ -17,7 +17,6 @@ import { VERBOSITY } from '../VerbositySelectField';
function PromptInventorySourceDetail({ resource }) {
const {
- custom_virtualenv,
group_by,
instance_filters,
overwrite,
@@ -93,7 +92,6 @@ function PromptInventorySourceDetail({ resource }) {
/>
)}
diff --git a/awx/ui/src/components/PromptDetail/PromptJobTemplateDetail.js b/awx/ui/src/components/PromptDetail/PromptJobTemplateDetail.js
index 1fd0877d..df04971a 100644
--- a/awx/ui/src/components/PromptDetail/PromptJobTemplateDetail.js
+++ b/awx/ui/src/components/PromptDetail/PromptJobTemplateDetail.js
@@ -41,7 +41,6 @@ function PromptJobTemplateDetail({ resource }) {
verbosity,
webhook_key,
webhook_service,
- custom_virtualenv,
} = resource;
let optionsList = '';
@@ -144,7 +143,6 @@ function PromptJobTemplateDetail({ resource }) {
)}
diff --git a/awx/ui/src/components/PromptDetail/PromptProjectDetail.js b/awx/ui/src/components/PromptDetail/PromptProjectDetail.js
index a51e49f4..dd1cebd2 100644
--- a/awx/ui/src/components/PromptDetail/PromptProjectDetail.js
+++ b/awx/ui/src/components/PromptDetail/PromptProjectDetail.js
@@ -17,7 +17,6 @@ function PromptProjectDetail({ resource }) {
const { t } = useLingui();
const {
allow_override,
- custom_virtualenv,
local_path,
scm_branch,
scm_clean,
@@ -89,7 +88,6 @@ function PromptProjectDetail({ resource }) {
)}
diff --git a/awx/ui/src/components/PromptDetail/data.inventory_source.json b/awx/ui/src/components/PromptDetail/data.inventory_source.json
index 57a0d750..9c9b11fc 100644
--- a/awx/ui/src/components/PromptDetail/data.inventory_source.json
+++ b/awx/ui/src/components/PromptDetail/data.inventory_source.json
@@ -101,7 +101,6 @@
"group_by": "group1,group2,group3",
"overwrite":true,
"overwrite_vars":true,
- "custom_virtualenv":null,
"timeout":0,
"verbosity":2,
"last_job_run":null,
diff --git a/awx/ui/src/components/PromptDetail/data.job_template.json b/awx/ui/src/components/PromptDetail/data.job_template.json
index 620bbb9f..7a518ba3 100644
--- a/awx/ui/src/components/PromptDetail/data.job_template.json
+++ b/awx/ui/src/components/PromptDetail/data.job_template.json
@@ -199,7 +199,6 @@
"become_enabled": true,
"diff_mode": false,
"allow_simultaneous": true,
- "custom_virtualenv": null,
"job_slice_count": 1,
"webhook_service": "github",
"webhook_credential": 8,
diff --git a/awx/ui/src/components/PromptDetail/data.project.json b/awx/ui/src/components/PromptDetail/data.project.json
index 371cc1d0..1b8c506c 100644
--- a/awx/ui/src/components/PromptDetail/data.project.json
+++ b/awx/ui/src/components/PromptDetail/data.project.json
@@ -108,7 +108,6 @@
"scm_update_on_launch":true,
"scm_update_cache_timeout":3,
"allow_override":true,
- "custom_virtualenv": "mock virtual env",
"last_update_failed":false,
"last_updated":"2020-03-11T20:18:14Z",
"default_environment": 1
diff --git a/awx/ui/src/components/TemplateList/TemplateListItem.js b/awx/ui/src/components/TemplateList/TemplateListItem.js
index 186ac47b..66215365 100644
--- a/awx/ui/src/components/TemplateList/TemplateListItem.js
+++ b/awx/ui/src/components/TemplateList/TemplateListItem.js
@@ -5,21 +5,18 @@
import 'styled-components/macro';
import React, { useState, useCallback } from 'react';
import { Link } from 'react-router-dom';
-import { Button, Popover, Tooltip, Chip } from '@patternfly/react-core';
+import { Button, Tooltip, Chip } from '@patternfly/react-core';
import { Tr, Td, ExpandableRowContent } from '@patternfly/react-table';
-import { Trans, useLingui } from '@lingui/react/macro';
+import { useLingui } from '@lingui/react/macro';
import {
ExclamationTriangleIcon,
PencilAltIcon,
ProjectDiagramIcon,
RocketIcon,
} from '@patternfly/react-icons';
-import styled from 'styled-components';
import { timeOfDay, formatDateString } from 'util/dates';
import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from 'api';
import { toTitleCase } from 'util/strings';
-import getDocsBaseUrl from 'util/getDocsBaseUrl';
-import { useConfig } from 'contexts/Config';
import { ActionsTd, ActionItem, TdBreakWord } from '../PaginatedTable';
import { DetailList, Detail, DeletedDetail } from '../DetailList';
import ChipGroup from '../ChipGroup';
@@ -29,14 +26,6 @@ import { LaunchButton } from '../LaunchButton';
import Sparkline from '../Sparkline';
import CopyButton from '../CopyButton';
-const ExclamationTriangleIconWarning = styled(ExclamationTriangleIcon)`
- color: var(--pf-global--warning-color--100);
- margin-left: 18px;
- cursor: pointer;
-`;
-
-ExclamationTriangleIconWarning.displayName = 'ExclamationTriangleIconWarning';
-
function TemplateListItem({
isExpanded,
onExpand,
@@ -49,14 +38,9 @@ function TemplateListItem({
rowIndex,
}) {
const { t } = useLingui();
- const config = useConfig();
const [isDisabled, setIsDisabled] = useState(false);
const labelId = `check-action-${template.id}`;
- const docsLink = `${getDocsBaseUrl(
- config
- )}/html/upgrade-migration-guide/upgrade_to_ees.html`;
-
const copyTemplate = useCallback(async () => {
let response;
if (template.type === 'job_template') {
@@ -92,11 +76,6 @@ function TemplateListItem({
(!summaryFields.project ||
(!summaryFields.inventory && !askInventoryOnLaunch));
- const missingExecutionEnvironment =
- template.type === 'job_template' &&
- template.custom_virtualenv &&
- !template.execution_environment;
-
const inventoryValue = (kind, id) => {
const inventorykind = kind === 'smart' ? 'smart_inventory' : 'inventory';
@@ -158,35 +137,6 @@ function TemplateListItem({
)}
- {missingExecutionEnvironment && (
-
- {t`Execution Environment Missing`}
- }
- bodyContent={
-
-
- Custom virtual environment {template.custom_virtualenv}{' '}
- must be replaced by an execution environment. For more
- information about migrating to execution environments see{' '}
-
- the documentation.
-
-
-
)}
diff --git a/awx_collection/plugins/modules/inventory_source.py b/awx_collection/plugins/modules/inventory_source.py
index 5f6c1781..a5607ba0 100644
--- a/awx_collection/plugins/modules/inventory_source.py
+++ b/awx_collection/plugins/modules/inventory_source.py
@@ -76,12 +76,6 @@
description:
- Execution Environment name, ID, or named URL to use for the source.
type: str
- custom_virtualenv:
- description:
- - Local absolute file path containing a custom Python virtualenv to use.
- - Only compatible with older versions of AWX/Controller
- - Deprecated, will be removed in the future
- type: str
overwrite:
description:
- Delete child groups and hosts not found in source.
@@ -179,7 +173,6 @@ def main():
limit=dict(),
credential=dict(),
execution_environment=dict(),
- custom_virtualenv=dict(),
organization=dict(),
overwrite=dict(type='bool'),
overwrite_vars=dict(type='bool'),
@@ -276,7 +269,6 @@ def main():
'source_vars',
'overwrite',
'overwrite_vars',
- 'custom_virtualenv',
'timeout',
'verbosity',
'update_on_launch',
diff --git a/awx_collection/plugins/modules/job_template.py b/awx_collection/plugins/modules/job_template.py
index 81fe4951..a635dc3f 100644
--- a/awx_collection/plugins/modules/job_template.py
+++ b/awx_collection/plugins/modules/job_template.py
@@ -86,12 +86,6 @@
description:
- Execution Environment name, ID, or named URL to use for the job template.
type: str
- custom_virtualenv:
- description:
- - Local absolute file path containing a custom Python virtualenv to use.
- - Only compatible with older versions of AWX/Tower
- - Deprecated, will be removed in the future
- type: str
instance_groups:
description:
- list of Instance Group names, IDs, or named URLs for this Organization to run on.
@@ -400,7 +394,6 @@ def main():
vault_credential=dict(),
credentials=dict(type='list', elements='str'),
execution_environment=dict(),
- custom_virtualenv=dict(),
instance_groups=dict(type="list", elements='str'),
forks=dict(type='int'),
limit=dict(),
@@ -538,7 +531,6 @@ def main():
'become_enabled',
'diff_mode',
'allow_simultaneous',
- 'custom_virtualenv',
'job_slice_count',
'webhook_service',
'prevent_instance_group_fallback',
diff --git a/awx_collection/plugins/modules/organization.py b/awx_collection/plugins/modules/organization.py
index 6fc406b9..3a40a891 100644
--- a/awx_collection/plugins/modules/organization.py
+++ b/awx_collection/plugins/modules/organization.py
@@ -38,12 +38,6 @@
description:
- Default Execution Environment name, ID, or named URL to use for jobs owned by the Organization.
type: str
- custom_virtualenv:
- description:
- - Local absolute file path containing a custom Python virtualenv to use.
- - Only compatible with older versions of AWX/Tower
- - Deprecated, will be removed in the future
- type: str
max_hosts:
description:
- The max hosts allowed in this organizations
@@ -122,7 +116,6 @@ def main():
new_name=dict(),
description=dict(),
default_environment=dict(),
- custom_virtualenv=dict(),
max_hosts=dict(type='int'),
instance_groups=dict(type="list", elements='str'),
notification_templates_started=dict(type="list", elements='str'),
@@ -141,7 +134,6 @@ def main():
new_name = module.params.get("new_name")
description = module.params.get('description')
default_ee = module.params.get('default_environment')
- custom_virtualenv = module.params.get('custom_virtualenv')
max_hosts = module.params.get('max_hosts')
state = module.params.get('state')
@@ -198,8 +190,6 @@ def main():
org_fields['description'] = description
if default_ee is not None:
org_fields['default_environment'] = module.resolve_name_to_id('execution_environments', default_ee)
- if custom_virtualenv is not None:
- org_fields['custom_virtualenv'] = custom_virtualenv
if max_hosts is not None:
org_fields['max_hosts'] = max_hosts
diff --git a/awx_collection/plugins/modules/project.py b/awx_collection/plugins/modules/project.py
index 2621e57a..e8d2fbd4 100644
--- a/awx_collection/plugins/modules/project.py
+++ b/awx_collection/plugins/modules/project.py
@@ -108,12 +108,6 @@
description:
- Default Execution Environment name, ID, or named URL to use for jobs relating to the project.
type: str
- custom_virtualenv:
- description:
- - Local absolute file path containing a custom Python virtualenv to use.
- - Only compatible with older versions of AWX/Tower
- - Deprecated, will be removed in the future
- type: str
organization:
description:
- Name, ID, or named URL of organization for the project.
@@ -267,7 +261,6 @@ def main():
allow_override=dict(type='bool', aliases=['scm_allow_override']),
timeout=dict(type='int', aliases=['job_timeout']),
default_environment=dict(),
- custom_virtualenv=dict(),
organization=dict(),
notification_templates_started=dict(type="list", elements='str'),
notification_templates_success=dict(type="list", elements='str'),
@@ -368,8 +361,6 @@ def main():
'scm_update_on_launch',
'scm_update_cache_timeout',
'timeout',
- 'scm_update_cache_timeout',
- 'custom_virtualenv',
'description',
'allow_override',
):
diff --git a/docs/docsite/rst/userguide/notification_parameters_supported.rst b/docs/docsite/rst/userguide/notification_parameters_supported.rst
index 5bc5dc18..44f5042b 100644
--- a/docs/docsite/rst/userguide/notification_parameters_supported.rst
+++ b/docs/docsite/rst/userguide/notification_parameters_supported.rst
@@ -13,7 +13,6 @@ This section describes the list of supported job attributes and the proper synta
- ``allow_simultaneous`` - (boolean) indicates if multiple jobs can run simultaneously from the JT associated with this job
- ``awx_node`` - (string) the instance that managed the isolated execution environment
- ``created`` - (datetime) timestamp when this job was created
-- ``custom_virtualenv`` - (string) custom virtual environment used to execute job
- ``description`` - (string) optional description of the job
- ``diff_mode`` - (boolean) if enabled, textual changes made to any templated files on the host are shown in the standard output
- ``elapsed`` - (decimal) elapsed time in seconds that the job ran
diff --git a/docs/execution_environments.md b/docs/execution_environments.md
index 8056b953..c6dfa71d 100644
--- a/docs/execution_environments.md
+++ b/docs/execution_environments.md
@@ -47,18 +47,3 @@ Jobs will use the first available execution environment in this list:
7. Any other global EE
If more than one EE fits a criteria (applies for 6 and 7), then the most recently created one will be used.
-
-## Migrating from Custom Virtual Environments
-
-If you have installed dependencies inside of custom virtual environments in
-a prior release, then have a look at this series of commands for help migrating
-dependencies out of the venvs and into EEs.
-
- - `awx-manage list_custom_venvs`
- - `awx-manage custom_venv_associations`
- - `awx-manage export_custom_venv`
-
-Follow those in order, and read the help text to see what arguments are necessary.
-
-Output from the `awx-manage export_custom_venv -q ..` command can
-be a starting point for writing an `ansible-builder` definition file.