foreman_salt 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +29 -0
- data/Rakefile +40 -0
- data/app/controllers/foreman_salt/concerns/hostgroups_controller_extensions.rb +19 -0
- data/app/controllers/foreman_salt/concerns/hosts_controller_extensions.rb +69 -0
- data/app/controllers/foreman_salt/concerns/smart_proxy_auth_extensions.rb +24 -0
- data/app/controllers/foreman_salt/concerns/unattended_controller_extensions.rb +18 -0
- data/app/controllers/foreman_salt/salt_autosign_controller.rb +43 -0
- data/app/controllers/foreman_salt/salt_keys_controller.rb +59 -0
- data/app/controllers/foreman_salt/salt_modules_controller.rb +45 -0
- data/app/helpers/concerns/foreman_salt/hosts_helper_extensions.rb +28 -0
- data/app/helpers/concerns/foreman_salt/smart_proxies_helper_extensions.rb +22 -0
- data/app/helpers/foreman_salt/salt_keys_helper.rb +9 -0
- data/app/lib/proxy_api/salt.rb +60 -0
- data/app/models/concerns/foreman_salt/host_managed_extensions.rb +64 -0
- data/app/models/concerns/foreman_salt/hostgroup_extensions.rb +49 -0
- data/app/models/concerns/foreman_salt/orchestration/salt.rb +72 -0
- data/app/models/foreman_salt/fact_name.rb +4 -0
- data/app/models/foreman_salt/salt_module.rb +22 -0
- data/app/overrides/foreman/salt_modules/_host_tab.html.erb +2 -0
- data/app/overrides/foreman/salt_modules/_host_tab_pane.html.erb +22 -0
- data/app/overrides/salt_modules_selector.rb +19 -0
- data/app/overrides/salt_proxy_selector.rb +13 -0
- data/app/services/foreman_salt/fact_importer.rb +108 -0
- data/app/services/foreman_salt/smart_proxies/salt_keys.rb +68 -0
- data/app/views/foreman_salt/salt_autosign/_form.html.erb +8 -0
- data/app/views/foreman_salt/salt_autosign/index.html.erb +21 -0
- data/app/views/foreman_salt/salt_autosign/new.html.erb +3 -0
- data/app/views/foreman_salt/salt_keys/index.erb +34 -0
- data/app/views/foreman_salt/salt_modules/_form.html.erb +15 -0
- data/app/views/foreman_salt/salt_modules/edit.html.erb +4 -0
- data/app/views/foreman_salt/salt_modules/index.html.erb +23 -0
- data/app/views/foreman_salt/salt_modules/new.html.erb +4 -0
- data/config/routes.rb +32 -0
- data/db/migrate/20140813081913_add_salt_proxy_to_host_and_host_group.rb +12 -0
- data/db/migrate/20140817210214_create_salt_modules.rb +20 -0
- data/db/migrate/20140829210214_add_salt_modules_to_hostgroups.rb +12 -0
- data/db/seeds.d/75-salt-seeds.rb +31 -0
- data/lib/foreman_salt/engine.rb +90 -0
- data/lib/foreman_salt/version.rb +3 -0
- data/lib/foreman_salt.rb +4 -0
- data/lib/tasks/foreman_salt_tasks.rake +31 -0
- data/test/factories/foreman_salt_factories.rb +32 -0
- data/test/functional/hosts_controller_test.rb +17 -0
- data/test/integration/salt_autosign_test.rb +29 -0
- data/test/integration/salt_keys_test.rb +45 -0
- data/test/integration/salt_module_test.rb +27 -0
- data/test/test_plugin_helper.rb +14 -0
- data/test/unit/grains_centos.json +108 -0
- data/test/unit/grains_importer_test.rb +38 -0
- data/test/unit/host_extensions_test.rb +32 -0
- data/test/unit/hostgroup_extensions_test.rb +40 -0
- data/test/unit/salt_keys_test.rb +46 -0
- 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,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
|