foreman_ansible 2.0.4 → 2.1.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/assets/stylesheets/foreman_ansible/foreman-ansible.css +3 -0
- data/app/helpers/foreman_ansible/ansible_reports_helper.rb +77 -12
- data/app/models/concerns/foreman_ansible/has_many_ansible_roles.rb +3 -1
- data/app/models/concerns/foreman_ansible/hostgroup_extensions.rb +4 -0
- data/app/models/setting/ansible.rb +10 -0
- data/app/services/foreman_ansible/ansible_report_scanner.rb +21 -0
- data/app/services/foreman_ansible/insights_plan_runner.rb +68 -0
- data/app/services/foreman_ansible/inventory_creator.rb +6 -11
- data/app/services/foreman_ansible/renderer_methods.rb +21 -0
- data/app/views/foreman_ansible/ansible_roles/_hostgroup_ansible_roles_button.erb +7 -8
- data/app/views/foreman_ansible/config_reports/_ansible.html.erb +6 -3
- data/app/views/foreman_ansible/config_reports/_output.html.erb +0 -1
- data/app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb +21 -0
- data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_galaxy.erb +32 -0
- data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb +28 -0
- data/app/views/foreman_ansible/job_templates/maintenance_plan.erb +19 -0
- data/app/views/foreman_ansible/job_templates/package_action_-_ansible_default.erb +45 -0
- data/app/views/foreman_ansible/job_templates/power_action_-_ansible_default.erb +28 -0
- data/app/views/foreman_ansible/job_templates/puppet_run_once_-_ansible_default.erb +21 -0
- data/app/views/foreman_ansible/job_templates/run_command_-_ansible_default.erb +22 -0
- data/app/views/foreman_ansible/job_templates/service_action_-_ansible_default.erb +61 -0
- data/lib/foreman_ansible/engine.rb +3 -1
- data/lib/foreman_ansible/register.rb +7 -0
- data/lib/foreman_ansible/remote_execution.rb +7 -0
- data/lib/foreman_ansible/version.rb +1 -1
- data/package.json +40 -0
- data/test/fixtures/report.json +26 -0
- data/test/test_plugin_helper.rb +7 -3
- data/test/unit/concerns/config_reports_extensions_test.rb +23 -0
- data/test/unit/helpers/ansible_reports_helper_test.rb +46 -0
- data/test/unit/services/inventory_creator_test.rb +1 -18
- data/webpack/components/ReportJsonViewer.js +17 -0
- data/webpack/index.js +4 -0
- metadata +45 -6
- data/app/views/foreman_ansible/job_templates/ansible_roles.erb +0 -17
- data/test/unit/helpers/foreman_ansible/ansible_reports_helper_test.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11936ad8fbecb22faf149473256064f197414c8b
|
4
|
+
data.tar.gz: f54a4994feab57e29e2a974d04137be329105b5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6446ec9cb86573ed497ee010b2aa05b1e36b62e3cc9a9cd97afdfc2fd2df6620baed984339fa52f0cffe169b8ba1e38e7b3aff9f42a663e8ce3ed4ac0b89cb34
|
7
|
+
data.tar.gz: 3b188ae9c37bcc7a1921a5ac008263a03c55867b322c5c4bb71bb67bf2347d6feed7b73513ad8cf2ec1b53fd82ea2b397ea8ed1d1afc0e861f0b422bb5491fcf
|
@@ -2,29 +2,94 @@ module ForemanAnsible
|
|
2
2
|
# This module takes the config reports stored in Foreman for Ansible and
|
3
3
|
# modifies them to be properly presented in views
|
4
4
|
module AnsibleReportsHelper
|
5
|
-
|
6
|
-
|
5
|
+
ANSIBLE_META_KEYS = %w[
|
6
|
+
_ansible_parsed _ansible_no_log _ansible_item_result
|
7
|
+
_ansible_ignore_errors _ansible_verbose_always _ansible_verbose_override
|
8
|
+
].freeze
|
9
|
+
ANSIBLE_HIDDEN_KEYS = %w[
|
10
|
+
invocation module_args results ansible_facts
|
11
|
+
stdout stderr
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
def ansible_module_name(log)
|
15
|
+
source_value = log.source.value
|
16
|
+
name = source_value.split(':')[0].strip if source_value.include?(':')
|
17
|
+
name
|
7
18
|
end
|
8
19
|
|
9
|
-
def
|
10
|
-
|
20
|
+
def ansible_module_args(log)
|
21
|
+
report_json_viewer module_invocations parsed_message_json(log)
|
11
22
|
end
|
12
23
|
|
13
24
|
def ansible_module_message(log)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
25
|
+
report_json_viewer hash_with_keys_removed parsed_message_json(log)
|
26
|
+
end
|
27
|
+
|
28
|
+
def ansible_report_origin_icon
|
29
|
+
'foreman_ansible/Ansible.png'
|
30
|
+
end
|
31
|
+
|
32
|
+
def ansible_report_origin_partial
|
33
|
+
'foreman_ansible/config_reports/ansible'
|
21
34
|
end
|
22
35
|
|
23
36
|
def ansible_report?(log)
|
24
37
|
module_name(log).present?
|
25
|
-
# Failures when parsing the log indicates it's not an Ansible report
|
26
38
|
rescue StandardError
|
27
39
|
false
|
28
40
|
end
|
41
|
+
|
42
|
+
def report_json_viewer(json)
|
43
|
+
uid = "reportjson-viewer-#{json.object_id}"
|
44
|
+
viewer = content_tag :div, '', :id => uid
|
45
|
+
viewer << mount_react_component('ReportJsonViewer',
|
46
|
+
"##{uid}", json.to_json)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def module_invocations(hash)
|
52
|
+
invocations = []
|
53
|
+
invocations << hash.delete('invocation')
|
54
|
+
results = hash.delete('results')
|
55
|
+
invocations << results
|
56
|
+
invocations = invocations.compact.flatten.map do |ih|
|
57
|
+
ih.is_a?(Hash) ? remove_keys(ih) : ih
|
58
|
+
end
|
59
|
+
invocations
|
60
|
+
end
|
61
|
+
|
62
|
+
def pretty_print_hash(hash)
|
63
|
+
prettyp = JSON.pretty_generate(remove_keys(hash))
|
64
|
+
prettyp.gsub!(/{\n*/, "\n")
|
65
|
+
prettyp.gsub!(/},*\n*/, "\n")
|
66
|
+
prettyp.gsub!(/^(\[|\])/, '')
|
67
|
+
prettyp.gsub!(/^[\s]*$\n/, '')
|
68
|
+
paragraph_style = 'white-space:pre;padding: 2em 0'
|
69
|
+
content_tag(:p, prettyp, :style => paragraph_style)
|
70
|
+
end
|
71
|
+
|
72
|
+
def hash_with_keys_removed(hash)
|
73
|
+
new_hash = remove_keys(hash)
|
74
|
+
remove_keys(new_hash, ANSIBLE_HIDDEN_KEYS)
|
75
|
+
end
|
76
|
+
|
77
|
+
def remove_keys(hash, keys = ANSIBLE_META_KEYS)
|
78
|
+
hash.each do |key, value|
|
79
|
+
if value.is_a? Array
|
80
|
+
value.each { |h| remove_keys(h) if h.is_a? Hash }
|
81
|
+
elsif value.is_a? Hash
|
82
|
+
remove_keys(value)
|
83
|
+
end
|
84
|
+
hash.delete(key) if keys.include? key
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parsed_message_json(log)
|
89
|
+
JSON.parse(log.message.value)
|
90
|
+
rescue StandardError => e
|
91
|
+
logger.error e
|
92
|
+
false
|
93
|
+
end
|
29
94
|
end
|
30
95
|
end
|
@@ -63,6 +63,16 @@ class Setting
|
|
63
63
|
' it is ready after a reboot.'),
|
64
64
|
'360',
|
65
65
|
N_('Post-provision timeout')
|
66
|
+
),
|
67
|
+
set(
|
68
|
+
'top_level_ansible_vars',
|
69
|
+
N_('Whether to put Ansible parameters in the "hostvars" '\
|
70
|
+
'top-level key of the inventory. By default it is true, so '\
|
71
|
+
'that Host Parameters can be used directly in the playbooks.'\
|
72
|
+
'When false, Host Parameters can only be accessed through'\
|
73
|
+
'foreman_params["host_parameter"] in the playbooks.'),
|
74
|
+
true,
|
75
|
+
N_('Top level Ansible variables')
|
66
76
|
)
|
67
77
|
].compact.each do |s|
|
68
78
|
create(s.update(:category => 'Setting::Ansible'))
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
# Scans ConfigReports after import for indicators of an Ansible report and
|
3
|
+
# sets the origin of the report to 'Ansible'
|
4
|
+
class AnsibleReportScanner
|
5
|
+
class << self
|
6
|
+
def scan(report, logs)
|
7
|
+
if (is_ansible = ansible_report?(logs))
|
8
|
+
report.origin = 'Ansible'
|
9
|
+
end
|
10
|
+
is_ansible
|
11
|
+
end
|
12
|
+
|
13
|
+
def ansible_report?(logs)
|
14
|
+
logs.any? do |log|
|
15
|
+
log['log'].fetch('messages', {}).
|
16
|
+
fetch('message', '') =~ /"_ansible_parsed"/
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
if defined?(RedhatAccess)
|
2
|
+
module ForemanAnsible
|
3
|
+
# Fetch information about a plan from RH Insights and run it
|
4
|
+
class InsightsPlanRunner
|
5
|
+
include RedhatAccess::Telemetry::LookUps
|
6
|
+
|
7
|
+
def initialize(organization, plan_id)
|
8
|
+
@organization = organization
|
9
|
+
@plan_id = plan_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_playbook
|
13
|
+
rules = playbook
|
14
|
+
hostname_rules_relation = hostname_rules(rules)
|
15
|
+
hosts = hostname_rules_relation.keys.map do |hostname|
|
16
|
+
Host::Managed.find_by(:name => hostname)
|
17
|
+
end
|
18
|
+
|
19
|
+
composer = JobInvocationComposer.for_feature(
|
20
|
+
:ansible_run_insights_plan,
|
21
|
+
hosts,
|
22
|
+
:organization_id => @organization.id, :plan_id => @plan_id
|
23
|
+
)
|
24
|
+
composer.save
|
25
|
+
composer.trigger
|
26
|
+
end
|
27
|
+
|
28
|
+
# Fetches the playbook from the Red Hat Insights API
|
29
|
+
def playbook
|
30
|
+
resource = RestClient::Resource.new(
|
31
|
+
"#{insights_api_host}/r/insights/"\
|
32
|
+
"v3/maintenance/#{@plan_id}/playbook",
|
33
|
+
get_ssl_options_for_org(@organization, nil)
|
34
|
+
)
|
35
|
+
response = resource.get
|
36
|
+
YAML.safe_load(response.body)
|
37
|
+
end
|
38
|
+
|
39
|
+
# This method creates a hash like this:
|
40
|
+
# {
|
41
|
+
# hostname1 => [rule1,rule2,rule3],
|
42
|
+
# hostname2 => [rule1,rule3],
|
43
|
+
# }
|
44
|
+
#
|
45
|
+
# Rules are distinguished by name and saved without the 'hosts' field
|
46
|
+
# as it's irrelevant in the Foreman REX context ('hosts: all' is used
|
47
|
+
# so that all=job invocation targets)
|
48
|
+
def rules_to_hash(rules)
|
49
|
+
result = {}
|
50
|
+
rules.map do |rule|
|
51
|
+
rule['hosts'] = 'all'
|
52
|
+
result[rule['name']] = rule
|
53
|
+
end
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def hostname_rules(rules)
|
58
|
+
result = Hash.new { |h, k| h[k] = [] }
|
59
|
+
rules.each do |rule|
|
60
|
+
rule['hosts'].split(',').each do |host|
|
61
|
+
result[host] << rule['name']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -22,6 +22,7 @@ module ForemanAnsible
|
|
22
22
|
hosts = @hosts.map do |h|
|
23
23
|
RemoteExecutionProvider.find_ip_or_hostname(h)
|
24
24
|
end
|
25
|
+
|
25
26
|
{ 'all' => { 'hosts' => hosts,
|
26
27
|
'vars' => template_inputs(@template_invocation) },
|
27
28
|
'_meta' => { 'hostvars' => hosts_vars } }
|
@@ -36,11 +37,15 @@ module ForemanAnsible
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def host_vars(host)
|
39
|
-
{
|
40
|
+
result = {
|
40
41
|
'foreman' => host_attributes(host),
|
41
42
|
'foreman_params' => host_params(host),
|
42
43
|
'foreman_ansible_roles' => host_roles(host)
|
43
44
|
}.merge(connection_params(host))
|
45
|
+
if Setting['top_level_ansible_vars']
|
46
|
+
result = result.merge(host_params(host))
|
47
|
+
end
|
48
|
+
result
|
44
49
|
end
|
45
50
|
|
46
51
|
def connection_params(host)
|
@@ -89,7 +94,6 @@ module ForemanAnsible
|
|
89
94
|
'ansible_become' => @template_invocation.effective_user,
|
90
95
|
'ansible_user' => host_setting(host, 'remote_execution_ssh_user'),
|
91
96
|
'ansible_ssh_pass' => rex_ssh_password(host),
|
92
|
-
'ansible_ssh_private_key_file' => ansible_or_rex_ssh_private_key(host),
|
93
97
|
'ansible_port' => host_setting(host, 'remote_execution_ssh_port')
|
94
98
|
}
|
95
99
|
# Backward compatibility for Ansible 1.x
|
@@ -111,15 +115,6 @@ module ForemanAnsible
|
|
111
115
|
host_setting(host, 'remote_execution_ssh_password')
|
112
116
|
end
|
113
117
|
|
114
|
-
def ansible_or_rex_ssh_private_key(host)
|
115
|
-
ansible_private_file = host_setting(host, 'ansible_ssh_private_key_file')
|
116
|
-
if !ansible_private_file.empty?
|
117
|
-
ansible_private_file
|
118
|
-
else
|
119
|
-
ForemanRemoteExecutionCore.settings[:ssh_identity_key_file]
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
118
|
private
|
124
119
|
|
125
120
|
def render_rabl(host, template)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ForemanAnsible
|
2
|
+
# Macro to fetch RH Insights plan playbook
|
3
|
+
module RendererMethods
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def insights_remediation(plan_id, organization_id = Organization.current.id)
|
7
|
+
insights_plan = ForemanAnsible::InsightsPlanRunner.new(
|
8
|
+
Organization.find(organization_id),
|
9
|
+
plan_id
|
10
|
+
)
|
11
|
+
rules = insights_plan.playbook
|
12
|
+
hostname_rules_relation = insights_plan.hostname_rules(rules)
|
13
|
+
global_rules = insights_plan.rules_to_hash(rules)
|
14
|
+
host_playbooks = hostname_rules_relation[@host.name].
|
15
|
+
reduce([]) do |acc, cur|
|
16
|
+
acc << global_rules[cur]
|
17
|
+
end
|
18
|
+
host_playbooks.to_yaml
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
<%=
|
2
|
-
if hostgroup.all_ansible_roles.empty?
|
2
|
+
play_roles = if hostgroup.all_ansible_roles.empty?
|
3
|
+
"<a title='No Roles assigned' href=\"#\">#{_('Play Roles')}</a>".html_safe
|
4
|
+
else
|
5
|
+
display_link_if_authorized(_('Play Roles'), hash_for_play_roles_hostgroup_path(:id => hostgroup), :'data-no-turbolink' => true)
|
6
|
+
end
|
7
|
+
|
3
8
|
action_buttons(
|
4
9
|
display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)),
|
5
10
|
display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup)),
|
11
|
+
play_roles,
|
6
12
|
display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :data => { :confirm => warning_message(hostgroup) }))
|
7
|
-
else
|
8
|
-
action_buttons(
|
9
|
-
display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)),
|
10
|
-
display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup)),
|
11
|
-
display_link_if_authorized(_('Play Roles'), hash_for_play_roles_hostgroup_path(:id => hostgroup), :'data-no-turbolink' => true),
|
12
|
-
display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :data => { :confirm => warning_message(hostgroup) }))
|
13
|
-
end
|
14
13
|
%>
|
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
<%= webpacked_plugins_js_for :foreman_ansible %>
|
2
|
+
<%= stylesheet 'foreman_ansible/foreman-ansible' %>
|
3
|
+
|
4
|
+
<table id='report_log' class="<%= table_css_classes %>">
|
2
5
|
<thead>
|
3
6
|
<tr>
|
4
7
|
<th><%= _("Level") %></th>
|
@@ -11,8 +14,8 @@
|
|
11
14
|
<% logs.each do |log| %>
|
12
15
|
<tr>
|
13
16
|
<td><span <%= report_tag log.level %>><%= h log.level %></span></td>
|
14
|
-
<td><%=
|
15
|
-
<td><%=
|
17
|
+
<td><%= ansible_module_name(log) %></td>
|
18
|
+
<td><%= ansible_module_args(log) %></td>
|
16
19
|
<td><%= ansible_module_message(log) %></td>
|
17
20
|
</tr>
|
18
21
|
<% end %>
|
@@ -3,7 +3,6 @@ We parse a few parts of the report log, to check if it's an Ansible report
|
|
3
3
|
An alternative to this would be to subclass Ansible < ConfigReport and change
|
4
4
|
the API endpoint at api/v2/config_reports to accept a :type argument with the
|
5
5
|
config management system type.
|
6
|
-
|
7
6
|
However, that solution breaks compatibility of this plugin with older versions
|
8
7
|
of Foreman that do not have that endpoint.
|
9
8
|
-->
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%#
|
2
|
+
name: Ansible Roles - Ansible Default
|
3
|
+
job_category: Ansible Playbook
|
4
|
+
description_format: Run Ansible roles
|
5
|
+
feature: ansible_run_host
|
6
|
+
snippet: false
|
7
|
+
provider_type: Ansible
|
8
|
+
kind: job_template
|
9
|
+
model: JobTemplate
|
10
|
+
%>
|
11
|
+
|
12
|
+
---
|
13
|
+
- hosts: all
|
14
|
+
tasks:
|
15
|
+
- name: Display all parameters known for the Foreman host
|
16
|
+
debug:
|
17
|
+
var: foreman_params
|
18
|
+
roles:
|
19
|
+
<%- if @host.all_ansible_roles.present? -%>
|
20
|
+
<%= @host.all_ansible_roles.map { |role| " - #{role.name.strip}" }.join("\n") %>
|
21
|
+
<%- end -%>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%#
|
2
|
+
name: Ansible Roles - Install from Galaxy
|
3
|
+
job_category: Ansible Galaxy
|
4
|
+
description_format: Install roles '%{ansible_roles_list}' from Galaxy
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: ansible_roles_list
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: "List of roles in Ansible Galaxy to install, separated by commas, e.g:
|
11
|
+
\"mysql, nginx\"\r\n\r\nThe default location is the 'roles_path' configured on
|
12
|
+
/etc/ansible/ansible.cfg, you may override it by filling the 'location' input.
|
13
|
+
Click on \"Advanced\" to see it."
|
14
|
+
advanced: false
|
15
|
+
- name: location
|
16
|
+
required: false
|
17
|
+
input_type: user
|
18
|
+
description: A particular directory where you want the downloaded roles to be placed.
|
19
|
+
advanced: true
|
20
|
+
provider_type: Ansible
|
21
|
+
kind: job_template
|
22
|
+
model: JobTemplate
|
23
|
+
%>
|
24
|
+
|
25
|
+
---
|
26
|
+
- hosts: all
|
27
|
+
tasks:
|
28
|
+
- command: ansible-galaxy install {{ item }} <% "-p #{input('location')}" if input('location').present? %>
|
29
|
+
register: out
|
30
|
+
with_items:
|
31
|
+
- <%= input('ansible_roles_list') %>
|
32
|
+
- debug: var=out
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<%#
|
2
|
+
name: Ansible Roles - Install from git
|
3
|
+
job_category: Ansible Roles Installation
|
4
|
+
description_format: Clone roles from git repository to %{location}
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: git_repository
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: "URL to the git repository containing the roles, e.g:\r\nhttps://github.com/theforeman/foreman_role_1"
|
11
|
+
advanced: false
|
12
|
+
- name: location
|
13
|
+
required: true
|
14
|
+
input_type: user
|
15
|
+
description: For example, '/etc/ansible/roles/foobar' . Look at '/etc/ansible/ansible.cfg'
|
16
|
+
roles_path option to find what is your roles_path
|
17
|
+
advanced: false
|
18
|
+
provider_type: Ansible
|
19
|
+
kind: job_template
|
20
|
+
model: JobTemplate
|
21
|
+
%>
|
22
|
+
|
23
|
+
---
|
24
|
+
- hosts: all
|
25
|
+
tasks:
|
26
|
+
- command: git clone <%= input('git_repository') %> <%= input('location') %>
|
27
|
+
register: out
|
28
|
+
- debug: var=out
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%#
|
2
|
+
kind: job_template
|
3
|
+
name: Ansible - Run insights maintenance plan
|
4
|
+
job_category: Ansible Playbook
|
5
|
+
description_format: 'Insights maintenance plan for host'
|
6
|
+
feature: ansible_run_insights_plan
|
7
|
+
template_inputs:
|
8
|
+
- name: plan_id
|
9
|
+
description: The playbook for the rule coming from insights.
|
10
|
+
input_type: user
|
11
|
+
required: true
|
12
|
+
- name: organization_id
|
13
|
+
description: The Foreman organization associated with the Insights account
|
14
|
+
input_type: user
|
15
|
+
required: true
|
16
|
+
provider_type: Ansible
|
17
|
+
%>
|
18
|
+
|
19
|
+
<%= insights_remediation(input(:plan_id), input(:organization_id)) %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<%#
|
2
|
+
name: Package Action - Ansible Default
|
3
|
+
job_category: Ansible Packages
|
4
|
+
description_format: 'Package %{name}: %{state}'
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: state
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: Whether to install (present, latest), or remove (absent) a package.
|
11
|
+
options: "present\r\nabsent\r\nlatest"
|
12
|
+
advanced: false
|
13
|
+
- name: name
|
14
|
+
required: true
|
15
|
+
input_type: user
|
16
|
+
description: "Package name, or package specifier with version, like name-1.0.\r\nBe
|
17
|
+
aware that packages are not always named the same and this module will not 'translate'
|
18
|
+
them per distro."
|
19
|
+
advanced: false
|
20
|
+
- name: pre_script
|
21
|
+
description: A script to run prior to the package action
|
22
|
+
input_type: user
|
23
|
+
required: false
|
24
|
+
advanced: true
|
25
|
+
- name: post_script
|
26
|
+
description: A script to run after the package action
|
27
|
+
input_type: user
|
28
|
+
required: false
|
29
|
+
advanced: true
|
30
|
+
provider_type: Ansible
|
31
|
+
kind: job_template
|
32
|
+
model: JobTemplate
|
33
|
+
%>
|
34
|
+
|
35
|
+
# For Windows targets use the win_package module instead.
|
36
|
+
---
|
37
|
+
- hosts: all
|
38
|
+
pre_tasks:
|
39
|
+
- shell: "<%= input('pre_script') %>"
|
40
|
+
tasks:
|
41
|
+
- package:
|
42
|
+
name: <%= input('name') %>
|
43
|
+
state: <%= input('state') %>
|
44
|
+
post_tasks:
|
45
|
+
- shell: "<%= input('post_script') %>"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<%#
|
2
|
+
name: Power Action - Ansible Default
|
3
|
+
job_category: Power
|
4
|
+
description_format: "%{action} host"
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: action
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: Action to perform on the service
|
11
|
+
options: "restart\r\nshutdown"
|
12
|
+
advanced: false
|
13
|
+
provider_type: Ansible
|
14
|
+
kind: job_template
|
15
|
+
model: JobTemplate
|
16
|
+
%>
|
17
|
+
|
18
|
+
---
|
19
|
+
- hosts: all
|
20
|
+
tasks:
|
21
|
+
- command: |
|
22
|
+
echo <%= input('action') %> host && sleep 3
|
23
|
+
<%= case input('action')
|
24
|
+
when 'restart'
|
25
|
+
'reboot'
|
26
|
+
else
|
27
|
+
'shutdown -h now'
|
28
|
+
end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%#
|
2
|
+
name: Puppet Run Once - Ansible Default
|
3
|
+
job_category: Puppet
|
4
|
+
description_format: 'Run Puppet once with "%{puppet_options}"'
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: puppet_options
|
8
|
+
required: false
|
9
|
+
input_type: user
|
10
|
+
description: Additional options to pass to Puppet
|
11
|
+
advanced: false
|
12
|
+
provider_type: Ansible
|
13
|
+
kind: job_template
|
14
|
+
model: JobTemplate
|
15
|
+
%>
|
16
|
+
|
17
|
+
---
|
18
|
+
- hosts: all
|
19
|
+
tasks:
|
20
|
+
- command: |
|
21
|
+
puppet agent --onetime --no-usecacheonfailure --no-daemonize <%= input("puppet_options") %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%#
|
2
|
+
name: Run Command - Ansible Default
|
3
|
+
job_category: Ansible Commands
|
4
|
+
description_format: Run %{command}
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: command
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: "Command to run on the host, e.g: \r\n\r\nmkdir helloworld"
|
11
|
+
advanced: false
|
12
|
+
provider_type: Ansible
|
13
|
+
kind: job_template
|
14
|
+
model: JobTemplate
|
15
|
+
%>
|
16
|
+
|
17
|
+
---
|
18
|
+
- hosts: all
|
19
|
+
tasks:
|
20
|
+
- command: <%= input('command') %>
|
21
|
+
register: out
|
22
|
+
- debug: var=out
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<%#
|
2
|
+
name: Service Action - Ansible Default
|
3
|
+
job_category: Ansible Service
|
4
|
+
description_format: "%{state} service %{name}"
|
5
|
+
snippet: false
|
6
|
+
template_inputs:
|
7
|
+
- name: state
|
8
|
+
required: true
|
9
|
+
input_type: user
|
10
|
+
description: started/stopped are idempotent actions that will not run commands unless
|
11
|
+
necessary. restarted will always bounce the service. reloaded will always reload.
|
12
|
+
At least one of state and enabled are required. Note that reloaded will start
|
13
|
+
the service if it is not already started, even if your chosen init system wouldn't
|
14
|
+
normally.
|
15
|
+
options: "started\r\nstopped\r\nrestarted\r\nreloaded"
|
16
|
+
advanced: false
|
17
|
+
- name: name
|
18
|
+
required: true
|
19
|
+
input_type: user
|
20
|
+
description: Name of the service.
|
21
|
+
advanced: false
|
22
|
+
- name: pattern
|
23
|
+
required: false
|
24
|
+
input_type: user
|
25
|
+
description: If the service does not respond to the status command, name a substring
|
26
|
+
to look for as would be found in the output of the ps command as a stand-in for
|
27
|
+
a status result. If the string is found, the service will be assumed to be running.
|
28
|
+
advanced: true
|
29
|
+
- name: sleep
|
30
|
+
required: false
|
31
|
+
input_type: user
|
32
|
+
description: If the service is being restarted then sleep this many seconds between
|
33
|
+
the stop and start command. This helps to workaround badly behaving init scripts
|
34
|
+
that exit immediately after signaling a process to stop.
|
35
|
+
advanced: true
|
36
|
+
- name: enabled
|
37
|
+
required: false
|
38
|
+
input_type: user
|
39
|
+
description: Whether the service should start on boot.
|
40
|
+
advanced: true
|
41
|
+
- name: args
|
42
|
+
required: false
|
43
|
+
input_type: user
|
44
|
+
description: Additional arguments provided on the command line
|
45
|
+
advanced: true
|
46
|
+
provider_type: Ansible
|
47
|
+
kind: job_template
|
48
|
+
model: JobTemplate
|
49
|
+
%>
|
50
|
+
|
51
|
+
# For Windows targets, we should use win_service
|
52
|
+
---
|
53
|
+
- hosts: all
|
54
|
+
tasks:
|
55
|
+
- service:
|
56
|
+
name: <%= input('name') %>
|
57
|
+
state: <%= input('state') %>
|
58
|
+
<%= "enabled: #{input('enabled')}" if input('enabled').present? %>
|
59
|
+
<%= "args: #{input('args')}" if input('args').present? %>
|
60
|
+
<%= "pattern: #{input('pattern')}" if input('pattern').present? %>
|
61
|
+
<%= "sleep: #{input('sleep')}" if input('sleep').present? %>
|
@@ -56,7 +56,8 @@ module ForemanAnsible
|
|
56
56
|
initializer 'foreman_ansible.configure_assets', :group => :assets do
|
57
57
|
SETTINGS[:foreman_ansible] = {
|
58
58
|
:assets => {
|
59
|
-
:precompile => ['foreman_ansible/Ansible.png'
|
59
|
+
:precompile => ['foreman_ansible/Ansible.png',
|
60
|
+
'foreman_ansible/foreman-ansible.css']
|
60
61
|
}
|
61
62
|
}
|
62
63
|
end
|
@@ -109,4 +110,5 @@ module ForemanAnsible
|
|
109
110
|
end
|
110
111
|
end
|
111
112
|
end
|
113
|
+
# rubocop:enable ClassLength
|
112
114
|
end
|
@@ -33,6 +33,8 @@ Foreman::Plugin.register :foreman_ansible do
|
|
33
33
|
:import_ansible_roles]
|
34
34
|
|
35
35
|
add_all_permissions_to_default_roles
|
36
|
+
extend_template_helpers ForemanAnsible::RendererMethods
|
37
|
+
allowed_template_helpers :insights_remediation
|
36
38
|
|
37
39
|
role_assignment_params = { :ansible_role_ids => [],
|
38
40
|
:ansible_roles => [] }
|
@@ -48,5 +50,10 @@ Foreman::Plugin.register :foreman_ansible do
|
|
48
50
|
apipie_documented_controllers [
|
49
51
|
"#{ForemanAnsible::Engine.root}/app/controllers/api/v2/*.rb"
|
50
52
|
]
|
53
|
+
|
54
|
+
# For backwards compatiblity with 1.17
|
55
|
+
if respond_to?(:register_report_scanner)
|
56
|
+
register_report_scanner ForemanAnsible::AnsibleReportScanner
|
57
|
+
end
|
51
58
|
end
|
52
59
|
# rubocop:enable BlockLength
|
@@ -17,6 +17,13 @@ module ForemanAnsible
|
|
17
17
|
:description => N_('Runs an Ansible playbook which contains all'\
|
18
18
|
' the roles defined for a host')
|
19
19
|
)
|
20
|
+
RemoteExecutionFeature.register(
|
21
|
+
:ansible_run_insights_plan,
|
22
|
+
N_('Ansible: Run Insights maintenance plan'),
|
23
|
+
:description => N_('Runs a given maintenance plan from Red Hat '\
|
24
|
+
'Access Insights given an ID.'),
|
25
|
+
:provided_inputs => %w[organization_id plan_id]
|
26
|
+
)
|
20
27
|
end
|
21
28
|
end
|
22
29
|
end
|
data/package.json
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"name": "foreman_ansible",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "[](https://codeclimate.com/github/theforeman/foreman_ansible) [](https://badge.fury.io/rb/foreman_ansible) [](https://github.com/theforeman/foreman_ansible/blob/master/LICENSE)",
|
5
|
+
"main": "index.js",
|
6
|
+
"directories": {
|
7
|
+
"test": "test"
|
8
|
+
},
|
9
|
+
"dependencies": {
|
10
|
+
"react-json-tree": "^0.11.0"
|
11
|
+
},
|
12
|
+
"devDependencies": {
|
13
|
+
"babel-eslint": "^8.2.1",
|
14
|
+
"babel-preset-env": "^1.6.0",
|
15
|
+
"babel-preset-react": "^6.24.1",
|
16
|
+
"babel-plugin-lodash": "^3.3.2",
|
17
|
+
"babel-plugin-transform-object-assign": "^6.22.0",
|
18
|
+
"babel-plugin-transform-class-properties": "^6.24.1",
|
19
|
+
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
20
|
+
"eslint": "^4.18.1",
|
21
|
+
"eslint-config-airbnb": "^16.0.0",
|
22
|
+
"eslint-plugin-import": "^2.8.0",
|
23
|
+
"eslint-plugin-jest": "^21.2.0",
|
24
|
+
"eslint-plugin-jsx-a11y": "^6.0.2",
|
25
|
+
"eslint-plugin-react": "^7.4.0"
|
26
|
+
},
|
27
|
+
"scripts": {
|
28
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
29
|
+
},
|
30
|
+
"repository": {
|
31
|
+
"type": "git",
|
32
|
+
"url": "git+https://github.com/bastilian/foreman_ansible.git"
|
33
|
+
},
|
34
|
+
"author": "",
|
35
|
+
"license": "ISC",
|
36
|
+
"bugs": {
|
37
|
+
"url": "https://github.com/bastilian/foreman_ansible/issues"
|
38
|
+
},
|
39
|
+
"homepage": "https://github.com/bastilian/foreman_ansible#readme"
|
40
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"reported_at":"2018-01-15 17:31:36 521275",
|
3
|
+
"metrics": {
|
4
|
+
"time":
|
5
|
+
{ "total":37 }
|
6
|
+
},
|
7
|
+
"host": "io.local",
|
8
|
+
"status": {
|
9
|
+
"applied": 0,
|
10
|
+
"failed": 0,
|
11
|
+
"skipped": 0
|
12
|
+
},
|
13
|
+
"logs": [
|
14
|
+
{
|
15
|
+
"log": {
|
16
|
+
"sources": {
|
17
|
+
"source": "common : Install Common packages"
|
18
|
+
},
|
19
|
+
"messages": {
|
20
|
+
"message": "{\"msg\": \"All items completed\", \"changed\": false, \"results\": [{\"_ansible_parsed\": true, \"changed\": false, \"_ansible_no_log\": false, \"cache_updated\": false, \"_ansible_item_result\": true, \"failed\": false, \"item\": \"git\", \"invocation\": {\"module_args\": {\"dpkg_options\": \"force-confdef,force-confold\", \"upgrade\": null, \"force\": false, \"force_apt_get\": false, \"package\": [\"git\"], \"autoclean\": false, \"name\": \"git\", \"purge\": false, \"allow_unauthenticated\": false, \"state\": \"present\", \"autoremove\": false, \"update_cache\": null, \"default_release\": null, \"only_upgrade\": false, \"cache_valid_time\": 0, \"deb\": null, \"install_recommends\": null}}, \"_ansible_ignore_errors\": null, \"cache_update_time\": 1515797094}, {\"_ansible_parsed\": true, \"changed\": false, \"_ansible_no_log\": false, \"cache_updated\": false, \"_ansible_item_result\": true, \"failed\": false, \"item\": \"htop\", \"invocation\": {\"module_args\": {\"dpkg_options\": \"force-confdef,force-confold\", \"upgrade\": null, \"force\": false, \"force_apt_get\": false, \"package\": [\"htop\"], \"autoclean\": false, \"name\": \"htop\", \"purge\": false, \"allow_unauthenticated\": false, \"state\": \"present\", \"autoremove\": false, \"update_cache\": null, \"default_release\": null, \"only_upgrade\": false, \"cache_valid_time\": 0, \"deb\": null, \"install_recommends\": null}}, \"_ansible_ignore_errors\": null, \"cache_update_time\": 1515797094}, {\"_ansible_parsed\": true, \"changed\": false, \"_ansible_no_log\": false, \"cache_updated\": false, \"_ansible_item_result\": true, \"failed\": false, \"item\": \"zsh\", \"invocation\": {\"module_args\": {\"dpkg_options\": \"force-confdef,force-confold\", \"upgrade\": null, \"force\": false, \"force_apt_get\": false, \"package\": [\"zsh\"], \"autoclean\": false, \"name\": \"zsh\", \"purge\": false, \"allow_unauthenticated\": false, \"state\": \"present\", \"autoremove\": false, \"update_cache\": null, \"default_release\": null, \"only_upgrade\": false, \"cache_valid_time\": 0, \"deb\": null, \"install_recommends\": null}}, \"_ansible_ignore_errors\": null, \"cache_update_time\": 1515797094}]}"},"level":"info"}},{"log":{"sources":{"source":"common : Copy default motd"},"messages":{"message":"{\"_ansible_parsed\": true, \"group\": \"root\", \"uid\": 0, \"checksum\": \"0a381ff6a86081af6dc957a77c7e2017a3244c4c\", \"changed\": false, \"owner\": \"root\", \"state\": \"file\", \"gid\": 0, \"mode\": \"0644\", \"diff\": {\"after\": {\"path\": \"/etc/motd\"}, \"before\": {\"path\": \"/etc/motd\"}}, \"invocation\": {\"module_args\": {\"directory_mode\": null, \"force\": false, \"remote_src\": null, \"path\": \"/etc/motd\", \"owner\": \"root\", \"follow\": false, \"group\": \"root\", \"unsafe_writes\": null, \"state\": \"file\", \"content\": null, \"serole\": null, \"diff_peek\": null, \"setype\": null, \"dest\": \"/etc/motd\", \"selevel\": null, \"original_basename\": \"motd.txt\", \"regexp\": null, \"validate\": null, \"src\": \"motd.txt\", \"seuser\": null, \"recurse\": false, \"delimiter\": null, \"mode\": null, \"attributes\": null, \"backup\": null}}, \"path\": \"/etc/motd\", \"size\": 1090, \"_ansible_no_log\": false}"
|
21
|
+
},
|
22
|
+
"level": "info"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
]
|
26
|
+
}
|
data/test/test_plugin_helper.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
require 'facets'
|
3
3
|
|
4
|
+
def ansible_fixture_file(filename)
|
5
|
+
File.join(
|
6
|
+
ForemanAnsible::Engine.root, 'test', 'fixtures', filename
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
4
10
|
def sample_facts_file
|
5
11
|
File.read(
|
6
|
-
|
7
|
-
ForemanAnsible::Engine.root, 'test', 'fixtures', 'sample_facts.json'
|
8
|
-
)
|
12
|
+
ansible_fixture_file('sample_facts.json')
|
9
13
|
)
|
10
14
|
end
|
11
15
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
|
3
|
+
# Tests for the behavior of Host with roles, checks inheritance, etc
|
4
|
+
class ConfigReportExtensionsTest < ActiveSupport::TestCase
|
5
|
+
let(:example_report) do
|
6
|
+
JSON.parse(File.read(ansible_fixture_file('report.json')))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.import' do
|
10
|
+
it 'sets an origin for Ansible reports' do
|
11
|
+
report = ConfigReport.import(example_report)
|
12
|
+
assert_equal 'Ansible', report.origin
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'sets no origin for other reports' do
|
16
|
+
report = ConfigReport.import(
|
17
|
+
'host' => 'io.local',
|
18
|
+
'reported_at' => Time.now.utc.to_s
|
19
|
+
)
|
20
|
+
assert_nil report.origin
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_plugin_helper'
|
2
|
+
|
3
|
+
class AnsibleReportsHelperTest < ActiveSupport::TestCase
|
4
|
+
include ForemanAnsible::AnsibleReportsHelper
|
5
|
+
include ActionView::Helpers::TagHelper
|
6
|
+
|
7
|
+
test 'is able to print a string instead of a hash' do
|
8
|
+
log_value = <<-ANSIBLELOG.strip_heredoc
|
9
|
+
{"_ansible_parsed": true, "_ansible_no_log": false, "changed": false, "results": ["ntp-4.2.8p10-3.fc27.x86_64 providing ntp is already installed"], "rc": 0, "invocation": {"module_args": {"allow_downgrade": false, "name": ["ntp"], "list": null, "disable_gpg_check": false, "conf_file": null, "install_repoquery": true, "state": "installed", "disablerepo": null, "update_cache": false, "enablerepo": null, "exclude": null, "security": false, "validate_certs": true, "installroot": "/", "skip_broken": false}}, "msg": ""}
|
10
|
+
ANSIBLELOG
|
11
|
+
message = FactoryBot.build(:message)
|
12
|
+
message.value = log_value
|
13
|
+
log = FactoryBot.build(:log)
|
14
|
+
log.message = message
|
15
|
+
assert_match(
|
16
|
+
/ntp-4.2.8p10-3.fc27.x86_64 providing ntp is already installed/,
|
17
|
+
module_invocations(parsed_message_json(log)).to_s
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
test 'pretty print is able to print a hash' do
|
22
|
+
hash = {
|
23
|
+
'allow_downgrade' => false,
|
24
|
+
'name' => ['ntp'],
|
25
|
+
'list' => nil,
|
26
|
+
'disable_gpg_check' => false,
|
27
|
+
'conf_file' => nil,
|
28
|
+
'install_repoquery' => true,
|
29
|
+
'state' => 'installed',
|
30
|
+
'disablerepo' => nil,
|
31
|
+
'update_cache' => false,
|
32
|
+
'enablerepo' => nil,
|
33
|
+
'exclude' => nil,
|
34
|
+
'security' => false,
|
35
|
+
'validate_certs' => true,
|
36
|
+
'installroot' => '/',
|
37
|
+
'skip_broken' => false
|
38
|
+
}
|
39
|
+
assert_equal(
|
40
|
+
hash,
|
41
|
+
remove_keys(
|
42
|
+
hash
|
43
|
+
)
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
@@ -25,6 +25,7 @@ module ForemanAnsible
|
|
25
25
|
@host.expects(:host_params).returns(extra_options).at_least_once
|
26
26
|
inventory = ForemanAnsible::InventoryCreator.new(@host,
|
27
27
|
@template_invocation)
|
28
|
+
|
28
29
|
assert_empty extra_options.to_a - inventory.connection_params(@host).to_a
|
29
30
|
end
|
30
31
|
|
@@ -61,8 +62,6 @@ module ForemanAnsible
|
|
61
62
|
connection_params['ansible_user']
|
62
63
|
refute_equal Setting['remote_execution_ssh_port'],
|
63
64
|
connection_params['ansible_port']
|
64
|
-
assert_equal ForemanRemoteExecutionCore.settings[:ssh_identity_key_file],
|
65
|
-
connection_params['ansible_ssh_private_key_file']
|
66
65
|
assert_equal extra_options['ansible_port'],
|
67
66
|
connection_params['ansible_port']
|
68
67
|
assert_equal Setting['remote_execution_ssh_password'],
|
@@ -78,22 +77,6 @@ module ForemanAnsible
|
|
78
77
|
inventory.rex_ssh_password(@host))
|
79
78
|
end
|
80
79
|
|
81
|
-
test 'ssh private key is passed when available' do
|
82
|
-
host = FactoryBot.build(:host)
|
83
|
-
path_to_key = '/path/to/private/key'
|
84
|
-
inventory = ForemanAnsible::InventoryCreator.new(host,
|
85
|
-
@template_invocation)
|
86
|
-
host.params.expects(:[]).with('ansible_ssh_private_key_file')
|
87
|
-
.returns(path_to_key)
|
88
|
-
host.params.expects(:[]).with('remote_execution_ssh_user')
|
89
|
-
.returns('root')
|
90
|
-
host.params.expects(:[]).with('remote_execution_ssh_port')
|
91
|
-
.returns('2222')
|
92
|
-
connection_params = inventory.connection_params(host)
|
93
|
-
assert_equal path_to_key,
|
94
|
-
connection_params['ansible_ssh_private_key_file']
|
95
|
-
end
|
96
|
-
|
97
80
|
test 'template invocation inputs are sent as Ansible variables' do
|
98
81
|
job_template = FactoryBot.build(
|
99
82
|
:job_template,
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import JSONTree from 'react-json-tree';
|
3
|
+
|
4
|
+
const theme = {
|
5
|
+
scheme: 'foreman',
|
6
|
+
backgroundColor: 'rgba(0, 0, 0, 255)',
|
7
|
+
base00: 'rgba(0, 0, 0, 0)',
|
8
|
+
};
|
9
|
+
|
10
|
+
class ReportJsonViewer extends React.Component {
|
11
|
+
render() {
|
12
|
+
return <div className="report-json-viewer">
|
13
|
+
<JSONTree data={this.props.data} hideRoot theme={theme} />
|
14
|
+
</div>;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
export default ReportJsonViewer;
|
data/webpack/index.js
ADDED
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: 2.0
|
4
|
+
version: 2.1.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: 2018-
|
11
|
+
date: 2018-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "<"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dynflow
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.14
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.14
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: foreman-tasks
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +59,9 @@ dependencies:
|
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '0.8'
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0.12'
|
48
65
|
type: :runtime
|
49
66
|
prerelease: false
|
50
67
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -52,6 +69,9 @@ dependencies:
|
|
52
69
|
- - "~>"
|
53
70
|
- !ruby/object:Gem::Version
|
54
71
|
version: '0.8'
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.12'
|
55
75
|
- !ruby/object:Gem::Dependency
|
56
76
|
name: foreman_ansible_core
|
57
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,6 +117,7 @@ files:
|
|
97
117
|
- README.md
|
98
118
|
- Rakefile
|
99
119
|
- app/assets/images/foreman_ansible/Ansible.png
|
120
|
+
- app/assets/stylesheets/foreman_ansible/foreman-ansible.css
|
100
121
|
- app/controllers/ansible_roles_controller.rb
|
101
122
|
- app/controllers/api/v2/ansible_roles_controller.rb
|
102
123
|
- app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb
|
@@ -124,13 +145,16 @@ files:
|
|
124
145
|
- app/overrides/hostgroup_ansible_roles_tab.rb
|
125
146
|
- app/overrides/hostgroup_play_roles.rb
|
126
147
|
- app/overrides/report_output.rb
|
148
|
+
- app/services/foreman_ansible/ansible_report_scanner.rb
|
127
149
|
- app/services/foreman_ansible/api_roles_importer.rb
|
128
150
|
- app/services/foreman_ansible/fact_importer.rb
|
129
151
|
- app/services/foreman_ansible/fact_parser.rb
|
130
152
|
- app/services/foreman_ansible/fact_sparser.rb
|
153
|
+
- app/services/foreman_ansible/insights_plan_runner.rb
|
131
154
|
- app/services/foreman_ansible/inventory_creator.rb
|
132
155
|
- app/services/foreman_ansible/playbook_creator.rb
|
133
156
|
- app/services/foreman_ansible/proxy_selector.rb
|
157
|
+
- app/services/foreman_ansible/renderer_methods.rb
|
134
158
|
- app/services/foreman_ansible/roles_importer.rb
|
135
159
|
- app/services/foreman_ansible/structured_fact_importer.rb
|
136
160
|
- app/services/foreman_ansible/ui_roles_importer.rb
|
@@ -150,7 +174,15 @@ files:
|
|
150
174
|
- app/views/foreman_ansible/api/v2/ansible_roles/show.json.rabl
|
151
175
|
- app/views/foreman_ansible/config_reports/_ansible.html.erb
|
152
176
|
- app/views/foreman_ansible/config_reports/_output.html.erb
|
153
|
-
- app/views/foreman_ansible/job_templates/
|
177
|
+
- app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb
|
178
|
+
- app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_galaxy.erb
|
179
|
+
- app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb
|
180
|
+
- app/views/foreman_ansible/job_templates/maintenance_plan.erb
|
181
|
+
- app/views/foreman_ansible/job_templates/package_action_-_ansible_default.erb
|
182
|
+
- app/views/foreman_ansible/job_templates/power_action_-_ansible_default.erb
|
183
|
+
- app/views/foreman_ansible/job_templates/puppet_run_once_-_ansible_default.erb
|
184
|
+
- app/views/foreman_ansible/job_templates/run_command_-_ansible_default.erb
|
185
|
+
- app/views/foreman_ansible/job_templates/service_action_-_ansible_default.erb
|
154
186
|
- config/routes.rb
|
155
187
|
- db/migrate/20160705082036_create_ansible_role.rb
|
156
188
|
- db/migrate/20160706074540_create_join_table_hosts_ansible_roles.rb
|
@@ -170,8 +202,10 @@ files:
|
|
170
202
|
- locale/en/foreman_ansible.po
|
171
203
|
- locale/foreman_ansible.pot
|
172
204
|
- locale/gemspec.rb
|
205
|
+
- package.json
|
173
206
|
- test/factories/ansible_proxy.rb
|
174
207
|
- test/factories/ansible_roles.rb
|
208
|
+
- test/fixtures/report.json
|
175
209
|
- test/fixtures/sample_facts.json
|
176
210
|
- test/functional/ansible_roles_controller_test.rb
|
177
211
|
- test/functional/api/v2/ansible_roles_controller_test.rb
|
@@ -182,9 +216,10 @@ files:
|
|
182
216
|
- test/unit/actions/run_ansible_job_test.rb
|
183
217
|
- test/unit/actions/run_proxy_ansible_command_test.rb
|
184
218
|
- test/unit/ansible_role_test.rb
|
219
|
+
- test/unit/concerns/config_reports_extensions_test.rb
|
185
220
|
- test/unit/concerns/host_managed_extensions_test.rb
|
186
221
|
- test/unit/concerns/hostgroup_extensions_test.rb
|
187
|
-
- test/unit/helpers/
|
222
|
+
- test/unit/helpers/ansible_reports_helper_test.rb
|
188
223
|
- test/unit/host_ansible_role_test.rb
|
189
224
|
- test/unit/hostgroup_ansible_role_test.rb
|
190
225
|
- test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
|
@@ -199,6 +234,8 @@ files:
|
|
199
234
|
- test/unit/services/roles_importer_test.rb
|
200
235
|
- test/unit/services/structured_fact_importer_test.rb
|
201
236
|
- test/unit/services/ui_roles_importer_test.rb
|
237
|
+
- webpack/components/ReportJsonViewer.js
|
238
|
+
- webpack/index.js
|
202
239
|
homepage: https://github.com/theforeman/foreman_ansible
|
203
240
|
licenses:
|
204
241
|
- GPL-3.0
|
@@ -232,6 +269,7 @@ test_files:
|
|
232
269
|
- test/functional/ansible_roles_controller_test.rb
|
233
270
|
- test/functional/hosts_controller_test.rb
|
234
271
|
- test/unit/ansible_role_test.rb
|
272
|
+
- test/unit/concerns/config_reports_extensions_test.rb
|
235
273
|
- test/unit/concerns/host_managed_extensions_test.rb
|
236
274
|
- test/unit/concerns/hostgroup_extensions_test.rb
|
237
275
|
- test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
|
@@ -241,15 +279,16 @@ test_files:
|
|
241
279
|
- test/unit/services/fact_importer_test.rb
|
242
280
|
- test/unit/services/fact_parser_test.rb
|
243
281
|
- test/unit/services/fact_sparser_test.rb
|
282
|
+
- test/unit/services/inventory_creator_test.rb
|
244
283
|
- test/unit/services/proxy_selector_test.rb
|
245
284
|
- test/unit/services/roles_importer_test.rb
|
246
285
|
- test/unit/services/structured_fact_importer_test.rb
|
247
286
|
- test/unit/services/ui_roles_importer_test.rb
|
248
|
-
- test/unit/services/inventory_creator_test.rb
|
249
287
|
- test/unit/actions/run_ansible_job_test.rb
|
250
288
|
- test/unit/actions/run_proxy_ansible_command_test.rb
|
289
|
+
- test/unit/helpers/ansible_reports_helper_test.rb
|
251
290
|
- test/unit/host_ansible_role_test.rb
|
252
291
|
- test/unit/hostgroup_ansible_role_test.rb
|
253
|
-
- test/unit/helpers/foreman_ansible/ansible_reports_helper_test.rb
|
254
292
|
- test/fixtures/sample_facts.json
|
293
|
+
- test/fixtures/report.json
|
255
294
|
- test/test_plugin_helper.rb
|
@@ -1,17 +0,0 @@
|
|
1
|
-
<%#
|
2
|
-
kind: job_template
|
3
|
-
name: Ansible Roles - Ansible Default
|
4
|
-
job_category: Ansible Playbook
|
5
|
-
description_format: 'Run Ansible roles for host'
|
6
|
-
feature: ansible_run_host
|
7
|
-
provider_type: Ansible
|
8
|
-
%>
|
9
|
-
|
10
|
-
---
|
11
|
-
- hosts: <%= @host.name %>
|
12
|
-
tasks:
|
13
|
-
- debug: msg=These are the parameters "{{ foreman_params }}"
|
14
|
-
roles:
|
15
|
-
<% if @host.all_ansible_roles.present? -%>
|
16
|
-
- <%= @host.all_ansible_roles.map { |role| role.name.strip }.join("\n - ") %>
|
17
|
-
<% end -%>
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
|
3
|
-
module ForemanAnsible
|
4
|
-
module Helpers
|
5
|
-
# Tests for the view helper that concerns the Ansible reports styles
|
6
|
-
class AnsibleReportsHelperTest < ActiveSupport::TestCase
|
7
|
-
include ForemanAnsible::AnsibleReportsHelper
|
8
|
-
|
9
|
-
test 'ansible_report? returns false when log is not parseable' do
|
10
|
-
refute ansible_report?('')
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'ansible_report? returns false when log is from Puppet' do
|
14
|
-
refute ansible_report?(FactoryBot.build(:log))
|
15
|
-
end
|
16
|
-
|
17
|
-
test 'ansible_report? returns true when log contains module_name' do
|
18
|
-
log = FactoryBot.build(:log)
|
19
|
-
log.source.value = '{ "module_name" : "foo" }'
|
20
|
-
assert ansible_report?(log)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|