diff --git a/awx/main/apps.py b/awx/main/apps.py index 8853a2f50dc5..3d9896374743 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -2,11 +2,13 @@ from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ -from awx.main.utils.common import bypass_in_test +from awx.main.utils.common import bypass_in_test, load_all_entry_points_for from awx.main.utils.migration import is_database_synchronized from awx.main.utils.named_url_graph import _customize_graph, generate_graph from awx.conf import register, fields +from awx_plugins.interfaces._temporary_private_licensing_api import detect_server_product_name + class MainConfig(AppConfig): name = 'awx.main' @@ -60,6 +62,17 @@ def _load_credential_types_feature(self): def load_credential_types_feature(self): return self._load_credential_types_feature() + def load_inventory_plugins(self): + from awx.main.models.inventory import InventorySourceOptions + + is_awx = detect_server_product_name() == 'AWX' + extra_entry_point_groups = () if is_awx else ('inventory.supported',) + entry_points = load_all_entry_points_for(['inventory', *extra_entry_point_groups]) + + for entry_point_name, entry_point in entry_points.items(): + cls = entry_point.load() + InventorySourceOptions.injectors[entry_point_name] = cls + def ready(self): super().ready() @@ -71,3 +84,4 @@ def ready(self): if not os.environ.get('AWX_SKIP_CREDENTIAL_TYPES_DISCOVER', None): self.load_credential_types_feature() self.load_named_url_feature() + self.load_inventory_plugins() diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index d14e81543de4..7c8758f40b4f 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -24,7 +24,6 @@ from rest_framework.exceptions import ParseError from ansible_base.lib.utils.models import prevent_search -from awx_plugins.inventory.plugins import PluginFileInjector # AWX from awx.api.versioning import reverse @@ -1402,7 +1401,3 @@ class Meta: def get_absolute_url(self, request=None): return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request) - - -for cls in PluginFileInjector.__subclasses__(): - InventorySourceOptions.injectors[cls.__name__] = cls diff --git a/awx/main/tests/functional/test_inventory_source_injectors.py b/awx/main/tests/functional/test_inventory_source_injectors.py index c7ab3d440c82..4c01c0a4fba7 100644 --- a/awx/main/tests/functional/test_inventory_source_injectors.py +++ b/awx/main/tests/functional/test_inventory_source_injectors.py @@ -196,9 +196,6 @@ def create_reference_data(source_dir, env, content): @pytest.mark.django_db @pytest.mark.parametrize('this_kind', discover_available_cloud_provider_plugin_names()) def test_inventory_update_injected_content(product_name, this_kind, inventory, fake_credential_factory, mock_me): - if this_kind.endswith('_supported'): - this_kind = this_kind[:-10] - ExecutionEnvironment.objects.create(name='Control Plane EE', managed=True) ExecutionEnvironment.objects.create(name='Default Job EE', managed=False) diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 8b482f6ed057..af8cf2212e3c 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -19,6 +19,7 @@ import tempfile import functools from importlib.metadata import version as _get_version +from importlib.metadata import entry_points, EntryPoint # Django from django.core.exceptions import ObjectDoesNotExist, FieldDoesNotExist @@ -1248,3 +1249,7 @@ def _new_func(*args, **kwargs): def unified_job_class_to_event_table_name(job_class): return f'main_{job_class().event_class.__name__.lower()}' + + +def load_all_entry_points_for(entry_point_subsections: list[str], /) -> dict[str, EntryPoint]: + return {ep.name: ep for entry_point_category in entry_point_subsections for ep in entry_points(group=f'awx_plugins.{entry_point_category}')}