foreman_acd 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/foreman_acd/ansible_playbooks_controller.rb +75 -0
- data/app/controllers/foreman_acd/app_instances_controller.rb +19 -2
- data/app/controllers/foreman_acd/concerns/ansible_playbook_parameters.rb +1 -1
- data/app/controllers/foreman_acd/remote_execution_controller.rb +37 -21
- data/app/lib/actions/foreman_acd/deploy_all_hosts.rb +12 -7
- data/app/lib/actions/foreman_acd/run_configurator.rb +10 -7
- data/app/models/concerns/foreman_acd/host_managed_extensions.rb +2 -2
- data/app/models/foreman_acd/acd_provider.rb +7 -1
- data/app/models/foreman_acd/ansible_playbook.rb +2 -1
- data/app/models/foreman_acd/app_instance.rb +1 -1
- data/app/services/foreman_acd/acd_proxy_proxy_selector.rb +17 -0
- data/app/services/foreman_acd/app_configurator.rb +59 -15
- data/app/services/foreman_acd/app_deployer.rb +8 -2
- data/app/services/foreman_acd/inventory_creator.rb +14 -0
- data/app/views/foreman_acd/ansible_playbooks/_form.html.erb +41 -7
- data/app/views/foreman_acd/app_definitions/_form.html.erb +1 -1
- data/app/views/foreman_acd/app_instances/_form.html.erb +1 -1
- data/app/views/foreman_acd/app_instances/index.html.erb +5 -3
- data/app/views/foreman_acd/app_instances/report.html.erb +1 -1
- data/app/views/templates/job/run_acd_ansible_playbook.erb +1 -1
- data/config/routes.rb +3 -0
- data/db/migrate/20210316151145_add_git_commit_to_ansible_playbooks.rb +8 -0
- data/db/migrate/20210503122809_add_git_url_to_ansible_playbooks.rb +8 -0
- data/db/seeds.d/75-job_templates.rb +1 -1
- data/lib/foreman_acd.rb +12 -0
- data/lib/foreman_acd/engine.rb +26 -4
- data/lib/foreman_acd/plugin.rb +0 -9
- data/lib/foreman_acd/version.rb +1 -1
- data/lib/tasks/foreman_acd_tasks.rake +0 -12
- data/package.json +8 -8
- data/test/controllers/ansible_playbooks_controller_test.rb +1 -1
- data/test/controllers/app_instances_controller_test.rb +8 -3
- data/test/controllers/ui_acd_controller_test.rb +22 -6
- data/test/factories/foreman_acd_factories.rb +18 -4
- data/test/models/acd_provider_test.rb +37 -0
- data/test/models/ansible_playbook_test.rb +11 -0
- data/test/models/app_definition_test.rb +1 -1
- data/test/models/app_instance_test.rb +2 -0
- data/test/models/concerns/host_extensions_test.rb +26 -0
- data/test/models/foreman_host_test.rb +12 -0
- data/webpack/__mocks__/foremanReact/API.js +2 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +3 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal.js +7 -0
- data/webpack/__mocks__/foremanReact/components/common/forms/CommonForm.js +2 -0
- data/webpack/__mocks__/foremanReact/components/common/forms/TextInput.js +2 -0
- data/webpack/__mocks__/foremanReact/components/hosts/powerStatus.js +1 -0
- data/webpack/__snapshots__/helper.test.js.snap +14 -0
- data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +1 -1
- data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionConfData_1.fixtures.js +288 -0
- data/webpack/components/ApplicationDefinition/__fixtures__/applicationDefinitionReducer.fixtures.js +79 -0
- data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +25 -0
- data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionReducer.test.js +119 -0
- data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionSelectors.test.js +41 -0
- data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +200 -0
- data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionReducer.test.js.snap +3033 -0
- data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionSelectors.test.js.snap +299 -0
- data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +1 -0
- data/webpack/components/ApplicationDefinition/components/__tests__/AnsiblePlaybookSelector.test.js +41 -0
- data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +121 -0
- data/webpack/components/ApplicationInstance/ApplicationInstance.js +3 -5
- data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceConfData_1.fixtures.js +263 -0
- data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +78 -0
- data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +23 -0
- data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +119 -0
- data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceSelectors.test.js +44 -0
- data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +209 -0
- data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +2719 -0
- data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceSelectors.test.js.snap +276 -0
- data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportData_1.fixtures.js +349 -0
- data/webpack/components/ApplicationInstanceReport/__fixtures__/applicationInstanceReportReducer.fixtures.js +20 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReport.test.js +47 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportReducer.test.js +41 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/ApplicationInstanceReportSelectors.test.js +26 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +130 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportReducer.test.js.snap +718 -0
- data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReportSelectors.test.js.snap +347 -0
- data/webpack/components/ApplicationInstanceReport/components/__tests__/ReportViewer.test.js +24 -0
- data/webpack/components/ApplicationInstanceReport/components/__tests__/__snapshots__/ReportViewer.test.js.snap +24 -0
- data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +2 -21
- data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +116 -84
- data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionReducer.fixtures.js +10 -4
- data/webpack/components/ParameterSelection/__tests__/ParameterSelection.test.js +36 -46
- data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +31 -25
- data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -6
- data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +2 -126
- data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +1483 -872
- data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +117 -79
- data/webpack/components/SyncGitRepo/SyncGitRepo.js +210 -0
- data/webpack/components/SyncGitRepo/SyncGitRepo.scss +1 -0
- data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +124 -0
- data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +9 -0
- data/webpack/components/SyncGitRepo/SyncGitRepoReducer.js +80 -0
- data/webpack/components/SyncGitRepo/SyncGitRepoSelectors.js +6 -0
- data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoConfData_1.fixtures.js +7 -0
- data/webpack/components/SyncGitRepo/__fixtures__/syncGitRepoReducer.fixtures.js +44 -0
- data/webpack/components/SyncGitRepo/__tests__/SyncGitRepo.test.js +27 -0
- data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoReducer.test.js +95 -0
- data/webpack/components/SyncGitRepo/__tests__/SyncGitRepoSelectors.test.js +32 -0
- data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +30 -0
- data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoReducer.test.js.snap +137 -0
- data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepoSelectors.test.js.snap +13 -0
- data/webpack/components/SyncGitRepo/components/FormTextInput.js +42 -0
- data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +46 -0
- data/webpack/components/SyncGitRepo/index.js +28 -0
- data/webpack/components/common/ExtTextInput.js +43 -0
- data/webpack/components/common/__tests__/EditTableEntry.test.js +53 -0
- data/webpack/components/common/__tests__/LockTableEntry.test.js +35 -0
- data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +2 -2
- data/webpack/components/common/__tests__/__snapshots__/EditTableEntry.test.js.snap +81 -0
- data/webpack/components/common/__tests__/__snapshots__/LockTableEntry.test.js.snap +60 -0
- data/webpack/helper.js +15 -1
- data/webpack/helper.test.js +37 -0
- data/webpack/index.js +2 -0
- data/webpack/reducer.js +4 -0
- metadata +92 -11
- data/webpack/components/common/EasyHeaderFormatter.js +0 -18
- data/webpack/components/common/__tests__/__snapshots__/AddParameter.test.js.snap +0 -35
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b616c7ba21eea339af8509f618585dcd949ddead6ecdec57278a62c751e4fd2
|
4
|
+
data.tar.gz: 75c7d2e2c07d306dee127bc50c6b300934f90066bc4a491e49f17f65ac6b7c24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bba62637508bbbd4e35772a55ad1126fea7a8cb3c1658c6f734b02ccf03d44048db40fa621bb51e796220668e7a49e8b03c3169a77b818f6dbbde117d09edfe2
|
7
|
+
data.tar.gz: a6e4ba1bb97250e8bcebe6180abcf4755859b73828febda64353b47021acadcc33fd99e2ab4b45ac965e5d643c368bbfb47aee421a80979c7a4c69354a18b297
|
@@ -7,6 +7,7 @@ module ForemanAcd
|
|
7
7
|
include ::ForemanAcd::Concerns::AnsiblePlaybookParameters
|
8
8
|
|
9
9
|
before_action :find_resource, :only => [:edit, :update, :destroy, :import_vars]
|
10
|
+
after_action :delete_synced_repo, :only => [:new, :edit, :create, :update, :destroy, :index]
|
10
11
|
|
11
12
|
def index
|
12
13
|
@ansible_playbooks = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
|
@@ -18,6 +19,11 @@ module ForemanAcd
|
|
18
19
|
|
19
20
|
def create
|
20
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
|
21
27
|
if @ansible_playbook.save
|
22
28
|
process_success :success_msg => _("Successfully created %s. You need to press the \"Import groups\" button
|
23
29
|
before this ansible playbook can be used in App Definitions!") % @ansible_playbook
|
@@ -29,6 +35,20 @@ module ForemanAcd
|
|
29
35
|
def edit; end
|
30
36
|
|
31
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
|
+
|
32
52
|
if @ansible_playbook.update(ansible_playbook_params)
|
33
53
|
process_success
|
34
54
|
else
|
@@ -44,10 +64,51 @@ module ForemanAcd
|
|
44
64
|
end
|
45
65
|
end
|
46
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
|
+
|
47
106
|
def action_permission
|
48
107
|
case params[:action]
|
49
108
|
when 'import_vars'
|
50
109
|
:import_vars
|
110
|
+
when 'sync_git_repo'
|
111
|
+
:sync_git_repo
|
51
112
|
when 'grab'
|
52
113
|
:grab
|
53
114
|
else
|
@@ -120,5 +181,19 @@ module ForemanAcd
|
|
120
181
|
process_error :error_msg => _(errors.join(' ')), :redirect => ansible_playbooks_path
|
121
182
|
end
|
122
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
|
123
198
|
end
|
124
199
|
end
|
@@ -72,10 +72,12 @@ module ForemanAcd
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def deploy
|
75
|
+
value = false
|
75
76
|
@app_instance.clean_all_hosts if params[:delete_hosts]
|
76
|
-
|
77
|
+
value = safe_deploy? if params[:safe_deploy]
|
78
|
+
session.delete(:remember_hosts)
|
77
79
|
logger.info('Run async foreman task to deploy hosts')
|
78
|
-
async_task = ForemanTasks.async_task(::Actions::ForemanAcd::DeployAllHosts, @app_instance)
|
80
|
+
async_task = ForemanTasks.async_task(::Actions::ForemanAcd::DeployAllHosts, @app_instance, value)
|
79
81
|
@app_instance.update!(:last_deploy_task => async_task)
|
80
82
|
process_success(:success_msg => _('Started task to deploy hosts for %s') % @app_instance)
|
81
83
|
rescue StandardError => e
|
@@ -84,6 +86,11 @@ module ForemanAcd
|
|
84
86
|
process_error :error_msg => error_msg
|
85
87
|
end
|
86
88
|
|
89
|
+
def safe_deploy?
|
90
|
+
return false if session[:remember_hosts].empty?
|
91
|
+
session[:remember_hosts]
|
92
|
+
end
|
93
|
+
|
87
94
|
def report
|
88
95
|
@report_hosts = collect_host_report_data
|
89
96
|
logger.debug("app instance host details: #{@report_hosts.inspect}")
|
@@ -91,14 +98,24 @@ module ForemanAcd
|
|
91
98
|
|
92
99
|
def app_instance_has_foreman_hosts
|
93
100
|
hosts = JSON.parse(@app_instance.hosts)
|
101
|
+
session[:remember_hosts] = []
|
94
102
|
hosts.each do |h|
|
95
103
|
if @app_instance.foreman_hosts.where(:hostname => h['hostname']).exists?
|
104
|
+
old_host = @app_instance.foreman_hosts.find_by(:hostname => h['hostname'])
|
105
|
+
|
96
106
|
@app_instance.foreman_hosts.where(:hostname => h['hostname']).
|
97
107
|
update(:service => h['service'], :description => h['description'],
|
98
108
|
:foremanParameters => JSON.dump(h['foremanParameters']), :ansibleParameters => JSON.dump(h['ansibleParameters']))
|
109
|
+
|
110
|
+
updated_host = @app_instance.foreman_hosts.find_by(:hostname => h['hostname'])
|
111
|
+
|
112
|
+
# Store hosts if updated for safe deploy
|
113
|
+
session[:remember_hosts] << updated_host.id if updated_host.updated_at != old_host.updated_at
|
99
114
|
else
|
100
115
|
@app_instance.foreman_hosts.create(:hostname => h['hostname'], :service => h['service'], :description => h['description'],
|
101
116
|
:foremanParameters => JSON.dump(h['foremanParameters']), :ansibleParameters => JSON.dump(h['ansibleParameters']))
|
117
|
+
# Store new hosts for safe deploy
|
118
|
+
session[:remember_hosts] << @app_instance.foreman_hosts.find_by(:hostname => h['hostname']).id
|
102
119
|
end
|
103
120
|
end
|
104
121
|
|
@@ -9,7 +9,7 @@ module ForemanAcd
|
|
9
9
|
class_methods do
|
10
10
|
def ansible_playbook_params_filter
|
11
11
|
Foreman::ParameterFilter.new(::ForemanAcd::AnsiblePlaybook).tap do |filter|
|
12
|
-
filter.permit(:name, :description, :scm_type, :path, :playfile, :location_ids => [], :organization_ids => [])
|
12
|
+
filter.permit(:name, :description, :scm_type, :path, :git_commit, :git_url, :playfile, :location_ids => [], :organization_ids => [])
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -4,25 +4,40 @@ module ForemanAcd
|
|
4
4
|
# Class to run remote execution jobs
|
5
5
|
class RemoteExecutionController < JobInvocationsController
|
6
6
|
def new
|
7
|
-
|
8
|
-
|
7
|
+
set_app_instance
|
8
|
+
result, job = init_configuration
|
9
|
+
|
10
|
+
if result.success == true
|
11
|
+
@composer = job
|
12
|
+
else
|
13
|
+
redirect_to(app_instances_path, :error => _("Coult not create remote execution job to configure the app '%{app_instance}': %{msg}") % {
|
14
|
+
:app_instance => @app_instance, :msg => result.error
|
15
|
+
})
|
16
|
+
end
|
9
17
|
end
|
10
18
|
|
11
19
|
def create
|
12
20
|
customize_first = params[:customize] || false
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
begin
|
22
|
+
set_app_instance
|
23
|
+
result, job = init_configuration
|
24
|
+
|
25
|
+
unless result.success == true
|
26
|
+
return redirect_to(app_instances_path, :error => _("Coult not create remote execution job to configure the app '%{app_instance}': %{msg}") % {
|
27
|
+
:app_instance => @app_instance, :msg => result.error
|
28
|
+
})
|
29
|
+
end
|
30
|
+
|
31
|
+
@composer = job
|
32
|
+
if customize_first == false
|
33
|
+
@composer.trigger!
|
34
|
+
redirect_to job_invocation_path(@composer.job_invocation)
|
35
|
+
else
|
36
|
+
# redirect to the job itself if we want to customize the job
|
37
|
+
render :action => 'new'
|
38
|
+
end
|
39
|
+
rescue StandardError => e
|
40
|
+
redirect_to app_instances_path, :error => _("#{job}, #{e}")
|
26
41
|
end
|
27
42
|
end
|
28
43
|
|
@@ -34,13 +49,14 @@ module ForemanAcd
|
|
34
49
|
|
35
50
|
private
|
36
51
|
|
37
|
-
def
|
38
|
-
app_instance = ForemanAcd::AppInstance.find_by(:id => params[:id])
|
39
|
-
|
52
|
+
def set_app_instance
|
53
|
+
@app_instance = ForemanAcd::AppInstance.find_by(:id => params[:id])
|
54
|
+
end
|
40
55
|
|
41
|
-
|
42
|
-
logger.debug("Creating
|
43
|
-
|
56
|
+
def init_configuration
|
57
|
+
logger.debug("Creating job to configure the app #{@app_instance}. Customize first: #{params[:customize]}")
|
58
|
+
app_configurator = ForemanAcd::AppConfigurator.new(@app_instance)
|
59
|
+
app_configurator.configure
|
44
60
|
end
|
45
61
|
end
|
46
62
|
end
|
@@ -4,27 +4,32 @@ module Actions
|
|
4
4
|
module ForemanAcd
|
5
5
|
# DeployAllHosts implements a Foreman Task EntryAction
|
6
6
|
class DeployAllHosts < Actions::EntryAction
|
7
|
-
def plan(app_instance)
|
8
|
-
action_subject(app_instance)
|
7
|
+
def plan(app_instance, safe_deploy)
|
8
|
+
action_subject(app_instance, :safe_deploy => safe_deploy)
|
9
9
|
plan_self(:id => app_instance.id)
|
10
10
|
end
|
11
11
|
|
12
12
|
def run
|
13
13
|
output[:status] = 'IN PROGRESS'
|
14
14
|
app_instance = ::ForemanAcd::AppInstance.find(input.fetch(:id))
|
15
|
+
safe_deploy = input.fetch(:safe_deploy)
|
15
16
|
|
16
|
-
# Goal: all or nothing
|
17
|
+
# Goal: all, safe_deploy or nothing
|
17
18
|
begin
|
18
|
-
|
19
|
+
if safe_deploy
|
20
|
+
::Foreman::Logging.logger('foreman_acd').info "Start to safe deploy hosts of the app #{app_instance}"
|
21
|
+
else
|
22
|
+
::Foreman::Logging.logger('foreman_acd').info "Start to deploy all hosts of the app #{app_instance}"
|
23
|
+
end
|
19
24
|
app_deployer = ::ForemanAcd::AppDeployer.new(app_instance)
|
20
|
-
output[:data] = app_deployer.deploy
|
25
|
+
output[:data] = app_deployer.deploy(safe_deploy)
|
21
26
|
output[:status] = 'SUCCESS'
|
22
27
|
rescue StandardError => e
|
23
|
-
::Foreman::Logging.logger('foreman_acd').error "Error while deploying hosts for application instance. Clean up all other hosts: #{e}"
|
28
|
+
::Foreman::Logging.logger('foreman_acd').error "Error while deploying hosts for application instance '#{app_instance.name}'. Clean up all other hosts: #{e}"
|
24
29
|
app_instance.clean_all_hosts
|
25
30
|
|
26
|
-
output[:error] = e.to_s
|
27
31
|
output[:status] = 'FAILURE'
|
32
|
+
raise "Error while deploying hosts for application instance '#{app_instance.name}': (#{e.message})"
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
@@ -15,15 +15,18 @@ module Actions
|
|
15
15
|
app_instance = ::ForemanAcd::AppInstance.find(input.fetch(:id))
|
16
16
|
app_configurator = ::ForemanAcd::AppConfigurator.new(app_instance)
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
result, job = app_configurator.configure
|
19
|
+
if result.success
|
20
|
+
::Foreman::Logging.logger('foreman_acd').info "Creating job to configure the app #{app_instance}"
|
21
|
+
job.trigger!
|
22
|
+
else
|
23
|
+
::Foreman::Logging.logger('foreman_acd').error "Could not create the job to configure the app #{app_instance}: #{result.error}"
|
24
|
+
end
|
23
25
|
rescue StandardError => e
|
24
|
-
::Foreman::Logging.logger('foreman_acd').error "Error while configuring application instance: #{e}"
|
25
|
-
|
26
|
+
::Foreman::Logging.logger('foreman_acd').error "Error while configuring application instance '#{app_instance.name}': #{e}"
|
27
|
+
|
26
28
|
output[:status] = 'FAILURE'
|
29
|
+
raise "Error while configuring hosts via ansible playbook for application instance '#{app_instance.name}': (#{e.message})"
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
@@ -13,13 +13,13 @@ module ForemanAcd
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
private
|
17
|
-
|
18
16
|
def deployed_via_acd?
|
19
17
|
find_app_instance_host
|
20
18
|
@app_instance_host.present?
|
21
19
|
end
|
22
20
|
|
21
|
+
private
|
22
|
+
|
23
23
|
def find_app_instance_host
|
24
24
|
@app_instance_host = ForemanAcd::ForemanHost.find_by(:host_id => id)
|
25
25
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ForemanAcd
|
4
4
|
# Implement a RemoteExecutionProvider
|
5
|
-
class AcdProvider < RemoteExecutionProvider
|
5
|
+
class AcdProvider < ::RemoteExecutionProvider
|
6
6
|
class << self
|
7
7
|
def supports_effective_user?
|
8
8
|
true
|
@@ -25,6 +25,12 @@ module ForemanAcd
|
|
25
25
|
def ssh_key_passphrase(_host); end
|
26
26
|
|
27
27
|
def sudo_password(_host); end
|
28
|
+
|
29
|
+
# Workaround till infrastructure jobs on proxies are possible. See
|
30
|
+
# configure in services/foreman_acd/app_configurator.rb for more details.
|
31
|
+
# def required_proxy_selector_for(_template)
|
32
|
+
# AcdProxyProxySelector.new
|
33
|
+
# end
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
@@ -12,6 +12,7 @@ module ForemanAcd
|
|
12
12
|
self.table_name = 'acd_ansible_playbooks'
|
13
13
|
has_many :app_definitions, :inverse_of => :ansible_playbook, :foreign_key => 'acd_ansible_playbook_id', :dependent => :restrict_with_error
|
14
14
|
validates :name, :presence => true, :uniqueness => true
|
15
|
+
validates :scm_type, :presence => true
|
15
16
|
scoped_search :on => :name
|
16
17
|
|
17
18
|
default_scope do
|
@@ -44,7 +45,7 @@ module ForemanAcd
|
|
44
45
|
|
45
46
|
def content
|
46
47
|
case scm_type
|
47
|
-
when 'directory'
|
48
|
+
when 'directory' || 'git'
|
48
49
|
File.read(File.join(path, playfile))
|
49
50
|
else
|
50
51
|
raise NotImplementedError.new "scm_type #{scm_type.inspect} not supported!"
|
@@ -54,7 +54,7 @@ module ForemanAcd
|
|
54
54
|
ids.each do |host_id|
|
55
55
|
h = ::Host.find(host_id) unless host_id.nil?
|
56
56
|
if h
|
57
|
-
Katello::RegistrationManager.unregister_host(h, :unregistering => false) if ForemanAcd
|
57
|
+
Katello::RegistrationManager.unregister_host(h, :unregistering => false) if ForemanAcd.with_katello?
|
58
58
|
h.destroy
|
59
59
|
end
|
60
60
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ForemanAcd
|
4
|
+
# AcdProxy Selector implementing a RemoteExecutionProxySelector which
|
5
|
+
# only returns the Smart Proxy of the given host
|
6
|
+
class AcdProxyProxySelector < ::RemoteExecutionProxySelector
|
7
|
+
def determine_proxy(*args)
|
8
|
+
host, _provider = args
|
9
|
+
|
10
|
+
# We already did the determine_proxy in app_configurator. We want that REX
|
11
|
+
# isn't doing the determination of the proxy twice.
|
12
|
+
# Therefore, we will just return the host, which is the proxy!
|
13
|
+
|
14
|
+
::SmartProxy.find_by(:name => host.name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -19,12 +19,36 @@ module ForemanAcd
|
|
19
19
|
|
20
20
|
begin
|
21
21
|
proxy_hosts = {}
|
22
|
-
|
22
|
+
job = nil
|
23
|
+
result = OpenStruct.new
|
23
24
|
|
24
25
|
hosts = @app_instance.foreman_hosts
|
26
|
+
|
27
|
+
# Important: This uses the REX Proxy Selector and not
|
28
|
+
# the AcdProxySelection because the AcdProxySelector
|
29
|
+
# does not find the proxy but only return the given
|
30
|
+
# host. This is required because we want to run the
|
31
|
+
# ansible playbook for a group of hosts on the smart proxy.
|
32
|
+
# So the process need to be:
|
33
|
+
# 1. get the proxy which is required to connect to host a,b,c
|
34
|
+
# 2. run the job on the proxy
|
35
|
+
# In 2. we need to make sure that REX doesn't try to find the
|
36
|
+
# proxy which is necessary to connect to the proxy
|
25
37
|
proxy_selector = RemoteExecutionProxySelector.new
|
26
38
|
hosts.each do |h|
|
27
|
-
|
39
|
+
begin
|
40
|
+
unless h.host
|
41
|
+
result.success = false
|
42
|
+
result.error = 'App Instance is not deployed'
|
43
|
+
return [result, job]
|
44
|
+
end
|
45
|
+
proxy = proxy_selector.determine_proxy(h.host, 'ACD')
|
46
|
+
result.success = true
|
47
|
+
rescue NoMethodError => e
|
48
|
+
result.success = false
|
49
|
+
result.error = "#{e}, Install/Update smart-proxies for ACD"
|
50
|
+
return [result, job]
|
51
|
+
end
|
28
52
|
proxy_hosts[proxy.name] = [] unless proxy_hosts.key?(proxy.name)
|
29
53
|
proxy_hosts[proxy.name] << h
|
30
54
|
end
|
@@ -32,23 +56,43 @@ module ForemanAcd
|
|
32
56
|
# TODO: just for testing...
|
33
57
|
# proxy_hosts = { Host.first.name => [ Host.first.id] }
|
34
58
|
|
35
|
-
|
59
|
+
proxy_inventories = {}
|
60
|
+
proxy_host_ids = []
|
36
61
|
proxy_hosts.each do |proxy_name, foreman_hosts|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
)
|
46
|
-
|
62
|
+
proxy_inventories[proxy_name] = ForemanAcd::InventoryCreator.new(@app_instance, foreman_hosts).create_inventory
|
63
|
+
|
64
|
+
# Workaround till infrastructure jobs on proxies are possible. See
|
65
|
+
# https://community.theforeman.org/t/infrastructure-roles/22001/33
|
66
|
+
#
|
67
|
+
# Why do we use 'foreman_hosts.first.host'? REX is 'host-centric'. During
|
68
|
+
# job execution, REX will try to find the proxy on which the job should be executed.
|
69
|
+
# We throw the first host at REX's feet so that the resolution of the
|
70
|
+
# proxy works (... which we have already done above).
|
71
|
+
# ACD on the smart proxy side will call the ansible-playbook for ALL hosts
|
72
|
+
# which are behind this smart proxy.
|
73
|
+
#
|
74
|
+
# Additionally, we disable that AcdProxyProxySelector is used.
|
75
|
+
# See required_proxy_selector_for in models/foreman_acd/acd_provider.rb
|
76
|
+
proxy_host_ids << foreman_hosts.first.host.id
|
77
|
+
|
78
|
+
# Actually, we want this:
|
79
|
+
# proxy_host_ids << Host.find_by(:name => proxy_name).id
|
47
80
|
end
|
81
|
+
|
82
|
+
job_input['inventory'] = YAML.dump(proxy_inventories)
|
83
|
+
composer = JobInvocationComposer.for_feature(
|
84
|
+
:run_acd_ansible_playbook,
|
85
|
+
proxy_host_ids,
|
86
|
+
job_input.to_hash
|
87
|
+
)
|
88
|
+
job = composer
|
48
89
|
rescue StandardError => e
|
49
|
-
|
90
|
+
result.success = false
|
91
|
+
result.error = _('Failed to configure hosts: %{err_msg}' % { :err_msg => e.message })
|
92
|
+
logger.error('Failed to configure hosts: %{err_class}: %{err_msg}' % { :err_class => e.class, :err_msg => e.message })
|
93
|
+
job = nil
|
50
94
|
end
|
51
|
-
|
95
|
+
[result, job]
|
52
96
|
end
|
53
97
|
end
|
54
98
|
end
|