From 4bf0ba816aae1b2c4b57ac4e2817a088b33b6639 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Fri, 22 Nov 2024 14:59:33 -0500 Subject: [PATCH 01/11] pull the correct collection plugin for the product --- awx/main/models/inventory.py | 12 ++++++++++-- .../functional/test_inventory_source_injectors.py | 3 --- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index d14e81543de4..30b2470ffb69 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -9,6 +9,7 @@ import copy import os.path from urllib.parse import urljoin +from importlib.metadata import entry_points # Django from django.conf import settings @@ -25,6 +26,7 @@ from ansible_base.lib.utils.models import prevent_search from awx_plugins.inventory.plugins import PluginFileInjector +from awx_plugins.interfaces._temporary_private_licensing_api import detect_server_product_name # AWX from awx.api.versioning import reverse @@ -1404,5 +1406,11 @@ 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 +awx_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory')} +supported_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory.supported')} +entry_points = awx_entry_points if detect_server_product_name() == 'AWX' else {**awx_entry_points, **supported_entry_points} +logger.info(entry_points) + +for entry_point_name, entry_point in entry_points.items(): + cls = entry_point.load() + InventorySourceOptions.injectors[entry_point_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 83d9360ff501..8073dc3940b4 100644 --- a/awx/main/tests/functional/test_inventory_source_injectors.py +++ b/awx/main/tests/functional/test_inventory_source_injectors.py @@ -195,9 +195,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(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) From bdcc1c4c9f2ab785a0891bd5f3a41ff27c7422c7 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Fri, 22 Nov 2024 21:44:59 -0500 Subject: [PATCH 02/11] remove unused import and logging line --- awx/main/models/inventory.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 30b2470ffb69..475ed222d28d 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -25,7 +25,6 @@ from rest_framework.exceptions import ParseError from ansible_base.lib.utils.models import prevent_search -from awx_plugins.inventory.plugins import PluginFileInjector from awx_plugins.interfaces._temporary_private_licensing_api import detect_server_product_name # AWX @@ -1409,7 +1408,6 @@ def get_absolute_url(self, request=None): awx_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory')} supported_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory.supported')} entry_points = awx_entry_points if detect_server_product_name() == 'AWX' else {**awx_entry_points, **supported_entry_points} -logger.info(entry_points) for entry_point_name, entry_point in entry_points.items(): cls = entry_point.load() From 0d5f7dca9ae3c80132006b0a3799ca09c686dec0 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Thu, 5 Dec 2024 13:39:48 -0800 Subject: [PATCH 03/11] refactor code to load entry points --- awx/main/apps.py | 4 ++++ awx/main/models/inventory.py | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index 8853a2f50dc5..2d4d293ac5b4 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -6,6 +6,7 @@ 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.main.models.inventory import InventorySourceOptions, entry_points class MainConfig(AppConfig): @@ -71,3 +72,6 @@ def ready(self): if not os.environ.get('AWX_SKIP_CREDENTIAL_TYPES_DISCOVER', None): self.load_credential_types_feature() self.load_named_url_feature() + for entry_point_name, entry_point in entry_points.items(): + cls = entry_point.load() + InventorySourceOptions.injectors[entry_point_name] = cls diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 475ed222d28d..512b485f0764 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -9,7 +9,7 @@ import copy import os.path from urllib.parse import urljoin -from importlib.metadata import entry_points +from importlib.metadata import entry_points, EntryPoint # Django from django.conf import settings @@ -1405,10 +1405,10 @@ def get_absolute_url(self, request=None): return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request) -awx_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory')} -supported_entry_points = {ep.name: ep for ep in entry_points(group='awx_plugins.inventory.supported')} -entry_points = awx_entry_points if detect_server_product_name() == 'AWX' else {**awx_entry_points, **supported_entry_points} +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}')} -for entry_point_name, entry_point in entry_points.items(): - cls = entry_point.load() - InventorySourceOptions.injectors[entry_point_name] = cls + +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]) From 18d1019dccdd8663d42262949f263c8fcb4233e4 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Thu, 5 Dec 2024 17:55:00 -0800 Subject: [PATCH 04/11] reformat method --- awx/main/apps.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index 2d4d293ac5b4..20be8ce3b3b5 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -6,7 +6,6 @@ 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.main.models.inventory import InventorySourceOptions, entry_points class MainConfig(AppConfig): @@ -60,6 +59,12 @@ def _load_credential_types_feature(self): @bypass_in_test def load_credential_types_feature(self): return self._load_credential_types_feature() + + def load_entry_points(self): + from awx.main.models.inventory import InventorySourceOptions, entry_points + 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() @@ -72,6 +77,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() - for entry_point_name, entry_point in entry_points.items(): - cls = entry_point.load() - InventorySourceOptions.injectors[entry_point_name] = cls + self.load_entry_points() From bb4203cc1929e6bf9069f98e574189056272c050 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Fri, 6 Dec 2024 11:10:54 -0500 Subject: [PATCH 05/11] lint fix --- awx/main/apps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index 20be8ce3b3b5..faa2f832cab2 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -59,9 +59,10 @@ def _load_credential_types_feature(self): @bypass_in_test def load_credential_types_feature(self): return self._load_credential_types_feature() - + def load_entry_points(self): from awx.main.models.inventory import InventorySourceOptions, entry_points + for entry_point_name, entry_point in entry_points.items(): cls = entry_point.load() InventorySourceOptions.injectors[entry_point_name] = cls From ee928ae1fa1c4e863cf5fc3391c9c52306ff9458 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Fri, 6 Dec 2024 14:50:11 -0500 Subject: [PATCH 06/11] renames for clarity and a lint fix --- awx/main/apps.py | 8 ++++---- awx/main/models/inventory.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index faa2f832cab2..d1c6eda15163 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -60,10 +60,10 @@ def _load_credential_types_feature(self): def load_credential_types_feature(self): return self._load_credential_types_feature() - def load_entry_points(self): - from awx.main.models.inventory import InventorySourceOptions, entry_points + def load_inventory_plugins(self): + from awx.main.models.inventory import InventorySourceOptions, inv_entry_points - for entry_point_name, entry_point in entry_points.items(): + for entry_point_name, entry_point in inv_entry_points.items(): cls = entry_point.load() InventorySourceOptions.injectors[entry_point_name] = cls @@ -78,4 +78,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_entry_points() + self.load_inventory_plugins() diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 512b485f0764..457bf3a46af4 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -1411,4 +1411,4 @@ def _load_all_entry_points_for(entry_point_subsections: list[str], /) -> dict[st 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]) +inv_entry_points = _load_all_entry_points_for(['inventory', *extra_entry_point_groups]) From 912e45028a7d197e7f8d90b299d9b11758c34b12 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Mon, 9 Dec 2024 10:57:15 -0500 Subject: [PATCH 07/11] move function to utils --- awx/main/models/inventory.py | 6 ------ awx/main/utils/common.py | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 457bf3a46af4..4a852411bab0 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -9,7 +9,6 @@ import copy import os.path from urllib.parse import urljoin -from importlib.metadata import entry_points, EntryPoint # Django from django.conf import settings @@ -1404,11 +1403,6 @@ class Meta: def get_absolute_url(self, request=None): return reverse('api:inventory_script_detail', kwargs={'pk': self.pk}, request=request) - -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}')} - - is_awx = detect_server_product_name() == 'AWX' extra_entry_point_groups = () if is_awx else ('inventory.supported',) inv_entry_points = _load_all_entry_points_for(['inventory', *extra_entry_point_groups]) diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index f283b8ec90ac..d20049c5900e 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 @@ -1234,3 +1235,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}')} From ddc521cda715fb16938694d736a6d213ccc4837b Mon Sep 17 00:00:00 2001 From: jessicamack Date: Mon, 9 Dec 2024 11:14:37 -0500 Subject: [PATCH 08/11] move the rest of the code into load_inventory_plugins --- awx/main/apps.py | 12 +++++++++--- awx/main/models/inventory.py | 5 ----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index d1c6eda15163..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' @@ -61,9 +63,13 @@ def load_credential_types_feature(self): return self._load_credential_types_feature() def load_inventory_plugins(self): - from awx.main.models.inventory import InventorySourceOptions, inv_entry_points + 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 inv_entry_points.items(): + for entry_point_name, entry_point in entry_points.items(): cls = entry_point.load() InventorySourceOptions.injectors[entry_point_name] = cls diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 4a852411bab0..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.interfaces._temporary_private_licensing_api import detect_server_product_name # 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) - -is_awx = detect_server_product_name() == 'AWX' -extra_entry_point_groups = () if is_awx else ('inventory.supported',) -inv_entry_points = _load_all_entry_points_for(['inventory', *extra_entry_point_groups]) From 9a2f15b17eca9d1318b2615ffcb3da2d0953a201 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Mon, 9 Dec 2024 12:05:15 -0500 Subject: [PATCH 09/11] temp - confirm that tests will pass --- requirements/requirements_git.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements_git.txt b/requirements/requirements_git.txt index f5aaccb8e3bd..92854f00f1b8 100644 --- a/requirements/requirements_git.txt +++ b/requirements/requirements_git.txt @@ -2,5 +2,5 @@ git+https://github.com/ansible/system-certifi.git@devel#egg=certifi # Remove pbr from requirements.in when moving ansible-runner to requirements.in git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner django-ansible-base @ git+https://github.com/ansible/django-ansible-base@devel#egg=django-ansible-base[rest_filters,jwt_consumer,resource_registry,rbac] -awx-plugins-core @ git+https://git@github.com/ansible/awx-plugins.git@devel#egg=awx-plugins-core +awx-plugins-core @ git+https://git@github.com/jessicamack/awx-plugins.git@add-entry-points#egg=awx-plugins-core awx_plugins.interfaces @ git+https://github.com/ansible/awx_plugins.interfaces.git From 8f4e49eac25bea71c02628c03eeca9a3958a9100 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Mon, 9 Dec 2024 15:02:13 -0500 Subject: [PATCH 10/11] revert change caught in merge --- requirements/requirements_git.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements_git.txt b/requirements/requirements_git.txt index 92854f00f1b8..058b1a59e6dc 100644 --- a/requirements/requirements_git.txt +++ b/requirements/requirements_git.txt @@ -1,6 +1,6 @@ git+https://github.com/ansible/system-certifi.git@devel#egg=certifi # Remove pbr from requirements.in when moving ansible-runner to requirements.in git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner -django-ansible-base @ git+https://github.com/ansible/django-ansible-base@devel#egg=django-ansible-base[rest_filters,jwt_consumer,resource_registry,rbac] +django-ansible-base @ git+https://github.com/ansible/django-ansible-base@devel#egg=django-ansible-base[rest-filters,jwt_consumer,resource-registry,rbac] awx-plugins-core @ git+https://git@github.com/jessicamack/awx-plugins.git@add-entry-points#egg=awx-plugins-core awx_plugins.interfaces @ git+https://github.com/ansible/awx_plugins.interfaces.git From 8017020fe13f0d6f9e32ebb3a33690a56995d833 Mon Sep 17 00:00:00 2001 From: jessicamack Date: Tue, 10 Dec 2024 12:21:08 -0500 Subject: [PATCH 11/11] change back requirement the related PR has been merged --- requirements/requirements_git.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements_git.txt b/requirements/requirements_git.txt index 058b1a59e6dc..9818bb7f529b 100644 --- a/requirements/requirements_git.txt +++ b/requirements/requirements_git.txt @@ -2,5 +2,5 @@ git+https://github.com/ansible/system-certifi.git@devel#egg=certifi # Remove pbr from requirements.in when moving ansible-runner to requirements.in git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner django-ansible-base @ git+https://github.com/ansible/django-ansible-base@devel#egg=django-ansible-base[rest-filters,jwt_consumer,resource-registry,rbac] -awx-plugins-core @ git+https://git@github.com/jessicamack/awx-plugins.git@add-entry-points#egg=awx-plugins-core +awx-plugins-core @ git+https://git@github.com/ansible/awx-plugins.git@devel#egg=awx-plugins-core awx_plugins.interfaces @ git+https://github.com/ansible/awx_plugins.interfaces.git