foreman_discovery 3.0.0 → 4.0.0

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/controllers/api/v2/discovered_hosts_controller.rb +31 -11
  4. data/app/controllers/api/v2/discovery_rules_controller.rb +8 -16
  5. data/app/controllers/concerns/foreman/controller/discovered_extensions.rb +47 -2
  6. data/app/controllers/discovered_hosts_controller.rb +30 -55
  7. data/app/controllers/discovery_rules_controller.rb +2 -4
  8. data/app/helpers/discovered_hosts_helper.rb +27 -5
  9. data/app/lib/facter_utils.rb +18 -0
  10. data/app/lib/puppet_fact_parser_extensions.rb +18 -32
  11. data/app/models/discovery_rule.rb +33 -2
  12. data/app/models/host/discovered.rb +47 -61
  13. data/app/models/host/managed_extensions.rb +12 -3
  14. data/app/models/setting/discovered.rb +18 -6
  15. data/app/services/foreman_discovery/host_converter.rb +22 -0
  16. data/app/views/api/v2/discovered_hosts/main.json.rabl +1 -1
  17. data/app/views/api/v2/discovery_rules/main.json.rabl +6 -1
  18. data/app/views/api/v2/discovery_rules/show.json.rabl +4 -0
  19. data/app/views/dashboard/_discovery_widget.html.erb +6 -4
  20. data/app/views/dashboard/_discovery_widget_host.html.erb +4 -0
  21. data/app/views/dashboard/_discovery_widget_host_list.html.erb +2 -3
  22. data/app/views/discovered_hosts/_discovered_host.html.erb +3 -5
  23. data/app/views/discovered_hosts/_discovered_hosts_list.html.erb +7 -7
  24. data/app/views/discovered_hosts/index.html.erb +1 -0
  25. data/app/views/discovery_rules/_form.html.erb +51 -32
  26. data/config/routes.rb +4 -4
  27. data/db/migrate/20150310153859_remove_discovery_attribute_sets_from_managed_hosts.rb +8 -0
  28. data/db/migrate/20150331132115_remove_old_permissions.rb +16 -0
  29. data/db/migrate/20150505111345_remove_leftover_tokens.rb +13 -0
  30. data/db/migrate/20150512150432_remove_old_discovery_reader_permissions.rb +10 -0
  31. data/db/migrate/20150714144500_review_discovery_permissions.rb +17 -0
  32. data/lib/foreman_discovery/engine.rb +46 -16
  33. data/lib/foreman_discovery/version.rb +1 -1
  34. data/locale/de/LC_MESSAGES/foreman_discovery.mo +0 -0
  35. data/locale/de/foreman_discovery.po +74 -72
  36. data/locale/de/foreman_discovery.pox +40 -0
  37. data/locale/en_GB/LC_MESSAGES/foreman_discovery.mo +0 -0
  38. data/locale/en_GB/foreman_discovery.po +90 -88
  39. data/locale/en_GB/foreman_discovery.pox +0 -0
  40. data/locale/es/LC_MESSAGES/foreman_discovery.mo +0 -0
  41. data/locale/es/foreman_discovery.po +3 -3
  42. data/locale/es/foreman_discovery.pox +41 -0
  43. data/locale/fr/LC_MESSAGES/foreman_discovery.mo +0 -0
  44. data/locale/fr/foreman_discovery.po +3 -3
  45. data/locale/fr/foreman_discovery.pox +69 -0
  46. data/locale/gl/LC_MESSAGES/foreman_discovery.mo +0 -0
  47. data/locale/gl/foreman_discovery.po +3 -3
  48. data/locale/gl/foreman_discovery.pox +21 -0
  49. data/locale/it/LC_MESSAGES/foreman_discovery.mo +0 -0
  50. data/locale/it/foreman_discovery.po +3 -3
  51. data/locale/it/foreman_discovery.pox +0 -0
  52. data/locale/ja/LC_MESSAGES/foreman_discovery.mo +0 -0
  53. data/locale/ja/foreman_discovery.po +67 -66
  54. data/locale/ja/foreman_discovery.pox +29 -0
  55. data/locale/ko/LC_MESSAGES/foreman_discovery.mo +0 -0
  56. data/locale/ko/foreman_discovery.po +3 -3
  57. data/locale/ko/foreman_discovery.pox +189 -0
  58. data/locale/messages.mo +0 -0
  59. data/locale/pt_BR/LC_MESSAGES/foreman_discovery.mo +0 -0
  60. data/locale/pt_BR/foreman_discovery.po +7 -7
  61. data/locale/pt_BR/foreman_discovery.pox +0 -0
  62. data/locale/ru/LC_MESSAGES/foreman_discovery.mo +0 -0
  63. data/locale/ru/foreman_discovery.po +98 -96
  64. data/locale/ru/foreman_discovery.pox +0 -0
  65. data/locale/sv_SE/LC_MESSAGES/foreman_discovery.mo +0 -0
  66. data/locale/sv_SE/foreman_discovery.po +3 -3
  67. data/locale/zh_CN/LC_MESSAGES/foreman_discovery.mo +0 -0
  68. data/locale/zh_CN/foreman_discovery.po +3 -3
  69. data/locale/zh_CN/foreman_discovery.pox +33 -0
  70. data/locale/zh_TW/LC_MESSAGES/foreman_discovery.mo +0 -0
  71. data/locale/zh_TW/foreman_discovery.po +3 -3
  72. data/locale/zh_TW/foreman_discovery.pox +23 -0
  73. data/test/functional/api/v2/discovered_hosts_controller_test.rb +45 -7
  74. data/test/functional/discovered_hosts_controller_test.rb +52 -11
  75. data/test/unit/discovered_extensions_test.rb +40 -17
  76. data/test/unit/discovery_rule_test.rb +59 -0
  77. data/test/unit/host_discovered_test.rb +69 -6
  78. data/test/unit/puppet_fact_parser_extensions_test.rb +55 -40
  79. metadata +103 -81
  80. data/app/services/host_converter.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73911ee5b9b16a403e8f2709babed0be65bcdd31
4
- data.tar.gz: ba4db8e574a8fac66bf4a7b481750581c2e22484
3
+ metadata.gz: fa7dff0a0f4756c41176a4e6b6be41f2815375cc
4
+ data.tar.gz: 7f83b17405564440f5939d66e15527363d07ad27
5
5
  SHA512:
6
- metadata.gz: ab7fba75b6799fcc3c95890a3f942cafea7f4c590a45514f0ebba707256cff977bc5cdec67bdea7bd5ed96c0a5897e6f3c1133b47bc930184fc3750458eee121
7
- data.tar.gz: 3fc4a54ee297c7c3134c3ef02e373225bfc809bc162a90b07dad598455318926065da63696fa0925066709cf1bbb4f54a00183ed8d9da1151243a8b048154695
6
+ metadata.gz: a588c3c7c19787aa5fa1cb36557e786889f294c0005bd4f1cb12dd614be77b88b2a8dbf3f46483ecf5129ad4cabc8f2a9a8cfd025eda077c9f160e0dc10debd0
7
+ data.tar.gz: 0e0e298f9a57c4a310e474f7dd3c6dd38b226d407a55a4a02a8e5c687b06c7149fd5c65da5cd951a61aa01e79833b7dd06539ad522a7e15f3d010aa268e1349d
data/README.md CHANGED
@@ -4,7 +4,7 @@ This plugin enables MaaS hardware discovery in Foreman.
4
4
 
5
5
  # Documentation
6
6
 
7
- The main documentation can be found in [Foreman Discovery 2.0 Manual] (http://theforeman.org/plugins/foreman_discovery/2.0/).
7
+ The main documentation can be found in the [Foreman Discovery manual] (http://theforeman.org/plugins/foreman_discovery/).
8
8
 
9
9
  ## Latest code
10
10
 
@@ -3,7 +3,7 @@ module Api
3
3
  class DiscoveredHostsController < ::Api::V2::BaseController
4
4
  include Foreman::Controller::DiscoveredExtensions
5
5
 
6
- before_filter :find_resource, :except => %w{index create facts auto_provision_all}
6
+ before_filter :find_resource, :except => %w{index create facts auto_provision_all reboot_all}
7
7
  skip_before_filter :authorize, :only => :facts
8
8
 
9
9
  resource_description do
@@ -36,7 +36,7 @@ module Api
36
36
  end
37
37
  end
38
38
 
39
- api :POST, "/discovered_hosts/", N_("Create a discovered host")
39
+ api :POST, "/discovered_hosts/", N_("Create a discovered host for testing (use /facts to create new hosts)")
40
40
  param_group :discovered_host, :as => :create
41
41
 
42
42
  def create
@@ -92,7 +92,7 @@ module Api
92
92
  end
93
93
 
94
94
  api :POST, "/discovered_hosts/facts", N_("Upload facts for a host, creating the host if required")
95
- param :facts, Hash, :required => true, :desc => N_("hash containing facts for the host")
95
+ param :facts, Hash, :required => true, :desc => N_("hash containing facts for the host with minimum set of facts: discovery_bootif, macaddress_eth0, ipaddress, ipaddress_eth0, interfaces: eth0 (example in case primary interface is named eth0)")
96
96
 
97
97
  def facts
98
98
  state = true
@@ -100,7 +100,7 @@ module Api
100
100
  @discovered_host, state = Host::Discovered.import_host_and_facts(params[:facts])
101
101
  end
102
102
  if Setting['discovery_auto']
103
- @discovered_host.transaction do
103
+ Host.transaction do
104
104
  if state && rule = find_discovery_rule(@discovered_host)
105
105
  state = perform_auto_provision(@discovered_host, rule)
106
106
  else
@@ -109,7 +109,9 @@ module Api
109
109
  end
110
110
  end
111
111
  process_response state
112
- rescue ::Foreman::Exception => e
112
+ rescue Exception => e
113
+ logger.warn "Host discovery failed, facts: #{params[:facts]}"
114
+ logger.debug e.message + "\n" + e.backtrace.join("\n")
113
115
  render :json => {'message'=>e.to_s}, :status => :unprocessable_entity
114
116
  end
115
117
 
@@ -117,12 +119,15 @@ module Api
117
119
  param :id, :identifier, :required => true
118
120
 
119
121
  def auto_provision
120
- @discovered_host.transaction do
122
+ Host.transaction do
121
123
  if rule = find_discovery_rule(@discovered_host)
122
124
  msg = _("Host %{host} was provisioned with rule %{rule}") % {:host => @discovered_host.name, :rule => rule.name}
123
125
  process_response perform_auto_provision(@discovered_host, rule), msg
124
126
  else
125
- process_success _("No rule found for host %s") % @discovered_host.name
127
+ render_error :custom_error, :status => :not_found,
128
+ :locals => {
129
+ :message => _("No rule found for host %s") % @discovered_host.name
130
+ }
126
131
  end
127
132
  end
128
133
  rescue ::Foreman::Exception => e
@@ -185,6 +190,21 @@ module Api
185
190
  render :json => {'message'=>e.to_s}
186
191
  end
187
192
 
193
+ api :PUT, "/discovered_hosts/reboot_all", N_("Rebooting all discovered hosts")
194
+
195
+ def reboot_all
196
+ error_message = perform_reboot_all
197
+ if error_message
198
+ render_error :custom_error,
199
+ :status => :unprocessable_entity,
200
+ :locals => {
201
+ :message => error_message
202
+ }
203
+ else
204
+ process_success _("Discovered hosts are rebooting now")
205
+ end
206
+ end
207
+
188
208
  private
189
209
 
190
210
  def resource_class
@@ -197,12 +217,12 @@ module Api
197
217
 
198
218
  def action_permission
199
219
  case params[:action]
200
- when 'auto_provision'
220
+ when 'auto_provision', 'auto_provision_all'
201
221
  :auto_provision
202
- when 'auto_provision_all'
203
- :auto_provision_all
204
- when 'refresh_facts', 'reboot'
222
+ when 'refresh_facts', 'reboot', 'reboot_all'
205
223
  :edit
224
+ when 'facts', 'create'
225
+ :submit
206
226
  else
207
227
  super
208
228
  end
@@ -28,13 +28,13 @@ module Api
28
28
 
29
29
  def_param_group :discovery_rule do
30
30
  param :discovery_rule, Hash, :action_aware => true do
31
- param :name, String, :required => true
32
- param :search, String, :required => true
33
- param :hostgroup_id, Integer, :required => true
34
- param :hostname, String, :required => true
35
- param :max_count, Integer
36
- param :priority, Integer
37
- param :enabled, :bool
31
+ param :name, String, :required => true, :desc => N_("represents rule name shown to the users")
32
+ param :search, String, :required => true, :desc => N_("query to match discovered hosts for the particular rule")
33
+ param :hostgroup_id, Integer, :required => true, :desc => N_("the hostgroup that is used to auto provision a host")
34
+ param :hostname, String, :desc => N_("defines a pattern to assign human-readable hostnames to the matching hosts")
35
+ param :max_count, Integer, :desc => N_("enables to limit maximum amount of provisioned hosts per rule")
36
+ param :priority, Integer, :desc => N_("puts the rules in order, low numbers go first. Must be greater then zero")
37
+ param :enabled, :bool, :desc => N_("flag is used for temporary shutdown of rules")
38
38
  end
39
39
  end
40
40
 
@@ -48,15 +48,7 @@ module Api
48
48
 
49
49
  api :PUT, "/discovery_rules/:id/", N_("Update a rule")
50
50
  param :id, :identifier, :required => true
51
- param :discovery_rule, Hash, :action_aware => true do
52
- param :name, String, :required => true
53
- param :search, String, :required => true
54
- param :hostgroup_id, Integer, :required => true
55
- param :hostname, String, :required => true
56
- param :max_count, Integer
57
- param :priority, Integer
58
- param :enabled, :bool
59
- end
51
+ param_group :discovery_rule, :as => :update
60
52
 
61
53
  def update
62
54
  process_response @discovery_rule.update_attributes(params[:discovery_rule])
@@ -3,6 +3,7 @@ module Foreman::Controller::DiscoveredExtensions
3
3
 
4
4
  # return auto provision rule or false when not present
5
5
  def find_discovery_rule host
6
+ raise(::Foreman::Exception.new(N_("Unable to find a discovery rule, no host provided (check permissions)"))) if host.nil?
6
7
  Rails.logger.debug "Finding auto discovery rule for host #{host.name} (#{host.id})"
7
8
  # for each discovery rule ordered by priority
8
9
  DiscoveryRule.where(:enabled => true).order(:priority).each do |rule|
@@ -14,8 +15,12 @@ module Foreman::Controller::DiscoveredExtensions
14
15
  # try to match the search
15
16
  begin
16
17
  if Host::Discovered.where(:id => host.id).search_for(rule.search).size > 0
17
- Rails.logger.info "Match found for host #{host.name} (#{host.id}) rule #{rule.name} (#{rule.id})"
18
- return rule
18
+ if validate_rule_by_taxonomy(rule, host)
19
+ Rails.logger.info "Match found for host #{host.name} (#{host.id}) rule #{rule.name} (#{rule.id})"
20
+ return rule
21
+ else
22
+ Rails.logger.warn "Rule #{rule.name} (#{rule.id}) can not be applied due to a difference in organization/location from host #{host.name} (#{host.id})"
23
+ end
19
24
  end
20
25
  rescue ScopedSearch::QueryNotSupported => e
21
26
  Rails.logger.warn "Invalid query for rule #{rule.name} (#{rule.id}): #{e.message}"
@@ -27,6 +32,16 @@ module Foreman::Controller::DiscoveredExtensions
27
32
  return false
28
33
  end
29
34
 
35
+ def validate_rule_by_taxonomy rule, host
36
+ if SETTINGS[:organizations_enabled]
37
+ return false unless rule.organizations.include?(host.organization)
38
+ end
39
+ if SETTINGS[:locations_enabled]
40
+ return false unless rule.locations.include?(host.location)
41
+ end
42
+ true
43
+ end
44
+
30
45
  # trigger the provisioning
31
46
  def perform_auto_provision original_host, rule
32
47
  Host.transaction do
@@ -44,5 +59,35 @@ module Foreman::Controller::DiscoveredExtensions
44
59
  end
45
60
  end
46
61
 
62
+ def perform_reboot_all hosts = Host::Discovered.all
63
+ result = true
64
+ error_message = _("Errors during reboot: %s")
65
+ overall_errors = ""
66
+
67
+ if hosts.count > 0
68
+ Host.transaction do
69
+ hosts.each do |discovered_host|
70
+ begin
71
+ unless discovered_host.reboot
72
+ error = "#{discovered_host.name}: failed to reboot "
73
+ overall_errors << error
74
+ logger.error error
75
+ end
76
+ rescue Exception => e
77
+ error = "#{discovered_host.name}: #{e.to_s} "
78
+ overall_errors << error
79
+ logger.error error
80
+ end
81
+ end
82
+ end
83
+ else
84
+ error_message = _("No discovered hosts to reboot")
85
+ result = false
86
+ end
87
+
88
+ if overall_errors.present? || !result
89
+ error_message % overall_errors.strip
90
+ end
91
+ end
47
92
 
48
93
  end
@@ -4,45 +4,23 @@ class DiscoveredHostsController < ::ApplicationController
4
4
  include Foreman::Controller::DiscoveredExtensions
5
5
  unloadable
6
6
 
7
- # Avoid auth for discovered host creation
8
- skip_before_filter :require_login, :require_ssl, :authorize, :verify_authenticity_token, :set_taxonomy, :session_expiry, :update_activity_time, :only => :create
9
-
10
7
  before_filter :find_by_name, :only => %w[show edit update destroy refresh_facts convert reboot auto_provision]
11
8
  before_filter :find_multiple, :only => [:multiple_destroy, :submit_multiple_destroy]
12
9
  before_filter :taxonomy_scope, :only => [:edit]
13
10
 
11
+ around_filter :skip_bullet, :only => [:edit]
12
+
14
13
  helper :hosts
15
14
 
16
15
  layout 'layouts/application'
17
16
 
18
17
  def index
19
- search = resource_base.search_for(params[:search], :order => params[:order])
20
- respond_to do |format|
21
- format.html do
22
- @hosts = search.includes(:location, :organization, :subnet, :model, :discovery_attribute_set).paginate(:page => params[:page])
23
- end
24
- format.json { render :json => search }
25
- end
26
- end
27
-
28
- # Importing yaml is restricted to puppetmasters, so instead we take the ip
29
- # as a parameter and use refresh_facts to get the rest
30
- def create
31
- Taxonomy.no_taxonomy_scope do
32
- host, imported = Host::Discovered.new(:ip => get_ip_from_env).refresh_facts
33
- respond_to do |format|
34
- format.yml {
35
- if imported
36
- render :text => _("Imported discovered host"), :status => 200 and return
37
- else
38
- render :text => _("Failed to import facts for discovered host"), :status => 400
39
- end
40
- }
41
- end
42
- end
43
- rescue Exception => e
44
- logger.warn "Failed to import facts for discovered host: #{e}"
45
- render :text => _("Failed to import facts for discovered host: %s") % (e), :status => 400
18
+ @hosts = resource_base.search_for(params[:search], :order => params[:order]).includes([
19
+ :location,
20
+ :organization,
21
+ :model,
22
+ :discovery_attribute_set
23
+ ], {:interfaces => :subnet}).paginate(:page => params[:page])
46
24
  end
47
25
 
48
26
  def show
@@ -60,14 +38,14 @@ class DiscoveredHostsController < ::ApplicationController
60
38
 
61
39
  def edit
62
40
  Host.transaction do
63
- @host = ::ForemanDiscovery::HostConverter.to_managed(@host) unless @host.nil?
41
+ @host = ::ForemanDiscovery::HostConverter.to_managed(@host, true, false) unless @host.nil?
64
42
  render :template => 'hosts/edit'
65
43
  end
66
44
  end
67
45
 
68
46
  def update
69
47
  Host.transaction do
70
- @host = ::ForemanDiscovery::HostConverter.to_managed(@host, false, false)
48
+ @host = ::ForemanDiscovery::HostConverter.to_managed(@host)
71
49
  forward_url_options
72
50
  Taxonomy.no_taxonomy_scope do
73
51
  if @host.update_attributes(params[:host])
@@ -105,6 +83,16 @@ class DiscoveredHostsController < ::ApplicationController
105
83
  :redirect => :back
106
84
  end
107
85
 
86
+ def reboot_all
87
+ error_message = perform_reboot_all
88
+
89
+ if error_message
90
+ process_error :error_msg => error_message, :redirect => :back
91
+ else
92
+ process_success :success_msg => _("Discovered hosts are rebooting now"), :success_redirect => :back
93
+ end
94
+ end
95
+
108
96
  def multiple_destroy
109
97
  end
110
98
 
@@ -137,7 +125,7 @@ class DiscoveredHostsController < ::ApplicationController
137
125
  end
138
126
 
139
127
  def auto_provision
140
- @host.transaction do
128
+ Host.transaction do
141
129
  if rule = find_discovery_rule(@host)
142
130
  if perform_auto_provision(@host, rule)
143
131
  process_success :success_msg => _("Host %{host} was provisioned with rule %{rule}") % {:host => @host.name, :rule => rule.name}, :success_redirect => discovered_hosts_path
@@ -214,18 +202,12 @@ class DiscoveredHostsController < ::ApplicationController
214
202
 
215
203
  def action_permission
216
204
  case params[:action]
217
- when 'refresh_facts', 'reboot'
218
- :view
219
- when 'new', 'create'
220
- :provision
221
- when 'update_multiple_location', 'select_multiple_organization', 'update_multiple_organization', 'select_multiple_location'
205
+ when 'refresh_facts', 'reboot', 'reboot_all', 'update_multiple_location', 'select_multiple_organization', 'update_multiple_organization', 'select_multiple_location'
222
206
  :edit
223
207
  when 'submit_multiple_destroy', 'multiple_destroy'
224
208
  :destroy
225
- when 'auto_provision'
209
+ when 'auto_provision', 'auto_provision_all'
226
210
  :auto_provision
227
- when 'auto_provision_all'
228
- :auto_provision_all
229
211
  else
230
212
  super
231
213
  end
@@ -257,20 +239,6 @@ class DiscoveredHostsController < ::ApplicationController
257
239
  redirect_to discovered_hosts_path
258
240
  end
259
241
 
260
- def get_ip_from_env
261
- # try to find host based on our client ip address
262
- ip = request.env['REMOTE_ADDR']
263
-
264
- # check if someone is asking on behave of another system (load balance etc)
265
- ip = request.env['HTTP_X_FORWARDED_FOR'] if request.env['HTTP_X_FORWARDED_FOR'].present?
266
-
267
- # Check for explicit parameter override
268
- ip = params.delete('ip') if params.include?('ip')
269
-
270
- # in case we got back multiple ips (see #1619)
271
- ip = ip.split(',').first
272
- end
273
-
274
242
  def taxonomy_scope
275
243
  if @host
276
244
  @organization = @host.organization
@@ -287,4 +255,11 @@ class DiscoveredHostsController < ::ApplicationController
287
255
  end
288
256
  end
289
257
 
258
+ # particular actions will always raise N+1 queries
259
+ def skip_bullet
260
+ Bullet.enable = false if defined? Bullet
261
+ yield
262
+ ensure
263
+ Bullet.enable = true if defined? Bullet
264
+ end
290
265
  end
@@ -53,10 +53,8 @@ class DiscoveryRulesController < ApplicationController
53
53
 
54
54
  def action_permission
55
55
  case params[:action]
56
- when 'enable'
57
- :enable
58
- when 'disable'
59
- :disable
56
+ when 'enable', 'disable'
57
+ :edit
60
58
  else
61
59
  super
62
60
  end
@@ -24,16 +24,15 @@ module DiscoveredHostsHelper
24
24
  end
25
25
 
26
26
  def multiple_discovered_hosts_actions_select
27
- actions = [[_('Delete hosts'), multiple_destroy_discovered_hosts_path]]
28
- actions << [_('Assign Organization'), select_multiple_organization_discovered_hosts_path] if SETTINGS[:organizations_enabled]
29
- actions << [_('Assign Location'), select_multiple_location_discovered_hosts_path] if SETTINGS[:locations_enabled]
27
+ actions = [[_('Delete hosts'), multiple_destroy_discovered_hosts_path, hash_for_multiple_destroy_discovered_hosts_path]]
28
+ actions << [_('Assign Organization'), select_multiple_organization_discovered_hosts_path, hash_for_select_multiple_organization_discovered_hosts_path] if SETTINGS[:organizations_enabled]
29
+ actions << [_('Assign Location'), select_multiple_location_discovered_hosts_path, hash_for_select_multiple_location_discovered_hosts_path] if SETTINGS[:locations_enabled]
30
30
 
31
31
  select_action_button( _("Select Action"), {:id => 'submit_multiple'},
32
32
  actions.map do |action|
33
- link_to_function(action[0], "build_modal(this, '#{action[1]}')", :'data-dialog-title' => _("%s - The following hosts are about to be changed") % action[0])
33
+ link_to_function(action[0], "build_modal(this, '#{action[1]}')", :'data-dialog-title' => _("%s - The following hosts are about to be changed") % action[0]) if authorized_for(action[2])
34
34
  end.flatten
35
35
  )
36
-
37
36
  end
38
37
 
39
38
  def turn_zero_to_not_available(value)
@@ -44,4 +43,27 @@ module DiscoveredHostsHelper
44
43
  host.try(:discovery_attribute_set).try(attr) || default_value
45
44
  end
46
45
 
46
+ def authorized_for_edit_destroy?
47
+ authorized_for(:controller => :discovered_hosts, :action => :edit) or
48
+ authorized_for(:controller => :discovered_hosts, :action => :destroy)
49
+ end
50
+
51
+ def discovery_status_icon(host)
52
+ if host.created_at > 1.day.ago
53
+ status_glyph = 'glyphicon-plus-sign'
54
+ status_message = _('New in the last 24 hours')
55
+ status_color = '#89A54E'
56
+ elsif host.last_report < 7.days.ago
57
+ status_glyph = 'glyphicon-exclamation-sign'
58
+ status_message = _('Not reported in more than 7 days')
59
+ status_color = '#AA4643'
60
+ else
61
+ status_glyph = 'glyphicon-ok-sign'
62
+ status_message = _('Reported in the last 7 days')
63
+ status_color = '#4572A7'
64
+ end
65
+
66
+ "<span class='glyphicon #{status_glyph}' style='color: #{status_color}'
67
+ title='#{status_message}'/>".html_safe
68
+ end
47
69
  end
@@ -0,0 +1,18 @@
1
+ module FacterUtils
2
+ class << self
3
+ # booted interface fact name
4
+ def bootif_name
5
+ Setting[:discovery_fact] || 'discovery_bootif'
6
+ end
7
+
8
+ # booted interface fact is present
9
+ def bootif_present(facts)
10
+ ! bootif_mac(facts).nil?
11
+ end
12
+
13
+ # booted interface MAC address (nil when not present)
14
+ def bootif_mac(facts)
15
+ facts[bootif_name]
16
+ end
17
+ end
18
+ end
@@ -2,42 +2,28 @@ module PuppetFactParserExtensions
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- # In Foreman 1.8 these two methods have been removed, we could reuse discovery_mac_fact_name in suggested_primary_interface(host) if needed
6
- if instance_methods.include?(:primary_interface)
7
- alias_method_chain :primary_interface, :discovery_fact
8
- end
9
-
10
- if instance_methods.include?(:ip)
11
- alias_method_chain :ip, :discovery_fact
5
+ begin
6
+ raise "method: suggested_primary_interface" unless instance_methods.include?(:suggested_primary_interface)
7
+ raise "method: parse_interfaces?" unless instance_methods.include?(:parse_interfaces?)
8
+ alias_method_chain :suggested_primary_interface, :bootif
9
+ alias_method_chain :parse_interfaces?, :bootif
10
+ rescue Exception => e
11
+ raise ::Foreman::WrappedException.new(e, N_("Incompatible version of puppet fact parser"))
12
12
  end
13
13
  end
14
14
 
15
- # we prefer discovery_bootif fact to choose right primary interface (interface used to boot the image)
16
- def primary_interface_with_discovery_fact
17
- if facts.has_key?(discovery_mac_fact_name)
18
- mac = facts[discovery_mac_fact_name]
19
- interfaces.each do |int, values|
20
- return int.to_s if (values[:macaddress].try(:downcase) == mac.try(:downcase))
21
- end
22
- end
23
- primary_interface_without_discovery_fact # fallback if we didn't find interface with such macaddress
15
+ # discovery has its own method of finding primary iface
16
+ def suggested_primary_interface_with_bootif(host)
17
+ return suggested_primary_interface_without_bootif(host) if host.type != "Host::Discovered"
18
+ bootif_mac = FacterUtils::bootif_mac(facts).try(:downcase)
19
+ detected = interfaces.detect { |_, values| values[:macaddress].try(:downcase) == bootif_mac }
20
+ Rails.logger.debug "Detected primary interface: #{detected}"
21
+ # return the detected interface as array [name, facts]
22
+ detected || raise(::Foreman::Exception.new(N_("Unable to detect primary interface using MAC '%{mac}' specified by discovery_fact '%{fact}'") % {:mac => bootif_mac, :fact => FacterUtils::bootif_name}))
24
23
  end
25
24
 
26
- # search for IP of interface with primary interface macaddress (ipaddress fact does not have to be interface used for boot)
27
- def ip_with_discovery_fact
28
- if facts[:interfaces] && facts.has_key?(discovery_mac_fact_name)
29
- facts[:interfaces].split(',').each do |interface|
30
- if facts["macaddress_#{interface}"].try(:downcase) == facts[discovery_mac_fact_name].try(:downcase)
31
- return facts["ipaddress_#{interface}"]
32
- end
33
- end
34
- end
35
- ip_without_discovery_fact # fallback if IP was not found
36
- end
37
-
38
- private
39
-
40
- def discovery_mac_fact_name
41
- Setting[:discovery_fact] || 'discovery_bootif'
25
+ # make 'ignore_puppet_facts_for_provisioning' setting non-effective
26
+ def parse_interfaces_with_bootif?
27
+ true
42
28
  end
43
29
  end
@@ -3,8 +3,7 @@ class DiscoveryRule < ActiveRecord::Base
3
3
  extend FriendlyId
4
4
  friendly_id :name
5
5
  include Parameterizable::ByIdName
6
-
7
- attr_accessible :name, :enabled, :hostgroup_id, :hostname, :max_count, :priority, :search
6
+ include Taxonomix
8
7
 
9
8
  validates :name, :presence => true, :uniqueness => true,
10
9
  :format => { :with => /\A(\S+)\Z/, :message => N_("can't contain white spaces.") }
@@ -15,6 +14,8 @@ class DiscoveryRule < ActiveRecord::Base
15
14
  validates :max_count, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }
16
15
  validates :priority, :presence => true, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }
17
16
  validates_lengths_from_database
17
+ before_validation :default_int_attributes
18
+ before_validation :enforce_taxonomy
18
19
 
19
20
  belongs_to :hostgroup
20
21
  has_many :hosts
@@ -23,4 +24,34 @@ class DiscoveryRule < ActiveRecord::Base
23
24
  scoped_search :on => :priority
24
25
  scoped_search :on => :search
25
26
  scoped_search :on => :enabled
27
+ scoped_search :in => :hostgroup, :on => :name, :complete_value => true, :rename => :hostgroup
28
+
29
+ # with proc support, default_scope can no longer be chained
30
+ # include all default scoping here
31
+ default_scope lambda {
32
+ with_taxonomy_scope do
33
+ order("discovery_rules.name")
34
+ end
35
+ }
36
+
37
+ def default_int_attributes
38
+ self.max_count ||= 0
39
+ self.priority ||= 0
40
+ end
41
+
42
+ def enforce_taxonomy
43
+ return if hostgroup.nil?
44
+ if SETTINGS[:organizations_enabled]
45
+ unless (ms = hostgroup.organizations - organizations).empty?
46
+ names = ms.collect(&:name).to_sentence
47
+ errors.add(:organizations, n_("Host group organization %s must also be associated to the discovery rule", "Host group organizations %s must also be associated to the discovery rule", ms.size) % names)
48
+ end
49
+ end
50
+ if SETTINGS[:locations_enabled]
51
+ unless (ms = hostgroup.locations - locations).empty?
52
+ names = ms.collect(&:name).to_sentence
53
+ errors.add(:locations, n_("Host group location %s must also be associated to the discovery rule", "Host group locations %s must also be associated to the discovery rule", ms.size) % names)
54
+ end
55
+ end
56
+ end
26
57
  end