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
@@ -3,9 +3,6 @@ require 'foreman_discovery/proxy_operations'
3
3
  class Host::Discovered < ::Host::Base
4
4
  include ScopedSearchExtensions
5
5
 
6
- belongs_to :location
7
- belongs_to :organization
8
- belongs_to :subnet
9
6
  belongs_to :hostgroup
10
7
  has_one :discovery_attribute_set, :foreign_key => :host_id, :dependent => :destroy
11
8
 
@@ -13,71 +10,46 @@ class Host::Discovered < ::Host::Base
13
10
 
14
11
  delegate :memory, :cpu_count, :disk_count, :disks_size, :to => :discovery_attribute_set
15
12
 
16
- scoped_search :on => :name, :complete_value => true, :default_order => true
13
+ scoped_search :on => :name, :complete_value => true
14
+ scoped_search :on => :created_at, :default_order => :desc
17
15
  scoped_search :on => :last_report, :complete_value => true
18
- scoped_search :on => :ip, :complete_value => true
19
- scoped_search :on => :mac, :complete_value => true
16
+ scoped_search :in => :primary_interface, :on => :ip, :complete_value => true
17
+ scoped_search :in => :primary_interface, :on => :mac, :complete_value => true
20
18
  scoped_search :in => :model, :on => :name, :complete_value => true, :rename => :model
21
19
  scoped_search :in => :fact_values, :on => :value, :in_key => :fact_names, :on_key => :name, :rename => :facts, :complete_value => true, :only_explicit => true
22
20
  scoped_search :in => :location, :on => :name, :rename => :location, :complete_value => true if SETTINGS[:locations_enabled]
23
21
  scoped_search :in => :organization, :on => :name, :rename => :organization, :complete_value => true if SETTINGS[:organizations_enabled]
24
22
  scoped_search :in => :subnet, :on => :network, :complete_value => true, :rename => :subnet
23
+ scoped_search :in => :subnet, :on => :name, :complete_value => true, :rename => 'subnet.name'
25
24
  scoped_search :in => :discovery_attribute_set, :on => :cpu_count, :rename => :cpu_count, :complete_value => true, :only_explicit => true
26
25
  scoped_search :in => :discovery_attribute_set, :on => :memory, :rename => :memory, :complete_value => true, :only_explicit => true
27
26
  scoped_search :in => :discovery_attribute_set, :on => :disk_count, :rename => :disk_count, :complete_value => true, :only_explicit => true
28
27
  scoped_search :in => :discovery_attribute_set, :on => :disks_size, :rename => :disks_size, :complete_value => true, :only_explicit => true
29
28
 
30
29
  default_scope lambda {
31
- org = Organization.current
32
- loc = Location.current
33
- conditions = {}
34
- conditions[:organization_id] = org.subtree_ids if org
35
- conditions[:location_id] = loc.subtree_ids if loc
36
- where(conditions)
30
+ where(taxonomy_conditions).order("hosts.created_at DESC")
37
31
  }
38
32
 
39
33
  def self.import_host_and_facts facts
40
34
  raise(::Foreman::Exception.new(N_("Invalid facts, must be a Hash"))) unless facts.is_a?(Hash)
41
- fact_name = Setting[:discovery_fact] || 'discovery_bootif'
42
- prefix_from_settings = Setting[:discovery_prefix]
43
- hostname_prefix = prefix_from_settings if prefix_from_settings.present? && prefix_from_settings.match(/^[a-zA-Z].*/)
44
- hostname_prefix ||= 'mac'
45
- hostname = facts[fact_name].try(:downcase).try(:gsub,/:/,'').try(:sub,/^/, hostname_prefix)
46
- raise(::Foreman::Exception.new(N_("Invalid facts: hash does not contain the required fact '%s'"), fact_name)) unless hostname
47
- raise(::Foreman::Exception.new(N_("Invalid facts: hash does not contain IP address"))) unless facts['ipaddress']
48
35
 
49
36
  # filter facts
50
37
  facts.reject!{|k,v| k =~ /kernel|operatingsystem|osfamily|ruby|path|time|swap|free|filesystem/i }
51
38
 
39
+ raise ::Foreman::Exception.new(N_("Expected discovery_fact '%s' is missing, unable to detect primary interface and set hostname") % FacterUtils::bootif_name) unless FacterUtils::bootif_present(facts)
40
+
41
+ # construct hostname
42
+ prefix_from_settings = Setting[:discovery_prefix]
43
+ hostname_prefix = prefix_from_settings if prefix_from_settings.present? && prefix_from_settings.match(/^[a-zA-Z].*/)
44
+ hostname_prefix ||= 'mac'
45
+ hostname = FacterUtils::bootif_mac(facts).try(:downcase).try(:gsub,/:/,'').try(:sub,/^/, hostname_prefix)
46
+
47
+ # create new host record
52
48
  h = ::Host::Discovered.find_by_name hostname
53
49
  h ||= Host.new :name => hostname, :type => "Host::Discovered"
54
50
  h.type = "Host::Discovered"
55
51
 
56
- macfact = facts[fact_name].try(:downcase)
57
- begin
58
- macfact = Net::Validations.normalize_mac(macfact)
59
- rescue ArgumentError => e
60
- macfact = facts['discovery_bootif'].try(:downcase)
61
- h.name = facts['discovery_bootif'].try(:downcase).try(:gsub,/:/,'').try(:sub,/^/, hostname_prefix)
62
- end
63
- h.mac = macfact
64
-
65
-
66
- if SETTINGS[:locations_enabled]
67
- begin
68
- h.location = (Location.find_by_name Setting[:discovery_location]) || Location.first
69
- rescue
70
- h.location = Location.first
71
- end
72
- end
73
- if SETTINGS[:organizations_enabled]
74
- begin
75
- h.organization = (Organization.find_by_name Setting[:discovery_organization]) || Organization.first
76
- rescue
77
- h.organization = Organization.first
78
- end
79
- end
80
-
52
+ # and save (interfaces are created via puppet parser extension)
81
53
  h.save(:validate => false) if h.new_record?
82
54
  state = h.import_facts(facts)
83
55
  return h, state
@@ -100,17 +72,35 @@ class Host::Discovered < ::Host::Base
100
72
  super
101
73
  end
102
74
 
103
- def populate_fields_from_facts facts = self.facts_hash, type = 'puppet'
104
- # type arg only added in 1.7
105
- if Gem::Dependency.new('', '>= 1.7').match?('', SETTINGS[:version].notag)
106
- importer = super
75
+ def populate_fields_from_facts(facts = self.facts_hash, type = 'puppet')
76
+ # detect interfaces and primary interface using extensions
77
+ parser = super(facts, type)
78
+
79
+ # set additional discovery attributes
80
+ primary_ip = self.primary_interface.ip
81
+ unless primary_ip.nil?
82
+ subnet = Subnet.subnet_for(primary_ip)
83
+ Rails.logger.warn "Subnet not detected for #{primary_ip}" if subnet.nil?
84
+ # set subnet
85
+ self.primary_interface.subnet = subnet
86
+ # set location and organization
87
+ if SETTINGS[:locations_enabled]
88
+ self.location = Location.find_by_name(Setting[:discovery_location]) ||
89
+ subnet.try(:locations).try(:first) ||
90
+ Location.first
91
+ end
92
+ if SETTINGS[:organizations_enabled]
93
+ self.organization = Organization.find_by_name(Setting[:discovery_organization]) ||
94
+ subnet.try(:organizations).try(:first) ||
95
+ Organization.first
96
+ end
107
97
  else
108
- importer = super(facts)
98
+ raise(::Foreman::Exception.new(N_("Unable to assign subnet, primary interface is missing IP address")))
109
99
  end
110
- self.primary_interface.subnet = Subnet.subnet_for(self.primary_interface.ip)
111
100
  self.discovery_attribute_set = DiscoveryAttributeSet.where(:host_id => id).first_or_create
112
101
  self.discovery_attribute_set.update_attributes(import_from_facts)
113
- self.save
102
+ self.save!
103
+ parser
114
104
  end
115
105
 
116
106
  def import_from_facts(facts = self.facts_hash)
@@ -160,18 +150,14 @@ class Host::Discovered < ::Host::Base
160
150
  proxy_url = self.proxy_url
161
151
 
162
152
  if proxy_url[:type] == 'proxy'
163
- status = ForemanDiscovery::ProxyOperations.new(:url => proxy_url[:url], :operation => 'reboot').parse_put_operation
153
+ ForemanDiscovery::ProxyOperations.new(:url => proxy_url[:url], :operation => 'reboot').
154
+ parse_put_operation.try(:fetch, 'result')
164
155
  else
165
- status = ::ProxyAPI::BMC.new(:url => "http://#{self.ip}:8443").power :action => "cycle"
156
+ ::ProxyAPI::BMC.new(:url => "http://#{self.ip}:8443").power :action => "cycle"
166
157
  end
167
-
168
- msg = status ? 'successful' : 'failed'
169
- logger.info "ForemanDiscovery: reboot result: #{msg}"
170
- status
171
- rescue => e
172
- logger.info "ForemanDiscovery: reboot result: failed"
173
- logger.warn e.backtrace.join('\n')
174
- raise e
158
+ rescue => e
159
+ ::Foreman::Logging.exception("Unable to reboot #{name}", e)
160
+ raise ::Foreman::WrappedException.new(e, N_("Unable to reboot %{name}: %{msg}"), :name => name, :msg => e.to_s)
175
161
  end
176
162
 
177
163
  def self.model_name
@@ -4,24 +4,33 @@ module Host::ManagedExtensions
4
4
  included do
5
5
  # execute standard callbacks
6
6
  after_validation :queue_reboot
7
+ after_save :delete_discovery_attribute_set
7
8
 
8
9
  belongs_to :discovery_rule
9
10
  end
10
11
 
11
12
  def queue_reboot
13
+ return unless errors.empty? && Setting[:discovery_reboot]
12
14
  return if new_record? # Discovered Hosts already exist, and new_records will break `find`
13
15
  return unless type_changed? and ::Host::Base.find(self.id).type == "Host::Discovered"
16
+ # reboot task must be high priority and there is no compensation action apparently
14
17
  post_queue.create(:name => _("Rebooting %s") % self, :priority => 10000,
15
18
  :action => [self, :setReboot])
16
19
  end
17
20
 
18
21
  def setReboot
19
22
  old.becomes(Host::Discovered).reboot
23
+ # It is too late to report error in the post_queue, we catch them and
24
+ # continue. If flash is implemented for new hosts (http://projects.theforeman.org/issues/10559)
25
+ # we can report the error to the user perhaps.
26
+ true
27
+ rescue ::Foreman::Exception
28
+ true
20
29
  end
21
30
 
22
- def delReboot
23
- # nothing to do here, in reality we should never hit this method since this should be the
24
- # last action in the queue.
31
+ def delete_discovery_attribute_set
32
+ return if new_record?
33
+ DiscoveryAttributeSet.destroy_all(:host_id => self.id) if type_changed?
25
34
  end
26
35
 
27
36
  end
@@ -9,34 +9,35 @@ class Setting::Discovered < ::Setting
9
9
 
10
10
  Setting.transaction do
11
11
  [
12
- self.set('discovery_fact', _("The default fact name to use for the MAC of the system"), "discovery_bootif"),
13
- self.set('discovery_auto', _("Automatically provision newly discovered hosts, according to the provisioning rules"), false),
12
+ self.set('discovery_fact', N_("Fact name to use for primary interface detection and hostname"), "discovery_bootif"),
13
+ self.set('discovery_auto', N_("Automatically provision newly discovered hosts, according to the provisioning rules"), false),
14
+ self.set('discovery_reboot', N_("Automatically reboot discovered host during provisioning"), true),
14
15
  ].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
15
16
  end
16
17
 
17
18
  Setting.transaction do
18
19
  [
19
- self.set('discovery_prefix', _("The default prefix to use for the host name, must start with a letter"), "mac"),
20
+ self.set('discovery_prefix', N_("The default prefix to use for the host name, must start with a letter"), "mac"),
20
21
  ].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
21
22
  end
22
23
 
23
24
  Setting.transaction do
24
25
  [
25
- self.set('discovery_fact_column', _("Show fact as an extra column in the discovered hosts list"), ""),
26
+ self.set('discovery_fact_column', N_("Extra facter columns to show in host lists (separate by comma)"), ""),
26
27
  ].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
27
28
  end
28
29
 
29
30
  if SETTINGS[:locations_enabled]
30
31
  Setting.transaction do
31
32
  [
32
- self.set('discovery_location', _("The default location to place discovered hosts in"), ""),
33
+ self.set('discovery_location', N_("The default location to place discovered hosts in"), ""),
33
34
  ].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
34
35
  end
35
36
  end
36
37
  if SETTINGS[:organizations_enabled]
37
38
  Setting.transaction do
38
39
  [
39
- self.set('discovery_organization', _("The default organization to place discovered hosts in"), "" ),
40
+ self.set('discovery_organization', N_("The default organization to place discovered hosts in"), "" ),
40
41
  ].compact.each { |s| self.create s.update(:category => "Setting::Discovered")}
41
42
  end
42
43
  end
@@ -45,4 +46,15 @@ class Setting::Discovered < ::Setting
45
46
 
46
47
  end
47
48
 
49
+ def self.discovery_fact_column_array
50
+ return [] if !Setting['discovery_fact_column'].present?
51
+ list = []
52
+ Setting['discovery_fact_column'].to_s.split(",").each do |value|
53
+ list << value.strip
54
+ end
55
+ rescue => error
56
+ logger.warn "Failed to parse comma delimited list [%s] into array. Error: %s" % [list,error]
57
+ ensure
58
+ list
59
+ end
48
60
  end
@@ -0,0 +1,22 @@
1
+ class ForemanDiscovery::HostConverter
2
+
3
+ # Converts discovered host to managed host without uptading the database.
4
+ # Record must be saved explicitly (using save! or update_attributes! or similar).
5
+ # This method MUST be called from a SQL transaction.
6
+ def self.to_managed(original_host, set_managed = true, set_build = true)
7
+ if ActiveRecord::Base.connection.open_transactions <= 0
8
+ raise "This method must be executed with explicit transaction"
9
+ end
10
+ host = original_host.becomes(::Host::Managed)
11
+ host.type = 'Host::Managed'
12
+ # the following flags can be skipped when parameters are set to false
13
+ if set_managed
14
+ host.managed = set_managed
15
+ host.primary_interface.managed = set_managed
16
+ end
17
+ # set build only and only on final save (otherwise interfaces are not being identified)
18
+ host.build = set_build if set_build
19
+ host
20
+ end
21
+
22
+ end
@@ -2,7 +2,7 @@ object @discovered_host
2
2
 
3
3
  extends "api/v2/discovered_hosts/base"
4
4
 
5
- attributes :ip, :mac, :last_report, :subnet_id, :subnet_name, :memory, :disk_count, :disks_size
5
+ attributes :ip, :mac, :last_report, :subnet_id, :subnet_name, :model_name, :memory, :disk_count, :disks_size
6
6
  attribute :cpu_count => :cpus
7
7
 
8
8
  if SETTINGS[:organizations_enabled]
@@ -2,4 +2,9 @@ object @discovery_rule
2
2
 
3
3
  extends "api/v2/discovery_rules/base"
4
4
 
5
- attributes :name, :enabled, :hostgroup_id, :hostname, :max_count, :priority, :search
5
+ attributes :name, :enabled, :hostgroup_id, :hostgroup_name, :hostname, :priority, :search
6
+ attribute :max_count => :hosts_limit
7
+
8
+ child :hosts do
9
+ extends "api/v2/discovered_hosts/base"
10
+ end
@@ -1,3 +1,7 @@
1
1
  object @discovery_rule
2
2
 
3
3
  extends "api/v2/discovery_rules/main"
4
+
5
+ node do |discovery_rule|
6
+ partial("api/v2/taxonomies/children_nodes", :object => discovery_rule)
7
+ end
@@ -1,10 +1,12 @@
1
- <h4 class="ca"><%= _('Discovered Host Pool') %> - <%= @current_permission %></h4>
2
1
  <% all_hosts = Host::Discovered.includes(:model).includes(:discovery_attribute_set).scoped %>
3
- <% hosts = all_hosts.limit(5) %>
2
+ <% hosts = all_hosts.limit(6) %>
3
+
4
+ <h4 class="header">
5
+ <%= link_to "#{all_hosts.size} #{n_('Discovered Host', 'Discovered Hosts', all_hosts.size)}", discovered_hosts_path %>
6
+ </h4>
7
+
4
8
  <% if hosts.empty? %>
5
9
  <p class="ca"><%= _("No discovered hosts available") %></p>
6
10
  <% else %>
7
11
  <%= render :partial => 'discovery_widget_host_list', :locals => { :hosts => hosts } %>
8
- <p class="ca"><%= link_to n_("Total pool size", "Total pool size", all_hosts.size), discovered_hosts_path %>
9
- - <%= all_hosts.size %> </p>
10
12
  <% end %>
@@ -0,0 +1,4 @@
1
+ <td><%= discovery_status_icon(host) %>&#8239;<%= link_to trunc_with_tooltip(h(host.name)), discovered_host_path(host) %></td>
2
+ <td class="hidden-tablet hidden-xs"><%= model_name host %></td>
3
+ <td class="hidden-tablet hidden-xs"><%= discovery_attribute(host, :cpu_count) %></td>
4
+ <td class="hidden-tablet hidden-xs"><%= number_to_human_size(discovery_attribute(host, :memory, 0) * 1024 * 1024) %></td>
@@ -2,15 +2,14 @@
2
2
  <thead>
3
3
  <th><%= _('Host') %></th>
4
4
  <th><%= _('Model') %></th>
5
- <th><%= _('IP Address') %></th>
6
5
  <th><%= _('CPUs') %></th>
7
6
  <th><%= _('Memory') %></th>
8
7
  </thead>
9
8
  <tbody>
10
9
  <% hosts.each do |host| %>
11
10
  <tr>
12
- <%= render :partial => "discovered_hosts/discovered_host", :locals => {
13
- :host => host, :hide_disk => true } %>
11
+ <%= render :partial => "discovery_widget_host", :locals => {
12
+ :host => host } %>
14
13
  </tr>
15
14
  <% end %>
16
15
  </tbody>
@@ -1,12 +1,10 @@
1
- <td><%= link_to trunc_with_tooltip(h(host.name)), discovered_host_path(host) %></td>
1
+ <td><%= discovery_status_icon(host) %>&#8239;<%= link_to trunc_with_tooltip(h(host.name)), discovered_host_path(host) %></td>
2
2
  <td class="hidden-tablet hidden-xs"><%= model_name host %></td>
3
3
  <td class="hidden-tablet hidden-xs"><%= host.ip %></td>
4
4
  <td class="hidden-tablet hidden-xs"><%= discovery_attribute(host, :cpu_count) %></td>
5
5
  <td class="hidden-tablet hidden-xs"><%= number_to_human_size(discovery_attribute(host, :memory, 0) * 1024 * 1024) %></td>
6
- <% unless defined? hide_disk %>
7
6
  <td class="hidden-tablet hidden-xs"><%= discovery_attribute(host, :disk_count) %></td>
8
7
  <td class="hidden-tablet hidden-xs"><%= number_to_human_size(discovery_attribute(host, :disks_size, 0) * 1024 * 1024) %></td>
9
- <% if Setting['discovery_fact_column'].present? %>
10
- <td class="hidden-tablet hidden-xs"><%= host.facts_hash[Setting['discovery_fact_column']] || 'N/A' %></td>
11
- <% end %>
8
+ <% Setting::Discovered.discovery_fact_column_array.each do |fact_column| %>
9
+ <td class="hidden-tablet hidden-xs"><%= host.facts_hash[fact_column.strip] || 'N/A' %></td>
12
10
  <% end %>
@@ -10,8 +10,8 @@
10
10
  <th class="hidden-tablet hidden-xs"><%= sort :memory, :as => _('Memory') %></th>
11
11
  <th class="hidden-tablet hidden-xs"><%= sort :disk_count, :as => _('Disk count') %></th>
12
12
  <th class="hidden-tablet hidden-xs"><%= sort :disks_size, :as => _('Disks size') %></th>
13
- <% if Setting['discovery_fact_column'].present? %>
14
- <th class="hidden-tablet hidden-xs"><%= Setting['discovery_fact_column'].capitalize %></th>
13
+ <% Setting::Discovered.discovery_fact_column_array.each do |fact_column| %>
14
+ <th class="hidden-tablet hidden-xs"><%= fact_column.strip.capitalize %></th>
15
15
  <% end %>
16
16
  <% if SETTINGS[:locations_enabled] -%>
17
17
  <th class="hidden-tablet hidden-xs"><%= sort :location, :as => _('Location') %></th>
@@ -26,7 +26,7 @@
26
26
  <% @hosts.each do |host| -%>
27
27
  <tr>
28
28
  <td class="ca">
29
- <%= check_box_tag "host_ids[]", nil, false, :id => "host_ids_#{host.id}", :disabled => !authorized?, :class => 'host_select_boxes', :onclick => 'hostChecked(this)' -%>
29
+ <%= check_box_tag "host_ids[]", nil, false, :id => "host_ids_#{host.id}", :disabled => !authorized_for_edit_destroy?, :class => 'host_select_boxes', :onclick => 'hostChecked(this)' -%>
30
30
  </td>
31
31
  <%= render :partial => "discovered_host", :locals => {:host => host} %>
32
32
  <% if SETTINGS[:locations_enabled] -%>
@@ -39,10 +39,10 @@
39
39
  <td class="hidden-tablet hidden-xs"><%= disc_report_column(host) %></td>
40
40
  <td>
41
41
  <%= action_buttons(
42
- link_to(_("Provision"), hash_for_edit_discovered_host_path(:id => host)),
43
- link_to(_("Auto Provision"), hash_for_auto_provision_discovered_host_path(:id => host), :method => :post),
44
- link_to(_("Refresh facts"), hash_for_refresh_facts_discovered_host_path(:id => host)),
45
- link_to(_("Reboot"), hash_for_reboot_discovered_host_path(:id => host), :method => :put),
42
+ display_link_if_authorized(_("Provision"), hash_for_edit_discovered_host_path(:id => host)),
43
+ display_link_if_authorized(_("Auto Provision"), hash_for_auto_provision_discovered_host_path(:id => host), :method => :post),
44
+ display_link_if_authorized(_("Refresh facts"), hash_for_refresh_facts_discovered_host_path(:id => host)),
45
+ display_link_if_authorized(_("Reboot"), hash_for_reboot_discovered_host_path(:id => host), :method => :put),
46
46
  display_delete_if_authorized(hash_for_discovered_host_path(:id => host), :confirm => _("Delete %s?") % host.name, :action => :destroy))%>
47
47
  </td>
48
48
  </tr>
@@ -1,3 +1,4 @@
1
1
  <% title_actions multiple_discovered_hosts_actions_select -%>
2
+ <% title_actions display_link_if_authorized(_("Reboot All"), hash_for_reboot_all_discovered_hosts_path, {:method => :put, :disabled => @hosts.empty?}) %>
2
3
  <% title_actions display_link_if_authorized(_("Auto Provision All"), hash_for_auto_provision_all_discovered_hosts_path, {:method => :post, :disabled => @hosts.empty?}) %>
3
4
  <%= render 'discovered_hosts_list' %>
@@ -1,34 +1,53 @@
1
1
  <%= form_for @discovery_rule, :url => (@discovery_rule.new_record? ? discovery_rules_path : discovery_rule_path(:id => @discovery_rule.id)) do |f| %>
2
- <%= base_errors_for @discovery_rule %>
3
- <%= text_f f, :name %>
4
- <%= autocomplete_f f, :search,
5
- :path => "discovered_hosts",
6
- :control_group_id => 'search_group', :size => 'col-md-9' %>
7
- <%= select_f f, :hostgroup_id, accessible_hostgroups, :id, :to_label, { :include_blank => false },
8
- { :help_inline => _('Target host group for this rule with all properties set')} %>
9
- <%= text_f f, :hostname, :help_inline => popover(
10
- _("Template"),
11
- "<div>" +
12
- _("Specify target hostname template pattern in the same syntax as in Provisioning Templates (ERB).") +
13
- "</div>"+
14
- "<div>" +
15
- _("Domain will be appended automatically. A hostname based on MAC address will be used when left blank. In addition to @host attribute function rand for random integers is available. Examples:") +
16
- "</div>"+
17
- "<pre>"+
18
- "myhost-&lt;%= rand(99999) %&gt;" + "\n\n" +
19
- "abc-&lt;%= @host.facts['bios_vendor'] + " + "\n" +
20
- " '-' + rand(99999) %&gt;" + "\n\n" +
21
- "xyz-&lt;%= @host.hostgroup.name %&gt;" + "\n\n" +
22
- "srv-&lt;%= @host.discovery_rule.name %&gt;" + "\n\n" +
23
- "server-&lt;%= @host.ip.gsub('.','-') + " + "\n" +
24
- " '-' + @host.hostgroup.subnet.name %&gt;" + "\n" +
25
- "</pre>"+
26
- "</div>"+
27
- "<div>"+
28
- _("When creating hostname patterns, make sure the resulting host names are unique. Hostnames must not start with numbers. A good approach is to use unique information provided by facter (MAC address, BIOS or serial ID).") +
29
- "</div>", :title => _("Hostname for provisioned hosts")).html_safe %>
30
- <%= text_f f, :max_count, :label => _('Hosts limit'), :help_inline => _('Maximum hosts provisioned with this rule (0 = unlimited)') %>
31
- <%= text_f f, :priority, :help_inline => _('Rule priority (lower integer means higher priority)') %>
32
- <%= checkbox_f f, :enabled %>
33
- <%= submit_or_cancel f %>
2
+ <%= base_errors_for @discovery_rule %>
3
+
4
+ <ul class="nav nav-tabs" data-tabs="tabs">
5
+ <li class="active"><a href="#primary" data-toggle="tab"><%= _('Primary') %></a></li>
6
+ <% if show_location_tab? %>
7
+ <li><a href="#locations" data-toggle="tab"><%= _('Locations') %></a></li>
8
+ <% end %>
9
+ <% if show_organization_tab? %>
10
+ <li><a href="#organizations" data-toggle="tab"><%= _('Organizations') %></a></li>
11
+ <% end %>
12
+ </ul>
13
+
14
+ <div class="tab-content">
15
+
16
+ <div class="tab-pane active" id="primary">
17
+ <%= text_f f, :name %>
18
+ <%= autocomplete_f f, :search,
19
+ :path => "discovered_hosts",
20
+ :control_group_id => 'search_group', :size => 'col-md-9' %>
21
+ <%= select_f f, :hostgroup_id, accessible_hostgroups, :id, :to_label, { :include_blank => false },
22
+ { :help_inline => _('Target host group for this rule with all properties set') } %>
23
+ <%= text_f f, :hostname, :help_inline => popover(
24
+ _("Template"),
25
+ "<div>" +
26
+ _("Specify target hostname template pattern in the same syntax as in Provisioning Templates (ERB).") +
27
+ "</div>"+
28
+ "<div>" +
29
+ _("Domain will be appended automatically. A hostname based on MAC address will be used when left blank. In addition to @host attribute function rand for random integers is available. Examples:") +
30
+ "</div>"+
31
+ "<pre>"+
32
+ "myhost-&lt;%= rand(99999) %&gt;" + "\n\n" +
33
+ "abc-&lt;%= @host.facts['bios_vendor'] + " + "\n" +
34
+ " '-' + rand(99999) %&gt;" + "\n\n" +
35
+ "xyz-&lt;%= @host.hostgroup.name %&gt;" + "\n\n" +
36
+ "srv-&lt;%= @host.discovery_rule.name %&gt;" + "\n\n" +
37
+ "server-&lt;%= @host.ip.gsub('.','-') + " + "\n" +
38
+ " '-' + @host.hostgroup.subnet.name %&gt;" + "\n" +
39
+ "</pre>"+
40
+ "</div>"+
41
+ "<div>"+
42
+ _("When creating hostname patterns, make sure the resulting host names are unique. Hostnames must not start with numbers. A good approach is to use unique information provided by facter (MAC address, BIOS or serial ID).") +
43
+ "</div>", :title => _("Hostname for provisioned hosts")).html_safe %>
44
+ <%= text_f f, :max_count, :label => _('Hosts limit'), :help_inline => _('Maximum hosts provisioned with this rule (0 = unlimited)') %>
45
+ <%= text_f f, :priority, :help_inline => _('Rule priority (lower integer means higher priority)') %>
46
+ <%= checkbox_f f, :enabled %>
47
+ </div>
48
+ <% if show_taxonomy_tabs? %>
49
+ <%= render 'taxonomies/loc_org_tabs', :f => f, :obj => @discovery_rule %>
50
+ <% end %>
51
+ </div>
52
+ <%= submit_or_cancel f %>
34
53
  <% end %>
data/config/routes.rb CHANGED
@@ -7,7 +7,7 @@ Rails.application.routes.draw do
7
7
  match 'medium_selected_discovered_hosts' => 'hosts#medium_selected'
8
8
 
9
9
  constraints(:id => /[^\/]+/) do
10
- resources :discovered_hosts do
10
+ resources :discovered_hosts, :except => [:new, :create] do
11
11
  member do
12
12
  get 'refresh_facts'
13
13
  put 'reboot'
@@ -22,6 +22,7 @@ Rails.application.routes.draw do
22
22
  post 'update_multiple_location'
23
23
  get 'auto_complete_search'
24
24
  post 'auto_provision_all'
25
+ put 'reboot_all'
25
26
  end
26
27
  end
27
28
  end
@@ -40,13 +41,12 @@ Rails.application.routes.draw do
40
41
  member do
41
42
  post 'auto_provision'
42
43
  put 'reboot'
44
+ put 'refresh_facts'
43
45
  end
44
46
  collection do
45
47
  post 'facts'
46
48
  post 'auto_provision_all'
47
- end
48
- member do
49
- put 'refresh_facts'
49
+ put 'reboot_all'
50
50
  end
51
51
  end
52
52
  resources :discovery_rules, :except => [:new, :edit]
@@ -0,0 +1,8 @@
1
+ class RemoveDiscoveryAttributeSetsFromManagedHosts < ActiveRecord::Migration
2
+ def up
3
+ DiscoveryAttributeSet.where(:id => DiscoveryAttributeSet.joins(:host).where(:'hosts.managed' => true).pluck("#{DiscoveryAttributeSet.table_name}.id")).delete_all
4
+ end
5
+
6
+ def down
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ class RemoveOldPermissions < ActiveRecord::Migration
2
+ def up
3
+ # remove invalid permissions causing http://projects.theforeman.org/issues/9963
4
+ perms = Permission.where("name like '%_discovered_hosts' and resource_type is null").destroy_all
5
+ say "Removed invalid permissions: #{perms.inspect}" if perms.size > 0
6
+
7
+ # unassociate and remove unused role "Discovery" (renamed to "Discovery Manager")
8
+ if old_role = Role.where(:name => "Discovery").first
9
+ UserRole.where(:role_id => old_role.id).destroy_all
10
+ say "Role 'Discovery' was removed, use 'Discovery Manager' instead" if old_role.destroy
11
+ end
12
+ end
13
+
14
+ def down
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ class RemoveLeftoverTokens < ActiveRecord::Migration
2
+ def up
3
+ existing_tokens = Host::Managed.all.map(&:token).compact
4
+ if existing_tokens.empty?
5
+ Token.delete_all
6
+ else
7
+ Token.where('id not in (?)', existing_tokens).delete_all
8
+ end
9
+ end
10
+
11
+ def down
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class RemoveOldDiscoveryReaderPermissions < ActiveRecord::Migration
2
+ def up
3
+ Permission.where("name like '%_discovery_rules' and resource_type is null").each do |permission|
4
+ permission.update_attributes(:resource_type => 'DiscoveryRule')
5
+ end
6
+ end
7
+
8
+ def down
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ class ReviewDiscoveryPermissions < ActiveRecord::Migration
2
+ def up
3
+ if (mgr = Role.find_by_name("Discovery Manager"))
4
+ perms = []
5
+ perms << "submit_discovered_hosts" if Permission.find_by_name("edit_discovered_hosts")
6
+ perms << "auto_provision_discovered_hosts" if Permission.find_by_name("provision_discovered_hosts")
7
+ perms << "create_discovery_rules" if Permission.find_by_name("new_discovery_rules")
8
+ perms << "destroy_discovery_rules" if Permission.find_by_name("delete_discovery_rules")
9
+ mgr.add_permissions!(perms)
10
+ end
11
+ Permission.find_by_name("new_discovery_rules").try(:destroy)
12
+ end
13
+
14
+ def down
15
+ # rollback is not supported
16
+ end
17
+ end