foreman_salt 0.0.2

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