foreman_salt 2.0.2 → 2.1.0

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