foreman_ansible 2.3.2 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/foreman_ansible/foreman-ansible.css +4 -0
  3. data/app/controllers/ansible_variables_controller.rb +28 -6
  4. data/app/controllers/api/v2/ansible_variables_controller.rb +9 -1
  5. data/app/controllers/concerns/foreman/controller/parameters/ansible_variable.rb +2 -1
  6. data/app/controllers/ui_ansible_roles_controller.rb +14 -0
  7. data/app/helpers/foreman_ansible/ansible_roles_helper.rb +19 -1
  8. data/app/models/ansible_role.rb +1 -0
  9. data/app/models/ansible_variable.rb +8 -3
  10. data/app/services/foreman_ansible/variables_importer.rb +61 -30
  11. data/app/views/ansible_roles/welcome.html.erb +1 -1
  12. data/app/views/ansible_variables/_fields.erb +12 -5
  13. data/app/views/ansible_variables/import.html.erb +4 -1
  14. data/app/views/ansible_variables/index.html.erb +8 -3
  15. data/app/views/ansible_variables/new.html.erb +17 -0
  16. data/app/views/api/v2/ansible_variables/create.json.rabl +3 -0
  17. data/app/views/api/v2/ansible_variables/show.json.rabl +1 -1
  18. data/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb +13 -13
  19. data/app/views/ui_ansible_roles/index.json.rabl +3 -0
  20. data/app/views/ui_ansible_roles/main.json.rabl +3 -0
  21. data/app/views/ui_ansible_roles/show.json.rabl +3 -0
  22. data/config/routes.rb +4 -2
  23. data/db/migrate/20190318094437_add_imported_attr_to_ansible_variables.rb +15 -0
  24. data/lib/foreman_ansible/register.rb +13 -2
  25. data/lib/foreman_ansible/version.rb +1 -1
  26. data/package.json +50 -9
  27. data/test/factories/ansible_variables.rb +1 -0
  28. data/test/functional/ansible_variables_controller_test.rb +10 -0
  29. data/test/functional/api/v2/ansible_variables_controller_test.rb +10 -0
  30. data/test/functional/ui_ansible_roles_controller_test.rb +14 -0
  31. data/test/unit/services/ansible_variables_importer_test.rb +20 -3
  32. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  33. data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +5 -0
  34. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.js +140 -0
  35. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.scss +45 -0
  36. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherActions.js +69 -0
  37. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherConstants.js +7 -0
  38. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherHelpers.js +7 -0
  39. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherReducer.js +69 -0
  40. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherSelectors.js +68 -0
  41. data/webpack/components/AnsibleRolesSwitcher/__fixtures__/ansibleRolesData.fixtures.js +20 -0
  42. data/webpack/components/AnsibleRolesSwitcher/__fixtures__/ansibleRolesSwitcherReducer.fixtures.js +36 -0
  43. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcher.test.js +30 -0
  44. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcherReducer.test.js +73 -0
  45. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcherSelectors.test.js +43 -0
  46. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcher.test.js.snap +79 -0
  47. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcherReducer.test.js.snap +399 -0
  48. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcherSelectors.test.js.snap +60 -0
  49. data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.js +33 -0
  50. data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.test.js +9 -0
  51. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +56 -0
  52. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.test.js +26 -0
  53. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRoleActionButton.js +16 -0
  54. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRolesSwitcherError.js +32 -0
  55. data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.js +67 -0
  56. data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.test.js +19 -0
  57. data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.js +52 -0
  58. data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.test.js +22 -0
  59. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsiblePermissionDenied.test.js.snap +26 -0
  60. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsibleRole.test.js.snap +108 -0
  61. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap +64 -0
  62. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +54 -0
  63. data/webpack/components/AnsibleRolesSwitcher/components/withProtectedView.js +14 -0
  64. data/webpack/components/AnsibleRolesSwitcher/index.js +44 -0
  65. data/webpack/components/ReportJsonViewer.js +11 -7
  66. data/webpack/index.js +14 -1
  67. data/webpack/reducer.js +7 -0
  68. data/webpack/test_setup.js +11 -0
  69. metadata +46 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3dd4a02656d2b41202e38c91fda9cd2b5b7bfb08
4
- data.tar.gz: a7f7f75580a6d389b09dd3a1bb47c4420b1ffab2
3
+ metadata.gz: 1bc81f85be7efbc4ebb9636fc9bd550d54fb22f3
4
+ data.tar.gz: d89aa3d74ffb81ed88a678e5f139530bdec076aa
5
5
  SHA512:
6
- metadata.gz: 52866dabe9b2a7bac15bc23920541c896cc337304a1bafcfbe057645ea73c85939cdbc989cec226c7f32f61b254891b345b7720bb1d771074f25ece5feea4d39
7
- data.tar.gz: afdbf297b5fe851adb1a71352b7b821b109d203ad094b51ede3f0d7f3658ea0d358f84022040c056bccf8e12b0810e9b68e2c7db0ae3c15488a44825080bc29c
6
+ metadata.gz: 853c086e4c7a344844c2da7360221030dba7ea21fd9d65d0f387b3c76825af7b2bae258ca8914eeaecfee5756ca99fbfc0d6bf7580e96dff2f458a3e9d449162
7
+ data.tar.gz: af2d1693fc63a41a202a2de837a9ae678b1400fc5c5c3eda567d4211e7244ac4036880d061fa74681052b277f356f33840d25f1845f92c5f02cc599f318b3103
@@ -1,3 +1,7 @@
1
1
  .report-json-viewer * {
2
2
  background: transparent !important;
3
3
  }
4
+
5
+ .btn.btn-default.no-float {
6
+ float: none;
7
+ }
@@ -18,6 +18,19 @@ class AnsibleVariablesController < ::LookupKeysController
18
18
  :per_page => params[:per_page])
19
19
  end
20
20
 
21
+ def new
22
+ @ansible_variable = AnsibleVariable.new
23
+ end
24
+
25
+ def create
26
+ @ansible_variable = AnsibleVariable.new(ansible_variable_params.merge(:imported => false))
27
+ if @ansible_variable.save
28
+ process_success
29
+ else
30
+ process_error
31
+ end
32
+ end
33
+
21
34
  def import
22
35
  import_roles = @importer_roles.import_role_names
23
36
  import_roles[:new_roles] = import_roles[:new]
@@ -27,11 +40,12 @@ class AnsibleVariablesController < ::LookupKeysController
27
40
  end
28
41
 
29
42
  def confirm_import
30
- results = @importer.finish_import(new_vars, old_vars)
31
- info _(
43
+ results = @importer.finish_import(new_vars, old_vars, updated_vars)
44
+ success _(
32
45
  "Import of variables successfully finished.\n"\
33
- "Added: #{results[:added].join(', ')} \n "\
34
- "Removed: #{results[:obsolete].join(', ')}"
46
+ "Added: #{results[:added].count} \n "\
47
+ "Removed: #{results[:obsolete].count} \n"\
48
+ "Updated: #{results[:updated].count}"
35
49
  )
36
50
  redirect_to ansible_variables_path
37
51
  end
@@ -49,11 +63,19 @@ class AnsibleVariablesController < ::LookupKeysController
49
63
  end
50
64
 
51
65
  def new_vars
52
- params[:changed] ? params[:changed][:new].as_json : {}
66
+ fetch_vars :new
53
67
  end
54
68
 
55
69
  def old_vars
56
- params[:changed] ? params[:changed][:obsolete].as_json : {}
70
+ fetch_vars :obsolete
71
+ end
72
+
73
+ def updated_vars
74
+ fetch_vars :update
75
+ end
76
+
77
+ def fetch_vars(key)
78
+ params.fetch(:changed, {}).fetch(key, {}).try(:as_json) || {}
57
79
  end
58
80
 
59
81
  def import_new_roles
@@ -6,6 +6,7 @@ module Api
6
6
  class AnsibleVariablesController < ::Api::V2::BaseController
7
7
  include ::Api::Version2
8
8
  include Foreman::Controller::Parameters::VariableLookupKey
9
+ include Foreman::Controller::Parameters::AnsibleVariable
9
10
 
10
11
  resource_description do
11
12
  api_version 'v2'
@@ -36,7 +37,7 @@ module Api
36
37
  def_param_group :ansible_variable do
37
38
  param :ansible_variable, Hash, :required => true, :action_aware => true do
38
39
  param :variable, String, :required => true, :desc => N_("Name of variable")
39
- param :ansible_role_id, :number, :desc => N_("Role ID")
40
+ param :ansible_role_id, :number, :required => true, :desc => N_("Role ID")
40
41
  param :default_value, :any_type, :of => LookupKey::KEY_TYPES, :desc => N_("Default value of variable")
41
42
  param :hidden_value, :bool, :desc => N_("When enabled the parameter is hidden in the UI")
42
43
  param :override_value_order, String, :desc => N_("The order in which values are resolved")
@@ -50,6 +51,13 @@ module Api
50
51
  end
51
52
  end
52
53
 
54
+ api :POST, '/ansible_variables', N_('Create Ansible variable')
55
+ param_group :ansible_variable, :as => :create
56
+ def create
57
+ @ansible_variable = AnsibleVariable.new(ansible_variable_params.merge(:imported => false))
58
+ process_response @ansible_variable.save
59
+ end
60
+
53
61
  api :PUT, '/ansible_variables/:id', N_('Updates Ansible variable')
54
62
  param :id, :identifier, :required => true
55
63
  param_group :ansible_variable, :as => :update
@@ -11,7 +11,8 @@ module Foreman
11
11
  class_methods do
12
12
  def ansible_variable_params_filter
13
13
  Foreman::ParameterFilter.new(::AnsibleVariable).tap do |filter|
14
- filter.permit :ansible_roles => [], :ansible_role_ids => [],
14
+ filter.permit :imported, :ansible_role_id,
15
+ :ansible_roles => [], :ansible_role_ids => [],
15
16
  :ansible_role_names => [],
16
17
  :param_classes => [], :param_classes_ids => [],
17
18
  :param_classes_names => []
@@ -0,0 +1,14 @@
1
+ class UiAnsibleRolesController < ::Api::V2::BaseController
2
+ def resource_name(resource = 'AnsibleRole')
3
+ super resource
4
+ end
5
+
6
+ def index
7
+ @ui_ansible_roles = resource_scope_for_index(:permission => :view_ansible_roles)
8
+ end
9
+
10
+ # restore original method from find_common to ignore resource nesting
11
+ def resource_scope(options = {})
12
+ @resource_scope ||= scope_for(resource_class, options)
13
+ end
14
+ end
@@ -5,12 +5,26 @@ module ForemanAnsible
5
5
  module AnsibleRolesHelper
6
6
  def ansible_proxy_links(hash, classes = nil)
7
7
  SmartProxy.with_features('Ansible').map do |proxy|
8
- display_link_if_authorized(_('From %s') % proxy.name,
8
+ display_link_if_authorized(_('Import from %s') % proxy.name,
9
9
  hash.merge(:proxy => proxy),
10
10
  :class => classes)
11
11
  end.flatten
12
12
  end
13
13
 
14
+ def ansible_role_select(f, persisted)
15
+ blank_opt = persisted ? {} : { :include_blank => true }
16
+ select_items = persisted ? [f.object.ansible_role] : AnsibleRole.order(:name)
17
+ select_f f,
18
+ :ansible_role_id,
19
+ select_items,
20
+ :id,
21
+ :to_label,
22
+ blank_opt,
23
+ :label => _("Ansible Role"),
24
+ :disabled => persisted,
25
+ :required => true
26
+ end
27
+
14
28
  def ansible_proxy_import(hash)
15
29
  select_action_button(_('Import'),
16
30
  { :primary => true, :class => 'roles-import' },
@@ -20,5 +34,9 @@ module ForemanAnsible
20
34
  def import_time(role)
21
35
  _('%s ago') % time_ago_in_words(role.updated_at)
22
36
  end
37
+
38
+ def roles_attrs(roles)
39
+ roles.map { |item| { :id => item.id, :name => item.name } }
40
+ end
23
41
  end
24
42
  end
@@ -17,6 +17,7 @@ class AnsibleRole < ApplicationRecord
17
17
  :class_name => 'AnsibleVariable'
18
18
 
19
19
  scoped_search :on => :name, :complete_value => true
20
+ scoped_search :on => :id, :complete_value => false
20
21
  scoped_search :on => :updated_at
21
22
  scoped_search :relation => :hosts,
22
23
  :on => :id, :rename => :host_id, :only_explicit => true
@@ -3,8 +3,9 @@
3
3
  # Represents the variables used in Ansible to parameterize playbooks
4
4
  class AnsibleVariable < LookupKey
5
5
  belongs_to :ansible_role, :inverse_of => :ansible_variables
6
- validates :ansible_role, :presence => true
6
+ validates :ansible_role_id, :presence => true
7
7
  scoped_search :on => :key, :aliases => [:name], :complete_value => true
8
+ scoped_search :on => :imported, :complete_value => { :true => true, :false => false }
8
9
  scoped_search :relation => :ansible_role, :on => :name,
9
10
  :complete_value => true, :rename => :ansible_role
10
11
 
@@ -12,8 +13,12 @@ class AnsibleVariable < LookupKey
12
13
  true
13
14
  end
14
15
 
15
- def self.humanize_class_name
16
- 'Ansible variable'
16
+ def self.humanize_class_name(options = nil)
17
+ if options.present?
18
+ super
19
+ else
20
+ "Ansible variable"
21
+ end
17
22
  end
18
23
 
19
24
  def editable_by_user?
@@ -6,6 +6,17 @@ module ForemanAnsible
6
6
  class VariablesImporter
7
7
  include ::ForemanAnsible::ProxyAPI
8
8
 
9
+ VARIABLE_TYPES = {
10
+ 'TrueClass' => 'boolean',
11
+ 'FalseClass' => 'boolean',
12
+ 'Integer' => 'integer',
13
+ 'Fixnum' => 'integer',
14
+ 'Float' => 'real',
15
+ 'Array' => 'array',
16
+ 'Hash' => 'hash',
17
+ 'String' => 'string'
18
+ }.freeze
19
+
9
20
  def initialize(proxy = nil)
10
21
  @ansible_proxy = proxy
11
22
  end
@@ -34,11 +45,15 @@ module ForemanAnsible
34
45
  end
35
46
 
36
47
  def initialize_variables(variables, role)
37
- variables.map do |variable|
48
+ variables.map do |variable_name, variable_default|
38
49
  variable = AnsibleVariable.find_or_initialize_by(
39
- :key => variable
40
- # :key_type, :default_value, :required
50
+ :key => variable_name
41
51
  )
52
+ if variable.new_record?
53
+ variable.assign_attributes(:default_value => variable_default,
54
+ :key_type => infer_key_type(variable_default),
55
+ :imported => true)
56
+ end
42
57
  variable.ansible_role = role
43
58
  variable.valid? ? variable : nil
44
59
  end
@@ -46,45 +61,48 @@ module ForemanAnsible
46
61
 
47
62
  def detect_changes(imported)
48
63
  changes = {}.with_indifferent_access
49
- old, changes[:new] = imported.partition { |role| role.id.present? }
50
- changes[:obsolete] = AnsibleVariable.where.not(:id => old.map(&:id))
64
+ persisted, changes[:new] = imported.partition { |role| role.id.present? }
65
+ changes[:update], _old = persisted.partition(&:changed?)
66
+ changes[:obsolete] = AnsibleVariable.where.not(:id => persisted.pluck(:id), :imported => false)
51
67
  changes
52
68
  end
53
69
 
54
- def finish_import(new, obsolete)
55
- results = { :added => [], :obsolete => [] }
70
+ def finish_import(new, obsolete, update)
71
+ results = { :added => [], :obsolete => [], :updated => [] }
56
72
  results[:added] = create_new_variables(new) if new.present?
57
73
  results[:obsolete] = delete_old_variables(obsolete) if obsolete.present?
74
+ results[:updated] = update_variables(update) if update.present?
58
75
  results
59
76
  end
60
77
 
61
- def create_new_variables(new)
62
- added = []
63
- new.each do |role, variables|
64
- variables.each_value do |variable_properties|
65
- variable = AnsibleVariable.new(
66
- JSON.parse(variable_properties)['ansible_variable']
67
- )
68
- variable.ansible_role = ::AnsibleRole.find_by(:name => role)
69
- variable.save
70
- added << variable.key
71
- end
78
+ def create_new_variables(variables)
79
+ iterate_over_variables(variables) do |role, memo, attrs|
80
+ variable = AnsibleVariable.new(
81
+ JSON.parse(attrs)['ansible_variable']
82
+ )
83
+ variable.ansible_role = ::AnsibleRole.find_by(:name => role)
84
+ variable.save
85
+ memo << variable
72
86
  end
73
- added
74
87
  end
75
88
 
76
- def delete_old_variables(old)
77
- removed = []
78
- old.each_value do |variables|
79
- variables.each_value do |variable|
80
- variable = AnsibleVariable.find(
81
- JSON.parse(variable)['ansible_variable']['id']
82
- )
83
- removed << variable.key
84
- variable.destroy
85
- end
89
+ def update_variables(variables)
90
+ iterate_over_variables(variables) do |_role, memo, attrs|
91
+ attributes = JSON.parse(attrs)['ansible_variable']
92
+ var = AnsibleVariable.find attributes['id']
93
+ var.update(attributes)
94
+ memo << var
95
+ end
96
+ end
97
+
98
+ def delete_old_variables(variables)
99
+ iterate_over_variables(variables) do |_role, memo, attrs|
100
+ variable = AnsibleVariable.find(
101
+ JSON.parse(attrs)['ansible_variable']['id']
102
+ )
103
+ memo << variable.key
104
+ variable.destroy
86
105
  end
87
- removed
88
106
  end
89
107
 
90
108
  private
@@ -96,5 +114,18 @@ module ForemanAnsible
96
114
  def remote_variables
97
115
  proxy_api.all_variables
98
116
  end
117
+
118
+ def infer_key_type(value)
119
+ VARIABLE_TYPES[value.class.to_s] || 'string'
120
+ end
121
+
122
+ def iterate_over_variables(variables)
123
+ variables.reduce([]) do |memo, (role, vars)|
124
+ vars.map do |_key, attrs|
125
+ yield role, memo, attrs if block_given?
126
+ memo
127
+ end
128
+ end
129
+ end
99
130
  end
100
131
  end
@@ -7,7 +7,7 @@
7
7
  <p><%= _('No ansible roles were found in Foreman. If you want to assign roles to your hosts,
8
8
  you have to import them first.').html_safe %>
9
9
  </p>
10
- <p><%= link_to(_('Learn more about this in the documentation.'), documentation_url('#4.1ImportingRoles', :root_url => ansible_doc_url)) %></p>
10
+ <p><%= link_to(_('Learn more about this in the documentation.'), documentation_url('#4.1ImportingRoles', :root_url => ansible_doc_url), target: '_blank') %></p>
11
11
  <div class="blank-slate-pf-secondary-action">
12
12
  <%= ansible_proxy_import(hash_for_import_ansible_roles_path) %>
13
13
  </div>
@@ -1,10 +1,11 @@
1
1
  <div id='<%= f.object.to_param %>' class='tab-pane fields'>
2
2
  <fieldset>
3
- <h2><%= _("Ansible Variable Details") %></h2>
4
- <%= text_f f, :key, :disabled => true, :size => "col-md-8" %>
5
- <%= f.hidden_field :key %>
3
+ <% is_imported = f.object.new_record? ? false : f.object.imported %>
4
+ <h2><%= is_imported ? _("Ansible Variable Details (Imported)") : _("Ansible Variable Details")%></h2>
5
+ <%= text_f f, :key, :disabled => f.object.persisted?, :size => "col-md-8" %>
6
6
  <%= textarea_f f, :description, :rows => :auto, :size => "col-md-8", :class => "no-stretch" %>
7
- <%= select_f f, :ansible_role_id, [f.object.ansible_role], :id, :to_label, {}, :label => _("Ansible Role"), :disabled => true %>
7
+ <%= ansible_role_select f, f.object.persisted? %>
8
+
8
9
  </fieldset>
9
10
  <fieldset>
10
11
  <h2><%= _("Default Behavior") %></h2>
@@ -12,7 +13,13 @@
12
13
  <%= checkbox_f(f, :override, :onchange => 'toggleOverrideValue(this)', :size => "col-md-8",
13
14
  :label_help => _('Mark the variable to be managed by Foreman. When the Ansible role of this variable is assigned to a host, the default value will be added to Ansible inventory as a host variable. Specify matchers to set a different value for such variable.')
14
15
  ) %>
15
- <%= param_type_selector(f, false, :onchange => 'keyTypeChange(this)', :disabled => !f.object.override) %>
16
+
17
+ <% version = Foreman::Version.new %>
18
+ <% if version.major.to_i >= 1 && version.minor.to_i >= 22 %>
19
+ <%= param_type_selector(f, false, :onchange => 'keyTypeChange(this)', :disabled => !f.object.override) %>
20
+ <% else %>
21
+ <%= param_type_selector(f, :onchange => 'keyTypeChange(this)', :disabled => !f.object.override) %>
22
+ <% end %>
16
23
  <%= textarea_f f, :default_value, :value => f.object.default_value_before_type_cast, :size => "col-md-8",
17
24
  :disabled => (!f.object.override || f.object.omit),
18
25
  :input_group_btn => fullscreen_input,
@@ -9,6 +9,9 @@
9
9
  <%= link_to_function(icon_text("check", _("Obsolete")),
10
10
  "toggleCheckboxesBySelector('.variable_select_boxes_obsolete')",
11
11
  :title => _("Check/Uncheck obsolete")) %>
12
+ <%= link_to_function(icon_text("check", _("Update")),
13
+ "toggleCheckboxesBySelector('.variable_select_boxes_update')",
14
+ :title => _("Check/Uncheck update")) %>
12
15
  </h6>
13
16
  <table class="<%= table_css_classes %>">
14
17
  <thead>
@@ -39,7 +42,7 @@
39
42
  <td><%= variable.ansible_role.hosts.count %></td>
40
43
  <td><%= variable.ansible_role.hostgroups.count %></td>
41
44
  <td>
42
- <%= { "new" => _("Add"), "obsolete" => _("Remove") }[kind] %>
45
+ <%= { "new" => _("Add"), "obsolete" => _("Remove"), "update" => _("Update") }[kind] %>
43
46
  </td>
44
47
  </tr>
45
48
  <% end %>
@@ -1,14 +1,18 @@
1
1
  <% title _("Ansible Variables") %>
2
+ <%= stylesheet 'foreman_ansible/foreman-ansible' %>
2
3
 
3
- <% title_actions ansible_proxy_import(hash_for_import_ansible_variables_path),
4
- documentation_button('#4.3Variables', :root_url => ansible_doc_url) %>
4
+ <%= title_actions ansible_proxy_import(hash_for_import_ansible_variables_path),
5
+ display_link_if_authorized(_('New Ansible Variable'), hash_for_new_ansible_variable_path, :class => "btn btn-default no-float"),
6
+ documentation_button('#4.3Variables', :root_url => ansible_doc_url)
7
+ %>
5
8
 
6
9
  <table class="<%= table_css_classes 'table-fixed' %>">
7
10
  <thead>
8
11
  <tr>
9
12
  <th class='col-md-6'><%= sort :name, :as => s_('Variable|Name') %></th>
10
13
  <th class='col-md-2'><%= sort :ansible_role, :as => s_('Variable|Role') %></th>
11
- <th class='col-md-2'><%= _('Type') %></th>
14
+ <th class='col-md-1'><%= _('Type') %></th>
15
+ <th class='col-md-1'><%= sort :imported, :as => _('Imported?') %></th>
12
16
  <th class='col-md-2'><%= _('Actions') %></th>
13
17
  </tr>
14
18
  </thead>
@@ -27,6 +31,7 @@
27
31
  hash_for_ansible_variables_path(:search => "ansible_role = #{variable.ansible_role}")
28
32
  ) %></td>
29
33
  <td class="ellipsis"><%= variable.key_type || 'string' %></td>
34
+ <td align='center'><%= checked_icon variable.imported %></td>
30
35
  <td class="ellipsis">
31
36
  <% links = [
32
37
  display_delete_if_authorized(
@@ -0,0 +1,17 @@
1
+ <%= breadcrumbs(
2
+ :items => [
3
+ {
4
+ :caption => _('Ansible Variables'),
5
+ :url => url_for(ansible_variables_path)
6
+ },
7
+ {
8
+ :caption => _('Create Ansible Variable')
9
+ }
10
+ ],
11
+ :switchable => false
12
+ ) %>
13
+ <% title(_('Create Ansible Variable')) %>
14
+ <%= form_for(@ansible_variable) do |f| %>
15
+ <%= render 'fields', :f => f %>
16
+ <%= submit_or_cancel f %>
17
+ <% end %>
@@ -0,0 +1,3 @@
1
+ object @ansible_variable
2
+
3
+ extends "api/v2/ansible_variables/show"
@@ -5,7 +5,7 @@ attributes :id, :variable, :ansible_role, :ansible_role_id, :description, :overr
5
5
  :variable_type, :hidden_value?, :validator_type,
6
6
  :validator_rule, :merge_overrides, :merge_default,
7
7
  :avoid_duplicates, :override_value_order, :created_at, :updated_at,
8
- :default_value
8
+ :default_value, :imported
9
9
 
10
10
  node do |ansible_variable|
11
11
  {
@@ -1,15 +1,15 @@
1
+ <%= webpacked_plugins_js_for :foreman_ansible %>
2
+ <%= webpacked_plugins_css_for :foreman_ansible %>
3
+
1
4
  <div class='tab-pane' id='ansible_roles'>
2
- <%= multiple_selects(
3
- f,
4
- :ansible_roles,
5
- AnsibleRole,
6
- f.object.is_a?(Hostgroup) ? (f.object.inherited_and_own_ansible_roles).map(&:id) : f.object.all_ansible_roles.map(&:id),
7
- {
8
- :disabled => f.object.inherited_ansible_roles.map(&:id),
9
- :label => _('Available roles'),
10
- :label_help => _('This list of roles will be applied when the host finishes<br/> '\
11
- 'provisioning. Users can also play these roles through the API<br/>'\
12
- 'or by clicking on the Play Roles button on the Host page ').html_safe
13
- },
14
- { 'data-inheriteds' => f.object.inherited_ansible_roles.map(&:id).to_json }) %>
5
+ <div id='ansible_roles_switcher'></div>
6
+ <% roles = f.object.is_a?(Hostgroup) ? roles_attrs(f.object.inherited_and_own_ansible_roles) : roles_attrs(f.object.all_ansible_roles) %>
7
+ <% class_name = f.object.is_a?(Hostgroup) ? 'Hostgroup' : 'Host' %>
8
+ <%= mount_react_component('AnsibleRolesSwitcher', '#ansible_roles_switcher', { :initialAssignedRoles => roles,
9
+ :inheritedRoleIds => f.object.inherited_ansible_roles.map(&:id),
10
+ :availableRolesUrl => ui_ansible_roles_path,
11
+ :resourceId => f.object.id,
12
+ :resourceName => class_name,
13
+ :canView => User.current.can?(:view_ansible_roles)
14
+ }.to_json) %>
15
15
  </div>
@@ -0,0 +1,3 @@
1
+ collection @ui_ansible_roles
2
+
3
+ extends "ui_ansible_roles/main"
@@ -0,0 +1,3 @@
1
+ object @ansible_role
2
+
3
+ extends "ui_ansible_roles/show"
@@ -0,0 +1,3 @@
1
+ object @ansible_role
2
+
3
+ extends "api/v2/ansible_roles/show"
data/config/routes.rb CHANGED
@@ -58,7 +58,9 @@ Rails.application.routes.draw do
58
58
  end
59
59
  end
60
60
 
61
- resources :ansible_variables, :except => [:show, :new, :create] do
61
+ resources :ui_ansible_roles, :only => [:index]
62
+
63
+ resources :ansible_variables, :except => [:show] do
62
64
  resources :lookup_values, :only => [:index, :create, :update, :destroy]
63
65
  collection do
64
66
  get :import
@@ -82,7 +84,7 @@ Rails.application.routes.draw do
82
84
  end
83
85
  end
84
86
 
85
- resources :ansible_variables, :only => [:show, :index, :destroy, :update] do
87
+ resources :ansible_variables, :only => [:show, :index, :destroy, :update, :create] do
86
88
  collection do
87
89
  put :import
88
90
  put :obsolete
@@ -0,0 +1,15 @@
1
+ class AddImportedAttrToAnsibleVariables < ActiveRecord::Migration[5.2]
2
+ def up
3
+ add_column :lookup_keys, :imported, :boolean
4
+
5
+ AnsibleVariable.find_in_batches do |batch|
6
+ batch.map do |variable|
7
+ variable.update_attribute :imported, true
8
+ end
9
+ end
10
+ end
11
+
12
+ def down
13
+ remove_column :lookup_keys, :imported
14
+ end
15
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # rubocop:disable BlockLength
4
4
  Foreman::Plugin.register :foreman_ansible do
5
- requires_foreman '>= 1.16'
5
+ requires_foreman '>= 1.21'
6
6
 
7
7
  security_block :foreman_ansible do
8
8
  permission :play_roles_on_host,
@@ -17,7 +17,8 @@ Foreman::Plugin.register :foreman_ansible do
17
17
  :resource_type => 'Hostgroup'
18
18
  permission :view_ansible_roles,
19
19
  { :ansible_roles => [:index, :auto_complete_search],
20
- :'api/v2/ansible_roles' => [:index, :show, :fetch] },
20
+ :'api/v2/ansible_roles' => [:index, :show, :fetch],
21
+ :ui_ansible_roles => [:index] },
21
22
  :resource_type => 'AnsibleRole'
22
23
  permission :destroy_ansible_roles,
23
24
  { :ansible_roles => [:destroy],
@@ -44,6 +45,12 @@ Foreman::Plugin.register :foreman_ansible do
44
45
  :'api/v2/ansible_variables' => [:destroy, :obsolete]
45
46
  },
46
47
  :resource_type => 'AnsibleVariable'
48
+ permission :create_ansible_variables,
49
+ {
50
+ :ansible_variables => [:new, :create],
51
+ :'api/v2/ansible_variables' => [:create]
52
+ },
53
+ :resource_type => 'AnsibleVariable'
47
54
  permission :import_ansible_variables,
48
55
  {
49
56
  :ansible_variables => [:import, :confirm_import],
@@ -69,6 +76,10 @@ Foreman::Plugin.register :foreman_ansible do
69
76
  :view_ansible_roles, :destroy_ansible_roles,
70
77
  :import_ansible_roles]
71
78
 
79
+ role 'Ansible Tower Inventory Reader',
80
+ [:view_hosts, :view_hostgroups, :view_facts],
81
+ 'Permissions required for the user which is used by Ansible Tower Dynamic Inventory Item'
82
+
72
83
  add_all_permissions_to_default_roles
73
84
  extend_template_helpers ForemanAnsible::RendererMethods
74
85
  allowed_template_helpers :insights_remediation
@@ -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 = '2.3.2'
7
+ VERSION = '2.3.3'
8
8
  end