foreman_ansible 3.0.9 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/app/controllers/api/v2/ansible_inventories_controller.rb +50 -0
- data/app/models/ansible_variable.rb +1 -0
- data/app/models/foreman_ansible/ansible_provider.rb +25 -1
- data/app/models/foreman_ansible/fact_name.rb +5 -1
- data/app/models/setting/ansible.rb +81 -88
- data/app/services/foreman_ansible/fact_importer.rb +5 -8
- data/app/services/foreman_ansible/fact_parser.rb +16 -4
- data/app/services/foreman_ansible/inventory_creator.rb +1 -12
- data/app/views/foreman_ansible/job_templates/run_playbook-ansible_default.erb +17 -0
- data/config/routes.rb +1 -2
- data/db/migrate/20190328114657_remove_top_level_ansible_variables_setting.rb +1 -1
- data/db/migrate/20191010074208_remove_ansible_implementation_setting.rb +5 -0
- data/db/seeds.d/75_job_templates.rb +2 -2
- data/lib/foreman_ansible/register.rb +5 -2
- data/lib/foreman_ansible/remote_execution.rb +6 -0
- data/lib/foreman_ansible/version.rb +1 -1
- data/locale/Makefile +7 -0
- data/locale/de/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/de/foreman_ansible.po +1 -1
- data/locale/en/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/en/foreman_ansible.po +1 -1
- data/locale/es/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/es/foreman_ansible.po +1 -1
- data/locale/fr/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/fr/foreman_ansible.po +1 -1
- data/locale/it/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/it/foreman_ansible.po +1 -1
- data/locale/ja/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ja/foreman_ansible.po +1 -1
- data/locale/ko/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ko/foreman_ansible.po +1 -1
- data/locale/pt_BR/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/pt_BR/foreman_ansible.po +1 -1
- data/locale/ru/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ru/foreman_ansible.po +1 -1
- data/locale/zh_CN/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/zh_CN/foreman_ansible.po +1 -1
- data/locale/zh_TW/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/zh_TW/foreman_ansible.po +1 -1
- data/package.json +3 -3
- data/test/unit/ansible_provider_test.rb +16 -0
- data/test/unit/ansible_variable_test.rb +10 -0
- data/test/unit/lib/foreman_ansible_core/ansible_runner_test.rb +51 -0
- data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +34 -1
- data/test/unit/services/fact_importer_test.rb +4 -2
- data/test/unit/services/fact_parser_test.rb +57 -4
- data/test/unit/services/inventory_creator_test.rb +10 -25
- data/webpack/__mocks__/foremanReact/common/I18n.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.js +18 -23
- data/webpack/index.js +5 -4
- metadata +15 -11
- data/app/lib/actions/foreman_ansible/helpers/host_common.rb +0 -39
data/config/routes.rb
CHANGED
@@ -8,7 +8,6 @@ Rails.application.routes.draw do
|
|
8
8
|
:defaults => { :apiv => 'v2' },
|
9
9
|
:apiv => /v1|v2/,
|
10
10
|
:constraints => ApiConstraints.new(:version => 2) do
|
11
|
-
|
12
11
|
constraints(:id => %r{[^\/]+}) do
|
13
12
|
resources :hosts, :only => [] do
|
14
13
|
member do
|
@@ -75,7 +74,6 @@ Rails.application.routes.draw do
|
|
75
74
|
:defaults => { :apiv => 'v2' },
|
76
75
|
:apiv => /v1|v2/,
|
77
76
|
:constraints => ApiConstraints.new(:version => 2) do
|
78
|
-
|
79
77
|
resources :ansible_roles, :only => [:show, :index, :destroy] do
|
80
78
|
collection do
|
81
79
|
put :import
|
@@ -99,6 +97,7 @@ Rails.application.routes.draw do
|
|
99
97
|
get :hosts
|
100
98
|
post :hostgroups
|
101
99
|
get :hostgroups
|
100
|
+
post :schedule
|
102
101
|
end
|
103
102
|
end
|
104
103
|
end
|
@@ -20,8 +20,8 @@ User.as_anonymous_admin do
|
|
20
20
|
:default => true,
|
21
21
|
:locked => true,
|
22
22
|
:update => sync)
|
23
|
-
template.organizations = organizations if
|
24
|
-
template.locations = locations if
|
23
|
+
template.organizations = organizations if template.present?
|
24
|
+
template.locations = locations if template.present?
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# rubocop:disable BlockLength
|
4
4
|
Foreman::Plugin.register :foreman_ansible do
|
5
|
-
requires_foreman '>= 1.
|
5
|
+
requires_foreman '>= 1.24'
|
6
6
|
|
7
7
|
security_block :foreman_ansible do
|
8
8
|
permission :play_roles_on_host,
|
@@ -71,6 +71,9 @@ Foreman::Plugin.register :foreman_ansible do
|
|
71
71
|
permission :edit_hostgroups,
|
72
72
|
{ :'api/v2/hostgroups' => [:assign_ansible_roles] },
|
73
73
|
:resource_type => 'Hostgroup'
|
74
|
+
permission :generate_report_templates,
|
75
|
+
{ :'api/v2/ansible_inventories' => [:schedule] },
|
76
|
+
:resource_type => 'ReportTemplate'
|
74
77
|
end
|
75
78
|
|
76
79
|
role 'Ansible Roles Manager',
|
@@ -82,7 +85,7 @@ Foreman::Plugin.register :foreman_ansible do
|
|
82
85
|
:edit_ansible_variables, :destroy_ansible_variables]
|
83
86
|
|
84
87
|
role 'Ansible Tower Inventory Reader',
|
85
|
-
[:view_hosts, :view_hostgroups, :view_facts],
|
88
|
+
[:view_hosts, :view_hostgroups, :view_facts, :generate_report_templates],
|
86
89
|
'Permissions required for the user which is used by Ansible Tower Dynamic Inventory Item'
|
87
90
|
|
88
91
|
add_all_permissions_to_default_roles
|
@@ -30,6 +30,12 @@ module ForemanAnsible
|
|
30
30
|
:provided_inputs => %w[organization_id plan_id],
|
31
31
|
:notification_builder => ForemanAnsible::InsightsNotificationBuilder
|
32
32
|
)
|
33
|
+
RemoteExecutionFeature.register(
|
34
|
+
:ansible_run_playbook,
|
35
|
+
N_('Run playbook'),
|
36
|
+
:description => N_('Run an Ansible playbook against given hosts'),
|
37
|
+
:provided_inputs => %w[playbook]
|
38
|
+
)
|
33
39
|
end
|
34
40
|
end
|
35
41
|
end
|
data/locale/Makefile
CHANGED
@@ -60,3 +60,10 @@ tx-update: tx-pull reset-po $(MOFILES)
|
|
60
60
|
git add ../locale/*/LC_MESSAGES
|
61
61
|
git commit -a --amend -m "i18n - pulling from tx"
|
62
62
|
-echo Changes commited!
|
63
|
+
|
64
|
+
mo-files: $(MOFILES)
|
65
|
+
git add $(POFILES) $(POTFILE) ../locale/*/LC_MESSAGES
|
66
|
+
git commit -m "i18n - pulling from tx"
|
67
|
+
@echo
|
68
|
+
@echo Changes commited!
|
69
|
+
@echo
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/package.json
CHANGED
@@ -7,11 +7,11 @@
|
|
7
7
|
"test": "test"
|
8
8
|
},
|
9
9
|
"dependencies": {
|
10
|
-
"@theforeman/vendor": "^
|
10
|
+
"@theforeman/vendor": "^1.7.0",
|
11
11
|
"react-json-tree": "^0.11.0"
|
12
12
|
},
|
13
13
|
"devDependencies": {
|
14
|
-
"@theforeman/vendor-dev": "^
|
14
|
+
"@theforeman/vendor-dev": "^1.7.0",
|
15
15
|
"babel-eslint": "^8.2.1",
|
16
16
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
17
17
|
"babel-plugin-transform-object-assign": "^6.22.0",
|
@@ -38,7 +38,7 @@
|
|
38
38
|
},
|
39
39
|
"scripts": {
|
40
40
|
"test": "node node_modules/.bin/jest webpack",
|
41
|
-
"lint": "
|
41
|
+
"lint": "eslint ./webpack"
|
42
42
|
},
|
43
43
|
"repository": {
|
44
44
|
"type": "git",
|
@@ -29,6 +29,22 @@ class AnsibleProviderTest < ActiveSupport::TestCase
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
context 'when using secrets' do
|
33
|
+
let(:host) { FactoryBot.build(:host) }
|
34
|
+
|
35
|
+
it 'generates secrets properly' do
|
36
|
+
params = {
|
37
|
+
'remote_execution_ssh_password' => 'password',
|
38
|
+
'remote_execution_sudo_password' => 'letmein'
|
39
|
+
}
|
40
|
+
host.expects(:params).twice.returns(params)
|
41
|
+
secrets = ForemanAnsible::AnsibleProvider.secrets(host)
|
42
|
+
host_secrets = secrets['per-host'][host.name]
|
43
|
+
assert_equal host_secrets['ansible_ssh_pass'], 'password'
|
44
|
+
assert_equal host_secrets['ansible_sudo_pass'], 'letmein'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
32
48
|
def command_options
|
33
49
|
ForemanAnsible::AnsibleProvider.
|
34
50
|
proxy_command_options(template_invocation, dummyhost)
|
@@ -11,4 +11,14 @@ class AnsibleRoleTest < ActiveSupport::TestCase
|
|
11
11
|
subject { AnsibleRole.new(:name => 'foo') }
|
12
12
|
should validate_uniqueness_of(:name)
|
13
13
|
end
|
14
|
+
|
15
|
+
test 'should cast default_value to hash' do
|
16
|
+
variable = FactoryBot.create(
|
17
|
+
:ansible_variable,
|
18
|
+
:key_type => 'hash',
|
19
|
+
:default_value => "{\r\n \"bat\": \"man\"\r\n}\r\n",
|
20
|
+
:override => true
|
21
|
+
)
|
22
|
+
assert variable.default_value.is_a?(Hash)
|
23
|
+
end
|
14
24
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module ForemanAnsibleCore
|
6
|
+
module Runner
|
7
|
+
class AnsibleRunnerTest < ActiveSupport::TestCase
|
8
|
+
describe AnsibleRunner do
|
9
|
+
it 'parses files without event data' do
|
10
|
+
content = <<~JSON
|
11
|
+
{"uuid": "a29d8592-f805-4d0e-b73d-7a53cc35a92e", "stdout": " [WARNING]: Consider using the yum module rather than running 'yum'. If you", "counter": 8, "end_line": 8, "runner_ident": "e2d9ae11-026a-4f9f-9679-401e4b852ab0", "start_line": 7, "event": "verbose"}
|
12
|
+
JSON
|
13
|
+
|
14
|
+
File.expects(:read).with('fake.json').returns(content)
|
15
|
+
runner = AnsibleRunner.allocate
|
16
|
+
runner.expects(:handle_broadcast_data)
|
17
|
+
assert runner.send(:handle_event_file, 'fake.json')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#rebuild_secrets' do
|
22
|
+
let(:inventory) do
|
23
|
+
{ 'all' => { 'hosts' => ['foreman.example.com'] },
|
24
|
+
'_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
|
25
|
+
end
|
26
|
+
let(:input) do
|
27
|
+
host_secrets = { 'ansible_ssh_pass' => 'letmein', 'ansible_sudo_pass' => 'iamroot' }
|
28
|
+
secrets = { 'per-host' => { 'foreman.example.com' => host_secrets } }
|
29
|
+
host_input = { 'input' => { 'action_input' => { 'secrets' => secrets } } }
|
30
|
+
{ 'foreman.example.com' => host_input }
|
31
|
+
end
|
32
|
+
let(:runner) { ForemanAnsibleCore::Runner::AnsibleRunner.allocate }
|
33
|
+
|
34
|
+
test 'uses secrets from inventory' do
|
35
|
+
test_inventory = inventory.merge('ssh_password' => 'sshpass', 'sudo_password' => 'sudopass')
|
36
|
+
rebuilt = runner.send(:rebuild_secrets, test_inventory, input)
|
37
|
+
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
38
|
+
assert_equal 'sshpass', host_vars['ansible_ssh_pass']
|
39
|
+
assert_equal 'sudopass', host_vars['ansible_sudo_pass']
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'host secrets are used when not overriden by inventory secrest' do
|
43
|
+
rebuilt = runner.send(:rebuild_secrets, inventory, input)
|
44
|
+
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
45
|
+
assert_equal 'letmein', host_vars['ansible_ssh_pass']
|
46
|
+
assert_equal 'iamroot', host_vars['ansible_sudo_pass']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -10,6 +10,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
10
10
|
ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:unknown_hosts).
|
11
11
|
returns([])
|
12
12
|
File.expects(:exist?).with(Dir.home).returns(true)
|
13
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
13
14
|
runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
14
15
|
assert '/etc/ansible', runner.instance_variable_get('@ansible_dir')
|
15
16
|
end
|
@@ -24,6 +25,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
24
25
|
test 'creates temp one if not provided' do
|
25
26
|
Dir.expects(:mktmpdir)
|
26
27
|
File.expects(:exist?).with(Dir.home).returns(true)
|
28
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
27
29
|
ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
28
30
|
end
|
29
31
|
|
@@ -32,6 +34,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
32
34
|
ForemanAnsibleCore.expects(:settings).returns(settings)
|
33
35
|
File.expects(:exist?).with(settings[:ansible_dir]).returns(true)
|
34
36
|
Dir.expects(:mktmpdir).never
|
37
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
35
38
|
runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
36
39
|
assert '/foo', runner.instance_variable_get('@working_dir')
|
37
40
|
end
|
@@ -39,7 +42,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
39
42
|
|
40
43
|
context 'TOFU policy' do # Trust On First Use
|
41
44
|
setup do
|
42
|
-
@inventory = { 'all' => { 'hosts' => ['foreman.example.com'] } }
|
45
|
+
@inventory = { 'all' => { 'hosts' => ['foreman.example.com'] } }
|
43
46
|
@output = StringIO.new
|
44
47
|
logger = Logger.new(@output)
|
45
48
|
ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:logger).
|
@@ -51,6 +54,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
51
54
|
with('foreman.example.com').returns(['somekey'])
|
52
55
|
ForemanAnsibleCore::Runner::Playbook.any_instance.
|
53
56
|
expects(:add_to_known_hosts).never
|
57
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
54
58
|
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
55
59
|
end
|
56
60
|
|
@@ -59,6 +63,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
59
63
|
with('foreman.example.com').returns([])
|
60
64
|
ForemanAnsibleCore::Runner::Playbook.any_instance.
|
61
65
|
expects(:add_to_known_hosts).with('foreman.example.com')
|
66
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
62
67
|
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
63
68
|
end
|
64
69
|
|
@@ -67,6 +72,7 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
67
72
|
with('foreman.example.com').returns([])
|
68
73
|
Net::SSH::Transport::Session.expects(:new).with('foreman.example.com').
|
69
74
|
raises(Net::Error)
|
75
|
+
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
70
76
|
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
71
77
|
assert_match(
|
72
78
|
/ERROR.*Failed to save host key for foreman.example.com: Net::Error/,
|
@@ -74,4 +80,31 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
74
80
|
)
|
75
81
|
end
|
76
82
|
end
|
83
|
+
|
84
|
+
context 'rebuild secrets' do
|
85
|
+
let(:inventory) do
|
86
|
+
{ 'all' => { 'hosts' => ['foreman.example.com'] },
|
87
|
+
'_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
|
88
|
+
end
|
89
|
+
let(:secrets) do
|
90
|
+
host_secrets = { 'ansible_ssh_pass' => 'letmein', 'ansible_sudo_pass' => 'iamroot' }
|
91
|
+
{ 'per-host' => { 'foreman.example.com' => host_secrets } }
|
92
|
+
end
|
93
|
+
let(:runner) { ForemanAnsibleCore::Runner::Playbook.allocate }
|
94
|
+
|
95
|
+
test 'uses secrets from inventory' do
|
96
|
+
test_inventory = inventory.merge('ssh_password' => 'sshpass', 'sudo_password' => 'sudopass')
|
97
|
+
rebuilt = runner.send(:rebuild_secrets, test_inventory, secrets)
|
98
|
+
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
99
|
+
assert_equal 'sshpass', host_vars['ansible_ssh_pass']
|
100
|
+
assert_equal 'sudopass', host_vars['ansible_sudo_pass']
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'host secrets are used when not overriden by inventory secrest' do
|
104
|
+
rebuilt = runner.send(:rebuild_secrets, inventory, secrets)
|
105
|
+
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
106
|
+
assert_equal 'letmein', host_vars['ansible_ssh_pass']
|
107
|
+
assert_equal 'iamroot', host_vars['ansible_sudo_pass']
|
108
|
+
end
|
109
|
+
end
|
77
110
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'test_plugin_helper'
|
4
|
+
|
3
5
|
module ForemanAnsible
|
4
6
|
# Test for the facts importer - only verify that given
|
5
7
|
# a set of facts it's able to import them
|
@@ -18,8 +20,8 @@ module ForemanAnsible
|
|
18
20
|
|
19
21
|
test 'missing_facts returns facts we do not have in the database' do
|
20
22
|
@fact_importer = FactImporter.new(@host, facts_json)
|
21
|
-
@fact_importer.expects(:
|
22
|
-
returns('ansible_cmdline'
|
23
|
+
@fact_importer.expects(:host_fact_names).
|
24
|
+
returns(['ansible_cmdline'])
|
23
25
|
refute @fact_importer.send(:missing_facts).include?('ansible_cmdline')
|
24
26
|
end
|
25
27
|
|