foreman_ansible 6.3.4 → 6.4.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/app/helpers/foreman_ansible/ansible_reports_helper.rb +35 -54
- data/app/helpers/foreman_ansible/ansible_roles_data_preparations.rb +22 -22
- data/app/models/concerns/foreman_ansible/hostgroup_extensions.rb +1 -1
- data/app/models/foreman_ansible/ansible_provider.rb +54 -2
- data/app/views/foreman_ansible/config_reports/_ansible.html.erb +14 -5
- data/app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb +4 -0
- data/app/views/foreman_ansible/job_templates/convert_to_rhel.erb +1 -1
- data/lib/foreman_ansible/engine.rb +0 -1
- data/lib/foreman_ansible/register.rb +4 -3
- data/lib/foreman_ansible/version.rb +1 -1
- data/package.json +7 -5
- data/test/unit/ansible_provider_test.rb +6 -3
- data/test/unit/helpers/ansible_reports_helper_test.rb +4 -30
- data/test/unit/hostgroup_ansible_role_test.rb +0 -13
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.js +35 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss +6 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.test.js +14 -0
- data/webpack/components/AnsibleHostDetail/index.js +6 -0
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsiblePermissionDenied.test.js.snap +2 -0
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap +4 -4
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +5 -0
- data/webpack/global_index.js +12 -0
- metadata +14 -35
- data/test/unit/lib/foreman_ansible_core/ansible_runner_test.rb +0 -51
- data/test/unit/lib/foreman_ansible_core/command_creator_test.rb +0 -64
- data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +0 -110
- data/webpack/__mocks__/foremanReact/common/I18n.js +0 -1
- data/webpack/__mocks__/foremanReact/common/helpers.js +0 -13
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -2
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +0 -5
- data/webpack/__mocks__/foremanReact/components/common/forms/OrderableSelect/helpers.js +0 -5
- data/webpack/__mocks__/foremanReact/redux/API.js +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05c975cb77fe5add41b7281dfa1c2451bb22a09ab5dc6251ab06fd4d00b834e2
|
4
|
+
data.tar.gz: 86613f4be767b5af80a06f83b9e13f8f030cd80bc362d866323111b61a0b23a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc27695cef374e8b709ddc3c3882056587cbf975ac7d497c1fec5aaa1885f85bcb3677c2c7fd3f2602f529cba0a6736017703f6d7ca413eb5f2ed7a6de112a94
|
7
|
+
data.tar.gz: ba0c5f9b94a51b7328cc0df73bfcc0f47831b1004b275be935fa73a83ae9c6f12b81086071ebe69292c8aa5ad436c5389a6a6f1ac457720bcefe034b456c0ec8
|
@@ -4,21 +4,19 @@ module ForemanAnsible
|
|
4
4
|
# This module takes the config reports stored in Foreman for Ansible and
|
5
5
|
# modifies them to be properly presented in views
|
6
6
|
module AnsibleReportsHelper
|
7
|
-
ANSIBLE_META_KEYS = %w[
|
8
|
-
_ansible_parsed _ansible_no_log _ansible_item_result
|
9
|
-
_ansible_ignore_errors _ansible_verbose_always _ansible_verbose_override
|
10
|
-
].freeze
|
11
|
-
ANSIBLE_HIDDEN_KEYS = %w[
|
12
|
-
invocation module_args results ansible_facts
|
13
|
-
stdout stderr
|
14
|
-
].freeze
|
15
|
-
|
16
7
|
def ansible_module_name(log)
|
17
8
|
source_value = log.source&.value
|
18
9
|
name = source_value.split(':')[0].strip if source_value&.include?(':')
|
19
10
|
name
|
20
11
|
end
|
21
12
|
|
13
|
+
def ansible_task_name(log)
|
14
|
+
source_value = log.source&.value
|
15
|
+
return source_value || no_data_message unless source_value.include? ':'
|
16
|
+
name = source_value.split(':')[1].strip if source_value.include?(':')
|
17
|
+
name || no_data_message
|
18
|
+
end
|
19
|
+
|
22
20
|
def ansible_run_in_check_mode?(log)
|
23
21
|
log.message&.value == 'check_mode_enabled' if check_mode_log?(log)
|
24
22
|
end
|
@@ -27,12 +25,36 @@ module ForemanAnsible
|
|
27
25
|
log.source&.value == 'check_mode'
|
28
26
|
end
|
29
27
|
|
30
|
-
def
|
31
|
-
|
28
|
+
def ansible_module_message(log)
|
29
|
+
msg_json = parsed_message_json(log)
|
30
|
+
module_action = msg_json['module']
|
31
|
+
case module_action
|
32
|
+
when 'package'
|
33
|
+
msg_json['results'].empty? ? msg_json['msg'] : msg_json['results']
|
34
|
+
when 'template'
|
35
|
+
module_args = msg_json['invocation']['module_args']
|
36
|
+
_("Rendered template #{module_args['_original_basename']} to #{msg_json['dest']}")
|
37
|
+
when 'service'
|
38
|
+
_("Service #{msg_json['name']} #{msg_json['state']} (enabled: #{msg_json['enabled']})")
|
39
|
+
when 'group'
|
40
|
+
_("User group #{msg_json['name']} #{msg_json['state']}, gid: #{msg_json['gid']}")
|
41
|
+
when 'user'
|
42
|
+
_("User #{msg_json['name']} #{msg_json['state']}, uid: #{msg_json['uid']}")
|
43
|
+
when 'cron'
|
44
|
+
module_args = msg_json['invocation']['module_args']
|
45
|
+
_("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
|
46
|
+
when 'copy'
|
47
|
+
module_args = msg_json['invocation']['module_args']
|
48
|
+
_("Copy #{module_args['_original_basename']} to #{msg_json['dest']}")
|
49
|
+
when 'command', 'shell'
|
50
|
+
msg_json['stdout_lines']
|
51
|
+
else
|
52
|
+
no_data_message
|
53
|
+
end
|
32
54
|
end
|
33
55
|
|
34
|
-
def
|
35
|
-
|
56
|
+
def no_data_message
|
57
|
+
_('No additional data')
|
36
58
|
end
|
37
59
|
|
38
60
|
def ansible_report_origin_icon
|
@@ -49,49 +71,8 @@ module ForemanAnsible
|
|
49
71
|
false
|
50
72
|
end
|
51
73
|
|
52
|
-
def report_json_viewer(json)
|
53
|
-
react_component('ReportJsonViewer', data: json)
|
54
|
-
end
|
55
|
-
|
56
74
|
private
|
57
75
|
|
58
|
-
def module_invocations(hash)
|
59
|
-
invocations = []
|
60
|
-
invocations << hash.delete('invocation')
|
61
|
-
results = hash.delete('results')
|
62
|
-
invocations << results
|
63
|
-
invocations = invocations.compact.flatten.map do |ih|
|
64
|
-
ih.is_a?(Hash) ? remove_keys(ih) : ih
|
65
|
-
end
|
66
|
-
invocations
|
67
|
-
end
|
68
|
-
|
69
|
-
def pretty_print_hash(hash)
|
70
|
-
prettyp = JSON.pretty_generate(remove_keys(hash))
|
71
|
-
prettyp.gsub!(/{\n*/, "\n")
|
72
|
-
prettyp.gsub!(/},*\n*/, "\n")
|
73
|
-
prettyp.gsub!(/^(\[|\])/, '')
|
74
|
-
prettyp.gsub!(/^[\s]*$\n/, '')
|
75
|
-
paragraph_style = 'white-space:pre;padding: 2em 0'
|
76
|
-
tag(:p, prettyp, :style => paragraph_style)
|
77
|
-
end
|
78
|
-
|
79
|
-
def hash_with_keys_removed(hash)
|
80
|
-
new_hash = remove_keys(hash)
|
81
|
-
remove_keys(new_hash, ANSIBLE_HIDDEN_KEYS)
|
82
|
-
end
|
83
|
-
|
84
|
-
def remove_keys(hash, keys = ANSIBLE_META_KEYS)
|
85
|
-
hash.each do |key, value|
|
86
|
-
if value.is_a? Array
|
87
|
-
value.each { |h| remove_keys(h) if h.is_a? Hash }
|
88
|
-
elsif value.is_a? Hash
|
89
|
-
remove_keys(value)
|
90
|
-
end
|
91
|
-
hash.delete(key) if keys.include? key
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
76
|
def parsed_message_json(log)
|
96
77
|
JSON.parse(log.message.value)
|
97
78
|
rescue StandardError => e
|
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
module ForemanAnsible
|
4
4
|
module AnsibleRolesDataPreparations
|
5
|
-
VARIABLE_ACTION_NAMES = { 'new' =>
|
6
|
-
ROLE_ACTION_NAMES = { 'new' =>
|
5
|
+
VARIABLE_ACTION_NAMES = { 'new' => N_('Add'), 'obsolete' => N_('Remove'), 'update' => N_('Update') }.freeze
|
6
|
+
ROLE_ACTION_NAMES = { 'new' => N_('Import Role'), 'obsolete' => N_('Remove Role'), 'old' => N_('Update Role Variables') }.freeze
|
7
7
|
|
8
|
-
def
|
9
|
-
VARIABLE_ACTION_NAMES[kind]
|
8
|
+
def get_variable_action(kind)
|
9
|
+
_(VARIABLE_ACTION_NAMES[kind])
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
ROLE_ACTION_NAMES[kind]
|
12
|
+
def get_role_action(kind)
|
13
|
+
_(ROLE_ACTION_NAMES[kind])
|
14
14
|
end
|
15
15
|
|
16
16
|
def get_old_roles_variables(imported_variables, role)
|
17
|
-
variables = { '
|
17
|
+
variables = { 'Add' => [], 'Remove' => [], 'Update' => [] }
|
18
18
|
imported_variables.each do |kind, temp_variables|
|
19
19
|
temp_variables.each do |temp_variable|
|
20
|
-
variables[kind].append(temp_variable.key) if temp_variable.ansible_role_id == role.id
|
20
|
+
variables[get_variable_action(kind)].append(temp_variable.key) if temp_variable.ansible_role_id == role.id
|
21
21
|
end
|
22
22
|
end
|
23
23
|
variables
|
@@ -26,16 +26,16 @@ module ForemanAnsible
|
|
26
26
|
def variables_to_s(variables)
|
27
27
|
str = ''
|
28
28
|
variables.each do |action, temp_variables|
|
29
|
-
str += "#{
|
29
|
+
str += "#{action}: #{temp_variables.size}, " unless temp_variables.empty?
|
30
30
|
end
|
31
31
|
str[0..-3]
|
32
32
|
end
|
33
33
|
|
34
34
|
def get_roles_variables(imported_variables, variables_importer, kind, role)
|
35
35
|
if kind == 'new'
|
36
|
-
variables = { '
|
36
|
+
variables = { 'Add' => variables_importer.get_variables_names(role.name) }
|
37
37
|
elsif kind == 'obsolete'
|
38
|
-
variables = { '
|
38
|
+
variables = { 'Remove' => role.ansible_variables.map(&:key) }
|
39
39
|
elsif kind == 'old'
|
40
40
|
variables = get_old_roles_variables(imported_variables, role)
|
41
41
|
end
|
@@ -51,25 +51,24 @@ module ForemanAnsible
|
|
51
51
|
match.to_s.empty? ? nil : match
|
52
52
|
end
|
53
53
|
|
54
|
-
def prepare_api_row(role, kind, variables)
|
54
|
+
def prepare_api_row(role, kind, variables, role_action)
|
55
55
|
{
|
56
56
|
name: role.name,
|
57
57
|
id: role.id,
|
58
|
-
role_action:
|
58
|
+
role_action: role_action,
|
59
59
|
variables: variables,
|
60
|
-
hosts_count:
|
61
|
-
hostgroup_count:
|
60
|
+
hosts_count: role_action == 'Remove Role' ? role.hosts.count : '',
|
61
|
+
hostgroup_count: role_action == 'Remove Role' ? role.hostgroups.count : '',
|
62
62
|
kind: kind
|
63
63
|
}
|
64
64
|
end
|
65
65
|
|
66
|
-
def prepare_ui_row(role, kind, variables)
|
66
|
+
def prepare_ui_row(role, kind, variables, role_action)
|
67
67
|
{ cells: [
|
68
68
|
role.name,
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
kind == 'obsolete' ? role.hostgroups.count : ''
|
69
|
+
role_action, variables,
|
70
|
+
role_action == 'Remove Role' ? role.hosts.count : '',
|
71
|
+
role_action == 'Remove Role' ? role.hostgroups.count : ''
|
73
72
|
],
|
74
73
|
role: role, kind: kind, id: role.name }
|
75
74
|
end
|
@@ -82,10 +81,11 @@ module ForemanAnsible
|
|
82
81
|
next if role_match_excluded_roles(role.name)
|
83
82
|
variables = get_roles_variables(imported_variables, variables_importer, kind, role)
|
84
83
|
next if variables.empty? && kind['old']
|
84
|
+
role_action = get_role_action(kind)
|
85
85
|
if is_ui
|
86
|
-
rows.append(prepare_ui_row(role, kind, variables))
|
86
|
+
rows.append(prepare_ui_row(role, kind, variables, role_action))
|
87
87
|
else
|
88
|
-
rows.append(prepare_api_row(role, kind, variables))
|
88
|
+
rows.append(prepare_api_row(role, kind, variables, role_action))
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
@@ -6,7 +6,7 @@ module ForemanAnsible
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
has_many :hostgroup_ansible_roles,
|
9
|
+
has_many :hostgroup_ansible_roles, :foreign_key => :hostgroup_id
|
10
10
|
has_many :ansible_roles,
|
11
11
|
-> { order('hostgroup_ansible_roles.position ASC') },
|
12
12
|
:through => :hostgroup_ansible_roles,
|
@@ -18,6 +18,10 @@ if defined? ForemanRemoteExecution
|
|
18
18
|
'Ansible'
|
19
19
|
end
|
20
20
|
|
21
|
+
def provider_input_namespace
|
22
|
+
:ansible
|
23
|
+
end
|
24
|
+
|
21
25
|
def proxy_command_options(template_invocation, host)
|
22
26
|
super(template_invocation, host).merge(
|
23
27
|
'ansible_inventory' => ::ForemanAnsible::InventoryCreator.new(
|
@@ -34,7 +38,6 @@ if defined? ForemanRemoteExecution
|
|
34
38
|
|
35
39
|
def secrets(host)
|
36
40
|
{
|
37
|
-
:key_passphrase => Setting[:remote_execution_ssh_key_passphrase],
|
38
41
|
'per-host' => {
|
39
42
|
host.name => {
|
40
43
|
'ansible_password' => rex_ssh_password(host),
|
@@ -52,16 +55,65 @@ if defined? ForemanRemoteExecution
|
|
52
55
|
host_setting(host, 'remote_execution_effective_user_password')
|
53
56
|
end
|
54
57
|
|
58
|
+
def host_setting(host, setting)
|
59
|
+
host.params[setting.to_s] || Setting[setting]
|
60
|
+
end
|
61
|
+
|
55
62
|
def supports_effective_user?
|
56
63
|
true
|
57
64
|
end
|
58
65
|
|
66
|
+
def provider_inputs
|
67
|
+
[
|
68
|
+
ForemanRemoteExecution::ProviderInput.new(
|
69
|
+
name: 'tags',
|
70
|
+
label: _('Tags'),
|
71
|
+
value: '',
|
72
|
+
value_type: 'plain',
|
73
|
+
description: 'Tags used for Ansible execution'
|
74
|
+
),
|
75
|
+
ForemanRemoteExecution::ProviderInput.new(
|
76
|
+
name: 'tags_flag',
|
77
|
+
label: _('Include/Exclude Tags'),
|
78
|
+
value: 'include',
|
79
|
+
description: 'Option whether to include or exclude tags',
|
80
|
+
options: "include\nexclude"
|
81
|
+
)
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
85
|
+
def provider_inputs_doc
|
86
|
+
opts = provider_inputs.find { |input| input.name == 'tags_flag' }.options.split("\n")
|
87
|
+
{
|
88
|
+
:namespace => provider_input_namespace,
|
89
|
+
:opts => { :desc => N_('Ansible provider specific inputs') },
|
90
|
+
:children => [
|
91
|
+
{
|
92
|
+
:name => :tags,
|
93
|
+
:type => Array,
|
94
|
+
:opts => { :required => false, :desc => N_('A comma separated list of tags to use for Ansible run') }
|
95
|
+
},
|
96
|
+
{
|
97
|
+
:name => :tags_flag,
|
98
|
+
:type => opts,
|
99
|
+
:opts => { :required => false, :desc => N_('Include\Exclude tags for Ansible run') }
|
100
|
+
}
|
101
|
+
]
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def proxy_command_provider_inputs(template_invocation)
|
106
|
+
tags = template_invocation.provider_input_values.find_by(:name => 'tags')&.value || ''
|
107
|
+
tags_flag = template_invocation.provider_input_values.find_by(:name => 'tags_flag')&.value || ''
|
108
|
+
{ :tags => tags, :tags_flag => tags_flag }
|
109
|
+
end
|
110
|
+
|
59
111
|
def proxy_operation_name
|
60
112
|
'ansible-runner'
|
61
113
|
end
|
62
114
|
|
63
115
|
def proxy_action_class
|
64
|
-
'
|
116
|
+
'Proxy::Ansible::TaskLauncher::Playbook::PlaybookRunnerAction'
|
65
117
|
end
|
66
118
|
|
67
119
|
private
|
@@ -10,8 +10,7 @@
|
|
10
10
|
<thead>
|
11
11
|
<tr>
|
12
12
|
<th><%= _("Level") %></th>
|
13
|
-
<th><%= _("
|
14
|
-
<th><%= _("Arguments") %></th>
|
13
|
+
<th><%= _("Task") %></th>
|
15
14
|
<th><%= _("Message") %></th>
|
16
15
|
</tr>
|
17
16
|
</thead>
|
@@ -20,9 +19,19 @@
|
|
20
19
|
<% unless check_mode_log?(log) %>
|
21
20
|
<tr>
|
22
21
|
<td><span <%= report_tag log.level %>><%= h log.level %></span></td>
|
23
|
-
<td
|
24
|
-
<td
|
25
|
-
|
22
|
+
<td><span title=<%= ansible_module_name(log) %>><%= ansible_task_name(log) %></span></td>
|
23
|
+
<td>
|
24
|
+
<% log_message = ansible_module_message(log) %>
|
25
|
+
<% if log_message.is_a? Array %>
|
26
|
+
<ul>
|
27
|
+
<% log_message.each do |message_line| %>
|
28
|
+
<li><%= message_line %></li>
|
29
|
+
<% end %>
|
30
|
+
</ul>
|
31
|
+
<% else %>
|
32
|
+
<%= log_message %>
|
33
|
+
<% end %>
|
34
|
+
</td>
|
26
35
|
</tr>
|
27
36
|
<% end %>
|
28
37
|
<% end %>
|
@@ -15,10 +15,14 @@ model: JobTemplate
|
|
15
15
|
- name: Display all parameters known for the Foreman host
|
16
16
|
debug:
|
17
17
|
var: foreman
|
18
|
+
tags:
|
19
|
+
- always
|
18
20
|
tasks:
|
19
21
|
- name: Apply roles
|
20
22
|
include_role:
|
21
23
|
name: "{{ role }}"
|
24
|
+
tags:
|
25
|
+
- always
|
22
26
|
loop: "{{ foreman_ansible_roles }}"
|
23
27
|
loop_control:
|
24
28
|
loop_var: role
|
@@ -34,7 +34,7 @@ kind: job_template
|
|
34
34
|
url: <%= subscription_manager_configuration_url(@host) %>
|
35
35
|
dest: /usr/share/convert2rhel/subscription-manager/katello-ca-consumer-latest.noarch.rpm
|
36
36
|
- name: Start convert2rhel
|
37
|
-
command: convert2rhel -y --activationkey "<%= input('Activation Key') %>" --org "<%= @host.organization.label %>"
|
37
|
+
command: convert2rhel -y --activationkey "<%= input('Activation Key') %>" --org "<%= @host.organization.label %>" > /root/convert2rhel.log
|
38
38
|
<%- if input('Restart') == "yes" -%>
|
39
39
|
- name: Reboot the machine
|
40
40
|
reboot:
|
@@ -76,10 +76,9 @@ Foreman::Plugin.register :foreman_ansible do
|
|
76
76
|
|
77
77
|
role 'Ansible Roles Manager',
|
78
78
|
[:play_roles_on_host, :play_roles_on_hostgroup,
|
79
|
-
:create_job_invocations, :view_job_templates, # to allow the play_roles
|
80
|
-
:create_template_invocations, :view_smart_proxies, # ...
|
81
79
|
:view_ansible_roles, :destroy_ansible_roles,
|
82
|
-
:import_ansible_roles,
|
80
|
+
:import_ansible_roles,
|
81
|
+
:view_ansible_variables,
|
83
82
|
:create_ansible_variables, :import_ansible_variables,
|
84
83
|
:edit_ansible_variables, :destroy_ansible_variables]
|
85
84
|
|
@@ -97,6 +96,8 @@ Foreman::Plugin.register :foreman_ansible do
|
|
97
96
|
parameter_filter Host::Managed, base_role_assignment_params.merge(:host_ansible_roles_attributes => {})
|
98
97
|
parameter_filter Hostgroup, base_role_assignment_params.merge(:hostgroup_ansible_roles_attributes => {})
|
99
98
|
|
99
|
+
register_global_js_file 'global'
|
100
|
+
|
100
101
|
divider :top_menu, :caption => N_('Ansible'), :parent => :configure_menu
|
101
102
|
menu :top_menu, :ansible_roles,
|
102
103
|
:caption => N_('Roles'),
|
data/package.json
CHANGED
@@ -14,16 +14,18 @@
|
|
14
14
|
},
|
15
15
|
"devDependencies": {
|
16
16
|
"@babel/core": "^7.7.0",
|
17
|
-
"@theforeman/builder": "^
|
18
|
-
"@theforeman/eslint-plugin-foreman": "
|
19
|
-
"@theforeman/
|
20
|
-
"@theforeman/
|
17
|
+
"@theforeman/builder": "^8.4.1",
|
18
|
+
"@theforeman/eslint-plugin-foreman": "^8.4.1",
|
19
|
+
"@theforeman/find-foreman": "^8.4.1",
|
20
|
+
"@theforeman/stories": "^8.4.1",
|
21
|
+
"@theforeman/test": "^8.4.1",
|
22
|
+
"@theforeman/vendor-dev": "^8.4.1",
|
21
23
|
"babel-eslint": "^10.0.3",
|
22
24
|
"eslint": "^6.7.2",
|
23
25
|
"prettier": "^1.13.5"
|
24
26
|
},
|
25
27
|
"scripts": {
|
26
|
-
"test": "tfm-test --plugin",
|
28
|
+
"test": "tfm-test --plugin --config jest.config.js",
|
27
29
|
"lint": "tfm-lint --plugin -d webpack"
|
28
30
|
},
|
29
31
|
"repository": {
|
@@ -30,11 +30,14 @@ class AnsibleProviderTest < ActiveSupport::TestCase
|
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'when using secrets' do
|
33
|
-
let(:host) { FactoryBot.
|
33
|
+
let(:host) { FactoryBot.build(:host) }
|
34
34
|
|
35
35
|
it 'generates secrets properly' do
|
36
|
-
|
37
|
-
|
36
|
+
params = {
|
37
|
+
'remote_execution_ssh_password' => 'password',
|
38
|
+
'remote_execution_effective_user_password' => 'letmein'
|
39
|
+
}
|
40
|
+
host.expects(:params).twice.returns(params)
|
38
41
|
secrets = ForemanAnsible::AnsibleProvider.secrets(host)
|
39
42
|
host_secrets = secrets['per-host'][host.name]
|
40
43
|
assert_equal host_secrets['ansible_password'], 'password'
|
@@ -6,43 +6,17 @@ class AnsibleReportsHelperTest < ActiveSupport::TestCase
|
|
6
6
|
include ForemanAnsible::AnsibleReportsHelper
|
7
7
|
include ActionView::Helpers::TagHelper
|
8
8
|
|
9
|
-
test '
|
9
|
+
test 'module message extraction' do
|
10
10
|
log_value = <<-ANSIBLELOG.strip_heredoc
|
11
|
-
|
11
|
+
{"msg": "Nothing to do", "changed": false, "results": [], "rc": 0, "invocation": {"module_args": {"name": ["openssh"], "state": "present", "allow_downgrade": false, "autoremove": false, "bugfix": false, "disable_gpg_check": false, "disable_plugin": [], "disablerepo": [], "download_only": false, "enable_plugin": [], "enablerepo": [], "exclude": [], "installroot": "/", "install_repoquery": true, "install_weak_deps": true, "security": false, "skip_broken": false, "update_cache": false, "update_only": false, "validate_certs": true, "lock_timeout": 30, "conf_file": null, "disable_excludes": null, "download_dir": null, "list": null, "releasever": null}}, "_ansible_no_log": false, "failed": false, "module": "package"}
|
12
12
|
ANSIBLELOG
|
13
13
|
message = FactoryBot.build(:message)
|
14
14
|
message.value = log_value
|
15
15
|
log = FactoryBot.build(:log)
|
16
16
|
log.message = message
|
17
17
|
assert_match(
|
18
|
-
/
|
19
|
-
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
|
-
test 'pretty print is able to print a hash' do
|
24
|
-
hash = {
|
25
|
-
'allow_downgrade' => false,
|
26
|
-
'name' => ['ntp'],
|
27
|
-
'list' => nil,
|
28
|
-
'disable_gpg_check' => false,
|
29
|
-
'conf_file' => nil,
|
30
|
-
'install_repoquery' => true,
|
31
|
-
'state' => 'installed',
|
32
|
-
'disablerepo' => nil,
|
33
|
-
'update_cache' => false,
|
34
|
-
'enablerepo' => nil,
|
35
|
-
'exclude' => nil,
|
36
|
-
'security' => false,
|
37
|
-
'validate_certs' => true,
|
38
|
-
'installroot' => '/',
|
39
|
-
'skip_broken' => false
|
40
|
-
}
|
41
|
-
assert_equal(
|
42
|
-
hash,
|
43
|
-
remove_keys(
|
44
|
-
hash
|
45
|
-
)
|
18
|
+
/Nothing to do/,
|
19
|
+
ansible_module_message(log).to_s
|
46
20
|
)
|
47
21
|
end
|
48
22
|
end
|
@@ -19,17 +19,4 @@ class HostgroupAnsibleRoleTest < ActiveSupport::TestCase
|
|
19
19
|
end
|
20
20
|
should validate_uniqueness_of(:ansible_role_id).scoped_to(:hostgroup_id)
|
21
21
|
end
|
22
|
-
|
23
|
-
describe 'ordering' do
|
24
|
-
test 'should list roles in correct order' do
|
25
|
-
hg = FactoryBot.create(:hostgroup)
|
26
|
-
5.times do |idx|
|
27
|
-
HostgroupAnsibleRole.create(:hostgroup => hg, :ansible_role => FactoryBot.create(:ansible_role), :position => idx)
|
28
|
-
end
|
29
|
-
|
30
|
-
hg.hostgroup_ansible_roles.each_with_index do |item, idx|
|
31
|
-
assert_equal(item.position, idx + 1)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
22
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { Tabs, Tab, TabTitleText, Label } from '@patternfly/react-core';
|
3
|
+
import { InfoCircleIcon } from '@patternfly/react-icons';
|
4
|
+
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
|
7
|
+
import './AnsibleHostDetail.scss';
|
8
|
+
|
9
|
+
const AnsibleHostDetail = props => {
|
10
|
+
// https://projects.theforeman.org/issues/32398
|
11
|
+
const [activeTab] = useState('variables');
|
12
|
+
|
13
|
+
return (
|
14
|
+
<Tabs activeKey={activeTab} isSecondary>
|
15
|
+
<Tab
|
16
|
+
eventKey="variables"
|
17
|
+
title={<TabTitleText>{__('Variables')}</TabTitleText>}
|
18
|
+
>
|
19
|
+
<div className="host-details-tab-item">
|
20
|
+
<div className="ansible-host-detail">
|
21
|
+
<Label
|
22
|
+
color="blue"
|
23
|
+
icon={<InfoCircleIcon />}
|
24
|
+
style={{ marginTop: '1.5rem' }}
|
25
|
+
>
|
26
|
+
Ansible Variables coming soon!
|
27
|
+
</Label>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</Tab>
|
31
|
+
</Tabs>
|
32
|
+
);
|
33
|
+
};
|
34
|
+
|
35
|
+
export default AnsibleHostDetail;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { render, screen } from '@testing-library/react';
|
3
|
+
import '@testing-library/jest-dom';
|
4
|
+
|
5
|
+
import AnsibleHostDetail from './';
|
6
|
+
|
7
|
+
describe('AnsibleHostDetail', () => {
|
8
|
+
it('should show content', () => {
|
9
|
+
render(<AnsibleHostDetail />);
|
10
|
+
expect(
|
11
|
+
screen.getByText('Ansible Variables coming soon!')
|
12
|
+
).toBeInTheDocument();
|
13
|
+
});
|
14
|
+
});
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
exports[`AnsiblePermissionDenied should render 1`] = `
|
4
4
|
<EmptyStatePattern
|
5
|
+
action={null}
|
5
6
|
description={
|
6
7
|
<span>
|
7
8
|
You are not authorized to perform this action.
|
@@ -22,5 +23,6 @@ exports[`AnsiblePermissionDenied should render 1`] = `
|
|
22
23
|
header="Permission Denied"
|
23
24
|
icon="lock"
|
24
25
|
iconType="fa"
|
26
|
+
secondaryActions={Array []}
|
25
27
|
/>
|
26
28
|
`;
|
data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
2
|
|
3
3
|
exports[`AssignedRolesList should render 1`] = `
|
4
|
-
<DndProvider
|
4
|
+
<Memo(DndProvider)
|
5
5
|
backend={[Function]}
|
6
6
|
>
|
7
7
|
<ListView
|
8
8
|
className=""
|
9
9
|
>
|
10
|
-
<
|
10
|
+
<DropTarget(DragSource(Orderable(AnsibleRole)))
|
11
11
|
icon="fa fa-minus-circle"
|
12
12
|
index={0}
|
13
13
|
key="1"
|
@@ -21,7 +21,7 @@ exports[`AssignedRolesList should render 1`] = `
|
|
21
21
|
}
|
22
22
|
}
|
23
23
|
/>
|
24
|
-
<
|
24
|
+
<DropTarget(DragSource(Orderable(AnsibleRole)))
|
25
25
|
icon="fa fa-minus-circle"
|
26
26
|
index={1}
|
27
27
|
key="2"
|
@@ -60,5 +60,5 @@ exports[`AssignedRolesList should render 1`] = `
|
|
60
60
|
}
|
61
61
|
/>
|
62
62
|
</div>
|
63
|
-
</DndProvider>
|
63
|
+
</Memo(DndProvider)>
|
64
64
|
`;
|
@@ -8,9 +8,14 @@ exports[`AvailableRolesList should render 1`] = `
|
|
8
8
|
className="sticky-pagination"
|
9
9
|
>
|
10
10
|
<PaginationWrapper
|
11
|
+
className=""
|
12
|
+
disableNext={false}
|
13
|
+
disablePrev={false}
|
11
14
|
dropdownButtonId="available-ansible-roles-pagination-row-dropdown"
|
12
15
|
itemCount={2}
|
13
16
|
onChange={[Function]}
|
17
|
+
onPageSet={[Function]}
|
18
|
+
onPerPageSelect={[Function]}
|
14
19
|
pagination={
|
15
20
|
Object {
|
16
21
|
"page": 1,
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
|
4
|
+
|
5
|
+
import AnsibleHostDetail from './components/AnsibleHostDetail';
|
6
|
+
|
7
|
+
addGlobalFill(
|
8
|
+
'host-details-page-tabs',
|
9
|
+
'Ansible',
|
10
|
+
<AnsibleHostDetail key="ansible-host-detail" />,
|
11
|
+
500
|
12
|
+
);
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_ansible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Lobato Garcia
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: foreman_ansible_core
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '3.0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '3.0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: acts_as_list
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -302,9 +288,6 @@ files:
|
|
302
288
|
- test/unit/hostgroup_ansible_role_test.rb
|
303
289
|
- test/unit/ignore_roles_test.rb
|
304
290
|
- test/unit/import_roles_and_variables.rb
|
305
|
-
- test/unit/lib/foreman_ansible_core/ansible_runner_test.rb
|
306
|
-
- test/unit/lib/foreman_ansible_core/command_creator_test.rb
|
307
|
-
- test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
|
308
291
|
- test/unit/lib/proxy_api/ansible_test.rb
|
309
292
|
- test/unit/services/ansible_report_importer_test.rb
|
310
293
|
- test/unit/services/ansible_variables_importer_test.rb
|
@@ -317,12 +300,10 @@ files:
|
|
317
300
|
- test/unit/services/roles_importer_test.rb
|
318
301
|
- test/unit/services/structured_fact_importer_test.rb
|
319
302
|
- test/unit/services/ui_roles_importer_test.rb
|
320
|
-
- webpack/
|
321
|
-
- webpack/
|
322
|
-
- webpack/
|
323
|
-
- webpack/
|
324
|
-
- webpack/__mocks__/foremanReact/components/common/forms/OrderableSelect/helpers.js
|
325
|
-
- webpack/__mocks__/foremanReact/redux/API.js
|
303
|
+
- webpack/components/AnsibleHostDetail/AnsibleHostDetail.js
|
304
|
+
- webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss
|
305
|
+
- webpack/components/AnsibleHostDetail/AnsibleHostDetail.test.js
|
306
|
+
- webpack/components/AnsibleHostDetail/index.js
|
326
307
|
- webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.js
|
327
308
|
- webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.scss
|
328
309
|
- webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesActions.js
|
@@ -368,13 +349,14 @@ files:
|
|
368
349
|
- webpack/components/AnsibleRolesSwitcher/components/withProtectedView.js
|
369
350
|
- webpack/components/AnsibleRolesSwitcher/index.js
|
370
351
|
- webpack/components/ReportJsonViewer.js
|
352
|
+
- webpack/global_index.js
|
371
353
|
- webpack/index.js
|
372
354
|
- webpack/reducer.js
|
373
355
|
homepage: https://github.com/theforeman/foreman_ansible
|
374
356
|
licenses:
|
375
357
|
- GPL-3.0
|
376
358
|
metadata: {}
|
377
|
-
post_install_message:
|
359
|
+
post_install_message:
|
378
360
|
rdoc_options: []
|
379
361
|
require_paths:
|
380
362
|
- lib
|
@@ -390,7 +372,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
390
372
|
version: '0'
|
391
373
|
requirements: []
|
392
374
|
rubygems_version: 3.1.2
|
393
|
-
signing_key:
|
375
|
+
signing_key:
|
394
376
|
specification_version: 4
|
395
377
|
summary: Ansible integration with Foreman (theforeman.org)
|
396
378
|
test_files:
|
@@ -399,8 +381,8 @@ test_files:
|
|
399
381
|
- test/factories/ansible_roles.rb
|
400
382
|
- test/factories/host_ansible_enhancements.rb
|
401
383
|
- test/fixtures/insights_playbook.yaml
|
402
|
-
- test/fixtures/report.json
|
403
384
|
- test/fixtures/sample_facts.json
|
385
|
+
- test/fixtures/report.json
|
404
386
|
- test/functional/ansible_roles_controller_test.rb
|
405
387
|
- test/functional/api/v2/ansible_inventories_controller_test.rb
|
406
388
|
- test/functional/api/v2/ansible_variables_controller_test.rb
|
@@ -419,24 +401,21 @@ test_files:
|
|
419
401
|
- test/unit/concerns/host_managed_extensions_test.rb
|
420
402
|
- test/unit/concerns/hostgroup_extensions_test.rb
|
421
403
|
- test/unit/helpers/ansible_reports_helper_test.rb
|
422
|
-
- test/unit/lib/foreman_ansible_core/command_creator_test.rb
|
423
|
-
- test/unit/lib/foreman_ansible_core/ansible_runner_test.rb
|
424
|
-
- test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
|
425
404
|
- test/unit/lib/proxy_api/ansible_test.rb
|
426
405
|
- test/unit/services/ansible_report_importer_test.rb
|
427
|
-
- test/unit/services/fact_importer_test.rb
|
428
406
|
- test/unit/services/fact_sparser_test.rb
|
429
407
|
- test/unit/services/insights_plan_runner_test.rb
|
430
408
|
- test/unit/services/roles_importer_test.rb
|
431
409
|
- test/unit/services/structured_fact_importer_test.rb
|
410
|
+
- test/unit/services/fact_importer_test.rb
|
432
411
|
- test/unit/services/ansible_variables_importer_test.rb
|
433
412
|
- test/unit/services/ui_roles_importer_test.rb
|
434
413
|
- test/unit/services/api_roles_importer_test.rb
|
435
414
|
- test/unit/services/fact_parser_test.rb
|
436
415
|
- test/unit/services/inventory_creator_test.rb
|
416
|
+
- test/unit/ansible_provider_test.rb
|
437
417
|
- test/unit/host_ansible_role_test.rb
|
418
|
+
- test/unit/hostgroup_ansible_role_test.rb
|
438
419
|
- test/unit/import_roles_and_variables.rb
|
439
420
|
- test/unit/ignore_roles_test.rb
|
440
|
-
- test/unit/hostgroup_ansible_role_test.rb
|
441
|
-
- test/unit/ansible_provider_test.rb
|
442
421
|
- test/foreman_ansible/helpers/ansible_roles_helper_test.rb
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
module ForemanAnsibleCore
|
6
|
-
module Runner
|
7
|
-
class AnsibleRunnerTest < ActiveSupport::TestCase
|
8
|
-
describe AnsibleRunner do
|
9
|
-
it 'parses files without event data' do
|
10
|
-
content = <<~JSON
|
11
|
-
{"uuid": "a29d8592-f805-4d0e-b73d-7a53cc35a92e", "stdout": " [WARNING]: Consider using the yum module rather than running 'yum'. If you", "counter": 8, "end_line": 8, "runner_ident": "e2d9ae11-026a-4f9f-9679-401e4b852ab0", "start_line": 7, "event": "verbose"}
|
12
|
-
JSON
|
13
|
-
|
14
|
-
File.expects(:read).with('fake.json').returns(content)
|
15
|
-
runner = AnsibleRunner.allocate
|
16
|
-
runner.expects(:handle_broadcast_data)
|
17
|
-
assert runner.send(:handle_event_file, 'fake.json')
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe '#rebuild_secrets' do
|
22
|
-
let(:inventory) do
|
23
|
-
{ 'all' => { 'hosts' => ['foreman.example.com'] },
|
24
|
-
'_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
|
25
|
-
end
|
26
|
-
let(:input) do
|
27
|
-
host_secrets = { 'ansible_password' => 'letmein', 'ansible_become_password' => 'iamroot' }
|
28
|
-
secrets = { 'per-host' => { 'foreman.example.com' => host_secrets } }
|
29
|
-
host_input = { 'input' => { 'action_input' => { 'secrets' => secrets } } }
|
30
|
-
{ 'foreman.example.com' => host_input }
|
31
|
-
end
|
32
|
-
let(:runner) { ForemanAnsibleCore::Runner::AnsibleRunner.allocate }
|
33
|
-
|
34
|
-
test 'uses secrets from inventory' do
|
35
|
-
test_inventory = inventory.merge('ssh_password' => 'sshpass', 'effective_user_password' => 'mypass')
|
36
|
-
rebuilt = runner.send(:rebuild_secrets, test_inventory, input)
|
37
|
-
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
38
|
-
assert_equal 'sshpass', host_vars['ansible_password']
|
39
|
-
assert_equal 'mypass', host_vars['ansible_become_password']
|
40
|
-
end
|
41
|
-
|
42
|
-
test 'host secrets are used when not overriden by inventory secrest' do
|
43
|
-
rebuilt = runner.send(:rebuild_secrets, inventory, input)
|
44
|
-
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
45
|
-
assert_equal 'letmein', host_vars['ansible_password']
|
46
|
-
assert_equal 'iamroot', host_vars['ansible_become_password']
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class CommandCreatorTest < ActiveSupport::TestCase
|
6
|
-
let(:inventory_file) { 'test_inventory' }
|
7
|
-
let(:playbook_file) { 'test_palybook.yml' }
|
8
|
-
subject do
|
9
|
-
ForemanAnsibleCore::CommandCreator.new(inventory_file, playbook_file, {})
|
10
|
-
end
|
11
|
-
|
12
|
-
test 'returns a command array including the ansible-playbook command' do
|
13
|
-
assert command_parts.include?('ansible-playbook')
|
14
|
-
end
|
15
|
-
|
16
|
-
test 'the last argument is the playbook_file' do
|
17
|
-
assert command_parts.last == playbook_file
|
18
|
-
end
|
19
|
-
|
20
|
-
describe 'environment variables' do
|
21
|
-
let(:environment_variables) { subject.command.first }
|
22
|
-
|
23
|
-
test 'has a JSON_INVENTORY_FILE set' do
|
24
|
-
assert environment_variables['JSON_INVENTORY_FILE']
|
25
|
-
end
|
26
|
-
|
27
|
-
test 'has no ANSIBLE_CALLBACK_WHITELIST set by default' do
|
28
|
-
assert_not environment_variables['ANSIBLE_CALLBACK_WHITELIST']
|
29
|
-
end
|
30
|
-
|
31
|
-
test 'with a REX command it sets ANSIBLE_CALLBACK_WHITELIST to empty' do
|
32
|
-
set_command_options(:remote_execution_command, true)
|
33
|
-
assert environment_variables['ANSIBLE_CALLBACK_WHITELIST']
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe 'command options' do
|
38
|
-
it 'can have verbosity set' do
|
39
|
-
level = '3'
|
40
|
-
level_string = Array.new(level.to_i).map { 'v' }.join
|
41
|
-
set_command_options(:verbosity_level, level)
|
42
|
-
assert command_parts.any? do |part|
|
43
|
-
part == "-#{level_string}"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'can have a timeout set' do
|
48
|
-
timeout = '5555'
|
49
|
-
set_command_options(:timeout, timeout)
|
50
|
-
assert command_parts.include?(timeout)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def command_parts
|
57
|
-
subject.command.flatten.map(&:to_s)
|
58
|
-
end
|
59
|
-
|
60
|
-
def set_command_options(option, value)
|
61
|
-
subject.instance_eval("@options[:#{option}] = \"#{value}\"",
|
62
|
-
__FILE__, __LINE__ - 1)
|
63
|
-
end
|
64
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
# Playbook Runner - this class uses foreman_tasks_core
|
6
|
-
# to run playbooks
|
7
|
-
class PlaybookRunnerTest < ActiveSupport::TestCase
|
8
|
-
context 'roles dir' do
|
9
|
-
test 'reads default when none provided' do
|
10
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:unknown_hosts).
|
11
|
-
returns([])
|
12
|
-
File.expects(:exist?).with(Dir.home).returns(true)
|
13
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
14
|
-
runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
15
|
-
assert '/etc/ansible', runner.instance_variable_get('@ansible_dir')
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'working_dir' do
|
20
|
-
setup do
|
21
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:unknown_hosts).
|
22
|
-
returns([])
|
23
|
-
end
|
24
|
-
|
25
|
-
test 'creates temp one if not provided' do
|
26
|
-
Dir.expects(:mktmpdir)
|
27
|
-
File.expects(:exist?).with(Dir.home).returns(true)
|
28
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
29
|
-
ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
30
|
-
end
|
31
|
-
|
32
|
-
test 'reads it when provided' do
|
33
|
-
settings = { :working_dir => '/foo', :ansible_dir => '/etc/foo' }
|
34
|
-
ForemanAnsibleCore.expects(:settings).returns(settings)
|
35
|
-
File.expects(:exist?).with(settings[:ansible_dir]).returns(true)
|
36
|
-
Dir.expects(:mktmpdir).never
|
37
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
|
38
|
-
runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
|
39
|
-
assert '/foo', runner.instance_variable_get('@working_dir')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context 'TOFU policy' do # Trust On First Use
|
44
|
-
setup do
|
45
|
-
@inventory = { 'all' => { 'hosts' => ['foreman.example.com'] } }
|
46
|
-
@output = StringIO.new
|
47
|
-
logger = Logger.new(@output)
|
48
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:logger).
|
49
|
-
returns(logger)
|
50
|
-
end
|
51
|
-
|
52
|
-
test 'ignores known hosts' do
|
53
|
-
Net::SSH::KnownHosts.expects(:search_for).
|
54
|
-
with('foreman.example.com').returns(['somekey'])
|
55
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.
|
56
|
-
expects(:add_to_known_hosts).never
|
57
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
58
|
-
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
59
|
-
end
|
60
|
-
|
61
|
-
test 'adds unknown hosts to known_hosts' do
|
62
|
-
Net::SSH::KnownHosts.expects(:search_for).
|
63
|
-
with('foreman.example.com').returns([])
|
64
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.
|
65
|
-
expects(:add_to_known_hosts).with('foreman.example.com')
|
66
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
67
|
-
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
68
|
-
end
|
69
|
-
|
70
|
-
test 'logs error when it cannot add to known_hosts' do
|
71
|
-
Net::SSH::KnownHosts.expects(:search_for).
|
72
|
-
with('foreman.example.com').returns([])
|
73
|
-
Net::SSH::Transport::Session.expects(:new).with('foreman.example.com').
|
74
|
-
raises(Net::Error)
|
75
|
-
ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
|
76
|
-
ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
|
77
|
-
assert_match(
|
78
|
-
/ERROR.*Failed to save host key for foreman.example.com: Net::Error/,
|
79
|
-
@output.string
|
80
|
-
)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'rebuild secrets' do
|
85
|
-
let(:inventory) do
|
86
|
-
{ 'all' => { 'hosts' => ['foreman.example.com'] },
|
87
|
-
'_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
|
88
|
-
end
|
89
|
-
let(:secrets) do
|
90
|
-
host_secrets = { 'ansible_password' => 'letmein', 'ansible_become_password' => 'iamroot' }
|
91
|
-
{ 'per-host' => { 'foreman.example.com' => host_secrets } }
|
92
|
-
end
|
93
|
-
let(:runner) { ForemanAnsibleCore::Runner::Playbook.allocate }
|
94
|
-
|
95
|
-
test 'uses secrets from inventory' do
|
96
|
-
test_inventory = inventory.merge('ssh_password' => 'sshpass', 'effective_user_password' => 'mypass')
|
97
|
-
rebuilt = runner.send(:rebuild_secrets, test_inventory, secrets)
|
98
|
-
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
99
|
-
assert_equal 'sshpass', host_vars['ansible_password']
|
100
|
-
assert_equal 'mypass', host_vars['ansible_become_password']
|
101
|
-
end
|
102
|
-
|
103
|
-
test 'host secrets are used when not overriden by inventory secrest' do
|
104
|
-
rebuilt = runner.send(:rebuild_secrets, inventory, secrets)
|
105
|
-
host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
|
106
|
-
assert_equal 'letmein', host_vars['ansible_password']
|
107
|
-
assert_equal 'iamroot', host_vars['ansible_become_password']
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
export const translate = s => s;
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import { camelCase } from 'lodash';
|
2
|
-
|
3
|
-
export const propsToCamelCase = ob =>
|
4
|
-
propsToCase(camelCase, 'propsToCamelCase only takes objects', ob);
|
5
|
-
|
6
|
-
const propsToCase = (casingFn, errorMsg, ob) => {
|
7
|
-
if (typeof ob !== 'object') throw Error(errorMsg);
|
8
|
-
|
9
|
-
return Object.keys(ob).reduce((memo, key) => {
|
10
|
-
memo[casingFn(key)] = ob[key];
|
11
|
-
return memo;
|
12
|
-
}, {});
|
13
|
-
};
|