foreman_ansible 10.4.3 → 11.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/app/graphql/types/overriden_ansible_variable.rb +2 -4
- data/app/helpers/foreman_ansible/ansible_hostgroups_helper.rb +6 -32
- data/app/helpers/foreman_ansible/ansible_reports_helper.rb +20 -27
- data/app/helpers/foreman_ansible/smart_proxies_helper.rb +1 -7
- data/app/views/foreman_ansible/config_reports/_ansible.html.erb +6 -2
- data/app/views/foreman_ansible/job_templates/capsule_upgrade_-_ansible_default.erb +32 -4
- data/db/migrate/20210818083407_fix_ansible_setting_category_to_dsl.rb +1 -1
- data/db/migrate/20221003153000_add_ansible_callback_enabled_to_templates.rb +1 -1
- data/lib/foreman_ansible/register.rb +1 -1
- data/lib/foreman_ansible/version.rb +1 -1
- data/package.json +1 -1
- data/test/fixtures/report.json +2 -106
- data/test/integration/hostgroup_js_test.rb +2 -4
- data/test/unit/concerns/config_reports_extensions_test.rb +2 -4
- data/test/unit/helpers/ansible_reports_helper_test.rb +4 -50
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js +2 -6
- data/webpack/graphql/queries/currentUserAttributes.gql +0 -5
- data/webpack/permissionsHelper.js +1 -4
- data/webpack/testHelper.js +0 -6
- metadata +9 -10
- data/app/views/foreman_ansible/job_templates/smart_proxy_upgrade_-_ansible_default.erb +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 348701b380a514ccae60dda27305a137438dd4cd2812f9515e071a527a0b20c5
|
4
|
+
data.tar.gz: ab770d603437ed890a945381d28411e0caff547f6bef26b22c98191fe6317b98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a780ccd49ae7534e43de5ea1f50aab631b3f59c30c5793455e242568b77d2572fe187f7f0c75667cb1c22ccfd03666dd2ce7df2541cb974df1693ff58079250
|
7
|
+
data.tar.gz: ab9bdea79a470967e8c6592d7166317668a5d9f892887b8d715fc1daaa9a8ce99959cb5c4da2496dabf4b9e4d2ada5909c2e78bfa250bcd13d2250d7d32a1473
|
@@ -8,14 +8,12 @@ module Types
|
|
8
8
|
argument :match, String, required: false
|
9
9
|
end
|
10
10
|
|
11
|
-
field :meta, ::Types::Meta
|
12
|
-
|
13
|
-
def meta
|
11
|
+
field :meta, ::Types::Meta, resolve: (proc do |object|
|
14
12
|
{
|
15
13
|
:can_edit => ::User.current.can?(object.ansible_variable.permission_name(:edit), object.ansible_variable),
|
16
14
|
:can_destroy => ::User.current.can?(object.ansible_variable.permission_name(:destroy), object.ansible_variable)
|
17
15
|
}
|
18
|
-
end
|
16
|
+
end)
|
19
17
|
|
20
18
|
def lookup_values(match: nil)
|
21
19
|
return CollectionLoader.for(object.ansible_variable.class, :lookup_values).load(object.ansible_variable) unless match
|
@@ -3,39 +3,13 @@
|
|
3
3
|
module ForemanAnsible
|
4
4
|
module AnsibleHostgroupsHelper
|
5
5
|
def ansible_hostgroups_actions(hostgroup)
|
6
|
-
|
7
|
-
|
6
|
+
play_roles = if hostgroup.all_ansible_roles.empty?
|
7
|
+
{ action: { content: (link_to _('Run all Ansible roles'), 'javascript:void(0);', disabled: true, title: 'No roles assigned', class: 'disabled'), options: { class: 'disabled' } }, priority: 31 }
|
8
|
+
else
|
9
|
+
{ action: display_link_if_authorized(_('Run all Ansible roles'), hash_for_play_roles_hostgroup_path(id: hostgroup), 'data-no-turbolink': true, title: _('Run all Ansible roles on hosts belonging to this host group')), priority: 31 }
|
10
|
+
end
|
8
11
|
|
9
|
-
if User.current.can?(:create_job_invocations)
|
10
|
-
actions << {
|
11
|
-
action: if is_hostgroup_empty
|
12
|
-
disabled_action_link(_('Run all Ansible roles'))
|
13
|
-
else
|
14
|
-
display_link_if_authorized(_('Run all Ansible roles'), hash_for_play_roles_hostgroup_path(id: hostgroup), 'data-no-turbolink': true, title: _('Run all Ansible roles on hosts belonging to this host group'))
|
15
|
-
end,
|
16
|
-
priority: 31
|
17
|
-
}
|
18
|
-
end
|
19
|
-
|
20
|
-
if User.current.can?(:view_job_invocations) && User.current.can?(:view_recurring_logics)
|
21
|
-
actions << {
|
22
|
-
action: if is_hostgroup_empty
|
23
|
-
disabled_action_link(_('Configure Ansible Job'))
|
24
|
-
else
|
25
|
-
link_to(_('Configure Ansible Job'), "/ansible/hostgroups/#{hostgroup.id}", class: 'la')
|
26
|
-
end,
|
27
|
-
priority: 32
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
actions
|
32
|
-
end
|
33
|
-
|
34
|
-
def disabled_action_link(text)
|
35
|
-
{
|
36
|
-
content: link_to(text, 'javascript:void(0);', disabled: true, title: _('No roles/hosts assigned'), class: 'disabled'),
|
37
|
-
options: { class: 'disabled' }
|
38
|
-
}
|
12
|
+
[play_roles] if User.current.can?(:create_job_invocations)
|
39
13
|
end
|
40
14
|
end
|
41
15
|
end
|
@@ -28,36 +28,26 @@ module ForemanAnsible
|
|
28
28
|
def ansible_module_message(log)
|
29
29
|
msg_json = parsed_message_json(log)
|
30
30
|
return _("Execution error: #{msg_json['msg']}") if msg_json['failed'].present?
|
31
|
-
return msg_json['censored'] if msg_json['censored'].present?
|
32
31
|
|
33
|
-
module_action = msg_json
|
32
|
+
module_action = msg_json['module']
|
34
33
|
case module_action
|
35
34
|
when 'package'
|
36
35
|
msg_json['results'].empty? ? msg_json['msg'] : msg_json['results']
|
37
36
|
when 'template'
|
38
|
-
|
39
|
-
|
40
|
-
end
|
37
|
+
module_args = msg_json['invocation']['module_args']
|
38
|
+
_("Rendered template #{module_args['_original_basename']} to #{msg_json['dest']}")
|
41
39
|
when 'service'
|
42
|
-
|
43
|
-
_("Service #{result['name']} #{result['state']} (enabled: #{result['enabled']})")
|
44
|
-
end
|
40
|
+
_("Service #{msg_json['name']} #{msg_json['state']} (enabled: #{msg_json['enabled']})")
|
45
41
|
when 'group'
|
46
|
-
|
47
|
-
_("User group #{result['name']} #{result['state']}, gid: #{result['gid']}")
|
48
|
-
end
|
42
|
+
_("User group #{msg_json['name']} #{msg_json['state']}, gid: #{msg_json['gid']}")
|
49
43
|
when 'user'
|
50
|
-
|
51
|
-
_("User #{result['name']} #{result['state']}, uid: #{result['uid']}")
|
52
|
-
end
|
44
|
+
_("User #{msg_json['name']} #{msg_json['state']}, uid: #{msg_json['uid']}")
|
53
45
|
when 'cron'
|
54
|
-
|
55
|
-
|
56
|
-
end
|
46
|
+
module_args = msg_json['invocation']['module_args']
|
47
|
+
_("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
|
57
48
|
when 'copy'
|
58
|
-
|
59
|
-
|
60
|
-
end
|
49
|
+
module_args = msg_json['invocation']['module_args']
|
50
|
+
_("Copy #{module_args['_original_basename']} to #{msg_json['dest']}")
|
61
51
|
when 'command', 'shell'
|
62
52
|
msg_json['stdout_lines']
|
63
53
|
else
|
@@ -79,16 +69,19 @@ module ForemanAnsible
|
|
79
69
|
false
|
80
70
|
end
|
81
71
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
72
|
+
def show_full_error_message_value(message_value)
|
73
|
+
tag.div class: 'replace-hidden-value' do
|
74
|
+
link_to_function(icon_text('plus', '', class: 'small'), 'replace_value_control(this, "div")',
|
75
|
+
title: _('Show full value'),
|
76
|
+
class: 'replace-hidden-value pull-right') +
|
77
|
+
(tag.span class: 'full-value' do
|
78
|
+
message_value
|
79
|
+
end)
|
89
80
|
end
|
90
81
|
end
|
91
82
|
|
83
|
+
private
|
84
|
+
|
92
85
|
def parsed_message_json(log)
|
93
86
|
JSON.parse(log.message.value)
|
94
87
|
rescue StandardError => e
|
@@ -27,13 +27,7 @@ module ForemanAnsible
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def proxy_update_button(proxy)
|
30
|
-
|
31
|
-
:ansible_run_capsule_upgrade
|
32
|
-
else
|
33
|
-
:ansible_run_smart_proxy_upgrade
|
34
|
-
end
|
35
|
-
|
36
|
-
feature = RemoteExecutionFeature.feature(name)
|
30
|
+
feature = RemoteExecutionFeature.feature(:ansible_run_capsule_upgrade)
|
37
31
|
return if feature.nil?
|
38
32
|
|
39
33
|
path = new_job_invocation_path(:host_ids => proxy.infrastructure_host_facets.pluck(:host_id),
|
@@ -29,8 +29,12 @@
|
|
29
29
|
<% end %>
|
30
30
|
</ul>
|
31
31
|
<% else %>
|
32
|
-
|
33
|
-
|
32
|
+
<% allowed_length = 150 %>
|
33
|
+
<div class='pull-left'>
|
34
|
+
<%= truncate(log_message, length: allowed_length) %>
|
35
|
+
</div>
|
36
|
+
<%= show_full_error_message_value(log_message) if log_message.length > allowed_length %>
|
37
|
+
<% end %>
|
34
38
|
</td>
|
35
39
|
</tr>
|
36
40
|
<% end %>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%#
|
2
|
-
name:
|
2
|
+
name: Smart Proxy Upgrade Playbook
|
3
3
|
snippet: false
|
4
4
|
template_inputs:
|
5
5
|
- name: target_version
|
@@ -26,8 +26,8 @@ feature: ansible_run_capsule_upgrade
|
|
26
26
|
- hosts: all
|
27
27
|
vars:
|
28
28
|
target_version: "<%= input('target_version').present? ? input('target_version') : product_short_version %>"
|
29
|
-
tasks:
|
30
29
|
<% if plugin_present?('foreman_theme_satellite') -%>
|
30
|
+
tasks:
|
31
31
|
- name: Gather the rpm package facts
|
32
32
|
package_facts:
|
33
33
|
manager: auto
|
@@ -75,7 +75,35 @@ feature: ansible_run_capsule_upgrade
|
|
75
75
|
fail:
|
76
76
|
msg: "Failed! Capsule server upgrade failed. See /var/log/foreman-installer/capsule.log in the Capsule server for more information"
|
77
77
|
<% else -%>
|
78
|
-
|
78
|
+
tasks:
|
79
|
+
- name: Gather the rpm package facts
|
80
|
+
package_facts:
|
81
|
+
manager: auto
|
82
|
+
|
83
|
+
- name: Fail if the target server is a Foreman server
|
79
84
|
fail:
|
80
|
-
msg: "
|
85
|
+
msg: "This playbook cannot be executed on a Foreman server. Use only on a Smart Proxy server."
|
86
|
+
when: "'foreman' in ansible_facts.packages"
|
87
|
+
|
88
|
+
- name: Install foreman release gpg key
|
89
|
+
rpm_key:
|
90
|
+
state: present
|
91
|
+
key: http://yum.theforeman.org/releases/{{ target_version }}/RPM-GPG-KEY-foreman
|
92
|
+
when: target_version != "nightly"
|
93
|
+
|
94
|
+
- name: Update foreman repositories
|
95
|
+
package:
|
96
|
+
name: https://yum.theforeman.org/releases/{{ target_version }}/el{{ ansible_distribution_major_version }}/{{ ansible_architecture }}/foreman-release.rpm
|
97
|
+
state: installed
|
98
|
+
|
99
|
+
- name: Clean yum metadata
|
100
|
+
command: yum clean all
|
101
|
+
|
102
|
+
- name: Update all packages
|
103
|
+
package:
|
104
|
+
name: '*'
|
105
|
+
state: latest
|
106
|
+
|
107
|
+
- name: Run the installer
|
108
|
+
shell: foreman-installer
|
81
109
|
<% end -%>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class FixAnsibleSettingCategoryToDsl < ActiveRecord::Migration[6.0]
|
2
2
|
def up
|
3
|
-
Setting.where(category: 'Setting::Ansible').update_all(category: 'Setting')
|
3
|
+
Setting.where(category: 'Setting::Ansible').update_all(category: 'Setting')
|
4
4
|
end
|
5
5
|
end
|
@@ -4,7 +4,7 @@ class AddAnsibleCallbackEnabledToTemplates < ActiveRecord::Migration[6.0]
|
|
4
4
|
def change
|
5
5
|
add_column :templates, :ansible_callback_enabled, :boolean, default: false
|
6
6
|
RemoteExecutionFeature.where(label: 'ansible_run_host').each do |rex_feature|
|
7
|
-
Template.
|
7
|
+
Template.find(rex_feature.job_template_id).update(ansible_callback_enabled: true)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
data/package.json
CHANGED
data/test/fixtures/report.json
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
{
|
2
2
|
"reporter": "ansible",
|
3
3
|
"reported_at":"2018-01-15 17:31:36 521275",
|
4
4
|
"metrics": {
|
@@ -24,108 +24,4 @@
|
|
24
24
|
}
|
25
25
|
}
|
26
26
|
]
|
27
|
-
}
|
28
|
-
{
|
29
|
-
"reporter": "ansible",
|
30
|
-
"reported_at":"2022-12-22 10:52:48 521275",
|
31
|
-
"metrics": {
|
32
|
-
"time":
|
33
|
-
{ "total":133 }
|
34
|
-
},
|
35
|
-
"host": "io.local",
|
36
|
-
"status": {
|
37
|
-
"applied": 8,
|
38
|
-
"failed": 0,
|
39
|
-
"skipped": 0
|
40
|
-
},
|
41
|
-
"logs": [
|
42
|
-
{
|
43
|
-
"log": {
|
44
|
-
"sources": {
|
45
|
-
"source": "Schedule multiple cronjobs"
|
46
|
-
},
|
47
|
-
"messages": {
|
48
|
-
"message": "{\"changed\": true, \"failed\": false, \"module\": \"cron\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"date\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"date > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Cron date\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"item\": \"date\", \"jobs\": [\"Cron date\"]}, {\"_ansible_item_label\": \"df\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"df > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Cron df\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"item\": \"df\", \"jobs\": [\"Cron date\", \"Cron df\"]}]}"
|
49
|
-
},
|
50
|
-
"level": "notice"
|
51
|
-
}
|
52
|
-
},
|
53
|
-
{
|
54
|
-
"log": {
|
55
|
-
"sources": {
|
56
|
-
"source": "Schedule one cronjob"
|
57
|
-
},
|
58
|
-
"messages": {
|
59
|
-
"message": "{\"_ansible_no_log\": false, \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"hostname > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Schedule hostname\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"jobs\": [\"Cron date\", \"Cron df\", \"Schedule hostname\"], \"module\": \"cron\"}"
|
60
|
-
},
|
61
|
-
"level": "notice"
|
62
|
-
}
|
63
|
-
},
|
64
|
-
{
|
65
|
-
"log": {
|
66
|
-
"sources": {
|
67
|
-
"source": "Render multiple templates"
|
68
|
-
},
|
69
|
-
"messages": {
|
70
|
-
"message": "{\"changed\": true, \"failed\": false, \"module\": \"template\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"test1.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"dba7673010f19a94af4345453005933fd511bea9\", \"dest\": \"/tmp/test1.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test1.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"dba7673010f19a94af4345453005933fd511bea9\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test1.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670606.02-7241-175625077259447/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test1.txt\", \"md5sum\": null, \"mode\": \"0644\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670606.02-7241-175625077259447/source\", \"state\": \"file\", \"uid\": 0}, {\"_ansible_item_label\": \"test2.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"9054fbe0b622c638224d50d20824d2ff6782e308\", \"dest\": \"/tmp/test2.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test2.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"9054fbe0b622c638224d50d20824d2ff6782e308\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test2.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670620.49-7241-225254470383476/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test2.txt\", \"md5sum\": null, \"mode\": \"0644\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670620.49-7241-225254470383476/source\", \"state\": \"file\", \"uid\": 0}]}"
|
71
|
-
},
|
72
|
-
"level": "notice"
|
73
|
-
}
|
74
|
-
},
|
75
|
-
{
|
76
|
-
"log": {
|
77
|
-
"sources": {
|
78
|
-
"source": "Render one template"
|
79
|
-
},
|
80
|
-
"messages": {
|
81
|
-
"message": "{\"_ansible_no_log\": false, \"changed\": true, \"checksum\": \"41c5985fc771b6ecfe8feaa99f8fa9b77ac7d6ce\", \"dest\": \"/tmp/test3.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test3.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"41c5985fc771b6ecfe8feaa99f8fa9b77ac7d6ce\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test3.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670634.79-7306-243717749452063/source\", \"unsafe_writes\": false, \"validate\": null}}, \"md5sum\": null, \"mode\": \"0644\", \"module\": \"template\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670634.79-7306-243717749452063/source\", \"state\": \"file\", \"uid\": 0}"
|
82
|
-
},
|
83
|
-
"level": "notice"
|
84
|
-
}
|
85
|
-
},
|
86
|
-
{
|
87
|
-
"log": {
|
88
|
-
"sources": {
|
89
|
-
"source": "Copy multiple local files"
|
90
|
-
},
|
91
|
-
"messages": {
|
92
|
-
"message": "{\"changed\": true, \"failed\": false, \"module\": \"copy\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"test4.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"ab2649b7e58f7e32b0c75be95d11e2979399d392\", \"dest\": \"/tmp/test4.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test4.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"ab2649b7e58f7e32b0c75be95d11e2979399d392\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test4.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": \"root\", \"local_follow\": null, \"mode\": 256, \"owner\": \"root\", \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670648.88-7343-91799014257533/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test4.txt\", \"md5sum\": null, \"mode\": \"0400\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670648.88-7343-91799014257533/source\", \"state\": \"file\", \"uid\": 0}, {\"_ansible_item_label\": \"test5.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"4ea77484f3a1c7dde4c0cca2f5c40953388f19f5\", \"dest\": \"/tmp/test5.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test5.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"4ea77484f3a1c7dde4c0cca2f5c40953388f19f5\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test5.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": \"root\", \"local_follow\": null, \"mode\": 256, \"owner\": \"root\", \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670662.97-7343-50902792283881/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test5.txt\", \"md5sum\": null, \"mode\": \"0400\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670662.97-7343-50902792283881/source\", \"state\": \"file\", \"uid\": 0}]}"
|
93
|
-
},
|
94
|
-
"level": "notice"
|
95
|
-
}
|
96
|
-
},
|
97
|
-
{
|
98
|
-
"log": {
|
99
|
-
"sources": {
|
100
|
-
"source": "Copy one local files"
|
101
|
-
},
|
102
|
-
"messages": {
|
103
|
-
"message": "{\"_ansible_no_log\": false, \"changed\": true, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"dest\": \"/tmp/test6.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test6.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test6.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": \"root\", \"local_follow\": null, \"mode\": 256, \"owner\": \"root\", \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670677.05-7408-75605497546833/source\", \"unsafe_writes\": false, \"validate\": null}}, \"md5sum\": null, \"mode\": \"0400\", \"module\": \"copy\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670677.05-7408-75605497546833/source\", \"state\": \"file\", \"uid\": 0}"
|
104
|
-
},
|
105
|
-
"level": "notice"
|
106
|
-
}
|
107
|
-
},
|
108
|
-
{
|
109
|
-
"log": {
|
110
|
-
"sources": {
|
111
|
-
"source": "Restart multiple services"
|
112
|
-
},
|
113
|
-
"messages": {
|
114
|
-
"message": "{\"changed\":true,\"failed\":false,\"module\":\"service\",\"msg\":\"All items completed\",\"results\":[{\"_ansible_item_label\":\"chronyd\",\"_ansible_no_log\":false,\"ansible_loop_var\":\"item\",\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"chronyd\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"item\":\"chronyd\",\"name\":\"chronyd\",\"state\":\"started\"},{\"_ansible_item_label\":\"firewalld\",\"_ansible_no_log\":false,\"ansible_loop_var\":\"item\",\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"firewalld\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"item\":\"firewalld\",\"name\":\"firewalld\",\"state\":\"started\"}]}"
|
115
|
-
},
|
116
|
-
"level": "notice"
|
117
|
-
}
|
118
|
-
},
|
119
|
-
{
|
120
|
-
"log": {
|
121
|
-
"sources": {
|
122
|
-
"source": "Restart one service"
|
123
|
-
},
|
124
|
-
"messages": {
|
125
|
-
"message": "{\"_ansible_no_log\":false,\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"chronyd\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"module\":\"service\",\"name\":\"chronyd\",\"state\":\"started\"}"
|
126
|
-
},
|
127
|
-
"level": "notice"
|
128
|
-
}
|
129
|
-
}
|
130
|
-
]
|
131
|
-
}]
|
27
|
+
}
|
@@ -10,23 +10,21 @@ class HostgroupJsTest < IntegrationTestWithJavascript
|
|
10
10
|
FactoryBot.create(:host, :hostgroup_id => hostgroup_with_roles.id)
|
11
11
|
end
|
12
12
|
|
13
|
-
test 'hostgroup without roles should have disabled
|
13
|
+
test 'hostgroup without roles should have disabled link' do
|
14
14
|
visit hostgroups_path(search: hostgroup.name)
|
15
15
|
|
16
16
|
first_row = page.find('table > tbody > tr:nth-child(1)')
|
17
17
|
first_row.find('td:nth-child(4) > div > a').click
|
18
18
|
|
19
19
|
assert_includes first(:link, 'Run all Ansible roles')[:class], 'disabled'
|
20
|
-
assert_includes first(:link, 'Configure Ansible Job')[:class], 'disabled'
|
21
20
|
end
|
22
21
|
|
23
|
-
test 'hostgroup with roles should have clickable
|
22
|
+
test 'hostgroup with roles should have clickable link' do
|
24
23
|
visit hostgroups_path(search: hostgroup_with_roles.name)
|
25
24
|
|
26
25
|
first_row = page.find('table > tbody > tr:nth-child(1)')
|
27
26
|
first_row.find('td:nth-child(4) > div > a').click
|
28
27
|
|
29
28
|
assert_not first(:link, 'Run all Ansible roles')[:class].include?('disabled')
|
30
|
-
assert_not first(:link, 'Configure Ansible Job')[:class].include?('disabled')
|
31
29
|
end
|
32
30
|
end
|
@@ -4,15 +4,13 @@ require 'test_plugin_helper'
|
|
4
4
|
|
5
5
|
# Tests for the behavior of Host with roles, checks inheritance, etc
|
6
6
|
class ConfigReportExtensionsTest < ActiveSupport::TestCase
|
7
|
-
let(:
|
7
|
+
let(:example_report) do
|
8
8
|
JSON.parse(File.read(ansible_fixture_file('report.json')))
|
9
9
|
end
|
10
10
|
|
11
|
-
let(:example_report1) { example_reports.first }
|
12
|
-
|
13
11
|
describe '.import' do
|
14
12
|
it 'sets an origin for Ansible reports' do
|
15
|
-
report = ConfigReport.import(
|
13
|
+
report = ConfigReport.import(example_report)
|
16
14
|
assert_equal 'Ansible', report.origin
|
17
15
|
end
|
18
16
|
|
@@ -20,62 +20,16 @@ ANSIBLELOG
|
|
20
20
|
)
|
21
21
|
end
|
22
22
|
|
23
|
-
test 'module message extraction with
|
24
|
-
example_report = JSON.parse(File.read(ansible_fixture_file('report.json'))).second
|
25
|
-
report = ConfigReport.import(example_report)
|
26
|
-
expected_outputs = [
|
27
|
-
'No additional data',
|
28
|
-
['Cron job: 0 5,2 * * * date > /dev/null (disabled: false)', 'Cron job: 0 5,2 * * * df > /dev/null (disabled: false)'],
|
29
|
-
['Cron job: 0 5,2 * * * hostname > /dev/null (disabled: false)'],
|
30
|
-
['Rendered template test1.txt.j2 to /tmp/test1.txt', 'Rendered template test2.txt.j2 to /tmp/test2.txt'],
|
31
|
-
['Rendered template test3.txt.j2 to /tmp/test3.txt'],
|
32
|
-
['Copy test4.txt to /tmp/test4.txt', 'Copy test5.txt to /tmp/test5.txt'],
|
33
|
-
['Copy test6.txt to /tmp/test6.txt'],
|
34
|
-
['Service chronyd started (enabled: )', 'Service firewalld started (enabled: )'],
|
35
|
-
['Service chronyd started (enabled: )']
|
36
|
-
]
|
37
|
-
actual_outputs = []
|
38
|
-
report.logs.each do |log|
|
39
|
-
actual_outputs << ansible_module_message(log)
|
40
|
-
end
|
41
|
-
assert_equal expected_outputs, actual_outputs
|
42
|
-
end
|
43
|
-
|
44
|
-
test 'accepting an almost empty message' do
|
23
|
+
test 'module message extraction with error' do
|
45
24
|
log_value = <<-ANSIBLELOG.strip_heredoc
|
46
|
-
{"changed":
|
25
|
+
{"msg": "AnsibleUndefinedVariable", "changed": false, "_ansible_no_log": false, "failed": true, "module": "template", "exception": "raise AnsibleUndefinedVariable"}
|
47
26
|
ANSIBLELOG
|
48
27
|
message = FactoryBot.build(:message, value: log_value)
|
49
|
-
log = FactoryBot.build(:log)
|
28
|
+
log = FactoryBot.build(:log, message: message)
|
50
29
|
log.message = message
|
51
|
-
assert_match(
|
52
|
-
/Copy/,
|
53
|
-
ansible_module_message(log).to_s
|
54
|
-
)
|
55
|
-
end
|
56
30
|
|
57
|
-
test 'FQCN module message extraction' do
|
58
|
-
log_value = <<-ANSIBLELOG.strip_heredoc
|
59
|
-
{"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": "ansible.builtin.package"}
|
60
|
-
ANSIBLELOG
|
61
|
-
message = FactoryBot.build(:message, value: log_value)
|
62
|
-
log = FactoryBot.build(:log)
|
63
|
-
log.message = message
|
64
|
-
assert_match(
|
65
|
-
/Nothing to do/,
|
66
|
-
ansible_module_message(log).to_s
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
test 'accepting a censored message' do
|
71
|
-
log_value = <<-ANSIBLELOG.strip_heredoc
|
72
|
-
{"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result", "changed": true, "failed": false, "module": "copy"}
|
73
|
-
ANSIBLELOG
|
74
|
-
message = FactoryBot.build(:message, value: log_value)
|
75
|
-
log = FactoryBot.build(:log)
|
76
|
-
log.message = message
|
77
31
|
assert_match(
|
78
|
-
|
32
|
+
'Execution error: AnsibleUndefinedVariable',
|
79
33
|
ansible_module_message(log).to_s
|
80
34
|
)
|
81
35
|
end
|
@@ -86,16 +86,12 @@ const validateRegexp = (variable, value) => {
|
|
86
86
|
};
|
87
87
|
|
88
88
|
const validateList = (variable, value) => {
|
89
|
-
|
90
|
-
if (typeof validatorRule !== 'string') {
|
91
|
-
validatorRule = validatorRule.toString();
|
92
|
-
}
|
93
|
-
if (validatorRule.split(',').find(item => item.trim() === value)) {
|
89
|
+
if (variable.validatorRule.split(',').find(item => item.trim() === value)) {
|
94
90
|
return validationSuccess;
|
95
91
|
}
|
96
92
|
return {
|
97
93
|
key: 'error',
|
98
|
-
msg: sprintf(__('Invalid, expected one of: %s'), validatorRule),
|
94
|
+
msg: sprintf(__('Invalid, expected one of: %s'), variable.validatorRule),
|
99
95
|
};
|
100
96
|
};
|
101
97
|
|
data/webpack/testHelper.js
CHANGED
@@ -71,9 +71,6 @@ export const userFactory = (login, permissions = []) => ({
|
|
71
71
|
permissions: {
|
72
72
|
nodes: permissions,
|
73
73
|
},
|
74
|
-
usergroups: {
|
75
|
-
nodes: [],
|
76
|
-
},
|
77
74
|
});
|
78
75
|
|
79
76
|
export const admin = {
|
@@ -84,9 +81,6 @@ export const admin = {
|
|
84
81
|
permissions: {
|
85
82
|
nodes: [],
|
86
83
|
},
|
87
|
-
usergroups: {
|
88
|
-
nodes: [],
|
89
|
-
},
|
90
84
|
};
|
91
85
|
|
92
86
|
export const intruder = userFactory('intruder', [
|
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:
|
4
|
+
version: 11.0.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: 2023-
|
11
|
+
date: 2023-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_list
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '9.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '9.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: foreman-tasks
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '7.
|
61
|
+
version: '7.0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '7.
|
68
|
+
version: '7.0'
|
69
69
|
description: Ansible integration with Foreman
|
70
70
|
email:
|
71
71
|
- elobatocs@gmail.com
|
@@ -201,7 +201,6 @@ files:
|
|
201
201
|
- app/views/foreman_ansible/job_templates/run_playbook-ansible_default.erb
|
202
202
|
- app/views/foreman_ansible/job_templates/service_action_-_ansible_default.erb
|
203
203
|
- app/views/foreman_ansible/job_templates/service_action_-_enable_web_console.erb
|
204
|
-
- app/views/foreman_ansible/job_templates/smart_proxy_upgrade_-_ansible_default.erb
|
205
204
|
- app/views/job_templates/_job_template_callback_tab_content.html.erb
|
206
205
|
- app/views/job_templates/_job_template_callback_tab_headers.html.erb
|
207
206
|
- app/views/ui_ansible_roles/index.json.rabl
|
@@ -479,16 +478,16 @@ test_files:
|
|
479
478
|
- test/factories/host_ansible_enhancements.rb
|
480
479
|
- test/fixtures/insights_playbook.yaml
|
481
480
|
- test/fixtures/playbooks_example_output.json
|
481
|
+
- test/fixtures/report.json
|
482
482
|
- test/fixtures/sample_facts.json
|
483
483
|
- test/fixtures/sample_playbooks.json
|
484
|
-
- test/fixtures/report.json
|
485
484
|
- test/foreman_ansible/helpers/ansible_roles_helper_test.rb
|
486
485
|
- test/functional/ansible_roles_controller_test.rb
|
487
486
|
- test/functional/ansible_variables_controller_test.rb
|
487
|
+
- test/functional/api/v2/ansible_inventories_controller_test.rb
|
488
488
|
- test/functional/api/v2/ansible_playbooks_controller_test.rb
|
489
489
|
- test/functional/api/v2/ansible_roles_controller_test.rb
|
490
490
|
- test/functional/api/v2/ansible_variables_controller_test.rb
|
491
|
-
- test/functional/api/v2/ansible_inventories_controller_test.rb
|
492
491
|
- test/functional/api/v2/hostgroups_controller_test.rb
|
493
492
|
- test/functional/api/v2/hosts_controller_test.rb
|
494
493
|
- test/functional/hosts_controller_test.rb
|
@@ -499,9 +498,9 @@ test_files:
|
|
499
498
|
- test/test_plugin_helper.rb
|
500
499
|
- test/unit/ansible_role_test.rb
|
501
500
|
- test/unit/ansible_variable_test.rb
|
501
|
+
- test/unit/concerns/config_reports_extensions_test.rb
|
502
502
|
- test/unit/concerns/host_managed_extensions_test.rb
|
503
503
|
- test/unit/concerns/hostgroup_extensions_test.rb
|
504
|
-
- test/unit/concerns/config_reports_extensions_test.rb
|
505
504
|
- test/unit/helpers/ansible_reports_helper_test.rb
|
506
505
|
- test/unit/host_ansible_role_test.rb
|
507
506
|
- test/unit/hostgroup_ansible_role_test.rb
|
@@ -1,59 +0,0 @@
|
|
1
|
-
<%#
|
2
|
-
name: Smart Proxy Upgrade Playbook
|
3
|
-
snippet: false
|
4
|
-
template_inputs:
|
5
|
-
- name: target_version
|
6
|
-
required: false
|
7
|
-
input_type: user
|
8
|
-
advanced: false
|
9
|
-
value_type: plain
|
10
|
-
hidden_value: false
|
11
|
-
- name: whitelist_options
|
12
|
-
required: false
|
13
|
-
input_type: user
|
14
|
-
advanced: false
|
15
|
-
value_type: plain
|
16
|
-
hidden_value: false
|
17
|
-
model: JobTemplate
|
18
|
-
job_category: Maintenance Operations
|
19
|
-
description_format: "%{template_name}"
|
20
|
-
provider_type: Ansible
|
21
|
-
kind: job_template
|
22
|
-
feature: ansible_run_smart_proxy_upgrade
|
23
|
-
%>
|
24
|
-
|
25
|
-
---
|
26
|
-
- hosts: all
|
27
|
-
vars:
|
28
|
-
target_version: "<%= input('target_version').present? ? input('target_version') : product_short_version %>"
|
29
|
-
tasks:
|
30
|
-
- name: Gather the rpm package facts
|
31
|
-
package_facts:
|
32
|
-
manager: auto
|
33
|
-
|
34
|
-
- name: Fail if the target server is a Foreman server
|
35
|
-
fail:
|
36
|
-
msg: "This playbook cannot be executed on a Foreman server. Use only on a Smart Proxy server."
|
37
|
-
when: "'foreman' in ansible_facts.packages"
|
38
|
-
|
39
|
-
- name: Install foreman release gpg key
|
40
|
-
rpm_key:
|
41
|
-
state: present
|
42
|
-
key: http://yum.theforeman.org/releases/{{ target_version }}/RPM-GPG-KEY-foreman
|
43
|
-
when: target_version != "nightly"
|
44
|
-
|
45
|
-
- name: Update foreman repositories
|
46
|
-
package:
|
47
|
-
name: https://yum.theforeman.org/releases/{{ target_version }}/el{{ ansible_distribution_major_version }}/{{ ansible_architecture }}/foreman-release.rpm
|
48
|
-
state: installed
|
49
|
-
|
50
|
-
- name: Clean yum metadata
|
51
|
-
command: yum clean all
|
52
|
-
|
53
|
-
- name: Update all packages
|
54
|
-
package:
|
55
|
-
name: '*'
|
56
|
-
state: latest
|
57
|
-
|
58
|
-
- name: Run the installer
|
59
|
-
shell: foreman-installer
|