foreman_discovery 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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