foreman_ansible 2.3.2 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
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