foreman_discovery 25.0.1 → 25.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b2b4531b45feeb13c37d3dea6805a1805a1e0dd721220faf08c24b99a232755
4
- data.tar.gz: fb7cbd5f6ac3b8272b6fca22229929851f837c037a120de0edc62b215d3177a3
3
+ metadata.gz: 95cebd63e44a4dd37542e995996eff81ed31f0b4b93039298abd37a3a0c83910
4
+ data.tar.gz: 978901f1f25b3e01b30a701d65f96242bec71847b38bd5b7901bcc7778a19628
5
5
  SHA512:
6
- metadata.gz: ba98c7a97aeb8b1d449a62d0c7a9276bebac9cfd3389f6698207528206856e9953f55affdbccb52c1f6e738bc32af41e3b9f857b011b9dfccb3a1ece4317696f
7
- data.tar.gz: b1c30494cc3fc3a8ea5dd621891622323923fdc2c324544b8c30fb6529c9c829141c2ad8299f514a5d3413658430c9d784915335ef3f3bb60dfe049c953ee19a
6
+ metadata.gz: f1b8e43d7343136d97407726f69297c1e84c809d189a35ae6941db6ec90b8de5be3443e349ca4af0dd9b555417434d6b082297d972385ecde2748606b98df4e2
7
+ data.tar.gz: afa86dba8270f1f29f2ceb4edb68dbfba7fa722e4bec342f8a08d69a6ff51c028714b343f77db188fdc59f2d48fa4968b4a44c3ea00bd34f65e7b2c25d511a84
@@ -53,6 +53,7 @@ module Api
53
53
  param :name, String
54
54
  param :environment_id, String, :desc => N_("required if host is managed and value is not inherited from host group")
55
55
  param :ip, String, :desc => N_("not required if using a subnet with DHCP proxy")
56
+ param :ip6, String, :desc => N_("not required if using an IPv6 subnet with DHCP proxy")
56
57
  param :mac, String, :desc => N_("not required if it's a virtual machine")
57
58
  param :architecture_id, :number, :desc => N_("required if host is managed and value is not inherited from host group")
58
59
  param :domain_id, :number, :desc => N_("required if host is managed and value is not inherited from host group")
@@ -62,6 +63,7 @@ module Api
62
63
  param :medium_id, String, :desc => N_("required if not imaged based provisioning and host is managed and value is not inherited from host group")
63
64
  param :ptable_id, :number, :desc => N_("required if host is managed and custom partition has not been defined")
64
65
  param :subnet_id, :number, :desc => N_("required if host is managed and value is not inherited from host group")
66
+ param :subnet6_id, :number, :desc => N_("required if host is managed, does not have IPv4 IP / Subnet, or the value is not inherited from the host group")
65
67
  param :sp_subnet_id, :number
66
68
  param :model_id, :number
67
69
  param :hostgroup_id, :number
@@ -1,43 +1,49 @@
1
- module Foreman::Controller::Parameters::DiscoveredHost
2
- extend ActiveSupport::Concern
3
- include Foreman::Controller::Parameters::Host
4
- if defined?(ForemanPuppet)
5
- include ForemanPuppet::Extensions::ParametersHost
6
- end
1
+ module Foreman
2
+ module Controller
3
+ module Parameters
4
+ module DiscoveredHost
5
+ extend ActiveSupport::Concern
6
+ include Foreman::Controller::Parameters::Host
7
+ if defined?(ForemanPuppet)
8
+ include ForemanPuppet::Extensions::ParametersHost
9
+ end
7
10
 
8
- class_methods do
9
- def discovered_host_params_filter
10
- Foreman::ParameterFilter.new(::Host::Discovered).tap do |filter|
11
- filter.permit :discovery_rule_id
11
+ class_methods do
12
+ def discovered_host_params_filter
13
+ Foreman::ParameterFilter.new(::Host::Discovered).tap do |filter|
14
+ filter.permit :discovery_rule_id
12
15
 
13
- add_host_base_params_filter(filter)
14
- add_host_common_params_filter(filter)
15
- add_host_puppet_params_filter(filter) if defined?(ForemanPuppet)
16
- end
17
- end
18
- end
16
+ add_host_base_params_filter(filter)
17
+ add_host_common_params_filter(filter)
18
+ add_host_puppet_params_filter(filter) if defined?(ForemanPuppet)
19
+ end
20
+ end
21
+ end
19
22
 
20
- def discovered_host_params
21
- filtered_params = self.class.discovered_host_params_filter.filter_params(params, parameter_filter_context)
22
- process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
23
- filtered_params
24
- end
23
+ def discovered_host_params
24
+ filtered_params = self.class.discovered_host_params_filter.filter_params(params, parameter_filter_context)
25
+ process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
26
+ filtered_params
27
+ end
25
28
 
26
- def discovered_host_params_host
27
- filtered_params = self.class.discovered_host_params_filter.filter_params(params, parameter_filter_context, :host)
28
- process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
29
- filtered_params
30
- end
29
+ def discovered_host_params_host
30
+ filtered_params = self.class.discovered_host_params_filter.filter_params(params, parameter_filter_context, :host)
31
+ process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
32
+ filtered_params
33
+ end
31
34
 
32
- def managed_host_params_host
33
- filtered_params = self.class.host_params_filter.filter_params(params, parameter_filter_context, :host)
34
- process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
35
- filtered_params
36
- end
35
+ def managed_host_params_host
36
+ filtered_params = self.class.host_params_filter.filter_params(params, parameter_filter_context, :host)
37
+ process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
38
+ filtered_params
39
+ end
37
40
 
38
- def managed_host_params
39
- filtered_params = self.class.host_params_filter.filter_params(params, parameter_filter_context)
40
- process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
41
- filtered_params
41
+ def managed_host_params
42
+ filtered_params = self.class.host_params_filter.filter_params(params, parameter_filter_context)
43
+ process_deprecated_puppet_params!(filtered_params) if defined?(ForemanPuppet)
44
+ filtered_params
45
+ end
46
+ end
47
+ end
42
48
  end
43
49
  end
@@ -1,17 +1,23 @@
1
- module Foreman::Controller::Parameters::DiscoveryRule
2
- extend ActiveSupport::Concern
3
- include Foreman::Controller::Parameters::Taxonomix
1
+ module Foreman
2
+ module Controller
3
+ module Parameters
4
+ module DiscoveryRule
5
+ extend ActiveSupport::Concern
6
+ include Foreman::Controller::Parameters::Taxonomix
4
7
 
5
- class_methods do
6
- def discovery_rule_params_filter
7
- Foreman::ParameterFilter.new(::DiscoveryRule).tap do |filter|
8
- filter.permit :name, :search, :hostname, :priority, :enabled, :hostgroup, :hostgroup_id, :max_count
9
- add_taxonomix_params_filter(filter)
8
+ class_methods do
9
+ def discovery_rule_params_filter
10
+ Foreman::ParameterFilter.new(::DiscoveryRule).tap do |filter|
11
+ filter.permit :name, :search, :hostname, :priority, :enabled, :hostgroup, :hostgroup_id, :max_count
12
+ add_taxonomix_params_filter(filter)
13
+ end
14
+ end
15
+ end
16
+
17
+ def discovery_rule_params
18
+ self.class.discovery_rule_params_filter.filter_params(params, parameter_filter_context)
19
+ end
10
20
  end
11
21
  end
12
22
  end
13
-
14
- def discovery_rule_params
15
- self.class.discovery_rule_params_filter.filter_params(params, parameter_filter_context)
16
- end
17
23
  end
@@ -335,19 +335,6 @@ class DiscoveredHostsController < ::ApplicationController
335
335
  Bullet.enable = true if defined? Bullet
336
336
  end
337
337
 
338
- def get_interfaces
339
- @host.interfaces.each do |interface|
340
- @interfaces << {:identifier => interface["identifier"], :type => interface["type"], :mac => interface["mac"], :ip => interface["ip"]? interface["ip"] : "N/A", :primary => interface["primary"], :provision => interface["provision"]}
341
- end
342
- end
343
-
344
- def add_custom_facts
345
- unless @host.primary_interface.subnet.nil?
346
- discovery_subnet = "#{@host.primary_interface.subnet.name} (#{@host.primary_interface.subnet.network})"
347
- assign_fact_to_category("discovery_subnet", discovery_subnet)
348
- end
349
- end
350
-
351
338
  def process_warning(hash = {})
352
339
  warning hash[:warning_msg]
353
340
  end
@@ -0,0 +1,354 @@
1
+ class DiscoveredHostsController < ::ApplicationController
2
+ include Foreman::Controller::Parameters::DiscoveredHost
3
+ include Foreman::Controller::AutoCompleteSearch
4
+ include Foreman::Controller::TaxonomyMultiple
5
+ include Foreman::Controller::DiscoveredExtensions
6
+ include ActionView::Helpers::NumberHelper
7
+
8
+ before_action :find_by_name, :only => %w[edit update destroy refresh_facts convert reboot auto_provision]
9
+ before_action :find_by_name_incl_subnet, :only => [:show]
10
+ before_action :find_multiple, :only => [:multiple_destroy, :submit_multiple_destroy, :multiple_reboot, :submit_multiple_reboot, :multiple_auto_provision, :submit_multiple_auto_provision]
11
+ before_action :taxonomy_scope, :only => [:edit]
12
+ before_action :check_for_subnet, :only => [:reboot, :auto_provision, :submit_multiple_reboot, :submit_multiple_auto_provision]
13
+
14
+ around_action :skip_bullet, :only => [:edit]
15
+
16
+ helper :hosts
17
+ if defined?(ForemanPuppet)
18
+ helper ForemanPuppet::HostsHelper
19
+ helper ForemanPuppet::HostsAndHostgroupsHelper
20
+ helper ForemanPuppet::PuppetclassesHelper
21
+ helper ForemanPuppet::PuppetclassLookupKeysHelper
22
+ end
23
+
24
+ layout 'layouts/application'
25
+
26
+ def model_of_controller
27
+ Host::Discovered
28
+ end
29
+
30
+ def index
31
+ @hosts = resource_base_search_and_page.includes([
32
+ :location,
33
+ :organization,
34
+ :model,
35
+ :discovery_attribute_set
36
+ ], {:interfaces => :subnet})
37
+ fact_array = @hosts.collect do |host|
38
+ [host.id, Hash[host.fact_values.joins(:fact_name).where('fact_names.name' => Setting['discovery_fact_column']).pluck(:name, :value)]]
39
+ end
40
+ @host_facts = Hash[fact_array]
41
+ end
42
+
43
+ def show
44
+ # filter graph time range
45
+ @range = nil
46
+ # summary report text
47
+ @report_summary = nil
48
+ resolver = ForemanDiscovery::FactToCategoryResolver.new(@host)
49
+ @categories_names = ForemanDiscovery::FactToCategoryResolver::CATEGORIES_NAMES
50
+ @categories = resolver.categories
51
+ @interfaces = resolver.interfaces
52
+ end
53
+
54
+ def destroy
55
+ @host.destroy
56
+ redirect_to :action => 'index'
57
+ end
58
+
59
+ def edit
60
+ quick = params.delete(:quick_submit)
61
+ @host = ::ForemanDiscovery::HostConverter.to_managed(@host, true, false, discovered_host_params_host) unless @host.nil?
62
+ setup_host_class_variables
63
+ @override_taxonomy = true
64
+ # need to permit this one but don't know how
65
+ if quick
66
+ perform_update(@host, _('Successfully provisioned %s') % @host.name)
67
+ else
68
+ @host.build = true
69
+ render :template => 'discovered_hosts/edit'
70
+ end
71
+ end
72
+
73
+ def update
74
+ @host = ::ForemanDiscovery::HostConverter.to_managed(@host, true, true, managed_host_params_host)
75
+ forward_url_options
76
+
77
+ @override_taxonomy = true
78
+ perform_update(@host)
79
+ end
80
+
81
+ def perform_update(host, success_message = nil)
82
+ Taxonomy.no_taxonomy_scope do
83
+ ::ForemanDiscovery::HostConverter.set_build_clean_facts(host)
84
+ ::ForemanDiscovery::HostConverter.unused_ip_for_host(host)
85
+ if host.save
86
+ host_path = Setting['host_details_ui'] ? host_details_page_path(host) : host_path(host)
87
+ success_options = { :success_redirect => host_path, :redirect_xhr => request.xhr? }
88
+ success_options[:success_msg] = success_message if success_message
89
+ process_success success_options
90
+ else
91
+ taxonomy_scope
92
+ load_vars_for_ajax
93
+ offer_to_overwrite_conflicts
94
+ process_error :object => host, :render => 'discovered_hosts/edit'
95
+ end
96
+ end
97
+ end
98
+
99
+ def refresh_facts
100
+ if @host.is_a?(::Host::Discovered) && @host.refresh_facts
101
+ process_success :success_msg => _("Facts refreshed for %s") % @host.name, :success_redirect => :back
102
+ else
103
+ process_error :error_msg => _("Failed to refresh facts for %s") % @host.name, :redirect => :back
104
+ end
105
+ rescue => e
106
+ exception = Foreman::WrappedException.new(e, N_("Failed to refresh facts for %{hostname} with error %{error_message}"), :hostname => @host.name, :error_message => e.message)
107
+ Foreman::Logging.exception exception.message, e
108
+ process_error :error_msg => exception.message, :redirect => :back
109
+ end
110
+
111
+ def reboot
112
+ unless @host.is_a?(::Host::Discovered)
113
+ process_error :error_msg => _("Host of type %s can not be rebooted") % @host.type, :redirect => :back
114
+ end
115
+
116
+ if @host.reboot
117
+ process_success :success_msg => _("Rebooting host %s") % @host.name, :success_redirect => :back
118
+ else
119
+ process_error :error_msg => _("Failed to reboot host %s") % @host.name, :redirect => :back
120
+ end
121
+ rescue => e
122
+ exception = Foreman::WrappedException.new(e, N_("Failed to reboot host %{hostname} with error %{error_message}"), :hostname => @host.name, :error_message => e.message)
123
+ Foreman::Logging.exception exception.message, e
124
+ process_error :error_msg => exception.message, :redirect => :back
125
+ end
126
+
127
+ def submit_multiple_reboot
128
+ error_message = perform_reboot_all(@hosts)
129
+
130
+ if error_message
131
+ process_error :error_msg => error_message, :redirect => :back
132
+ else
133
+ process_success :success_msg => _("Discovered hosts are rebooting now"), :success_redirect => :back
134
+ end
135
+ rescue => e
136
+ exception = Foreman::WrappedException.new(e, N_("Failed to reboot hosts with error %s"), e.message)
137
+ Foreman::Logging.exception exception.message, e
138
+ process_error :error_msg => exception.message, :redirect => :back
139
+ end
140
+
141
+ def multiple_destroy
142
+ end
143
+
144
+ def multiple_reboot
145
+ end
146
+
147
+ def multiple_auto_provision
148
+ end
149
+
150
+ def submit_multiple_destroy
151
+ # keep all the ones that were not deleted for notification.
152
+ missed_hosts = @hosts.select {|host| !host.destroy }
153
+ if missed_hosts
154
+ success _("Destroyed selected hosts")
155
+ else
156
+ error _("The following hosts were not deleted: %s") % missed_hosts
157
+ end
158
+ redirect_to(discovered_hosts_path)
159
+ end
160
+
161
+ def auto_provision
162
+ if rule = find_discovery_rule(@host)
163
+ if perform_auto_provision(@host, rule)
164
+ process_success :success_msg => _("Host %{host} was provisioned with rule %{rule}") % {:host => @host.name, :rule => rule.name}, :success_redirect => discovered_hosts_path
165
+ else
166
+ errors = @host.errors.full_messages.join(' ')
167
+ logger.warn "Failed to auto provision host %s: %s" % [@host.name, errors]
168
+ process_error :error_msg => _("Failed to auto provision host %s: %s") % [@host.name, errors], :redirect => :back
169
+ end
170
+ else
171
+ process_success :success_msg => _("No rule found for host %s") % @host.name, :success_redirect => :back
172
+ end
173
+ end
174
+
175
+ def submit_multiple_auto_provision
176
+ result = true
177
+ error_message = _("Errors during auto provisioning: %s")
178
+
179
+ if Host::Discovered.count == 0
180
+ error_message = _("No discovered hosts to provision")
181
+ result = false
182
+ end
183
+
184
+ overall_errors = ""
185
+ @hosts.each do |discovered_host|
186
+ if rule = find_discovery_rule(discovered_host)
187
+ result &= perform_auto_provision(discovered_host, rule)
188
+ unless discovered_host.errors.empty?
189
+ errors = discovered_host.errors.full_messages.join(' ')
190
+ logger.warn "Failed to auto provision host %s: %s" % [discovered_host.name, errors]
191
+ overall_errors << "#{discovered_host.name}: #{errors} "
192
+ end
193
+ end
194
+ end
195
+ if result
196
+ process_success :success_msg => _("Discovered hosts are provisioning now"), :success_redirect => :back
197
+ else
198
+ process_error :error_msg => error_message % overall_errors, :redirect => :back
199
+ end
200
+ end
201
+
202
+ def resource_class
203
+ Host::Discovered
204
+ end
205
+
206
+ private
207
+
208
+ def setup_host_class_variables
209
+ if @host.hostgroup
210
+ subnet = @host.hostgroup.subnet || @host.subnet
211
+ subnet6 = @host.hostgroup.subnet6 || @host.subnet6
212
+ @architecture = @host.hostgroup.architecture
213
+ @operatingsystem = @host.hostgroup.operatingsystem
214
+ if defined?(ForemanPuppet)
215
+ @environment = @host.hostgroup.environment
216
+ @host.environment = @environment
217
+ end
218
+ @domain = @host.hostgroup.domain
219
+ @subnet = subnet
220
+ @subnet6 = subnet6
221
+ @compute_profile = @host.hostgroup.compute_profile
222
+ @realm = @host.hostgroup.realm
223
+ @host.interfaces.first.assign_attributes(subnet: subnet, subnet6: subnet6, domain: @domain)
224
+ end
225
+ end
226
+
227
+ def resource_base
228
+ @resource_base ||= ::Host::Discovered.authorized(current_permission, ::Host::Discovered)
229
+ end
230
+
231
+ def load_vars_for_ajax
232
+ return unless @host
233
+ if defined?(ForemanPuppet)
234
+ @environment = @host.environment
235
+ end
236
+ @architecture = @host.architecture
237
+ @domain = @host.domain
238
+ @operatingsystem = @host.operatingsystem
239
+ @medium = @host.medium
240
+ end
241
+
242
+ # this is required for template generation (such as pxelinux) which is not done via a web request
243
+ def forward_url_options(host = @host)
244
+ host.url_options = url_options if @host.respond_to?(:url_options)
245
+ end
246
+
247
+ # if a save failed and the only reason was network conflicts then flag this so that the view
248
+ # is rendered differently and the next save operation will be forced
249
+ def offer_to_overwrite_conflicts
250
+ @host.overwrite = "true" if @host.errors.any? and @host.errors.are_all_conflicts?
251
+ end
252
+
253
+ def controller_permission
254
+ 'discovered_hosts'
255
+ end
256
+
257
+ def action_permission
258
+ case params[:action]
259
+ when 'refresh_facts', 'reboot', 'multiple_reboot', 'update_multiple_location',
260
+ 'select_multiple_organization', 'update_multiple_organization', 'select_multiple_location', 'submit_multiple_reboot'
261
+ :edit
262
+ when 'submit_multiple_destroy', 'multiple_destroy'
263
+ :destroy
264
+ when 'auto_provision', 'multiple_auto_provision', 'submit_multiple_auto_provision'
265
+ :auto_provision
266
+ else
267
+ super
268
+ end
269
+ end
270
+
271
+ def find_by_name(*includes)
272
+ not_found and return false if (id = params[:id]).blank?
273
+ id.downcase!
274
+ @host = includes.empty? ? resource_base.find_by_id(id) : resource_base.includes(includes).find_by_id(id)
275
+ @host ||= includes.empty? ? resource_base.find_by_name(id) : resource_base.includes(includes).find_by_name(id)
276
+ not_found and return(false) unless @host
277
+ @host
278
+ end
279
+
280
+ def check_for_subnet
281
+ hosts_without_subnet = []
282
+ case params[:action]
283
+ when 'reboot', 'auto_provision'
284
+ if @host.subnet.nil?
285
+ process_warning :warning_msg => _("Discovered host reported from unknown subnet, communication will not be proxied.")
286
+ end
287
+ when 'submit_multiple_reboot', 'submit_multiple_auto_provision'
288
+ hosts_without_subnet = @hosts.limit(3).select { |host| host.subnet.nil? }.pluck(:name)
289
+ if hosts_without_subnet.present?
290
+ process_warning :warning_msg => _("Discovered hosts reported from unknown subnet are %s, communication will not be proxied.") % hosts_without_subnet.join(', ')
291
+ end
292
+ end
293
+ end
294
+
295
+ def find_by_name_incl_subnet
296
+ find_by_name({:interfaces => :subnet})
297
+ end
298
+
299
+ def find_multiple
300
+ # Lets search by name or id and make sure one of them exists first
301
+ if params[:host_names].present? or params[:host_ids].present?
302
+ @hosts = Host::Discovered.includes(:model, :fact_values, :interfaces, :location, :organization).where("id IN (?) or name IN (?)", params[:host_ids], params[:host_names] )
303
+ if @hosts.empty?
304
+ error _('No hosts were found with that id or name')
305
+ redirect_to(discovered_hosts_path) and return false
306
+ end
307
+ else
308
+ error _('No hosts selected')
309
+ redirect_to(discovered_hosts_path) and return false
310
+ end
311
+
312
+ return @hosts
313
+ rescue => e
314
+ error _("Something went wrong while selecting hosts - %s") % e
315
+ redirect_to discovered_hosts_path
316
+ end
317
+
318
+ def taxonomy_scope
319
+ if @host
320
+ @organization = @host.organization
321
+ @location = @host.location
322
+ end
323
+
324
+ @organization ||= Organization.current
325
+ @organization ||= Organization.my_organizations.first
326
+ @location ||= Location.current
327
+ @location ||= Location.my_locations.first
328
+ end
329
+
330
+ # particular actions will always raise N+1 queries
331
+ def skip_bullet
332
+ Bullet.enable = false if defined? Bullet
333
+ yield
334
+ ensure
335
+ Bullet.enable = true if defined? Bullet
336
+ end
337
+
338
+ <<<<<<< HEAD
339
+ def add_custom_facts
340
+ unless @host.primary_interface.subnet.nil?
341
+ discovery_subnet = "#{@host.primary_interface.subnet.name} (#{@host.primary_interface.subnet.network})"
342
+ assign_fact_to_category("discovery_subnet", discovery_subnet)
343
+ =======
344
+ def get_interfaces
345
+ @host.interfaces.each do |interface|
346
+ @interfaces << {:identifier => interface["identifier"], :type => interface["type"], :mac => interface["mac"], :ip => interface["ip"]? interface["ip"] : "N/A", :primary => interface["primary"], :provision => interface["provision"]}
347
+ >>>>>>> 58baad5 (Support subnet6 facts in FactToCategoryResolver)
348
+ end
349
+ end
350
+
351
+ def process_warning(hash = {})
352
+ warning hash[:warning_msg]
353
+ end
354
+ end
@@ -18,6 +18,7 @@ class Host::Discovered < ::Host::Base
18
18
  scoped_search :on => :created_at, :default_order => :desc, :only_explicit => true
19
19
  scoped_search :on => :last_report, :complete_value => true, :only_explicit => true
20
20
  scoped_search :relation => :primary_interface, :on => :ip, :complete_value => true
21
+ scoped_search :relation => :primary_interface, :on => :ip6, :complete_value => true
21
22
  scoped_search :relation => :primary_interface, :on => :mac, :complete_value => true
22
23
  scoped_search :relation => :model, :on => :name, :complete_value => true, :rename => :model, :only_explicit => true
23
24
  scoped_search :relation => :fact_values, :on => :value, :in_key => :fact_names, :on_key => :name, :rename => :facts, :complete_value => true, :only_explicit => true
@@ -33,7 +33,8 @@ module ForemanDiscovery
33
33
  identifier: interface["identifier"],
34
34
  type: interface["type"],
35
35
  mac: interface["mac"],
36
- ip: interface["ip"] || "N/A",
36
+ ip: interface["ip"],
37
+ ip6: interface["ip6"],
37
38
  primary: interface["primary"],
38
39
  provision: interface["provision"],
39
40
  }
@@ -50,10 +51,7 @@ module ForemanDiscovery
50
51
  assign_fact_to_category(key, value)
51
52
  end
52
53
 
53
- return if host.primary_interface.subnet.nil?
54
-
55
- discovery_subnet = "#{host.primary_interface.subnet.name} (#{host.primary_interface.subnet.network})"
56
- assign_fact_to_category("discovery_subnet", discovery_subnet)
54
+ subnets_facts(host.primary_interface)
57
55
  end
58
56
 
59
57
  def assign_fact_to_category(key, value)
@@ -74,6 +72,14 @@ module ForemanDiscovery
74
72
  end
75
73
  end
76
74
 
75
+ def subnets_facts(iface)
76
+ subnet4 = iface.subnet
77
+ subnet6 = iface.subnet6
78
+
79
+ assign_fact_to_category("discovery_subnet", "#{subnet4.name} (#{subnet4.network})") if subnet4
80
+ assign_fact_to_category("discovery_subnet6", "#{subnet6.name} (#{subnet6.network})") if subnet6
81
+ end
82
+
77
83
  def highlights
78
84
  /^(productname|memorysize|manufacturer|architecture|macaddress$|processorcount|physicalprocessorcount|discovery_subnet|discovery_boot|ipaddress$)/
79
85
  end
@@ -103,4 +109,3 @@ module ForemanDiscovery
103
109
  end
104
110
  end
105
111
  end
106
-
@@ -52,15 +52,18 @@ module ForemanDiscovery
52
52
 
53
53
  return if neighbors.nil?
54
54
 
55
- ip = primary.ip
55
+ ip = primary.ip
56
+ ip6 = primary.ip6
56
57
  mac = primary.mac
57
58
  name = primary.name
59
+
58
60
  primary.update(
59
61
  :primary => false,
60
62
  :provision => false,
61
63
  :managed => false,
62
64
  :name => nil,
63
- :ip => nil
65
+ :ip => nil,
66
+ :ip6 => nil
64
67
  )
65
68
 
66
69
  bond = Nic::Bond.create(
@@ -70,6 +73,7 @@ module ForemanDiscovery
70
73
  :provision => true,
71
74
  :name => name,
72
75
  :ip => ip,
76
+ :ip6 => ip6,
73
77
  :mac => mac,
74
78
  :host => host
75
79
  )
@@ -2,7 +2,8 @@ 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, :hardware_model_name, :memory, :disk_count, :disks_size
5
+ attributes :ip, :ip6, :mac, :last_report, :subnet_id,
6
+ :subnet_name, :hardware_model_name, :memory, :disk_count, :disks_size
6
7
  attribute :cpu_count => :cpus
7
8
 
8
9
  node :subnet_name do |host|
@@ -1,6 +1,7 @@
1
1
  <td class="ellipsis"><%= link_to (discovery_status_icon(host) + '&nbsp;'.html_safe + trunc_with_tooltip(h(host.name))), discovered_host_path(host) %></td>
2
2
  <td class="hidden-tablet hidden-xs"><%= host.try(:hardware_model_name) || 'N/A' %></td>
3
3
  <td class="hidden-tablet hidden-xs"><%= host.ip %></td>
4
+ <td class="hidden-tablet hidden-xs"><%= host.ip6 %></td>
4
5
  <td class="hidden-tablet hidden-xs"><%= discovery_attribute(host, :cpu_count) %></td>
5
6
  <td class="hidden-tablet hidden-xs"><%= number_to_human_size(discovery_attribute(host, :memory, 0) * 1024 * 1024) %></td>
6
7
  <td class="hidden-tablet hidden-xs"><%= discovery_attribute(host, :disk_count) %></td>
@@ -5,7 +5,8 @@
5
5
  <th class="ca"><%= check_box_tag "check_all", "", false, { :onclick => "tfm.hosts.table.toggleCheck()", :'check-title' => _("Select all items in this page"), :'uncheck-title'=> _("items selected. Uncheck to Clear") } %></th>
6
6
  <th class=''><%= sort :name, :as => _('Name') %></th>
7
7
  <th class="hidden-tablet hidden-xs"><%= sort :model, :as => _('Model') %></th>
8
- <th class="hidden-tablet hidden-xs"><%= sort :ip, :as => _('IP Address') %></th>
8
+ <th class="hidden-tablet hidden-xs"><%= sort :ip, :as => _('IPv4') %></th>
9
+ <th class="hidden-tablet hidden-xs"><%= sort :ip6, :as => _('IPv6') %></th>
9
10
  <th class="hidden-tablet hidden-xs"><%= sort :cpu_count, :as => _('CPUs') %></th>
10
11
  <th class="hidden-tablet hidden-xs"><%= sort :memory, :as => _('Memory') %></th>
11
12
  <th class="hidden-tablet hidden-xs"><%= sort :disk_count, :as => _('Disk Count') %></th>
@@ -44,7 +44,8 @@
44
44
  <th class="hidden-xs " width="12%"><%= _('Type') %></th>
45
45
  <th class="hidden-xs "><%= _('Identifier') %></th>
46
46
  <th class="hidden-xs "><%= _("MAC address") %></th>
47
- <th class="hidden-xs "><%= _("IP address") %></th>
47
+ <th class="hidden-xs "><%= _("IPv4") %></th>
48
+ <th class="hidden-xs "><%= _("IPv6") %></th>
48
49
  </tr>
49
50
  <% @interfaces.each do |interface| %>
50
51
  <tr>
@@ -52,6 +53,7 @@
52
53
  <td class="ellipsis"><%= interface[:identifier] %></td>
53
54
  <td class="ellipsis"><%= interface[:mac] %></td>
54
55
  <td class="ellipsis"><%= interface[:ip] %></td>
56
+ <td class="ellipsis"><%= interface[:ip6] %></td>
55
57
  </tr>
56
58
  <% end %>
57
59
  </table>
@@ -3,7 +3,12 @@
3
3
  <%= link_to host, discovered_host_url(:id => host, :host => @url.host, :port => @url.port, :only_path => false, :protocol => @url.scheme) %>
4
4
  </td>
5
5
  <td style="<%= td_style%>"><%= host.try(:hardware_model_name) || 'N/A' %></td>
6
+ <% if host.ip %>
6
7
  <td style="<%= td_style%>"><%= host.ip %></td>
8
+ <% end %>
9
+ <% if host.ip6 %>
10
+ <td style="<%= td_style%>"><%= host.ip6 %></td>
11
+ <% end %>
7
12
  <td style="<%= td_style%>"><%= discovery_attribute(host, :cpu_count) %></td>
8
13
  <td style="<%= td_style%>"><%= number_to_human_size(discovery_attribute(host, :memory, 0) * 1024 * 1024) %></td>
9
14
  <td style="<%= td_style%>"><%= discovery_attribute(host, :disk_count) %></td>
@@ -1,3 +1,3 @@
1
1
  module ForemanDiscovery
2
- VERSION = "25.0.1"
2
+ VERSION = "25.1.0"
3
3
  end
@@ -44,7 +44,9 @@
44
44
  "timezone": "GMT",
45
45
  "fqdn": "a.server.b.domain",
46
46
  "ipaddress_eth0": "10.35.27.3",
47
+ "ipaddress6_eth0": "2001:db8:9a7b:fb60::3",
47
48
  "ipaddress_eth1": "10.35.27.4",
49
+ "ipaddress6_eth1": "2001:db8:9a7b:fb60::4",
48
50
  "puppetversion": "2.6.12",
49
51
  "path": "/root/.gem/bin:/root/.gem/ruby/1.8/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/sbin:/usr/sbin:/root/scripts",
50
52
  "hardwaremodel": "x86_64",
@@ -58,11 +60,14 @@
58
60
  "macaddress_eth0_182": "E4:1F:13:CC:36:58",
59
61
  "memorysize": "15.57 GB",
60
62
  "ipaddress": "10.35.27.2",
63
+ "ipaddress6": "2001:db8:5f42:7cd1::2",
61
64
  "rubyversion": "1.8.7",
62
65
  "macaddress_eth0_183": "E4:1F:13:CC:36:58",
63
66
  "physicalprocessorcount": "1",
64
67
  "network_lo": "127.0.0.0",
68
+ "network6_lo": "::1",
65
69
  "gateway": "10.35.27.62",
70
+ "gateway6": "2001:db8:2c7d:f15e::3e",
66
71
  "lsbdistid": "RedHatEnterpriseServer",
67
72
  "lsbdistdescription": "Red Hat Enterprise Linux Server release 6.2 (Santiago)",
68
73
  "swapsize": "17.70 GB",
@@ -90,11 +95,13 @@
90
95
  "lldp_neighbor_portID_eth1": "Eth170/1/3",
91
96
  "lldp_neighbor_sysName_eth1": "DC2-A03-DR-01",
92
97
  "lldp_neighbor_mngAddr_ipv4_eth1": "192.0.2.13",
98
+ "lldp_neighbor_mngAddr_ipv6_eth1": "2001:db8:4d2b:dc7b::13",
93
99
  "lldp_neighbor_PVID_eth1": "182",
94
100
  "lldp_neighbor_chassisID_eth0": "e0:d1:73:38:5a:84",
95
101
  "lldp_neighbor_portID_eth0": "Eth171/1/3",
96
102
  "lldp_neighbor_sysName_eth0": "DC2-A04-DR-03",
97
103
  "lldp_neighbor_mngAddr_ipv4_eth0": "192.0.2.13",
104
+ "lldp_neighbor_mngAddr_ipv6_eth0": "2001:db8:4d2b:dc7b::13",
98
105
  "lldp_neighbor_PVID_eth0": "182"
99
106
  }
100
107
  }
@@ -25,6 +25,12 @@ class Api::V2::DiscoveredHostsControllerTest < ActionController::TestCase
25
25
  "memorysize_mb" => "42000.42",
26
26
  "discovery_version" => "3.0.0",
27
27
  }
28
+
29
+ @facts6 = @facts.merge({
30
+ "ipaddress" => "2001:db8::1",
31
+ "ipaddress6_eth0" => "2001:db8::1",
32
+ })
33
+
28
34
  set_default_settings
29
35
  ::ForemanDiscovery::NodeAPI::PowerService.any_instance.stubs(:reboot).returns(true)
30
36
  ::ForemanDiscovery::HostConverter.stubs(:unused_ip_for_host)
@@ -52,6 +58,16 @@ class Api::V2::DiscoveredHostsControllerTest < ActionController::TestCase
52
58
  assert_equal Setting[:discovery_location], show_response["location_name"]
53
59
  end
54
60
 
61
+ def test_show_host_ipv6
62
+ host = discover_host_from_facts(@facts6)
63
+ get :show, params: { :id => host.id }
64
+ assert_response :success
65
+
66
+ response = ActiveSupport::JSON.decode(@response.body)
67
+ assert_equal "macaabbccddeeff", response["name"]
68
+ assert_equal @facts6["ipaddress6_eth0"], response["ip6"]
69
+ end
70
+
55
71
  def test_delete_discovered_host
56
72
  host = discover_host_from_facts(@facts)
57
73
  delete :destroy, params: { :id => host.id }
@@ -91,6 +107,25 @@ class Api::V2::DiscoveredHostsControllerTest < ActionController::TestCase
91
107
  assert actual.build?
92
108
  end
93
109
 
110
+ def test_provision_ipv6_host
111
+ subnet6 = FactoryBot.create(:subnet_ipv6, :network => "2001:db8::")
112
+ host = discover_host_from_facts(@facts6)
113
+ hostgroup = setup_hostgroup(host, subnets: { subnet6: subnet6 })
114
+
115
+ put :update, params: {
116
+ id: host.id,
117
+ discovered_host: {
118
+ hostgroup_id: hostgroup.id,
119
+ build: true
120
+ }
121
+ }
122
+
123
+ assert_response :success
124
+ actual = Host.unscoped.find(host.id)
125
+ assert actual.build?
126
+ assert_equal actual.ip6, @facts6["ipaddress6_eth0"]
127
+ end
128
+
94
129
  def test_provision_host_without_build_flag
95
130
  FactoryBot.create(:organization, :name => 'SomeOrg')
96
131
  FactoryBot.create(:location, :name => 'SomeLoc')
@@ -70,9 +70,11 @@ def set_default_settings
70
70
  Setting['discovery_auto_bond'] = false
71
71
  end
72
72
 
73
- def setup_hostgroup(host)
73
+ def setup_hostgroup(host, subnets: nil)
74
74
  domain = FactoryBot.create(:domain)
75
- subnet = FactoryBot.create(:subnet_ipv4, :network => "192.168.100.0")
75
+ subnets ||= {
76
+ subnet: FactoryBot.create(:subnet_ipv4, :network => "192.168.100.0")
77
+ }
76
78
  medium = FactoryBot.create(:medium, :organizations => [host.organization], :locations => [host.location])
77
79
  os = FactoryBot.create(:operatingsystem, :with_ptables, :with_archs, :media => [medium])
78
80
  args = {
@@ -80,11 +82,11 @@ def setup_hostgroup(host)
80
82
  :architecture => os.architectures.first,
81
83
  :ptable => os.ptables.first,
82
84
  :medium => os.media.first,
83
- :subnet => subnet,
84
85
  :domain => domain,
85
86
  :organizations => [host.organization],
86
87
  :locations => [host.location]
87
- }
88
+ }.merge(subnets)
89
+
88
90
  if defined?(ForemanPuppet)
89
91
  environment = FactoryBot.create(:environment, :organizations => [host.organization], :locations => [host.location])
90
92
  args[:environment] = environment
@@ -92,15 +94,26 @@ def setup_hostgroup(host)
92
94
  else
93
95
  hostgroup = FactoryBot.create(:hostgroup, :with_rootpass, **args)
94
96
  end
95
- domain.subnets << hostgroup.subnet
97
+
98
+ hostgroup_subnets = [hostgroup.subnet6, hostgroup.subnet].compact
99
+ domain.subnets << hostgroup_subnets
100
+
101
+ hostgroup_taxonomies(hostgroup, hostgroup_subnets, host)
102
+ end
103
+
104
+ def hostgroup_taxonomies(hostgroup, hostgroup_subnets, host)
96
105
  hostgroup.medium.organizations |= [host.organization]
97
106
  hostgroup.medium.locations |= [host.location]
98
107
  hostgroup.ptable.organizations |= [host.organization]
99
108
  hostgroup.ptable.locations |= [host.location]
100
109
  hostgroup.domain.organizations |= [host.organization]
101
110
  hostgroup.domain.locations |= [host.location]
102
- hostgroup.subnet.organizations |= [host.organization]
103
- hostgroup.subnet.locations |= [host.location]
111
+
112
+ hostgroup_subnets.each do |subnet|
113
+ subnet.organizations |= [host.organization]
114
+ subnet.locations |= [host.location]
115
+ end
116
+
104
117
  if defined?(ForemanPuppet)
105
118
  hostgroup.environment.organizations |= [host.organization]
106
119
  hostgroup.environment.locations |= [host.location]
@@ -109,6 +122,7 @@ def setup_hostgroup(host)
109
122
  hostgroup.puppet_ca_proxy.organizations |= [host.organization]
110
123
  hostgroup.puppet_ca_proxy.locations |= [host.location]
111
124
  end
125
+
112
126
  hostgroup
113
127
  end
114
128
 
@@ -1,6 +1,9 @@
1
1
  require_relative '../test_plugin_helper'
2
2
 
3
3
  class LldpNeighborsTest < ActiveSupport::TestCase
4
+ include FactImporterIsolation
5
+ allow_transactions_for_any_importer
6
+
4
7
  test "#get_neighbors_by_interface gives nothing with no LLDP facts" do
5
8
  assert_nil simple_facts.get_neighbors_by_interface('eth0')
6
9
  end
@@ -32,6 +35,37 @@ class LldpNeighborsTest < ActiveSupport::TestCase
32
35
  assert_equal({'182' => %w(eth2), '184' => %w(eth1)}, lldp_facts.list_by_pvid)
33
36
  end
34
37
 
38
+ test "#eventually_make_bond" do
39
+ facts = parse_json_fixture('facts_with_lldp_bond_candidate', true)
40
+ host = discover_host_from_facts(facts)
41
+ primary = host.primary_interface
42
+
43
+ assert_equal 0, host.interfaces.where(:type => 'Nic::Bond').count
44
+
45
+ assert primary.primary
46
+ assert primary.provision
47
+ assert primary.ip
48
+ assert primary.ip6
49
+
50
+ ForemanDiscovery::LldpNeighbors.eventually_make_bond(host)
51
+
52
+ bond = host.primary_interface
53
+
54
+ assert_nil primary.ip
55
+ assert_nil primary.ip6
56
+ assert_nil primary.name
57
+ assert_not primary.primary
58
+ assert_not primary.provision
59
+ assert_not primary.managed
60
+
61
+ assert bond.primary
62
+ assert bond.provision
63
+ assert bond.ip
64
+ assert bond.ip6
65
+ assert_equal bond.type, 'Nic::Bond'
66
+ assert_equal bond.identifier, 'bond0'
67
+ end
68
+
35
69
  private
36
70
 
37
71
  def simple_facts
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_discovery
3
3
  version: !ruby/object:Gem::Version
4
- version: 25.0.1
4
+ version: 25.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aditi Puntambekar
@@ -76,7 +76,7 @@ authors:
76
76
  autorequire:
77
77
  bindir: bin
78
78
  cert_chain: []
79
- date: 2024-12-11 00:00:00.000000000 Z
79
+ date: 2025-01-27 00:00:00.000000000 Z
80
80
  dependencies: []
81
81
  description: MaaS Discovery Plugin engine for Foreman
82
82
  email: gsutclif@redhat.com
@@ -112,6 +112,7 @@ files:
112
112
  - app/controllers/concerns/foreman/controller/parameters/discovered_host.rb
113
113
  - app/controllers/concerns/foreman/controller/parameters/discovery_rule.rb
114
114
  - app/controllers/discovered_hosts_controller.rb
115
+ - app/controllers/discovered_hosts_controller.rb.orig
115
116
  - app/controllers/discovery_rules_controller.rb
116
117
  - app/controllers/foreman_discovery/concerns/hosts_controller_extensions.rb
117
118
  - app/helpers/discovered_hosts_helper.rb