foreman_ansible 6.3.0 → 6.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/foreman_ansible/ansible_reports_helper.rb +35 -54
  3. data/app/models/foreman_ansible/ansible_provider.rb +50 -1
  4. data/app/views/foreman_ansible/config_reports/_ansible.html.erb +14 -5
  5. data/app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb +4 -0
  6. data/lib/foreman_ansible/engine.rb +0 -1
  7. data/lib/foreman_ansible/register.rb +2 -0
  8. data/lib/foreman_ansible/version.rb +1 -1
  9. data/package.json +7 -5
  10. data/test/unit/helpers/ansible_reports_helper_test.rb +4 -30
  11. data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.js +35 -0
  12. data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss +6 -0
  13. data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.test.js +14 -0
  14. data/webpack/components/AnsibleHostDetail/index.js +6 -0
  15. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsiblePermissionDenied.test.js.snap +2 -0
  16. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap +4 -4
  17. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +5 -0
  18. data/webpack/global_index.js +12 -0
  19. metadata +12 -33
  20. data/test/unit/lib/foreman_ansible_core/ansible_runner_test.rb +0 -51
  21. data/test/unit/lib/foreman_ansible_core/command_creator_test.rb +0 -64
  22. data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +0 -110
  23. data/webpack/__mocks__/foremanReact/common/I18n.js +0 -1
  24. data/webpack/__mocks__/foremanReact/common/helpers.js +0 -13
  25. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -2
  26. data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +0 -5
  27. data/webpack/__mocks__/foremanReact/components/common/forms/OrderableSelect/helpers.js +0 -5
  28. data/webpack/__mocks__/foremanReact/redux/API.js +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3dbc63a3f68609ae8682419576047000d3e815ddfc430e899c93b6f420cdbd8a
4
- data.tar.gz: ee146c0e155b24635e223ddb0d1ae6693a9921772001f39dbc64eaadde81a075
3
+ metadata.gz: 05c975cb77fe5add41b7281dfa1c2451bb22a09ab5dc6251ab06fd4d00b834e2
4
+ data.tar.gz: 86613f4be767b5af80a06f83b9e13f8f030cd80bc362d866323111b61a0b23a9
5
5
  SHA512:
6
- metadata.gz: de0fb54a0b6ef91411c1b09a36d6602bfd11771bd630035596d2ba173c3fc48e258c62e4f7a04c93172ee7f38485be7096ebefe708378b748e8122a5f332729d
7
- data.tar.gz: 36f23bdd7d722daababf92449772c6bd1be6e4a5b46ad5913b2fa5a37578bd33c149bab9ce3192481d75192b5600d0c13734957c6e97317ff34230043566cb14
6
+ metadata.gz: dc27695cef374e8b709ddc3c3882056587cbf975ac7d497c1fec5aaa1885f85bcb3677c2c7fd3f2602f529cba0a6736017703f6d7ca413eb5f2ed7a6de112a94
7
+ data.tar.gz: ba0c5f9b94a51b7328cc0df73bfcc0f47831b1004b275be935fa73a83ae9c6f12b81086071ebe69292c8aa5ad436c5389a6a6f1ac457720bcefe034b456c0ec8
@@ -4,21 +4,19 @@ module ForemanAnsible
4
4
  # This module takes the config reports stored in Foreman for Ansible and
5
5
  # modifies them to be properly presented in views
6
6
  module AnsibleReportsHelper
7
- ANSIBLE_META_KEYS = %w[
8
- _ansible_parsed _ansible_no_log _ansible_item_result
9
- _ansible_ignore_errors _ansible_verbose_always _ansible_verbose_override
10
- ].freeze
11
- ANSIBLE_HIDDEN_KEYS = %w[
12
- invocation module_args results ansible_facts
13
- stdout stderr
14
- ].freeze
15
-
16
7
  def ansible_module_name(log)
17
8
  source_value = log.source&.value
18
9
  name = source_value.split(':')[0].strip if source_value&.include?(':')
19
10
  name
20
11
  end
21
12
 
13
+ def ansible_task_name(log)
14
+ source_value = log.source&.value
15
+ return source_value || no_data_message unless source_value.include? ':'
16
+ name = source_value.split(':')[1].strip if source_value.include?(':')
17
+ name || no_data_message
18
+ end
19
+
22
20
  def ansible_run_in_check_mode?(log)
23
21
  log.message&.value == 'check_mode_enabled' if check_mode_log?(log)
24
22
  end
@@ -27,12 +25,36 @@ module ForemanAnsible
27
25
  log.source&.value == 'check_mode'
28
26
  end
29
27
 
30
- def ansible_module_args(log)
31
- report_json_viewer module_invocations parsed_message_json(log)
28
+ def ansible_module_message(log)
29
+ msg_json = parsed_message_json(log)
30
+ module_action = msg_json['module']
31
+ case module_action
32
+ when 'package'
33
+ msg_json['results'].empty? ? msg_json['msg'] : msg_json['results']
34
+ when 'template'
35
+ module_args = msg_json['invocation']['module_args']
36
+ _("Rendered template #{module_args['_original_basename']} to #{msg_json['dest']}")
37
+ when 'service'
38
+ _("Service #{msg_json['name']} #{msg_json['state']} (enabled: #{msg_json['enabled']})")
39
+ when 'group'
40
+ _("User group #{msg_json['name']} #{msg_json['state']}, gid: #{msg_json['gid']}")
41
+ when 'user'
42
+ _("User #{msg_json['name']} #{msg_json['state']}, uid: #{msg_json['uid']}")
43
+ when 'cron'
44
+ module_args = msg_json['invocation']['module_args']
45
+ _("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
46
+ when 'copy'
47
+ module_args = msg_json['invocation']['module_args']
48
+ _("Copy #{module_args['_original_basename']} to #{msg_json['dest']}")
49
+ when 'command', 'shell'
50
+ msg_json['stdout_lines']
51
+ else
52
+ no_data_message
53
+ end
32
54
  end
33
55
 
34
- def ansible_module_message(log)
35
- report_json_viewer hash_with_keys_removed parsed_message_json(log)
56
+ def no_data_message
57
+ _('No additional data')
36
58
  end
37
59
 
38
60
  def ansible_report_origin_icon
@@ -49,49 +71,8 @@ module ForemanAnsible
49
71
  false
50
72
  end
51
73
 
52
- def report_json_viewer(json)
53
- react_component('ReportJsonViewer', data: json)
54
- end
55
-
56
74
  private
57
75
 
58
- def module_invocations(hash)
59
- invocations = []
60
- invocations << hash.delete('invocation')
61
- results = hash.delete('results')
62
- invocations << results
63
- invocations = invocations.compact.flatten.map do |ih|
64
- ih.is_a?(Hash) ? remove_keys(ih) : ih
65
- end
66
- invocations
67
- end
68
-
69
- def pretty_print_hash(hash)
70
- prettyp = JSON.pretty_generate(remove_keys(hash))
71
- prettyp.gsub!(/{\n*/, "\n")
72
- prettyp.gsub!(/},*\n*/, "\n")
73
- prettyp.gsub!(/^(\[|\])/, '')
74
- prettyp.gsub!(/^[\s]*$\n/, '')
75
- paragraph_style = 'white-space:pre;padding: 2em 0'
76
- tag(:p, prettyp, :style => paragraph_style)
77
- end
78
-
79
- def hash_with_keys_removed(hash)
80
- new_hash = remove_keys(hash)
81
- remove_keys(new_hash, ANSIBLE_HIDDEN_KEYS)
82
- end
83
-
84
- def remove_keys(hash, keys = ANSIBLE_META_KEYS)
85
- hash.each do |key, value|
86
- if value.is_a? Array
87
- value.each { |h| remove_keys(h) if h.is_a? Hash }
88
- elsif value.is_a? Hash
89
- remove_keys(value)
90
- end
91
- hash.delete(key) if keys.include? key
92
- end
93
- end
94
-
95
76
  def parsed_message_json(log)
96
77
  JSON.parse(log.message.value)
97
78
  rescue StandardError => e
@@ -18,6 +18,10 @@ if defined? ForemanRemoteExecution
18
18
  'Ansible'
19
19
  end
20
20
 
21
+ def provider_input_namespace
22
+ :ansible
23
+ end
24
+
21
25
  def proxy_command_options(template_invocation, host)
22
26
  super(template_invocation, host).merge(
23
27
  'ansible_inventory' => ::ForemanAnsible::InventoryCreator.new(
@@ -59,12 +63,57 @@ if defined? ForemanRemoteExecution
59
63
  true
60
64
  end
61
65
 
66
+ def provider_inputs
67
+ [
68
+ ForemanRemoteExecution::ProviderInput.new(
69
+ name: 'tags',
70
+ label: _('Tags'),
71
+ value: '',
72
+ value_type: 'plain',
73
+ description: 'Tags used for Ansible execution'
74
+ ),
75
+ ForemanRemoteExecution::ProviderInput.new(
76
+ name: 'tags_flag',
77
+ label: _('Include/Exclude Tags'),
78
+ value: 'include',
79
+ description: 'Option whether to include or exclude tags',
80
+ options: "include\nexclude"
81
+ )
82
+ ]
83
+ end
84
+
85
+ def provider_inputs_doc
86
+ opts = provider_inputs.find { |input| input.name == 'tags_flag' }.options.split("\n")
87
+ {
88
+ :namespace => provider_input_namespace,
89
+ :opts => { :desc => N_('Ansible provider specific inputs') },
90
+ :children => [
91
+ {
92
+ :name => :tags,
93
+ :type => Array,
94
+ :opts => { :required => false, :desc => N_('A comma separated list of tags to use for Ansible run') }
95
+ },
96
+ {
97
+ :name => :tags_flag,
98
+ :type => opts,
99
+ :opts => { :required => false, :desc => N_('Include\Exclude tags for Ansible run') }
100
+ }
101
+ ]
102
+ }
103
+ end
104
+
105
+ def proxy_command_provider_inputs(template_invocation)
106
+ tags = template_invocation.provider_input_values.find_by(:name => 'tags')&.value || ''
107
+ tags_flag = template_invocation.provider_input_values.find_by(:name => 'tags_flag')&.value || ''
108
+ { :tags => tags, :tags_flag => tags_flag }
109
+ end
110
+
62
111
  def proxy_operation_name
63
112
  'ansible-runner'
64
113
  end
65
114
 
66
115
  def proxy_action_class
67
- 'ForemanAnsibleCore::TaskLauncher::Playbook::PlaybookRunnerAction'
116
+ 'Proxy::Ansible::TaskLauncher::Playbook::PlaybookRunnerAction'
68
117
  end
69
118
 
70
119
  private
@@ -10,8 +10,7 @@
10
10
  <thead>
11
11
  <tr>
12
12
  <th><%= _("Level") %></th>
13
- <th><%= _("Module") %></th>
14
- <th><%= _("Arguments") %></th>
13
+ <th><%= _("Task") %></th>
15
14
  <th><%= _("Message") %></th>
16
15
  </tr>
17
16
  </thead>
@@ -20,9 +19,19 @@
20
19
  <% unless check_mode_log?(log) %>
21
20
  <tr>
22
21
  <td><span <%= report_tag log.level %>><%= h log.level %></span></td>
23
- <td><%= ansible_module_name(log) %></td>
24
- <td><%= ansible_module_args(log) %></td>
25
- <td><%= ansible_module_message(log) %></td>
22
+ <td><span title=<%= ansible_module_name(log) %>><%= ansible_task_name(log) %></span></td>
23
+ <td>
24
+ <% log_message = ansible_module_message(log) %>
25
+ <% if log_message.is_a? Array %>
26
+ <ul>
27
+ <% log_message.each do |message_line| %>
28
+ <li><%= message_line %></li>
29
+ <% end %>
30
+ </ul>
31
+ <% else %>
32
+ <%= log_message %>
33
+ <% end %>
34
+ </td>
26
35
  </tr>
27
36
  <% end %>
28
37
  <% end %>
@@ -15,10 +15,14 @@ model: JobTemplate
15
15
  - name: Display all parameters known for the Foreman host
16
16
  debug:
17
17
  var: foreman
18
+ tags:
19
+ - always
18
20
  tasks:
19
21
  - name: Apply roles
20
22
  include_role:
21
23
  name: "{{ role }}"
24
+ tags:
25
+ - always
22
26
  loop: "{{ foreman_ansible_roles }}"
23
27
  loop_control:
24
28
  loop_var: role
@@ -4,7 +4,6 @@ require 'deface'
4
4
  require 'acts_as_list'
5
5
  require 'fast_gettext'
6
6
  require 'gettext_i18n_rails'
7
- require 'foreman_ansible_core' if Rails.env.test?
8
7
  require 'foreman_ansible/remote_execution'
9
8
 
10
9
  module ForemanAnsible
@@ -96,6 +96,8 @@ Foreman::Plugin.register :foreman_ansible do
96
96
  parameter_filter Host::Managed, base_role_assignment_params.merge(:host_ansible_roles_attributes => {})
97
97
  parameter_filter Hostgroup, base_role_assignment_params.merge(:hostgroup_ansible_roles_attributes => {})
98
98
 
99
+ register_global_js_file 'global'
100
+
99
101
  divider :top_menu, :caption => N_('Ansible'), :parent => :configure_menu
100
102
  menu :top_menu, :ansible_roles,
101
103
  :caption => N_('Roles'),
@@ -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 = '6.3.0'
7
+ VERSION = '6.4.0'
8
8
  end
data/package.json CHANGED
@@ -14,16 +14,18 @@
14
14
  },
15
15
  "devDependencies": {
16
16
  "@babel/core": "^7.7.0",
17
- "@theforeman/builder": "^6.0.0",
18
- "@theforeman/eslint-plugin-foreman": "6.0.0",
19
- "@theforeman/test": "^6.0.0",
20
- "@theforeman/vendor-dev": "^6.0.0",
17
+ "@theforeman/builder": "^8.4.1",
18
+ "@theforeman/eslint-plugin-foreman": "^8.4.1",
19
+ "@theforeman/find-foreman": "^8.4.1",
20
+ "@theforeman/stories": "^8.4.1",
21
+ "@theforeman/test": "^8.4.1",
22
+ "@theforeman/vendor-dev": "^8.4.1",
21
23
  "babel-eslint": "^10.0.3",
22
24
  "eslint": "^6.7.2",
23
25
  "prettier": "^1.13.5"
24
26
  },
25
27
  "scripts": {
26
- "test": "tfm-test --plugin",
28
+ "test": "tfm-test --plugin --config jest.config.js",
27
29
  "lint": "tfm-lint --plugin -d webpack"
28
30
  },
29
31
  "repository": {
@@ -6,43 +6,17 @@ class AnsibleReportsHelperTest < ActiveSupport::TestCase
6
6
  include ForemanAnsible::AnsibleReportsHelper
7
7
  include ActionView::Helpers::TagHelper
8
8
 
9
- test 'is able to print a string instead of a hash' do
9
+ test 'module message extraction' do
10
10
  log_value = <<-ANSIBLELOG.strip_heredoc
11
- {"_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": ""}
11
+ {"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": "package"}
12
12
  ANSIBLELOG
13
13
  message = FactoryBot.build(:message)
14
14
  message.value = log_value
15
15
  log = FactoryBot.build(:log)
16
16
  log.message = message
17
17
  assert_match(
18
- /ntp-4.2.8p10-3.fc27.x86_64 providing ntp is already installed/,
19
- module_invocations(parsed_message_json(log)).to_s
20
- )
21
- end
22
-
23
- test 'pretty print is able to print a hash' do
24
- hash = {
25
- 'allow_downgrade' => false,
26
- 'name' => ['ntp'],
27
- 'list' => nil,
28
- 'disable_gpg_check' => false,
29
- 'conf_file' => nil,
30
- 'install_repoquery' => true,
31
- 'state' => 'installed',
32
- 'disablerepo' => nil,
33
- 'update_cache' => false,
34
- 'enablerepo' => nil,
35
- 'exclude' => nil,
36
- 'security' => false,
37
- 'validate_certs' => true,
38
- 'installroot' => '/',
39
- 'skip_broken' => false
40
- }
41
- assert_equal(
42
- hash,
43
- remove_keys(
44
- hash
45
- )
18
+ /Nothing to do/,
19
+ ansible_module_message(log).to_s
46
20
  )
47
21
  end
48
22
  end
@@ -0,0 +1,35 @@
1
+ import React, { useState } from 'react';
2
+ import { Tabs, Tab, TabTitleText, Label } from '@patternfly/react-core';
3
+ import { InfoCircleIcon } from '@patternfly/react-icons';
4
+
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+
7
+ import './AnsibleHostDetail.scss';
8
+
9
+ const AnsibleHostDetail = props => {
10
+ // https://projects.theforeman.org/issues/32398
11
+ const [activeTab] = useState('variables');
12
+
13
+ return (
14
+ <Tabs activeKey={activeTab} isSecondary>
15
+ <Tab
16
+ eventKey="variables"
17
+ title={<TabTitleText>{__('Variables')}</TabTitleText>}
18
+ >
19
+ <div className="host-details-tab-item">
20
+ <div className="ansible-host-detail">
21
+ <Label
22
+ color="blue"
23
+ icon={<InfoCircleIcon />}
24
+ style={{ marginTop: '1.5rem' }}
25
+ >
26
+ Ansible Variables coming soon!
27
+ </Label>
28
+ </div>
29
+ </div>
30
+ </Tab>
31
+ </Tabs>
32
+ );
33
+ };
34
+
35
+ export default AnsibleHostDetail;
@@ -0,0 +1,6 @@
1
+ @import '~@patternfly/patternfly/base/patternfly-variables';
2
+
3
+ .ansible-host-detail {
4
+ background-color: $pf-color-white;
5
+ padding: 1.8rem;
6
+ }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+
5
+ import AnsibleHostDetail from './';
6
+
7
+ describe('AnsibleHostDetail', () => {
8
+ it('should show content', () => {
9
+ render(<AnsibleHostDetail />);
10
+ expect(
11
+ screen.getByText('Ansible Variables coming soon!')
12
+ ).toBeInTheDocument();
13
+ });
14
+ });
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import AnsibleHostDetail from './AnsibleHostDetail';
3
+
4
+ const WrappedAnsibleHostDetail = props => <AnsibleHostDetail {...props} />;
5
+
6
+ export default WrappedAnsibleHostDetail;
@@ -2,6 +2,7 @@
2
2
 
3
3
  exports[`AnsiblePermissionDenied should render 1`] = `
4
4
  <EmptyStatePattern
5
+ action={null}
5
6
  description={
6
7
  <span>
7
8
  You are not authorized to perform this action.
@@ -22,5 +23,6 @@ exports[`AnsiblePermissionDenied should render 1`] = `
22
23
  header="Permission Denied"
23
24
  icon="lock"
24
25
  iconType="fa"
26
+ secondaryActions={Array []}
25
27
  />
26
28
  `;
@@ -1,13 +1,13 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`AssignedRolesList should render 1`] = `
4
- <DndProvider
4
+ <Memo(DndProvider)
5
5
  backend={[Function]}
6
6
  >
7
7
  <ListView
8
8
  className=""
9
9
  >
10
- <Component
10
+ <DropTarget(DragSource(Orderable(AnsibleRole)))
11
11
  icon="fa fa-minus-circle"
12
12
  index={0}
13
13
  key="1"
@@ -21,7 +21,7 @@ exports[`AssignedRolesList should render 1`] = `
21
21
  }
22
22
  }
23
23
  />
24
- <Component
24
+ <DropTarget(DragSource(Orderable(AnsibleRole)))
25
25
  icon="fa fa-minus-circle"
26
26
  index={1}
27
27
  key="2"
@@ -60,5 +60,5 @@ exports[`AssignedRolesList should render 1`] = `
60
60
  }
61
61
  />
62
62
  </div>
63
- </DndProvider>
63
+ </Memo(DndProvider)>
64
64
  `;
@@ -8,9 +8,14 @@ exports[`AvailableRolesList should render 1`] = `
8
8
  className="sticky-pagination"
9
9
  >
10
10
  <PaginationWrapper
11
+ className=""
12
+ disableNext={false}
13
+ disablePrev={false}
11
14
  dropdownButtonId="available-ansible-roles-pagination-row-dropdown"
12
15
  itemCount={2}
13
16
  onChange={[Function]}
17
+ onPageSet={[Function]}
18
+ onPerPageSelect={[Function]}
14
19
  pagination={
15
20
  Object {
16
21
  "page": 1,
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+
3
+ import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
4
+
5
+ import AnsibleHostDetail from './components/AnsibleHostDetail';
6
+
7
+ addGlobalFill(
8
+ 'host-details-page-tabs',
9
+ 'Ansible',
10
+ <AnsibleHostDetail key="ansible-host-detail" />,
11
+ 500
12
+ );
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_ansible
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.3.0
4
+ version: 6.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Lobato Garcia
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-17 00:00:00.000000000 Z
11
+ date: 2021-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: foreman_ansible_core
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '3.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '3.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: acts_as_list
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -302,9 +288,6 @@ files:
302
288
  - test/unit/hostgroup_ansible_role_test.rb
303
289
  - test/unit/ignore_roles_test.rb
304
290
  - test/unit/import_roles_and_variables.rb
305
- - test/unit/lib/foreman_ansible_core/ansible_runner_test.rb
306
- - test/unit/lib/foreman_ansible_core/command_creator_test.rb
307
- - test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
308
291
  - test/unit/lib/proxy_api/ansible_test.rb
309
292
  - test/unit/services/ansible_report_importer_test.rb
310
293
  - test/unit/services/ansible_variables_importer_test.rb
@@ -317,12 +300,10 @@ files:
317
300
  - test/unit/services/roles_importer_test.rb
318
301
  - test/unit/services/structured_fact_importer_test.rb
319
302
  - test/unit/services/ui_roles_importer_test.rb
320
- - webpack/__mocks__/foremanReact/common/I18n.js
321
- - webpack/__mocks__/foremanReact/common/helpers.js
322
- - webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js
323
- - webpack/__mocks__/foremanReact/components/common/EmptyState.js
324
- - webpack/__mocks__/foremanReact/components/common/forms/OrderableSelect/helpers.js
325
- - webpack/__mocks__/foremanReact/redux/API.js
303
+ - webpack/components/AnsibleHostDetail/AnsibleHostDetail.js
304
+ - webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss
305
+ - webpack/components/AnsibleHostDetail/AnsibleHostDetail.test.js
306
+ - webpack/components/AnsibleHostDetail/index.js
326
307
  - webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.js
327
308
  - webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.scss
328
309
  - webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesActions.js
@@ -368,13 +349,14 @@ files:
368
349
  - webpack/components/AnsibleRolesSwitcher/components/withProtectedView.js
369
350
  - webpack/components/AnsibleRolesSwitcher/index.js
370
351
  - webpack/components/ReportJsonViewer.js
352
+ - webpack/global_index.js
371
353
  - webpack/index.js
372
354
  - webpack/reducer.js
373
355
  homepage: https://github.com/theforeman/foreman_ansible
374
356
  licenses:
375
357
  - GPL-3.0
376
358
  metadata: {}
377
- post_install_message:
359
+ post_install_message:
378
360
  rdoc_options: []
379
361
  require_paths:
380
362
  - lib
@@ -390,7 +372,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
390
372
  version: '0'
391
373
  requirements: []
392
374
  rubygems_version: 3.1.2
393
- signing_key:
375
+ signing_key:
394
376
  specification_version: 4
395
377
  summary: Ansible integration with Foreman (theforeman.org)
396
378
  test_files:
@@ -399,8 +381,8 @@ test_files:
399
381
  - test/factories/ansible_roles.rb
400
382
  - test/factories/host_ansible_enhancements.rb
401
383
  - test/fixtures/insights_playbook.yaml
402
- - test/fixtures/report.json
403
384
  - test/fixtures/sample_facts.json
385
+ - test/fixtures/report.json
404
386
  - test/functional/ansible_roles_controller_test.rb
405
387
  - test/functional/api/v2/ansible_inventories_controller_test.rb
406
388
  - test/functional/api/v2/ansible_variables_controller_test.rb
@@ -419,16 +401,13 @@ test_files:
419
401
  - test/unit/concerns/host_managed_extensions_test.rb
420
402
  - test/unit/concerns/hostgroup_extensions_test.rb
421
403
  - test/unit/helpers/ansible_reports_helper_test.rb
422
- - test/unit/lib/foreman_ansible_core/command_creator_test.rb
423
- - test/unit/lib/foreman_ansible_core/ansible_runner_test.rb
424
- - test/unit/lib/foreman_ansible_core/playbook_runner_test.rb
425
404
  - test/unit/lib/proxy_api/ansible_test.rb
426
405
  - test/unit/services/ansible_report_importer_test.rb
427
- - test/unit/services/fact_importer_test.rb
428
406
  - test/unit/services/fact_sparser_test.rb
429
407
  - test/unit/services/insights_plan_runner_test.rb
430
408
  - test/unit/services/roles_importer_test.rb
431
409
  - test/unit/services/structured_fact_importer_test.rb
410
+ - test/unit/services/fact_importer_test.rb
432
411
  - test/unit/services/ansible_variables_importer_test.rb
433
412
  - test/unit/services/ui_roles_importer_test.rb
434
413
  - test/unit/services/api_roles_importer_test.rb
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- module ForemanAnsibleCore
6
- module Runner
7
- class AnsibleRunnerTest < ActiveSupport::TestCase
8
- describe AnsibleRunner do
9
- it 'parses files without event data' do
10
- content = <<~JSON
11
- {"uuid": "a29d8592-f805-4d0e-b73d-7a53cc35a92e", "stdout": " [WARNING]: Consider using the yum module rather than running 'yum'. If you", "counter": 8, "end_line": 8, "runner_ident": "e2d9ae11-026a-4f9f-9679-401e4b852ab0", "start_line": 7, "event": "verbose"}
12
- JSON
13
-
14
- File.expects(:read).with('fake.json').returns(content)
15
- runner = AnsibleRunner.allocate
16
- runner.expects(:handle_broadcast_data)
17
- assert runner.send(:handle_event_file, 'fake.json')
18
- end
19
- end
20
-
21
- describe '#rebuild_secrets' do
22
- let(:inventory) do
23
- { 'all' => { 'hosts' => ['foreman.example.com'] },
24
- '_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
25
- end
26
- let(:input) do
27
- host_secrets = { 'ansible_password' => 'letmein', 'ansible_become_password' => 'iamroot' }
28
- secrets = { 'per-host' => { 'foreman.example.com' => host_secrets } }
29
- host_input = { 'input' => { 'action_input' => { 'secrets' => secrets } } }
30
- { 'foreman.example.com' => host_input }
31
- end
32
- let(:runner) { ForemanAnsibleCore::Runner::AnsibleRunner.allocate }
33
-
34
- test 'uses secrets from inventory' do
35
- test_inventory = inventory.merge('ssh_password' => 'sshpass', 'effective_user_password' => 'mypass')
36
- rebuilt = runner.send(:rebuild_secrets, test_inventory, input)
37
- host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
38
- assert_equal 'sshpass', host_vars['ansible_password']
39
- assert_equal 'mypass', host_vars['ansible_become_password']
40
- end
41
-
42
- test 'host secrets are used when not overriden by inventory secrest' do
43
- rebuilt = runner.send(:rebuild_secrets, inventory, input)
44
- host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
45
- assert_equal 'letmein', host_vars['ansible_password']
46
- assert_equal 'iamroot', host_vars['ansible_become_password']
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class CommandCreatorTest < ActiveSupport::TestCase
6
- let(:inventory_file) { 'test_inventory' }
7
- let(:playbook_file) { 'test_palybook.yml' }
8
- subject do
9
- ForemanAnsibleCore::CommandCreator.new(inventory_file, playbook_file, {})
10
- end
11
-
12
- test 'returns a command array including the ansible-playbook command' do
13
- assert command_parts.include?('ansible-playbook')
14
- end
15
-
16
- test 'the last argument is the playbook_file' do
17
- assert command_parts.last == playbook_file
18
- end
19
-
20
- describe 'environment variables' do
21
- let(:environment_variables) { subject.command.first }
22
-
23
- test 'has a JSON_INVENTORY_FILE set' do
24
- assert environment_variables['JSON_INVENTORY_FILE']
25
- end
26
-
27
- test 'has no ANSIBLE_CALLBACK_WHITELIST set by default' do
28
- assert_not environment_variables['ANSIBLE_CALLBACK_WHITELIST']
29
- end
30
-
31
- test 'with a REX command it sets ANSIBLE_CALLBACK_WHITELIST to empty' do
32
- set_command_options(:remote_execution_command, true)
33
- assert environment_variables['ANSIBLE_CALLBACK_WHITELIST']
34
- end
35
- end
36
-
37
- describe 'command options' do
38
- it 'can have verbosity set' do
39
- level = '3'
40
- level_string = Array.new(level.to_i).map { 'v' }.join
41
- set_command_options(:verbosity_level, level)
42
- assert command_parts.any? do |part|
43
- part == "-#{level_string}"
44
- end
45
- end
46
-
47
- it 'can have a timeout set' do
48
- timeout = '5555'
49
- set_command_options(:timeout, timeout)
50
- assert command_parts.include?(timeout)
51
- end
52
- end
53
-
54
- private
55
-
56
- def command_parts
57
- subject.command.flatten.map(&:to_s)
58
- end
59
-
60
- def set_command_options(option, value)
61
- subject.instance_eval("@options[:#{option}] = \"#{value}\"",
62
- __FILE__, __LINE__ - 1)
63
- end
64
- end
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- # Playbook Runner - this class uses foreman_tasks_core
6
- # to run playbooks
7
- class PlaybookRunnerTest < ActiveSupport::TestCase
8
- context 'roles dir' do
9
- test 'reads default when none provided' do
10
- ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:unknown_hosts).
11
- returns([])
12
- File.expects(:exist?).with(Dir.home).returns(true)
13
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
14
- runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
15
- assert '/etc/ansible', runner.instance_variable_get('@ansible_dir')
16
- end
17
- end
18
-
19
- context 'working_dir' do
20
- setup do
21
- ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:unknown_hosts).
22
- returns([])
23
- end
24
-
25
- test 'creates temp one if not provided' do
26
- Dir.expects(:mktmpdir)
27
- File.expects(:exist?).with(Dir.home).returns(true)
28
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
29
- ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
30
- end
31
-
32
- test 'reads it when provided' do
33
- settings = { :working_dir => '/foo', :ansible_dir => '/etc/foo' }
34
- ForemanAnsibleCore.expects(:settings).returns(settings)
35
- File.expects(:exist?).with(settings[:ansible_dir]).returns(true)
36
- Dir.expects(:mktmpdir).never
37
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(nil)
38
- runner = ForemanAnsibleCore::Runner::Playbook.new(nil, nil, :suspended_action => nil)
39
- assert '/foo', runner.instance_variable_get('@working_dir')
40
- end
41
- end
42
-
43
- context 'TOFU policy' do # Trust On First Use
44
- setup do
45
- @inventory = { 'all' => { 'hosts' => ['foreman.example.com'] } }
46
- @output = StringIO.new
47
- logger = Logger.new(@output)
48
- ForemanAnsibleCore::Runner::Playbook.any_instance.stubs(:logger).
49
- returns(logger)
50
- end
51
-
52
- test 'ignores known hosts' do
53
- Net::SSH::KnownHosts.expects(:search_for).
54
- with('foreman.example.com').returns(['somekey'])
55
- ForemanAnsibleCore::Runner::Playbook.any_instance.
56
- expects(:add_to_known_hosts).never
57
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
58
- ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
59
- end
60
-
61
- test 'adds unknown hosts to known_hosts' do
62
- Net::SSH::KnownHosts.expects(:search_for).
63
- with('foreman.example.com').returns([])
64
- ForemanAnsibleCore::Runner::Playbook.any_instance.
65
- expects(:add_to_known_hosts).with('foreman.example.com')
66
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
67
- ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
68
- end
69
-
70
- test 'logs error when it cannot add to known_hosts' do
71
- Net::SSH::KnownHosts.expects(:search_for).
72
- with('foreman.example.com').returns([])
73
- Net::SSH::Transport::Session.expects(:new).with('foreman.example.com').
74
- raises(Net::Error)
75
- ForemanAnsibleCore::Runner::Playbook.any_instance.expects(:rebuild_secrets).returns(@inventory)
76
- ForemanAnsibleCore::Runner::Playbook.new(@inventory, nil, :suspended_action => nil)
77
- assert_match(
78
- /ERROR.*Failed to save host key for foreman.example.com: Net::Error/,
79
- @output.string
80
- )
81
- end
82
- end
83
-
84
- context 'rebuild secrets' do
85
- let(:inventory) do
86
- { 'all' => { 'hosts' => ['foreman.example.com'] },
87
- '_meta' => { 'hostvars' => { 'foreman.example.com' => {} } } }
88
- end
89
- let(:secrets) do
90
- host_secrets = { 'ansible_password' => 'letmein', 'ansible_become_password' => 'iamroot' }
91
- { 'per-host' => { 'foreman.example.com' => host_secrets } }
92
- end
93
- let(:runner) { ForemanAnsibleCore::Runner::Playbook.allocate }
94
-
95
- test 'uses secrets from inventory' do
96
- test_inventory = inventory.merge('ssh_password' => 'sshpass', 'effective_user_password' => 'mypass')
97
- rebuilt = runner.send(:rebuild_secrets, test_inventory, secrets)
98
- host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
99
- assert_equal 'sshpass', host_vars['ansible_password']
100
- assert_equal 'mypass', host_vars['ansible_become_password']
101
- end
102
-
103
- test 'host secrets are used when not overriden by inventory secrest' do
104
- rebuilt = runner.send(:rebuild_secrets, inventory, secrets)
105
- host_vars = rebuilt.dig('_meta', 'hostvars', 'foreman.example.com')
106
- assert_equal 'letmein', host_vars['ansible_password']
107
- assert_equal 'iamroot', host_vars['ansible_become_password']
108
- end
109
- end
110
- end
@@ -1 +0,0 @@
1
- export const translate = s => s;
@@ -1,13 +0,0 @@
1
- import { camelCase } from 'lodash';
2
-
3
- export const propsToCamelCase = ob =>
4
- propsToCase(camelCase, 'propsToCamelCase only takes objects', ob);
5
-
6
- const propsToCase = (casingFn, errorMsg, ob) => {
7
- if (typeof ob !== 'object') throw Error(errorMsg);
8
-
9
- return Object.keys(ob).reduce((memo, key) => {
10
- memo[casingFn(key)] = ob[key];
11
- return memo;
12
- }, {});
13
- };
@@ -1,2 +0,0 @@
1
- const PaginationWrapper = () => jest.fn();
2
- export default PaginationWrapper;
@@ -1,5 +0,0 @@
1
- const EmptyState = () => jest.fn();
2
-
3
- export const EmptyStatePattern = () => jest.fn();
4
-
5
- export default EmptyState;
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
-
3
- export const orderable = (Component, orderableProps) => props => (
4
- <Component {...orderableProps} {...props} />
5
- );
@@ -1,7 +0,0 @@
1
- export const API = {
2
- get: jest.fn(),
3
- put: jest.fn(),
4
- post: jest.fn(),
5
- delete: jest.fn(),
6
- patch: jest.fn(),
7
- };