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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1b51e2ee078f80efdc740694e7b27dd61bc6143420f7452db7d44dd085b6a30
4
- data.tar.gz: f45a78080c31ffe8e5ad6595fb45ed5f81d151b68a113c1059615471c62cc245
3
+ metadata.gz: 04ef2672d90809de50a458709449a10b393e8b4cf2eae9c1d905682822ecac82
4
+ data.tar.gz: 1aadd4214a4d53962dfffc9014ae05168c8125ea7a3addc34235d29333c7c30e
5
5
  SHA512:
6
- metadata.gz: 238e18d65857e84570cb3c7fe9429c945d5c6eb05bcc9cd2dd814181ab47a0d2e271edc056c3a0a0497c424b990af57ad8113ddbda1779eddadffd0c142b2794
7
- data.tar.gz: 38e1705a05da9f3d6885ec03bb7dcc0353eaac253896b0d5466aea839973d1ae25a51e3a1aee6eb98c7b9079d0494bf5e2991e1d6ac150c443460e1646dc844a
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/1.x/index.html)
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 :POST, '/ansible_roles/import', N_('Import Ansible roles')
33
- param :proxy, Hash, N_('Smart Proxy to import from')
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 :POST, '/ansible_roles/obsolete', N_('Obsolete Ansible roles')
39
- param :proxy, Hash, N_('Smart Proxy to import from')
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[:proxy]
48
- @proxy = SmartProxy.authorized(:view_smart_proxies).find(params[:proxy])
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? || inherited_ansible_roles.present?
25
- task = ::ForemanTasks.async_task(
26
- ::Actions::ForemanAnsible::PlayHostRoles,
27
- self,
28
- ::ForemanAnsible::ProxySelector.new,
29
- :timeout => Setting['ansible_post_provision_timeout']
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
- "#{Rails.application.routes.url_helpers.task_path(task)}.")
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.save_without_auditing
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
- :default => true,
17
- :locked => true,
18
- :update => sync)
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
@@ -2,5 +2,5 @@
2
2
  # This way other parts of Foreman can just call ForemanAnsible::VERSION
3
3
  # and detect what version the plugin is running.
4
4
  module ForemanAnsible
5
- VERSION = '2.1.2'.freeze
5
+ VERSION = '2.2.0'.freeze
6
6
  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.1.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-05-03 00:00:00.000000000 Z
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