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.
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