foreman_salt 2.0.2 → 2.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.
Files changed (40) hide show
  1. checksums.yaml +13 -5
  2. data/app/assets/javascripts/foreman_salt/states.js +33 -0
  3. data/app/controllers/foreman_salt/api/v2/salt_states_controller.rb +53 -2
  4. data/app/controllers/foreman_salt/concerns/hostgroups_controller_extensions.rb +23 -2
  5. data/app/controllers/foreman_salt/concerns/hosts_controller_extensions.rb +7 -3
  6. data/app/controllers/foreman_salt/minions_controller.rb +33 -1
  7. data/app/controllers/foreman_salt/salt_modules_controller.rb +45 -1
  8. data/app/controllers/foreman_salt/state_importer.rb +72 -0
  9. data/app/helpers/foreman_salt/salt_modules_helper.rb +19 -0
  10. data/app/lib/proxy_api/salt.rb +18 -0
  11. data/app/models/foreman_salt/concerns/host_managed_extensions.rb +23 -8
  12. data/app/models/foreman_salt/concerns/hostgroup_extensions.rb +12 -9
  13. data/app/models/foreman_salt/host_salt_module.rb +6 -0
  14. data/app/models/foreman_salt/hostgroup_salt_module.rb +6 -0
  15. data/app/models/foreman_salt/salt_environment.rb +13 -6
  16. data/app/models/foreman_salt/salt_module.rb +27 -5
  17. data/app/models/foreman_salt/salt_module_environment.rb +14 -0
  18. data/app/overrides/salt_environment_host_selector.rb +9 -0
  19. data/app/overrides/{salt_environment_selector.rb → salt_environment_hostgroup_selector.rb} +2 -6
  20. data/app/overrides/salt_modules_selector.rb +4 -4
  21. data/app/services/foreman_salt/fact_importer.rb +1 -1
  22. data/app/services/foreman_salt/report_importer.rb +9 -7
  23. data/app/services/foreman_salt/smart_proxies/salt_keys.rb +1 -1
  24. data/app/views/foreman_salt/salt_environments/index.html.erb +8 -2
  25. data/app/views/foreman_salt/salt_modules/_form.html.erb +7 -1
  26. data/app/{overrides/foreman → views/foreman_salt}/salt_modules/_host_tab.html.erb +0 -0
  27. data/app/views/foreman_salt/salt_modules/_host_tab_pane.html.erb +33 -0
  28. data/app/views/foreman_salt/salt_modules/import.html.erb +43 -0
  29. data/app/views/foreman_salt/salt_modules/index.html.erb +17 -5
  30. data/config/routes.rb +23 -3
  31. data/db/migrate/20150411003302_add_environments_to_modules.rb +17 -0
  32. data/db/migrate/20150509094409_rename_join_tables.rb +11 -0
  33. data/db/migrate/20150509101505_add_primary_keys.rb +6 -0
  34. data/lib/foreman_salt/engine.rb +21 -1
  35. data/lib/foreman_salt/version.rb +1 -1
  36. data/lib/tasks/foreman_salt_tasks.rake +0 -1
  37. data/test/unit/host_extensions_test.rb +15 -1
  38. data/test/unit/hostgroup_extensions_test.rb +2 -2
  39. metadata +35 -24
  40. data/app/overrides/foreman/salt_modules/_host_tab_pane.html.erb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2f3f97f7067977ffca23c926e798efc4a29d240d
4
- data.tar.gz: e2f771a0dcf32c7077bb1ac66bd0521f7d784713
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDYxMGMzYTMxM2FjODk0NGY5YzU2YWFlYjZlZGIxOGM4OGMwYzQ1MQ==
5
+ data.tar.gz: !binary |-
6
+ ZWYxNGRiOWY2MmYxMjExNTJiYWM4N2ZlOTE3ZjBiZGJiNWIzOGExZg==
5
7
  SHA512:
6
- metadata.gz: da42071ca83b47261517336c59ed9218d797169a3a4d142e36bfe6e423275bee81fca4d5f21886475b77ae79a182b695dad8e533c649e7fc16a6b5f0a0aaef03
7
- data.tar.gz: 6b08a1effbccba43df1ea0721488ca8c28467468994f3b102bdbf14c8d8c6be14873710dfbe9a2d0e85623d8e3d211a90e9b4186390bc1e4094d744b65fad9c8
8
+ metadata.gz: !binary |-
9
+ YmU3NjEwNzA3NWMwOWQ0MDBhYTljOWMxOWZjNzliMTJlODc4NzRlOWVlN2Q5
10
+ ZWY4MGNiNjlmNWNlNGMxNWVmYjU0YmQ1YjkyODhjYTY2YzM2ODIxYjNkYjc2
11
+ MGQwNzI0NTFjNGUzZDQxOWU2YWQzZWQ1ZDgwZjJkNmYxN2MyMWQ=
12
+ data.tar.gz: !binary |-
13
+ NDA2MDM3Y2ZiMzE5NzUwOWMwY2QyYmE4YzFmY2YzNDIyYmE2NzM4YjM0ODc3
14
+ NGE0MDdjMGJjYzA2MWIzOTg3NzRhNGUyMTdlZWVmN2M1ODAyYTAyZDY5YjM3
15
+ NGI2NGI2MjZmYzA5NGU2ZTQ4NTA4YzgxYmJlMjI5Y2I2ODBlMTM=
@@ -0,0 +1,33 @@
1
+ $(document).on( "ContentLoad", function() {
2
+ update_salt_states($('#host_salt_environment_id'));
3
+ });
4
+
5
+ function update_salt_states(element) {
6
+ var host_id = $("form").data('id')
7
+ var env_id = $('*[id*=salt_environment_id]').val();
8
+ var url = $(element).attr('data-url');
9
+ var data = $("form").serialize().replace('method=put', 'method=post');
10
+
11
+ if (url.match('hostgroups')) {
12
+ data = data + '&hostgroup_id=' + host_id
13
+ } else {
14
+ data = data + '&host_id=' + host_id
15
+ }
16
+
17
+ if (env_id == "") return;
18
+
19
+ $(element).indicator_show();
20
+ $.ajax({
21
+ type: 'post',
22
+ url: url,
23
+ data: data,
24
+ success: function(request) {
25
+ $('#salt_modules').html(request);
26
+ $('[rel="twipsy"]').tooltip();
27
+ multiSelectOnLoad();
28
+ },
29
+ complete: function() {
30
+ $(element).indicator_hide();
31
+ }
32
+ });
33
+ }
@@ -2,11 +2,22 @@ module ForemanSalt
2
2
  module Api
3
3
  module V2
4
4
  class SaltStatesController < ::ForemanSalt::Api::V2::BaseController
5
- before_filter :find_resource, :except => [:index, :create]
5
+ include StateImporter
6
+
7
+ before_filter :find_resource, :except => [:index, :create, :import]
8
+ before_filter :find_proxy, :only => :import
9
+ before_filter :find_environment, :only => :index
6
10
 
7
11
  api :GET, '/salt_states', N_('List all Salt states')
12
+ param :salt_environment_id, :identifier_dottable, :required => false, :desc => N_('Limit to a specific environment')
8
13
  def index
9
- @salt_states = resource_scope_for_index
14
+ if @salt_environment
15
+ @salt_states = resource_scope_for_index.joins(:salt_environments).where('salt_module_environments.salt_environment_id' => @salt_environment)
16
+ else
17
+ @salt_states = resource_scope_for_index
18
+ end
19
+
20
+ @subtotal = @salt_states.count
10
21
  end
11
22
 
12
23
  api :GET, '/salt_states/:id/', N_('Show a state')
@@ -33,6 +44,28 @@ module ForemanSalt
33
44
  process_response @salt_state.destroy
34
45
  end
35
46
 
47
+ api :POST, '/salt_states/import/:smart_proxy_id', N_('Import states from a salt master')
48
+ param :smart_proxy_id, :identifier_dottable, :required => true, :desc => N_('Salt Smart Proxy ID')
49
+ param :salt_environment_ids, Array, :required => false, :desc => N_('Limit to a specific environments')
50
+ param :actions, Array, :required => false, :desc => N_('Limit to specific actions: i.e. add, remove')
51
+ param :dryrun, :bool, :required => false, :desc => N_('Dryrun only')
52
+ def import
53
+ states = fetch_states_from_proxy(@proxy, params[:salt_environment_ids])
54
+ unless params[:dryrun]
55
+ states[:changes].each do |environment, state|
56
+ if state[:add].any? && (params[:actions].blank? || params[:actions].include?('add'))
57
+ add_to_environment(state[:add], environment)
58
+ end
59
+
60
+ if state[:remove].any? && (params[:actions].blank? || params[:actions].include?('remove'))
61
+ remove_from_environment(state[:remove], environment)
62
+ end
63
+ end
64
+ clean_orphans
65
+ end
66
+ render :text => states.to_json
67
+ end
68
+
36
69
  def controller_permission
37
70
  'salt_modules'
38
71
  end
@@ -40,6 +73,24 @@ module ForemanSalt
40
73
  def resource_class
41
74
  ForemanSalt::SaltModule
42
75
  end
76
+
77
+ def action_permission
78
+ case params[:action]
79
+ when 'import'
80
+ :import
81
+ else
82
+ super
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def find_environment
89
+ if params[:salt_environment_id]
90
+ @salt_environment = ForemanSalt::SaltEnvironment.find(params[:salt_environment_id])
91
+ fail _('Could not find salt environment with id %s') % params[:salt_environment_id] unless @salt_environment
92
+ end
93
+ end
43
94
  end
44
95
  end
45
96
  end
@@ -7,12 +7,33 @@ module ForemanSalt
7
7
  alias_method_chain :load_vars_for_ajax, :salt_modules
8
8
  end
9
9
 
10
+ def salt_environment_selected
11
+ @hostgroup = Hostgroup.authorized(:view_hostgroups, Hostgroup).find_by_id(params[:hostgroup_id]) || Hostgroup.new(params[:hostgroup])
12
+
13
+ if params[:hostgroup][:salt_environment_id].present?
14
+ @salt_environment = ::ForemanSalt::SaltEnvironment.find(params[:hostgroup][:salt_environment_id])
15
+ load_vars_for_ajax
16
+ render :partial => 'foreman_salt/salt_modules/host_tab_pane'
17
+ else
18
+ logger.info 'environment_id is required to render states'
19
+ end
20
+ end
21
+
10
22
  private
11
23
 
12
24
  def load_vars_for_ajax_with_salt_modules
13
25
  load_vars_for_ajax_without_salt_modules
14
- @salt_modules = @hostgroup.salt_modules
15
- @inherited_salt_modules = @hostgroup.inherited_salt_modules
26
+ @obj = @hostgroup
27
+ @salt_environment ||= @hostgroup.salt_environment
28
+
29
+ if @salt_environment
30
+ @inherited_salt_modules = @salt_environment.salt_modules.where(:id => @hostgroup.inherited_salt_modules)
31
+ @salt_modules = @salt_environment.salt_modules - @inherited_salt_modules
32
+ else
33
+ @inherited_salt_modules = @salt_modules = []
34
+ end
35
+
36
+ @selected = @hostgroup.salt_modules || []
16
37
  end
17
38
  end
18
39
  end
@@ -13,7 +13,8 @@ module ForemanSalt
13
13
  return head(:not_found) unless @hostgroup
14
14
 
15
15
  @salt_modules = @host.salt_modules if @host
16
- @inherited_salt_modules = @hostgroup.salt_modules
16
+ @salt_environment = @host.salt_environment if @host
17
+ @inherited_salt_modules = @hostgroup.all_salt_modules
17
18
  process_hostgroup_without_salt_modules
18
19
  end
19
20
 
@@ -21,8 +22,11 @@ module ForemanSalt
21
22
 
22
23
  def load_vars_for_ajax_with_salt_modules
23
24
  return unless @host
24
- @salt_modules = @host.salt_modules
25
- @inherited_salt_modules = @host.hostgroup.salt_modules if @host.hostgroup
25
+ @obj = @host
26
+ @salt_environment = @host.salt_environment if @host
27
+ @selected = @host.salt_modules
28
+ @salt_modules = @host.salt_environment ? @salt_environment.salt_modules : []
29
+ @inherited_salt_modules = @host.hostgroup.all_salt_modules if @host.hostgroup
26
30
  load_vars_for_ajax_without_salt_modules
27
31
  end
28
32
  end
@@ -8,7 +8,7 @@ module ForemanSalt
8
8
  def node
9
9
  enc = {}
10
10
  env = @minion.salt_environment.blank? ? 'base' : @minion.salt_environment.name
11
- enc['classes'] = @minion.salt_modules.any? ? @minion.salt_modules.map(&:name) : []
11
+ enc['classes'] = @minion.salt_modules_for_enc
12
12
 
13
13
  pillars = @minion.info['parameters']
14
14
  enc['parameters'] = Setting[:salt_namespace_pillars] ? { 'foreman' => pillars } : pillars
@@ -32,12 +32,24 @@ module ForemanSalt
32
32
  redirect_to host_path(@minion)
33
33
  end
34
34
 
35
+ def salt_environment_selected
36
+ if params[:host][:salt_environment_id].present?
37
+ @salt_environment = ::ForemanSalt::SaltEnvironment.find(params[:host][:salt_environment_id])
38
+ load_ajax_vars
39
+ render :partial => 'foreman_salt/salt_modules/host_tab_pane'
40
+ else
41
+ logger.info 'environment_id is required to render states'
42
+ end
43
+ end
44
+
35
45
  def action_permission
36
46
  case params[:action]
37
47
  when 'run'
38
48
  :saltrun
39
49
  when 'node'
40
50
  :view
51
+ when 'salt_environment_selected'
52
+ :edit
41
53
  else
42
54
  super
43
55
  end
@@ -50,5 +62,25 @@ module ForemanSalt
50
62
  def resource_class
51
63
  Host
52
64
  end
65
+
66
+ private
67
+
68
+ def load_ajax_vars
69
+ @minion = Host::Base.authorized(:view_hosts, Host).find_by_id(params[:host_id])
70
+ if @minion
71
+ unless @minion.is_a?(Host::Managed)
72
+ @minion = @host.becomes(Host::Managed)
73
+ @minion.type = 'Host::Managed'
74
+ end
75
+ @minion.attributes = params[:host]
76
+ else
77
+ @minion ||= Host::Managed.new(params[:host])
78
+ end
79
+
80
+ @obj = @minion
81
+ @inherited_salt_modules = @salt_environment.salt_modules.where(:id => @minion.hostgroup ? @minion.hostgroup.all_salt_modules : [])
82
+ @salt_modules = @salt_environment.salt_modules - @inherited_salt_modules
83
+ @selected = @minion.salt_modules || []
84
+ end
53
85
  end
54
86
  end
@@ -1,11 +1,13 @@
1
1
  module ForemanSalt
2
2
  class SaltModulesController < ::ForemanSalt::ApplicationController
3
3
  include Foreman::Controller::AutoCompleteSearch
4
+ include StateImporter
4
5
 
5
6
  before_filter :find_resource, :only => [:edit, :update, :destroy]
7
+ before_filter :find_proxy, :only => :import
6
8
 
7
9
  def index
8
- @salt_modules = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
10
+ @salt_modules = resource_base.search_for(params[:search], :order => params[:order]).includes(:salt_environments).paginate(:page => params[:page])
9
11
  end
10
12
 
11
13
  def new
@@ -23,6 +25,7 @@ module ForemanSalt
23
25
  end
24
26
 
25
27
  def edit
28
+ @salt_environments = @salt_module.salt_environments
26
29
  end
27
30
 
28
31
  def update
@@ -41,5 +44,46 @@ module ForemanSalt
41
44
  process_error
42
45
  end
43
46
  end
47
+
48
+ def action_permission
49
+ case params[:action]
50
+ when 'import'
51
+ :import
52
+ when 'apply_changes'
53
+ :import
54
+ else
55
+ super
56
+ end
57
+ end
58
+
59
+ def import
60
+ result = fetch_states_from_proxy(@proxy)
61
+ @changes = result[:changes]
62
+ @deletes = result[:deletes]
63
+
64
+ if @changes.empty?
65
+ notice _('No changes found')
66
+ redirect_to salt_modules_path
67
+ end
68
+ end
69
+
70
+ def apply_changes
71
+ if params[:changed].blank?
72
+ notice _('No changes found')
73
+ redirect_to salt_modules_path
74
+ else
75
+ params[:changed].each do |environment, states|
76
+ next unless states[:add] || states[:remove]
77
+ environment = SaltEnvironment.find_or_create_by_name(environment)
78
+
79
+ add_to_environment(JSON.load(states[:add]), environment) if states[:add]
80
+ remove_from_environment(JSON.load(states[:remove]), environment) if states[:remove]
81
+ end
82
+
83
+ clean_orphans
84
+ notice _('Successfully imported')
85
+ redirect_to salt_modules_path
86
+ end
87
+ end
44
88
  end
45
89
  end
@@ -0,0 +1,72 @@
1
+ module ForemanSalt
2
+ module StateImporter
3
+ extend ActiveSupport::Concern
4
+
5
+ private
6
+
7
+ def find_proxy
8
+ @proxy = SmartProxy.find(params[:proxy] || params[:smart_proxy_id])
9
+ return :not_found unless @proxy
10
+ end
11
+
12
+ def fetch_states_from_proxy(proxy, environments = nil)
13
+ result = { :changes => {},
14
+ :deletes => [] }
15
+
16
+ new = ProxyAPI::Salt.new(:url => proxy.url).states_list
17
+ old = SaltModule.to_hash
18
+
19
+ environments ||= new.keys + old.keys
20
+
21
+ environments.each do |environment|
22
+ old_states = old[environment] || []
23
+ new_states = new[environment] || []
24
+
25
+ if old_states.any?
26
+ removed = old_states - new_states
27
+ added = new_states - old_states
28
+ else
29
+ added = new_states
30
+ removed = []
31
+ end
32
+
33
+ if added.any? || removed.any?
34
+ result[:changes][environment] = {}
35
+
36
+ unless removed.blank?
37
+ result[:changes][environment][:remove] = removed
38
+ result[:deletes] << environment if removed.count == old[environment].count && added.blank?
39
+ end
40
+
41
+ result[:changes][environment][:add] = added unless added.blank?
42
+ end
43
+ end
44
+
45
+ result
46
+ end
47
+
48
+ def add_to_environment(states, environment)
49
+ states.each do |state_name|
50
+ state = SaltModule.find_or_create_by_name(state_name)
51
+ state.salt_environments << SaltEnvironment.find(environment)
52
+ end
53
+ end
54
+
55
+ def remove_from_environment(states, environment)
56
+ states.each do |state_name|
57
+ state = SaltModule.find(state_name)
58
+ state.salt_environments.delete(environment) if state
59
+ end
60
+ end
61
+
62
+ def clean_orphans
63
+ SaltModule.all.each do |state|
64
+ state.destroy if state.salt_environments.empty?
65
+ end
66
+
67
+ SaltEnvironment.all.each do |environment|
68
+ environment.destroy if environment.salt_modules.empty?
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module ForemanSalt
2
+ module SaltModulesHelper
3
+ def import_from_proxies
4
+ links = SmartProxy.with_features('Salt').map do |proxy|
5
+ display_link_if_authorized(_('Import from %s') % proxy.name, hash_for_import_salt_modules_path.merge(:proxy => proxy), :class => 'btn btn-default')
6
+ end.flatten
7
+
8
+ select_action_button(_('Import'), {}, links)
9
+ end
10
+
11
+ def colorize(state)
12
+ # Make the state easier to read
13
+ combo = %w(2E9DB9 4D1D59 2C777E 1C4758 591D4B)
14
+ state.split('.').each_with_index.map do |section, index|
15
+ "<span style='color: ##{combo[index % 5]}; font-weight: bold;'>#{section}</span>"
16
+ end.join('.').html_safe
17
+ end
18
+ end
19
+ end
@@ -25,6 +25,24 @@ module ::ProxyAPI
25
25
  raise ProxyException.new(url, e, N_('Unable to delete Salt autosign for %s'), name)
26
26
  end
27
27
 
28
+ def environments_list
29
+ parse(get('environments'))
30
+ rescue => e
31
+ raise ProxyException.new(url, e, N_('Unable to fetch Salt environments list'))
32
+ end
33
+
34
+ def states_list
35
+ states = {}
36
+
37
+ environments_list.each do |environment|
38
+ states[environment] = parse(get("environments/#{environment}"))
39
+ end
40
+
41
+ states
42
+ rescue => e
43
+ raise ProxyException.new(url, e, N_('Unable to fetch Salt states list'))
44
+ end
45
+
28
46
  def key_list
29
47
  parse(get('key'))
30
48
  rescue => e
@@ -4,12 +4,20 @@ module ForemanSalt
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- has_and_belongs_to_many :salt_modules, :class_name => 'ForemanSalt::SaltModule', :join_table => 'hosts_salt_modules', :foreign_key => 'host_id'
7
+ has_many :salt_modules, :through => :host_salt_modules, :class_name => '::ForemanSalt::SaltModule'
8
+ has_many :host_salt_modules, :foreign_key => :host_id, :class_name => '::ForemanSalt::HostSaltModule'
9
+
8
10
  belongs_to :salt_proxy, :class_name => 'SmartProxy'
9
11
  belongs_to :salt_environment, :class_name => 'ForemanSalt::SaltEnvironment'
12
+
10
13
  alias_method_chain :params, :salt_proxy
11
14
  alias_method_chain :set_hostgroup_defaults, :salt_proxy
12
15
  alias_method_chain :smart_proxy_ids, :salt_proxy
16
+
17
+ scoped_search :in => :salt_modules, :on => :name, :complete_value => true, :rename => :salt_state
18
+ scoped_search :in => :salt_environment, :on => :name, :complete_value => true, :rename => :salt_environment
19
+
20
+ validate :salt_modules_in_host_environment
13
21
  end
14
22
 
15
23
  def handle_salt
@@ -23,14 +31,11 @@ module ForemanSalt
23
31
  params
24
32
  end
25
33
 
26
- def salt_modules
27
- return super unless hostgroup
28
- [super + hostgroup.salt_modules].flatten
29
- end
34
+ def salt_modules_for_enc
35
+ return [] unless self.salt_environment
30
36
 
31
- def salt_module_ids
32
- return super unless hostgroup
33
- [super + hostgroup.salt_module_ids].flatten
37
+ hostgroup_modules = self.hostgroup ? self.hostgroup.all_salt_modules : []
38
+ self.salt_environment.salt_modules.where(:id => self.salt_modules + hostgroup_modules).pluck(:name)
34
39
  end
35
40
 
36
41
  def salt_master
@@ -62,6 +67,16 @@ module ForemanSalt
62
67
  end
63
68
  ids
64
69
  end
70
+
71
+ def salt_modules_in_host_environment
72
+ return unless self.salt_modules.any?
73
+
74
+ if self.salt_environment
75
+ errors.add(:base, _('Salt states must be in the environment of the host')) unless (self.salt_modules - self.salt_environment.salt_modules).empty?
76
+ else
77
+ errors.add(:base, _('Host must have an environment in order to set salt states'))
78
+ end
79
+ end
65
80
  end
66
81
  end
67
82
  end
@@ -4,19 +4,22 @@ module ForemanSalt
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- has_and_belongs_to_many :salt_modules, :class_name => 'ForemanSalt::SaltModule'
7
+ has_many :salt_modules, :through => :hostgroup_salt_modules, :class_name => '::ForemanSalt::SaltModule'
8
+ has_many :hostgroup_salt_modules, :class_name => '::ForemanSalt::HostgroupSaltModule'
9
+
8
10
  belongs_to :salt_proxy, :class_name => 'SmartProxy'
9
11
  belongs_to :salt_environment, :class_name => 'ForemanSalt::SaltEnvironment'
10
- end
11
12
 
12
- def salt_modules
13
- return super unless ancestry.present?
14
- ([super] + [inherited_salt_modules]).flatten.uniq.compact
13
+ scoped_search :in => :salt_modules, :on => :name, :complete_value => true, :rename => :salt_state
14
+ scoped_search :in => :salt_environment, :on => :name, :complete_value => true, :rename => :salt_environment
15
15
  end
16
16
 
17
- def salt_module_ids
18
- return super unless ancestry.present?
19
- ([super] + [inherited_salt_module_ids]).flatten.uniq.compact
17
+ def all_salt_modules
18
+ if ancestry.present?
19
+ (self.salt_modules + self.inherited_salt_modules).uniq
20
+ else
21
+ self.salt_modules
22
+ end
20
23
  end
21
24
 
22
25
  def inherited_salt_modules
@@ -25,7 +28,7 @@ module ForemanSalt
25
28
 
26
29
  def inherited_salt_module_ids
27
30
  if ancestry.present?
28
- self.class.sort_by_ancestry(ancestors.reject { |ancestor| ancestor.salt_module_ids.empty? }).last.try(:salt_modules)
31
+ self.class.sort_by_ancestry(ancestors.reject { |ancestor| ancestor.salt_module_ids.empty? }).map(&:salt_module_ids).inject(&:+).uniq
29
32
  else
30
33
  []
31
34
  end
@@ -0,0 +1,6 @@
1
+ module ForemanSalt
2
+ class HostSaltModule < ActiveRecord::Base
3
+ belongs_to :host, :class_name => "Host::Managed", :foreign_key => :host_id
4
+ belongs_to :salt_module
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module ForemanSalt
2
+ class HostgroupSaltModule < ActiveRecord::Base
3
+ belongs_to :hostgroup
4
+ belongs_to :salt_module
5
+ end
6
+ end
@@ -5,19 +5,26 @@ module ForemanSalt
5
5
  extend FriendlyId
6
6
  friendly_id :name
7
7
 
8
- before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups)
9
-
10
8
  has_many :hosts, :class_name => '::Host::Managed'
11
9
  has_many :hostgroups, :class_name => '::Hostgroup'
12
10
 
13
- validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A[\w\d\.]+\z/, :message => N_('is alphanumeric and cannot contain spaces') }
11
+ has_many :salt_modules, :through => :salt_module_environments, :before_remove => :remove_from_hosts
12
+ has_many :salt_module_environments
14
13
 
15
- default_scope lambda {
16
- order('salt_environments.name')
17
- }
14
+ validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A[\w\d\.]+\z/, :message => N_('is alphanumeric and cannot contain spaces') }
18
15
 
19
16
  scoped_search :on => :name, :complete_value => true
20
17
  scoped_search :in => :hostgroups, :on => :name, :complete_value => true, :rename => :hostgroup
21
18
  scoped_search :in => :hosts, :on => :name, :complete_value => true, :rename => :host
19
+
20
+ def self.humanize_class_name(_name = nil)
21
+ _('Salt environment')
22
+ end
23
+
24
+ private
25
+
26
+ def remove_from_hosts(state)
27
+ HostSaltModule.joins(:host).where(:hosts => { :salt_environment_id => id }, :salt_module_id => state).destroy
28
+ end
22
29
  end
23
30
  end
@@ -5,20 +5,42 @@ module ForemanSalt
5
5
  extend FriendlyId
6
6
  friendly_id :name
7
7
 
8
- before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups)
9
- has_and_belongs_to_many :hosts, :class_name => '::Host::Managed', :join_table => 'hosts_salt_modules',
10
- :association_foreign_key => 'host_id'
8
+ # before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups)
11
9
 
12
- has_and_belongs_to_many :hostgroups, :class_name => '::Hostgroup', :join_table => 'hostgroups_salt_modules'
10
+ has_many :hosts, :through => :host_salt_modules, :class_name => '::Host::Managed'
11
+ has_many :host_salt_modules, :foreign_key => :salt_module_id
13
12
 
14
- validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A(?:[\w\d]+\.{0,1})+[^\.]\z/, :message => N_('must be alphanumeric, can contain dots and must not contain spaces') }
13
+ has_many :hostgroups, :through => :hostgroup_salt_modules
14
+ has_many :hostgroup_salt_modules, :foreign_key => :salt_module_id
15
+
16
+ has_many :salt_environments, :through => :salt_module_environments
17
+ has_many :salt_module_environments
18
+
19
+ validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A(?:[\w\d\-]+\.{0,1})+[^\.]\z/, :message => N_('must be alphanumeric, can contain periods, dashes, underscores and must not contain spaces') }
15
20
 
16
21
  default_scope lambda {
17
22
  order('salt_modules.name')
18
23
  }
19
24
 
25
+ scope :in_environment, ->(environment) { joins(:salt_environments).where('salt_module_environments.salt_environment_id' => environment) }
26
+
20
27
  scoped_search :on => :name, :complete_value => true
28
+ scoped_search :in => :salt_environments, :on => :name, :complete_value => true, :rename => :environment
21
29
  scoped_search :in => :hostgroups, :on => :name, :complete_value => true, :rename => :hostgroup
22
30
  scoped_search :in => :hosts, :on => :name, :complete_value => true, :rename => :host
31
+
32
+ def self.to_hash
33
+ states = {}
34
+
35
+ SaltEnvironment.all.each do |environment|
36
+ states[environment.name] = environment.salt_modules.map(&:name)
37
+ end
38
+
39
+ states
40
+ end
41
+
42
+ def self.humanize_class_name(_name = nil)
43
+ _('Salt state')
44
+ end
23
45
  end
24
46
  end
@@ -0,0 +1,14 @@
1
+ module ForemanSalt
2
+ class SaltModuleEnvironment < ActiveRecord::Base
3
+ belongs_to :salt_environment
4
+ belongs_to :salt_module
5
+
6
+ before_destroy :remove_from_hosts
7
+
8
+ private
9
+
10
+ def remove_from_hosts
11
+ HostSaltModule.joins(:host).where(:hosts => { :salt_environment_id => salt_environment_id }, :salt_module_id => salt_module_id).destroy
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ selector_text = "<%= select_f f, :salt_environment_id, ForemanSalt::SaltEnvironment.all, :id, :name,
2
+ { :include_blank => blank_or_inherit_f(f, :salt_environment) },
3
+ { :label => _('Salt Environment'), :onchange => 'update_salt_states(this)', :'data-url' => salt_environment_selected_minions_path,
4
+ :'data-host-id' => (@host || @hostgroup).id, :help_inline => :indicator} %>"
5
+
6
+ Deface::Override.new(:virtual_path => 'hosts/_form',
7
+ :name => 'add_salt_environment_to_host',
8
+ :insert_bottom => 'div#primary',
9
+ :text => selector_text)