foreman_salt 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +29 -0
  4. data/Rakefile +40 -0
  5. data/app/controllers/foreman_salt/concerns/hostgroups_controller_extensions.rb +19 -0
  6. data/app/controllers/foreman_salt/concerns/hosts_controller_extensions.rb +69 -0
  7. data/app/controllers/foreman_salt/concerns/smart_proxy_auth_extensions.rb +24 -0
  8. data/app/controllers/foreman_salt/concerns/unattended_controller_extensions.rb +18 -0
  9. data/app/controllers/foreman_salt/salt_autosign_controller.rb +43 -0
  10. data/app/controllers/foreman_salt/salt_keys_controller.rb +59 -0
  11. data/app/controllers/foreman_salt/salt_modules_controller.rb +45 -0
  12. data/app/helpers/concerns/foreman_salt/hosts_helper_extensions.rb +28 -0
  13. data/app/helpers/concerns/foreman_salt/smart_proxies_helper_extensions.rb +22 -0
  14. data/app/helpers/foreman_salt/salt_keys_helper.rb +9 -0
  15. data/app/lib/proxy_api/salt.rb +60 -0
  16. data/app/models/concerns/foreman_salt/host_managed_extensions.rb +64 -0
  17. data/app/models/concerns/foreman_salt/hostgroup_extensions.rb +49 -0
  18. data/app/models/concerns/foreman_salt/orchestration/salt.rb +72 -0
  19. data/app/models/foreman_salt/fact_name.rb +4 -0
  20. data/app/models/foreman_salt/salt_module.rb +22 -0
  21. data/app/overrides/foreman/salt_modules/_host_tab.html.erb +2 -0
  22. data/app/overrides/foreman/salt_modules/_host_tab_pane.html.erb +22 -0
  23. data/app/overrides/salt_modules_selector.rb +19 -0
  24. data/app/overrides/salt_proxy_selector.rb +13 -0
  25. data/app/services/foreman_salt/fact_importer.rb +108 -0
  26. data/app/services/foreman_salt/smart_proxies/salt_keys.rb +68 -0
  27. data/app/views/foreman_salt/salt_autosign/_form.html.erb +8 -0
  28. data/app/views/foreman_salt/salt_autosign/index.html.erb +21 -0
  29. data/app/views/foreman_salt/salt_autosign/new.html.erb +3 -0
  30. data/app/views/foreman_salt/salt_keys/index.erb +34 -0
  31. data/app/views/foreman_salt/salt_modules/_form.html.erb +15 -0
  32. data/app/views/foreman_salt/salt_modules/edit.html.erb +4 -0
  33. data/app/views/foreman_salt/salt_modules/index.html.erb +23 -0
  34. data/app/views/foreman_salt/salt_modules/new.html.erb +4 -0
  35. data/config/routes.rb +32 -0
  36. data/db/migrate/20140813081913_add_salt_proxy_to_host_and_host_group.rb +12 -0
  37. data/db/migrate/20140817210214_create_salt_modules.rb +20 -0
  38. data/db/migrate/20140829210214_add_salt_modules_to_hostgroups.rb +12 -0
  39. data/db/seeds.d/75-salt-seeds.rb +31 -0
  40. data/lib/foreman_salt/engine.rb +90 -0
  41. data/lib/foreman_salt/version.rb +3 -0
  42. data/lib/foreman_salt.rb +4 -0
  43. data/lib/tasks/foreman_salt_tasks.rake +31 -0
  44. data/test/factories/foreman_salt_factories.rb +32 -0
  45. data/test/functional/hosts_controller_test.rb +17 -0
  46. data/test/integration/salt_autosign_test.rb +29 -0
  47. data/test/integration/salt_keys_test.rb +45 -0
  48. data/test/integration/salt_module_test.rb +27 -0
  49. data/test/test_plugin_helper.rb +14 -0
  50. data/test/unit/grains_centos.json +108 -0
  51. data/test/unit/grains_importer_test.rb +38 -0
  52. data/test/unit/host_extensions_test.rb +32 -0
  53. data/test/unit/hostgroup_extensions_test.rb +40 -0
  54. data/test/unit/salt_keys_test.rb +46 -0
  55. metadata +122 -0
@@ -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