Duplicated entries in discovered hosts when the host PXE with a different NIC

Problem: Duplicated entries in discovered hosts when the host PXE’ed with a different NIC.

We updated settings discovery_hostname and discovery_prefix to have host name in the way of serial-######, this works like a charm.

However, when the host boot with a different NIC, a duplicated entry is created in the discovered hosts list.

Looking at the logs we can see that when the host boots with a different NIC, Foreman attempts to create a new host entry and failed because the name is already in use (full trace at the bottom). Besides the error, we can see a duplicated entry in the UI’s discovered hosts list.

error (ActiveRecord::RecordInvalid): Validation failed: Name has already been taken

Ruby is not one of my skills. But looking at the code of discovered.rb line 90, it seems bootif_mac is used to determine if the host exists or not, but then hostname is used to actually create that host.

Is it possible to use hostname to validate if the hosts exists or not?
If not, do you think further validations can be added to check all hosts’s interfaces instead of just bootif_mac?

Expected outcome: Foreman should realize is the same host booting with a different NIC and not create a duplicated entry.

Foreman and Proxy versions: 3.7.0

Foreman and Proxy plugin versions: Proxy 3.7.0, Discovery 22.0.4

Distribution and version: Rocky Linux 8.8

Other relevant data:

Traceback:

"_type"=>:foreman_discovery}' error (ActiveRecord::RecordInvalid): Validation failed: Name has already been taken
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/validations.rb:80:in `raise_validation_error'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/validations.rb:53:in `save!'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/transactions.rb:302:in `block in save!'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `block in transaction'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `transaction'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/transactions.rb:350:in `with_transaction_returning_status'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/transactions.rb:302:in `save!'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/suppressor.rb:48:in `save!'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/models/host/discovered.rb:135:in `populate_discovery_fields_from_facts'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/models/host/discovered.rb:127:in `populate_fields_from_facts'
 9b49284c | /usr/share/foreman/app/services/host_fact_importer.rb:50:in `block (2 levels) in parse_facts'
 9b49284c | /usr/share/foreman/app/services/foreman/telemetry_helper.rb:28:in `telemetry_duration_histogram'
 9b49284c | /usr/share/foreman/app/services/host_fact_importer.rb:49:in `block in parse_facts'
 9b49284c | /usr/share/foreman/app/services/host_fact_importer.rb:93:in `skipping_orchestration'
 9b49284c | /usr/share/foreman/app/services/host_fact_importer.rb:45:in `parse_facts'
 9b49284c | /usr/share/foreman/app/services/host_fact_importer.rb:34:in `import_facts'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/services/foreman_discovery/host_fact_importer.rb:8:in `import_facts'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/models/host/discovered.rb:103:in `import_host'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/controllers/api/v2/discovered_hosts_controller.rb:110:in `block in facts'
 9b49284c | /usr/share/foreman/app/models/concerns/foreman/thread_session.rb:108:in `as'
 9b49284c | /usr/share/foreman/app/models/concerns/foreman/thread_session.rb:114:in `as_anonymous_admin'
 9b49284c | /usr/share/gems/gems/foreman_discovery-22.0.4/app/controllers/api/v2/discovered_hosts_controller.rb:109:in `facts'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/abstract_controller/base.rb:228:in `process_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/rendering.rb:30:in `process_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
 9b49284c | /usr/share/foreman/app/controllers/concerns/foreman/controller/timezone.rb:10:in `set_timezone'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
 9b49284c | /usr/share/foreman/app/models/concerns/foreman/thread_session.rb:32:in `clear_thread'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
 9b49284c | /usr/share/foreman/app/controllers/concerns/foreman/controller/topbar_sweeper.rb:12:in `set_topbar_sweeper_controller'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
 9b49284c | /usr/share/gems/gems/audited-5.3.3/lib/audited/sweeper.rb:16:in `around'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
 9b49284c | /usr/share/gems/gems/audited-5.3.3/lib/audited/sweeper.rb:16:in `around'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/callbacks.rb:137:in `run_callbacks'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/abstract_controller/callbacks.rb:41:in `process_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/rescue.rb:22:in `process_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/notifications.rb:203:in `block in instrument'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
 9b49284c | /usr/share/gems/gems/activesupport-6.1.7.3/lib/active_support/notifications.rb:203:in `instrument'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/instrumentation.rb:33:in `process_action'
 9b49284c | /usr/share/gems/gems/actionpack-6.1.7.3/lib/action_controller/metal/params_wrapper.rb:249:in `process_action'
 9b49284c | /usr/share/gems/gems/activerecord-6.1.7.3/lib/active_record/railties/controller_runtime.rb:27:in `process_action'

Thanks for your support : )