foreman_acd 0.7.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/app/controllers/foreman_acd/ansible_playbooks_controller.rb +17 -2
  4. data/app/controllers/foreman_acd/app_definitions_controller.rb +104 -7
  5. data/app/controllers/foreman_acd/app_instances_controller.rb +15 -30
  6. data/app/controllers/foreman_acd/concerns/app_instance_mixins.rb +36 -0
  7. data/app/controllers/ui_acd_controller.rb +42 -3
  8. data/app/lib/actions/foreman_acd/run_configurator.rb +1 -0
  9. data/app/models/concerns/foreman_acd/host_managed_extensions.rb +40 -27
  10. data/app/models/foreman_acd/app_instance.rb +47 -2
  11. data/app/models/foreman_acd/foreman_host.rb +8 -0
  12. data/app/services/foreman_acd/app_deployer.rb +19 -2
  13. data/app/services/foreman_acd/inventory_creator.rb +11 -1
  14. data/app/views/foreman_acd/app_definitions/_form.html.erb +4 -0
  15. data/app/views/foreman_acd/app_definitions/import.html.erb +20 -1
  16. data/app/views/foreman_acd/app_definitions/index.html.erb +3 -6
  17. data/app/views/foreman_acd/app_instances/_form.html.erb +4 -0
  18. data/app/views/foreman_acd/app_instances/index.html.erb +15 -11
  19. data/app/views/foreman_acd/app_instances/report.html.erb +7 -2
  20. data/app/views/ui_acd/host_report.json.rabl +4 -0
  21. data/app/views/ui_acd/report_data.json.rabl +10 -0
  22. data/app/views/ui_acd/validate_hostname.json.rabl +6 -0
  23. data/config/routes.rb +3 -0
  24. data/db/migrate/20210818125913_add_is_existing_host_to_foreman_host.rb +8 -0
  25. data/db/migrate/20210902110645_add_initial_configure_task.rb +8 -0
  26. data/lib/foreman_acd/plugin.rb +9 -9
  27. data/lib/foreman_acd/version.rb +1 -1
  28. data/lib/foreman_acd.rb +27 -9
  29. data/package.json +8 -25
  30. data/test/controllers/ui_acd_controller_test.rb +4 -1
  31. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
  32. data/webpack/__snapshots__/helper.test.js.snap +1 -1
  33. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +34 -10
  34. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +12 -0
  35. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +1 -0
  36. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +30 -9
  37. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +4 -0
  38. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +1 -0
  39. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionSelectors.test.js +12 -0
  40. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +31 -5
  41. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionSelectors.test.js.snap +8 -0
  42. data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +1 -1
  43. data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +3 -3
  44. data/webpack/components/ApplicationDefinition/index.js +8 -0
  45. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.js +214 -0
  46. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.scss +1 -0
  47. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportActions.js +161 -0
  48. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportConstants.js +6 -0
  49. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportReducer.js +79 -0
  50. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportSelectors.js +8 -0
  51. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportConfData_1.fixtures.js +129 -0
  52. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportReducer.fixtures.js +29 -0
  53. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImport.test.js +20 -0
  54. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportReducer.test.js +43 -0
  55. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportSelectors.test.js +29 -0
  56. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImport.test.js.snap +62 -0
  57. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportReducer.test.js.snap +362 -0
  58. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportSelectors.test.js.snap +130 -0
  59. data/webpack/components/ApplicationDefinitionImport/index.js +32 -0
  60. data/webpack/components/ApplicationInstance/ApplicationInstance.js +102 -26
  61. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +118 -6
  62. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +4 -0
  63. data/webpack/components/ApplicationInstance/ApplicationInstanceHelper.js +15 -0
  64. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +71 -30
  65. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +4 -0
  66. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +2 -0
  67. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +1 -0
  68. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +12 -0
  69. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceSelectors.test.js +12 -0
  70. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +98 -7
  71. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +271 -0
  72. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceSelectors.test.js.snap +8 -0
  73. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +1 -0
  74. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +1 -1
  75. data/webpack/components/ApplicationInstance/helper.js +0 -0
  76. data/webpack/components/ApplicationInstance/index.js +8 -0
  77. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +81 -6
  78. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +35 -1
  79. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +3 -0
  80. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +19 -0
  81. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +4 -0
  82. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +1 -124
  83. data/webpack/components/ApplicationInstanceReport/index.js +8 -1
  84. data/webpack/components/ExistingHostSelection/ExistingHostSelection.js +104 -0
  85. data/webpack/components/ExistingHostSelection/ExistingHostSelection.scss +15 -0
  86. data/webpack/components/ExistingHostSelection/ExistingHostSelectionActions.js +71 -0
  87. data/webpack/components/ExistingHostSelection/ExistingHostSelectionConstants.js +4 -0
  88. data/webpack/components/ExistingHostSelection/ExistingHostSelectionHelper.js +0 -0
  89. data/webpack/components/ExistingHostSelection/ExistingHostSelectionReducer.js +90 -0
  90. data/webpack/components/ExistingHostSelection/ExistingHostSelectionSelectors.js +8 -0
  91. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionConfData_1.fixtures.js +191 -0
  92. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionReducer.fixtures.js +203 -0
  93. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelection.test.js +19 -0
  94. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionReducer.test.js +59 -0
  95. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionSelectors.test.js +36 -0
  96. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelection.test.js.snap +35 -0
  97. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionReducer.test.js.snap +614 -0
  98. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionSelectors.test.js.snap +27 -0
  99. data/webpack/components/ExistingHostSelection/components/ServiceSelector.js +48 -0
  100. data/webpack/components/ExistingHostSelection/components/__tests__/ServiceSelector.test.js +35 -0
  101. data/webpack/components/ExistingHostSelection/components/__tests__/__snapshots__/ServiceSelector.test.js.snap +77 -0
  102. data/webpack/components/ExistingHostSelection/index.js +26 -0
  103. data/webpack/components/ParameterSelection/ParameterSelection.js +103 -1
  104. data/webpack/components/ParameterSelection/ParameterSelection.scss +7 -0
  105. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +46 -4
  106. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +2 -0
  107. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +5 -1
  108. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +52 -11
  109. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -0
  110. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +8 -0
  111. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +2 -0
  112. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -0
  113. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +96 -0
  114. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +117 -17
  115. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +13 -0
  116. data/webpack/components/ParameterSelection/index.js +4 -1
  117. data/webpack/components/SyncGitRepo/SyncGitRepo.js +2 -10
  118. data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +2 -3
  119. data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +0 -1
  120. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +1 -0
  121. data/webpack/components/SyncGitRepo/components/FormTextInput.js +1 -1
  122. data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +3 -2
  123. data/webpack/components/common/DeleteTableEntry.js +16 -2
  124. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +38 -0
  125. data/webpack/helper.js +21 -1
  126. data/webpack/helper.test.js +20 -1
  127. data/webpack/index.js +5 -0
  128. data/webpack/js-yaml.js +3874 -0
  129. data/webpack/reducer.js +13 -2
  130. data/webpack/test_setup.js +0 -2
  131. metadata +46 -2
@@ -32,7 +32,7 @@ module ForemanAcd
32
32
 
33
33
  children[ansible_group] = { 'hosts' => {} } unless children.key?(host_service['ansibleGroup'])
34
34
 
35
- ansible_vars = JSON.parse(foreman_host.ansibleParameters).map { |v| { v['name'] => v['value'] } }.reduce({}, :merge!)
35
+ ansible_vars = JSON.parse(foreman_host.ansibleParameters).map { |v| { v['name'] => get_param_value(foreman_host.host, v['value']) } }.reduce({}, :merge!)
36
36
 
37
37
  # in case there is no ansible_user defined, set "root" as default.
38
38
  ansible_vars['ansible_user'] = 'root' unless ansible_vars.key?('ansible_user')
@@ -46,6 +46,16 @@ module ForemanAcd
46
46
 
47
47
  private
48
48
 
49
+ def get_param_value(host, value)
50
+ search_param = value.match(/PARAM\[([^\s]*)\]/)
51
+ return value if search_param.nil?
52
+
53
+ resolved_value = host.host_param(search_param[1])
54
+ logger.warn "Could not resolve ansible host param value #{value} for host #{host}" if resolved_value.nil?
55
+
56
+ resolved_value
57
+ end
58
+
49
59
  def ansible_or_rex_ssh_private_key(host)
50
60
  ansible_private_file = host_setting(host, 'ansible_ssh_private_key_file')
51
61
  if !ansible_private_file.empty?
@@ -24,6 +24,10 @@
24
24
  if @app_definition.ansible_vars_all.present?
25
25
  json["ansibleVarsAll"] = JSON.parse(@app_definition.ansible_vars_all)
26
26
  end
27
+
28
+ json["supportedPlugins"] = {}
29
+ json["supportedPlugins"]["puppet"] = defined?(ForemanPuppet) != nil
30
+ json["supportedPlugins"]["katello"] = defined?(Katello) != nil
27
31
  %>
28
32
 
29
33
  <%= form_for @app_definition, :url => (@app_definition.new_record? ? app_definitions_path : app_definition_path(:id => @app_definition.id)) do |f| %>
@@ -1,3 +1,22 @@
1
+ <%= javascript_include_tag *webpack_asset_paths('foreman_acd', extension: 'js') %>
2
+ <%
3
+ json = {
4
+ "organization": current_organization,
5
+ "location": current_location,
6
+ "hostgroups": @hostgroups,
7
+ "foremanDataUrl": ui_acd_foreman_data_path("__id__"),
8
+ "ansibleDataUrl": ui_acd_ansible_data_path("__id__"),
9
+ "services": [],
10
+ "ansibleVarsAll": [],
11
+ }
12
+
13
+ if @app_definition.new_record?
14
+ json["mode"] = "newDefinition"
15
+ else
16
+ json["mode"] = "editDefinition"
17
+ end
18
+ %>
19
+
1
20
  <% title _('Import Application Definition') %>
2
21
 
3
22
  <%= form_for @app_definition, :url => (app_definitions_path), :html => { :multipart => true } do |f| %>
@@ -10,7 +29,7 @@
10
29
  <div class="tab-pane active" id="primary">
11
30
  <%= text_f f, :name %>
12
31
  <%= text_f f, :description %>
13
- <%= file_field_f f, :app_definition_file, :label_help => _("Application Definition file") %>
32
+ <%= react_component('ApplicationDefinitionImport', json,) %>
14
33
  </div>
15
34
  </div>
16
35
 
@@ -1,15 +1,12 @@
1
1
  <% title _('Application Definitions') %>
2
2
 
3
- <% title_actions button_group(
4
- new_link(_('New Application Definition')),
5
- display_link_if_authorized(_("Import"), hash_for_import_app_definitions_path, :class => 'btn btn-default', :style => "display: none;")
6
- ) %>
3
+ <% title_actions new_link(_('New Application Definition')), display_link_if_authorized(_("Import"), hash_for_import_app_definitions_path, :class => 'btn btn-default') %>
7
4
 
8
5
  <table class="table table-bordered table-striped">
9
6
  <tr>
10
7
  <th><%= sort :name, :as => s_('AppDefinition|Name') %></th>
11
8
  <th><%= _('Description') %></th>
12
- <th></th>
9
+ <th><%= _('Actions') %></th>
13
10
  </tr>
14
11
  <% for app_definition in @app_definitions %>
15
12
  <tr>
@@ -19,7 +16,7 @@
19
16
  <%= action_buttons(
20
17
  display_delete_if_authorized(hash_for_app_definition_path(:id => app_definition),
21
18
  :data => { 'confirm': _('Delete %s?') % app_definition.name }),
22
- # TODO: add export feature again if app-def + ansible playbook can be exported together display_link_if_authorized(_("Export"), hash_for_export_app_definition_path(:id => app_definition))
19
+ display_link_if_authorized(_("Export"), hash_for_export_app_definition_path(:id => app_definition))
23
20
  ) %>
24
21
  </td>
25
22
  </tr>
@@ -24,6 +24,10 @@
24
24
  "ansibleVarsAll": @app_instance.ansible_vars_all.blank? ? [] : JSON.parse(@app_instance.ansible_vars_all),
25
25
  }
26
26
  end
27
+
28
+ json["supportedPlugins"] = {}
29
+ json["supportedPlugins"]["puppet"] = defined?(ForemanPuppet) != nil
30
+ json["supportedPlugins"]["katello"] = defined?(Katello) != nil
27
31
  %>
28
32
 
29
33
  <%= form_for @app_instance, :url => (@app_instance.new_record? ? app_instances_path : app_instance_path(:id => @app_instance.id)) do |f| %>
@@ -53,21 +53,25 @@
53
53
  <div class="modal-content">
54
54
  <div class="modal-header">
55
55
  <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
56
- <h4 class="modal-title"><%= _('Confirmation Box')%></h4>
56
+ <h4 class="modal-title"><%= _('Confirmation')%></h4>
57
57
  </div>
58
58
  <div class="modal-body">
59
- <p> <%= _("Confirm to delete ") %> <%= app_instance %></p>
59
+ <p> <%= _("Confirm to delete application instance: ") %> <%= app_instance %></p>
60
60
  <%= form_tag destroy_with_hosts_app_instance_path(:id => app_instance.id), :method => :delete do %>
61
- <% if app_instance.foreman_hosts.where.not(:host_id => [nil, false]).any? %>
62
- <p><%= _("Select the hosts to delete along with ") %> <%= app_instance %>: </p>
63
- <% end %>
64
- <% app_instance.foreman_hosts.each do |foreman_host|%>
61
+ <% showSelectHostsNote = true %>
62
+ <% app_instance.foreman_hosts.select(&:fresh_host?).each do |foreman_host|%>
65
63
  <% if foreman_host.host_id? %>
66
- <%= check_box_tag 'foreman_host_ids[]', foreman_host.host_id -%>
67
- <%= h foreman_host.host.name -%>
68
- </br>
64
+ <% if showSelectHostsNote %>
65
+ <p><%= _("Select the hosts to delete along with ") %> <%= app_instance %>: </p>
66
+ <% showSelectHostsNote = false %>
67
+ <% end %>
68
+ <%= check_box_tag 'foreman_host_ids[]', foreman_host.host_id, false, class: 'acd_host' -%> <%= h foreman_host.host.name -%>
69
+ </br>
69
70
  <% end %>
70
71
  <% end %>
72
+ <hr width="90%">
73
+ <p> <%= check_box_tag "check_all", "", false, { :onchange => "toggleCheckboxesBySelector('.acd_host')" } %> Select / unselect all hosts</p>
74
+ <br /><p><%= _("Note: Hosts which already existed and were added to the application instance are not shown in this dialog!") %></p>
71
75
  </div>
72
76
  <div class="modal-footer">
73
77
  <button type="button" class="btn btn-primary" data-dismiss="modal"><%= _('Cancel') %></button>
@@ -91,8 +95,8 @@
91
95
  <%= form_tag deploy_app_instance_path(:id => app_instance.id), :method => :post do %>
92
96
  <% if app_instance.foreman_hosts.where.not(:host_id => [nil, false]).any? %>
93
97
  <ul>
94
- <li><%= check_box_tag 'delete_hosts'-%><%= _('Delete all hosts before deploying ') %><%= app_instance%></li>
95
- <li><%= check_box_tag 'safe_deploy' -%><%= _('Deploy only new and changed hosts for ') %><%= app_instance%></li>
98
+ <li><%= check_box_tag 'delete_hosts'-%> <%= _('Delete all hosts before deploying ') %><%= app_instance%></li>
99
+ <li><%= check_box_tag 'safe_deploy' -%> <%= _('Deploy only new and changed hosts for ') %><%= app_instance%></li>
96
100
  </ul>
97
101
  <% end %>
98
102
  </div>
@@ -9,12 +9,17 @@
9
9
 
10
10
  <%
11
11
  json = {
12
- "mode": 'lastReport',
12
+ "deploymentState": @app_instance.deployment_state.to_s,
13
+ "initialConfigureState": @app_instance.initial_configure_state.to_s,
13
14
  "appInstanceName": @app_instance.name,
14
15
  "hosts": @report_hosts,
15
16
  "deployTaskUrl": foreman_tasks_task_path(@app_instance.last_deploy_task),
16
- "configureJobUrl": job_invocations_path(search: "description ~ \"ACD application #{@app_instance.name}\"")
17
+ "configureJobUrl": job_invocations_path(search: "description ~ \"ACD application #{@app_instance.name}\""),
18
+ "reportDataUrl": ui_acd_report_data_path("__id__"),
19
+ "appInstanceId": @app_instance.id,
17
20
  }
21
+
22
+ json["initialConfigureJobUrl"] = job_invocation_path(@app_instance.initial_configure_job) unless @app_instance.initial_configure_job.nil?
18
23
  %>
19
24
 
20
25
  <div id='report'></div>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ collection @hosts
4
+ attributes :id, :name, :build, :hostUrl, :isExistingHost, :progress_report, :powerStatusUrl
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ object @report_data
4
+ attribute :deploymentState
5
+ attribute :initialConfigureState
6
+ attribute :initialConfigureJobUrl
7
+
8
+ child :hosts => :hosts do
9
+ extends 'ui_acd/host_report'
10
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ object @host_validation
4
+ attribute :hostname
5
+ attribute :fqdn
6
+ attribute :result
data/config/routes.rb CHANGED
@@ -18,6 +18,7 @@ Rails.application.routes.draw do
18
18
  collection do
19
19
  get 'auto_complete_search'
20
20
  get 'import'
21
+ post 'handle_file_upload'
21
22
  end
22
23
 
23
24
  member do
@@ -42,6 +43,8 @@ Rails.application.routes.draw do
42
43
  get 'ui_acd_app/:id', :to => 'ui_acd#app', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_app
43
44
  get 'ui_acd_foreman_data/:id', :to => 'ui_acd#foreman_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_foreman_data
44
45
  get 'ui_acd_ansible_data/:id', :to => 'ui_acd#ansible_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_ansible_data
46
+ get 'ui_acd_report_data/:id', :to => 'ui_acd#report_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_report_data
47
+ get 'ui_acd_validate_hostname', :to => 'ui_acd#validate_hostname', :as => :ui_acd_validate_hostname
45
48
 
46
49
  scope :api, :path => '/api', :defaults => { :format => 'json' } do
47
50
  scope '(:apiv)', :defaults => { :apiv => 'v2' },
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add is_existing_host to app instance
4
+ class AddIsExistingHostToForemanHost < ActiveRecord::Migration[6.0]
5
+ def change
6
+ add_column :acd_foreman_hosts, :is_existing_host, :boolean, :default => false, :null => false
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add AddInitialConfigureTask
4
+ class AddInitialConfigureTask < ActiveRecord::Migration[5.2]
5
+ def change
6
+ add_column :acd_app_instances, :initial_configure_task_id, :uuid, :null => true
7
+ end
8
+ end
@@ -33,7 +33,7 @@ Foreman::Plugin.register :foreman_acd do
33
33
  :resource_type => 'ForemanAcd::AnsiblePlaybook'
34
34
 
35
35
  permission :edit_ansible_playbooks,
36
- { :'foreman_acd/ansible_playbooks' => [:update, :edit],
36
+ { :'foreman_acd/ansible_playbooks' => [:update, :edit, :sync_git_repo],
37
37
  :'foreman_acd/api/v2/ansible_playbooks' => [:update] },
38
38
  :resource_type => 'ForemanAcd::AnsiblePlaybook'
39
39
 
@@ -72,7 +72,7 @@ Foreman::Plugin.register :foreman_acd do
72
72
  :resource_type => 'ForemanAcd::AppDefinition'
73
73
 
74
74
  permission :export_app_definitions,
75
- { :'foreman_acd/app_definitions' => [:export],
75
+ { :'foreman_acd/app_definitions' => [:export, :handle_file_upload],
76
76
  :'foreman_acd/api/v2/app_definitions' => [:export] },
77
77
  :resource_type => 'ForemanAcd::AppDefinition'
78
78
 
@@ -111,16 +111,16 @@ Foreman::Plugin.register :foreman_acd do
111
111
  :'foreman_acd/api/v2/app_instances' => [:report] },
112
112
  :resource_type => 'ForemanAcd::AppInstance'
113
113
 
114
- permission :new_remote_execution,
114
+ permission :new_acd_configure_job,
115
115
  { :'foreman_acd/remote_execution' => [:new] },
116
- :resource_type => 'ForemanAcd::RemoteExecution'
116
+ :resource_type => 'ForemanAcd::AppInstance'
117
117
 
118
- permission :create_remote_execution,
118
+ permission :create_acd_configure_job,
119
119
  { :'foreman_acd/remote_execution' => [:create] },
120
- :resource_type => 'ForemanAcd::RemoteExecution'
120
+ :resource_type => 'ForemanAcd::AppInstance'
121
121
 
122
122
  permission :view_ui_acd,
123
- { :ui_acd => [:app, :foreman_data, :ansible_data] }
123
+ { :ui_acd => [:app, :foreman_data, :ansible_data, :validate_hostname, :report_data] }
124
124
 
125
125
  permission :acd_foreman_hosts,
126
126
  { :'foreman_acd/app_instances' => [:create, :edit, :update, :deploy, :destroy_with_hosts, :destroy] },
@@ -137,7 +137,7 @@ Foreman::Plugin.register :foreman_acd do
137
137
  :create_app_instances, :view_app_instances, :edit_app_instances,
138
138
  :destroy_app_instances,
139
139
  :deploy_app_instances,
140
- :new_remote_execution, :create_remote_execution,
140
+ :new_acd_configure_job, :create_acd_configure_job,
141
141
  :report_app_instances,
142
142
  :view_ui_acd,
143
143
  :view_hosts, :build_hosts, :power_hosts, :create_hosts, :edit_hosts, :destroy_hosts, :console_hosts,
@@ -150,7 +150,7 @@ Foreman::Plugin.register :foreman_acd do
150
150
  role 'Application Centric Deployment User', [:create_app_instances, :view_app_instances, :edit_app_instances,
151
151
  :destroy_app_instances,
152
152
  :deploy_app_instances,
153
- :new_remote_execution, :create_remote_execution,
153
+ :new_acd_configure_job, :create_acd_configure_job,
154
154
  :report_app_instances,
155
155
  :view_ui_acd,
156
156
  :view_hosts, :build_hosts, :power_hosts, :create_hosts, :edit_hosts, :destroy_hosts, :console_hosts,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanAcd
4
- VERSION = '0.7.0'
4
+ VERSION = '0.9.2'
5
5
  end
data/lib/foreman_acd.rb CHANGED
@@ -4,16 +4,34 @@ require 'foreman_acd/engine'
4
4
 
5
5
  # Module required to start the Foreman Rails engine
6
6
  module ForemanAcd
7
- def self.acd_base_path
8
- '/var/lib/foreman/foreman_acd/'
9
- end
7
+ RUN_CONFIGURATOR_DELAY = 240
10
8
 
11
- def self.ansible_playbook_path
12
- File.join(acd_base_path, 'ansible-playbooks')
13
- end
9
+ class << self
10
+ def acd_base_path
11
+ '/var/lib/foreman/foreman_acd/'
12
+ end
13
+
14
+ def ansible_playbook_path
15
+ File.join(acd_base_path, 'ansible-playbooks')
16
+ end
17
+
18
+ def proxy_setting
19
+ HttpProxy.default_global_content_proxy&.full_url ||
20
+ Setting[:http_proxy]
21
+ end
22
+
23
+ def initiate_acd_app_configurator(app_instance)
24
+ return unless app_instance.hosts_deployment_finished?
25
+
26
+ ::Foreman::Logging.logger('foreman_acd').info("All hosts of app (#{app_instance.name}) were built. Schedule app configurator...")
27
+ start_acd_app_configurator(app_instance)
28
+ end
14
29
 
15
- def self.proxy_setting
16
- HttpProxy.default_global_content_proxy&.full_url ||
17
- Setting[:http_proxy]
30
+ def start_acd_app_configurator(app_instance)
31
+ task = ForemanTasks.delay(::Actions::ForemanAcd::RunConfigurator,
32
+ { :start_at => Time.zone.now + RUN_CONFIGURATOR_DELAY },
33
+ app_instance)
34
+ app_instance.update(:initial_configure_task_id => task.id)
35
+ end
18
36
  end
19
37
  end
data/package.json CHANGED
@@ -1,42 +1,25 @@
1
1
  {
2
2
  "name": "foreman_acd",
3
- "version": "0.3.0",
3
+ "version": "0.9.2",
4
4
  "description": "foreman application centric deployment",
5
5
  "main": "index.js",
6
6
  "directories": {
7
7
  "test": "test"
8
8
  },
9
- "dependencies": {
10
- "@theforeman/vendor": "^1.7.0",
11
- "react-intl": "^2.8.0"
9
+ "peerDependencies": {
10
+ "@theforeman/vendor": ">= 10.1.0"
12
11
  },
13
12
  "devDependencies": {
14
- "@theforeman/vendor-dev": "^1.7.0",
15
- "babel-eslint": "^8.2.1",
16
- "babel-jest": "^23.6.0",
17
- "babel-plugin-dynamic-import-node": "^2.3.3",
18
- "babel-plugin-syntax-dynamic-import": "^6.18.0",
13
+ "@theforeman/builder": "^10.1.0",
14
+ "@theforeman/eslint-plugin-foreman": "^10.1.0",
15
+ "@theforeman/test": "^10.1.0",
16
+ "@theforeman/vendor-dev": "^10.1.0",
19
17
  "babel-plugin-transform-class-properties": "^6.24.1",
20
- "babel-plugin-transform-object-assign": "^6.22.0",
21
- "babel-plugin-transform-object-rest-spread": "^6.26.0",
22
18
  "babel-preset-env": "^1.6.0",
23
19
  "babel-preset-react": "^6.24.1",
24
- "enzyme": "^3.11.0",
25
- "enzyme-adapter-react-16": "^1.15.6",
26
- "enzyme-to-json": "^3.6.1",
27
- "eslint": "^4.18.1",
28
- "eslint-plugin-import": "^2.22.1",
29
- "eslint-plugin-jest": "^21.2.0",
30
- "eslint-plugin-patternfly-react": "^0.2.1",
31
- "eslint-plugin-react": "^7.22.0",
32
- "identity-obj-proxy": "^3.0.0",
33
20
  "jest": "^23.6.0",
34
- "jest-cli": "^23.6.0",
35
21
  "jest-prop-type-error": "^1.1.0",
36
- "lodash": "^4.17.21",
37
- "react-redux-test-utils": "^0.1.1",
38
- "sortabular": "~1.5.1",
39
- "table-resolver": "~3.2.0"
22
+ "react-redux-test-utils": "^0.1.1"
40
23
  },
41
24
  "scripts": {
42
25
  "test": "node node_modules/.bin/jest --no-cache"
@@ -30,7 +30,10 @@ class UiAcdControllerTest < ActionController::TestCase
30
30
  assert_equal json_app_all.first['name'], parsed_all_response.first['name']
31
31
  end
32
32
 
33
- test 'get foreman data json' do
33
+ test 'get foreman data json foreman <3' do
34
+ # TODO: Get rid of the puppet dependency at all!
35
+ skip 'Puppet env was removed with foreman >= 3.x' unless defined?(ForemanPuppet)
36
+
34
37
  hostgroup = FactoryBot.create(:hostgroup, :with_domain, :with_os, :with_environment)
35
38
  get :foreman_data, :params => { :id => hostgroup.id }, :session => set_session_user
36
39
  assert_response :success
@@ -0,0 +1,2 @@
1
+ export const setModalOpen = () => jest.fn();
2
+ export const setModalClosed = () => jest.fn();
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`helper creates a object from an array 1`] = `
3
+ exports[`helper formats a nice, easy header 1`] = `
4
4
  <TableHeading
5
5
  align=""
6
6
  aria-label="TheLabel"
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
4
4
  import {
5
5
  Icon,
6
6
  Button,
7
+ MessageDialog,
7
8
  } from 'patternfly-react';
8
9
  import * as resolve from 'table-resolver';
9
10
  import ForemanModal from 'foremanReact/components/ForemanModal';
@@ -56,7 +57,7 @@ class ApplicationDefinition extends React.Component {
56
57
 
57
58
  componentDidMount() {
58
59
  const {
59
- data: { mode, ansiblePlaybook, ansibleDataUrl, services, ansibleVarsAll, hostgroups },
60
+ data: { mode, ansiblePlaybook, ansibleDataUrl, services, ansibleVarsAll, hostgroups, supportedPlugins },
60
61
  initApplicationDefinition,
61
62
  addApplicationDefinitionService,
62
63
  deleteApplicationDefinitionService,
@@ -75,21 +76,21 @@ class ApplicationDefinition extends React.Component {
75
76
  bsStyle="default"
76
77
  onClick={() => activateEditApplicationDefinitionService(additionalData)}
77
78
  >
78
- <Icon type="pf" name="edit" title={__("edit entry")} />
79
+ <Icon type="pf" name="edit" title={__("Edit entry")} />
79
80
  </Button>
80
81
  &nbsp;
81
82
  <Button
82
83
  bsStyle="default"
83
84
  onClick={() => openForemanParameterSelectionModal(additionalData)}
84
85
  >
85
- <Icon type="pf" name="settings" title={__("change parameters")} />
86
+ <Icon type="pf" name="settings" title={__("Change parameters")} />
86
87
  </Button>
87
88
  &nbsp;
88
89
  <Button
89
90
  bsStyle="default"
90
91
  onClick={() => openAnsibleParameterSelectionModal(additionalData)}
91
92
  >
92
- <span title={__("change ansible variables")}>A</span>
93
+ <span title={__("Change ansible variables")}>A</span>
93
94
  </Button>
94
95
  &nbsp;
95
96
  <DeleteTableEntry
@@ -193,6 +194,7 @@ class ApplicationDefinition extends React.Component {
193
194
  ansiblePlaybook,
194
195
  services,
195
196
  ansibleVarsAll,
197
+ supportedPlugins,
196
198
  this.headerFormatter,
197
199
  this.inlineEditFormatter,
198
200
  this.inlineEditButtonsFormatter,
@@ -202,9 +204,11 @@ class ApplicationDefinition extends React.Component {
202
204
  render() {
203
205
  const {
204
206
  data: { organization, location, mode, ansiblePlaybooks, foremanDataUrl, ansibleDataUrl },
207
+ showAlertModal, alertModalText, alertModalTitle, closeAlertModal,
205
208
  ansiblePlaybook,
206
209
  services,
207
210
  columns,
211
+ hiddenForemanParameterTypes,
208
212
  addApplicationDefinitionService,
209
213
  confirmEditApplicationDefinitionService,
210
214
  cancelEditApplicationDefinitionService,
@@ -216,12 +220,22 @@ class ApplicationDefinition extends React.Component {
216
220
  loadAnsibleData,
217
221
  } = this.props;
218
222
 
219
-
220
223
  return (
221
224
  <span>
225
+ <MessageDialog
226
+ show={showAlertModal}
227
+ onHide={closeAlertModal}
228
+ primaryAction={closeAlertModal}
229
+ primaryActionButtonContent={__('OK')}
230
+ primaryActionButtonBsStyle={"danger"}
231
+ icon={<Icon type="pf" name="error-circle-o" />}
232
+ title={alertModalTitle}
233
+ primaryContent={alertModalText}
234
+ />
222
235
  <div>
223
236
  <AnsiblePlaybookSelector
224
237
  label="Ansible Playbook"
238
+ hidden={ false }
225
239
  editable={ mode == 'newDefinition' }
226
240
  viewText={ ansiblePlaybook.name }
227
241
  options={ ansiblePlaybooks }
@@ -230,9 +244,9 @@ class ApplicationDefinition extends React.Component {
230
244
  additionalData={{url: ansibleDataUrl }}
231
245
  />
232
246
  {ansiblePlaybook.id == '' ? (
233
- <p style={{ paddingTop: 25 }}>
247
+ <div style={{ paddingTop: 25 }}>
234
248
  <pre>{ "Ansible Playbook can't be blank" }</pre>
235
- </p>
249
+ </div>
236
250
  ) : (<div></div>)}
237
251
 
238
252
  </div>
@@ -279,7 +293,7 @@ class ApplicationDefinition extends React.Component {
279
293
  isAllGroup: true
280
294
  })}
281
295
  >
282
- <span title={__("change ansible variables for 'all'")}>A</span>
296
+ <span title={__("Change ansible variables for 'all'")}>A</span>
283
297
  </Button>
284
298
  </span>
285
299
  </div>
@@ -296,6 +310,7 @@ class ApplicationDefinition extends React.Component {
296
310
  <ParameterSelection
297
311
  editModeCallback={ (hide) => changeParameterSelectionMode({ mode: hide })}
298
312
  paramType={ PARAMETER_SELECTION_PARAM_TYPE_FOREMAN }
313
+ hiddenParameterTypes={ hiddenForemanParameterTypes }
299
314
  location={ location }
300
315
  organization={ organization }
301
316
  paramDataUrl= { foremanDataUrl }
@@ -339,13 +354,13 @@ class ApplicationDefinition extends React.Component {
339
354
  </ForemanModal>
340
355
  </div>
341
356
  <RailsData
342
- key='applications_definition'
357
+ key='application_definition_services_data'
343
358
  view='app_definition'
344
359
  parameter='services'
345
360
  value={JSON.stringify(this.props.services)}
346
361
  />
347
362
  <RailsData
348
- key='applications_definition'
363
+ key='application_definition_ansible_data'
349
364
  view='app_definition'
350
365
  parameter='ansible_vars_all'
351
366
  value={JSON.stringify(this.props.ansibleVarsAll)}
@@ -356,23 +371,32 @@ class ApplicationDefinition extends React.Component {
356
371
 
357
372
  ApplicationDefinition.defaultProps = {
358
373
  error: {},
374
+ showAlertModal: false,
375
+ alertModalText: '',
376
+ alertModalTitle: '',
359
377
  editMode: false,
360
378
  ansiblePlaybook: { "id": '', "name": '' },
361
379
  services: [],
362
380
  ansibleVarsAll: [],
363
381
  parametersData: {},
364
382
  columns: [],
383
+ hiddenForemanParameterTypes: [],
365
384
  editParamsOfRowId: null,
366
385
  paramEditMode: false,
367
386
  }
368
387
 
369
388
  ApplicationDefinition.propTypes = {
370
389
  initApplicationDefinition: PropTypes.func,
390
+ showAlertModal: PropTypes.bool,
391
+ alertModalText: PropTypes.string,
392
+ alertModalTitle: PropTypes.string,
371
393
  editMode: PropTypes.bool.isRequired,
372
394
  ansiblePlaybook: PropTypes.object,
373
395
  services: PropTypes.array,
374
396
  ansibleVarsAll: PropTypes.array,
375
397
  columns: PropTypes.array,
398
+ hiddenForemanParameterTypes: PropTypes.array,
399
+ closeAlertModal: PropTypes.func,
376
400
  addApplicationDefinitionService: PropTypes.func,
377
401
  deleteApplicationDefinitionService: PropTypes.func,
378
402
  activateEditApplicationDefinitionService: PropTypes.func,
@@ -17,6 +17,7 @@ import {
17
17
 
18
18
  import {
19
19
  APPLICATION_DEFINITION_INIT,
20
+ APPLICATION_DEFINITION_CLOSE_ALERT_MODAL,
20
21
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST,
21
22
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS,
22
23
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE,
@@ -33,6 +34,10 @@ import {
33
34
  APPLICATION_DEFINITION_CHANGE_PARAMETER_SELECTION_MODE,
34
35
  } from './ApplicationDefinitionConstants';
35
36
 
37
+ import {
38
+ supportedPluginsToHiddenParameterTypes,
39
+ } from '../../helper';
40
+
36
41
  import {
37
42
  transformAnsiblePlaybook,
38
43
  } from './ApplicationDefinitionHelper';
@@ -41,6 +46,7 @@ export const initApplicationDefinition = (
41
46
  ansiblePlaybook,
42
47
  services,
43
48
  ansibleVarsAll,
49
+ supportedPlugins,
44
50
  headerFormatter,
45
51
  inlineEditFormatter,
46
52
  inlineEditButtonsFormatter,
@@ -167,6 +173,7 @@ export const initApplicationDefinition = (
167
173
  }
168
174
  initialState.services = services;
169
175
  initialState.ansibleVarsAll = ansibleVarsAll;
176
+ initialState.hiddenForemanParameterTypes = supportedPluginsToHiddenParameterTypes(supportedPlugins);
170
177
 
171
178
  dispatch({
172
179
  type: APPLICATION_DEFINITION_INIT,
@@ -182,6 +189,11 @@ const errorHandler = (msg, err) => {
182
189
  return { type: msg, payload: { error } };
183
190
  };
184
191
 
192
+ export const closeAlertModal = () => ({
193
+ type: APPLICATION_DEFINITION_CLOSE_ALERT_MODAL,
194
+ payload: {}
195
+ });
196
+
185
197
  export const loadAnsibleData = (
186
198
  ansiblePlaybookId,
187
199
  additionalData
@@ -1,4 +1,5 @@
1
1
  export const APPLICATION_DEFINITION_INIT = 'INIT_APPLICATION_DEFINITION_INIT';
2
+ export const APPLICATION_DEFINITION_CLOSE_ALERT_MODAL = 'APPLICATION_DEFINITION_CLOSE_ALERT_MODAL';
2
3
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST';
3
4
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS';
4
5
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE';