smart_proxy_dhcp_kea 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +675 -0
- data/README.md +52 -0
- data/bundler.d/dhcp_kea.rb +4 -0
- data/config/dhcp_remote_kea.yml.example +24 -0
- data/lib/smart_proxy_dhcp_kea.rb +9 -0
- data/lib/smart_proxy_dhcp_kea/dhcp_kea.rb +4 -0
- data/lib/smart_proxy_dhcp_kea/dhcp_kea_main.rb +127 -0
- data/lib/smart_proxy_dhcp_kea/dhcp_kea_plugin.rb +16 -0
- data/lib/smart_proxy_dhcp_kea/keapostgre_dhcp_network.rb +132 -0
- data/lib/smart_proxy_dhcp_kea/plugin_configuration.rb +58 -0
- data/lib/smart_proxy_dhcp_kea/subnet_service_initializer.rb +100 -0
- data/lib/smart_proxy_dhcp_kea/version.rb +7 -0
- data/test/integration_test.rb +134 -0
- data/test/plugin_configuration_test.rb +68 -0
- data/test/test_helper.rb +7 -0
- metadata +160 -0
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# SmartProxyDhcpKea
|
2
|
+
|
3
|
+
This Foreman smart proxy plugin allow to interface with Kea DHCP provider. Postgres and Mysql database are supported, anyway Mysql has not been tested yet.
|
4
|
+
|
5
|
+
# Installation
|
6
|
+
|
7
|
+
Smart proxy plugin are ruby gems. They can be easly instaled with `gem`.
|
8
|
+
|
9
|
+
## Prerequisites
|
10
|
+
|
11
|
+
The smart proxy need to interact both with postgresql and mysql. To do that it uses `mysql2` and `pg` gems, which are automatically installed, but some dependencies are needed. So if gem installation goes wrong, try to install them with `yum`:
|
12
|
+
|
13
|
+
yum install ruby-devel
|
14
|
+
yum install potgresql-devel
|
15
|
+
yum install mysql-devel
|
16
|
+
|
17
|
+
## Manual installation
|
18
|
+
|
19
|
+
It's possible to install manually this smart proxy plugin using `gem`
|
20
|
+
|
21
|
+
gem install 'smart_proxy_dhcp_kea'
|
22
|
+
|
23
|
+
The gem with all its dependencies will be installed. Next you need to specify the gem into the `~foreman-proxy/bundler.d/Gemfile.local.rb` file. Create the file if it doesn't exist.
|
24
|
+
|
25
|
+
echo "gem 'smat_proxy_dhcp_kea'" > /usr/share/foreman-proxy/bundler.d/Gemfile.local.rb
|
26
|
+
|
27
|
+
Next restart the foreman-proxy service and refresh features form the control panel.
|
28
|
+
|
29
|
+
systemctl restart foreman-proxy
|
30
|
+
|
31
|
+
The DHCP feature should be now active.
|
32
|
+
|
33
|
+
# Configuration
|
34
|
+
|
35
|
+
To enable this DHCP provider, edit `/etc/foreman-proxy/settings.d/dhcp.yml` and set:
|
36
|
+
|
37
|
+
:use_provider: dhcp_kea
|
38
|
+
|
39
|
+
Then you need to create /etc/foreman-proxy/settings.d/dhcp\_kea.yml file and specify the following parameters.
|
40
|
+
|
41
|
+
:db: [postgres, mysql]
|
42
|
+
:dbname: [database_name]
|
43
|
+
:username: [username]
|
44
|
+
:password: [password]
|
45
|
+
:host: [host_address]
|
46
|
+
:port: [db_port]
|
47
|
+
|
48
|
+
|
49
|
+
This smart proxy support both postgres and mysql database for kea. You need to specify in the configuration file which one are you going to use. Mysql is the default databse. Also, if postgres is choosen, a table called subnets, in which subnets are stored into keasubnets database is required. The subnet schema is indeed present by default in MySQL database.
|
50
|
+
|
51
|
+
# Contributing
|
52
|
+
Pierfrancesco Cifra
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
#
|
3
|
+
# Configuration file for ISC dhcp provider
|
4
|
+
#
|
5
|
+
|
6
|
+
#:config: /etc/dhcp/dhcpd.conf
|
7
|
+
#:leases: /var/lib/dhcpd/dhcpd.leases
|
8
|
+
#
|
9
|
+
# Redhat 5
|
10
|
+
#
|
11
|
+
#:config: /etc/dhcpd.conf
|
12
|
+
#
|
13
|
+
# Settings for Ubuntu
|
14
|
+
#
|
15
|
+
#:config: /etc/dhcp3/dhcpd.conf
|
16
|
+
#:leases: /var/lib/dhcp3/dhcpd.leases
|
17
|
+
|
18
|
+
# Specifies TSIG key name and secret
|
19
|
+
#:key_name: secret_key_name
|
20
|
+
#:key_secret: secret_key
|
21
|
+
|
22
|
+
#:omapi_port: 7911
|
23
|
+
|
24
|
+
# use :server setting in dhcp.yml if you are managing a dhcp server which is not localhost
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'dhcp_common/dhcp_common'
|
2
|
+
require 'dhcp_common/server'
|
3
|
+
|
4
|
+
|
5
|
+
module Proxy::DHCP::DhcpKea
|
6
|
+
class Provider < ::Proxy::DHCP::Server
|
7
|
+
attr_reader :host, :port, :dbname, :username, :password, :keapostgre_network, :subnet_service, :free_ips, :db
|
8
|
+
|
9
|
+
def initialize(host, port, dbname, username, password, keapostgre_network, subnet_service, free_ip_service, db)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
@db = db
|
13
|
+
@dbname = dbname
|
14
|
+
@username = username
|
15
|
+
@password = password
|
16
|
+
@keapostgre_network = keapostgre_network
|
17
|
+
@subnet_service = subnet_service
|
18
|
+
@free_ips = free_ip_service
|
19
|
+
super('kea', 'nil', subnet_service, free_ips)
|
20
|
+
end
|
21
|
+
|
22
|
+
def unused_ip(subnet_address, mac_address, from_address, to_address)
|
23
|
+
require 'ipaddr'
|
24
|
+
require 'resolv'
|
25
|
+
require 'pg'
|
26
|
+
require 'mysql2'
|
27
|
+
|
28
|
+
|
29
|
+
if db == 'postgres'
|
30
|
+
con = PG.connect :dbname => 'keasubnets', :user => username, :password => password, :host => host, :port => port
|
31
|
+
subnet = con.exec_params("select encode(address, 'escape') from subnets where encode(address, 'escape') like $1;", ['%' + subnet_address + '%'])
|
32
|
+
|
33
|
+
|
34
|
+
if subnet.num_tuples.zero?
|
35
|
+
logger.error 'This subnet does not exist. Not found in databse'
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
else
|
40
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
41
|
+
st = con.prepare("select subnet_prefix from dhcp4_subnet where subnet_prefix like ?;")
|
42
|
+
subnet = st.execute('%' + subnet_address + '%')
|
43
|
+
|
44
|
+
if subnet.count.zero?
|
45
|
+
logger.warning 'This subnet does not exist. Not found in databse'
|
46
|
+
return nil
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
mask = '/' + subnet.getvalue(0,0)[-2..-1]
|
54
|
+
subnet_address = subnet_address + mask
|
55
|
+
logger.debug 'Start searching ip address in subnet ' + subnet_address
|
56
|
+
|
57
|
+
|
58
|
+
unless from_address
|
59
|
+
addr = IPAddr.new(subnet_address.to_s)
|
60
|
+
from_address = IPAddr.new((addr.to_range().first.to_i + 1), Socket::AF_INET).to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
unless to_address
|
64
|
+
addr = IPAddr.new(subnet_address.to_s)
|
65
|
+
to_address = IPAddr.new((addr.to_range().last.to_i - 1), Socket::AF_INET).to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
logger.debug 'Starting search for a free ip address form ' + from_address.to_s + ' to ' + to_address.to_s
|
69
|
+
possible_ip = free_ips.find_free_ip(from_address, to_address, all_hosts(subnet_address) + all_leases(subnet_address))
|
70
|
+
|
71
|
+
logger.debug 'Possible ip found: ' + possible_ip
|
72
|
+
|
73
|
+
while possible_ip != nil
|
74
|
+
begin
|
75
|
+
Resolv.getname possible_ip
|
76
|
+
logger.warning 'Address ' + possible_ip + ' resolved. Cannot use it'
|
77
|
+
possible_ip = free_ips.find_free_ip(from_address, to_address, all_hosts(subnet_address) + all_leases(subnet_address))
|
78
|
+
rescue Resolv::ResolvError => e
|
79
|
+
logger.warning 'Address ' + possible_ip + ' not resolved. Can use it'
|
80
|
+
return possible_ip
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
def add_record(options={})
|
88
|
+
logger.debug "Hui1 '#{options}'"
|
89
|
+
record = super(options)
|
90
|
+
logger.debug "Hui '#{record}'"
|
91
|
+
keapostgre_network.add_dhcp_record options
|
92
|
+
record
|
93
|
+
rescue Exception => e
|
94
|
+
logger.error msg = "Error adding DHCP record: #{e}"
|
95
|
+
raise Proxy::DHCP::Error, msg
|
96
|
+
end
|
97
|
+
|
98
|
+
def del_record(record)
|
99
|
+
logger.debug "Hui '#{record}'"
|
100
|
+
# libvirt only supports one subnet per network
|
101
|
+
keapostgre_network.del_dhcp_record record
|
102
|
+
rescue Exception => e
|
103
|
+
logger.error msg = "Error removing DHCP record: #{e}"
|
104
|
+
raise Proxy::DHCP::Error, msg
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_record(subnet_address, ip_or_mac_address)
|
108
|
+
if ip_or_mac_address =~ Resolv::IPv4::Regex
|
109
|
+
keapostgre_network.find_records_by_ip ip_or_mac_address
|
110
|
+
else
|
111
|
+
keapostgre_network.find_records_by_mac ip_or_mac_address
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_records_by_ip(subnet_address, ip_address)
|
116
|
+
keapostgre_network.find_records_by_ip ip_address
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_records_by_mac(subnet_address, mac_address)
|
120
|
+
keapostgre_network.find_records_by_mac mac_address
|
121
|
+
end
|
122
|
+
|
123
|
+
def del_record_by_mac(subnet_address, mac_address)
|
124
|
+
keapostgre_network.del_record_by_mac mac_address
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Proxy::DHCP::DhcpKea
|
2
|
+
class Plugin < ::Proxy::Provider
|
3
|
+
plugin :dhcp_kea, ::Proxy::DHCP::DhcpKea::VERSION
|
4
|
+
|
5
|
+
default_settings :host => '127.0.0.1', :port => '5432', :dbname => 'keadb', :username => 'postgres', :db => 'postgres'
|
6
|
+
|
7
|
+
requires :dhcp, '>= 1.16'
|
8
|
+
|
9
|
+
validate_readable :config, :leases
|
10
|
+
|
11
|
+
load_classes ::Proxy::DHCP::DhcpKea::PluginConfiguration
|
12
|
+
load_dependency_injection_wirings ::Proxy::DHCP::DhcpKea::PluginConfiguration
|
13
|
+
|
14
|
+
start_services :free_ips
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'pg'
|
2
|
+
require 'mysql2'
|
3
|
+
|
4
|
+
module ::Proxy::DHCP::DhcpKea
|
5
|
+
class KeaDHCPNetwork
|
6
|
+
|
7
|
+
attr_reader :host, :port, :dbname, :username, :password, :db
|
8
|
+
|
9
|
+
def initialize(host, port, dbname, username, password, free_ips_service = nil, db)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
@db = db
|
13
|
+
@dbname = dbname
|
14
|
+
@username = username
|
15
|
+
@password = password
|
16
|
+
@free_ips = free_ips_service
|
17
|
+
end
|
18
|
+
|
19
|
+
def dhcp_leases
|
20
|
+
find_network.dhcp_leases
|
21
|
+
rescue ArgumentError
|
22
|
+
# workaround for ruby-libvirt < 0.6.1 - DHCP leases API is broken there
|
23
|
+
# (http://libvirt.org/git/?p=ruby-libvirt.git;a=commit;h=c2d4192ebf28b8030b753b715a72f0cdf725d313)
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_dhcp_record(record)
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
if db.to_s == 'postgres'
|
32
|
+
con = PG.connect :dbname => 'keasubnets', :user => username, :password => password, :host => host, :port => port
|
33
|
+
query = "SELECT subnet_id from subnets WHERE encode(address,'escape') ~ $1 ORDER BY RIGHT(encode(address,'escape'),2) DESC;"
|
34
|
+
subnet_id = nil
|
35
|
+
subnet_id = con.exec_params(query, [record['network']])[0]['subnet_id']
|
36
|
+
else
|
37
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
38
|
+
st = con.prepare("SELECT subnet_id from dhcp4_subnet WHERE subnet_prefix like ? ORDER BY RIGHT(subnet_prefix,2) DESC;")
|
39
|
+
subnet_id = nil
|
40
|
+
subnet_id = st.execute(record['network'].to_s + '%')[0]['subnet_id']
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
unless subnet_id
|
45
|
+
raise Proxy::DHCP::Error, "Unable to find subnet_id for ip: #{record.ip}"
|
46
|
+
end
|
47
|
+
con.close if con
|
48
|
+
|
49
|
+
if db == 'postgres'
|
50
|
+
con = PG.connect :dbname => dbname, :user => username, :password => password, :host => host, :port => port
|
51
|
+
query = "INSERT INTO hosts(dhcp_identifier,dhcp_identifier_type,dhcp4_subnet_id,ipv4_address,hostname,dhcp4_client_classes,dhcp4_next_server,dhcp4_boot_file_name) VALUES(DECODE($1,'hex'),0,$2,(SELECT ($3::inet - '0.0.0.0'::inet) as ip_integer),$4,'foreman',(SELECT ($5::inet - '0.0.0.0'::inet) as ip_integer),$6)"
|
52
|
+
con.exec_params(query, [record['mac'].gsub(":",""), subnet_id, record['ip'], record['name'], record['nextServer'],record['filename']])
|
53
|
+
else
|
54
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
55
|
+
st = con.prepare("INSERT INTO hosts(dhcp_identifier,dhcp_identifier_type,dhcp4_subnet_id,ipv4_address,hostname,dhcp4_client_classes,dhcp4_next_server,dhcp4_boot_file_name) VALUES(?,0,?,INET_ATON(?) as ip_integer),?,'foreman',INET_ATON(?) as ip_integer),?)")
|
56
|
+
st.execute(record['mac'].gsub(":",""), subnet_id, record['ip'], record['name'], record['nextServer'],record['filename'])
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
con.close if con
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def del_dhcp_record(record)
|
66
|
+
|
67
|
+
if db == 'postgres'
|
68
|
+
con = PG.connect :dbname => dbname, :user => username, :password => password, :host => host, :port => port
|
69
|
+
con.exec_params("DELETE FROM hosts WHERE encode(dhcp_identifier,'hex') = $1", [record.mac.gsub(":","")])
|
70
|
+
else
|
71
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
72
|
+
st = con.prepare("DELETE FROM hosts WHERE dhcp_identifier = ?")
|
73
|
+
st.execute(record.mac.gsub(":",""))
|
74
|
+
end
|
75
|
+
|
76
|
+
con.close if con
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def del_record_by_mac(mac)
|
81
|
+
|
82
|
+
if db == 'postgres'
|
83
|
+
con = PG.connect :dbname => dbname, :user => username, :password => password, :host => host, :port => port
|
84
|
+
con.exec_params("DELETE FROM hosts WHERE encode(dhcp_identifier,'hex') = $1", [mac.gsub(":","")])
|
85
|
+
else
|
86
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
87
|
+
st = con.prepare("DELETE FROM hosts WHERE dhcp_identifier = ?")
|
88
|
+
st.execute(mac.gsub(":",""))
|
89
|
+
end
|
90
|
+
|
91
|
+
con.close if con
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def find_records_by_mac(mac)
|
97
|
+
|
98
|
+
if db == 'postgres'
|
99
|
+
con = PG.connect :dbname => dbname, :user => username, :password => password, :host => host, :port => port
|
100
|
+
host_info = con.exec_params("SELECT encode(dhcp_identifier,'hex') as mac,(SELECT('0.0.0.0'::inet + ipv4_address)) as ip,hostname FROM hosts WHERE encode(dhcp_identifier,'hex') = $1", [mac.gsub(":","")] )
|
101
|
+
else
|
102
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
103
|
+
st = con.prepare("SELECT dhcp_identifier as mac,(INET_NTOA(ipv4_address)) as ip,hostname FROM hosts WHERE dhcp_identifier = ?")
|
104
|
+
host_info = st.execute(mac.gsub(":",""))
|
105
|
+
end
|
106
|
+
|
107
|
+
con.close if con
|
108
|
+
Proxy::DHCP::Record.new(host_info[0]['hostname'], host_info[0]['ip'], host_info[0]['mac'].scan(/.{1,2}/).join(':'))
|
109
|
+
end
|
110
|
+
|
111
|
+
def find_records_by_ip(ip)
|
112
|
+
|
113
|
+
if db == 'postgres'
|
114
|
+
con = PG.connect :dbname => dbname, :user => username, :password => password, :host => host, :port => port
|
115
|
+
host_info = con.exec_params("SELECT encode(dhcp_identifier,'hex') as mac,(SELECT('0.0.0.0'::inet + ipv4_address)) as ip,hostname FROM hosts WHERE ipv4_address = (SELECT ($1::inet - '0.0.0.0'::inet) as ip_integer)", [ip] )
|
116
|
+
else
|
117
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
118
|
+
st = con.prepare("SELECT dhcp_identifier as mac,INET_NTOA(ipv4_address) as ip,hostname FROM hosts WHERE ipv4_address = INET_ATON(?)")
|
119
|
+
host_info = st.execute(ip)
|
120
|
+
end
|
121
|
+
|
122
|
+
con.close if con
|
123
|
+
Proxy::DHCP::Record.new(host_info[0]['hostname'], host_info[0]['ip'], host_info[0]['mac'].scan(/.{1,2}/).join(':'))
|
124
|
+
rescue Exception => e
|
125
|
+
return ''
|
126
|
+
raise e
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Proxy::DHCP::DhcpKea
|
2
|
+
class PluginConfiguration
|
3
|
+
|
4
|
+
include Proxy::Log
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
def load_dependency_injection_wirings(container, settings)
|
9
|
+
|
10
|
+
|
11
|
+
logger.debug 'Plugin initializer, database used is ' + settings[:db].to_s
|
12
|
+
|
13
|
+
container.dependency :memory_store, ::Proxy::MemoryStore
|
14
|
+
|
15
|
+
container.dependency :subnet_service, (lambda do
|
16
|
+
::Proxy::DHCP::SubnetService.new(container.get_dependency(:memory_store),
|
17
|
+
container.get_dependency(:memory_store), container.get_dependency(:memory_store),
|
18
|
+
container.get_dependency(:memory_store), container.get_dependency(:memory_store))
|
19
|
+
end)
|
20
|
+
|
21
|
+
|
22
|
+
container.dependency :subnet_service_initializer, (lambda do
|
23
|
+
::Proxy::DHCP::DhcpKea::SubnetServiceInitializer.new(settings[:config], settings[:leases],
|
24
|
+
container.get_dependency(:parser), container.get_dependency(:subnet_service))
|
25
|
+
end)
|
26
|
+
|
27
|
+
|
28
|
+
container.dependency :keapostgre_network, (lambda do
|
29
|
+
::Proxy::DHCP::DhcpKea::KeaDHCPNetwork.new(settings[:host], settings[:port], settings[:dbname], settings[:username], settings[:password], settings[:db])
|
30
|
+
end)
|
31
|
+
|
32
|
+
|
33
|
+
container.dependency :initialized_subnet_service, (lambda do
|
34
|
+
::Proxy::DHCP::DhcpKea::SubnetServiceInitializer.new(settings[:host], settings[:port], settings[:dbname], settings[:username], settings[:password], settings[:db]).initialized_subnet_service(container.get_dependency(:subnet_service))
|
35
|
+
end)
|
36
|
+
|
37
|
+
|
38
|
+
container.singleton_dependency :free_ips, lambda {::Proxy::DHCP::FreeIps.new }
|
39
|
+
|
40
|
+
container.dependency :dhcp_provider, (lambda do
|
41
|
+
::Proxy::DHCP::DhcpKea::Provider.new(settings[:host], settings[:port], settings[:dbname], settings[:username], settings[:password], container.get_dependency(:keapostgre_network),
|
42
|
+
container.get_dependency(:initialized_subnet_service),
|
43
|
+
container.get_dependency(:free_ips), settings[:db])
|
44
|
+
end)
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_classes
|
50
|
+
require 'smart_proxy_dhcp_kea/keapostgre_dhcp_network'
|
51
|
+
require 'dhcp_common/subnet_service'
|
52
|
+
require 'dhcp_common/free_ips'
|
53
|
+
require 'dhcp_common/server'
|
54
|
+
require 'smart_proxy_dhcp_kea/subnet_service_initializer'
|
55
|
+
require 'smart_proxy_dhcp_kea/dhcp_kea_main'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'ipaddr'
|
3
|
+
require 'pg'
|
4
|
+
require 'mysql2'
|
5
|
+
|
6
|
+
|
7
|
+
module Proxy::DHCP::DhcpKea
|
8
|
+
class SubnetServiceInitializer
|
9
|
+
include Proxy::Log
|
10
|
+
|
11
|
+
attr_reader :host, :port, :dbname, :username, :password, :db
|
12
|
+
|
13
|
+
def initialize(host, port, dbname, username, password, db, free_ips_service = nil)
|
14
|
+
@host = host
|
15
|
+
@port = port
|
16
|
+
@db = db
|
17
|
+
@dbname = dbname
|
18
|
+
@username = username
|
19
|
+
@password = password
|
20
|
+
@free_ips = free_ips_service
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialized_subnet_service(subnet_service)
|
24
|
+
subnet_service.add_subnets(*parse_config_for_subnets)
|
25
|
+
logger.debug msg = "Initializing subnet"
|
26
|
+
# load_subnet_data(subnet_service)
|
27
|
+
subnet_service
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_config_for_subnets
|
31
|
+
|
32
|
+
ret_val = []
|
33
|
+
|
34
|
+
if db == 'postgres'
|
35
|
+
con = PG.connect :dbname => 'keasubnets', :user => username, :password => password, :host => host, :port => port
|
36
|
+
rs = con.exec "SELECT encode(address,'escape') from subnets"
|
37
|
+
else
|
38
|
+
con = Mysql2::Client.new(:dbname => dbname, :user => username, :password => password, :host => host, :port => port)
|
39
|
+
rs = con.query ("SELECT subnet_prefix from dhcp4_subnet")
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'ipaddress'
|
43
|
+
rs.each do |subnet|
|
44
|
+
ip = IPAddress::IPv4.new subnet['encode']
|
45
|
+
ret_val << Proxy::DHCP::Subnet.new(ip.address, ip.netmask)
|
46
|
+
logger.debug ip.to_s
|
47
|
+
end
|
48
|
+
logger.debug ret_val.to_s
|
49
|
+
ret_val
|
50
|
+
rescue Exception => e
|
51
|
+
logger.error msg = "Unable to parse postgres subnets: #{e}"
|
52
|
+
raise Proxy::DHCP::Error, msg
|
53
|
+
end
|
54
|
+
|
55
|
+
# Expects subnet_service to have subnet data
|
56
|
+
def parse_config_for_dhcp_reservations(subnet_service)
|
57
|
+
to_ret = []
|
58
|
+
doc = REXML::Document.new xml = libvirt_network.dump_xml
|
59
|
+
REXML::XPath.each(doc, "//network/ip[not(@family) or @family='ipv4']/dhcp/host") do |e|
|
60
|
+
subnet = subnet_service.find_subnet(e.attributes['ip'])
|
61
|
+
to_ret << Proxy::DHCP::Reservation.new(
|
62
|
+
e.attributes["name"],
|
63
|
+
e.attributes["ip"],
|
64
|
+
e.attributes["mac"],
|
65
|
+
subnet,
|
66
|
+
:hostname => e.attributes["name"])
|
67
|
+
end
|
68
|
+
to_ret
|
69
|
+
rescue Exception => e
|
70
|
+
logger.error msg = "Unable to parse reservations XML: #{e}"
|
71
|
+
logger.debug xml if defined?(xml)
|
72
|
+
raise Proxy::DHCP::Error, msg
|
73
|
+
end
|
74
|
+
|
75
|
+
def load_subnet_data(subnet_service)
|
76
|
+
reservations = parse_config_for_dhcp_reservations(subnet_service)
|
77
|
+
reservations.each { |record| subnet_service.add_host(record.subnet_address, record) }
|
78
|
+
leases = load_leases(subnet_service)
|
79
|
+
leases.each { |lease| subnet_service.add_lease(lease.subnet_address, lease) }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Expects subnet_service to have subnet data
|
83
|
+
def load_leases(subnet_service)
|
84
|
+
leases = libvirt_network.dhcp_leases
|
85
|
+
leases.map do |element|
|
86
|
+
subnet = subnet_service.find_subnet(element['ipaddr'])
|
87
|
+
Proxy::DHCP::Lease.new(
|
88
|
+
nil,
|
89
|
+
element['ipaddr'],
|
90
|
+
element['mac'],
|
91
|
+
subnet,
|
92
|
+
Time.now.utc,
|
93
|
+
Time.at(element['expirytime'] || 0).utc,
|
94
|
+
'active'
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|