foreman_ansible 11.0.0 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 348701b380a514ccae60dda27305a137438dd4cd2812f9515e071a527a0b20c5
4
- data.tar.gz: ab770d603437ed890a945381d28411e0caff547f6bef26b22c98191fe6317b98
3
+ metadata.gz: c401e27d48eec2462af90e4ee0f94668b3615ef5e4ce7df7e95e1f5732364447
4
+ data.tar.gz: 1644ac60d2f1b352f46ef5409960d00b64c17f2090eb235b528d88579b9fbbc6
5
5
  SHA512:
6
- metadata.gz: 0a780ccd49ae7534e43de5ea1f50aab631b3f59c30c5793455e242568b77d2572fe187f7f0c75667cb1c22ccfd03666dd2ce7df2541cb974df1693ff58079250
7
- data.tar.gz: ab9bdea79a470967e8c6592d7166317668a5d9f892887b8d715fc1daaa9a8ce99959cb5c4da2496dabf4b9e4d2ada5909c2e78bfa250bcd13d2250d7d32a1473
6
+ metadata.gz: 41fc9d4cf864862b5fa562f5a507407d800962fec4f7a27535dd47850a034ee291b12757a4500ebff1c1649b3c2f83be169f1d537871e00a1472064da5907683
7
+ data.tar.gz: 858837e2b4314f437b4fd361a66c657cc11ee52d4af798e1a7ac17b32443f18ce36dcd78db4004a9fc8ee1d951f56ff3e144d3fe097b699e6f673c6798bb94c3
@@ -8,12 +8,14 @@ module Types
8
8
  argument :match, String, required: false
9
9
  end
10
10
 
11
- field :meta, ::Types::Meta, resolve: (proc do |object|
11
+ field :meta, ::Types::Meta
12
+
13
+ def meta
12
14
  {
13
15
  :can_edit => ::User.current.can?(object.ansible_variable.permission_name(:edit), object.ansible_variable),
14
16
  :can_destroy => ::User.current.can?(object.ansible_variable.permission_name(:destroy), object.ansible_variable)
15
17
  }
16
- end)
18
+ end
17
19
 
18
20
  def lookup_values(match: nil)
19
21
  return CollectionLoader.for(object.ansible_variable.class, :lookup_values).load(object.ansible_variable) unless match
@@ -3,13 +3,19 @@
3
3
  module ForemanAnsible
4
4
  module AnsibleHostgroupsHelper
5
5
  def ansible_hostgroups_actions(hostgroup)
6
+ actions = []
6
7
  play_roles = if hostgroup.all_ansible_roles.empty?
7
8
  { action: { content: (link_to _('Run all Ansible roles'), 'javascript:void(0);', disabled: true, title: 'No roles assigned', class: 'disabled'), options: { class: 'disabled' } }, priority: 31 }
8
9
  else
9
10
  { action: display_link_if_authorized(_('Run all Ansible roles'), hash_for_play_roles_hostgroup_path(id: hostgroup), 'data-no-turbolink': true, title: _('Run all Ansible roles on hosts belonging to this host group')), priority: 31 }
10
11
  end
11
12
 
12
- [play_roles] if User.current.can?(:create_job_invocations)
13
+ assign_jobs = { action: { content: (link_to _('Configure Ansible Job'), "/ansible/hostgroups/#{hostgroup.id}", class: 'la') }, priority: 32 }
14
+
15
+ actions.push play_roles if User.current.can?(:create_job_invocations)
16
+ actions.push assign_jobs if User.current.can?(:view_job_invocations) && User.current.can?(:view_recurring_logics)
17
+
18
+ actions
13
19
  end
14
20
  end
15
21
  end
@@ -28,26 +28,36 @@ module ForemanAnsible
28
28
  def ansible_module_message(log)
29
29
  msg_json = parsed_message_json(log)
30
30
  return _("Execution error: #{msg_json['msg']}") if msg_json['failed'].present?
31
+ return msg_json['censored'] if msg_json['censored'].present?
31
32
 
32
- module_action = msg_json['module']
33
+ module_action = msg_json.fetch('module', '').delete_prefix('ansible.builtin.').delete_prefix('ansible.legacy.')
33
34
  case module_action
34
35
  when 'package'
35
36
  msg_json['results'].empty? ? msg_json['msg'] : msg_json['results']
36
37
  when 'template'
37
- module_args = msg_json['invocation']['module_args']
38
- _("Rendered template #{module_args['_original_basename']} to #{msg_json['dest']}")
38
+ get_results(msg_json) do |module_args, result|
39
+ _("Rendered template #{module_args['_original_basename']} to #{result['dest']}")
40
+ end
39
41
  when 'service'
40
- _("Service #{msg_json['name']} #{msg_json['state']} (enabled: #{msg_json['enabled']})")
42
+ get_results(msg_json) do |_, result|
43
+ _("Service #{result['name']} #{result['state']} (enabled: #{result['enabled']})")
44
+ end
41
45
  when 'group'
42
- _("User group #{msg_json['name']} #{msg_json['state']}, gid: #{msg_json['gid']}")
46
+ get_results(msg_json) do |_, result|
47
+ _("User group #{result['name']} #{result['state']}, gid: #{result['gid']}")
48
+ end
43
49
  when 'user'
44
- _("User #{msg_json['name']} #{msg_json['state']}, uid: #{msg_json['uid']}")
50
+ get_results(msg_json) do |_, result|
51
+ _("User #{result['name']} #{result['state']}, uid: #{result['uid']}")
52
+ end
45
53
  when 'cron'
46
- module_args = msg_json['invocation']['module_args']
47
- _("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
54
+ get_results(msg_json) do |module_args, _|
55
+ _("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
56
+ end
48
57
  when 'copy'
49
- module_args = msg_json['invocation']['module_args']
50
- _("Copy #{module_args['_original_basename']} to #{msg_json['dest']}")
58
+ get_results(msg_json) do |module_args, result|
59
+ _("Copy #{module_args['_original_basename']} to #{result['dest']}")
60
+ end
51
61
  when 'command', 'shell'
52
62
  msg_json['stdout_lines']
53
63
  else
@@ -82,6 +92,14 @@ module ForemanAnsible
82
92
 
83
93
  private
84
94
 
95
+ def get_results(msg_json)
96
+ results = msg_json.key?('results') ? msg_json['results'] : [msg_json]
97
+ results.map do |result|
98
+ module_args = result.fetch('invocation', {}).fetch('module_args', {})
99
+ yield module_args, result
100
+ end
101
+ end
102
+
85
103
  def parsed_message_json(log)
86
104
  JSON.parse(log.message.value)
87
105
  rescue StandardError => e
@@ -1,5 +1,5 @@
1
1
  class FixAnsibleSettingCategoryToDsl < ActiveRecord::Migration[6.0]
2
2
  def up
3
- Setting.where(category: 'Setting::Ansible').update_all(category: 'Setting')
3
+ Setting.where(category: 'Setting::Ansible').update_all(category: 'Setting') if column_exists?(:settings, :category)
4
4
  end
5
5
  end
@@ -4,5 +4,5 @@
4
4
  # This way other parts of Foreman can just call ForemanAnsible::VERSION
5
5
  # and detect what version the plugin is running.
6
6
  module ForemanAnsible
7
- VERSION = '11.0.0'
7
+ VERSION = '11.1.0'
8
8
  end
@@ -1,4 +1,4 @@
1
- {
1
+ [{
2
2
  "reporter": "ansible",
3
3
  "reported_at":"2018-01-15 17:31:36 521275",
4
4
  "metrics": {
@@ -24,4 +24,108 @@
24
24
  }
25
25
  }
26
26
  ]
27
- }
27
+ },
28
+ {
29
+ "reporter": "ansible",
30
+ "reported_at":"2022-12-22 10:52:48 521275",
31
+ "metrics": {
32
+ "time":
33
+ { "total":133 }
34
+ },
35
+ "host": "io.local",
36
+ "status": {
37
+ "applied": 8,
38
+ "failed": 0,
39
+ "skipped": 0
40
+ },
41
+ "logs": [
42
+ {
43
+ "log": {
44
+ "sources": {
45
+ "source": "Schedule multiple cronjobs"
46
+ },
47
+ "messages": {
48
+ "message": "{\"changed\": true, \"failed\": false, \"module\": \"cron\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"date\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"date > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Cron date\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"item\": \"date\", \"jobs\": [\"Cron date\"]}, {\"_ansible_item_label\": \"df\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"df > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Cron df\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"item\": \"df\", \"jobs\": [\"Cron date\", \"Cron df\"]}]}"
49
+ },
50
+ "level": "notice"
51
+ }
52
+ },
53
+ {
54
+ "log": {
55
+ "sources": {
56
+ "source": "Schedule one cronjob"
57
+ },
58
+ "messages": {
59
+ "message": "{\"_ansible_no_log\": false, \"changed\": true, \"envs\": [], \"failed\": false, \"invocation\": {\"module_args\": {\"backup\": false, \"cron_file\": null, \"day\": \"*\", \"disabled\": false, \"env\": null, \"hour\": \"5,2\", \"insertafter\": null, \"insertbefore\": null, \"job\": \"hostname > /dev/null\", \"minute\": \"0\", \"month\": \"*\", \"name\": \"Schedule hostname\", \"reboot\": false, \"special_time\": null, \"state\": \"present\", \"user\": null, \"weekday\": \"*\"}}, \"jobs\": [\"Cron date\", \"Cron df\", \"Schedule hostname\"], \"module\": \"cron\"}"
60
+ },
61
+ "level": "notice"
62
+ }
63
+ },
64
+ {
65
+ "log": {
66
+ "sources": {
67
+ "source": "Render multiple templates"
68
+ },
69
+ "messages": {
70
+ "message": "{\"changed\": true, \"failed\": false, \"module\": \"template\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"test1.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"dba7673010f19a94af4345453005933fd511bea9\", \"dest\": \"/tmp/test1.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test1.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"dba7673010f19a94af4345453005933fd511bea9\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test1.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670606.02-7241-175625077259447/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test1.txt\", \"md5sum\": null, \"mode\": \"0644\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670606.02-7241-175625077259447/source\", \"state\": \"file\", \"uid\": 0}, {\"_ansible_item_label\": \"test2.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"9054fbe0b622c638224d50d20824d2ff6782e308\", \"dest\": \"/tmp/test2.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test2.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"9054fbe0b622c638224d50d20824d2ff6782e308\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test2.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670620.49-7241-225254470383476/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test2.txt\", \"md5sum\": null, \"mode\": \"0644\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670620.49-7241-225254470383476/source\", \"state\": \"file\", \"uid\": 0}]}"
71
+ },
72
+ "level": "notice"
73
+ }
74
+ },
75
+ {
76
+ "log": {
77
+ "sources": {
78
+ "source": "Render one template"
79
+ },
80
+ "messages": {
81
+ "message": "{\"_ansible_no_log\": false, \"changed\": true, \"checksum\": \"41c5985fc771b6ecfe8feaa99f8fa9b77ac7d6ce\", \"dest\": \"/tmp/test3.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test3.txt.j2\", \"attributes\": null, \"backup\": false, \"checksum\": \"41c5985fc771b6ecfe8feaa99f8fa9b77ac7d6ce\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test3.txt\", \"directory_mode\": null, \"follow\": false, \"force\": true, \"group\": null, \"local_follow\": null, \"mode\": null, \"owner\": null, \"regexp\": null, \"remote_src\": null, \"selevel\": null, \"serole\": null, \"setype\": null, \"seuser\": null, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670634.79-7306-243717749452063/source\", \"unsafe_writes\": false, \"validate\": null}}, \"md5sum\": null, \"mode\": \"0644\", \"module\": \"template\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670634.79-7306-243717749452063/source\", \"state\": \"file\", \"uid\": 0}"
82
+ },
83
+ "level": "notice"
84
+ }
85
+ },
86
+ {
87
+ "log": {
88
+ "sources": {
89
+ "source": "Copy multiple local files"
90
+ },
91
+ "messages": {
92
+ "message": "{\"changed\": true, \"failed\": false, \"module\": \"copy\", \"msg\": \"All items completed\", \"results\": [{\"_ansible_item_label\": \"test4.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"ab2649b7e58f7e32b0c75be95d11e2979399d392\", \"dest\": \"/tmp/test4.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test4.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"ab2649b7e58f7e32b0c75be95d11e2979399d392\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test4.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-1671670648.88-7343-91799014257533/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test4.txt\", \"md5sum\": null, \"mode\": \"0400\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670648.88-7343-91799014257533/source\", \"state\": \"file\", \"uid\": 0}, {\"_ansible_item_label\": \"test5.txt\", \"_ansible_no_log\": false, \"ansible_loop_var\": \"item\", \"changed\": true, \"checksum\": \"4ea77484f3a1c7dde4c0cca2f5c40953388f19f5\", \"dest\": \"/tmp/test5.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test5.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"4ea77484f3a1c7dde4c0cca2f5c40953388f19f5\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test5.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-1671670662.97-7343-50902792283881/source\", \"unsafe_writes\": false, \"validate\": null}}, \"item\": \"test5.txt\", \"md5sum\": null, \"mode\": \"0400\", \"owner\": \"root\", \"secontext\": \"unconfined_u:object_r:admin_home_t:s0\", \"size\": 6, \"src\": \"/root/.ansible/tmp/ansible-tmp-1671670662.97-7343-50902792283881/source\", \"state\": \"file\", \"uid\": 0}]}"
93
+ },
94
+ "level": "notice"
95
+ }
96
+ },
97
+ {
98
+ "log": {
99
+ "sources": {
100
+ "source": "Copy one local files"
101
+ },
102
+ "messages": {
103
+ "message": "{\"_ansible_no_log\": false, \"changed\": true, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"dest\": \"/tmp/test6.txt\", \"diff\": [], \"failed\": false, \"gid\": 0, \"group\": \"root\", \"invocation\": {\"module_args\": {\"_original_basename\": \"test6.txt\", \"attributes\": null, \"backup\": false, \"checksum\": \"ec4cddb45c3ce640bed61b3d8ab6c18e715dac78\", \"content\": null, \"delimiter\": null, \"dest\": \"/tmp/test6.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}"
104
+ },
105
+ "level": "notice"
106
+ }
107
+ },
108
+ {
109
+ "log": {
110
+ "sources": {
111
+ "source": "Restart multiple services"
112
+ },
113
+ "messages": {
114
+ "message": "{\"changed\":true,\"failed\":false,\"module\":\"service\",\"msg\":\"All items completed\",\"results\":[{\"_ansible_item_label\":\"chronyd\",\"_ansible_no_log\":false,\"ansible_loop_var\":\"item\",\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"chronyd\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"item\":\"chronyd\",\"name\":\"chronyd\",\"state\":\"started\"},{\"_ansible_item_label\":\"firewalld\",\"_ansible_no_log\":false,\"ansible_loop_var\":\"item\",\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"firewalld\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"item\":\"firewalld\",\"name\":\"firewalld\",\"state\":\"started\"}]}"
115
+ },
116
+ "level": "notice"
117
+ }
118
+ },
119
+ {
120
+ "log": {
121
+ "sources": {
122
+ "source": "Restart one service"
123
+ },
124
+ "messages": {
125
+ "message": "{\"_ansible_no_log\":false,\"changed\":true,\"failed\":false,\"invocation\":{\"module_args\":{\"daemon_reexec\":false,\"daemon_reload\":false,\"enabled\":null,\"force\":null,\"masked\":null,\"name\":\"chronyd\",\"no_block\":false,\"scope\":null,\"state\":\"restarted\",\"user\":null}},\"module\":\"service\",\"name\":\"chronyd\",\"state\":\"started\"}"
126
+ },
127
+ "level": "notice"
128
+ }
129
+ }
130
+ ]
131
+ }]
@@ -4,13 +4,15 @@ require 'test_plugin_helper'
4
4
 
5
5
  # Tests for the behavior of Host with roles, checks inheritance, etc
6
6
  class ConfigReportExtensionsTest < ActiveSupport::TestCase
7
- let(:example_report) do
7
+ let(:example_reports) do
8
8
  JSON.parse(File.read(ansible_fixture_file('report.json')))
9
9
  end
10
10
 
11
+ let(:example_report1) { example_reports.first }
12
+
11
13
  describe '.import' do
12
14
  it 'sets an origin for Ansible reports' do
13
- report = ConfigReport.import(example_report)
15
+ report = ConfigReport.import(example_report1)
14
16
  assert_equal 'Ansible', report.origin
15
17
  end
16
18
 
@@ -33,4 +33,64 @@ ANSIBLELOG
33
33
  ansible_module_message(log).to_s
34
34
  )
35
35
  end
36
+
37
+ test 'accepting an almost empty message' do
38
+ log_value = <<-ANSIBLELOG.strip_heredoc
39
+ {"changed": true, "failed": false, "module": "copy"}
40
+ ANSIBLELOG
41
+ message = FactoryBot.build(:message, value: log_value)
42
+ log = FactoryBot.build(:log)
43
+ log.message = message
44
+ assert_match(
45
+ /Copy/,
46
+ ansible_module_message(log).to_s
47
+ )
48
+ end
49
+
50
+ test 'FQCN module message extraction' do
51
+ log_value = <<-ANSIBLELOG.strip_heredoc
52
+ {"msg": "Nothing to do", "changed": false, "results": [], "rc": 0, "invocation": {"module_args": {"name": ["openssh"], "state": "present", "allow_downgrade": false, "autoremove": false, "bugfix": false, "disable_gpg_check": false, "disable_plugin": [], "disablerepo": [], "download_only": false, "enable_plugin": [], "enablerepo": [], "exclude": [], "installroot": "/", "install_repoquery": true, "install_weak_deps": true, "security": false, "skip_broken": false, "update_cache": false, "update_only": false, "validate_certs": true, "lock_timeout": 30, "conf_file": null, "disable_excludes": null, "download_dir": null, "list": null, "releasever": null}}, "_ansible_no_log": false, "failed": false, "module": "ansible.builtin.package"}
53
+ ANSIBLELOG
54
+ message = FactoryBot.build(:message, value: log_value)
55
+ log = FactoryBot.build(:log)
56
+ log.message = message
57
+ assert_match(
58
+ /Nothing to do/,
59
+ ansible_module_message(log).to_s
60
+ )
61
+ end
62
+
63
+ test 'accepting a censored message' do
64
+ log_value = <<-ANSIBLELOG.strip_heredoc
65
+ {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result", "changed": true, "failed": false, "module": "copy"}
66
+ ANSIBLELOG
67
+ message = FactoryBot.build(:message, value: log_value)
68
+ log = FactoryBot.build(:log)
69
+ log.message = message
70
+ assert_match(
71
+ /output has been hidden/,
72
+ ansible_module_message(log).to_s
73
+ )
74
+ end
75
+
76
+ test 'module message extraction with action' do
77
+ example_report = JSON.parse(File.read(ansible_fixture_file('report.json'))).second
78
+ report = ConfigReport.import(example_report)
79
+ expected_outputs = [
80
+ 'No additional data',
81
+ ['Cron job: 0 5,2 * * * date > /dev/null (disabled: false)', 'Cron job: 0 5,2 * * * df > /dev/null (disabled: false)'],
82
+ ['Cron job: 0 5,2 * * * hostname > /dev/null (disabled: false)'],
83
+ ['Rendered template test1.txt.j2 to /tmp/test1.txt', 'Rendered template test2.txt.j2 to /tmp/test2.txt'],
84
+ ['Rendered template test3.txt.j2 to /tmp/test3.txt'],
85
+ ['Copy test4.txt to /tmp/test4.txt', 'Copy test5.txt to /tmp/test5.txt'],
86
+ ['Copy test6.txt to /tmp/test6.txt'],
87
+ ['Service chronyd started (enabled: )', 'Service firewalld started (enabled: )'],
88
+ ['Service chronyd started (enabled: )']
89
+ ]
90
+ actual_outputs = []
91
+ report.logs.each do |log|
92
+ actual_outputs << ansible_module_message(log)
93
+ end
94
+ assert_equal expected_outputs, actual_outputs
95
+ end
36
96
  end
@@ -8,4 +8,9 @@ fragment CurrentUserAttributes on User {
8
8
  name
9
9
  }
10
10
  }
11
+ usergroups {
12
+ nodes {
13
+ admin
14
+ }
15
+ }
11
16
  }
@@ -11,7 +11,10 @@ export const permissionCheck = (user, permissionsRequired) => {
11
11
  );
12
12
  }
13
13
 
14
- if (user.admin) {
14
+ if (
15
+ user.admin ||
16
+ user.usergroups.nodes.find(usergroup => usergroup.admin === true)
17
+ ) {
15
18
  return { allowed: true };
16
19
  }
17
20
 
@@ -71,6 +71,9 @@ export const userFactory = (login, permissions = []) => ({
71
71
  permissions: {
72
72
  nodes: permissions,
73
73
  },
74
+ usergroups: {
75
+ nodes: [],
76
+ },
74
77
  });
75
78
 
76
79
  export const admin = {
@@ -81,6 +84,9 @@ export const admin = {
81
84
  permissions: {
82
85
  nodes: [],
83
86
  },
87
+ usergroups: {
88
+ nodes: [],
89
+ },
84
90
  };
85
91
 
86
92
  export const intruder = userFactory('intruder', [
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: 11.0.0
4
+ version: 11.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: 2023-01-08 00:00:00.000000000 Z
11
+ date: 2023-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_list
@@ -478,9 +478,9 @@ test_files:
478
478
  - test/factories/host_ansible_enhancements.rb
479
479
  - test/fixtures/insights_playbook.yaml
480
480
  - test/fixtures/playbooks_example_output.json
481
- - test/fixtures/report.json
482
481
  - test/fixtures/sample_facts.json
483
482
  - test/fixtures/sample_playbooks.json
483
+ - test/fixtures/report.json
484
484
  - test/foreman_ansible/helpers/ansible_roles_helper_test.rb
485
485
  - test/functional/ansible_roles_controller_test.rb
486
486
  - test/functional/ansible_variables_controller_test.rb
@@ -498,9 +498,9 @@ test_files:
498
498
  - test/test_plugin_helper.rb
499
499
  - test/unit/ansible_role_test.rb
500
500
  - test/unit/ansible_variable_test.rb
501
- - test/unit/concerns/config_reports_extensions_test.rb
502
501
  - test/unit/concerns/host_managed_extensions_test.rb
503
502
  - test/unit/concerns/hostgroup_extensions_test.rb
503
+ - test/unit/concerns/config_reports_extensions_test.rb
504
504
  - test/unit/helpers/ansible_reports_helper_test.rb
505
505
  - test/unit/host_ansible_role_test.rb
506
506
  - test/unit/hostgroup_ansible_role_test.rb