foreman_ansible 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e5605f307b791042daffaba55f5f392dc4a8b6b
4
- data.tar.gz: eeb4d1e7aa6b25ebf1ab9533534332427c8a06ff
3
+ metadata.gz: 275aa3a16113e61a5eaf4fdaf6dddb0db8ebd40f
4
+ data.tar.gz: 2926a08f5acb7551b2945bb1662bddd57151daeb
5
5
  SHA512:
6
- metadata.gz: d9bcb91b7af9c9a525990109cf779a396e41134d077087326f203252dadda87f6eafdf951b66fb650e4b07a9f1ea7609e7798e55f7c4319ee33aee69592aacff
7
- data.tar.gz: c271443947d2d76c328af95afc6b729684a00e5086a2cba6066a950b59127cb484adfef88fc081f511c1e3bef0f5c2def8908a8da3d2d478512a9871a7f2aa30
6
+ metadata.gz: cd4524fc8bb4059abe867a4beea2c62e51e07560792fccbaa5e653ff4f09750451b36a3d5ab314ec873ab55853917302331e18a9c5bc8272653d1cfea3f69eb7
7
+ data.tar.gz: 746ea0fc1a44d761d323ab2077b0743169e88f00f4f338e50d8efeb4882ce3b7d9f1d6a76d0a9d913d325a26f0f64935031d3b6833419360f98e7cdcb3395b4c
@@ -1,8 +1,12 @@
1
+ require "#{ForemanAnsible::Engine.root}/lib/foreman_ansible/version"
2
+
1
3
  module ForemanAnsible
2
4
  # General helper for foreman_ansible
3
5
  module AnsiblePluginHelper
4
6
  def ansible_doc_url
5
- 'http://theforeman.org/plugins/foreman_ansible/1.x/index.html'
7
+ major_version = ::ForemanAnsible::VERSION.split('.')[0]
8
+ 'https://theforeman.org/plugins/foreman_ansible/'\
9
+ "#{major_version}.x/index.html"
6
10
  end
7
11
  end
8
12
  end
@@ -4,12 +4,16 @@ if defined? ForemanRemoteExecution
4
4
  # Read the source of other RemoteExecution providers for more.
5
5
  class AnsibleProvider < RemoteExecutionProvider
6
6
  class << self
7
- def humanized_name
8
- 'Ansible'
7
+ def ssh_password(host)
8
+ host_setting(host, :remote_execution_ssh_password)
9
+ end
10
+
11
+ def ssh_key_passphrase(host)
12
+ host_setting(host, :remote_execution_ssh_key_passphrase)
9
13
  end
10
14
 
11
- def host_setting(host, setting)
12
- host.params[setting.to_s] || Setting[setting]
15
+ def humanized_name
16
+ 'Ansible'
13
17
  end
14
18
 
15
19
  def proxy_command_options(template_invocation, host)
@@ -10,41 +10,9 @@ class Setting
10
10
  # rubocop:disable BlockLength
11
11
  def load_defaults
12
12
  return unless super
13
+ Setting::BLANK_ATTRS.push('ansible_ssh_private_key_file')
13
14
  transaction do
14
15
  [
15
- set(
16
- 'ansible_port',
17
- N_('Use this port to connect to hosts '\
18
- 'and run Ansible. You can override this on hosts '\
19
- 'by adding a parameter "ansible_port"'),
20
- 22,
21
- N_('Port')
22
- ),
23
- set(
24
- 'ansible_user',
25
- N_('Foreman will try to connect to hosts as this user by '\
26
- 'default when running Ansible playbooks. You can '\
27
- 'override this on hosts by adding a parameter '\
28
- '"ansible_user"'),
29
- 'root',
30
- N_('User')
31
- ),
32
- set(
33
- 'ansible_become',
34
- N_('Foreman will use the sudo command to run roles on hosts '\
35
- 'You can override this on hosts by adding a parameter '\
36
- '"ansible_become"'),
37
- true,
38
- N_('Become')
39
- ),
40
- set(
41
- 'ansible_ssh_pass',
42
- N_('Use this password by default when running Ansible '\
43
- 'playbooks. You can override this on hosts '\
44
- 'by adding a parameter "ansible_ssh_pass"'),
45
- 'ansible',
46
- N_('Password')
47
- ),
48
16
  set(
49
17
  'ansible_ssh_private_key_file',
50
18
  N_('Use this to supply a path to an SSH Private Key '\
@@ -100,7 +68,6 @@ class Setting
100
68
  create(s.update(:category => 'Setting::Ansible'))
101
69
  end
102
70
  end
103
- Setting::BLANK_ATTRS.push('ansible_ssh_private_key_file')
104
71
  true
105
72
  end
106
73
  # rubocop:enable AbcSize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'securerandom'
2
4
  module ForemanAnsible
3
5
  # Service to list an inventory to be passed to the ansible-playbook binary
@@ -40,10 +42,16 @@ module ForemanAnsible
40
42
  end
41
43
 
42
44
  def connection_params(host)
43
- params = ansible_settings.merge ansible_extra_options(host)
44
- # Backward compatibility for Ansible 1.x
45
- params['ansible_ssh_port'] = params['ansible_port']
46
- params['ansible_ssh_user'] = params['ansible_user']
45
+ # Preference order is:
46
+ # 1st option: host parameters.
47
+ # - If they're set to 'ansible_whatever' we use that over anything else
48
+ # 2nd option: REX options.
49
+ # - both settings, ssh password, effective_user can be used
50
+ # 3rd option:
51
+ # - other settings
52
+ params = ansible_settings.
53
+ merge(remote_execution_options(host)).
54
+ merge(ansible_extra_options(host))
47
55
  params
48
56
  end
49
57
 
@@ -61,8 +69,7 @@ module ForemanAnsible
61
69
 
62
70
  def ansible_settings
63
71
  Hash[
64
- %w[port user ssh_pass connection
65
- ssh_private_key_file become
72
+ %w[connection ssh_private_key_file
66
73
  winrm_server_cert_validation].map do |setting|
67
74
  ["ansible_#{setting}", Setting["ansible_#{setting}"]]
68
75
  end
@@ -75,10 +82,50 @@ module ForemanAnsible
75
82
  end
76
83
  end
77
84
 
85
+ def remote_execution_options(host)
86
+ params = {
87
+ 'ansible_become' => @template_invocation.effective_user,
88
+ 'ansible_user' => host_setting(host, 'remote_execution_ssh_user'),
89
+ 'ansible_ssh_pass' => rex_ssh_password(host),
90
+ 'ansible_ssh_private_key_file' => ansible_or_rex_ssh_private_key(host),
91
+ 'ansible_port' => host_setting(host, 'remote_execution_ssh_port')
92
+ }
93
+ # Backward compatibility for Ansible 1.x
94
+ params['ansible_ssh_port'] = params['ansible_port']
95
+ params['ansible_ssh_user'] = params['ansible_user']
96
+ params
97
+ end
98
+
99
+ def template_inputs(template_invocation)
100
+ input_values = template_invocation.input_values
101
+ result = input_values.each_with_object({}) do |input, vars_hash|
102
+ vars_hash[input.template_input.name] = input.value
103
+ end
104
+ result
105
+ end
106
+
107
+ def rex_ssh_password(host)
108
+ @template_invocation.job_invocation.password ||
109
+ host_setting(host, 'remote_execution_ssh_password')
110
+ end
111
+
112
+ def ansible_or_rex_ssh_private_key(host)
113
+ ansible_private_file = host_setting(host, 'ansible_ssh_private_key_file')
114
+ if !ansible_private_file.empty?
115
+ ansible_private_file
116
+ else
117
+ ForemanRemoteExecutionCore.settings[:ssh_identity_key_file]
118
+ end
119
+ end
120
+
78
121
  private
79
122
 
80
123
  def render_rabl(host, template)
81
124
  Rabl.render(host, template, :format => 'hash')
82
125
  end
126
+
127
+ def host_setting(host, setting)
128
+ host.params[setting.to_s] || Setting[setting]
129
+ end
83
130
  end
84
131
  end
@@ -1,6 +1,7 @@
1
1
  <% title _("Ansible Roles") %>
2
2
 
3
- <% title_actions ansible_proxy_import(hash_for_import_ansible_roles_path) %>
3
+ <% title_actions ansible_proxy_import(hash_for_import_ansible_roles_path),
4
+ documentation_button('#4.1ImportingRoles', :root_url => ansible_doc_url) %>
4
5
 
5
6
  <table class="<%= table_css_classes 'table-fixed' %>">
6
7
  <thead>
@@ -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.0.2'.freeze
5
+ VERSION = '2.0.3'.freeze
6
6
  end
@@ -1,11 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_plugin_helper'
2
4
 
3
5
  module ForemanAnsible
4
6
  # Test how the inventory creator service transforms host params into
5
7
  # inventory variables and connection options
8
+ # rubocop:disable ClassLength
6
9
  class InventoryCreatorTest < ActiveSupport::TestCase
7
10
  setup do
8
11
  @host = FactoryBot.build(:host)
12
+ @template_invocation = OpenStruct.new(
13
+ :job_invocation => OpenStruct.new(:password => 'foobar'),
14
+ :effective_user => 'foobar'
15
+ )
9
16
  end
10
17
 
11
18
  test 'ansible_ parameters get turned into host variables' do
@@ -16,34 +23,135 @@ module ForemanAnsible
16
23
  'ansible_user' => 'someone'
17
24
  }
18
25
  @host.expects(:host_params).returns(extra_options).at_least_once
19
- inventory = ForemanAnsible::InventoryCreator.new(@host)
26
+ inventory = ForemanAnsible::InventoryCreator.new(@host,
27
+ @template_invocation)
20
28
 
21
29
  assert_empty extra_options.to_a - inventory.connection_params(@host).to_a
22
30
  end
23
31
 
24
32
  test 'settings are respected if param cannot be found' do
25
33
  extra_options = { 'ansible_user' => 'someone', 'ansible_port' => 2000 }
26
- Setting.expects(:[]).with('ansible_become').returns(nil).at_least_once
34
+ Setting.expects(:[]).with('Enable_Smart_Variables_in_ENC').
35
+ returns(nil).at_least_once
27
36
  Setting.expects(:[]).with('ansible_ssh_private_key_file').
28
37
  returns(nil).at_least_once
29
- Setting.expects(:[]).with('ansible_port').returns(nil).at_least_once
30
- Setting.expects(:[]).with('ansible_user').returns(nil).at_least_once
31
- Setting.expects(:[]).with('ansible_ssh_pass').
38
+ Setting.expects(:[]).with('remote_execution_ssh_port').
39
+ returns(2222).at_least_once
40
+ Setting.expects(:[]).with('remote_execution_ssh_user').
41
+ returns('root').at_least_once
42
+ Setting.expects(:[]).with('remote_execution_ssh_password').
32
43
  returns('asafepassword').at_least_once
33
44
  Setting.expects(:[]).with('ansible_winrm_server_cert_validation').
34
45
  returns(true).at_least_once
35
46
  Setting.expects(:[]).with('ansible_connection').
36
47
  returns('ssh').at_least_once
37
48
  @host.expects(:host_params).returns(extra_options).at_least_once
38
- inventory = ForemanAnsible::InventoryCreator.new(@host)
49
+ @template_invocation.job_invocation.expects(:password).
50
+ returns(nil).at_least_once
51
+ inventory = ForemanAnsible::InventoryCreator.new(@host,
52
+ @template_invocation)
39
53
  connection_params = inventory.connection_params(@host)
40
54
  assert_empty extra_options.to_a - inventory.connection_params(@host).to_a
55
+ assert_equal @template_invocation.effective_user,
56
+ connection_params['ansible_become']
41
57
  assert_equal Setting['ansible_connection'],
42
58
  connection_params['ansible_connection']
43
- assert_equal Setting['ansible_ssh_pass'],
59
+ refute_equal Setting['remote_execution_ssh_user'],
60
+ connection_params['ansible_user']
61
+ assert_equal extra_options['ansible_user'],
62
+ connection_params['ansible_user']
63
+ refute_equal Setting['remote_execution_ssh_port'],
64
+ connection_params['ansible_port']
65
+ assert_equal ForemanRemoteExecutionCore.settings[:ssh_identity_key_file],
66
+ connection_params['ansible_ssh_private_key_file']
67
+ assert_equal extra_options['ansible_port'],
68
+ connection_params['ansible_port']
69
+ assert_equal Setting['remote_execution_ssh_password'],
44
70
  connection_params['ansible_ssh_pass']
45
71
  assert_equal Setting['ansible_winrm_server_cert_validation'],
46
72
  connection_params['ansible_winrm_server_cert_validation']
47
73
  end
74
+
75
+ test 'job invocation ssh password is passed when available' do
76
+ inventory = ForemanAnsible::InventoryCreator.new(@host,
77
+ @template_invocation)
78
+ assert_equal(@template_invocation.job_invocation.password,
79
+ inventory.rex_ssh_password(@host))
80
+ end
81
+
82
+ test 'ssh private key is passed when available' do
83
+ host = FactoryBot.build(:host)
84
+ path_to_key = '/path/to/private/key'
85
+ inventory = ForemanAnsible::InventoryCreator.new(host,
86
+ @template_invocation)
87
+ host.params.expects(:[]).with('ansible_ssh_private_key_file')
88
+ .returns(path_to_key)
89
+ host.params.expects(:[]).with('remote_execution_ssh_user')
90
+ .returns('root')
91
+ host.params.expects(:[]).with('remote_execution_ssh_port')
92
+ .returns('2222')
93
+ connection_params = inventory.connection_params(host)
94
+ assert_equal path_to_key,
95
+ connection_params['ansible_ssh_private_key_file']
96
+ end
97
+
98
+ test 'template invocation inputs are sent as Ansible variables' do
99
+ job_template = FactoryBot.build(
100
+ :job_template,
101
+ :template => 'service restart {{service_name}}'
102
+ )
103
+ job_invocation = FactoryBot.create(:job_invocation)
104
+ job_template.template_inputs << FactoryBot.build(:template_input,
105
+ :name => 'service_name',
106
+ :input_type => 'user',
107
+ :required => true)
108
+ template_invocation = FactoryBot.build(:template_invocation,
109
+ :template => job_template,
110
+ :job_invocation => job_invocation)
111
+ job_invocation.expects(:password).returns(nil).at_least_once
112
+ input_value = FactoryBot.create(
113
+ :template_invocation_input_value,
114
+ :template_invocation => template_invocation,
115
+ :template_input => job_template.template_inputs.first,
116
+ :value => 'foreman'
117
+ )
118
+ template_invocation.input_values << input_value
119
+ inventory = ForemanAnsible::InventoryCreator.new([@host],
120
+ template_invocation)
121
+ assert_equal({ 'service_name' => 'foreman' },
122
+ inventory.to_hash['all']['vars'])
123
+ end
124
+
125
+ context 'top-level parameters sent as variables' do
126
+ setup do
127
+ # Fetching the Host parameters requires this Setting, since
128
+ # this plugin does not provide fixtures
129
+ Setting.create(:name => 'top_level_ansible_vars',
130
+ :description => 'sample description',
131
+ :default => true)
132
+ @template_invocation = OpenStruct.new(
133
+ :job_invocation => OpenStruct.new(:password => 'foobar'),
134
+ :input_values => []
135
+ )
136
+ end
137
+
138
+ test 'parameters are passed as top-level "hostvars" by default' do
139
+ @host.expects(:host_params).returns('hello' => 'foreman').at_least_once
140
+ inventory = ForemanAnsible::InventoryCreator.new([@host],
141
+ @template_invocation)
142
+ hostvar = inventory.to_hash['_meta']['hostvars'][@host.name]['hello']
143
+ assert_equal 'foreman', hostvar
144
+ end
145
+
146
+ test 'parameters NOT passed as top-level "hostvars" if false' do
147
+ Setting['top_level_ansible_vars'] = false
148
+ @host.expects(:host_params).returns('hello' => 'foreman').at_least_once
149
+ inventory = ForemanAnsible::InventoryCreator.new([@host],
150
+ @template_invocation)
151
+ hostvar = inventory.to_hash['_meta']['hostvars'][@host.name]['hello']
152
+ refute_equal 'foreman', hostvar
153
+ end
154
+ end
48
155
  end
156
+ # rubocop:enable ClassLength
49
157
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_ansible
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Lobato Garcia