diff --git a/app/helpers/foreman_ansible/ansible_reports_helper.rb b/app/helpers/foreman_ansible/ansible_reports_helper.rb index 813dcfb60..b51beb68a 100644 --- a/app/helpers/foreman_ansible/ansible_reports_helper.rb +++ b/app/helpers/foreman_ansible/ansible_reports_helper.rb @@ -36,7 +36,7 @@ def ansible_module_message(log) msg_json['results'].empty? ? msg_json['msg'] : msg_json['results'] when 'template' get_results(msg_json) do |module_args, result| - _("Rendered template #{module_args['_original_basename']} to #{result['dest']}") + add_diff(_("Rendered template #{module_args['_original_basename']} to #{result['dest']}. "), result['dest'], result) end when 'service' get_results(msg_json) do |_, result| @@ -56,12 +56,25 @@ def ansible_module_message(log) end when 'copy' get_results(msg_json) do |module_args, result| - _("Copy #{module_args['_original_basename']} to #{result['dest']}") + add_diff(_("Copy #{module_args['_original_basename']} to #{result['dest']}. "), result['dest'], result) end when 'command', 'shell' msg_json['stdout_lines'] else - no_data_message + have_diff = false + get_results(msg_json) do |_, result| + if result['report_diff'].present? + have_diff = true + break + end + end + if have_diff + get_results(msg_json) do |module_args, result| + add_diff('', module_args['path'] || '', result) if result['report_diff'].present? + end + else + no_data_message + end end end @@ -95,8 +108,10 @@ def show_full_error_message_value(message_value) def get_results(msg_json) results = msg_json.key?('results') ? msg_json['results'] : [msg_json] results.map do |result| - module_args = result.fetch('invocation', {}).fetch('module_args', {}) - yield module_args, result + if result.is_a?(Hash) + module_args = result.fetch('invocation', {}).fetch('module_args', {}) + yield module_args, result + end end end @@ -106,5 +121,19 @@ def parsed_message_json(log) Foreman::Logging.exception('Error while parsing ansible message json', e) {} end + + def add_diff(message, title, result) + diff = if result['report_diff'].blank? + _('No Diff') + else + # Add '\n' before the unified diff as the Javascript displaying the + # diff expects this. + link_to(_('Show Diff'), '#', data: { diff: "\n#{result['report_diff']}", title: title }, onclick: 'tfm.configReportsModalDiff.showDiff(this);') + end + # diff is already HTML safe and should not be escaped again. Hence escape + # the contents of message and concatenate it with diff and + # declare it HTML safe. + (h(message) + diff).html_safe # rubocop:disable Rails/OutputSafety + end end end diff --git a/app/models/foreman_ansible/ansible_provider.rb b/app/models/foreman_ansible/ansible_provider.rb index d151fa006..0455fdaf1 100644 --- a/app/models/foreman_ansible/ansible_provider.rb +++ b/app/models/foreman_ansible/ansible_provider.rb @@ -33,6 +33,7 @@ def proxy_command_options(template_invocation, host) ), :name => host.name, :check_mode => host.host_param('ansible_roles_check_mode'), + :diff_mode => host.host_param('ansible_roles_diff_mode'), :cleanup_working_dirs => cleanup_working_dirs?(host) ) end diff --git a/db/seeds.d/100_common_parameters.rb b/db/seeds.d/100_common_parameters.rb index e15815ee1..7390e6651 100644 --- a/db/seeds.d/100_common_parameters.rb +++ b/db/seeds.d/100_common_parameters.rb @@ -1,6 +1,7 @@ CommonParameter.without_auditing do params = [ - { name: 'ansible_roles_check_mode', key_type: 'boolean', value: false } + { name: 'ansible_roles_check_mode', key_type: 'boolean', value: false }, + { name: 'ansible_roles_diff_mode', key_type: 'boolean', value: false } ] params.each { |param| CommonParameter.find_or_create_by(param) } diff --git a/test/fixtures/report.json b/test/fixtures/report.json index 8f36a17c7..3d33b93a0 100644 --- a/test/fixtures/report.json +++ b/test/fixtures/report.json @@ -105,6 +105,17 @@ "level": "notice" } }, + { + "log": { + "sources": { + "source": "Copy one local file with diff" + }, + "messages": { + "message": "{\"_ansible_no_log\": false, \"changed\": true, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"dest\": \"/tmp/test7.txt\", \"report_diff\": \"--- /tmp/test7.txt\\n+++ /tmp/test7.txt\\n@@ -0,0 +1 @@\\n+Hello\\n\", \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test7.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test7.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": \"root\", \"local_follow\": null, \"mode\": 256, \"owner\": \"root\", \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670677.05-7408-75605497546833/source\", \"unsafe_writes\": false, \"validate\": null}}, \"md5sum\": null, \"mode\": \"0400\", \"module\": \"copy\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670677.05-7408-75605497546833/source\", \"state\": \"file\", \"uid\": 0}" + }, + "level": "notice" + } + }, { "log": { "sources": { diff --git a/test/unit/helpers/ansible_reports_helper_test.rb b/test/unit/helpers/ansible_reports_helper_test.rb index c390ff260..e1fa56132 100644 --- a/test/unit/helpers/ansible_reports_helper_test.rb +++ b/test/unit/helpers/ansible_reports_helper_test.rb @@ -5,6 +5,8 @@ class AnsibleReportsHelperTest < ActiveSupport::TestCase include ForemanAnsible::AnsibleReportsHelper include ActionView::Helpers::TagHelper + include ActionView::Helpers::UrlHelper + include ERB::Util test 'module message extraction' do log_value = <<-ANSIBLELOG.strip_heredoc @@ -80,10 +82,11 @@ class AnsibleReportsHelperTest < ActiveSupport::TestCase 'No additional data', ['Cron job: 0 5,2 * * * date > /dev/null (disabled: false)', 'Cron job: 0 5,2 * * * df > /dev/null (disabled: false)'], ['Cron job: 0 5,2 * * * hostname > /dev/null (disabled: false)'], - ['Rendered template test1.txt.j2 to /tmp/test1.txt', 'Rendered template test2.txt.j2 to /tmp/test2.txt'], - ['Rendered template test3.txt.j2 to /tmp/test3.txt'], - ['Copy test4.txt to /tmp/test4.txt', 'Copy test5.txt to /tmp/test5.txt'], - ['Copy test6.txt to /tmp/test6.txt'], + ['Rendered template test1.txt.j2 to /tmp/test1.txt. No Diff', 'Rendered template test2.txt.j2 to /tmp/test2.txt. No Diff'], + ['Rendered template test3.txt.j2 to /tmp/test3.txt. No Diff'], + ['Copy test4.txt to /tmp/test4.txt. No Diff', 'Copy test5.txt to /tmp/test5.txt. No Diff'], + ['Copy test6.txt to /tmp/test6.txt. No Diff'], + ["Copy test7.txt to /tmp/test7.txt. Show Diff"], ['Service chronyd started (enabled: )', 'Service firewalld started (enabled: )'], ['Service chronyd started (enabled: )'] ]