foreman_salt 0.0.2

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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +29 -0
  4. data/Rakefile +40 -0
  5. data/app/controllers/foreman_salt/concerns/hostgroups_controller_extensions.rb +19 -0
  6. data/app/controllers/foreman_salt/concerns/hosts_controller_extensions.rb +69 -0
  7. data/app/controllers/foreman_salt/concerns/smart_proxy_auth_extensions.rb +24 -0
  8. data/app/controllers/foreman_salt/concerns/unattended_controller_extensions.rb +18 -0
  9. data/app/controllers/foreman_salt/salt_autosign_controller.rb +43 -0
  10. data/app/controllers/foreman_salt/salt_keys_controller.rb +59 -0
  11. data/app/controllers/foreman_salt/salt_modules_controller.rb +45 -0
  12. data/app/helpers/concerns/foreman_salt/hosts_helper_extensions.rb +28 -0
  13. data/app/helpers/concerns/foreman_salt/smart_proxies_helper_extensions.rb +22 -0
  14. data/app/helpers/foreman_salt/salt_keys_helper.rb +9 -0
  15. data/app/lib/proxy_api/salt.rb +60 -0
  16. data/app/models/concerns/foreman_salt/host_managed_extensions.rb +64 -0
  17. data/app/models/concerns/foreman_salt/hostgroup_extensions.rb +49 -0
  18. data/app/models/concerns/foreman_salt/orchestration/salt.rb +72 -0
  19. data/app/models/foreman_salt/fact_name.rb +4 -0
  20. data/app/models/foreman_salt/salt_module.rb +22 -0
  21. data/app/overrides/foreman/salt_modules/_host_tab.html.erb +2 -0
  22. data/app/overrides/foreman/salt_modules/_host_tab_pane.html.erb +22 -0
  23. data/app/overrides/salt_modules_selector.rb +19 -0
  24. data/app/overrides/salt_proxy_selector.rb +13 -0
  25. data/app/services/foreman_salt/fact_importer.rb +108 -0
  26. data/app/services/foreman_salt/smart_proxies/salt_keys.rb +68 -0
  27. data/app/views/foreman_salt/salt_autosign/_form.html.erb +8 -0
  28. data/app/views/foreman_salt/salt_autosign/index.html.erb +21 -0
  29. data/app/views/foreman_salt/salt_autosign/new.html.erb +3 -0
  30. data/app/views/foreman_salt/salt_keys/index.erb +34 -0
  31. data/app/views/foreman_salt/salt_modules/_form.html.erb +15 -0
  32. data/app/views/foreman_salt/salt_modules/edit.html.erb +4 -0
  33. data/app/views/foreman_salt/salt_modules/index.html.erb +23 -0
  34. data/app/views/foreman_salt/salt_modules/new.html.erb +4 -0
  35. data/config/routes.rb +32 -0
  36. data/db/migrate/20140813081913_add_salt_proxy_to_host_and_host_group.rb +12 -0
  37. data/db/migrate/20140817210214_create_salt_modules.rb +20 -0
  38. data/db/migrate/20140829210214_add_salt_modules_to_hostgroups.rb +12 -0
  39. data/db/seeds.d/75-salt-seeds.rb +31 -0
  40. data/lib/foreman_salt/engine.rb +90 -0
  41. data/lib/foreman_salt/version.rb +3 -0
  42. data/lib/foreman_salt.rb +4 -0
  43. data/lib/tasks/foreman_salt_tasks.rake +31 -0
  44. data/test/factories/foreman_salt_factories.rb +32 -0
  45. data/test/functional/hosts_controller_test.rb +17 -0
  46. data/test/integration/salt_autosign_test.rb +29 -0
  47. data/test/integration/salt_keys_test.rb +45 -0
  48. data/test/integration/salt_module_test.rb +27 -0
  49. data/test/test_plugin_helper.rb +14 -0
  50. data/test/unit/grains_centos.json +108 -0
  51. data/test/unit/grains_importer_test.rb +38 -0
  52. data/test/unit/host_extensions_test.rb +32 -0
  53. data/test/unit/hostgroup_extensions_test.rb +40 -0
  54. data/test/unit/salt_keys_test.rb +46 -0
  55. metadata +122 -0
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'ForemanSalt'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,19 @@
1
+ module ForemanSalt
2
+ module Concerns
3
+ module HostgroupsControllerExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :load_vars_for_ajax, :salt_modules
8
+ end
9
+
10
+ private
11
+
12
+ def load_vars_for_ajax_with_salt_modules
13
+ load_vars_for_ajax_without_salt_modules
14
+ @salt_modules = @hostgroup.salt_modules
15
+ @inherited_salt_modules = @hostgroup.inherited_salt_modules
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,69 @@
1
+ module ForemanSalt
2
+ module Concerns
3
+ module HostsControllerExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method :find_by_name_salt, :find_by_name
8
+ before_filter :find_by_name_salt, :only => [:saltrun]
9
+ alias_method_chain :action_permission, :salt_run
10
+ alias_method_chain :load_vars_for_ajax, :salt_modules
11
+ alias_method_chain :process_hostgroup, :salt_modules
12
+ end
13
+
14
+ def saltrun
15
+ if @host.saltrun!
16
+ notice _("Successfully executed, check log files for more details")
17
+ else
18
+ error @host.errors[:base].to_sentence
19
+ end
20
+ redirect_to host_path(@host)
21
+ end
22
+
23
+ def salt_external_node
24
+ begin
25
+ @host = resource_base.find_by_name(params[:name])
26
+ enc = {}
27
+ enc["classes"] = @host.salt_modules.any? ? @host.salt_modules.map(&:name) : []
28
+ enc["parameters"] = @host.info["parameters"]
29
+ respond_to do |format|
30
+ format.html { render :text => "<pre>#{ERB::Util.html_escape(enc.to_yaml)}</pre>" }
31
+ format.yml { render :text => enc.to_yaml }
32
+ end
33
+ rescue
34
+ logger.warn "Failed to generate external nodes for #{@host} with #{$!}"
35
+ render :text => _('Unable to generate output, Check log files\n'), :status => 412 and return
36
+ end
37
+ end
38
+
39
+ def process_hostgroup_with_salt_modules
40
+ @hostgroup = Hostgroup.find(params[:host][:hostgroup_id]) if params[:host][:hostgroup_id].to_i > 0
41
+ return head(:not_found) unless @hostgroup
42
+
43
+ @salt_modules = @host.salt_modules if @host
44
+ @inherited_salt_modules = @hostgroup.salt_modules
45
+ process_hostgroup_without_salt_modules
46
+ end
47
+
48
+ private
49
+
50
+ def action_permission_with_salt_run
51
+ case params[:action]
52
+ when 'saltrun'
53
+ :saltrun
54
+ when 'salt_external_node'
55
+ :view
56
+ else
57
+ action_permission_without_salt_run
58
+ end
59
+ end
60
+
61
+ def load_vars_for_ajax_with_salt_modules
62
+ return unless @host
63
+ @salt_modules = @host.salt_modules
64
+ @inherited_salt_modules = @host.hostgroup.salt_modules if @host.hostgroup
65
+ load_vars_for_ajax_without_salt_modules
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,24 @@
1
+ module ForemanSalt
2
+ module Concerns
3
+ module SmartProxyAuthExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ alias_method_chain :require_puppetmaster_or_login, :salt
8
+ case self.controller_path
9
+ when 'hosts'
10
+ add_puppetmaster_filters [::HostsController::PUPPETMASTER_ACTIONS, :salt_external_node].flatten
11
+ end
12
+ end
13
+
14
+ def require_puppetmaster_or_login_with_salt
15
+ if auth_smart_proxy(::SmartProxy.with_features("Salt"), ::Setting[:require_ssl_puppetmasters])
16
+ set_admin_user
17
+ return true
18
+ else
19
+ require_puppetmaster_or_login_without_salt
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module ForemanSalt
2
+ module Concerns
3
+ module UnattendedControllerExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_filter :handle_salt, :only => [:provision]
8
+ end
9
+
10
+ private
11
+
12
+ def handle_salt
13
+ return true if @spoof
14
+ render(:text => _("Failed to set autosign for host. Terminating the build!"), :status => 500) unless @host.respond_to?(:handle_salt) && @host.handle_salt
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,43 @@
1
+ module ForemanSalt
2
+ class SaltAutosignController < ::ApplicationController
3
+
4
+ def index
5
+ setup
6
+ autosign = @api.autosign_list
7
+ @autosign = autosign.paginate :page => params[:page], :per_page => Setting::General.entries_per_page
8
+ end
9
+
10
+ def new
11
+ setup
12
+ end
13
+
14
+ def create
15
+ setup
16
+
17
+ if @api.autosign_create(params[:id])
18
+ process_success({:success_redirect => hash_for_smart_proxy_salt_autosign_index_path, :success_msg => _("Autosign created for #{params[:id]}"),
19
+ :object_name => params[:id]})
20
+ else
21
+ process_error({:redirect => hash_for_smart_proxy_salt_autosign_index_path})
22
+ end
23
+ end
24
+
25
+ def destroy
26
+ setup
27
+
28
+ if @api.autosign_remove(params[:id])
29
+ process_success({:success_redirect => hash_for_smart_proxy_salt_autosign_index_path, :success_msg => _("Autosign deleted for #{params[:id]}"),
30
+ :object_name => params[:id]})
31
+ else
32
+ process_error({:redirect => hash_for_smart_proxy_salt_autosign_index_path})
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def setup
39
+ @proxy = SmartProxy.authorized(:view_smart_proxies_salt_autosign).find(params[:smart_proxy_id])
40
+ @api = ProxyAPI::Salt.new({:url => @proxy.url})
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ module ForemanSalt
2
+ class SaltKeysController < ::ApplicationController
3
+
4
+ def index
5
+ @proxy = find_proxy
6
+
7
+ Rails.cache.delete("saltkeys_#{@proxy.id}") if params[:expire_cache] == "true"
8
+ keys = if params[:state].blank?
9
+ SmartProxies::SaltKeys.all @proxy
10
+ else
11
+ SmartProxies::SaltKeys.find_by_state @proxy, params[:state].downcase
12
+ end
13
+ @keys = keys.sort.paginate :page => params[:page], :per_page => Setting::General.entries_per_page
14
+ end
15
+
16
+ def accept
17
+ @proxy = find_proxy(permission = :edit_smart_proxies_salt_keys)
18
+ key = SmartProxies::SaltKeys.find(@proxy, params[:salt_key_id])
19
+ if key.accept
20
+ process_success({:success_redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true),
21
+ :success_msg => _("Key accepted for #{key}"), :object_name => key.to_s})
22
+ else
23
+ process_error({:redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true)})
24
+ end
25
+ end
26
+
27
+ def reject
28
+ @proxy = find_proxy(permission = :edit_smart_proxies_salt_keys)
29
+ key = SmartProxies::SaltKeys.find(@proxy, params[:salt_key_id])
30
+ if key.reject
31
+ process_success({:success_redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true),
32
+ :success_msg => _("Key rejected for #{key}"), :object_name => key.to_s})
33
+ else
34
+ process_error({:redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true)})
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ @proxy = find_proxy(permission = :destroy_smart_proxies_salt_keys)
40
+ key = SmartProxies::SaltKeys.find(@proxy, params[:id])
41
+ if key.delete
42
+ process_success({:success_redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true),
43
+ :success_msg => _("Key deleted for #{key}"), :object_name => key.to_s})
44
+ else
45
+ process_error({:redirect => hash_for_smart_proxy_salt_keys_path(:state => params[:state], :expire_cache => true)})
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def controller_permission
52
+ 'smart_proxies_salt_keys'
53
+ end
54
+
55
+ def find_proxy(permission = :view_smart_proxies_salt_keys)
56
+ SmartProxy.authorized(permission).find(params[:smart_proxy_id])
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,45 @@
1
+ module ForemanSalt
2
+ class SaltModulesController < ::ApplicationController
3
+ include Foreman::Controller::AutoCompleteSearch
4
+
5
+ before_filter :find_by_name, :only => [:edit, :update, :destroy]
6
+
7
+ def index
8
+ @salt_modules = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
9
+ end
10
+
11
+ def new
12
+ @salt_module = SaltModule.new
13
+ end
14
+
15
+ def create
16
+ logger.info("Params: #{params.inspect}")
17
+ @salt_module = SaltModule.new(params[:foreman_salt_salt_module])
18
+ if @salt_module.save
19
+ process_success
20
+ else
21
+ process_error
22
+ end
23
+ end
24
+
25
+ def edit
26
+ end
27
+
28
+ def update
29
+ if @salt_module.update_attributes(params[:foreman_salt_salt_module])
30
+ notice _("Successfully updated %s." % @salt_module.to_s)
31
+ redirect_to salt_modules_path
32
+ else
33
+ process_error
34
+ end
35
+ end
36
+
37
+ def destroy
38
+ if @salt_module.destroy
39
+ process_success
40
+ else
41
+ process_error
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ module ForemanSalt
2
+ module HostsHelperExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method_chain :host_title_actions, :salt_run
7
+ alias_method_chain :show_appropriate_host_buttons, :salt
8
+ end
9
+
10
+ def show_appropriate_host_buttons_with_salt(host)
11
+ (show_appropriate_host_buttons_without_salt(host) +
12
+ [(link_to_if_authorized(_("Salt ENC"), {:controller => :hosts, :action => :salt_external_node, :name => host},
13
+ :title => _("Salt external nodes YAML dump"), :class => 'btn btn-default') unless host.salt_master.blank?)]).flatten.compact
14
+ end
15
+
16
+ def host_title_actions_with_salt_run(host)
17
+ title_actions(
18
+ button_group(
19
+ if host.try(:salt_proxy)
20
+ link_to_if_authorized(_("Run Salt"), {:controller => :hosts, :action => :saltrun, :id => @host},
21
+ :title => _("Trigger a state.highstate run on a node"))
22
+ end
23
+ )
24
+ )
25
+ host_title_actions_without_salt_run(host)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ module ForemanSalt
2
+ module SmartProxiesHelperExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method_chain :proxy_actions, :salt_proxy
7
+ end
8
+
9
+ def proxy_actions_with_salt_proxy(proxy, authorizer)
10
+ salt = proxy.features.detect { |feature| feature.name == 'Salt' }
11
+ [
12
+ if salt
13
+ display_link_if_authorized(_("Salt Keys"), {:controller => 'foreman_salt/salt_keys', :action => 'index', :smart_proxy_id => proxy})
14
+ end,
15
+
16
+ if salt
17
+ display_link_if_authorized(_("Salt Autosign"), {:controller => 'foreman_salt/salt_autosign', :action => 'index', :smart_proxy_id => proxy})
18
+ end
19
+ ] + proxy_actions_without_salt_proxy(proxy, authorizer)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module ForemanSalt
2
+ module SaltKeysHelper
3
+ def salt_keys_state_filter
4
+ select_tag "Filter", options_for_select(["", _("Accepted"),_("Rejected"), _("Unaccepted")], params[:state]),
5
+ :onchange => "window.location.href = location.protocol + '//' + location.host + location.pathname + (this.value == '' ? '' : ('?state=' + this.value))"
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,60 @@
1
+ module ::ProxyAPI
2
+ class Salt < ::ProxyAPI::Resource
3
+ def initialize args
4
+ @url = args[:url] + "/salt/"
5
+ super args
6
+ end
7
+
8
+ def autosign_list
9
+ parse(get("autosign"))
10
+ rescue => e
11
+ raise ProxyException.new(url, e, N_("Unable to fetch autosign list"))
12
+ end
13
+
14
+ def autosign_create name
15
+ parse(post("", "autosign/#{URI.escape(name)}"))
16
+ rescue => e
17
+ raise ProxyException.new(url, e, N_("Unable to set Salt autosign for %s"), name)
18
+ end
19
+
20
+ def autosign_remove name
21
+ parse(delete("autosign/#{URI.escape(name)}"))
22
+ rescue RestClient::ResourceNotFound
23
+ true # entry doesn't exists anyway
24
+ rescue => e
25
+ raise ProxyException.new(url, e, N_("Unable to delete Salt autosign for %s"), name)
26
+ end
27
+
28
+ def key_list
29
+ parse(get("key"))
30
+ rescue => e
31
+ raise ProxyException.new(url, e, N_("Unable to fetch Salt key list"))
32
+ end
33
+
34
+ def key_accept name
35
+ parse(post("","key/#{name}"))
36
+ rescue => e
37
+ raise ProxyException.new(url, e, N_("Unable to accept Salt key for %s"), name)
38
+ end
39
+
40
+ def key_reject name
41
+ parse(delete("key/reject/#{name}"))
42
+ rescue => e
43
+ raise ProxyException.new(url, e, N_("Unable to reject Salt key for %s"), name)
44
+ end
45
+
46
+ def key_delete name
47
+ parse(delete("key/#{name}"))
48
+ rescue RestClient::ResourceNotFound
49
+ true
50
+ rescue => e
51
+ raise ProxyException.new(url, e, N_("Unable to delete Salt key for %s"), name)
52
+ end
53
+
54
+ def highstate name
55
+ parse(post("", "highstate/#{name}"))
56
+ rescue => e
57
+ raise ProxyException.new(url, e, N_("Unable to run Salt state.highstate for %s"), name)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,64 @@
1
+ module ForemanSalt
2
+ module HostManagedExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_and_belongs_to_many :salt_modules, :class_name => "ForemanSalt::SaltModule", :join_table => "hosts_salt_modules", :foreign_key => "host_id"
7
+ belongs_to :salt_proxy, :class_name => "SmartProxy"
8
+ alias_method_chain :params, :salt_proxy
9
+ alias_method_chain :set_hostgroup_defaults, :salt_proxy
10
+ alias_method_chain :smart_proxy_ids, :salt_proxy
11
+ end
12
+
13
+ def handle_salt
14
+ return true unless salt?
15
+ salt_autosign_create
16
+ end
17
+
18
+ def params_with_salt_proxy
19
+ params = params_without_salt_proxy
20
+ params["salt_master"] = salt_master unless salt_master.blank?
21
+ params
22
+ end
23
+
24
+ def salt_modules
25
+ return super unless hostgroup
26
+ [super + hostgroup.salt_modules].flatten
27
+ end
28
+
29
+ def salt_module_ids
30
+ return super unless hostgroup
31
+ [super + hostgroup.salt_module_ids].flatten
32
+ end
33
+
34
+ def salt_master
35
+ salt_proxy.to_s
36
+ end
37
+
38
+ def saltrun!
39
+ unless salt_proxy.present?
40
+ errors.add(:base, _("No Salt master defined - can't continue"))
41
+ logger.warn "Unable to execute salt run, no salt proxies defined"
42
+ return false
43
+ end
44
+ ProxyAPI::Salt.new({:url => salt_proxy.url}).highstate name
45
+ rescue => e
46
+ errors.add(:base, _("Failed to execute state.highstate: %s") % e)
47
+ false
48
+ end
49
+
50
+ def set_hostgroup_defaults_with_salt_proxy
51
+ return unless hostgroup
52
+ assign_hostgroup_attributes(%w{salt_proxy_id})
53
+ set_hostgroup_defaults_without_salt_proxy
54
+ end
55
+
56
+ def smart_proxy_ids_with_salt_proxy
57
+ ids = smart_proxy_ids_without_salt_proxy
58
+ [salt_proxy, hostgroup.try(:salt_proxy)].compact.each do |proxy|
59
+ ids << proxy.id
60
+ end
61
+ ids
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,49 @@
1
+ module ForemanSalt
2
+ module HostgroupExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_and_belongs_to_many :salt_modules, :class_name => "ForemanSalt::SaltModule"
7
+ belongs_to :salt_proxy, :class_name => "SmartProxy"
8
+ end
9
+
10
+ def salt_modules
11
+ return super unless ancestry.present?
12
+ ([super] + [inherited_salt_modules]).flatten.uniq.compact
13
+ end
14
+
15
+ def salt_module_ids
16
+ return super unless ancestry.present?
17
+ ([super] + [inherited_salt_module_ids]).flatten.uniq.compact
18
+ end
19
+
20
+ def inherited_salt_modules
21
+ ForemanSalt::SaltModule.where(:id => inherited_salt_module_ids)
22
+ end
23
+
24
+ def inherited_salt_module_ids
25
+ if ancestry.present?
26
+ self.class.sort_by_ancestry(ancestors.reject { |ancestor| ancestor.salt_module_ids.empty? }).last.try(:salt_modules)
27
+ else
28
+ []
29
+ end
30
+ end
31
+
32
+ def salt_proxy
33
+ return super unless ancestry.present?
34
+ SmartProxy.find_by_id(inherited_salt_proxy_id)
35
+ end
36
+
37
+ def inherited_salt_proxy_id
38
+ if ancestry.present?
39
+ read_attribute(:salt_proxy_id) || self.class.sort_by_ancestry(ancestors.where("salt_proxy_id is not NULL")).last.try(:salt_proxy_id)
40
+ else
41
+ self.salt_proxy_id
42
+ end
43
+ end
44
+
45
+ def salt_master
46
+ salt_proxy.to_s
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,72 @@
1
+ module ForemanSalt
2
+ module Orchestration
3
+ module Salt
4
+ extend ActiveSupport::Concern
5
+ include ::Orchestration
6
+
7
+ included do
8
+ after_validation :queue_salt_autosign
9
+ before_destroy :queue_salt_destroy
10
+ end
11
+
12
+ def salt?
13
+ name.present? && salt_proxy.present?
14
+ end
15
+
16
+ def initialize_salt
17
+ @salt_api ||= ProxyAPI::Salt.new :url => salt_proxy.url
18
+ end
19
+
20
+ def queue_salt_autosign
21
+ return unless salt? && errors.empty?
22
+ new_record? ? queue_salt_autosign_create : queue_salt_autosign_update
23
+ end
24
+
25
+ def queue_salt_autosign_create
26
+ # do nothing - we'll set autosign at the last second: when a host requests a provision URL
27
+ end
28
+
29
+ def queue_salt_autosign_update
30
+ # Host has been built --> remove auto sign
31
+ if old.build? and !build?
32
+ queue.create(:name => _("Remove autosign entry for %s") % self, :priority => 50, :action => [self, :salt_autosign_remove])
33
+ end
34
+ end
35
+
36
+ def queue_salt_destroy
37
+ queue.create(:name => _("Remove autosign entry for %s") % self, :priority => 50, :action => [self, :salt_autosign_remove])
38
+ queue.create(:name => _("Delete existing salt key for %s") % self, :priority => 50, :action => [self, :salt_key_delete])
39
+ end
40
+
41
+ def queue_salt_autosign_remove
42
+ return unless salt? && errors.empty?
43
+ queue.create(:name => _("Remove autosign entry for %s") % self, :priority => 50, :action => [self, :salt_autosign_remove])
44
+ end
45
+
46
+ def salt_autosign_create
47
+ logger.info "Create autosign entry for #{name}"
48
+ initialize_salt
49
+ salt_key_delete # if there's already an existing key
50
+ @salt_api.autosign_create name
51
+ rescue => e
52
+ failure _("Failed to create %{name}'s Salt autosign entry: %{e}") % { :name => name, :e => proxy_error(e) }
53
+ end
54
+
55
+ def salt_autosign_remove
56
+ logger.info "Remove autosign entry for #{name}"
57
+ initialize_salt
58
+ @salt_api.autosign_remove name
59
+ rescue => e
60
+ failure _("Failed to remove %{name}'s Salt autosign entry: %{e}") % { :name => name, :e => proxy_error(e) }
61
+ end
62
+
63
+ def salt_key_delete
64
+ logger.info "Delete salt key for #{name}"
65
+ initialize_salt
66
+ @salt_api.key_delete name
67
+ rescue => e
68
+ failure _("Failed to delete %{name}'s Salt key: %{e}") % { :name => name, :e => proxy_error(e) }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,4 @@
1
+ module ForemanSalt
2
+ class FactName < ::FactName; end
3
+ end
4
+
@@ -0,0 +1,22 @@
1
+ module ForemanSalt
2
+ class SaltModule < ActiveRecord::Base
3
+ include Taxonomix
4
+ include Authorizable
5
+
6
+ before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups)
7
+ has_and_belongs_to_many :hosts, :class_name => "::Host::Managed", :join_table => "hosts_salt_modules",
8
+ :association_foreign_key => 'host_id'
9
+
10
+ has_and_belongs_to_many :hostgroups, :class_name => "::Hostgroup", :join_table => "hostgroups_salt_modules"
11
+
12
+ validates :name, :uniqueness => true, :presence => true, :format => { :with => /\A[\w\d]+\z/, :message => N_("is alphanumeric and cannot contain spaces") }
13
+
14
+ default_scope lambda {
15
+ order("salt_modules.name")
16
+ }
17
+
18
+ scoped_search :on => :name, :complete_value => true
19
+ scoped_search :in => :hostgroups, :on => :name, :complete_value => true, :rename => :hostgroup
20
+ scoped_search :in => :hosts, :on => :name, :complete_value => true, :rename => :host
21
+ end
22
+ end
@@ -0,0 +1,2 @@
1
+ <li><a href="#salt_modules" data-toggle="tab"><%= _('Salt Modules') %></a></li>
2
+