foreman_remote_execution 3.2.1 → 3.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.eslintrc +5 -30
- data/.github/workflows/ci.yml +101 -0
- data/.gitignore +1 -0
- data/.rubocop_todo.yml +3 -0
- data/Gemfile +1 -0
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.scss +6 -5
- data/app/controllers/api/v2/job_invocations_controller.rb +22 -1
- data/app/controllers/api/v2/template_invocations_controller.rb +4 -1
- data/app/helpers/job_invocations_helper.rb +1 -1
- data/app/helpers/remote_execution_helper.rb +38 -33
- data/app/lib/actions/remote_execution/run_host_job.rb +3 -2
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +1 -1
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +10 -5
- data/app/models/remote_execution_provider.rb +5 -0
- data/app/services/default_proxy_proxy_selector.rb +18 -0
- data/app/views/api/v2/job_invocations/main.json.rabl +8 -2
- data/app/views/job_invocations/_card_target_hosts.html.erb +1 -1
- data/app/views/job_invocations/_tab_hosts.html.erb +3 -23
- data/app/views/job_invocations/index.html.erb +2 -1
- data/app/views/job_invocations/show.html.erb +0 -6
- data/app/views/job_invocations/show.json.erb +4 -0
- data/app/views/templates/ssh/package_action.erb +1 -0
- data/app/views/templates/ssh/puppet_agent_disable.erb +3 -0
- data/app/views/templates/ssh/puppet_agent_enable.erb +3 -0
- data/app/views/templates/ssh/puppet_install_modules_from_forge.erb +3 -0
- data/app/views/templates/ssh/puppet_run_once.erb +3 -0
- data/db/seeds.d/70-job_templates.rb +1 -1
- data/foreman_remote_execution.gemspec +4 -5
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/action_names.rb +0 -1
- data/package.json +16 -33
- data/test/functional/api/v2/job_invocations_controller_test.rb +42 -14
- data/test/models/orchestration/ssh_test.rb +32 -0
- data/test/unit/concerns/host_extensions_test.rb +7 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +1 -0
- data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
- data/webpack/__mocks__/foremanReact/constants.js +3 -0
- data/webpack/index.js +9 -7
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +52 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +8 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +1 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +12 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/HostItem.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/HostStatus.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHosts.test.js +6 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostItem.test.js.snap +31 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +12 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +81 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +43 -0
- data/webpack/react_app/components/TargetingHosts/components/HostItem.js +39 -0
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +54 -0
- data/webpack/react_app/components/TargetingHosts/index.js +37 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +10 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +6 -3
- data/webpack/react_app/components/jobInvocations/index.js +19 -7
- data/webpack/react_app/redux/actions/jobInvocations/index.js +12 -8
- data/webpack/react_app/redux/consts.js +1 -2
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +8 -40
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +17 -11
- data/webpack/test_setup.js +2 -1
- metadata +26 -12
- data/.hound.yml +0 -19
- data/.travis.yml +0 -6
- data/app/views/job_invocations/_host_actions_td.html.erb +0 -3
- data/app/views/job_invocations/_host_name_td.html.erb +0 -8
- data/app/views/job_invocations/_host_status_td.html.erb +0 -1
- data/app/views/job_invocations/show.js.erb +0 -23
|
@@ -19,8 +19,14 @@ child :targeting do
|
|
|
19
19
|
attributes :bookmark_id, :search_query, :targeting_type, :user_id, :status, :status_label,
|
|
20
20
|
:randomized_ordering
|
|
21
21
|
|
|
22
|
-
child
|
|
22
|
+
child @hosts do
|
|
23
23
|
extends 'api/v2/hosts/base'
|
|
24
|
+
|
|
25
|
+
if params[:host_status] == 'true'
|
|
26
|
+
node :job_status do |host|
|
|
27
|
+
@host_statuses[host.id]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
24
30
|
end
|
|
25
31
|
end
|
|
26
32
|
|
|
@@ -28,7 +34,7 @@ child :task do
|
|
|
28
34
|
attributes :id, :state
|
|
29
35
|
end
|
|
30
36
|
|
|
31
|
-
child
|
|
37
|
+
child @template_invocations do
|
|
32
38
|
attributes :template_id, :template_name
|
|
33
39
|
child :input_values do
|
|
34
40
|
attributes :template_input_name, :template_input_id
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<% template_invocations = job_invocation.pattern_template_invocations %>
|
|
2
|
-
<div class="card-pf card-pf-accented">
|
|
2
|
+
<div class="card-pf card-pf-accented target-hosts-card">
|
|
3
3
|
<div class="card-pf-title">
|
|
4
4
|
<h2 style="height: 18px;" class="card-pf-title">
|
|
5
5
|
<%= _('Target hosts') %>
|
|
@@ -15,29 +15,9 @@
|
|
|
15
15
|
<% end %>
|
|
16
16
|
<br>
|
|
17
17
|
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<th><%= sort :name, :as => _('Host') %></th>
|
|
22
|
-
<th><%= _('Status') %></th>
|
|
23
|
-
<th><%= _('Actions') %></th>
|
|
24
|
-
</tr>
|
|
25
|
-
</thead>
|
|
26
|
-
|
|
27
|
-
<tbody>
|
|
28
|
-
<% hosts.each do |host| %>
|
|
29
|
-
<% template_invocation = job_invocation.template_invocations.find { |template_invocation| template_invocation.host_id == host.id } %>
|
|
30
|
-
<% task = template_invocation.try(:run_host_job_task) %>
|
|
31
|
-
<tr>
|
|
32
|
-
<% options = { :host => host, :task => task, :job_invocation => job_invocation, :template_invocation => template_invocation } %>
|
|
33
|
-
<%= render 'host_name_td', options %>
|
|
34
|
-
<%= render 'host_status_td', options %>
|
|
35
|
-
<%= render 'host_actions_td', options %>
|
|
36
|
-
</tr>
|
|
37
|
-
<% end %>
|
|
38
|
-
</tbody>
|
|
39
|
-
</table>
|
|
40
|
-
|
|
18
|
+
<div id="targeting_hosts">
|
|
19
|
+
<%= mount_react_component('TargetingHosts', '#targeting_hosts') %>
|
|
20
|
+
</div>
|
|
41
21
|
<%= will_paginate_with_info @hosts, :container => true %>
|
|
42
22
|
<% else %>
|
|
43
23
|
<div class="alert alert-warning">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<% stylesheet 'foreman_remote_execution/foreman_remote_execution' %>
|
|
1
2
|
<% title _('Job invocations') %>
|
|
2
3
|
|
|
3
4
|
<% title_actions(job_invocations_buttons) %>
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
<tbody>
|
|
20
21
|
<% @job_invocations.each do |invocation| %>
|
|
21
22
|
<tr>
|
|
22
|
-
<td><%= link_to_if_authorized invocation_description(invocation), hash_for_job_invocation_path(invocation).merge(:auth_object => invocation, :permission => :view_job_invocations, :authorizer => authorizer) %></td>
|
|
23
|
+
<td class="text_warp"><%= link_to_if_authorized invocation_description(invocation), hash_for_job_invocation_path(invocation).merge(:auth_object => invocation, :permission => :view_job_invocations, :authorizer => authorizer) %></td>
|
|
23
24
|
<td><%= trunc_with_tooltip(invocation&.targeting&.search_query, 15) %></td>
|
|
24
25
|
<td><%= link_to_invocation_task_if_authorized(invocation) %></td>
|
|
25
26
|
<td><%= invocation_result(invocation, :success_count) %></td>
|
|
@@ -41,9 +41,3 @@
|
|
|
41
41
|
<% end %>
|
|
42
42
|
<%= render_tab_content_for(:main_tabs, subject: @job_invocation) %>
|
|
43
43
|
</div>
|
|
44
|
-
|
|
45
|
-
<script id="job_invocation_refresh" data-refresh-url="<%= job_invocation_path(@job_invocation) %>">
|
|
46
|
-
<% if @auto_refresh %>
|
|
47
|
-
delayed_refresh($('script#job_invocation_refresh').data('refresh-url'), job_invocation_refresh_data());
|
|
48
|
-
<% end %>
|
|
49
|
-
</script>
|
|
@@ -97,6 +97,7 @@ handle_zypp_res_codes () {
|
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
-%>
|
|
100
|
+
[ -x "$(command -v subscription-manager)" ] && subscription-manager refresh
|
|
100
101
|
apt-get -y update
|
|
101
102
|
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y <%= action %> <%= input("package") %>
|
|
102
103
|
<% elsif package_manager == 'zypper' -%>
|
|
@@ -13,4 +13,7 @@ template_inputs:
|
|
|
13
13
|
provider_type: SSH
|
|
14
14
|
kind: job_template
|
|
15
15
|
-%>
|
|
16
|
+
<% if @host.operatingsystem.family == 'Debian' -%>
|
|
17
|
+
export PATH=/opt/puppetlabs/bin:$PATH
|
|
18
|
+
<% end -%>
|
|
16
19
|
puppet agent --disable "<%= input("comment").present? ? input("comment") : "Disabled using Foreman Remote Execution" %> - <%= current_user %> - $(date "+%d/%m/%Y %H:%M")"
|
|
@@ -33,4 +33,7 @@ template_inputs:
|
|
|
33
33
|
provider_type: SSH
|
|
34
34
|
kind: job_template
|
|
35
35
|
-%>
|
|
36
|
+
<% if @host.operatingsystem.family == 'Debian' -%>
|
|
37
|
+
export PATH=/opt/puppetlabs/bin:$PATH
|
|
38
|
+
<% end -%>
|
|
36
39
|
puppet module install <%= input('puppet_module') %> <%= "--target-dir #{input('target_dir')}" if input('target_dir').present? %> <%= "--version #{input('version')}" if input('version').present? %> <%= "--force" if input('force') == "true" %> <%= "--ignore-dependencies" if input('ignore_dependencies') == "true" %>
|
|
@@ -11,4 +11,7 @@ template_inputs:
|
|
|
11
11
|
input_type: user
|
|
12
12
|
required: false
|
|
13
13
|
%>
|
|
14
|
+
<% if @host.operatingsystem.family == 'Debian' -%>
|
|
15
|
+
export PATH=/opt/puppetlabs/bin:$PATH
|
|
16
|
+
<% end -%>
|
|
14
17
|
puppet agent --onetime --no-usecacheonfailure --no-daemonize <%= input("puppet_options") %>
|
|
@@ -4,7 +4,7 @@ User.as_anonymous_admin do
|
|
|
4
4
|
JobTemplate.without_auditing do
|
|
5
5
|
Dir[File.join("#{ForemanRemoteExecution::Engine.root}/app/views/templates/**/*.erb")].each do |template|
|
|
6
6
|
sync = !Rails.env.test? && Setting[:remote_execution_sync_templates]
|
|
7
|
-
template = JobTemplate.import_raw!(File.read(template), :default => true, :
|
|
7
|
+
template = JobTemplate.import_raw!(File.read(template), :default => true, :lock => true, :update => sync)
|
|
8
8
|
template.organizations = organizations if template.present?
|
|
9
9
|
template.locations = locations if template.present?
|
|
10
10
|
end
|
|
@@ -15,10 +15,9 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
s.description = 'A plugin bringing remote execution to the Foreman, completing the config ' +
|
|
16
16
|
'management functionality with remote management functionality.'
|
|
17
17
|
|
|
18
|
-
s.files =
|
|
19
|
-
file
|
|
20
|
-
|
|
21
|
-
file == 'foreman_remote_execution_core.gemspec'
|
|
18
|
+
s.files = `git ls-files`.split("\n").reject do |file|
|
|
19
|
+
file.start_with?('scripts', 'lib/foreman_remote_execution_core') ||
|
|
20
|
+
file == 'foreman_remote_execution_core.gemspec'
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
s.test_files = `git ls-files test`.split("\n")
|
|
@@ -30,6 +29,6 @@ Gem::Specification.new do |s|
|
|
|
30
29
|
s.add_dependency 'foreman-tasks', '>= 0.15.1'
|
|
31
30
|
|
|
32
31
|
s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
|
|
33
|
-
s.add_development_dependency 'rubocop'
|
|
32
|
+
s.add_development_dependency 'rubocop', '~> 0.80.0'
|
|
34
33
|
s.add_development_dependency 'rdoc'
|
|
35
34
|
end
|
data/locale/action_names.rb
CHANGED
data/package.json
CHANGED
|
@@ -3,25 +3,14 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"license": "GPL-3.0",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"lint": "
|
|
7
|
-
"test": "
|
|
8
|
-
"test:watch": "
|
|
9
|
-
"test:current": "
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"node_modules",
|
|
15
|
-
"webpack"
|
|
16
|
-
],
|
|
17
|
-
"setupFiles": [
|
|
18
|
-
"raf/polyfill",
|
|
19
|
-
"./webpack/test_setup.js"
|
|
20
|
-
],
|
|
21
|
-
"testPathIgnorePatterns": [
|
|
22
|
-
"/node_modules/",
|
|
23
|
-
"<rootDir>/foreman/"
|
|
24
|
-
]
|
|
6
|
+
"lint": "tfm-lint --plugin -d /webpack",
|
|
7
|
+
"test": "tfm-test --plugin",
|
|
8
|
+
"test:watch": "tfm-test --plugin --watchAll",
|
|
9
|
+
"test:current": "tfm-test --plugin --watch",
|
|
10
|
+
"publish-coverage": "tfm-publish-coverage",
|
|
11
|
+
"stories": "tfm-stories --plugin",
|
|
12
|
+
"stories:build": "tfm-build-stories --plugin",
|
|
13
|
+
"stories:deploy": "surge --project .storybook-dist"
|
|
25
14
|
},
|
|
26
15
|
"repository": {
|
|
27
16
|
"type": "git",
|
|
@@ -32,22 +21,16 @@
|
|
|
32
21
|
},
|
|
33
22
|
"devDependencies": {
|
|
34
23
|
"@babel/core": "^7.7.0",
|
|
35
|
-
"@theforeman/builder": "^4.
|
|
36
|
-
"@theforeman/
|
|
24
|
+
"@theforeman/builder": "^4.2.1",
|
|
25
|
+
"@theforeman/eslint-plugin-foreman": "^4.2.1",
|
|
26
|
+
"@theforeman/stories": "^4.2.1",
|
|
27
|
+
"@theforeman/test": "^4.2.1",
|
|
28
|
+
"@theforeman/vendor-dev": "^4.2.1",
|
|
37
29
|
"babel-eslint": "^10.0.0",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"enzyme-adapter-react-16": "^1.1.0",
|
|
41
|
-
"enzyme-to-json": "^3.1.2",
|
|
42
|
-
"eslint": "^4.10.0",
|
|
43
|
-
"eslint-config-airbnb": "^16.0.0",
|
|
44
|
-
"eslint-plugin-import": "^2.8.0",
|
|
45
|
-
"eslint-plugin-jest": "^21.2.0",
|
|
46
|
-
"eslint-plugin-jsx-a11y": "^6.0.2",
|
|
47
|
-
"eslint-plugin-react": "^7.4.0",
|
|
48
|
-
"jest": "^24.9.0"
|
|
30
|
+
"eslint": "^6.8.0",
|
|
31
|
+
"prettier": "^1.19.1"
|
|
49
32
|
},
|
|
50
33
|
"peerDependencies": {
|
|
51
|
-
"@theforeman/vendor": ">= 4.
|
|
34
|
+
"@theforeman/vendor": ">= 4.2.1"
|
|
52
35
|
}
|
|
53
36
|
}
|
|
@@ -4,7 +4,7 @@ module Api
|
|
|
4
4
|
module V2
|
|
5
5
|
class JobInvocationsControllerTest < ActionController::TestCase
|
|
6
6
|
setup do
|
|
7
|
-
@invocation = FactoryBot.create(:job_invocation, :with_template, :with_task)
|
|
7
|
+
@invocation = FactoryBot.create(:job_invocation, :with_template, :with_task, :with_unplanned_host)
|
|
8
8
|
@template = FactoryBot.create(:job_template, :with_input)
|
|
9
9
|
|
|
10
10
|
# Without this the template in template_invocations and in pattern_template_invocations
|
|
@@ -20,18 +20,32 @@ module Api
|
|
|
20
20
|
assert_response :success
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
describe 'show' do
|
|
24
|
+
test 'should get invocation detail' do
|
|
25
|
+
get :show, params: { :id => @invocation.id }
|
|
26
|
+
assert_response :success
|
|
27
|
+
template = ActiveSupport::JSON.decode(@response.body)
|
|
28
|
+
assert_not_empty template
|
|
29
|
+
assert_equal template['job_category'], @invocation.job_category
|
|
30
|
+
assert_not_empty template['targeting']['hosts']
|
|
31
|
+
end
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
test 'should get invocation detail when taxonomies are set' do
|
|
34
|
+
taxonomy_params = %w(organization location).reduce({}) { |acc, cur| acc.merge("#{cur}_id" => FactoryBot.create(cur)) }
|
|
35
|
+
get :show, params: taxonomy_params.merge(:id => @invocation.id)
|
|
36
|
+
assert_response :success
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
test 'should see only permitted hosts' do
|
|
40
|
+
@user = FactoryBot.create(:user, admin: false)
|
|
41
|
+
setup_user('view', 'job_invocations', nil, @user)
|
|
42
|
+
setup_user('view', 'hosts', 'name ~ nope.example.com', @user)
|
|
43
|
+
|
|
44
|
+
get :show, params: { :id => @invocation.id }, session: set_session_user(@user)
|
|
45
|
+
assert_response :success
|
|
46
|
+
response = ActiveSupport::JSON.decode(@response.body)
|
|
47
|
+
assert_empty response['targeting']['hosts']
|
|
48
|
+
end
|
|
35
49
|
end
|
|
36
50
|
|
|
37
51
|
context 'creation' do
|
|
@@ -108,7 +122,7 @@ module Api
|
|
|
108
122
|
end
|
|
109
123
|
|
|
110
124
|
describe '#output' do
|
|
111
|
-
let(:host) { @invocation.
|
|
125
|
+
let(:host) { @invocation.targeting.hosts.first }
|
|
112
126
|
|
|
113
127
|
test 'should provide output for delayed task' do
|
|
114
128
|
ForemanTasks::Task.any_instance.expects(:scheduled?).returns(true)
|
|
@@ -137,6 +151,12 @@ module Api
|
|
|
137
151
|
assert_equal result['message'], "Job invocation not found by id '#{invocation_id}'"
|
|
138
152
|
assert_response :missing
|
|
139
153
|
end
|
|
154
|
+
|
|
155
|
+
test 'should get output only for host in job invocation' do
|
|
156
|
+
get :output, params: { job_invocation_id: @invocation.id,
|
|
157
|
+
host_id: FactoryBot.create(:host).id }
|
|
158
|
+
assert_response :missing
|
|
159
|
+
end
|
|
140
160
|
end
|
|
141
161
|
|
|
142
162
|
describe 'raw output' do
|
|
@@ -148,7 +168,7 @@ module Api
|
|
|
148
168
|
let(:fake_task) do
|
|
149
169
|
OpenStruct.new :pending? => false, :main_action => OpenStruct.new(:live_output => fake_output)
|
|
150
170
|
end
|
|
151
|
-
let(:host) { @invocation.
|
|
171
|
+
let(:host) { @invocation.targeting.hosts.first }
|
|
152
172
|
|
|
153
173
|
test 'should provide raw output for a host' do
|
|
154
174
|
JobInvocation.any_instance.expects(:task).returns(OpenStruct.new(:scheduled? => false))
|
|
@@ -184,6 +204,12 @@ module Api
|
|
|
184
204
|
assert_nil result['output']
|
|
185
205
|
assert_response :success
|
|
186
206
|
end
|
|
207
|
+
|
|
208
|
+
test 'should get raw output only for host in job invocation' do
|
|
209
|
+
get :raw_output, params: { job_invocation_id: @invocation.id,
|
|
210
|
+
host_id: FactoryBot.create(:host).id }
|
|
211
|
+
assert_response :missing
|
|
212
|
+
end
|
|
187
213
|
end
|
|
188
214
|
|
|
189
215
|
test 'should cancel a job' do
|
|
@@ -232,11 +258,13 @@ module Api
|
|
|
232
258
|
end
|
|
233
259
|
|
|
234
260
|
test 'should not raise an exception when reruning failed has no hosts' do
|
|
261
|
+
@invocation.targeting.hosts.first.destroy
|
|
235
262
|
JobInvocation.any_instance.expects(:generate_description)
|
|
236
263
|
JobInvocationComposer.any_instance
|
|
237
264
|
.expects(:validate_job_category)
|
|
238
265
|
.with(@invocation.job_category)
|
|
239
266
|
.returns(@invocation.job_category)
|
|
267
|
+
|
|
240
268
|
post :rerun, params: { :id => @invocation.id, :failed_only => true }
|
|
241
269
|
assert_response :success
|
|
242
270
|
result = ActiveSupport::JSON.decode(@response.body)
|
|
@@ -15,10 +15,42 @@ class SSHOrchestrationTest < ActiveSupport::TestCase
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it 'attempts to drop IP address and hostname from smart proxies on rebuild' do
|
|
18
|
+
host.stubs(:skip_orchestration?).returns false
|
|
19
|
+
SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(interface.ip)
|
|
20
|
+
SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(host.name)
|
|
21
|
+
|
|
18
22
|
host.build = true
|
|
19
23
|
host.save!
|
|
24
|
+
|
|
20
25
|
ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
|
|
21
26
|
"ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
|
|
22
27
|
_(host.queue.task_ids).must_equal ids
|
|
28
|
+
_(host.queue.items.map(&:status)).must_equal %w(completed completed)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'does not fail on 404 from the smart proxy' do
|
|
32
|
+
host.stubs(:skip_orchestration?).returns false
|
|
33
|
+
SmartProxy.any_instance.expects(:drop_host_from_known_hosts).raises(RestClient::ResourceNotFound).twice
|
|
34
|
+
host.build = true
|
|
35
|
+
host.save!
|
|
36
|
+
ids = ["ssh_remove_known_hosts_interface_#{interface.ip}_#{proxy.id}",
|
|
37
|
+
"ssh_remove_known_hosts_host_#{host.name}_#{proxy.id}"]
|
|
38
|
+
_(host.queue.task_ids).must_equal ids
|
|
39
|
+
_(host.queue.items.map(&:status)).must_equal %w(completed completed)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'does not trigger the removal when creating a new host' do
|
|
43
|
+
SmartProxy.any_instance.expects(:drop_host_from_known_hosts).never
|
|
44
|
+
host = Host::Managed.new(:name => 'test', :ip => '127.0.0.1')
|
|
45
|
+
host.stubs(:skip_orchestration?).returns false
|
|
46
|
+
_(host.queue.task_ids).must_equal []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'does not call to the proxy when target is nil' do
|
|
50
|
+
host.stubs(:skip_orchestration?).returns false
|
|
51
|
+
SmartProxy.any_instance.expects(:drop_host_from_known_hosts).with(host.name)
|
|
52
|
+
host.interfaces.first.stubs(:ip)
|
|
53
|
+
host.destroy
|
|
54
|
+
_(host.queue.items.map(&:status)).must_equal %w(completed completed)
|
|
23
55
|
end
|
|
24
56
|
end
|
|
@@ -48,6 +48,13 @@ class ForemanRemoteExecutionHostExtensionsTest < ActiveSupport::TestCase
|
|
|
48
48
|
_(host.host_param('remote_execution_ssh_keys')).must_include sshkey
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
it 'merges ssh key as a string from host parameters and proxies' do
|
|
52
|
+
key = 'ssh-rsa not-even-a-key something@somewhere.com'
|
|
53
|
+
host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_keys', :value => key)
|
|
54
|
+
_(host.host_param('remote_execution_ssh_keys')).must_include key
|
|
55
|
+
_(host.host_param('remote_execution_ssh_keys')).must_include sshkey
|
|
56
|
+
end
|
|
57
|
+
|
|
51
58
|
it 'has ssh keys in the parameters even when no user specified' do
|
|
52
59
|
# this is a case, when using the helper in provisioning templates
|
|
53
60
|
FactoryBot.create(:smart_proxy, :ssh)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const translate = s => s;
|
data/webpack/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
-
import { mount, registerReducer } from 'foremanReact/common/MountingService';
|
|
4
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
1
|
+
import { registerReducer } from 'foremanReact/common/MountingService';
|
|
5
2
|
import componentRegistry from 'foremanReact/components/componentRegistry';
|
|
6
3
|
import JobInvocationContainer from './react_app/components/jobInvocations';
|
|
4
|
+
import TargetingHosts from './react_app/components/TargetingHosts';
|
|
7
5
|
import rootReducer from './react_app/redux/reducers';
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
name: 'JobInvocationContainer',
|
|
11
|
-
type:
|
|
7
|
+
const components = [
|
|
8
|
+
{ name: 'JobInvocationContainer', type: JobInvocationContainer },
|
|
9
|
+
{ name: 'TargetingHosts', type: TargetingHosts },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
components.forEach(component => {
|
|
13
|
+
componentRegistry.register(component);
|
|
12
14
|
});
|
|
13
15
|
|
|
14
16
|
registerReducer('foremanRemoteExecutionReducers', rootReducer);
|