foreman_ansible 2.1.2 → 2.2.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/README.md +1 -1
- data/app/controllers/api/v2/ansible_roles_controller.rb +9 -6
- data/app/controllers/foreman_ansible/api/v2/hostgroups_param_group_extensions.rb +17 -0
- data/app/controllers/foreman_ansible/api/v2/hosts_param_group_extensions.rb +17 -0
- data/app/models/concerns/foreman_ansible/host_managed_extensions.rb +19 -7
- data/app/models/setting/ansible.rb +2 -2
- data/app/services/foreman_ansible/fact_parser.rb +1 -52
- data/app/services/foreman_ansible/operating_system_parser.rb +92 -0
- data/db/migrate/20180410125416_rename_ansible_job_categories.rb +1 -1
- data/db/seeds.d/75_job_templates.rb +8 -4
- data/lib/foreman_ansible/engine.rb +6 -0
- data/lib/foreman_ansible/version.rb +1 -1
- data/test/functional/api/v2/ansible_roles_controller_test.rb +12 -0
- data/test/functional/api/v2/hosts_controller_test.rb +26 -0
- data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +45 -0
- data/test/unit/services/fact_parser_test.rb +81 -0
- metadata +5 -5
- data/app/services/foreman_ansible/proxy_selector.rb +0 -33
- data/test/unit/services/proxy_selector_test.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04ef2672d90809de50a458709449a10b393e8b4cf2eae9c1d905682822ecac82
|
4
|
+
data.tar.gz: 1aadd4214a4d53962dfffc9014ae05168c8125ea7a3addc34235d29333c7c30e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae214b5e3516d85af5cb3ade922061ced9e797b39e078cfe63db3b87cc11faf817186aff3230704f2d7d501e5b0d08ccd2e042289a2ef8ae22a430ac6e09f369
|
7
|
+
data.tar.gz: 3a91c4fdb49e342f20a709aaa5e9083e77af70bca95738e8aa0e2bb53441cde66e2f662351a65f2b2195b3cc365ef9793616281ecb35c17f63f0d904c541ee05
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
Reporting and facts import from Ansible to Foreman.
|
8
8
|
|
9
9
|
* Main website: [theforeman.org](http://theforeman.org)
|
10
|
-
* Plugin manual: [foreman_ansible manual](http://theforeman.org/plugins/foreman_ansible
|
10
|
+
* Plugin manual: [foreman_ansible manual](http://theforeman.org/plugins/foreman_ansible)
|
11
11
|
* ServerFault tag: [Foreman](http://serverfault.com/questions/tagged/foreman)
|
12
12
|
* Issues: [foreman ansible on Redmine](http://projects.theforeman.org/projects/ansible/issues)
|
13
13
|
* Community and support: [#theforeman](https://kiwiirc.com/client/irc.freenode.net/?#theforeman) for general support, [#theforeman-dev](https://kiwiirc.com/client/irc.freenode.net/?#theforeman-dev) for development chat in [Freenode](irc.freenode.net)
|
@@ -29,24 +29,27 @@ module Api
|
|
29
29
|
process_response @ansible_role.destroy
|
30
30
|
end
|
31
31
|
|
32
|
-
api :
|
33
|
-
param :
|
32
|
+
api :PUT, '/ansible_roles/import', N_('Import Ansible roles')
|
33
|
+
param :proxy_id, :identifier, N_('Smart Proxy to import from')
|
34
34
|
def import
|
35
35
|
@imported = @importer.import!
|
36
36
|
end
|
37
37
|
|
38
|
-
api :
|
39
|
-
param :
|
38
|
+
api :PUT, '/ansible_roles/obsolete', N_('Obsolete Ansible roles')
|
39
|
+
param :proxy_id, :identifier, N_('Smart Proxy to import from')
|
40
40
|
def obsolete
|
41
41
|
@obsoleted = @importer.obsolete!
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
+
# rubocop:disable DotPosition
|
46
47
|
def find_proxy
|
47
|
-
return nil unless params[:
|
48
|
-
@proxy = SmartProxy.authorized(:view_smart_proxies)
|
48
|
+
return nil unless params[:proxy_id]
|
49
|
+
@proxy = SmartProxy.authorized(:view_smart_proxies)
|
50
|
+
.find(params[:proxy_id])
|
49
51
|
end
|
52
|
+
# rubocop:enable DotPosition
|
50
53
|
|
51
54
|
def create_importer
|
52
55
|
@importer = ForemanAnsible::ApiRolesImporter.new(@proxy)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
# Extends the hostgroups api controller to support creating with roles
|
5
|
+
module HostgroupsParamGroupExtensions
|
6
|
+
extend Apipie::DSL::Concern
|
7
|
+
|
8
|
+
update_api(:create, :update) do
|
9
|
+
param :hostgroup, Hash do
|
10
|
+
param :ansible_role_ids, Array,
|
11
|
+
:desc => N_('IDs of associated ansible roles')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
# Extends the hosts api controller to support creating/updating with roles
|
5
|
+
module HostsParamGroupExtensions
|
6
|
+
extend Apipie::DSL::Concern
|
7
|
+
|
8
|
+
update_api(:create, :update) do
|
9
|
+
param :host, Hash do
|
10
|
+
param :ansible_role_ids, Array,
|
11
|
+
:desc => N_('IDs of associated ansible roles')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -2,7 +2,9 @@ module ForemanAnsible
|
|
2
2
|
# Relations to make Host::Managed 'have' ansible roles
|
3
3
|
module HostManagedExtensions
|
4
4
|
extend ActiveSupport::Concern
|
5
|
+
include ::ForemanAnsible::Concerns::JobInvocationHelper
|
5
6
|
|
7
|
+
# rubocop:disable Metrics/BlockLength
|
6
8
|
included do
|
7
9
|
has_many :host_ansible_roles, :foreign_key => :host_id
|
8
10
|
has_many :ansible_roles, :through => :host_ansible_roles,
|
@@ -20,18 +22,28 @@ module ForemanAnsible
|
|
20
22
|
hostgroup.all_ansible_roles
|
21
23
|
end
|
22
24
|
|
25
|
+
# This one should be fixed, disabled for the moment as we're
|
26
|
+
# in a rush to get the release out
|
27
|
+
# rubocop:disable Metrics/AbcSize
|
23
28
|
def play_ansible_roles
|
24
|
-
return unless ansible_roles.present? ||
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
return true unless ansible_roles.present? ||
|
30
|
+
inherited_ansible_roles.present?
|
31
|
+
composer = job_composer(:ansible_run_host, self)
|
32
|
+
composer.triggering.mode = :future
|
33
|
+
composer.triggering.start_at = (
|
34
|
+
Time.zone.now +
|
35
|
+
Setting::Ansible[:ansible_post_provision_timeout].to_i.seconds
|
30
36
|
)
|
37
|
+
composer.trigger!
|
31
38
|
logger.info("Task for Ansible roles on #{self} before_provision: "\
|
32
|
-
"#{
|
39
|
+
"#{job_invocation_path(composer.job_invocation)}")
|
40
|
+
rescue Foreman::Exception => e
|
41
|
+
logger.info("Error running Ansible roles on #{self} before_provision: "\
|
42
|
+
"#{e.message}")
|
33
43
|
end
|
44
|
+
# rubocop:enable Metrics/AbcSize
|
34
45
|
end
|
46
|
+
# rubocop:enable Metrics/BlockLength
|
35
47
|
end
|
36
48
|
end
|
37
49
|
|
@@ -43,11 +43,11 @@ class Setting
|
|
43
43
|
'ansible_verbosity',
|
44
44
|
N_('Foreman will add the this level of verbosity for '\
|
45
45
|
'additional debugging output when running Ansible playbooks.'),
|
46
|
-
'',
|
46
|
+
'0',
|
47
47
|
N_('Default verbosity level'),
|
48
48
|
nil,
|
49
49
|
:collection => lambda do
|
50
|
-
{ '' => N_('Disabled'),
|
50
|
+
{ '0' => N_('Disabled'),
|
51
51
|
'1' => N_('Level 1 (-v)'),
|
52
52
|
'2' => N_('Level 2 (-vv)'),
|
53
53
|
'3' => N_('Level 3 (-vvv)'),
|
@@ -2,18 +2,13 @@ module ForemanAnsible
|
|
2
2
|
# Override methods from Foreman app/services/fact_parser so that facts
|
3
3
|
# representing host properties are understood when they come from Ansible.
|
4
4
|
class FactParser < ::FactParser
|
5
|
+
include OperatingSystemParser
|
5
6
|
attr_reader :facts
|
6
7
|
|
7
8
|
def initialize(facts)
|
8
9
|
@facts = HashWithIndifferentAccess.new(facts[:ansible_facts])
|
9
10
|
end
|
10
11
|
|
11
|
-
def operatingsystem
|
12
|
-
args = { :name => os_name, :major => os_major, :minor => os_minor }
|
13
|
-
Operatingsystem.where(args).first ||
|
14
|
-
Operatingsystem.create!(args.merge(:description => os_description))
|
15
|
-
end
|
16
|
-
|
17
12
|
# Don't do anything as there's no env in Ansible
|
18
13
|
def environment; end
|
19
14
|
|
@@ -75,52 +70,6 @@ module ForemanAnsible
|
|
75
70
|
facts[:"ansible_#{interface}"]['ipv4']['address']
|
76
71
|
end
|
77
72
|
|
78
|
-
def os_name
|
79
|
-
facts[:ansible_distribution] ||
|
80
|
-
facts[:ansible_lsb] && facts[:ansible_lsb]['id']
|
81
|
-
end
|
82
|
-
|
83
|
-
def debian_os_major_sid
|
84
|
-
case facts[:ansible_distribution_major_version]
|
85
|
-
when /wheezy/i
|
86
|
-
'7'
|
87
|
-
when /jessie/i
|
88
|
-
'8'
|
89
|
-
when /stretch/i
|
90
|
-
'9'
|
91
|
-
when /buster/i
|
92
|
-
'10'
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity
|
97
|
-
def os_major
|
98
|
-
if os_name == 'Debian' &&
|
99
|
-
facts[:ansible_distribution_major_version][%r{\/sid}i]
|
100
|
-
debian_os_major_sid
|
101
|
-
else
|
102
|
-
facts[:ansible_distribution_major_version] ||
|
103
|
-
facts[:ansible_lsb] && facts[:ansible_lsb]['major_release'] ||
|
104
|
-
(facts[:version].split('R')[0] if os_name == 'junos')
|
105
|
-
end
|
106
|
-
end
|
107
|
-
# rubocop:enable AbcSize, CyclomaticComplexity, PerceivedComplexity
|
108
|
-
|
109
|
-
def os_release
|
110
|
-
facts[:ansible_distribution_version] ||
|
111
|
-
facts[:ansible_lsb] && facts[:ansible_lsb]['release']
|
112
|
-
end
|
113
|
-
|
114
|
-
def os_minor
|
115
|
-
_, minor = (os_release.split('.') unless os_release.nil?) ||
|
116
|
-
(facts[:version].split('R') if os_name == 'junos')
|
117
|
-
minor || ''
|
118
|
-
end
|
119
|
-
|
120
|
-
def os_description
|
121
|
-
facts[:ansible_lsb] && facts[:ansible_lsb]['description']
|
122
|
-
end
|
123
|
-
|
124
73
|
# Returns first non-empty fact. Needed to check for empty strings.
|
125
74
|
def detect_fact(fact_names)
|
126
75
|
facts[
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
# Methods to parse facts related to the OS
|
3
|
+
module OperatingSystemParser
|
4
|
+
def operatingsystem
|
5
|
+
args = { :name => os_name, :major => os_major, :minor => os_minor }
|
6
|
+
return @local_os if local_os(args).present?
|
7
|
+
return @new_os if new_os(args).present?
|
8
|
+
logger.debug do
|
9
|
+
'Ansible facts parser: No OS could be created with '\
|
10
|
+
"os_name='#{os_name}' os_major='#{os_major}' "\
|
11
|
+
"os_minor='#{os_minor}': "\
|
12
|
+
"#{@new_os.errors if @new_os.present?}"
|
13
|
+
end
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def local_os(args)
|
18
|
+
@local_os = Operatingsystem.where(args).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def new_os(args)
|
22
|
+
return @new_os if @new_os.present?
|
23
|
+
@new_os = Operatingsystem.new(args.merge(:description => os_description))
|
24
|
+
@new_os if @new_os.valid? && @new_os.save
|
25
|
+
end
|
26
|
+
|
27
|
+
def debian_os_major_sid
|
28
|
+
case facts[:ansible_distribution_major_version]
|
29
|
+
when /wheezy/i
|
30
|
+
'7'
|
31
|
+
when /jessie/i
|
32
|
+
'8'
|
33
|
+
when /stretch/i
|
34
|
+
'9'
|
35
|
+
when /buster/i
|
36
|
+
'10'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# rubocop:disable AbcSize, CyclomaticComplexity, PerceivedComplexity
|
41
|
+
def os_major
|
42
|
+
if os_name == 'Debian' &&
|
43
|
+
facts[:ansible_distribution_major_version][%r{\/sid}i]
|
44
|
+
debian_os_major_sid
|
45
|
+
else
|
46
|
+
facts[:ansible_distribution_major_version] ||
|
47
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['major_release'] ||
|
48
|
+
(facts[:version].split('R')[0] if os_name == 'junos')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# rubocop:enable AbcSize, CyclomaticComplexity, PerceivedComplexity
|
52
|
+
|
53
|
+
def os_release
|
54
|
+
facts[:ansible_distribution_version] ||
|
55
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['release']
|
56
|
+
end
|
57
|
+
|
58
|
+
# rubocop:disable AbcSize
|
59
|
+
def os_minor
|
60
|
+
_, minor = (os_release.split('.', 2) unless os_release.nil?) ||
|
61
|
+
(facts[:version].split('R') if os_name == 'junos')
|
62
|
+
# Until Foreman supports os.minor as something that's not a number,
|
63
|
+
# we should remove the extra dots in the version. E.g:
|
64
|
+
# '6.1.7601.65536' becomes '6.1.760165536'
|
65
|
+
if facts[:ansible_os_family] == 'Windows'
|
66
|
+
minor, patch = minor.split('.', 2)
|
67
|
+
patch.tr!('.', '')
|
68
|
+
minor = "#{minor}.#{patch}"
|
69
|
+
end
|
70
|
+
minor || ''
|
71
|
+
end
|
72
|
+
|
73
|
+
def os_name
|
74
|
+
if facts[:ansible_os_family] == 'Windows'
|
75
|
+
facts[:ansible_os_name].tr(" \n\t", '') ||
|
76
|
+
facts[:ansible_distribution].tr(" \n\t", '')
|
77
|
+
else
|
78
|
+
facts[:ansible_distribution] ||
|
79
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['id']
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# rubocop:enable AbcSize
|
83
|
+
|
84
|
+
def os_description
|
85
|
+
if facts[:ansible_os_family] == 'Windows'
|
86
|
+
facts[:ansible_os_name].strip || facts[:ansible_distribution].strip
|
87
|
+
else
|
88
|
+
facts[:ansible_lsb] && facts[:ansible_lsb]['description']
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -14,7 +14,7 @@ class RenameAnsibleJobCategories < ActiveRecord::Migration[5.1]
|
|
14
14
|
job_templates.each do |job_template|
|
15
15
|
next if job_template.job_category =~ /^Ansible/
|
16
16
|
job_template.job_category = "Ansible #{job_template.job_category}"
|
17
|
-
job_template.
|
17
|
+
job_template.save
|
18
18
|
end
|
19
19
|
|
20
20
|
service_template = JobTemplate.where(
|
@@ -1,3 +1,5 @@
|
|
1
|
+
organizations = Organization.unscoped.all
|
2
|
+
locations = Location.unscoped.all
|
1
3
|
User.as_anonymous_admin do
|
2
4
|
RemoteExecutionFeature.without_auditing do
|
3
5
|
if Rails.env.test? || File.basename($PROGRAM_NAME) == 'rake'
|
@@ -12,10 +14,12 @@ User.as_anonymous_admin do
|
|
12
14
|
Dir[File.join("#{ForemanAnsible::Engine.root}/app/views/foreman_ansible/"\
|
13
15
|
'job_templates/**/*.erb')].each do |template|
|
14
16
|
sync = !Rails.env.test? && Setting[:remote_execution_sync_templates]
|
15
|
-
JobTemplate.import_raw!(File.read(template),
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
template = JobTemplate.import_raw!(File.read(template),
|
18
|
+
:default => true,
|
19
|
+
:locked => true,
|
20
|
+
:update => sync)
|
21
|
+
template.organizations = organizations if SETTINGS[:organizations_enabled] && template.present?
|
22
|
+
template.locations = locations if SETTINGS[:locations_enabled] && template.present?
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -92,12 +92,18 @@ module ForemanAnsible
|
|
92
92
|
::Api::V2::HostsController.send(
|
93
93
|
:include, ForemanAnsible::Api::V2::HostsControllerExtensions
|
94
94
|
)
|
95
|
+
::Api::V2::HostsController.send(
|
96
|
+
:include, ForemanAnsible::Api::V2::HostsParamGroupExtensions
|
97
|
+
)
|
95
98
|
::HostgroupsController.send(
|
96
99
|
:include, ForemanAnsible::Concerns::HostgroupsControllerExtensions
|
97
100
|
)
|
98
101
|
::Api::V2::HostgroupsController.send(
|
99
102
|
:include, ForemanAnsible::Api::V2::HostgroupsControllerExtensions
|
100
103
|
)
|
104
|
+
::Api::V2::HostgroupsController.send(
|
105
|
+
:include, ForemanAnsible::Api::V2::HostgroupsParamGroupExtensions
|
106
|
+
)
|
101
107
|
rescue StandardError => e
|
102
108
|
Rails.logger.warn "Foreman Ansible: skipping engine hook (#{e})"
|
103
109
|
end
|
@@ -22,6 +22,18 @@ module Api
|
|
22
22
|
assert_response :ok
|
23
23
|
refute AnsibleRole.exists?(@role.id)
|
24
24
|
end
|
25
|
+
|
26
|
+
test 'should import' do
|
27
|
+
put :import,
|
28
|
+
:session => set_session_user
|
29
|
+
assert_response :success
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'should obsolete' do
|
33
|
+
put :obsolete,
|
34
|
+
:session => set_session_user
|
35
|
+
assert_response :success
|
36
|
+
end
|
25
37
|
end
|
26
38
|
end
|
27
39
|
end
|
@@ -5,6 +5,8 @@ module Api
|
|
5
5
|
# Tests for the extra methods to play roles on a Host
|
6
6
|
class HostsControllerTest < ActionController::TestCase
|
7
7
|
setup do
|
8
|
+
@ansible_role1 = FactoryBot.create(:ansible_role)
|
9
|
+
@ansible_role2 = FactoryBot.create(:ansible_role)
|
8
10
|
@host1 = FactoryBot.create(:host)
|
9
11
|
@host2 = FactoryBot.create(:host)
|
10
12
|
end
|
@@ -36,6 +38,30 @@ module Api
|
|
36
38
|
response = JSON.parse(@response.body)
|
37
39
|
assert_job_invocation_is_ok(response, targets)
|
38
40
|
end
|
41
|
+
|
42
|
+
test 'should create a host with ansible_role_ids param' do
|
43
|
+
post :create,
|
44
|
+
:params => { :host => { :ansible_role_ids => @ansible_role1.id,
|
45
|
+
:managed => false,
|
46
|
+
:name => 'Doe' } },
|
47
|
+
:session => set_session_user
|
48
|
+
assert_response :created
|
49
|
+
assert assigns('host').ansible_roles, [@ansible_role1]
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'should update a host with ansible_role_ids param' do
|
53
|
+
host = FactoryBot.create(:host,
|
54
|
+
:managed => false,
|
55
|
+
:ansible_role_ids => [@ansible_role1.id])
|
56
|
+
post :update,
|
57
|
+
:params => {
|
58
|
+
:id => host.id,
|
59
|
+
:host => { :ansible_role_ids => [@ansible_role2.id] }
|
60
|
+
},
|
61
|
+
:session => set_session_user
|
62
|
+
assert_response :success
|
63
|
+
assert assigns('host').ansible_roles, [@ansible_role2]
|
64
|
+
end
|
39
65
|
end
|
40
66
|
end
|
41
67
|
end
|
@@ -5,6 +5,8 @@ require 'test_helper'
|
|
5
5
|
class PlaybookRunnerTest < ActiveSupport::TestCase
|
6
6
|
context 'roles dir' do
|
7
7
|
test 'reads default when none provided' do
|
8
|
+
ForemanAnsibleCore::PlaybookRunner.any_instance.stubs(:unknown_hosts).
|
9
|
+
returns([])
|
8
10
|
File.expects(:exist?).with('/etc/ansible').returns(true)
|
9
11
|
runner = ForemanAnsibleCore::PlaybookRunner.new(nil, nil)
|
10
12
|
assert '/etc/ansible', runner.instance_variable_get('@ansible_dir')
|
@@ -12,6 +14,11 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
12
14
|
end
|
13
15
|
|
14
16
|
context 'working_dir' do
|
17
|
+
setup do
|
18
|
+
ForemanAnsibleCore::PlaybookRunner.any_instance.stubs(:unknown_hosts).
|
19
|
+
returns([])
|
20
|
+
end
|
21
|
+
|
15
22
|
test 'creates temp one if not provided' do
|
16
23
|
Dir.expects(:mktmpdir)
|
17
24
|
File.expects(:exist?).with('/etc/ansible').returns(true)
|
@@ -27,4 +34,42 @@ class PlaybookRunnerTest < ActiveSupport::TestCase
|
|
27
34
|
assert '/foo', runner.instance_variable_get('@working_dir')
|
28
35
|
end
|
29
36
|
end
|
37
|
+
|
38
|
+
context 'TOFU policy' do # Trust On First Use
|
39
|
+
setup do
|
40
|
+
@inventory = { 'all' => { 'hosts' => ['foreman.example.com'] } }.to_json
|
41
|
+
@output = StringIO.new
|
42
|
+
logger = Logger.new(@output)
|
43
|
+
ForemanAnsibleCore::PlaybookRunner.any_instance.stubs(:logger).
|
44
|
+
returns(logger)
|
45
|
+
end
|
46
|
+
|
47
|
+
test 'ignores known hosts' do
|
48
|
+
Net::SSH::KnownHosts.expects(:search_for).
|
49
|
+
with('foreman.example.com').returns(['somekey'])
|
50
|
+
ForemanAnsibleCore::PlaybookRunner.any_instance.
|
51
|
+
expects(:add_to_known_hosts).never
|
52
|
+
ForemanAnsibleCore::PlaybookRunner.new(@inventory, nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
test 'adds unknown hosts to known_hosts' do
|
56
|
+
Net::SSH::KnownHosts.expects(:search_for).
|
57
|
+
with('foreman.example.com').returns([])
|
58
|
+
ForemanAnsibleCore::PlaybookRunner.any_instance.
|
59
|
+
expects(:add_to_known_hosts).with('foreman.example.com')
|
60
|
+
ForemanAnsibleCore::PlaybookRunner.new(@inventory, nil)
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'logs error when it cannot add to known_hosts' do
|
64
|
+
Net::SSH::KnownHosts.expects(:search_for).
|
65
|
+
with('foreman.example.com').returns([])
|
66
|
+
Net::SSH::Transport::Session.expects(:new).with('foreman.example.com').
|
67
|
+
raises(Net::Error)
|
68
|
+
ForemanAnsibleCore::PlaybookRunner.new(@inventory, nil)
|
69
|
+
assert_match(
|
70
|
+
/ERROR.*Failed to save host key for foreman.example.com: Net::Error/,
|
71
|
+
@output.string
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
30
75
|
end
|
@@ -38,6 +38,15 @@ module ForemanAnsible
|
|
38
38
|
@facts_parser.operatingsystem
|
39
39
|
end
|
40
40
|
|
41
|
+
test 'does not fail if facts are not enough to create OS' do
|
42
|
+
@facts_parser.expects(:os_name).returns('fakeos').at_least_once
|
43
|
+
@facts_parser.expects(:os_major).returns('').at_least_once
|
44
|
+
@facts_parser.expects(:os_minor).returns('').at_least_once
|
45
|
+
@facts_parser.expects(:os_description).returns('').at_least_once
|
46
|
+
Operatingsystem.any_instance.expects(:valid?).returns(false)
|
47
|
+
assert_nil @facts_parser.operatingsystem
|
48
|
+
end
|
49
|
+
|
41
50
|
private
|
42
51
|
|
43
52
|
def expect_where(model, fact_name)
|
@@ -71,4 +80,76 @@ module ForemanAnsible
|
|
71
80
|
assert_equal 'Debian', os.name
|
72
81
|
end
|
73
82
|
end
|
83
|
+
|
84
|
+
# Tests for Windows parser
|
85
|
+
class WindowsFactParserTest < ActiveSupport::TestCase
|
86
|
+
context 'Windows 7' do
|
87
|
+
setup do
|
88
|
+
@facts_parser = ForemanAnsible::FactParser.new(
|
89
|
+
HashWithIndifferentAccess.new(
|
90
|
+
'_type' => 'ansible',
|
91
|
+
'_timestamp' => '2015-10-29 20:01:51 +0100',
|
92
|
+
'ansible_facts' => {
|
93
|
+
'ansible_architecture' => '32-Bit',
|
94
|
+
'ansible_distribution' => 'Microsoft Windows 7 Enterprise ',
|
95
|
+
'ansible_distribution_major_version' => '6',
|
96
|
+
'ansible_distribution_version' => '6.1.7601.65536',
|
97
|
+
'ansible_os_family' => 'Windows',
|
98
|
+
'ansible_os_name' => 'Microsoft Windows 7 Enterprise',
|
99
|
+
'ansible_product_name' => 'DS61',
|
100
|
+
'ansible_product_serial' => 'To be filled by O.E.M.',
|
101
|
+
'ansible_system' => 'Win32NT',
|
102
|
+
'ansible_win_rm_certificate_expires' => '2021-01-23 15:08:48',
|
103
|
+
'ansible_windows_domain' => 'example.com'
|
104
|
+
}
|
105
|
+
)
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
test 'parses Windows 7 Enterprise correctly' do
|
110
|
+
os = @facts_parser.operatingsystem
|
111
|
+
assert_equal '6', os.major
|
112
|
+
assert_equal '6.1.760165536', os.release
|
113
|
+
assert_equal '1.760165536', os.minor
|
114
|
+
assert_equal 'Windows', os.family
|
115
|
+
assert_equal 'Microsoft Windows 7 Enterprise', os.description
|
116
|
+
assert_equal 'MicrosoftWindows7Enterprise', os.name
|
117
|
+
assert os.valid?
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'Windows Server 2016' do
|
122
|
+
setup do
|
123
|
+
@facts_parser = ForemanAnsible::FactParser.new(
|
124
|
+
HashWithIndifferentAccess.new(
|
125
|
+
'_type' => 'ansible',
|
126
|
+
'_timestamp' => '2015-10-29 20:01:51 +0100',
|
127
|
+
'ansible_facts' => {
|
128
|
+
'ansible_architecture' => '64-Bit',
|
129
|
+
'ansible_distribution' => 'Microsoft Windows Server 2016 '\
|
130
|
+
'Standard',
|
131
|
+
'ansible_distribution_major_version' => '10',
|
132
|
+
'ansible_distribution_version' => '10.0.14393.0',
|
133
|
+
'ansible_os_family' => 'Windows',
|
134
|
+
'ansible_os_name' => 'Microsoft Windows Server 2016 Standard',
|
135
|
+
'ansible_system' => 'Win32NT',
|
136
|
+
'ansible_win_rm_certificate_expires' => '2021-01-23 15:08:48',
|
137
|
+
'ansible_windows_domain' => 'example.com'
|
138
|
+
}
|
139
|
+
)
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
test 'parses Windows Server correctly' do
|
144
|
+
os = @facts_parser.operatingsystem
|
145
|
+
assert_equal '10', os.major
|
146
|
+
assert_equal '10.0.143930', os.release
|
147
|
+
assert_equal '0.143930', os.minor
|
148
|
+
assert_equal 'Windows', os.family
|
149
|
+
assert_equal 'Microsoft Windows Server 2016 Standard', os.description
|
150
|
+
assert_equal 'MicrosoftWindowsServer2016Standard', os.name
|
151
|
+
assert os.valid?
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
74
155
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_ansible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Lobato Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -101,7 +101,9 @@ files:
|
|
101
101
|
- app/controllers/ansible_roles_controller.rb
|
102
102
|
- app/controllers/api/v2/ansible_roles_controller.rb
|
103
103
|
- app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb
|
104
|
+
- app/controllers/foreman_ansible/api/v2/hostgroups_param_group_extensions.rb
|
104
105
|
- app/controllers/foreman_ansible/api/v2/hosts_controller_extensions.rb
|
106
|
+
- app/controllers/foreman_ansible/api/v2/hosts_param_group_extensions.rb
|
105
107
|
- app/controllers/foreman_ansible/concerns/hostgroups_controller_extensions.rb
|
106
108
|
- app/controllers/foreman_ansible/concerns/hosts_controller_extensions.rb
|
107
109
|
- app/controllers/foreman_ansible/concerns/job_invocation_helper.rb
|
@@ -133,8 +135,8 @@ files:
|
|
133
135
|
- app/services/foreman_ansible/insights_notification_builder.rb
|
134
136
|
- app/services/foreman_ansible/insights_plan_runner.rb
|
135
137
|
- app/services/foreman_ansible/inventory_creator.rb
|
138
|
+
- app/services/foreman_ansible/operating_system_parser.rb
|
136
139
|
- app/services/foreman_ansible/playbook_creator.rb
|
137
|
-
- app/services/foreman_ansible/proxy_selector.rb
|
138
140
|
- app/services/foreman_ansible/renderer_methods.rb
|
139
141
|
- app/services/foreman_ansible/roles_importer.rb
|
140
142
|
- app/services/foreman_ansible/structured_fact_importer.rb
|
@@ -215,7 +217,6 @@ files:
|
|
215
217
|
- test/unit/services/fact_sparser_test.rb
|
216
218
|
- test/unit/services/insights_plan_runner_test.rb
|
217
219
|
- test/unit/services/inventory_creator_test.rb
|
218
|
-
- test/unit/services/proxy_selector_test.rb
|
219
220
|
- test/unit/services/roles_importer_test.rb
|
220
221
|
- test/unit/services/structured_fact_importer_test.rb
|
221
222
|
- test/unit/services/ui_roles_importer_test.rb
|
@@ -250,7 +251,6 @@ test_files:
|
|
250
251
|
- test/unit/hostgroup_ansible_role_test.rb
|
251
252
|
- test/unit/services/api_roles_importer_test.rb
|
252
253
|
- test/unit/services/fact_sparser_test.rb
|
253
|
-
- test/unit/services/proxy_selector_test.rb
|
254
254
|
- test/unit/services/insights_plan_runner_test.rb
|
255
255
|
- test/unit/services/structured_fact_importer_test.rb
|
256
256
|
- test/unit/services/ui_roles_importer_test.rb
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module ForemanAnsible
|
2
|
-
# Contains proxy selection rules for a host playbook run
|
3
|
-
class ProxySelector < ::ForemanTasks::ProxySelector
|
4
|
-
def available_proxies(host)
|
5
|
-
proxies = {}
|
6
|
-
if host.execution_interface && host.execution_interface.subnet
|
7
|
-
proxies[:subnet] = host.
|
8
|
-
execution_interface.
|
9
|
-
subnet.
|
10
|
-
remote_execution_proxies.with_features(provider)
|
11
|
-
end
|
12
|
-
proxies[:fallback] = host.smart_proxies.with_features('Ansible')
|
13
|
-
proxies[:global] = proxy_scope(host).authorized.with_features('Ansible')
|
14
|
-
proxies
|
15
|
-
end
|
16
|
-
|
17
|
-
def determine_proxy(*args)
|
18
|
-
result = super
|
19
|
-
return result unless result == :not_available
|
20
|
-
# Always run roles in some way, even if there are no proxies, Foreman
|
21
|
-
# should take that role in that case.
|
22
|
-
:not_defined
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def proxy_scope(host)
|
28
|
-
return ::SmartProxy unless Taxonomy.enabled_taxonomies.any?
|
29
|
-
::SmartProxy.with_taxonomy_scope_override(host.location,
|
30
|
-
host.organization)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
# Tests for the Proxy Selector service
|
4
|
-
class ProxySelectorTest < ActiveSupport::TestCase
|
5
|
-
setup do
|
6
|
-
@host = FactoryBot.create(:host)
|
7
|
-
end
|
8
|
-
|
9
|
-
test 'reuses proxies already assigned to host' do
|
10
|
-
mocked_scope = mock
|
11
|
-
mocked_scope.expects(:with_features).with('Ansible').returns('foo')
|
12
|
-
@host.expects(:smart_proxies).returns(mocked_scope)
|
13
|
-
proxy_selector = ForemanAnsible::ProxySelector.new
|
14
|
-
assert_equal 'foo',
|
15
|
-
proxy_selector.available_proxies(@host)[:fallback]
|
16
|
-
end
|
17
|
-
|
18
|
-
test 'only finds proxies that are within host taxonomies' do
|
19
|
-
@host.organization = taxonomies(:organization1)
|
20
|
-
@ansible_proxy = FactoryBot.create(:smart_proxy, :with_ansible,
|
21
|
-
:organizations => [@host.organization])
|
22
|
-
# Unreachable proxy, because of the organizations mismatch with Host
|
23
|
-
FactoryBot.create(:smart_proxy, :with_ansible, :organizations => [])
|
24
|
-
proxy_selector = ForemanAnsible::ProxySelector.new
|
25
|
-
setup_user('view', 'smart_proxies')
|
26
|
-
assert_equal [@ansible_proxy],
|
27
|
-
proxy_selector.available_proxies(@host)[:global]
|
28
|
-
end
|
29
|
-
end
|