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.
- 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
|