foreman_ansible 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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