Changing a host's primary NIC

Is it safe to move IP/Mac/Hostname information from one NIC to another,
directly from the database? For example, if I have an eth0 and bond0
configured on a host, and both either share the same IP/Mac/name, or one or
the other is unconfigured, should it be safe to directly update the
IP/Mac/Name to move it to the bond0 interface, via SQL commands? I'm
thinking SQL that would look like this, executed from within a script:

With eth0 set as primary, with IP 10.0.0.1, Mac: 00:00:00:00:00:01,

Hostname: myhostname.fqdn, move the config as follows:

Configure bond0 to be primary interface

update nics set ip=10.0.0.1, mac=00:00:00:00:00:01, name=myhostname.fqdn,
primary=1, provision=1, managed=1 where host_id=<host_id> and
identifier="bond0"

Unconfigure eth0

update nics set ip=NULL, mac=NULL, name=NULL, primary=0, provision=0,
managed=0 where host_id=<host_id> and identifier="eth0"

This is my situation…

I'm setting up Foreman (1.9.3) to handle hardware provisioning within our
environment. I'd like to be able to set the primary interface as "bond0"
for most hosts, with IP and host name configured on bond0. We have been
using Foreman for quite awhile, but not for provisioning, so we have
existing host records with NIC information that doesn't reflect how we want
them to be provisioned. Most of our primary interfaces have been
configured as "eth0". This requires me to move the IP/MAC/hostname from
eth0 to a newly created (or previously existing with duplicated
information) bond0.

Unfortunately, due to the way that Foreman is handling validation, I can't
just move the IP information over from witihn the UI. I get a conflict
that won't let me save (as an aside, I've attempted to patch the changes
from Bug #11034: network/interfaces validation checks the removed interfaces - Foreman, which doesn't change
this). The API (via hammer) doesn't seem to give me a simple way to do it
either. I can't update the new interface prior to removing the old one,
and I don't want to remove the old one, for fear of triggering DNS
deletions from our Smart Proxy (I need to script this to run against
thousands of production hosts, so our operators don't run into a problem
each time they try to provision a host… I don't want DNS to be
deleted/re-added each time I update a host).

My workaround for the time being is to disable the
"ignore_puppet_facts_for_provisioning" setting (currently enabled), to
temporarily bring in all interfaces from the host. I would follow that by
re-enabling the setting to prevent further updates, and then run a script
to cleanup duplicates and ensure the IP is on the right interface (bond0),
by directly modifying the nics table.

Does this sound like a reasonable approach? I'm mostly asking to give
myself confidence that it's not insane, and to make sure I'm not missing
something terribly obvious that could cause future problems in my
environment. I want our operators to be able to modify the NIC
configuration of a host from within the UI, and it doesn't seem doable
right now with how Foreman is handling validation in the UI.

Yeah, bond handling is something we need to revisit. There's a number of
subtle issues that make it tricky to handle correctly, which is why we
don't allow duplicate IPs and so forth at the moment. Feedback on how you'd
like to see it fixed would be great on #13024
<Bug #13024: Bond0 and eth0 share IP causing duplicate IP conflict when bond0 is created after kickstart and subsequently imported - Foreman> - there's also debate there
about some of other issues around uniqueness and so on. We need a clear
design before we can fix it.

For now, you might be able to do what you want from the Rails console,
which would have the advantage of going through the code paths and updating
dependant information. You should be able to execute something similar to
your SQL - maybe host=Host.find('fqdn') ; host.nics.where(:name =>
'bond0').primary=true ; …

The downside is that I've not actually tested that approach - I have no
bonded hosts at the moment. If that doesn't work, you could try the SQL
route (it looks ok at first glance), but I'd suggest careful testing in a
sandboxed Foreman with a copy of the db first.