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
@@ -0,0 +1,22 @@
1
+ <% @inherited_salt_modules = [] if @inherited_salt_modules.blank? %>
2
+ <div class="tab-pane" id="salt_modules">
3
+ <div class="row">
4
+ <div class="col-md-4">
5
+ <h3>Inherited Modules</h3>
6
+ <ul>
7
+ <% @inherited_salt_modules.sort.each do |salt_module| -%>
8
+ <li title="Inherited from hostgroup"><%= salt_module.name -%></li>
9
+ <% end -%>
10
+ </ul>
11
+ </div>
12
+ <div class="col-md-8">
13
+ <h3>Salt Modules</h3>
14
+ <% if @inherited_salt_modules.blank? -%>
15
+ <%= multiple_selects f, :salt_module, ::ForemanSalt::SaltModule, @salt_modules.try(:map, &:id), :label => "" %>
16
+ <% else -%>
17
+ <%= multiple_selects f, :salt_module, ::ForemanSalt::SaltModule.where('id NOT IN (?)', @inherited_salt_modules.map(&:id)), @salt_modules.try(:map, &:id), :label => "" %>
18
+ <% end -%>
19
+ </div>
20
+ </div>
21
+ </div>
22
+
@@ -0,0 +1,19 @@
1
+ Deface::Override.new(:virtual_path => "hosts/_form",
2
+ :name => "add_salt_modules_tab_to_host",
3
+ :insert_after => 'li.active',
4
+ :partial => '../overrides/foreman/salt_modules/host_tab')
5
+
6
+ Deface::Override.new(:virtual_path => "hosts/_form",
7
+ :name => "add_salt_modules_tab_pane_to_host",
8
+ :insert_before => 'div#puppet_klasses',
9
+ :partial => '../overrides/foreman/salt_modules/host_tab_pane')
10
+
11
+ Deface::Override.new(:virtual_path => "hostgroups/_form",
12
+ :name => "add_salt_modules_tab_to_hg",
13
+ :insert_after => 'li.active',
14
+ :partial => '../overrides/foreman/salt_modules/host_tab')
15
+
16
+ Deface::Override.new(:virtual_path => "hostgroups/_form",
17
+ :name => "add_salt_modules_tab_pane_to_hg",
18
+ :insert_before => 'div#puppet_klasses',
19
+ :partial => '../overrides/foreman/salt_modules/host_tab_pane')
@@ -0,0 +1,13 @@
1
+ selector_text = "<%= select_f f, :salt_proxy_id, SmartProxy.unscoped.with_features('Salt').with_taxonomy_scope(@location,@organization, :path_ids), :id, :name,
2
+ { :include_blank => blank_or_inherit_f(f, :salt_proxy) },
3
+ { :label => _('Salt Master') } %>"
4
+
5
+ Deface::Override.new(:virtual_path => "hosts/_form",
6
+ :name => "add_salt_proxy_to_host",
7
+ :insert_bottom => 'div#primary',
8
+ :text => selector_text)
9
+
10
+ Deface::Override.new(:virtual_path => "hostgroups/_form",
11
+ :name => "add_salt_proxy_to_hostgroup",
12
+ :insert_bottom => 'div#primary',
13
+ :text => selector_text)
@@ -0,0 +1,108 @@
1
+ module ForemanSalt
2
+ class FactImporter < ::FactImporter
3
+ def fact_name_class
4
+ ForemanSalt::FactName
5
+ end
6
+
7
+ def self.support_background
8
+ true
9
+ end
10
+
11
+ private
12
+
13
+ attr_accessor :original_facts
14
+
15
+ def add_new_facts
16
+ @counters[:added] = 0
17
+ add_missing_facts(unsparse(original_facts))
18
+ logger.debug("Merging facts for '#{host}': added #{@counters[:added]} facts")
19
+ end
20
+
21
+ def add_missing_facts(tree_hash, parent = nil, prefix = '')
22
+ tree_hash.each do |name, value|
23
+ name_with_prefix = prefix.empty? ? name : prefix + FactName::SEPARATOR + name
24
+
25
+ compose = value.is_a?(Hash)
26
+ if fact_names[name_with_prefix].present?
27
+ fact_name_id = fact_names[name_with_prefix]
28
+ else
29
+ fact_name_id = fact_name_class.create!(:name => name_with_prefix,
30
+ :parent_id => parent,
31
+ :compose => compose).id
32
+ end
33
+
34
+ if compose
35
+ add_fact(name_with_prefix, nil, fact_name_id)
36
+ add_missing_facts(value, fact_name_id, name_with_prefix)
37
+ else
38
+ add_fact(name_with_prefix, value, fact_name_id)
39
+ end
40
+ end
41
+ end
42
+
43
+ def add_fact(name, value, fact_name_id)
44
+ if facts_to_create.include?(name)
45
+ host.fact_values.send(method,
46
+ :value => value, :fact_name_id => fact_name_id)
47
+ @counters[:added] += 1
48
+ end
49
+ end
50
+
51
+ def facts_to_create
52
+ @facts_to_create ||= facts.keys - db_facts.keys
53
+ end
54
+
55
+ def fact_names
56
+ @fact_names ||= fact_name_class.maximum(:id, :group => 'name')
57
+ end
58
+
59
+ # if the host does not exists yet, we don't have an host_id to use the fact_values table.
60
+ def method
61
+ @method ||= host.new_record? ? :build : :create!
62
+ end
63
+
64
+ def normalize(facts)
65
+ @original_facts = super(facts)
66
+ @facts = completify(@original_facts)
67
+ end
68
+
69
+ def completify(hash)
70
+ new_facts = hash.dup
71
+ hash.each do |fact_name, value|
72
+ name_parts = fact_name.split(FactName::SEPARATOR)
73
+
74
+ name_parts.inject([]) do |memo, name|
75
+ memo = memo + [name]
76
+ key = memo.join(FactName::SEPARATOR)
77
+ new_facts[key] ||= name_parts == memo ? value : nil
78
+ memo
79
+ end
80
+ end
81
+ new_facts
82
+ end
83
+
84
+ def sort_by_key(hash)
85
+ hash.sort_by { |k, v| k.to_s }
86
+ end
87
+
88
+ def sparse(hash, options={})
89
+ hash.map do |k, v|
90
+ prefix = (options.fetch(:prefix, [])+[k])
91
+ next Sparsify::sparse(v, options.merge(:prefix => prefix)) if v.is_a? Hash
92
+ { prefix.join(options.fetch(:separator, FactName::SEPARATOR)) => v }
93
+ end.reduce(:merge) || Hash.new
94
+ end
95
+
96
+ def unsparse(hash, options={})
97
+ ret = Hash.new
98
+ sparse(hash).each do |k, v|
99
+ current = ret
100
+ key = k.to_s.split(options.fetch(:separator, FactName::SEPARATOR))
101
+ current = (current[key.shift] ||= Hash.new) until (key.size<=1)
102
+ current[key.first] = v
103
+ end
104
+ return ret
105
+ end
106
+ end
107
+ end
108
+
@@ -0,0 +1,68 @@
1
+ module ForemanSalt
2
+ class SmartProxies::SaltKeys
3
+
4
+ attr_reader :name, :state, :fingerprint, :smart_proxy_id
5
+
6
+ def initialize opts
7
+ @name, @state, @fingerprint, @smart_proxy_id = opts.flatten
8
+ end
9
+
10
+ class << self
11
+
12
+ def all(proxy)
13
+ raise ::Foreman::Exception.new(N_("Must specify a Smart Proxy to use")) if proxy.nil?
14
+
15
+ unless (keys = Rails.cache.read("saltkeys_#{proxy.id}"))
16
+ api = ProxyAPI::Salt.new({:url => proxy.url})
17
+ keys = api.key_list.map do |name, properties|
18
+ new([name.strip, properties['state'], properties['fingerprint'], proxy.id])
19
+ end.compact
20
+
21
+ Rails.cache.write("saltkeys_#{proxy.id}", keys, {:expires_in => 1.minute }) if Rails.env.production?
22
+ end
23
+ keys
24
+ end
25
+
26
+ def find(proxy, name)
27
+ all(proxy).select{|c| c.name == name}.first
28
+ end
29
+
30
+ def find_by_state(proxy, state)
31
+ all(proxy).select{|c| c.state == state}
32
+ end
33
+ end
34
+
35
+ def accept
36
+ raise ::Foreman::Exception.new(N_("unable to re-accept an accepted key")) unless state == "unaccepted"
37
+ proxy = SmartProxy.find(smart_proxy_id)
38
+ Rails.cache.delete("saltkeys_#{proxy.id}") if Rails.env.production?
39
+ ProxyAPI::Salt.new({:url => proxy.url}).key_accept name
40
+ end
41
+
42
+ def reject
43
+ raise ::Foreman::Exception.new(N_("unable to reject an accepted key")) unless state == "unaccepted"
44
+ proxy = SmartProxy.find(smart_proxy_id)
45
+ Rails.cache.delete("saltkeys_#{proxy.id}") if Rails.env.production?
46
+ ProxyAPI::Salt.new({:url => proxy.url}).key_reject name
47
+ end
48
+
49
+
50
+ def delete
51
+ proxy = SmartProxy.find(smart_proxy_id)
52
+ Rails.cache.delete("saltkeys_#{proxy.id}") if Rails.env.production?
53
+ ProxyAPI::Salt.new({:url => proxy.url}).key_delete name
54
+ end
55
+
56
+ def to_param
57
+ name
58
+ end
59
+
60
+ def to_s
61
+ name
62
+ end
63
+
64
+ def <=> other
65
+ self.name <=> other.name
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,8 @@
1
+ <%= form_tag url_for(:controller => 'foreman_salt/salt_autosign', :smart_proxy_id => @proxy, :action => 'index') do |f| %>
2
+ <div class="clearfix">
3
+ <div class="input">
4
+ <%= label_tag(_("Name")) %> <%= text_field_tag(:id, "", :size => 60) %> <%= submit_tag _('Save'), :class => "btn btn-success" %>
5
+ </div>
6
+ </div>
7
+ <% end %>
8
+
@@ -0,0 +1,21 @@
1
+ <% title _("Autosign entries for %s") % @proxy %>
2
+
3
+ <% title_actions display_link_if_authorized(_("Keys"), hash_for_smart_proxy_salt_keys_path), display_link_if_authorized(_("New"), {:controller => 'foreman_salt/salt_autosign', :action => 'new', :smart_proxy_id => @proxy, :auth_object => @proxy, :permission => 'create_smart_proxies_salt_keys'}) %>
4
+
5
+ <table class='table table-bordered table-striped table-condensed'>
6
+ <tr>
7
+ <th><%= _("Name") %></th>
8
+ <th></th>
9
+ </tr>
10
+ <% @autosign.each do |key| %>
11
+ <tr>
12
+ <td><%= key%> </td>
13
+ <td>
14
+ <%= action_buttons(display_delete_if_authorized(hash_for_smart_proxy_salt_autosign_path.merge(:smart_proxy_id => @proxy, :id => key), :class => 'delete')) %>
15
+ </td>
16
+ </tr>
17
+ <% end %>
18
+ </table>
19
+
20
+ <%= page_entries_info @autosign %>
21
+ <%= will_paginate @autosign %>
@@ -0,0 +1,3 @@
1
+ <% title _("New Autosign Entry") %>
2
+
3
+ <%= render :partial => 'form' %>
@@ -0,0 +1,34 @@
1
+ <% title _("Salt Keys on %s") % @proxy.name %>
2
+ <% search_bar _("Filter %s") % salt_keys_state_filter %>
3
+
4
+ <% title_actions display_link_if_authorized(_("Autosign"), hash_for_smart_proxy_salt_autosign_index_path) %>
5
+
6
+ <table class='table table-bordered table-striped table-condensed'>
7
+ <tr>
8
+ <th><%= _("Key Name") %></th>
9
+ <th><%= _("State") %></th>
10
+ <th><%= _("Fingerprint") %></th>
11
+ <th></th>
12
+ </tr>
13
+ <% @keys.each do |key| %>
14
+ <tr>
15
+ <td><%= key.name %> </td>
16
+ <td><%= _(key.state.humanize) %></td>
17
+ <td><%= key.fingerprint %></td>
18
+ <td>
19
+ <%= action_buttons(
20
+ if key.state == "unaccepted"
21
+ [display_link_if_authorized(_("Accept"), hash_for_smart_proxy_salt_key_accept_path.merge(:state => params[:state], :salt_key_id => key)),
22
+ display_link_if_authorized(_("Reject"), hash_for_smart_proxy_salt_key_reject_path.merge(:state => params[:state], :salt_key_id => key))]
23
+ end,
24
+ display_delete_if_authorized(hash_for_smart_proxy_salt_key_path(:smart_proxy_id => @proxy, :id => key, :state => params[:state], :class => 'delete'))
25
+ )
26
+ %>
27
+ </td>
28
+ </tr>
29
+ <% end %>
30
+ </table>
31
+
32
+ <%= page_entries_info @keys %>
33
+ <%= will_paginate @keys %>
34
+
@@ -0,0 +1,15 @@
1
+ <%= form_for @salt_module, :url => (@salt_module.new_record? ? salt_modules_path : salt_module_path(:id => @salt_module.id)) do |f| %>
2
+ <%= base_errors_for @salt_module %>
3
+ <ul class="nav nav-tabs" data-tabs="tabs">
4
+ <li class="active"><a href="#primary" data-toggle="tab"><%= _('Salt Modules') %></a></li>
5
+ </ul>
6
+
7
+ <div class="tab-content">
8
+ <div class="tab-pane active" id="primary">
9
+ <%= text_f f, :name %>
10
+ </div>
11
+ </div>
12
+
13
+ <%= submit_or_cancel f %>
14
+ <% end %>
15
+
@@ -0,0 +1,4 @@
1
+ <% title(_("Edit Salt Module %s") % @salt_module) %>
2
+
3
+ <%= render :partial => 'form' %>
4
+
@@ -0,0 +1,23 @@
1
+ <% title _("Salt modules") %>
2
+
3
+ <% title_actions button_group(display_link_if_authorized(_("New Salt module"), hash_for_new_salt_module_path)) %>
4
+
5
+ <table class="table table-bordered table-striped">
6
+ <tr>
7
+ <th><%= sort :name, :as => s_("SaltModule|Name") %></th>
8
+ <th></th>
9
+ </tr>
10
+ <% for salt_module in @salt_modules %>
11
+ <tr>
12
+ <td><%=link_to_if_authorized h(salt_module.name), hash_for_edit_salt_module_path(:id => salt_module).merge(:auth_object => salt_module, :authorizer => authorizer) %></td>
13
+ <td>
14
+ <%= action_buttons(display_delete_if_authorized hash_for_salt_module_path(:id => salt_module).merge(:auth_object => salt_module, :authorizer => authorizer),
15
+ :confirm => _("Delete %s?") % salt_module.name) %>
16
+ </td>
17
+ </tr>
18
+ <% end %>
19
+ </table>
20
+
21
+ <%= page_entries_info @salt_modules %>
22
+ <%= will_paginate @salt_modules %>
23
+
@@ -0,0 +1,4 @@
1
+ <% title _("New Salt module") %>
2
+
3
+ <%= render :partial => 'form' %>
4
+
data/config/routes.rb ADDED
@@ -0,0 +1,32 @@
1
+ Rails.application.routes.draw do
2
+
3
+ scope :salt, :path => '/salt' do
4
+ match "/node/:name" => 'hosts#salt_external_node', :constraints => { :name => /[^\.][\w\.-]+/ }
5
+
6
+ resources :salt_modules, :controller => 'foreman_salt/salt_modules' do
7
+ collection do
8
+ get 'auto_complete_search'
9
+ end
10
+ end
11
+ end
12
+
13
+ constraints(:smart_proxy_id => /[^\/]+/) do
14
+ resources :smart_proxies, :except => [:show] do
15
+ constraints(:id => /[^\/]+/) do
16
+ resources :salt_autosign, :only => [:index, :destroy, :create, :new], :controller => 'foreman_salt/salt_autosign'
17
+ resources :salt_keys, :only => [:index, :destroy], :controller => 'foreman_salt/salt_keys' do
18
+ get :accept
19
+ get :reject
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ constraints(:id => /[^\/]+/) do
26
+ resources :hosts do
27
+ member do
28
+ get :saltrun
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ class AddSaltProxyToHostAndHostGroup < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :hosts, :salt_proxy_id, :integer
4
+ add_column :hostgroups, :salt_proxy_id, :integer
5
+ end
6
+
7
+ def self.down
8
+ remove_column :hosts, :salt_proxy_id
9
+ remove_column :hostgroups, :salt_proxy_id
10
+ end
11
+
12
+ end
@@ -0,0 +1,20 @@
1
+ class CreateSaltModules < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :salt_modules do |t|
4
+ t.string :name, :default => "", :null => false
5
+ t.timestamps
6
+ end
7
+
8
+ create_table 'hosts_salt_modules', :id => false do |t|
9
+ t.column :host_id, :integer
10
+ t.column :salt_module_id, :integer
11
+ end
12
+
13
+ add_index :salt_modules, :name, :unique => true
14
+ end
15
+
16
+ def self.down
17
+ drop_table :salt_modules
18
+ drop_table :hosts_salt_modules
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ class AddSaltModulesToHostgroups < ActiveRecord::Migration
2
+ def self.up
3
+ create_table 'hostgroups_salt_modules', :id => false do |t|
4
+ t.column :hostgroup_id, :integer
5
+ t.column :salt_module_id, :integer
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :hostgroups_salt_modules
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ # Create feature for Smart Proxy
2
+ Feature.find_or_create_by_name("Salt")
3
+
4
+ # Seed our permissions
5
+ permissions = [
6
+ %w(Host saltrun_hosts),
7
+ %w(Host view_hosts),
8
+ %w(ForemanSalt::SaltModule create_salt_modules),
9
+ %w(ForemanSalt::SaltModule view_salt_modules),
10
+ %w(ForemanSalt::SaltModule edit_salt_modules),
11
+ %w(ForemanSalt::SaltModule destroy_salt_modules),
12
+ %w(SmartProxy view_smart_proxies_salt_keys),
13
+ %w(SmartProxy destroy_smart_proxies_salt_keys),
14
+ %w(SmartProxy edit_smart_proxies_salt_keys),
15
+ %w(SmartProxy destroy_smart_proxies_salt_autosign),
16
+ %w(SmartProxy create_smart_proxies_salt_autosign),
17
+ %w(SmartProxy view_smart_proxies_salt_autosign),
18
+ ]
19
+
20
+ permissions.each do |resource, permission|
21
+ Permission.find_or_create_by_resource_type_and_name resource, permission
22
+ end
23
+
24
+ # Add new viewing permissions to Viewer role
25
+ viewer = Role.find_by_name('Viewer')
26
+
27
+ if viewer
28
+ [:view_smart_proxies_salt_keys, :view_smart_proxies_salt_autosign, :view_salt_modules].each do |permission|
29
+ viewer.add_permissions!([permission]) unless viewer.permissions.include? Permission.find_by_name(permission)
30
+ end
31
+ end
@@ -0,0 +1,90 @@
1
+ require 'deface'
2
+
3
+ module ForemanSalt
4
+ class Engine < ::Rails::Engine
5
+
6
+ config.autoload_paths += Dir["#{config.root}/app/controllers/concerns"]
7
+ config.autoload_paths += Dir["#{config.root}/app/helpers/concerns"]
8
+ config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
9
+ config.autoload_paths += Dir["#{config.root}/app/overrides"]
10
+ config.autoload_paths += Dir["#{config.root}/app/services"]
11
+ config.autoload_paths += Dir["#{config.root}/app/lib"]
12
+
13
+ # Add any db migrations
14
+ initializer "foreman_salt.load_app_instance_data" do |app|
15
+ app.config.paths['db/migrate'] += ForemanSalt::Engine.paths['db/migrate'].existent
16
+ end
17
+
18
+ initializer 'foreman_salt.register_plugin', :after=> :finisher_hook do |app|
19
+ Foreman::Plugin.register :foreman_salt do
20
+ requires_foreman '>= 1.6'
21
+
22
+ menu :top_menu, :salt,
23
+ :url_hash => {:controller => :'foreman_salt/salt_modules', :action => :index },
24
+ :caption => 'Modules',
25
+ :parent => :configure_menu,
26
+ :after => :common_parameters
27
+
28
+ divider :top_menu, :parent => :configure_menu,
29
+ :caption => "Salt",
30
+ :after => :common_parameters
31
+
32
+ security_block :hosts do |map|
33
+ permission :saltrun_hosts, {:hosts => [:saltrun]}, :resource_type => 'Host'
34
+ permission :view_hosts, {:hosts => [:salt_external_node]}, :resource_type => 'Host'
35
+ end
36
+
37
+ security_block :salt_modules do |map|
38
+ permission :create_salt_modules, {:'foreman_salt/salt_modules' => [:new, :create]}, :resource_type => "ForemanSalt::SaltModule"
39
+ permission :view_salt_modules, {:'foreman_salt/salt_modules' => [:index, :show, :auto_complete_search]}, :resource_type => "ForemanSalt::SaltModule"
40
+ permission :edit_salt_modules, {:'foreman_salt/salt_modules' => [:update, :edit]},:resource_type => "ForemanSalt::SaltModule"
41
+ permission :destroy_salt_modules, {:'foreman_salt/salt_modules' => [:destroy]}, :resource_type => "ForemanSalt::SaltModule"
42
+ end
43
+
44
+ security_block :salt_keys do |map|
45
+ permission :view_smart_proxies_salt_keys, {:'foreman_salt/salt_keys' => [:index]}, :resource_type => "SmartProxy"
46
+ permission :destroy_smart_proxies_salt_keys, {:'foreman_salt/salt_keys' => [:destroy]},:resource_type => "SmartProxy"
47
+ permission :edit_smart_proxies_salt_keys, {:'foreman_salt/salt_keys' => [:accept, :reject]}, :resource_type => "SmartProxy"
48
+ end
49
+
50
+ security_block :salt_autosign do |map|
51
+ permission :destroy_smart_proxies_salt_autosign, {:'foreman_salt/salt_autosign' => [:destroy]}, :resource_type => "SmartProxy"
52
+ permission :create_smart_proxies_salt_autosign, {:'foreman_salt/salt_autosign' => [:new, :create]}, :resource_type => "SmartProxy"
53
+ permission :view_smart_proxies_salt_autosign, {:'foreman_salt/salt_autosign' => [:index]}, :resource_type => "SmartProxy"
54
+ end
55
+
56
+ role "Salt admin", [:saltrun_hosts, :create_salt_modules, :view_salt_modules, :edit_salt_modules, :destroy_salt_modules,
57
+ :view_smart_proxies_salt_keys, :destroy_smart_proxies_salt_keys, :edit_smart_proxies_salt_keys,
58
+ :create_smart_proxies_salt_autosign, :view_smart_proxies_salt_autosign, :destroy_smart_proxies_salt_autosign]
59
+
60
+ end
61
+ end
62
+
63
+ config.to_prepare do
64
+ begin
65
+ ::FactImporter.register_fact_importer(:foreman_salt, ForemanSalt::FactImporter)
66
+
67
+ # Helper Extensions
68
+ ::HostsHelper.send :include, ForemanSalt::HostsHelperExtensions
69
+ ::SmartProxiesHelper.send :include, ForemanSalt::SmartProxiesHelperExtensions
70
+
71
+ # Model Extensions
72
+ ::Host::Managed.send :include, ForemanSalt::Concerns::HostManagedExtensions
73
+ ::Host::Managed.send :include, ForemanSalt::Orchestration::Salt
74
+ ::Hostgroup.send :include, ForemanSalt::Concerns::HostgroupExtensions
75
+
76
+ # Controller Extensions
77
+ ::UnattendedController.send :include, ForemanSalt::Concerns::UnattendedControllerExtensions
78
+ ::HostsController.send :include, ForemanSalt::Concerns::HostsControllerExtensions
79
+ ::HostsController.send :include, ForemanSalt::Concerns::SmartProxyAuthExtensions
80
+ ::HostgroupsController.send :include, ForemanSalt::Concerns::HostgroupsControllerExtensions
81
+
82
+ # API Extensions
83
+ ::Api::V2::HostsController.send :include, ForemanSalt::Concerns::SmartProxyAuthExtensions
84
+ ::Api::V2::ReportsController.send :include, ForemanSalt::Concerns::SmartProxyAuthExtensions
85
+ rescue => e
86
+ puts "ForemanSalt: skipping engine hook (#{e.to_s})"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,3 @@
1
+ module ForemanSalt
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,4 @@
1
+ require "foreman_salt/engine"
2
+
3
+ module ForemanSalt
4
+ end
@@ -0,0 +1,31 @@
1
+ # Tasks
2
+ namespace :foreman_salt do
3
+ namespace :example do
4
+ desc 'Example Task'
5
+ task :task => :environment do
6
+ # Task goes here
7
+ end
8
+ end
9
+ end
10
+
11
+ # Tests
12
+ namespace :test do
13
+ desc "Test ForemanSalt"
14
+ Rake::TestTask.new(:foreman_salt) do |t|
15
+ test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
16
+ t.libs << ["test",test_dir]
17
+ t.pattern = "#{test_dir}/**/*_test.rb"
18
+ t.verbose = true
19
+ end
20
+ end
21
+
22
+ Rake::Task[:test].enhance do
23
+ Rake::Task['test:foreman_salt'].invoke
24
+ end
25
+
26
+ load 'tasks/jenkins.rake'
27
+ if Rake::Task.task_defined?(:'jenkins:setup')
28
+ Rake::Task["jenkins:unit"].enhance do
29
+ Rake::Task['test:foreman_salt'].invoke
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ FactoryGirl.define do
2
+ factory :smart_proxy, :class => "::SmartProxy" do
3
+ sequence(:name) { |n| "proxy#{n}" }
4
+ sequence(:url) { |n| "http://proxy#{n}.example.com:9090" }
5
+
6
+ trait :with_salt_feature do
7
+ features { [::Feature.find_or_create_by_name('Salt')] }
8
+ end
9
+ end
10
+
11
+ factory :salt_module, :class => "ForemanSalt::SaltModule" do
12
+ sequence(:name) { |n| "module#{n}" }
13
+ end
14
+ end
15
+
16
+ FactoryGirl.modify do
17
+ factory :host do
18
+ trait :with_salt_proxy do
19
+ salt_proxy { FactoryGirl.create :smart_proxy, :with_salt_feature }
20
+ end
21
+ end
22
+
23
+ factory :hostgroup do
24
+ trait :with_salt_proxy do
25
+ salt_proxy { FactoryGirl.create :smart_proxy, :with_salt_feature }
26
+ end
27
+
28
+ trait :with_salt_modules do
29
+ salt_modules { FactoryGirl.create_list :salt_module, 10 }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class HostsControllerTest < ActionController::TestCase
4
+ test 'salt smart proxy should get salt external node' do
5
+ User.current = nil
6
+ Setting[:restrict_registered_puppetmasters] = true
7
+ Setting[:require_ssl_puppetmasters] = false
8
+
9
+
10
+ proxy = FactoryGirl.create :smart_proxy, :with_salt_feature
11
+ Resolv.any_instance.stubs(:getnames).returns([proxy.to_s])
12
+
13
+ host = FactoryGirl.create :host
14
+ get :salt_external_node, {:name => host.name, :format => "yml"}
15
+ assert_response :success
16
+ end
17
+ end