Intro
Historically Foreman treated itself, Smart Proxies and Hosts as completely unrelated objects, even though you usually have Foreman and Smart Proxy machines registered as Hosts in Foreman. So far we managed without knowing the relationship between Host, Smart Proxies and Foreman, but lately use cases, which would be rather hard to implement without this link, started popping up. Most of the use cases originate in remote execution, but I’m sure that once we establish this, it will find its use in other places as well.
Use cases
Because Foreman treated itself and Smart Proxies the same way as any other Host, it was possible to run remote execution jobs against Foreman itself or against its Smart Proxies. What however wasn’t really possible, was requiring a special permission for doing so. The users could add a special permission by hand, however they had to keep the permission’s filters in sync with their Hosts and Smart Proxies.
In Satellite land we have two ansible playbooks which are meant to be run against the Satellite infrastructure itself. One sets up the cloud.redhat.com connector and is meant to be run against Foreman, the other is meant to run against Smart Proxies and upgrades them. Again, because Foreman doesn’t know the relationships, we cannot offer only relevant hosts when triggering these jobs and keeping track of what host does what is left to the user.
Even in Foreman land, we could think of many places where this would make our life easier. E.g. we could have a job to install a plugin, perform a backup, clean up ArfReport storage on OpenSCAP enabled smart proxies and so on.
Proposal
To address this, I propose we establish a link between Host and Smart Proxy object. Because only a small number of the Hosts will actually be linked to Smart Proxies, this relationship will be tracked by a InfrastructureFacet
, which will be created on demand. The association between Host, InfrastructureFacet
and SmartProxy
would be as follows:
Host 1 -- 0..1 InfrastructureFacet 0..1 -- 0..1 SmartProxy
Since there is no Foreman object, there will be a field in the facet, marking the Host as Foreman. This will allow us to have permissions based on whether a Host is Foreman and/or Smart Proxy and filter Hosts by the same criteria.
Implementation details
To be able to link Hosts against other objects reliably, we need to have a piece of information that will be available on both sides, so we can use it as a key. On the Foreman side, we already have instance_id
and as part of my POC I introduced the same instance identificator to Smart Proxy as well.
Deployment
When you run the installer to install Foreman, it will generate a new UUID, store it in the database and then create a custom fact out of it. This way we will be able to compare the UUID from Host’s facts against the actual instance_id
. I can imagine three cases there:
- There is no fact and therefore the Host is not a Foreman.
- There is a fact and it matches Foreman’s
instance_id
, meaning the Host is this Foreman - There is a fact, but it differs from Foreman’s
instance_id
, meaning the Host is a different Foreman instance.
For Smart Proxy the process is similar. Installer generates an UUID, puts it into Smart Proxy’s settings.yml
, creates a custom fact out of it and also sends it over to Foreman when registering the Smart Proxy. Smart Proxy’s instance_id
will also be available through the /versions
API, so that clicking Refresh
in Smart Proxy details updates its instance_id
.
Each time Foreman receives facts, it will look for the custom facts, creating or editing InfrastructureFacet
accordingly.
In situations where we’re not installing a new Foreman instance, the way how we’d deploy this stays the same for Smart Proxy, but is slightly different for Foreman. Foreman already does have its instance_id
, but it is generated when Foreman first starts and then kept in the database. To be able to perform this flow, we will need to get the value out of the database so the installer can work with it, more details in Add 1.
Edge cases
Of course, this proposal is not perfect and does not address every single possible eventuality under the sun, such as:
- multiple Smart Proxies with different
instance_ids
on a single Host - multiple Hosts reporting the same Smart Proxy instance id, although this could be partially addressed by one-to-many association between
SmartProxy
andInfrastructureFacet
- multiple Hosts reporting different Smart Proxy id, but being behind a load balancer. If the users put Smart Proxies behind a load balancer, then they should make sure all the hosts report the same, which reduces this issue to the previous one
POC PRs
- theforeman/foreman#8254
- theforeman/smart-proxy#783
- theforeman/puppet-foreman#914
- theforeman/puppet-foreman_proxy
- theforeman/foreman_remote_execution#560
Add 1 - Upgrade considerations
I can see three paths we could take here, but I wouldn’t call any of them nice.
- Don’t do anything special and behave the same way as if a clean installation was being done. This would result in Foreman’s instance_id getting changed, which may not be an issue for some users, but it would break things for users using find-it-fix-it from cloud.redhat.com as it relies on the instance_id.
- Adding a note to the release notes, saying that if a user needs to keep the same instance_id, they should retrieve it manually and then pass it as an argument to the installer.
- An installer migration/hook, which would essentially 2) behind the scenes.