foreman_acd 0.2.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -56
  3. data/app/controllers/foreman_acd/ansible_playbooks_controller.rb +199 -0
  4. data/app/controllers/foreman_acd/api/v2/ansible_playbooks_controller.rb +72 -0
  5. data/app/controllers/foreman_acd/api/v2/app_definitions_controller.rb +1 -0
  6. data/app/controllers/foreman_acd/api/v2/app_instances_controller.rb +62 -0
  7. data/app/controllers/foreman_acd/app_definitions_controller.rb +19 -10
  8. data/app/controllers/foreman_acd/app_instances_controller.rb +111 -137
  9. data/app/controllers/foreman_acd/concerns/ansible_playbook_parameters.rb +23 -0
  10. data/app/controllers/foreman_acd/concerns/app_definition_parameters.rb +1 -1
  11. data/app/controllers/foreman_acd/concerns/app_instance_parameters.rb +1 -1
  12. data/app/controllers/foreman_acd/remote_execution_controller.rb +62 -0
  13. data/app/controllers/ui_acd_controller.rb +20 -3
  14. data/app/lib/actions/foreman_acd/deploy_all_hosts.rb +47 -0
  15. data/app/lib/actions/foreman_acd/run_configurator.rb +44 -0
  16. data/app/models/concerns/foreman_acd/host_managed_extensions.rb +51 -0
  17. data/app/models/foreman_acd/acd_provider.rb +36 -0
  18. data/app/models/foreman_acd/ansible_playbook.rb +68 -0
  19. data/app/models/foreman_acd/app_definition.rb +25 -0
  20. data/app/models/foreman_acd/app_instance.rb +42 -0
  21. data/app/models/foreman_acd/foreman_host.rb +23 -0
  22. data/app/models/foreman_acd/taxonomy_extensions.rb +17 -0
  23. data/app/services/foreman_acd/acd_proxy_proxy_selector.rb +17 -0
  24. data/app/services/foreman_acd/app_configurator.rb +98 -0
  25. data/app/services/foreman_acd/app_deployer.rb +157 -0
  26. data/app/services/foreman_acd/inventory_creator.rb +68 -0
  27. data/app/views/foreman_acd/ansible_playbooks/_form.html.erb +64 -0
  28. data/app/views/foreman_acd/ansible_playbooks/edit.html.erb +11 -0
  29. data/app/views/foreman_acd/ansible_playbooks/index.html.erb +30 -0
  30. data/app/views/foreman_acd/ansible_playbooks/new.html.erb +3 -0
  31. data/app/views/foreman_acd/api/v2/ansible_playbooks/base.json.rabl +5 -0
  32. data/app/views/foreman_acd/api/v2/ansible_playbooks/index.json.rabl +5 -0
  33. data/app/views/foreman_acd/api/v2/ansible_playbooks/show.json.rabl +9 -0
  34. data/app/views/foreman_acd/api/v2/app_definitions/base.json.rabl +5 -0
  35. data/app/views/foreman_acd/api/v2/app_definitions/index.json.rabl +5 -0
  36. data/app/views/foreman_acd/api/v2/app_definitions/show.json.rabl +9 -0
  37. data/app/views/foreman_acd/api/v2/app_instances/base.json.rabl +5 -0
  38. data/app/views/foreman_acd/api/v2/app_instances/index.json.rabl +5 -0
  39. data/app/views/foreman_acd/api/v2/app_instances/show.json.rabl +5 -0
  40. data/app/views/foreman_acd/app_definitions/_form.html.erb +34 -12
  41. data/app/views/foreman_acd/app_definitions/edit.html.erb +10 -0
  42. data/app/views/foreman_acd/app_definitions/index.html.erb +4 -4
  43. data/app/views/foreman_acd/app_instances/_form.html.erb +11 -9
  44. data/app/views/foreman_acd/app_instances/edit.html.erb +10 -0
  45. data/app/views/foreman_acd/app_instances/index.html.erb +89 -10
  46. data/app/views/foreman_acd/app_instances/report.html.erb +6 -3
  47. data/app/views/templates/job/run_acd_ansible_playbook.erb +62 -0
  48. data/app/views/ui_acd/ansible_data.json.rabl +6 -0
  49. data/app/views/ui_acd/app.json.rabl +6 -2
  50. data/app/views/ui_acd/app_definition.json.rabl +1 -1
  51. data/app/views/ui_acd/{fdata.json.rabl → foreman_data.json.rabl} +1 -1
  52. data/config/routes.rb +32 -2
  53. data/db/migrate/20200916091018_create_ansible_playbooks.rb +20 -0
  54. data/db/migrate/20200917120220_add_ansible_playbook_id.rb +14 -0
  55. data/db/migrate/20201016002819_add_ansible_vars_all_to_app_definitions.rb +8 -0
  56. data/db/migrate/20201016104338_add_ansible_vars_all_to_app_instances.rb +8 -0
  57. data/db/migrate/20210112111548_add_organization_to_app_instance.rb +22 -0
  58. data/db/migrate/20210112113853_add_location_to_app_instance.rb +8 -0
  59. data/db/migrate/20210202141658_create_foreman_hosts.rb +24 -0
  60. data/db/migrate/20210204111306_remove_hosts_from_app_instances.rb +8 -0
  61. data/db/migrate/20210209091014_rename_acd_tables.rb +16 -0
  62. data/db/migrate/20210216083522_add_last_progress_report.rb +8 -0
  63. data/db/migrate/20210216091529_add_last_deploy_task.rb +8 -0
  64. data/db/migrate/20210316151145_add_git_commit_to_ansible_playbooks.rb +8 -0
  65. data/db/migrate/20210503122809_add_git_url_to_ansible_playbooks.rb +8 -0
  66. data/db/seeds.d/62_acd_proxy_feature.rb +4 -0
  67. data/db/seeds.d/75-job_templates.rb +13 -0
  68. data/lib/foreman_acd.rb +12 -0
  69. data/lib/foreman_acd/engine.rb +43 -3
  70. data/lib/foreman_acd/plugin.rb +88 -22
  71. data/lib/foreman_acd/version.rb +1 -1
  72. data/lib/tasks/foreman_acd_tasks.rake +0 -12
  73. data/locale/en/foreman_acd.edit.po +326 -0
  74. data/locale/en/foreman_acd.po +232 -2
  75. data/locale/en/foreman_acd.po.time_stamp +0 -0
  76. data/locale/foreman_acd.pot +343 -8
  77. data/package.json +9 -9
  78. data/test/controllers/ansible_playbooks_controller_test.rb +27 -0
  79. data/test/controllers/app_instances_controller_test.rb +8 -3
  80. data/test/controllers/ui_acd_controller_test.rb +22 -6
  81. data/test/factories/foreman_acd_factories.rb +18 -4
  82. data/test/models/acd_provider_test.rb +37 -0
  83. data/test/models/ansible_playbook_test.rb +11 -0
  84. data/test/models/app_definition_test.rb +1 -1
  85. data/test/models/app_instance_test.rb +2 -0
  86. data/test/models/concerns/host_extensions_test.rb +26 -0
  87. data/test/models/foreman_host_test.rb +12 -0
  88. data/webpack/__mocks__/foremanReact/API.js +2 -0
  89. data/webpack/__mocks__/foremanReact/common/I18n.js +3 -0
  90. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  91. data/webpack/__mocks__/foremanReact/components/ForemanModal.js +7 -0
  92. data/webpack/__mocks__/foremanReact/components/common/forms/CommonForm.js +2 -0
  93. data/webpack/__mocks__/foremanReact/components/common/forms/TextInput.js +2 -0
  94. data/webpack/__mocks__/foremanReact/components/hosts/powerStatus.js +1 -0
  95. data/webpack/__snapshots__/helper.test.js.snap +14 -0
  96. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +159 -29
  97. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +106 -14
  98. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +8 -2
  99. data/webpack/components/ApplicationDefinition/ApplicationDefinitionHelper.js +26 -0
  100. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +143 -21
  101. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +3 -0
  102. data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionConfData_1.fixtures.js +288 -0
  103. data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionReducer.fixtures.js +79 -0
  104. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +25 -0
  105. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionReducer.test.js +119 -0
  106. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionSelectors.test.js +41 -0
  107. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +200 -0
  108. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionReducer.test.js.snap +3033 -0
  109. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionSelectors.test.js.snap +299 -0
  110. data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +50 -0
  111. data/webpack/components/ApplicationDefinition/components/__tests__/AnsiblePlaybookSelector.test.js +41 -0
  112. data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +121 -0
  113. data/webpack/components/ApplicationDefinition/index.js +6 -0
  114. data/webpack/components/ApplicationInstance/ApplicationInstance.js +151 -44
  115. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +47 -10
  116. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +5 -2
  117. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +114 -28
  118. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +3 -1
  119. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceConfData_1.fixtures.js +263 -0
  120. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +78 -0
  121. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +23 -0
  122. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +119 -0
  123. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceSelectors.test.js +44 -0
  124. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +209 -0
  125. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +2719 -0
  126. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceSelectors.test.js.snap +276 -0
  127. data/webpack/components/ApplicationInstance/components/Service.js +1 -1
  128. data/webpack/components/ApplicationInstance/index.js +4 -0
  129. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +53 -60
  130. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.scss +17 -0
  131. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +7 -51
  132. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +2 -4
  133. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +4 -18
  134. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +0 -1
  135. data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportData_1.fixtures.js +349 -0
  136. data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportReducer.fixtures.js +20 -0
  137. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReport.test.js +47 -0
  138. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportReducer.test.js +41 -0
  139. data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportSelectors.test.js +26 -0
  140. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +130 -0
  141. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportReducer.test.js.snap +718 -0
  142. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportSelectors.test.js.snap +347 -0
  143. data/webpack/components/ApplicationInstanceReport/components/ReportViewer.js +1 -1
  144. data/webpack/components/ApplicationInstanceReport/components/__tests__/ReportViewer.test.js +24 -0
  145. data/webpack/components/ApplicationInstanceReport/components/__tests__/__snapshots__/ReportViewer.test.js.snap +24 -0
  146. data/webpack/components/ApplicationInstanceReport/index.js +0 -2
  147. data/webpack/components/ParameterSelection/ParameterSelection.js +85 -50
  148. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +68 -62
  149. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +6 -3
  150. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +0 -32
  151. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +47 -35
  152. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -2
  153. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +116 -84
  154. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionReducer.fixtures.js +10 -4
  155. data/webpack/components/ParameterSelection/__tests__/ParameterSelection.test.js +36 -46
  156. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +31 -25
  157. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -6
  158. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +2 -126
  159. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +1483 -872
  160. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +117 -79
  161. data/webpack/components/ParameterSelection/index.js +4 -4
  162. data/webpack/components/SyncGitRepo/SyncGitRepo.js +210 -0
  163. data/webpack/components/SyncGitRepo/SyncGitRepo.scss +1 -0
  164. data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +124 -0
  165. data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +9 -0
  166. data/webpack/components/SyncGitRepo/SyncGitRepoReducer.js +80 -0
  167. data/webpack/components/SyncGitRepo/SyncGitRepoSelectors.js +6 -0
  168. data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoConfData_1.fixtures.js +7 -0
  169. data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoReducer.fixtures.js +44 -0
  170. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepo.test.js +27 -0
  171. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoReducer.test.js +95 -0
  172. data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoSelectors.test.js +32 -0
  173. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +30 -0
  174. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoReducer.test.js.snap +137 -0
  175. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoSelectors.test.js.snap +13 -0
  176. data/webpack/components/SyncGitRepo/components/FormTextInput.js +42 -0
  177. data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +46 -0
  178. data/webpack/components/SyncGitRepo/index.js +28 -0
  179. data/webpack/components/common/DeleteTableEntry.js +3 -3
  180. data/webpack/components/common/EditTableEntry.js +50 -0
  181. data/webpack/components/common/ExtTextInput.js +43 -0
  182. data/webpack/components/common/LockTableEntry.js +60 -0
  183. data/webpack/components/common/__tests__/EditTableEntry.test.js +53 -0
  184. data/webpack/components/common/__tests__/LockTableEntry.test.js +35 -0
  185. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +2 -2
  186. data/webpack/components/common/__tests__/__snapshots__/EditTableEntry.test.js.snap +81 -0
  187. data/webpack/components/common/__tests__/__snapshots__/LockTableEntry.test.js.snap +60 -0
  188. data/webpack/helper.js +15 -1
  189. data/webpack/helper.test.js +37 -0
  190. data/webpack/index.js +2 -0
  191. data/webpack/reducer.js +18 -11
  192. metadata +184 -10
  193. data/app/views/foreman_acd/app_instances/deploy.html.erb +0 -19
  194. data/webpack/components/common/__tests__/__snapshots__/AddParameter.test.js.snap +0 -35
  195. data/webpack/components/common/__tests__/__snapshots__/DeleteParameter.test.js.snap +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef0b36ad161877bede4fe9a9df532a8201fc31710b1f42ab988152aeba863cac
4
- data.tar.gz: a629384ff81f18c21883ea4a09a76828988bff02e6a709a7f2151e77fff46836
3
+ metadata.gz: 7b616c7ba21eea339af8509f618585dcd949ddead6ecdec57278a62c751e4fd2
4
+ data.tar.gz: 75c7d2e2c07d306dee127bc50c6b300934f90066bc4a491e49f17f65ac6b7c24
5
5
  SHA512:
6
- metadata.gz: 8c8843594e0cbad7c6b85398c8b4d2c8fe18703ef7dc5c2ebd4fd46ccd0690a3cf30588e13dcef66e9d568fa4c5ca97fd272ebb5f5107e3f2ad1258f9fb9d35f
7
- data.tar.gz: 99181b0218e89485fffedfdd1374b095c1830614718332246f72238af50adb65610e03fdaa0a035f6cd68208d8f72679b141eac2b558dc1824abb30b21120b56
6
+ metadata.gz: bba62637508bbbd4e35772a55ad1126fea7a8cb3c1658c6f734b02ccf03d44048db40fa621bb51e796220668e7a49e8b03c3169a77b818f6dbbde117d09edfe2
7
+ data.tar.gz: a6e4ba1bb97250e8bcebe6180abcf4755859b73828febda64353b47021acadcc33fd99e2ab4b45ac965e5d643c368bbfb47aee421a80979c7a4c69354a18b297
data/README.md CHANGED
@@ -2,88 +2,139 @@
2
2
 
3
3
  # Foreman Application Centric Deployment
4
4
 
5
- A plugin to bring an user self service portal and application centric deployment to Foreman.
5
+ A Foreman plugin providing application centric deployment and a self-service portal.
6
6
 
7
- # Description
7
+ # Introduction
8
8
 
9
- The target of this plugin is, to deploy whole applications which include multiple hosts
10
- and an Ansible Playbook / saltstack state to configure the application.
9
+ The target of this plugin is to deploy whole applications which include multiple hosts and configure them using an Ansible playbook.
11
10
 
12
11
  This plugin follows the idea of different user types working together.
13
- The administrative user creates application definitions including multiple servers and
14
- configuration management items (Ansible Playbook, saltstack state).
15
- The user can create and deploy new application instances with an easy to use self service portal.
12
+ The _administrative user_ creates Application Definitions including multiple servers and configuration management items (Ansible Playbooks).
13
+ The _user_ can create and deploy new Application Instances with an easy to use self-service portal.
16
14
 
17
- *Example Application Definition:*
18
- To run a complex web application, a loadbalancer is required.
19
- The loadbalancer routes the requests to 3 different web servers.
20
- The web servers are using a database which is in high availability mode on 2 hosts.
21
- => 6 hosts are required.
15
+ *Example Application Definition*
16
+ To run a complex web application, a load balancer is required.
17
+ The load balancer routes the requests to three different web servers.
18
+ The web servers are using a database which runs in high availability mode on two hosts.
19
+ Therefore, six hosts in total are required.
22
20
 
23
- This plugin aims to setup all 6 hosts and to deploy the application.
21
+ This plugin aims to setup all six hosts and to deploy the application.
24
22
 
25
- # Current State
26
- In the current state the plugin can be used to provide an easy to use self service user portal
27
- to deploy new servers.
23
+ # Architecture
28
24
 
29
- # Road Map
30
- - Self service portal for single host deployments (current version)
31
- - Add application deployment with single host requirements
32
- - Add application deployment with multi host requirements
25
+ ## Ansible Playbooks
33
26
 
34
- ## WARNING
27
+ * Specify the path on your Foreman server to the Ansible playbook and playfile
28
+ * Read groups configured in the Ansible playbook
35
29
 
36
- This plugin is in development.
37
- In the current state, a self service portal to deploy single servers can be created.
30
+ ## Application Definitions
31
+
32
+ * Use the configured Ansible playbook in an Application Definition
33
+ * Overwrite group variables of the Ansible playbook for the Application Definition
34
+ * Set Foreman parameters in the Application Definition
35
+ * Setup various services like web servers, database servers, etc.
36
+
37
+ ## Application Instances
38
+
39
+ * Use an Application Definition for your Application Instance
40
+ * Configure specific hosts which use the Application Definition's services
41
+ * Deploy these hosts
42
+ * Configure the hosts using the configured Ansible playbook
43
+
44
+ # How It Works
45
+
46
+ * Configure an Ansible playbook, an Application Definition, and create an Application Instance.
47
+ * All hosts are created when deploying the Application Instance.
48
+ * After provisioning, the hosts are configured with the linked Ansible playbook.
49
+ * This uses the [Smart Proxy ACD](https://github.com/ATIX-AG/smart_proxy_acd) component.
50
+ * The job to configure the hosts will be send to the Smart Proxy ACD component which will
51
+ * download the Ansible playbook from your Foreman server (provided by an foreman_acd API);
52
+ * extract the Ansible playbook on the Smart Proxy;
53
+ * and run the Ansible playbook on the Smart Proxy.
54
+ * You can see the output of the Ansible playbook run on the *Monitor > Job* page.
55
+
56
+ :warning: This plugin is still in development.
38
57
 
39
58
  ## Installation
40
59
 
41
- See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
42
- for how to install Foreman plugins
60
+ See the [installation](https://theforeman.org/plugins/#2.Installation) chapter of the Foreman plugins documentation on how to install Foreman plugins.
61
+
62
+ ### TL;DR:
63
+
64
+ yum install tfm-rubygem-foreman_acd
65
+ foreman-maintain service restart
66
+
67
+ In some cases, you need to manually run
68
+
69
+ foreman-rake db:migrate
70
+ foreman-rake db:seed
71
+
72
+ ### Smart Proxy Installation
73
+
74
+ You will need to install [Smart Proxy ACD](https://github.com/ATIX-AG/smart_proxy_acd), too.
43
75
 
44
- ATM, Katello plugin need to exist, too.
76
+ yum install tfm-rubygem-smart_proxy_acd tfm-rubygem-smart_proxy_acd_core
77
+ foreman-maintain service restart
78
+
79
+ You need to refresh the smart proxy features in *Infrastructure > Smart Proxies > Your Smart-Proxy > Actions > Refresh* after the installation of the Smart Proxy ACD components.
80
+
81
+ ### Tips
82
+
83
+ * Make sure you have the [Katello](https://theforeman.org/plugins/katello/) plugin installed.
84
+ * Make sure the Job Template `Run ACD Ansible Playbook - ACD Default` is part of your organization/location context.
45
85
 
46
86
  ## Usage
47
87
 
48
- Application Definition (Admin)
49
- * Create an Application Definition (Configure -> Application Definition) first
50
- * Select the Hostgroup you want to use.
51
- * Specifiy the values, a user could overwrite.
52
- (you can set a default value, if you want)
53
-
54
- Application Instance (User)
55
- * Create an Application Instance (Configure -> Application Instrane)
56
- * Select the Application Definition which should be used
57
- * Set the values.
58
- Remember, all parameters need to have a value.
59
- * Save the Application Instance
60
- * To Deploy the host, select "Deploy" in the Action selection dropdown field
61
- on the Application Instance index site
88
+ ### Ansible Playbook
89
+
90
+ * Copy (or checkout a git repository) an Ansible playbook.
91
+ Store it in `/etc/foreman/plugins/foreman_acd/ansible-playbooks/` so that SELinux is able to read it.
92
+ * Add a new Ansible Playbook via *Applications > Ansible Playbooks*.
93
+ * Specify the path to the Ansible playbook and name of the playbook file. (e.g. `site.yml`).
94
+ * Save it and press *Import group variables* for this newly created Ansible playbook.
95
+
96
+ ### Application Definition (for Admins)
97
+
98
+ * Create an Application Definition via *Applications > Application Definitions*.
99
+ * Select the Ansible Playbook you want to use.
100
+ * Add new services and specify the host group you want to use.
101
+ * Specify any values a user will be allowed to overwrite.
102
+ You may also set a default value.
103
+
104
+ ### Application Instance (for Users)
105
+
106
+ * Create an Application Instance via *Applications > Application Instances*.
107
+ * Select the Application Definition you want to use.
108
+ * Overwrite desired values.
109
+ All Foreman parameters require a value.
110
+ * Save the Application Instance.
111
+
112
+ ### Deploy and Configure the Application Instance (for Users)
113
+
114
+ * Select *Deploy* in the action drop down menu via *Applications > Application Instance* to deploy a host.
115
+ * Verify if the hosts are deployed via the *Report* button from the action drop down menu.
116
+ * Run the Ansible playbook via *Run Ansible playbook* from the action drop down menu after all hosts are deployed.
62
117
 
63
118
  ## TODO
64
119
 
65
- - Add ansible playbook / saltstack support to configure the application
66
- - Multi-host support
67
- - Add validation to the different parameter types
120
+ * Add `git` support for the Ansible playbooks.
121
+ * Provide application templates which contains application definition and the required Ansible-playbook.
122
+ * Add Saltstack support to configure the application.
123
+ * Extend the Foreman parameter and value validation.
68
124
 
69
125
  ## Contributing
70
126
 
71
- Fork and send a Pull Request. Thanks!
127
+ Fork and send a Pull Request.
128
+ Thanks!
72
129
 
73
130
  ## Copyright
74
131
 
75
- Copyright (c) 2019 ATIX AG
76
-
77
- This program is free software: you can redistribute it and/or modify
78
- it under the terms of the GNU General Public License as published by
79
- the Free Software Foundation, either version 3 of the License, or
80
- (at your option) any later version.
132
+ Copyright (c) 2021 ATIX AG
81
133
 
82
- This program is distributed in the hope that it will be useful,
83
- but WITHOUT ANY WARRANTY; without even the implied warranty of
84
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85
- GNU General Public License for more details.
134
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
86
135
 
87
- You should have received a copy of the GNU General Public License
88
- along with this program. If not, see <http://www.gnu.org/licenses/>.
136
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
137
+ See the GNU General Public License for more details.
89
138
 
139
+ You should have received a copy of the GNU General Public License along with this program.
140
+ If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanAcd
4
+ # Ansible Playbook Controller
5
+ class AnsiblePlaybooksController < ::ForemanAcd::ApplicationController
6
+ include Foreman::Controller::AutoCompleteSearch
7
+ include ::ForemanAcd::Concerns::AnsiblePlaybookParameters
8
+
9
+ before_action :find_resource, :only => [:edit, :update, :destroy, :import_vars]
10
+ after_action :delete_synced_repo, :only => [:new, :edit, :create, :update, :destroy, :index]
11
+
12
+ def index
13
+ @ansible_playbooks = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
14
+ end
15
+
16
+ def new
17
+ @ansible_playbook = AnsiblePlaybook.new
18
+ end
19
+
20
+ def create
21
+ @ansible_playbook = AnsiblePlaybook.new(ansible_playbook_params)
22
+ if session[:git_path]
23
+ @ansible_playbook.update(:path => ansible_playbook_full_path(ansible_playbook_rename(@ansible_playbook[:name])))
24
+ FileUtils.mv(session[:git_path], @ansible_playbook[:path])
25
+ session[:git_path] = nil
26
+ end
27
+ if @ansible_playbook.save
28
+ process_success :success_msg => _("Successfully created %s. You need to press the \"Import groups\" button
29
+ before this ansible playbook can be used in App Definitions!") % @ansible_playbook
30
+ else
31
+ process_error
32
+ end
33
+ end
34
+
35
+ def edit; end
36
+
37
+ def update
38
+ # Move synced repo to new path if ansible_playbook name is changed
39
+ if !session[:git_path].nil? && ansible_playbook_params[:name] != @ansible_playbook[:name]
40
+ FileUtils.mv(@ansible_playbook[:path], ansible_playbook_full_path(ansible_playbook_rename(ansible_playbook_params[:name])))
41
+ @ansible_playbook.update(:path => ansible_playbook_full_path(ansible_playbook_rename(ansible_playbook_params[:name])))
42
+ session[:git_path] = nil
43
+
44
+ # Remove old version and copy new version of synced repository
45
+ elsif !session[:git_path].nil? && ansible_playbook_params[:name] == @ansible_playbook.name
46
+ remove_ansible_dir(@ansible_playbook[:path]) if @ansible_playbook.path
47
+ @ansible_playbook.update(:path => ansible_playbook_full_path(ansible_playbook_rename(@ansible_playbook[:name])))
48
+ FileUtils.mv(session[:git_path], @ansible_playbook[:path])
49
+ session[:git_path] = nil
50
+ end
51
+
52
+ if @ansible_playbook.update(ansible_playbook_params)
53
+ process_success
54
+ else
55
+ process_error
56
+ end
57
+ end
58
+
59
+ def destroy
60
+ if @ansible_playbook.destroy
61
+ process_success
62
+ else
63
+ process_error
64
+ end
65
+ end
66
+
67
+ def sync_git_repo
68
+ @ansible_playbook = AnsiblePlaybook.new
69
+ sync_params = params[:ansible_playbook]
70
+ dir = Dir.mktmpdir
71
+
72
+ begin
73
+ git = Git.init(dir)
74
+
75
+ if ForemanAcd.proxy_setting.present?
76
+ git.config('http.proxy', ForemanAcd.proxy_setting)
77
+ logger.info("HTTP Proxy used: #{git.config['http.proxy']}")
78
+ end
79
+
80
+ git.add_remote('origin', sync_params[:git_url])
81
+ git.fetch
82
+ git.checkout(sync_params[:git_commit])
83
+
84
+ session[:git_path] = git.dir.path
85
+ rescue StandardError => e
86
+ logger.error("Failed to sync git repository: #{e}")
87
+ render :json => { :status => 'error', :message => e }, :status => :internal_server_error
88
+ end
89
+ end
90
+
91
+ # Remove abandoned synced git repositories
92
+ def delete_synced_repo
93
+ names = []
94
+ AnsiblePlaybook.all.each do |ansible_playbook|
95
+ names.push(ansible_playbook_rename(ansible_playbook.name))
96
+ end
97
+ names.push('.', '..')
98
+ return unless Dir.exist?(ForemanAcd.ansible_playbook_path)
99
+ Dir.foreach(ForemanAcd.ansible_playbook_path) do |dirname|
100
+ next if names.include? dirname
101
+ remove_ansible_dir(ansible_playbook_full_path(dirname))
102
+ logger.info("Successfully removed #{dirname}")
103
+ end
104
+ end
105
+
106
+ def action_permission
107
+ case params[:action]
108
+ when 'import_vars'
109
+ :import_vars
110
+ when 'sync_git_repo'
111
+ :sync_git_repo
112
+ when 'grab'
113
+ :grab
114
+ else
115
+ super
116
+ end
117
+ end
118
+
119
+ # We need to move these to a smart_proxy_acd
120
+ def extract_variables(playbook_path)
121
+ errors = []
122
+ vars = {}
123
+
124
+ unless File.directory?(playbook_path) || File.directory?("#{playbook_path}/group_vars")
125
+ errors << "Playbook path '#{playbook_path}' or '#{playbook_path}/group_vars' doesn't exist"
126
+ return vars, errors
127
+ end
128
+
129
+ everything_empty = true
130
+
131
+ vars_files = Dir.glob("#{playbook_path}/group_vars/**/*")
132
+ vars_files.each do |vars_file|
133
+ loaded_yaml = {}
134
+ next if File.directory?(vars_file)
135
+
136
+ begin
137
+ loaded_yaml = YAML.load_file(vars_file)
138
+ rescue Psych::SyntaxError
139
+ err = "#{vars_file} is not YAML file"
140
+ logger.error(err)
141
+ errors << err
142
+ end
143
+ unless loaded_yaml.is_a? Hash
144
+ err = "Could not parse YAML file #{vars_file}"
145
+ logger.error(err)
146
+ errors << err
147
+ end
148
+ everything_empty = false unless loaded_yaml.empty?
149
+
150
+ # We need to support: group_vars/group_file and group_vars/group_dir/yaml_files
151
+ dir_and_file = File.split(vars_file)
152
+
153
+ group_name = if File.basename(dir_and_file[0]) == 'group_vars' # in case of group_vars/group_file
154
+ File.basename(dir_and_file[1], '.*')
155
+ else # in case of group_vars/group_dir/yaml_files
156
+ File.basename(dir_and_file[0])
157
+ end
158
+
159
+ logger.debug("Add ansible vars from file #{vars_file} to group #{group_name}")
160
+
161
+ if vars.key?(group_name)
162
+ vars[group_name].merge!(loaded_yaml)
163
+ else
164
+ vars[group_name] = loaded_yaml
165
+ end
166
+ end
167
+
168
+ errors << "No ansible group variable in #{playbook_path} defined." if everything_empty
169
+
170
+ [vars, errors]
171
+ end
172
+
173
+ def import_vars
174
+ logger.debug("Load ansible group vars for #{@ansible_playbook} from #{@ansible_playbook.path}")
175
+ vars, errors = extract_variables(@ansible_playbook.path)
176
+ @ansible_playbook.vars = vars.to_json
177
+ @ansible_playbook.save
178
+ if errors.empty?
179
+ process_success :success_msg => _('Successfully loaded ansible group variables from %s') % @ansible_playbook.name, :redirect => ansible_playbooks_path
180
+ else
181
+ process_error :error_msg => _(errors.join(' ')), :redirect => ansible_playbooks_path
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ def ansible_playbook_rename(name)
188
+ name.split(/\W+/).join('_')
189
+ end
190
+
191
+ def remove_ansible_dir(dirpath)
192
+ FileUtils.remove_dir(dirpath) if Dir.exist?(dirpath)
193
+ end
194
+
195
+ def ansible_playbook_full_path(dirname)
196
+ File.join(ForemanAcd.ansible_playbook_path, dirname)
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanAcd
4
+ module Api
5
+ module V2
6
+ # API controller for Ansible Playbooks
7
+ class AnsiblePlaybooksController < ::ForemanAcd::Api::V2::BaseController
8
+ include ::Foreman::Controller::SmartProxyAuth
9
+ include ::ForemanAcd::Concerns::AnsiblePlaybookParameters
10
+
11
+ before_action :find_resource, :except => [:index, :create, :grab]
12
+
13
+ add_smart_proxy_filters :grab, :features => 'ACD'
14
+
15
+ api :GET, '/ansible_playbooks/:id', N_('Show ansible playbook')
16
+ param :id, :identifier, :required => true
17
+ def show; end
18
+
19
+ api :GET, '/ansible_playbooks', N_('List ansible playbooks')
20
+ param_group :search_and_pagination, ::Api::V2::BaseController
21
+ add_scoped_search_description_for(AnsiblePlaybook)
22
+ def index
23
+ @ansible_playbooks = resource_scope_for_index
24
+ end
25
+
26
+ def_param_group :ansible_playbook do
27
+ param :ansible_playbook, Hash, :required => true, :action_aware => true do
28
+ param :name, String, :required => true
29
+ param_group :taxonomies, ::Api::V2::BaseController
30
+ param :description, String, :required => true
31
+ param :services, String, :required => true
32
+ end
33
+ end
34
+
35
+ api :POST, '/ansible_playbooks', N_('Create a ansible playbook')
36
+ param_group :ansible_playbook, :as => :create
37
+ def create
38
+ @ansible_playbook = AnsiblePlaybook.new(ansible_playbook_params)
39
+ process_response @ansible_playbook.save
40
+ end
41
+
42
+ api :DELETE, '/ansible_playbooks/:id', N_('Deletes ansible playbook')
43
+ param :id, :identifier, :required => true
44
+ def destroy
45
+ process_response @ansible_playbook.destroy
46
+ end
47
+
48
+ api :GET, '/ansible_playbooks/:id/grab', N_('Grab ansible playbook')
49
+ param :id, :identifier, :required => true
50
+ def grab
51
+ ap = resource_class.find(params['id'])
52
+ command = "tar cz -C #{ap.path} --exclude \".git\" . 2>/dev/null | base64"
53
+ result = `#{command}`
54
+ send_data result, :type => 'text/plain', :disposition => 'inline'
55
+ end
56
+
57
+ def action_permission
58
+ case params[:action]
59
+ when 'grab'
60
+ 'grab'
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def resource_class
67
+ ForemanAcd::AnsiblePlaybook
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end