Foreman and Smart Proxy API communication

Hi There,

I’m starting development on the phpIPAM plugin integration, and I’m trying to understand the mechanism that Foreman is using to communicate with the Smart Proxy API. DHCP For example, uses the dhcp_proxy below.

# /app/models/subnet.rb
...
def dhcp?
  supports_ipam_mode?(:dhcp) && dhcp && dhcp.url.present?
end

def dhcp_proxy(attrs = {})
  @dhcp_proxy ||= ProxyAPI::DHCP.new({:url => dhcp.url}.merge(attrs)) if dhcp?
end
...

Where is dhcp.url defined? Is this injected from the DHCP smart proxy plugin itself, or is it defined somewhere else?

Any help or guidance would be appreciated.

Thanks,

Chris

Hey,

welcome to Rails, conventions are sometimes very fuzzy and actually unreadable. The dhcp is an associated Feature model class.

Thanks @lzap. So for a new plugin(i.e. foreman_phpipam), we should have an associated Feature model class for this as well I’m assuming? Where should this class reside? In the smart proxy plugin, then loaded into the smart proxy itself with load_classes? Just trying to understand how everything communicates with one another.

Let me assume that phpIPAM can actually manage DHCP and DNS server for a moment. Then you need to write two smart-proxy plugins which will be implementations of DHCP and DNS modules. The API for DHCP and DNS is simple - create, delete entry, also there are few query commands for DHCP API like list of subnets, reservations and leases and give me next free IP. Foreman talks to Smart Proxy to do these actions, when creating a new host Foreman asks the DHCP module to provide the next available IP address and performs a “lock” on it so concurrect requests take a different one.

There is no need of creating a new feature in Foreman if this is enough for you to implement stuff. Foreman core has a concept of IPAM providers in the Rails codebase and there are few implementations: DHCP (which uses what I have just described), None (manual), DB and RandomDB. They both use a database table to perform very simplistic IPAM.

Here is how it would look like:

However if phpIPAM does not perform actual creation of records, then you want probably Foreman to create those records and in that case only implement new IPAM class in Foreman Rails codebase. The interface is very simple as you can see:

An IPAM class takes Subnet model and provides suggest_ip method which lookups an IP. Make sure to “lock” IPs so concurrent request will not have race condition issues. Unfortunately, IPAMs are not pluggable meaning that there is no plugin API to provide those from plugins. Also they are not configurable as well.

In this case, you have few options. Provide a patch into Foreman core adding new IPAM provider and use our Settings mechanism to provide configuration of URL, credentials etc. However we are trying to actually decrease amount of configuration settings long-term because we have too many.

Or you can make the IPAM pluggable and then write new Foreman plugin providing the new implementation. Then you can choose how you want to provide the configuration.

1 Like

Thank you @lzap - This level of detail helps a lot.

After reading this and looking at the code a little more, things are starting to become more clear. I will be able to move forward with this.

I will likely go the patch route in adding new IPAM provider with Settings mechanism etc. Making the IPAM pluggable makes more sense, however I would have to look into that at a later date once I have more time, and am more familiar with the code base and release process etc.

Out of my curiousity as I was not able to quickly read it from its homepage - does phpIPAM manage records or is it just inventory?

If you want to work on plugin mechanism I can help you with that - should not be that hard. All you need to do is to expose list of IPAM providers, currently it’s just a constant.

Hello @lzap,

Sorry for the delayed response. I have pushed the new foreman and smart proxy plugins to Github, and also new branches for Foreman and Smart Proxy patches. This is really only for review at this point.

More detail is in this thread

Thanks,

Chris