foreman_ansible 2.0.2 → 2.0.3

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
  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