foreman_ansible_director 0.3.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/app/controllers/foreman_ansible_director/api/v2/ansible_content_controller.rb +101 -4
  4. data/app/controllers/foreman_ansible_director/api/v2/ansible_director_api_controller.rb +1 -0
  5. data/app/controllers/foreman_ansible_director/api/v2/ansible_variable_overrides_controller.rb +122 -0
  6. data/app/controllers/foreman_ansible_director/api/v2/ansible_variables_controller.rb +49 -0
  7. data/app/controllers/foreman_ansible_director/api/v2/assignments_controller.rb +132 -0
  8. data/app/controllers/foreman_ansible_director/api/v2/execution_environments_controller.rb +86 -0
  9. data/app/controllers/foreman_ansible_director/api/v2/lifecycle_environment_paths_controller.rb +94 -0
  10. data/app/controllers/foreman_ansible_director/api/v2/lifecycle_environments_controller.rb +177 -0
  11. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/bulk/destroy.rb +5 -2
  12. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/destroy.rb +58 -54
  13. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/destroy_providers/galaxy/destroy_full.rb +43 -0
  14. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/destroy_providers/galaxy/destroy_partial.rb +53 -0
  15. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/destroy_providers/git/destroy_full.rb +34 -0
  16. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/destroy_providers/git/destroy_partial.rb +41 -0
  17. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/extract_variables.rb +27 -7
  18. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import.rb +11 -4
  19. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/galaxy/import_collection.rb +16 -1
  20. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/galaxy/rescue.rb +62 -0
  21. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/galaxy/update.rb +2 -0
  22. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/galaxy/update_collection.rb +13 -15
  23. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/git/import_collection.rb +16 -1
  24. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/import_providers/git/rescue.rb +63 -0
  25. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/index/dynamic/index_git_collection.rb +3 -3
  26. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/index/index_git_collection.rb +41 -23
  27. data/app/lib/foreman_ansible_director/actions/ansible_content_unit/index/index_static.rb +83 -57
  28. data/app/lib/foreman_ansible_director/actions/base/ansible_director_action.rb +4 -3
  29. data/app/lib/foreman_ansible_director/actions/proxy/build_execution_environment.rb +12 -1
  30. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/distribution/create.rb +40 -16
  31. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/distribution/destroy.rb +23 -8
  32. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/remote/collection/create.rb +9 -3
  33. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/remote/collection/destroy.rb +23 -9
  34. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/remote/git/create.rb +8 -3
  35. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/remote/git/destroy.rb +33 -5
  36. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/remote/role/create.rb +1 -0
  37. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/repository/create.rb +12 -4
  38. data/app/lib/foreman_ansible_director/actions/pulp3/ansible/repository/destroy.rb +22 -8
  39. data/app/lib/foreman_ansible_director/actions/remote_execution/Provider/ansible_navigator_provider.rb +16 -8
  40. data/app/lib/foreman_ansible_director/actions/remote_execution/Provider/ansible_script_provider.rb +5 -5
  41. data/app/lib/foreman_ansible_director/actions/rescue/ansible_content_unit/common/cleanup_check.rb +35 -0
  42. data/app/lib/foreman_ansible_director/ansible_content/ansible_content_helpers.rb +33 -26
  43. data/app/lib/foreman_ansible_director/generators/content_generator.rb +18 -6
  44. data/app/lib/foreman_ansible_director/generators/inventory_generator.rb +1 -0
  45. data/app/lib/foreman_ansible_director/parsers/proxy/dynflow/task_status_parser.rb +13 -0
  46. data/app/models/foreman_ansible_director/ansible_collection.rb +2 -2
  47. data/app/models/foreman_ansible_director/concerns/host_extensions.rb +5 -6
  48. data/app/models/foreman_ansible_director/concerns/hostgroup_extensions.rb +7 -1
  49. data/app/models/foreman_ansible_director/content_unit.rb +9 -3
  50. data/app/models/foreman_ansible_director/execution_environment.rb +9 -5
  51. data/app/models/foreman_ansible_director/lifecycle_environment.rb +9 -0
  52. data/app/models/foreman_ansible_director/lifecycle_environment_path.rb +1 -23
  53. data/app/overrides/create_host_ansible_tab.rb +12 -12
  54. data/app/services/foreman_ansible_director/ansible_director_proxy_selector.rb +20 -0
  55. data/app/services/foreman_ansible_director/ansible_report_importer.rb +0 -3
  56. data/app/services/foreman_ansible_director/cert/certs.rb +10 -2
  57. data/app/services/foreman_ansible_director/content_service.rb +35 -29
  58. data/app/services/foreman_ansible_director/execution_environment_service.rb +32 -20
  59. data/app/services/foreman_ansible_director/lifecycle_environment_path_service.rb +5 -0
  60. data/app/services/foreman_ansible_director/lifecycle_environment_service.rb +19 -2
  61. data/app/services/foreman_ansible_director/proxy/base_client.rb +9 -5
  62. data/app/services/foreman_ansible_director/pulp3/base_client.rb +14 -5
  63. data/app/views/foreman_ansible_director/ansible_content/_ansible_content_tab_content.html.erb +3 -3
  64. data/app/views/foreman_ansible_director/ansible_content/ansible_content/_ansible_content_tab_content.html.erb +3 -1
  65. data/app/views/foreman_ansible_director/api/v2/execution_environments/index.json.rabl +1 -1
  66. data/app/views/foreman_ansible_director/job_templates/apply_ansible_configuration.erb +12 -0
  67. data/app/views/foreman_ansible_director/job_templates/run_playbook-ansible_default.erb +3 -3
  68. data/config/routes.rb +3 -0
  69. data/db/migrate/20260316000001_ansible_director_schema.rb +278 -0
  70. data/db/seeds.d/62_ansible_director_proxy_feature.rb +6 -0
  71. data/lib/foreman_ansible_director/constants.rb +7 -1
  72. data/lib/foreman_ansible_director/register.rb +104 -37
  73. data/lib/foreman_ansible_director/remote_execution.rb +3 -10
  74. data/locale/en/foreman_ansible_director.po +257 -2
  75. data/locale/foreman_ansible_director.pot +460 -8
  76. data/locale/gemspec.rb +2 -1
  77. data/package.json +16 -5
  78. data/test/factories/ansible_content_factory.rb +2 -1
  79. data/test/services/unit/execution_environment_service_test.rb +6 -0
  80. data/tsconfig.json +1 -1
  81. data/webpack/components/ansible_content/AnsibleContentPage.tsx +4 -25
  82. data/webpack/components/ansible_content/components/AnsibleContentTable.tsx +8 -4
  83. data/webpack/components/ansible_content/components/AnsibleContentTablePrimaryRow.tsx +10 -9
  84. data/webpack/components/ansible_content/components/AnsibleContentTableSecondaryRow.tsx +19 -14
  85. data/webpack/components/ansible_content/components/AnsibleContentTableWrapper.tsx +93 -46
  86. data/webpack/components/ansible_content/components/AnsibleContentWizard/AnsibleContentWizard.tsx +19 -15
  87. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/ProviderSelectionStep.tsx +40 -27
  88. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/DefaultFooter.tsx +4 -0
  89. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/FinishFooter.tsx +5 -4
  90. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/GalaxyContentUnitInput.tsx +18 -91
  91. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/GitContentUnitInput.tsx +53 -36
  92. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/components/GitRefInput.tsx +9 -2
  93. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/components/IdentifierInput.tsx +121 -0
  94. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/components/VersionInput.tsx +13 -9
  95. data/webpack/components/ansible_content/components/AnsibleContentWizard/components/components/components/__test__/GitRefInput.test.tsx +103 -0
  96. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/AnsibleVariablesOverview.tsx +8 -5
  97. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/AnsibleVariablesSelector.tsx +163 -232
  98. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/VariableManagementModal/OverrideCard.tsx +6 -2
  99. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/VariableManagementModal/OverrideManagementModal.tsx +53 -26
  100. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/VariableManagementModal/OverridesTabContent.tsx +33 -1
  101. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/VariableManagementModal/VariableManagementModalContent.tsx +66 -11
  102. data/webpack/components/ansible_content/components/AnsibleVariablesOverview/VariableManagementModal/VariableManagementModalWrapper.tsx +6 -3
  103. data/webpack/components/ansible_environments/AnsibleEnvironmentsPage.tsx +8 -2
  104. data/webpack/components/ansible_environments/components/AnsibleLcePathIndexWrapper.tsx +32 -6
  105. data/webpack/components/ansible_environments/components/components/AnsibleExecutionEnvSelectionModal.tsx +2 -2
  106. data/webpack/components/ansible_environments/components/components/AnsibleExecutionEnvSelectionModalWrapper.tsx +6 -1
  107. data/webpack/components/ansible_environments/components/components/AnsibleLceComponent.tsx +24 -5
  108. data/webpack/components/ansible_environments/components/components/AnsibleLceComponentHeaderActions.tsx +10 -12
  109. data/webpack/components/ansible_environments/components/components/AnsibleLceComponentWrapper.tsx +4 -1
  110. data/webpack/components/ansible_environments/components/components/AnsibleLcePathComponent.tsx +30 -20
  111. data/webpack/components/ansible_environments/components/components/AnsibleLcePathComponentHeaderActions.tsx +6 -4
  112. data/webpack/components/ansible_environments/components/components/AnsibleLcePathEmptyState.tsx +2 -2
  113. data/webpack/components/ansible_environments/components/components/AnsibleLibraryOverview.tsx +16 -5
  114. data/webpack/components/ansible_execution_environments/AnsibleExecutionEnvPage.tsx +16 -9
  115. data/webpack/components/ansible_execution_environments/ExecutionEnvGrid.tsx +31 -4
  116. data/webpack/components/ansible_execution_environments/components/ContentUnitModal.tsx +6 -3
  117. data/webpack/components/ansible_execution_environments/components/ExecutionEnvCard.tsx +27 -119
  118. data/webpack/components/ansible_execution_environments/components/ExecutionEnvCardHeaderActions.tsx +137 -51
  119. data/webpack/components/ansible_execution_environments/components/ExecutionEnvCreateCard.tsx +61 -135
  120. data/webpack/components/ansible_execution_environments/components/ExecutionEnvEditCard.tsx +208 -0
  121. data/webpack/components/ansible_execution_environments/components/ExecutionEnvGridWrapper.tsx +28 -11
  122. data/webpack/components/ansible_execution_environments/components/components/ContentUnitSelectorWrapper.tsx +6 -1
  123. data/webpack/components/ansible_execution_environments/components/components/DropdownEditable.tsx +19 -14
  124. data/webpack/components/ansible_execution_environments/components/components/TextInputEditable.tsx +3 -0
  125. data/webpack/components/ansible_execution_environments/components/components/__test__/DropdownEditable.test.tsx +66 -0
  126. data/webpack/components/ansible_execution_environments/components/components/components/ContentUnitSelector.tsx +51 -23
  127. data/webpack/components/common/AdContextWrapper.tsx +3 -1
  128. data/webpack/components/common/Page.tsx +59 -59
  129. data/webpack/components/common/PermittedButton.tsx +10 -2
  130. data/webpack/components/common/__test__/Page.test.tsx +29 -0
  131. data/webpack/components/common/__test__/PermittedButton.test.tsx +99 -0
  132. data/webpack/components/extensions/components/LifecycleEnvComponentWrapper.tsx +3 -1
  133. data/webpack/components/extensions/create_host_tab/CreateHostAnsibleContentTab.tsx +1 -1
  134. data/webpack/components/extensions/host_details/HostDetailsLceCard/HostDetailsLceCard.tsx +7 -5
  135. data/webpack/components/extensions/host_details/HostDetailsLceCard/components/HostDetailsLceCardHeaderActions.tsx +5 -3
  136. data/webpack/components/extensions/host_details/HostDetailsLceCard/components/LcePathSelector.tsx +7 -5
  137. data/webpack/components/extensions/host_details/HostDetailsLceCard/components/LcePathSelectorWrapper.tsx +1 -1
  138. data/webpack/components/extensions/host_details/HostDetailsTab/HostDetailsTab.tsx +4 -3
  139. data/webpack/components/extensions/host_details/HostDetailsTab/components/AssignmentComponent.tsx +5 -4
  140. data/webpack/components/extensions/host_details/HostDetailsTab/components/AssignmentComponentWrapper.tsx +2 -1
  141. data/webpack/components/extensions/host_details/HostDetailsTab/components/LceAssignmentSelector.tsx +18 -8
  142. data/webpack/components/extensions/host_details/HostDetailsTab/components/LceContentList.tsx +1 -1
  143. data/webpack/components/extensions/host_details/HostDetailsTab/components/LceContentListWrapper.tsx +2 -1
  144. data/webpack/components/extensions/host_details/HostDetailsTab/components/OverrideGridWrapper.tsx +2 -1
  145. data/webpack/global_index.js +5 -4
  146. data/webpack/helpers/components/__test__/ConfirmationModal.test.tsx +124 -0
  147. data/webpack/helpers/typeGuards/executionEnvTypeGuards.ts +8 -0
  148. data/webpack/test_setup.js +2 -0
  149. data/webpack/types/AnsibleExecutionEnvTypes.d.ts +6 -2
  150. data/webpack/types/foremanReact/common/i18n.d.ts +1 -1
  151. data/webpack/types/foremanReact/components/PF4/TableIndexPage/Table/TableHooks.d.ts +6 -0
  152. data/webpack/types/foremanReact/components/SearchBar/index.d.ts +29 -0
  153. metadata +34 -33
  154. data/app/views/foreman_ansible_director/job_templates/ansible_collections_-_install_from_galaxy.erb +0 -28
  155. data/app/views/foreman_ansible_director/job_templates/ansible_roles_-_ansible_default.erb +0 -28
  156. data/app/views/foreman_ansible_director/job_templates/ansible_roles_-_install_from_galaxy.erb +0 -32
  157. data/app/views/foreman_ansible_director/job_templates/ansible_roles_-_install_from_git.erb +0 -31
  158. data/app/views/foreman_ansible_director/job_templates/ansible_windows_updates.erb +0 -160
  159. data/app/views/foreman_ansible_director/job_templates/capsule_update_-_ansible_default.erb +0 -73
  160. data/app/views/foreman_ansible_director/job_templates/capsule_upgrade_-_ansible_default.erb +0 -79
  161. data/app/views/foreman_ansible_director/job_templates/convert_to_rhel.erb +0 -79
  162. data/app/views/foreman_ansible_director/job_templates/download_and_execute_script.erb +0 -34
  163. data/app/views/foreman_ansible_director/job_templates/puppet_run_once_-_ansible_default.erb +0 -25
  164. data/app/views/foreman_ansible_director/job_templates/run_ansible_roles.erb +0 -12
  165. data/app/views/foreman_ansible_director/job_templates/service_action_-_enable_web_console.erb +0 -16
  166. data/app/views/foreman_ansible_director/job_templates/smart_proxy_upgrade_-_ansible_default.erb +0 -59
  167. data/db/migrate/20250601000004_create_ansible_schema.rb +0 -122
  168. data/db/migrate/20250606000001_add_lifecycle_envs.rb +0 -118
  169. data/db/migrate/20250806000001_add_hash_to_ee.rb +0 -7
  170. data/db/migrate/20250815000001_add_assignments.rb +0 -14
  171. data/db/migrate/20250930000001_extend_lookup_keys.rb +0 -7
  172. data/db/migrate/20251011000001_add_lce_to_hg.rb +0 -7
  173. data/db/migrate/20251202000001_add_child_to_lce.rb +0 -7
  174. data/db/migrate/20260107000001_git_cu.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c0d7d2f9058b198146ff2d5ab9f7bb9ec169a35bec93cb4f9158275d7dd49bc
4
- data.tar.gz: da14ad425b11842fddc2b3c3b2e41f9bc3fce94e456c0b498963f141192696ab
3
+ metadata.gz: ad5a385698810d3de3c2a7807d683ef2deacc5e12d3ec40d340ca2b3ce13b512
4
+ data.tar.gz: 396708fd055a23d192e4355d08fe5a76396869d8ec36785c4951cc9572268e13
5
5
  SHA512:
6
- metadata.gz: '092293405b4e00629435adf177d7cb222e2aa20596cd17640ad5bc2f7e8d1da03f88daa5d5d091949830a9ed7dbc69c78a526803f1570e8176ad338240cbe43c'
7
- data.tar.gz: 19698be3a587b5b73959befe17b2b5fa674ebfb416d5628483ad73472ab80e7a8e9fc80ee3c623d80d4ebeac842f1e5122ee5a48b7e92596bc77879ec7d61837
6
+ metadata.gz: de0b152a577bfc6cd2f45bb43ee16d456fbd15146510fe6429158cf05a2bad4d6ed1f963131e12e27fd74524bafacb85fb2737ab2c3886be277632889d827ead
7
+ data.tar.gz: 28b6076faaae3c7b027cfe31528d5ea650e88cd0bd682a93d7feca85ae7660a976e628c3d5aac0334fde8dc6b420911873249d9716f2d3fab3e20424e1ec606b
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Foreman Ansible Director is a foreman plugin integrating Ansible into Foreman.
4
4
 
5
5
  ## Current Status
6
- > [!WARNING]
6
+ > [!WARNING]
7
7
  > At the time of publishing (2026-02-01), this plugin is in an intermediate state.
8
8
  > It is not ready for production use.
9
9
 
@@ -20,9 +20,9 @@ Breaking changes are expected until version 1.0.0 is reached.
20
20
  - Importing and deletion of Ansible content can be done via the Foreman web-UI
21
21
  - Ansible content can be imported from Ansible Galaxy and Git repositories
22
22
  - A dedicated lifecycle management system for Ansible content allows promotion of configurations along a path such as `Development` -> `Test` -> `Production` similar to Katello lifecycle environments.
23
- - Ansible and its dependencies are encapsulated in execution environments, which are used to run Ansible content.
24
- - Use of different ansible-core versions through execution environments.
25
- - Automatic provisioning of execution environments and Ansible content based on user-defined Ansible configurations.
23
+ - Ansible and its dependencies are encapsulated in Execution Environments, which are used to run Ansible content.
24
+ - Use of different ansible-core versions through Execution Environments.
25
+ - Automatic provisioning of Execution Environments and Ansible content based on user-defined Ansible configurations.
26
26
  - Unified interface (REST API) for both UI and external tools.
27
27
 
28
28
 
@@ -4,11 +4,57 @@ module ForemanAnsibleDirector
4
4
  module Api
5
5
  module V2
6
6
  class AnsibleContentController < AnsibleDirectorApiController
7
- before_action :find_organization, only: %i[create_units destroy_units]
7
+ before_action :find_organization, only: %i[create_units]
8
8
  before_action :find_optional_organization, only: %i[index]
9
9
 
10
- # TODO: APIDOC
10
+ resource_description { resource_id 'AD Ansible Content' }
11
11
 
12
+ # region ApiDoc: POST /api/v2/ansible_director/ansible_content
13
+ api :POST, '/v2/ansible_director/ansible_content', N_('Import Ansible content units')
14
+ param :organization_id, :number, desc: N_('Organization identifier.'), required: true
15
+ param :units, Array, desc: N_('Array of content units to import.'), required: true do
16
+ param :unit_name,
17
+ String,
18
+ desc: N_('Identifier of the content unit.'),
19
+ example: N_('manala.roles'),
20
+ required: true
21
+ param :unit_type,
22
+ %w[role collection],
23
+ desc: N_('Type of the content unit.'),
24
+ example: N_('collection'),
25
+ required: true
26
+ param :unit_source_type,
27
+ %w[galaxy git],
28
+ desc: N_('Source type of the content unit.'),
29
+ example: N_('galaxy'),
30
+ required: true
31
+ param :unit_source,
32
+ String,
33
+ desc: N_('Source URL or path for the content unit (e.g., Galaxy URL or Git repo).'),
34
+ example: N_('https://galaxy.ansible.com'),
35
+ required: true
36
+ param :unit_versions,
37
+ Array,
38
+ desc: N_('An array of versions to import (e.g., ["1.0.0", "2.0.0"]).'),
39
+ example: %w[1.0.0 2.0.0],
40
+ required: true
41
+ end
42
+ # TRANSLATORS: ApiDoc, do not translate!
43
+ example <<~EXAMPLE
44
+ {
45
+ "organization_id": 1,
46
+ "units": [
47
+ {
48
+ "unit_name": "manala.roles",
49
+ "unit_type": "collection",
50
+ "unit_source_type": "galaxy",
51
+ "unit_source": "https://galaxy.ansible.com",
52
+ "unit_versions": ["5.2.0"]
53
+ }
54
+ ]
55
+ }
56
+ EXAMPLE
57
+ # endregion
12
58
  def create_units
13
59
  resolved = ::ForemanAnsibleDirector::AnsibleContent::AnsibleContentHelpers.resolve_import_payload(
14
60
  params[:units]
@@ -20,6 +66,11 @@ module ForemanAnsibleDirector
20
66
  )
21
67
  end
22
68
 
69
+ # region ApiDoc: GET /api/v2/ansible_director/ansible_content
70
+ api :GET, '/v2/ansible_director/ansible_content', N_('List Ansible content units')
71
+ param :organization_id, :number, desc: N_('Organization identifier'), required: false
72
+ param_group :search_and_pagination, ::Api::V2::BaseController
73
+ # endregion
23
74
  def index
24
75
  scope = resource_scope_for_index
25
76
  @ansible_content_units = if @organization
@@ -29,22 +80,68 @@ module ForemanAnsibleDirector
29
80
  end
30
81
  end
31
82
 
83
+ # region ApiDoc: GET /api/v2/ansible_director/ansible_content/:content_unit_id/versions/:content_unit_version_id
84
+ api :GET, '/v2/ansible_director/ansible_content/:content_unit_id/versions/:content_unit_version_id',
85
+ N_('Show details of a specific Ansible content unit version')
86
+ # endregion
32
87
  def version_detail
33
88
  @content_unit_version = ::ForemanAnsibleDirector::ContentUnitVersion.find_by(id: params[:version])
34
89
  end
35
90
 
36
91
  # TODO: This needs to check and invalidate built EEs
92
+ # region ApiDoc: DELETE /api/v2/ansible_director/ansible_content
93
+ api :DELETE, '/v2/ansible_director/ansible_content',
94
+ N_('Destroy previously imported Ansible content units.')
95
+ param :units, Array, desc: N_('Array of content units to destroy.'), required: true do
96
+ param :unit_id, :number, desc: N_('ID of the Ansible content unit to destroy.'), required: true
97
+ # TRANSLATORS: ApiDoc, do not translate!
98
+ param :unit_version_ids, Array,
99
+ desc: <<~DESC,
100
+ Array of version IDs to delete.
101
+ Optional: If not supplied, every version of the given content unit will be deleted.
102
+ DESC
103
+ required: false
104
+ end
105
+ # TRANSLATORS: ApiDoc, do not translate!
106
+ example <<~EXAMPLE
107
+ {
108
+ "units": [
109
+ {
110
+ "unit_id": 42,
111
+ "unit_version_ids": [101, 102]
112
+ },
113
+ {
114
+ "unit_id": 43,
115
+ "unit_version_ids": [105]
116
+ }
117
+ ]
118
+ }
119
+ EXAMPLE
120
+ # endregion
37
121
  def destroy_units
38
122
  resolved = ::ForemanAnsibleDirector::AnsibleContent::AnsibleContentHelpers.resolve_destroy_payload(
39
- params[:units]
123
+ destroy_params
40
124
  )
41
125
  @bulk_destroy_task =
42
126
  ForemanTasks.sync_task(::ForemanAnsibleDirector::Actions::AnsibleContentUnit::Bulk::Destroy,
43
- resolved_content_units: resolved, organization_id: @organization.id)
127
+ resolved_content_units: resolved)
128
+ end
129
+
130
+ def model_of_controller
131
+ resource_class
44
132
  end
45
133
 
46
134
  private
47
135
 
136
+ def destroy_params
137
+ params.require(:units).map do |unit|
138
+ unit.permit(
139
+ :unit_id,
140
+ unit_version_ids: []
141
+ )
142
+ end
143
+ end
144
+
48
145
  def validate_requirements_payload
49
146
  # TODO: Grammar
50
147
  params.require(:requirements_file)
@@ -5,6 +5,7 @@ module ForemanAnsibleDirector
5
5
  module V2
6
6
  class AnsibleDirectorApiController < ::Api::V2::BaseController
7
7
  include ::Api::Version2
8
+ include ::Foreman::Controller::AutoCompleteSearch
8
9
 
9
10
  def find_organization
10
11
  @organization = Organization.current || find_optional_organization
@@ -7,6 +7,30 @@ module ForemanAnsibleDirector
7
7
  before_action :find_variable, only: %i[create]
8
8
  before_action :find_override, only: %i[update destroy]
9
9
 
10
+ resource_description { resource_id 'AD Ansible Variable Overrides' }
11
+
12
+ # region ApiDoc: GET /api/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides
13
+ api :GET, '/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides',
14
+ N_('List overrides for a target')
15
+ # TRANSLATORS: ApiDoc, do not translate!
16
+ description <<~DESC
17
+ List override values associated with a given target (host or hostgroup).
18
+ Overrides are matched at runtime based on the predefined hierarchy: Default -> Hostgroup -> Host.
19
+ DESC
20
+ param :target,
21
+ %w[HOST HOSTGROUP],
22
+ desc: N_('Type of the target entity.'),
23
+ required: true
24
+ param :target_id,
25
+ :number,
26
+ desc: N_('ID of the target entity.'),
27
+ required: true
28
+ param :include_overridable,
29
+ [true, false],
30
+ desc: N_('Whether to include overridable variables in the response.'),
31
+ example: false,
32
+ required: false
33
+ # endregion
10
34
  def index_for_target
11
35
  target = ::ForemanAnsibleDirector::AssignmentService.find_target(
12
36
  target_type: params[:target],
@@ -17,6 +41,46 @@ module ForemanAnsibleDirector
17
41
  include_overridable: include_overridable
18
42
  end
19
43
 
44
+ # region ApiDoc: POST /api/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides
45
+ api :POST, '/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides',
46
+ N_('Create an override for an Ansible variable')
47
+ # TRANSLATORS: ApiDoc, do not translate!
48
+ description <<~DESC
49
+ Create a new override rule for the specified Ansible variable.
50
+ Overrides allow customizing the variable value for specific hosts, hostgroups, or other matchers.
51
+ DESC
52
+ param :ansible_variable_id,
53
+ :number,
54
+ desc: N_('ID of the Ansible variable to override.'),
55
+ required: true
56
+ param :override, Hash, desc: N_('Override definition'), required: true do
57
+ param :value,
58
+ String,
59
+ desc: N_('Override value (must be valid JSON when the variable type is `json`, `array`, or `hash`).'),
60
+ example: '192.168.1.1',
61
+ required: true
62
+ param :matcher,
63
+ %w[fqdn hostgroup],
64
+ desc: N_('Matcher type.'),
65
+ example: 'fqdn',
66
+ required: true
67
+ param :matcher_value,
68
+ String,
69
+ desc: N_('Value for the matcher (e.g., "myhost.example.com").'),
70
+ example: 'myhost.example.com',
71
+ required: true
72
+ end
73
+ # TRANSLATORS: ApiDoc, do not translate!
74
+ example <<~EXAMPLE
75
+ {
76
+ "override": {
77
+ "value": "prod-ntp.internal",
78
+ "matcher": "fqdn",
79
+ "matcher_value": "prod-web-01.example.com"
80
+ }
81
+ }
82
+ EXAMPLE
83
+ # endregion
20
84
  def create
21
85
  override = override_params
22
86
  ::ForemanAnsibleDirector::VariableService.create_override(
@@ -27,6 +91,48 @@ module ForemanAnsibleDirector
27
91
  )
28
92
  end
29
93
 
94
+ # region ApiDoc: PUT /api/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides/:id
95
+ api :PUT, '/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides/:id', N_('Update an override')
96
+ # TRANSLATORS: ApiDoc, do not translate!
97
+ description <<~DESC
98
+ Update an existing override rule.
99
+ DESC
100
+ param :ansible_variable_id,
101
+ :number,
102
+ desc: N_('ID of the Ansible variable.'),
103
+ required: true
104
+ param :id,
105
+ :number,
106
+ desc: N_('ID of the override to update.'),
107
+ required: true
108
+ param :override, Hash, desc: N_('Override update'), required: true do
109
+ param :value,
110
+ String,
111
+ desc: N_('New override value.'),
112
+ example: 'backup-ntp.internal',
113
+ required: false
114
+ param :matcher,
115
+ String,
116
+ desc: N_('New matcher type (e.g., "hostgroup").'),
117
+ example: 'hostgroup',
118
+ required: false
119
+ param :matcher_value,
120
+ String,
121
+ desc: N_('New matcher value (e.g., "my_hostgroup").'),
122
+ example: 'my_hostgroup',
123
+ required: false
124
+ end
125
+ # TRANSLATORS: ApiDoc, do not translate!
126
+ example <<~EXAMPLE
127
+ {
128
+ "override": {
129
+ "value": "staging-ntp.internal",
130
+ "matcher": "hostgroup",
131
+ "matcher_value": "Staging"
132
+ }
133
+ }
134
+ EXAMPLE
135
+ # endregion
30
136
  def update
31
137
  override = override_params
32
138
  ::ForemanAnsibleDirector::VariableService.edit_override(
@@ -37,6 +143,22 @@ module ForemanAnsibleDirector
37
143
  )
38
144
  end
39
145
 
146
+ # region ApiDoc: DELETE /api/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides/:id
147
+ api :DELETE, '/v2/ansible_director/ansible_variables/:ansible_variable_id/overrides/:id',
148
+ N_('Delete an override')
149
+ # TRANSLATORS: ApiDoc, do not translate!
150
+ description <<~DESC
151
+ Delete an override rule.
152
+ DESC
153
+ param :ansible_variable_id,
154
+ :number,
155
+ desc: N_('ID of the Ansible variable.'),
156
+ required: true
157
+ param :id,
158
+ :number,
159
+ desc: N_('ID of the override to delete.'),
160
+ required: true
161
+ # endregion
40
162
  def destroy
41
163
  ::ForemanAnsibleDirector::VariableService.destroy_override(@override)
42
164
  end
@@ -6,9 +6,58 @@ module ForemanAnsibleDirector
6
6
  class AnsibleVariablesController < AnsibleDirectorApiController
7
7
  before_action :find_resource, only: %i[show update]
8
8
 
9
+ resource_description { resource_id 'AD Ansible Variables' }
10
+
11
+ # region ApiDoc: GET /api/v2/ansible_director/ansible_variables/:id
12
+ api :GET, '/v2/ansible_director/ansible_variables/:id', N_('Show details of an Ansible variable')
13
+ # TRANSLATORS: ApiDoc, do not translate!
14
+ description <<~DESC
15
+ Retrieve details of a specific Ansible variable.
16
+ DESC
17
+ # endregion
9
18
  def show
10
19
  end
11
20
 
21
+ # region ApiDoc: PUT /api/v2/ansible_director/ansible_variables/:id
22
+ api :PUT, '/v2/ansible_director/ansible_variables/:id', N_('Update an Ansible variable')
23
+ # TRANSLATORS: ApiDoc, do not translate!
24
+ description <<~DESC
25
+ Update basic attributes (key, type, default value, and overridability) of an Ansible variable.
26
+ DESC
27
+ param :ansible_variable, Hash, desc: N_('Ansible variable updates'), required: true do
28
+ param :key,
29
+ String,
30
+ desc: N_('Name of the variable.'),
31
+ example: 'ansible_user',
32
+ required: true
33
+ param :type,
34
+ %w[string integer boolean float json array hash],
35
+ desc: N_('Type of the variable value.'),
36
+ example: 'string',
37
+ required: true
38
+ param :default_value,
39
+ String,
40
+ desc: N_('Default value (must be valid JSON when type is `json`, `array`, or `hash`).'),
41
+ example: 'root',
42
+ required: true
43
+ param :overridable,
44
+ [true, false],
45
+ desc: N_('Whether this variable can be overridden on hosts or hostgroups.'),
46
+ example: true,
47
+ required: false
48
+ end
49
+ # TRANSLATORS: ApiDoc, do not translate!
50
+ example <<~EXAMPLE
51
+ {
52
+ "ansible_variable": {
53
+ "key": "ansible_user",
54
+ "type": "string",
55
+ "default_value": "root",
56
+ "overridable": true
57
+ }
58
+ }
59
+ EXAMPLE
60
+ # endregion
12
61
  def update
13
62
  variable = variable_params
14
63
  ::ForemanAnsibleDirector::VariableService.edit_variable(
@@ -6,6 +6,28 @@ module ForemanAnsibleDirector
6
6
  class AssignmentsController < AnsibleDirectorApiController
7
7
  before_action :find_resource, only: %i[destroy]
8
8
 
9
+ resource_description { resource_id 'AD Ansible Content Assignments' }
10
+
11
+ # region ApiDoc: GET /api/v2/ansible_director/assignments
12
+ api :GET, '/v2/ansible_director/assignments', N_('List resolved Ansible content assignments for a target')
13
+ # TRANSLATORS: ApiDoc, do not translate!
14
+ description <<~DESC
15
+ Retrieve all Ansible content units *resolved* for a given target (host or hostgroup).
16
+ This includes content inherited through the assignment hierarchy or direct assignments.
17
+ DESC
18
+ param :target,
19
+ %w[HOST HOSTGROUP],
20
+ desc: N_('Type of the target entity.'),
21
+ required: true
22
+ param :target_id,
23
+ :number,
24
+ desc: N_('ID of the target entity.'),
25
+ required: true
26
+ # TRANSLATORS: ApiDoc, do not translate!
27
+ example <<~EXAMPLE
28
+ GET /api/v2/ansible_director/assignments?target=HOST&target_id=123
29
+ EXAMPLE
30
+ # endregion
9
31
  def assignments
10
32
  target = ::ForemanAnsibleDirector::AssignmentService.find_target(
11
33
  target_type: params[:target],
@@ -15,6 +37,54 @@ module ForemanAnsibleDirector
15
37
  @assignments = target.resolved_ansible_content
16
38
  end
17
39
 
40
+ # region ApiDoc: POST /api/v2/ansible_director/assignments
41
+ api :POST, '/v2/ansible_director/assignments', N_('Assign Ansible content to a target')
42
+ # TRANSLATORS: ApiDoc, do not translate!
43
+ description <<~DESC
44
+ Assign Ansible content from a source (e.g., a lifecycle environment) to a target.
45
+ DESC
46
+ param :assignment, Hash, desc: N_('Assignment definition'), required: true do
47
+ param :source, Hash, desc: N_('Source (provider of content)'), required: true do
48
+ param :type,
49
+ %w[ACR],
50
+ desc: N_('Type of source. Currently, only Ansible collection roles (ACR) are supported as sources.'),
51
+ example: 'ACR',
52
+ required: true
53
+ param :id,
54
+ :number,
55
+ desc: N_('ID of the source entity.'),
56
+ example: 5,
57
+ required: true
58
+ end
59
+ param :target, Hash, desc: N_('Target (receiver of content)'), required: true do
60
+ param :type,
61
+ %w[HOST HOSTGROUP],
62
+ desc: N_('Type of target. Both hosts (HOST) and hostgroups (HOSTGROUP) are supported as targets.'),
63
+ example: 'HOST',
64
+ required: true
65
+ param :id,
66
+ :number,
67
+ desc: N_('ID of the target entity.'),
68
+ example: 6,
69
+ required: true
70
+ end
71
+ end
72
+ # TRANSLATORS: ApiDoc, do not translate!
73
+ example <<~EXAMPLE
74
+ {
75
+ "assignment": {
76
+ "source": {
77
+ "type": "ACR",
78
+ "id": 109
79
+ },
80
+ "target": {
81
+ "type": "HOST",
82
+ "id": 1
83
+ }
84
+ }
85
+ }
86
+ EXAMPLE
87
+ # endregion
18
88
  def assign
19
89
  assignment = assignment_params
20
90
 
@@ -34,6 +104,57 @@ module ForemanAnsibleDirector
34
104
  )
35
105
  end
36
106
 
107
+ # region ApiDoc: POST /api/v2/ansible_director/assignments/bulk
108
+ api :POST, '/v2/ansible_director/assignments/bulk', N_('Bulk assign Ansible content')
109
+ # TRANSLATORS: ApiDoc, do not translate!
110
+ description <<~DESC
111
+ Bulk-assign Ansible content from a source (e.g., a lifecycle environment) to targets.
112
+ Equivalent to calling `/assign` multiple times.
113
+ DESC
114
+ param :assignments, Array, desc: N_('Array of assignment objects'), required: true do
115
+ param :source, Hash, desc: N_('Source (provider of content)'), required: true do
116
+ param :type,
117
+ %w[ACR],
118
+ desc: N_('Type of source. Currently, only Ansible collection roles (ACR) are supported as sources.'),
119
+ example: 'ACR',
120
+ required: true
121
+ param :id,
122
+ :number,
123
+ desc: N_('ID of the source entity.'),
124
+ example: 5,
125
+ required: true
126
+ end
127
+ param :target, Hash, desc: N_('Target (receiver of content)'), required: true do
128
+ param :type,
129
+ %w[HOST HOSTGROUP],
130
+ desc: N_('Type of target. Both hosts (HOST) and hostgroups (HOSTGROUP) are supported as targets.'),
131
+ example: 'HOST',
132
+ required: true
133
+ param :id,
134
+ :number,
135
+ desc: N_('ID of the target entity.'),
136
+ example: 6,
137
+ required: true
138
+ end
139
+ end
140
+ # TRANSLATORS: ApiDoc, do not translate!
141
+ example <<~EXAMPLE
142
+ {
143
+ "assignments": [
144
+ {
145
+ "source": {
146
+ "type": "ACR",
147
+ "id": 109
148
+ },
149
+ "target": {
150
+ "type": "HOST",
151
+ "id": 1
152
+ }
153
+ }
154
+ ]
155
+ }
156
+ EXAMPLE
157
+ # endregion
37
158
  def assign_bulk
38
159
  assignments = bulk_assignment_params
39
160
  ::ForemanAnsibleDirector::AssignmentService.create_bulk_assignments(
@@ -41,6 +162,17 @@ module ForemanAnsibleDirector
41
162
  )
42
163
  end
43
164
 
165
+ # region ApiDoc: DELETE /api/v2/ansible_director/assignments/:id
166
+ api :DELETE, '/v2/ansible_director/assignments/:id', N_('Delete an Ansible content assignment')
167
+ # TRANSLATORS: ApiDoc, do not translate!
168
+ description <<~DESC
169
+ Note: This deletes the assignment record but not the underlying Ansible content.
170
+ DESC
171
+ param :id,
172
+ :number,
173
+ desc: N_('ID of the assignment to delete.'),
174
+ required: true
175
+ # endregion
44
176
  def destroy
45
177
  ::ForemanAnsibleDirector::AssignmentService.destroy_assignment(@assignment)
46
178
  end
@@ -9,10 +9,54 @@ module ForemanAnsibleDirector
9
9
  before_action :find_resource, only: %i[update destroy]
10
10
  before_action :find_organization, only: %i[create]
11
11
 
12
+ resource_description { resource_id 'AD Ansible Execution Environments' }
13
+
14
+ # region ApiDoc: GET /api/v2/ansible_director/execution_environments
15
+ api :GET, '/v2/ansible_director/execution_environments', N_('List all execution environments')
16
+ param :organization_id, :number, desc: N_('Organization identifier.'), required: false
17
+ param_group :search_and_pagination, ::Api::V2::BaseController
18
+ # endregion
12
19
  def index
13
20
  @execution_environments = resource_scope_for_index
14
21
  end
15
22
 
23
+ # region ApiDoc: POST /api/v2/ansible_director/execution_environments
24
+ api :POST, '/v2/ansible_director/execution_environments', N_('Create an Execution Environment')
25
+ param :organization_id, :number, desc: N_('Organization identifier'), required: true
26
+ param :execution_environment, Hash, desc: N_('Execution Environment definition'), required: true do
27
+ param :name,
28
+ String,
29
+ desc: N_('Execution Environment name.'),
30
+ example: 'MyExecutionEnvironment',
31
+ required: true
32
+ param :base_image_url,
33
+ String,
34
+ desc: N_('Execution Environment base image URL. The image must be pullable by an unauthenticated user.'),
35
+ example: 'registry.fedoraproject.org/fedora:43',
36
+ required: true
37
+ # TRANSLATORS: ApiDoc, do not translate!
38
+ param :ansible_version,
39
+ String,
40
+ desc: <<~DESC,
41
+ Version of "ansible-core" to be used in this execution environment.
42
+ The version must match one of the available releases.
43
+ See: https://pypi.org/project/ansible-core/#history
44
+ DESC
45
+ example: ::ForemanAnsibleDirector::Constants::DEFAULT_ANSIBLE_VERSION,
46
+ required: true
47
+ end
48
+ # TRANSLATORS: ApiDoc, do not translate!
49
+ example <<~EXAMPLE
50
+ {
51
+ "organization_id": 1,
52
+ "execution_environment": {
53
+ "name": "EE-2.20.0",
54
+ "base_image_url": "quay.io/fedora/fedora:42",
55
+ "ansible_version": "2.20.0"
56
+ }
57
+ }
58
+ EXAMPLE
59
+ # endregion
16
60
  def create
17
61
  permitted_params = execution_environment_params
18
62
  # content = permitted_params.delete(:content)
@@ -25,6 +69,41 @@ module ForemanAnsibleDirector
25
69
  )
26
70
  end
27
71
 
72
+ # region ApiDoc: PATCH /api/v2/ansible_director/execution_environments/:id
73
+ api :PATCH, '/v2/ansible_director/execution_environments/:id', N_('Update an Execution Environment')
74
+ param :execution_environment, Hash, desc: N_('Execution Environment definition'), required: true do
75
+ param :name,
76
+ String,
77
+ desc: N_('Execution Environment name.'),
78
+ example: 'MyExecutionEnvironment',
79
+ required: false
80
+ param :base_image_url,
81
+ String,
82
+ desc: N_('Execution Environment base image URL. The image must be pullable by an unauthenticated user.'),
83
+ example: 'registry.fedoraproject.org/fedora:43',
84
+ required: false
85
+ # TRANSLATORS: ApiDoc, do not translate!
86
+ param :ansible_version,
87
+ String,
88
+ desc: <<~DESC,
89
+ Version of "ansible-core" to be used in this execution environment.
90
+ The version must match one of the available releases.
91
+ See: https://pypi.org/project/ansible-core/#history
92
+ DESC
93
+ example: ::ForemanAnsibleDirector::Constants::DEFAULT_ANSIBLE_VERSION,
94
+ required: false
95
+ end
96
+ # TRANSLATORS: ApiDoc, do not translate!
97
+ example <<~EXAMPLE
98
+ {
99
+ "execution_environment": {
100
+ "name": "EE-2.20.0",
101
+ "base_image_url": "quay.io/fedora/fedora:42",
102
+ "ansible_version": "2.20.0"
103
+ }
104
+ }
105
+ EXAMPLE
106
+ # endregion
28
107
  def update
29
108
  permitted_params = execution_environment_params
30
109
  # content = permitted_params.delete(:content)
@@ -37,11 +116,18 @@ module ForemanAnsibleDirector
37
116
  )
38
117
  end
39
118
 
119
+ # region ApiDoc: DELETE /api/v2/ansible_director/execution_environments/:id
120
+ api :DELETE, '/v2/ansible_director/execution_environments/:id', N_('Delete an Execution Environment')
121
+ # endregion
40
122
  def destroy
41
123
  @execution_environment.destroy
42
124
  ::ForemanAnsibleDirector::ExecutionEnvironmentService.destroy_execution_environment @execution_environment
43
125
  end
44
126
 
127
+ def model_of_controller
128
+ resource_class
129
+ end
130
+
45
131
  private
46
132
 
47
133
  def execution_environment_params