Skip to content

Commit 8172241

Browse files
author
Christopher Smith
committed
Fixes #34205 - External IPAM Integration
1 parent 28b0212 commit 8172241

25 files changed

+1416
-1
lines changed

Contributors

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Ashley Penney <apenney@gmail.com>
1010
Baptiste Agasse <baptiste.agasse@lyra-network.com>
1111
Brandon Weeks <weeks@squareup.com>
1212
Christian Arnold <christian.arnold@t-systems.de>
13+
Christopher Smith <grizzthedj@gmail.com>
1314
Corey Osman <corey@logicminds.biz>
1415
Daniel Baeurer <daniel.baeurer@gmail.com>
1516
Daniel Helgenberger <daniel.helgenberger@m-box.de>

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Currently Supported modules:
1919
* HTTPBoot - endpoint exposing a (TFTP) directory via HTTP(s) for UEFI HTTP booting
2020
* Logs - log buffer of proxy logs for easier troubleshooting
2121
* Templates - unattended Foreman endpoint proxy
22+
* External IPAM - Integration with External IPAM providers
2223

2324
# Installation
2425
Read the [Smart Proxy Installation section](https://theforeman.org/manuals/latest/index.html#4.3.1SmartProxyInstallation) of the manual.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
:enabled: false
3+
4+
# Built-in providers:
5+
# 1. phpIPAM: externalipam_phpipam
6+
# 2. Netbox: externalipam_netbox
7+
8+
:use_provider: externalipam_netbox
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
# url is the hostname and path of the Netbox instance
3+
:url: 'https://netbox.example.com'
4+
5+
# token is the Netbox API token
6+
:token: 'netbox_token'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
# url is the hostname and path of the phpIPAM instance.
3+
:url: 'https://phpipam.example.com'
4+
5+
# The phpIPAM user name for authentication. Please note that an API Key also needs to be
6+
# setup with the exact same name as the user name configured here. When setting up the API
7+
# Key in phpIPAM, "User token" must be used for the "App Security" setting.
8+
:user: 'ipam_user'
9+
10+
# The password for above user account. Note that this is the password of the user, and not
11+
# the API Key itself.
12+
:password: 'ipam_password'

lib/proxy/validations.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class Error < RuntimeError; end
99
class InvalidIPAddress < Error; end
1010
class InvalidMACAddress < Error; end
1111
class InvalidSubnet < Error; end
12+
class InvalidCidr < Error; end
13+
class IpNotInCidr < Error; end
1214

1315
private
1416

@@ -61,6 +63,23 @@ def validate_subnet(subnet)
6163
subnet
6264
end
6365

66+
def validate_cidr(address, prefix)
67+
cidr = "#{address}/#{prefix}"
68+
network = IPAddr.new(cidr).to_s
69+
if network != IPAddr.new(address).to_s
70+
raise InvalidCidr, "Network address #{address} should be #{network} with prefix #{prefix}"
71+
end
72+
cidr
73+
rescue IPAddr::Error => e
74+
raise Proxy::Validations::Error, e.to_s
75+
end
76+
77+
def validate_ip_in_cidr(ip, cidr)
78+
raise IpNotInCidr, "IP #{ip} is not in #{cidr}" unless IPAddr.new(cidr).include?(IPAddr.new(ip))
79+
rescue IPAddr::Error => e
80+
raise Proxy::Validations::Error, e.to_s
81+
end
82+
6483
def validate_server(server)
6584
raise Proxy::DHCP::Error, "Invalid Server #{server}" unless server.is_a?(Proxy::DHCP::Server)
6685
server

lib/smart_proxy_main.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ module Proxy
6161
require 'dhcp_isc/dhcp_isc'
6262
require 'dhcp_native_ms/dhcp_native_ms'
6363
require 'dhcp_libvirt/dhcp_libvirt'
64+
require 'externalipam/externalipam'
6465
require 'puppetca/puppetca'
6566
require 'puppetca_http_api/puppetca_http_api'
6667
require 'puppetca_hostname_whitelisting/puppetca_hostname_whitelisting'

modules/dhcp_common/free_ips.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def clean_up_allocated_ips
3333
break if @allocation_timestamps.first.nil? || @allocation_timestamps.first[1] > time_now
3434
ip, _ = @allocation_timestamps.shift
3535
@allocated_ips.delete(ip)
36-
logger.debug("#{ip} marked as free.")
36+
logger.trace("#{ip} marked as free for DHCP.")
3737
end
3838
end
3939
end
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
require 'yaml'
2+
require 'json'
3+
require 'net/http'
4+
require 'uri'
5+
require 'externalipam/ipam_helper'
6+
7+
module Proxy::Ipam
8+
# Class to handle authentication and HTTP transactions with External IPAM providers
9+
class ApiResource
10+
include ::Proxy::Log
11+
include Proxy::Ipam::IpamHelper
12+
13+
def initialize(params = {})
14+
@api_base = params[:api_base]
15+
@token = params[:token]
16+
@auth_header = params[:auth_header] || 'Authorization'
17+
end
18+
19+
def get(path, params = nil)
20+
url = @api_base + path
21+
url += "?#{URI.encode_www_form(params)}" if params
22+
uri = URI(url)
23+
request = Net::HTTP::Get.new(uri)
24+
request[@auth_header] = @token
25+
request['Accept'] = 'application/json'
26+
request(request, uri)
27+
end
28+
29+
def delete(path)
30+
uri = URI(@api_base + path)
31+
request = Net::HTTP::Delete.new(uri)
32+
request[@auth_header] = @token
33+
request['Accept'] = 'application/json'
34+
request(request, uri)
35+
end
36+
37+
def post(path, body = nil)
38+
uri = URI(@api_base + path)
39+
request = Net::HTTP::Post.new(uri)
40+
request.body = body
41+
request[@auth_header] = @token
42+
request['Accept'] = 'application/json'
43+
request['Content-Type'] = 'application/json'
44+
request(request, uri)
45+
end
46+
47+
private
48+
49+
def request(request, uri)
50+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
51+
http.request(request)
52+
end
53+
end
54+
end
55+
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module ::Proxy::Ipam
2+
class ConfigurationLoader
3+
def load_classes
4+
require 'externalipam/dependency_injection'
5+
require 'externalipam/ipam_api'
6+
end
7+
end
8+
end

0 commit comments

Comments
 (0)