foreman_ansible 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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": "[![Code Climate](https://codeclimate.com/github/theforeman/foreman_ansible/badges/gpa.svg)](https://codeclimate.com/github/theforeman/foreman_ansible) [![Gem Version](https://badge.fury.io/rb/foreman_ansible.svg)](https://badge.fury.io/rb/foreman_ansible) [![GPL License](https://img.shields.io/github/license/theforeman/foreman_ansible.svg)](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
|