foreman_ansible 3.0.9 → 4.0.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/Rakefile +1 -1
- data/app/controllers/api/v2/ansible_inventories_controller.rb +50 -0
- data/app/models/ansible_variable.rb +1 -0
- data/app/models/foreman_ansible/ansible_provider.rb +25 -1
- data/app/models/foreman_ansible/fact_name.rb +5 -1
- data/app/models/setting/ansible.rb +81 -88
- data/app/services/foreman_ansible/fact_importer.rb +5 -8
- data/app/services/foreman_ansible/fact_parser.rb +16 -4
- data/app/services/foreman_ansible/inventory_creator.rb +1 -12
- data/app/views/foreman_ansible/job_templates/run_playbook-ansible_default.erb +17 -0
- data/config/routes.rb +1 -2
- data/db/migrate/20190328114657_remove_top_level_ansible_variables_setting.rb +1 -1
- data/db/migrate/20191010074208_remove_ansible_implementation_setting.rb +5 -0
- data/db/seeds.d/75_job_templates.rb +2 -2
- data/lib/foreman_ansible/register.rb +5 -2
- data/lib/foreman_ansible/remote_execution.rb +6 -0
- data/lib/foreman_ansible/version.rb +1 -1
- data/locale/Makefile +7 -0
- data/locale/de/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/de/foreman_ansible.po +1 -1
- data/locale/en/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/en/foreman_ansible.po +1 -1
- data/locale/es/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/es/foreman_ansible.po +1 -1
- data/locale/fr/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/fr/foreman_ansible.po +1 -1
- data/locale/it/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/it/foreman_ansible.po +1 -1
- data/locale/ja/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ja/foreman_ansible.po +1 -1
- data/locale/ko/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ko/foreman_ansible.po +1 -1
- data/locale/pt_BR/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/pt_BR/foreman_ansible.po +1 -1
- data/locale/ru/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/ru/foreman_ansible.po +1 -1
- data/locale/zh_CN/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/zh_CN/foreman_ansible.po +1 -1
- data/locale/zh_TW/LC_MESSAGES/foreman_ansible.mo +0 -0
- data/locale/zh_TW/foreman_ansible.po +1 -1
- data/package.json +3 -3
- data/test/unit/ansible_provider_test.rb +16 -0
- data/test/unit/ansible_variable_test.rb +10 -0
- data/test/unit/lib/foreman_ansible_core/ansible_runner_test.rb +51 -0
- data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +34 -1
- data/test/unit/services/fact_importer_test.rb +4 -2
- data/test/unit/services/fact_parser_test.rb +57 -4
- data/test/unit/services/inventory_creator_test.rb +10 -25
- data/webpack/__mocks__/foremanReact/common/I18n.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +1 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.js +18 -23
- data/webpack/index.js +5 -4
- metadata +15 -11
- data/app/lib/actions/foreman_ansible/helpers/host_common.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75b0679707788dc074b4a0393b12f40e04129508
|
4
|
+
data.tar.gz: a94d06214e2975de3fe5db4e34a924f83f083a26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44c06deccb3733c5e29bfbe294a0f5a31bf1005c3e1239397142c410224e06990a505d40a3d06c58686664b75e6aa2b0dfabf83b97fce7706d4afa3aa775e607
|
7
|
+
data.tar.gz: fd568be4b00eafbf89696d4a1468cd0996e5b0c9ecef42ed841982e67ee87bdbe3b3ff1265ebdecd2a402eb0abd4546ebf8ec2a92d5231374ae9dc29e51115f4
|
data/Rakefile
CHANGED
@@ -31,10 +31,52 @@ module Api
|
|
31
31
|
show_inventory :hostgroup_ids, :hostgroup_id
|
32
32
|
end
|
33
33
|
|
34
|
+
api :POST, '/ansible_inventories/schedule',
|
35
|
+
N_('Schedule generating of Ansible Inventory report')
|
36
|
+
param :input_values, Hash, N_('Hash of input values of type input=>value')
|
37
|
+
param :report_format, ReportTemplateFormat.selectable.map(&:id),
|
38
|
+
N_("Report format, defaults to '%s'") % 'json'
|
39
|
+
example <<-EXAMPLE
|
40
|
+
POST /ansible/api/ansible_inventories/schedule
|
41
|
+
{
|
42
|
+
"input_values": {
|
43
|
+
"Organization": "yes",
|
44
|
+
"Location": "yes",
|
45
|
+
"IPv4": "yes",
|
46
|
+
"Facts": "no"
|
47
|
+
}
|
48
|
+
}
|
49
|
+
200
|
50
|
+
{
|
51
|
+
"job_id": UNIQUE-REPORT-GENERATING-JOB-UUID
|
52
|
+
"data_url": "/api/v2/report_templates/1/report_data/UNIQUE-REPORT-GENERATING-JOB-UUID"
|
53
|
+
}
|
54
|
+
EXAMPLE
|
55
|
+
|
56
|
+
def schedule
|
57
|
+
@composer = ReportComposer.from_api_params(schedule_params)
|
58
|
+
if @composer.valid?
|
59
|
+
job = @composer.schedule_rendering
|
60
|
+
response = { :job_id => job.provider_job_id }
|
61
|
+
response[:data_url] = report_data_api_report_template_path(
|
62
|
+
@report_template, :job_id => job.provider_job_id
|
63
|
+
)
|
64
|
+
render :json => response
|
65
|
+
else
|
66
|
+
@ansible_inventory = @composer
|
67
|
+
process_resource_error(:resource => @ansible_inventory)
|
68
|
+
end
|
69
|
+
rescue StandardError => e
|
70
|
+
render_error 'standard_error', :status => :internal_error,
|
71
|
+
:locals => { :exception => e }
|
72
|
+
end
|
73
|
+
|
34
74
|
def action_permission
|
35
75
|
case params[:action]
|
36
76
|
when 'hosts', 'hostgroups'
|
37
77
|
:view
|
78
|
+
when 'schedule'
|
79
|
+
:generate
|
38
80
|
else
|
39
81
|
super
|
40
82
|
end
|
@@ -42,6 +84,14 @@ module Api
|
|
42
84
|
|
43
85
|
private
|
44
86
|
|
87
|
+
def schedule_params
|
88
|
+
template_name = Setting::Ansible.find_by(:name => 'ansible_inventory_template').value
|
89
|
+
@report_template = ReportTemplate.find_by!(:name => template_name)
|
90
|
+
params[:id] = @report_template.id
|
91
|
+
params[:report_format] = 'json' if params[:report_format].blank?
|
92
|
+
params
|
93
|
+
end
|
94
|
+
|
45
95
|
def show_inventory(ids_key, condition_key)
|
46
96
|
ids = params.fetch(ids_key, []).uniq
|
47
97
|
render :json => ForemanAnsible::InventoryCreator.new(Host.where(condition_key => ids)).to_hash.to_json
|
@@ -4,6 +4,7 @@
|
|
4
4
|
class AnsibleVariable < LookupKey
|
5
5
|
belongs_to :ansible_role, :inverse_of => :ansible_variables
|
6
6
|
validates :ansible_role_id, :presence => true
|
7
|
+
before_validation :cast_default_value, :if => :override?
|
7
8
|
validates :key, :uniqueness => { :scope => :ansible_role_id }
|
8
9
|
scoped_search :on => :key, :aliases => [:name], :complete_value => true
|
9
10
|
scoped_search :on => :imported, :complete_value => { :true => true, :false => false }
|
@@ -23,6 +23,7 @@ if defined? ForemanRemoteExecution
|
|
23
23
|
'ansible_inventory' => ::ForemanAnsible::InventoryCreator.new(
|
24
24
|
[host], template_invocation
|
25
25
|
).to_hash.to_json,
|
26
|
+
:verbosity_level => Setting[:ansible_verbosity],
|
26
27
|
:remote_execution_command => ansible_command?(
|
27
28
|
template_invocation.template
|
28
29
|
),
|
@@ -30,12 +31,35 @@ if defined? ForemanRemoteExecution
|
|
30
31
|
)
|
31
32
|
end
|
32
33
|
|
34
|
+
def secrets(host)
|
35
|
+
{
|
36
|
+
'per-host' => {
|
37
|
+
host.name => {
|
38
|
+
'ansible_ssh_pass' => rex_ssh_password(host),
|
39
|
+
'ansible_sudo_pass' => rex_sudo_password(host)
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def rex_ssh_password(host)
|
46
|
+
host_setting(host, 'remote_execution_ssh_password')
|
47
|
+
end
|
48
|
+
|
49
|
+
def rex_sudo_password(host)
|
50
|
+
host_setting(host, 'remote_execution_sudo_password')
|
51
|
+
end
|
52
|
+
|
53
|
+
def host_setting(host, setting)
|
54
|
+
host.params[setting.to_s] || Setting[setting]
|
55
|
+
end
|
56
|
+
|
33
57
|
def supports_effective_user?
|
34
58
|
true
|
35
59
|
end
|
36
60
|
|
37
61
|
def proxy_operation_name
|
38
|
-
|
62
|
+
'ansible-runner'
|
39
63
|
end
|
40
64
|
|
41
65
|
private
|
@@ -5,101 +5,94 @@ class Setting
|
|
5
5
|
class Ansible < ::Setting
|
6
6
|
class << self
|
7
7
|
# It would be more disadvantages than advantages to split up
|
8
|
-
#
|
8
|
+
# default_settings into multiple methods, this way it's already very
|
9
9
|
# manageable.
|
10
10
|
# rubocop:disable AbcSize
|
11
11
|
# rubocop:disable MethodLength
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
'0',
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
'ansible-playbook',
|
88
|
-
N_('Implementation for running Ansible'),
|
89
|
-
nil,
|
90
|
-
:collection => lambda do
|
91
|
-
Hash[%w[ansible-playbook ansible-runner].map { |x| [x, x] }]
|
92
|
-
end
|
93
|
-
)
|
94
|
-
].compact.each do |s|
|
95
|
-
create(s.update(:category => 'Setting::Ansible'))
|
96
|
-
end
|
97
|
-
end
|
98
|
-
true
|
12
|
+
def default_settings
|
13
|
+
[
|
14
|
+
set(
|
15
|
+
'ansible_ssh_private_key_file',
|
16
|
+
N_('Use this to supply a path to an SSH Private Key '\
|
17
|
+
'that Ansible will use in lieu of a password '\
|
18
|
+
'Override with "ansible_ssh_private_key_file" '\
|
19
|
+
'host parameter'),
|
20
|
+
'',
|
21
|
+
N_('Private Key Path')
|
22
|
+
),
|
23
|
+
set(
|
24
|
+
'ansible_connection',
|
25
|
+
N_('Use this connection type by default when running '\
|
26
|
+
'Ansible playbooks. You can override this on hosts by '\
|
27
|
+
'adding a parameter "ansible_connection"'),
|
28
|
+
'ssh',
|
29
|
+
N_('Connection type')
|
30
|
+
),
|
31
|
+
set(
|
32
|
+
'ansible_winrm_server_cert_validation',
|
33
|
+
N_('Enable/disable WinRM server certificate '\
|
34
|
+
'validation when running Ansible playbooks. You can override '\
|
35
|
+
'this on hosts by adding a parameter '\
|
36
|
+
'"ansible_winrm_server_cert_validation"'),
|
37
|
+
'validate',
|
38
|
+
N_('WinRM cert Validation')
|
39
|
+
),
|
40
|
+
set(
|
41
|
+
'ansible_verbosity',
|
42
|
+
N_('Foreman will add this level of verbosity for '\
|
43
|
+
'additional debugging output when running Ansible playbooks.'),
|
44
|
+
'0',
|
45
|
+
N_('Default verbosity level'),
|
46
|
+
nil,
|
47
|
+
:collection => lambda do
|
48
|
+
{ '0' => N_('Disabled'),
|
49
|
+
'1' => N_('Level 1 (-v)'),
|
50
|
+
'2' => N_('Level 2 (-vv)'),
|
51
|
+
'3' => N_('Level 3 (-vvv)'),
|
52
|
+
'4' => N_('Level 4 (-vvvv)') }
|
53
|
+
end
|
54
|
+
),
|
55
|
+
set(
|
56
|
+
'ansible_post_provision_timeout',
|
57
|
+
N_('Timeout (in seconds) to set when Foreman will trigger a '\
|
58
|
+
'play Ansible roles task after a host is fully provisioned. '\
|
59
|
+
'Set this to the maximum time you expect a host to take '\
|
60
|
+
'until it is ready after a reboot.'),
|
61
|
+
'360',
|
62
|
+
N_('Post-provision timeout')
|
63
|
+
),
|
64
|
+
set(
|
65
|
+
'ansible_interval',
|
66
|
+
N_('Timeout (in minutes) when hosts should have reported.'),
|
67
|
+
'30',
|
68
|
+
N_('Ansible report timeout')
|
69
|
+
),
|
70
|
+
set(
|
71
|
+
'ansible_out_of_sync_disabled',
|
72
|
+
format(N_('Disable host configuration status turning to out of'\
|
73
|
+
' sync for %{cfgmgmt} after report does not arrive within'\
|
74
|
+
' configured interval'), :cfgmgmt => 'Ansible'),
|
75
|
+
false,
|
76
|
+
format(N_('%{cfgmgmt} out of sync disabled'),
|
77
|
+
:cfgmgmt => 'Ansible')
|
78
|
+
),
|
79
|
+
set(
|
80
|
+
'ansible_inventory_template',
|
81
|
+
N_('Foreman will use this template to schedule the report '\
|
82
|
+
'with Ansible inventory'),
|
83
|
+
'Ansible Inventory',
|
84
|
+
N_('Default Ansible inventory report template')
|
85
|
+
)
|
86
|
+
]
|
99
87
|
end
|
100
88
|
# rubocop:enable AbcSize
|
101
89
|
# rubocop:enable MethodLength
|
102
90
|
|
91
|
+
def load_defaults
|
92
|
+
Setting::BLANK_ATTRS.push('ansible_ssh_private_key_file')
|
93
|
+
super
|
94
|
+
end
|
95
|
+
|
103
96
|
def humanized_category
|
104
97
|
N_('Ansible')
|
105
98
|
end
|
@@ -55,16 +55,13 @@ module ForemanAnsible
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def missing_facts
|
58
|
-
db_fact_names = if db_facts.is_a? Hash
|
59
|
-
db_facts.keys
|
60
|
-
else
|
61
|
-
db_facts
|
62
|
-
end
|
63
|
-
# In Foreman versions prior to 1.14, the db_facts key
|
64
|
-
# used to be a hash. Now it's an ActiveRecord::AssociationRelation
|
65
58
|
@missing_facts ||= facts.keys +
|
66
59
|
FactSparser.sparse(@original_facts).keys -
|
67
|
-
|
60
|
+
host_fact_names
|
61
|
+
end
|
62
|
+
|
63
|
+
def host_fact_names
|
64
|
+
host.fact_names.where(:type => fact_name_class.to_s).pluck(:name)
|
68
65
|
end
|
69
66
|
|
70
67
|
# Returns pairs [id, fact_name]
|
@@ -51,19 +51,27 @@ module ForemanAnsible
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def get_facts_for_interface(
|
55
|
-
interface.tr
|
54
|
+
def get_facts_for_interface(iface_name)
|
55
|
+
interface = iface_name.tr('-', '_') # virbr1-nic -> virbr1_nic
|
56
56
|
interface_facts = facts[:"ansible_#{interface}"]
|
57
57
|
ipaddress = ip_from_interface(interface)
|
58
58
|
ipaddress6 = ipv6_from_interface(interface)
|
59
|
-
|
59
|
+
macaddress = mac_from_interface(interface)
|
60
|
+
iface_facts = HashWithIndifferentAccess[
|
60
61
|
interface_facts.merge(:ipaddress => ipaddress,
|
61
|
-
:ipaddress6 => ipaddress6
|
62
|
+
:ipaddress6 => ipaddress6,
|
63
|
+
:macaddress => macaddress)
|
62
64
|
]
|
65
|
+
logger.debug { "Ansible interface #{interface} facts: #{iface_facts.inspect}" }
|
66
|
+
iface_facts
|
63
67
|
end
|
64
68
|
|
65
69
|
def ipmi_interface; end
|
66
70
|
|
71
|
+
def boot_timestamp
|
72
|
+
Time.zone.now.to_i - facts['ansible_uptime_seconds'].to_i
|
73
|
+
end
|
74
|
+
|
67
75
|
private
|
68
76
|
|
69
77
|
def ansible_interfaces
|
@@ -71,6 +79,10 @@ module ForemanAnsible
|
|
71
79
|
facts[:ansible_interfaces].sort
|
72
80
|
end
|
73
81
|
|
82
|
+
def mac_from_interface(interface)
|
83
|
+
facts[:"ansible_#{interface}"]['perm_macaddress'].presence || facts[:"ansible_#{interface}"]['macaddress']
|
84
|
+
end
|
85
|
+
|
74
86
|
def ip_from_interface(interface)
|
75
87
|
return if facts[:"ansible_#{interface}"]['ipv4'].blank?
|
76
88
|
facts[:"ansible_#{interface}"]['ipv4']['address']
|
@@ -98,8 +98,7 @@ module ForemanAnsible
|
|
98
98
|
def remote_execution_options(host)
|
99
99
|
params = {
|
100
100
|
'ansible_user' => host_setting(host, 'remote_execution_ssh_user'),
|
101
|
-
'
|
102
|
-
'ansible_sudo_pass' => rex_sudo_password(host),
|
101
|
+
'ansible_become_method' => host_setting(host, 'remote_execution_effective_user_method'),
|
103
102
|
'ansible_ssh_private_key_file' => ansible_or_rex_ssh_private_key(host),
|
104
103
|
'ansible_port' => host_setting(host, 'remote_execution_ssh_port'),
|
105
104
|
'ansible_host' => AnsibleProvider.find_ip_or_hostname(host)
|
@@ -123,16 +122,6 @@ module ForemanAnsible
|
|
123
122
|
result
|
124
123
|
end
|
125
124
|
|
126
|
-
def rex_ssh_password(host)
|
127
|
-
@template_invocation.job_invocation.password ||
|
128
|
-
host_setting(host, 'remote_execution_ssh_password')
|
129
|
-
end
|
130
|
-
|
131
|
-
def rex_sudo_password(host)
|
132
|
-
@template_invocation.job_invocation.sudo_password ||
|
133
|
-
host_setting(host, 'remote_execution_sudo_password')
|
134
|
-
end
|
135
|
-
|
136
125
|
def ansible_or_rex_ssh_private_key(host)
|
137
126
|
ansible_private_file = host_setting(host, 'ansible_ssh_private_key_file')
|
138
127
|
if !ansible_private_file.empty?
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%#
|
2
|
+
name: Ansible - Run playbook
|
3
|
+
snippet: false
|
4
|
+
job_category: Ansible Playbook
|
5
|
+
provider_type: Ansible
|
6
|
+
kind: job_template
|
7
|
+
feature: ansible_run_playbook
|
8
|
+
template_inputs:
|
9
|
+
- name: playbook
|
10
|
+
required: true
|
11
|
+
input_type: user
|
12
|
+
description: The playbook to run against given hosts
|
13
|
+
advanced: false
|
14
|
+
value_type: plain
|
15
|
+
%>
|
16
|
+
|
17
|
+
<%= input('playbook') %>
|