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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/foreman_ansible/foreman-ansible.css +3 -0
  3. data/app/helpers/foreman_ansible/ansible_reports_helper.rb +77 -12
  4. data/app/models/concerns/foreman_ansible/has_many_ansible_roles.rb +3 -1
  5. data/app/models/concerns/foreman_ansible/hostgroup_extensions.rb +4 -0
  6. data/app/models/setting/ansible.rb +10 -0
  7. data/app/services/foreman_ansible/ansible_report_scanner.rb +21 -0
  8. data/app/services/foreman_ansible/insights_plan_runner.rb +68 -0
  9. data/app/services/foreman_ansible/inventory_creator.rb +6 -11
  10. data/app/services/foreman_ansible/renderer_methods.rb +21 -0
  11. data/app/views/foreman_ansible/ansible_roles/_hostgroup_ansible_roles_button.erb +7 -8
  12. data/app/views/foreman_ansible/config_reports/_ansible.html.erb +6 -3
  13. data/app/views/foreman_ansible/config_reports/_output.html.erb +0 -1
  14. data/app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb +21 -0
  15. data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_galaxy.erb +32 -0
  16. data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb +28 -0
  17. data/app/views/foreman_ansible/job_templates/maintenance_plan.erb +19 -0
  18. data/app/views/foreman_ansible/job_templates/package_action_-_ansible_default.erb +45 -0
  19. data/app/views/foreman_ansible/job_templates/power_action_-_ansible_default.erb +28 -0
  20. data/app/views/foreman_ansible/job_templates/puppet_run_once_-_ansible_default.erb +21 -0
  21. data/app/views/foreman_ansible/job_templates/run_command_-_ansible_default.erb +22 -0
  22. data/app/views/foreman_ansible/job_templates/service_action_-_ansible_default.erb +61 -0
  23. data/lib/foreman_ansible/engine.rb +3 -1
  24. data/lib/foreman_ansible/register.rb +7 -0
  25. data/lib/foreman_ansible/remote_execution.rb +7 -0
  26. data/lib/foreman_ansible/version.rb +1 -1
  27. data/package.json +40 -0
  28. data/test/fixtures/report.json +26 -0
  29. data/test/test_plugin_helper.rb +7 -3
  30. data/test/unit/concerns/config_reports_extensions_test.rb +23 -0
  31. data/test/unit/helpers/ansible_reports_helper_test.rb +46 -0
  32. data/test/unit/services/inventory_creator_test.rb +1 -18
  33. data/webpack/components/ReportJsonViewer.js +17 -0
  34. data/webpack/index.js +4 -0
  35. metadata +45 -6
  36. data/app/views/foreman_ansible/job_templates/ansible_roles.erb +0 -17
  37. 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: 832a0aa23787c1f390fab13d3ecc3e58a60c6af6
4
- data.tar.gz: 3ca0fcc13b040e9e36fb7a7d2b3ff9c4344d8b12
3
+ metadata.gz: 11936ad8fbecb22faf149473256064f197414c8b
4
+ data.tar.gz: f54a4994feab57e29e2a974d04137be329105b5b
5
5
  SHA512:
6
- metadata.gz: 73c63a710e5d0de08464f4a4e24fe65d782294b6f1eee55978235eb1df0d35378ad9336c919fe44d0e8c13849c610620d3a357352a51e6f770aa56d557f2ef98
7
- data.tar.gz: 728a72b85aeda5be356c6c442b523fd36ffb0775a3a090dc83cd3623bd3145569f0fc6aa8aa136d937cba3b274832c0ebadcf5fe4fbf6df8dc7f09603d5c4f20
6
+ metadata.gz: 6446ec9cb86573ed497ee010b2aa05b1e36b62e3cc9a9cd97afdfc2fd2df6620baed984339fa52f0cffe169b8ba1e38e7b3aff9f42a663e8ce3ed4ac0b89cb34
7
+ data.tar.gz: 3b188ae9c37bcc7a1921a5ac008263a03c55867b322c5c4bb71bb67bf2347d6feed7b73513ad8cf2ec1b53fd82ea2b397ea8ed1d1afc0e861f0b422bb5491fcf
@@ -0,0 +1,3 @@
1
+ .report-json-viewer * {
2
+ background: transparent !important;
3
+ }
@@ -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
- def module_name(log)
6
- JSON.parse(log.source.value)['module_name']
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 module_args(log)
10
- JSON.parse(log.source.value)['module_args']
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
- paragraph_style = 'margin:0px;font-family:Menlo,Monaco,Consolas,monospace'
15
- safe_join(
16
- JSON.parse(log.message.value).except('invocation').map do |name, value|
17
- next if value.blank?
18
- content_tag(:p, "#{name}: #{value}", :style => paragraph_style)
19
- end
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
@@ -6,7 +6,9 @@ module ForemanAnsible
6
6
 
7
7
  included do
8
8
  def all_ansible_roles
9
- (ansible_roles + inherited_ansible_roles).uniq
9
+ result = (ansible_roles + inherited_ansible_roles).uniq
10
+ result += host_ansible_roles if is_a? Hostgroup
11
+ result
10
12
  end
11
13
  end
12
14
  end
@@ -14,6 +14,10 @@ module ForemanAnsible
14
14
  roles + hostgroup.ansible_roles
15
15
  end.uniq
16
16
  end
17
+
18
+ def host_ansible_roles
19
+ hosts.all.includes(:ansible_roles).flat_map(&:ansible_roles)
20
+ end
17
21
  end
18
22
  end
19
23
  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
- <table id='report_log' class="table table-bordered table-striped">
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><%= h module_name(log) %></td>
15
- <td><%= h module_args(log) %></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
@@ -2,5 +2,5 @@
2
2
  # This way other parts of Foreman can just call ForemanAnsible::VERSION
3
3
  # and detect what version the plugin is running.
4
4
  module ForemanAnsible
5
- VERSION = '2.0.4'.freeze
5
+ VERSION = '2.1.0'.freeze
6
6
  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
+ }
@@ -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
- File.join(
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
@@ -0,0 +1,4 @@
1
+ import componentRegistry from 'foremanReact/components/componentRegistry';
2
+ import ReportJsonViewer from './components/ReportJsonViewer';
3
+
4
+ componentRegistry.register({ name: 'ReportJsonViewer', type: ReportJsonViewer });
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
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-04-06 00:00:00.000000000 Z
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/ansible_roles.erb
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/foreman_ansible/ansible_reports_helper_test.rb
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