-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #34205 - External IPAM Integration
- Loading branch information
Christopher Smith
committed
Jan 3, 2022
1 parent
d60623c
commit de613b4
Showing
23 changed files
with
1,498 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ Ashley Penney <[email protected]> | |
Baptiste Agasse <[email protected]> | ||
Brandon Weeks <[email protected]> | ||
Christian Arnold <[email protected]> | ||
Christopher Smith <[email protected]> | ||
Corey Osman <[email protected]> | ||
Daniel Baeurer <[email protected]> | ||
Daniel Helgenberger <[email protected]> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
:enabled: false | ||
|
||
# Supported providers: | ||
# 1. phpIPAM: externalipam_phpipam | ||
# 2. Netbox: externalipam_netbox | ||
|
||
:use_provider: externalipam_netbox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--- | ||
:url: 'http://my-netbox-url.com' | ||
:token: 'netbox_token' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
:url: 'http://my-phpipam-url.com' | ||
:user: 'ipam_user' | ||
:password: 'ipam_password' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
require 'yaml' | ||
require 'json' | ||
require 'net/http' | ||
require 'uri' | ||
require 'externalipam/ipam_helper' | ||
|
||
module Proxy::Ipam | ||
# Class to handle authentication and HTTP transactions with External IPAM providers | ||
class ApiResource | ||
include ::Proxy::Log | ||
include Proxy::Ipam::IpamHelper | ||
|
||
def initialize(params = {}) | ||
@api_base = params[:api_base] | ||
@token = params[:token] | ||
@auth_header = params[:auth_header] || 'Authorization' | ||
end | ||
|
||
def get(path) | ||
uri = URI(@api_base + path) | ||
request = Net::HTTP::Get.new(uri) | ||
request[@auth_header] = @token | ||
request['Accept'] = 'application/json' | ||
|
||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| | ||
http.request(request) | ||
end | ||
end | ||
|
||
def delete(path) | ||
uri = URI(@api_base + path) | ||
request = Net::HTTP::Delete.new(uri) | ||
request[@auth_header] = @token | ||
request['Accept'] = 'application/json' | ||
|
||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| | ||
http.request(request) | ||
end | ||
end | ||
|
||
def post(path, body = nil) | ||
uri = URI(@api_base + path) | ||
request = Net::HTTP::Post.new(uri) | ||
request.body = body | ||
request[@auth_header] = @token | ||
request['Accept'] = 'application/json' | ||
request['Content-Type'] = 'application/json' | ||
|
||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| | ||
http.request(request) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module ::Proxy::Ipam | ||
class ConfigurationLoader | ||
def load_classes | ||
require 'externalipam/dependency_injection' | ||
require 'externalipam/ipam_api' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module Proxy::Ipam | ||
module DependencyInjection | ||
include Proxy::DependencyInjection::Accessors | ||
def container_instance | ||
@container_instance ||= ::Proxy::Plugins.instance.find { |p| p[:name] == :externalipam }[:di_container] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
require 'externalipam/externalipam_plugin' | ||
require 'externalipam/configuration_loader' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
require 'externalipam/phpipam/phpipam_plugin' | ||
require 'externalipam/netbox/netbox_plugin' | ||
|
||
module Proxy::Ipam | ||
class Plugin < ::Proxy::Plugin | ||
plugin :externalipam, ::Proxy::VERSION | ||
uses_provider | ||
default_settings use_provider: 'externalipam_phpipam' | ||
rackup_path File.expand_path('http_config.ru', __dir__) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
require 'externalipam/ipam_api' | ||
|
||
map '/ipam' do | ||
run Proxy::Ipam::Api | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
require 'yaml' | ||
require 'json' | ||
require 'monitor' | ||
require 'concurrent' | ||
require 'time' | ||
require 'externalipam/ipam_helper' | ||
require 'singleton' | ||
|
||
module Proxy::Ipam | ||
# Class for managing temp in-memory cache to prevent same IP's being suggested in race conditions | ||
class IpCache | ||
include Singleton | ||
include Proxy::Log | ||
include Proxy::Ipam::IpamHelper | ||
|
||
DEFAULT_CLEANUP_INTERVAL = 60 | ||
|
||
def initialize | ||
@m = Monitor.new | ||
init_cache | ||
start_cleanup_task | ||
end | ||
|
||
def provider_name(provider) | ||
@provider = provider | ||
end | ||
|
||
def set_group(group, value) | ||
@ip_cache[group.to_sym] = value | ||
end | ||
|
||
def get_group(group) | ||
@ip_cache[group.to_sym] | ||
end | ||
|
||
def get_cidr(group, cidr) | ||
@ip_cache[group.to_sym][cidr.to_sym] | ||
end | ||
|
||
def get_ip(group_name, cidr, mac) | ||
@ip_cache[group_name.to_sym][cidr.to_sym][mac.to_sym][:ip] | ||
end | ||
|
||
def cleanup_interval | ||
DEFAULT_CLEANUP_INTERVAL | ||
end | ||
|
||
def ip_exists(ip, cidr, group_name) | ||
cidr_key = @ip_cache[group_name.to_sym][cidr.to_sym]&.to_s | ||
cidr_key.include?(ip.to_s) | ||
end | ||
|
||
def add(ip, mac, cidr, group_name) | ||
logger.debug("Adding IP '#{ip}' to cache for subnet '#{cidr}' in group '#{group_name}' for IPAM provider #{@provider}") | ||
@m.synchronize do | ||
mac_addr = mac.nil? || mac.empty? ? SecureRandom.uuid : mac | ||
group_hash = @ip_cache[group_name.to_sym] | ||
|
||
group_hash.each do |key, values| | ||
if values.key? mac_addr.to_sym | ||
@ip_cache[group_name.to_sym][key].delete(mac_addr.to_sym) | ||
end | ||
@ip_cache[group_name.to_sym].delete(key) if @ip_cache[group_name.to_sym][key].nil? || @ip_cache[group_name.to_sym][key].empty? | ||
end | ||
|
||
if group_hash.key?(cidr.to_sym) | ||
@ip_cache[group_name.to_sym][cidr.to_sym][mac_addr.to_sym] = {ip: ip.to_s, timestamp: Time.now.to_s} | ||
else | ||
@ip_cache = @ip_cache.merge({group_name.to_sym => {cidr.to_sym => {mac_addr.to_sym => {ip: ip.to_s, timestamp: Time.now.to_s}}}}) | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def start_cleanup_task | ||
logger.info("Starting ip cache maintenance for IPAM provider #{@provider}, used by /next_ip.") | ||
@timer_task = Concurrent::TimerTask.new(execution_interval: DEFAULT_CLEANUP_INTERVAL) { init_cache } | ||
@timer_task.execute | ||
end | ||
|
||
# @ip_cache structure | ||
# | ||
# Groups of subnets are cached under the External IPAM Group name. For example, | ||
# "IPAM Group Name" would be the section name in phpIPAM. All IP's cached for subnets | ||
# that do not have an External IPAM group specified, they are cached under the "" key. IP's | ||
# are cached using one of two possible keys: | ||
# 1). Mac Address | ||
# 2). UUID (Used when Mac Address not specified) | ||
# | ||
# { | ||
# "": { | ||
# "100.55.55.0/24":{ | ||
# "00:0a:95:9d:68:10": {"ip": "100.55.55.1", "timestamp": "2019-09-17 12:03:43 -D400"}, | ||
# "906d8bdc-dcc0-4b59-92cb-665935e21662": {"ip": "100.55.55.2", "timestamp": "2019-09-17 11:43:22 -D400"} | ||
# }, | ||
# }, | ||
# "IPAM Group Name": { | ||
# "123.11.33.0/24":{ | ||
# "00:0a:95:9d:68:33": {"ip": "123.11.33.1", "timestamp": "2019-09-17 12:04:43 -0400"}, | ||
# "00:0a:95:9d:68:34": {"ip": "123.11.33.2", "timestamp": "2019-09-17 12:05:48 -0400"}, | ||
# "00:0a:95:9d:68:35": {"ip": "123.11.33.3", "timestamp:: "2019-09-17 12:06:50 -0400"} | ||
# } | ||
# }, | ||
# "Another IPAM Group": { | ||
# "185.45.39.0/24":{ | ||
# "00:0a:95:9d:68:55": {"ip": "185.45.39.1", "timestamp": "2019-09-17 12:04:43 -0400"}, | ||
# "00:0a:95:9d:68:56": {"ip": "185.45.39.2", "timestamp": "2019-09-17 12:05:48 -0400"} | ||
# } | ||
# } | ||
# } | ||
def init_cache | ||
@m.synchronize do | ||
if @ip_cache && !@ip_cache.empty? | ||
logger.debug("Processing ip cache for IPAM provider #{@provider}") | ||
@ip_cache.each do |group, subnets| | ||
subnets.each do |cidr, macs| | ||
macs.each do |mac, ip| | ||
if Time.now - Time.parse(ip[:timestamp]) > DEFAULT_CLEANUP_INTERVAL | ||
@ip_cache[group][cidr].delete(mac) | ||
end | ||
end | ||
@ip_cache[group].delete(cidr) if @ip_cache[group][cidr].nil? || @ip_cache[group][cidr].empty? | ||
end | ||
end | ||
else | ||
logger.debug("Clearing ip cache for IPAM provider #{@provider}") | ||
@ip_cache = {'': {}} | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.