smart_proxy_ipam 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/smart_proxy_ipam/api_resource.rb +1 -4
- data/lib/smart_proxy_ipam/ip_cache.rb +39 -32
- data/lib/smart_proxy_ipam/ipam_api.rb +26 -27
- data/lib/smart_proxy_ipam/ipam_helper.rb +21 -24
- data/lib/smart_proxy_ipam/ipam_validator.rb +3 -3
- data/lib/smart_proxy_ipam/netbox/netbox_client.rb +25 -20
- data/lib/smart_proxy_ipam/phpipam/phpipam_client.rb +10 -10
- data/lib/smart_proxy_ipam/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0754301cca6caabaf785d9c4a7753d8543289fa9754339c12f706d23610577d2
|
4
|
+
data.tar.gz: ad1c8b77662f0ff667ff1c2127bfb9af6221dfe67cd7877968c6425e20fc4074
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74ba390d81e5be049f0ab15c1586babb91feddbde52c513cf65c35cc140a7471d3f531d578da899b406c09bdebbf8f6039a15e8105bf8ee7bafd67bb5ec3e4a9
|
7
|
+
data.tar.gz: a6fe51e572df5e809546fea30864b5bdf153e7eb297bc0a6ae909eda79c181fc028f6b7c2421c1745f62ef20e94bbf55f2cfcd1f5a86270c1ed372db22c3722d
|
@@ -21,20 +21,17 @@ module Proxy::Ipam
|
|
21
21
|
request = Net::HTTP::Get.new(uri)
|
22
22
|
request[@auth_header] = @token
|
23
23
|
request['Accept'] = 'application/json'
|
24
|
-
request['Content-Type'] = 'application/json'
|
25
24
|
|
26
25
|
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
27
26
|
http.request(request)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
def delete(path
|
30
|
+
def delete(path)
|
32
31
|
uri = URI(@api_base + path)
|
33
|
-
uri.query = URI.encode_www_form(body) if body
|
34
32
|
request = Net::HTTP::Delete.new(uri)
|
35
33
|
request[@auth_header] = @token
|
36
34
|
request['Accept'] = 'application/json'
|
37
|
-
request['Content-Type'] = 'application/json'
|
38
35
|
|
39
36
|
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
40
37
|
http.request(request)
|
@@ -4,38 +4,45 @@ require 'monitor'
|
|
4
4
|
require 'concurrent'
|
5
5
|
require 'time'
|
6
6
|
require 'smart_proxy_ipam/ipam_helper'
|
7
|
+
require 'singleton'
|
7
8
|
|
8
9
|
module Proxy::Ipam
|
9
10
|
# Class for managing temp in-memory cache to prevent same IP's being suggested in race conditions
|
10
11
|
class IpCache
|
12
|
+
include Singleton
|
11
13
|
include Proxy::Log
|
12
14
|
include Proxy::Ipam::IpamHelper
|
13
15
|
|
14
16
|
DEFAULT_CLEANUP_INTERVAL = 60
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@m = Monitor.new
|
20
|
+
init_cache
|
21
|
+
start_cleanup_task
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_provider(provider)
|
25
|
+
@provider = provider
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_provider
|
29
|
+
@provider
|
23
30
|
end
|
24
31
|
|
25
32
|
def set_group(group, value)
|
26
|
-
|
33
|
+
@ip_cache[group.to_sym] = value
|
27
34
|
end
|
28
35
|
|
29
36
|
def get_group(group)
|
30
|
-
|
37
|
+
@ip_cache[group.to_sym]
|
31
38
|
end
|
32
39
|
|
33
40
|
def get_cidr(group, cidr)
|
34
|
-
|
41
|
+
@ip_cache[group.to_sym][cidr.to_sym]
|
35
42
|
end
|
36
43
|
|
37
44
|
def get_ip(group_name, cidr, mac)
|
38
|
-
|
45
|
+
@ip_cache[group_name.to_sym][cidr.to_sym][mac.to_sym][:ip]
|
39
46
|
end
|
40
47
|
|
41
48
|
def get_cleanup_interval
|
@@ -43,27 +50,27 @@ module Proxy::Ipam
|
|
43
50
|
end
|
44
51
|
|
45
52
|
def ip_exists(ip, cidr, group_name)
|
46
|
-
cidr_key =
|
53
|
+
cidr_key = @ip_cache[group_name.to_sym][cidr.to_sym]&.to_s
|
47
54
|
cidr_key.include?(ip.to_s)
|
48
55
|
end
|
49
56
|
|
50
57
|
def add(ip, mac, cidr, group_name)
|
51
|
-
logger.debug("Adding IP '#{ip}' to cache for subnet '#{cidr}' in group '#{group_name}' for provider #{@provider}")
|
52
|
-
|
58
|
+
logger.debug("Adding IP '#{ip}' to cache for subnet '#{cidr}' in group '#{group_name}' for IPAM provider #{@provider.to_s}")
|
59
|
+
@m.synchronize do
|
53
60
|
mac_addr = mac.nil? || mac.empty? ? SecureRandom.uuid : mac
|
54
|
-
group_hash =
|
61
|
+
group_hash = @ip_cache[group_name.to_sym]
|
55
62
|
|
56
63
|
group_hash.each do |key, values|
|
57
64
|
if values.keys.include? mac_addr.to_sym
|
58
|
-
|
65
|
+
@ip_cache[group_name.to_sym][key].delete(mac_addr.to_sym)
|
59
66
|
end
|
60
|
-
|
67
|
+
@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?
|
61
68
|
end
|
62
69
|
|
63
70
|
if group_hash.key?(cidr.to_sym)
|
64
|
-
|
71
|
+
@ip_cache[group_name.to_sym][cidr.to_sym][mac_addr.to_sym] = {ip: ip.to_s, timestamp: Time.now.to_s}
|
65
72
|
else
|
66
|
-
|
73
|
+
@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}}}})
|
67
74
|
end
|
68
75
|
end
|
69
76
|
end
|
@@ -71,12 +78,12 @@ module Proxy::Ipam
|
|
71
78
|
private
|
72
79
|
|
73
80
|
def start_cleanup_task
|
74
|
-
logger.info("Starting ip cache maintenance for provider #{@provider}, used by /next_ip.")
|
75
|
-
|
76
|
-
|
81
|
+
logger.info("Starting ip cache maintenance for IPAM provider #{@provider.to_s}, used by /next_ip.")
|
82
|
+
@timer_task = Concurrent::TimerTask.new(execution_interval: DEFAULT_CLEANUP_INTERVAL) { init_cache }
|
83
|
+
@timer_task.execute
|
77
84
|
end
|
78
85
|
|
79
|
-
#
|
86
|
+
# @ip_cache structure
|
80
87
|
#
|
81
88
|
# Groups of subnets are cached under the External IPAM Group name. For example,
|
82
89
|
# "IPAM Group Name" would be the section name in phpIPAM. All IP's cached for subnets
|
@@ -107,22 +114,22 @@ module Proxy::Ipam
|
|
107
114
|
# }
|
108
115
|
# }
|
109
116
|
def init_cache
|
110
|
-
|
111
|
-
if
|
112
|
-
logger.debug("Processing ip cache for provider #{@provider}")
|
113
|
-
|
117
|
+
@m.synchronize do
|
118
|
+
if @ip_cache && !@ip_cache.empty?
|
119
|
+
logger.debug("Processing ip cache for IPAM provider #{@provider.to_s}")
|
120
|
+
@ip_cache.each do |group, subnets|
|
114
121
|
subnets.each do |cidr, macs|
|
115
122
|
macs.each do |mac, ip|
|
116
123
|
if Time.now - Time.parse(ip[:timestamp]) > DEFAULT_CLEANUP_INTERVAL
|
117
|
-
|
124
|
+
@ip_cache[group][cidr].delete(mac)
|
118
125
|
end
|
119
126
|
end
|
120
|
-
|
127
|
+
@ip_cache[group].delete(cidr) if @ip_cache[group][cidr].nil? || @ip_cache[group][cidr].empty?
|
121
128
|
end
|
122
129
|
end
|
123
130
|
else
|
124
|
-
logger.debug("Clearing ip cache for provider #{@provider}")
|
125
|
-
|
131
|
+
logger.debug("Clearing ip cache for IPAM provider #{@provider.to_s}")
|
132
|
+
@ip_cache = {'': {}}
|
126
133
|
end
|
127
134
|
end
|
128
135
|
end
|
@@ -51,7 +51,7 @@ module Proxy::Ipam
|
|
51
51
|
group_name = get_request_group(params)
|
52
52
|
|
53
53
|
next_ip = provider.get_next_ip(mac, cidr, group_name)
|
54
|
-
halt 404, { error:
|
54
|
+
halt 404, { error: ERRORS[:no_free_ips] }.to_json if next_ip.nil?
|
55
55
|
next_ip.to_json
|
56
56
|
rescue Proxy::Validations::Error => e
|
57
57
|
logger.warn(e.message)
|
@@ -60,8 +60,8 @@ module Proxy::Ipam
|
|
60
60
|
logger.warn(e.message)
|
61
61
|
halt 500, { error: e.message }.to_json
|
62
62
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
63
|
-
logger.warn(
|
64
|
-
halt 500, { error:
|
63
|
+
logger.warn(ERRORS[:no_connection])
|
64
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -98,7 +98,7 @@ module Proxy::Ipam
|
|
98
98
|
group_name = get_request_group(params)
|
99
99
|
subnet = provider.get_ipam_subnet(cidr, group_name)
|
100
100
|
|
101
|
-
halt 404, { error:
|
101
|
+
halt 404, { error: ERRORS[:no_subnet] }.to_json if subnet.nil?
|
102
102
|
subnet.to_json
|
103
103
|
rescue Proxy::Validations::Error => e
|
104
104
|
logger.warn(e.message)
|
@@ -107,8 +107,8 @@ module Proxy::Ipam
|
|
107
107
|
logger.warn(e.message)
|
108
108
|
halt 500, { error: e.message }.to_json
|
109
109
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
110
|
-
logger.warn(
|
111
|
-
halt 500, { error:
|
110
|
+
logger.warn(ERRORS[:no_connection])
|
111
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
@@ -139,9 +139,8 @@ module Proxy::Ipam
|
|
139
139
|
content_type :json
|
140
140
|
|
141
141
|
begin
|
142
|
-
halt 500, { error:
|
142
|
+
halt 500, { error: ERRORS[:groups_not_supported] }.to_json unless provider.groups_supported?
|
143
143
|
groups = provider.get_ipam_groups
|
144
|
-
halt 404, { error: errors[:no_groups] }.to_json if groups.nil?
|
145
144
|
groups.to_json
|
146
145
|
rescue Proxy::Validations::Error => e
|
147
146
|
logger.warn(e.message)
|
@@ -150,8 +149,8 @@ module Proxy::Ipam
|
|
150
149
|
logger.warn(e.message)
|
151
150
|
halt 500, { error: e.message }.to_json
|
152
151
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
153
|
-
logger.warn(
|
154
|
-
halt 500, { error:
|
152
|
+
logger.warn(ERRORS[:no_connection])
|
153
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
155
154
|
end
|
156
155
|
end
|
157
156
|
|
@@ -186,7 +185,7 @@ module Proxy::Ipam
|
|
186
185
|
group_name = get_request_group(params)
|
187
186
|
group = provider.get_ipam_group(group_name)
|
188
187
|
|
189
|
-
halt 404, { error:
|
188
|
+
halt 404, { error: ERRORS[:no_group] }.to_json if group.nil?
|
190
189
|
group.to_json
|
191
190
|
rescue Proxy::Validations::Error => e
|
192
191
|
logger.warn(e.message)
|
@@ -195,8 +194,8 @@ module Proxy::Ipam
|
|
195
194
|
logger.warn(e.message)
|
196
195
|
halt 500, { error: e.message }.to_json
|
197
196
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
198
|
-
logger.warn(
|
199
|
-
halt 500, { error:
|
197
|
+
logger.warn(ERRORS[:no_connection])
|
198
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
200
199
|
end
|
201
200
|
end
|
202
201
|
|
@@ -234,7 +233,7 @@ module Proxy::Ipam
|
|
234
233
|
group_name = get_request_group(params)
|
235
234
|
subnets = provider.get_ipam_subnets(group_name)
|
236
235
|
|
237
|
-
halt 404, { error:
|
236
|
+
halt 404, { error: ERRORS[:no_subnets_in_group] }.to_json if subnets.nil?
|
238
237
|
subnets.to_json
|
239
238
|
rescue Proxy::Validations::Error => e
|
240
239
|
logger.warn(e.message)
|
@@ -243,8 +242,8 @@ module Proxy::Ipam
|
|
243
242
|
logger.warn(e.message)
|
244
243
|
halt 500, { error: e.message }.to_json
|
245
244
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
246
|
-
logger.warn(
|
247
|
-
halt 500, { error:
|
245
|
+
logger.warn(ERRORS[:no_connection])
|
246
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
248
247
|
end
|
249
248
|
end
|
250
249
|
|
@@ -276,7 +275,7 @@ module Proxy::Ipam
|
|
276
275
|
group_name = get_request_group(params)
|
277
276
|
subnet = provider.get_ipam_subnet(cidr, group_name)
|
278
277
|
|
279
|
-
halt 404, { error:
|
278
|
+
halt 404, { error: ERRORS[:no_subnet] }.to_json if subnet.nil?
|
280
279
|
validate_ip_in_cidr!(ip, cidr)
|
281
280
|
ip_exists = provider.ip_exists?(ip, subnet[:id], group_name)
|
282
281
|
halt 200, ip_exists.to_json
|
@@ -287,8 +286,8 @@ module Proxy::Ipam
|
|
287
286
|
logger.warn(e.message)
|
288
287
|
halt 500, { error: e.message }.to_json
|
289
288
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
290
|
-
logger.warn(
|
291
|
-
halt 500, { error:
|
289
|
+
logger.warn(ERRORS[:no_connection])
|
290
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
292
291
|
end
|
293
292
|
end
|
294
293
|
|
@@ -321,13 +320,13 @@ module Proxy::Ipam
|
|
321
320
|
group_name = get_request_group(params)
|
322
321
|
subnet = provider.get_ipam_subnet(cidr, group_name)
|
323
322
|
|
324
|
-
halt 404, { error:
|
323
|
+
halt 404, { error: ERRORS[:no_subnet] }.to_json if subnet.nil?
|
325
324
|
add_ip_params = { cidr: cidr, subnet_id: subnet[:id], group_name: group_name }
|
326
325
|
validate_ip_in_cidr!(ip, cidr)
|
327
326
|
|
328
327
|
ip_added = provider.add_ip_to_subnet(ip, add_ip_params) # Returns nil on success
|
329
328
|
halt 500, ip_added.to_json unless ip_added.nil?
|
330
|
-
|
329
|
+
status 201
|
331
330
|
rescue Proxy::Validations::Error => e
|
332
331
|
logger.warn(e.message)
|
333
332
|
halt 400, { error: e.to_s }.to_json
|
@@ -335,8 +334,8 @@ module Proxy::Ipam
|
|
335
334
|
logger.warn(e.message)
|
336
335
|
halt 500, { error: e.message }.to_json
|
337
336
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
338
|
-
logger.warn(
|
339
|
-
halt 500, { error:
|
337
|
+
logger.warn(ERRORS[:no_connection])
|
338
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
340
339
|
end
|
341
340
|
end
|
342
341
|
|
@@ -369,13 +368,13 @@ module Proxy::Ipam
|
|
369
368
|
group_name = get_request_group(params)
|
370
369
|
subnet = provider.get_ipam_subnet(cidr, group_name)
|
371
370
|
|
372
|
-
halt 404, { error:
|
371
|
+
halt 404, { error: ERRORS[:no_subnet] }.to_json if subnet.nil?
|
373
372
|
del_ip_params = { cidr: cidr, subnet_id: subnet[:id], group_name: group_name }
|
374
373
|
validate_ip_in_cidr!(ip, cidr)
|
375
374
|
|
376
375
|
ip_deleted = provider.delete_ip_from_subnet(ip, del_ip_params) # Returns nil on success
|
377
376
|
halt 500, ip_deleted.to_json unless ip_deleted.nil?
|
378
|
-
halt
|
377
|
+
halt 204
|
379
378
|
rescue Proxy::Validations::Error => e
|
380
379
|
logger.warn(e.message)
|
381
380
|
halt 400, { error: e.to_s }.to_json
|
@@ -383,8 +382,8 @@ module Proxy::Ipam
|
|
383
382
|
logger.warn(e.message)
|
384
383
|
halt 500, { error: e.message }.to_json
|
385
384
|
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
386
|
-
logger.warn(
|
387
|
-
halt 500, { error:
|
385
|
+
logger.warn(ERRORS[:no_connection])
|
386
|
+
halt 500, { error: ERRORS[:no_connection] }.to_json
|
388
387
|
end
|
389
388
|
end
|
390
389
|
end
|
@@ -3,12 +3,31 @@ module Proxy::Ipam::IpamHelper
|
|
3
3
|
include ::Proxy::Validations
|
4
4
|
|
5
5
|
MAX_IP_RETRIES = 5
|
6
|
+
ERRORS = {
|
7
|
+
cidr: "A 'cidr' parameter for the subnet must be provided(e.g. IPv4: 100.10.10.0/24, IPv6: 2001:db8:abcd:12::/124)",
|
8
|
+
mac: "A 'mac' address must be provided(e.g. 00:0a:95:9d:68:10)",
|
9
|
+
ip: "Missing 'ip' parameter. An IPv4 or IPv6 address must be provided(e.g. IPv4: 100.10.10.22, IPv6: 2001:db8:abcd:12::3)",
|
10
|
+
group_name: "A 'group_name' must be provided",
|
11
|
+
no_ip: 'IP address not found',
|
12
|
+
no_free_ips: 'No free addresses found',
|
13
|
+
no_connection: 'Unable to connect to External IPAM server',
|
14
|
+
no_group: 'Group not found in External IPAM',
|
15
|
+
no_groups: 'No groups found in External IPAM',
|
16
|
+
no_subnet: 'Subnet not found in External IPAM',
|
17
|
+
no_subnets_in_group: 'No subnets found in External IPAM group',
|
18
|
+
provider: "The IPAM provider must be specified(e.g. 'phpipam' or 'netbox')",
|
19
|
+
groups_not_supported: 'Groups are not supported',
|
20
|
+
add_ip: 'Error adding IP to External IPAM',
|
21
|
+
bad_mac: 'Mac address is invalid',
|
22
|
+
bad_ip: 'IP address is invalid',
|
23
|
+
bad_cidr: 'The network cidr is invalid'
|
24
|
+
}.freeze
|
6
25
|
|
7
26
|
def provider
|
8
27
|
@provider ||=
|
9
28
|
begin
|
10
29
|
unless client.authenticated?
|
11
|
-
halt 500, {error: 'Invalid credentials for External IPAM'}.to_json
|
30
|
+
halt 500, { error: 'Invalid credentials for External IPAM' }.to_json
|
12
31
|
end
|
13
32
|
client
|
14
33
|
end
|
@@ -71,7 +90,7 @@ module Proxy::Ipam::IpamHelper
|
|
71
90
|
end
|
72
91
|
end
|
73
92
|
|
74
|
-
next_ip
|
93
|
+
{data: next_ip}
|
75
94
|
end
|
76
95
|
|
77
96
|
def increment_ip(ip)
|
@@ -88,26 +107,4 @@ module Proxy::Ipam::IpamHelper
|
|
88
107
|
halt 500, { error: errors[:groups_not_supported] }.to_json if group && !provider.groups_supported?
|
89
108
|
group
|
90
109
|
end
|
91
|
-
|
92
|
-
def errors
|
93
|
-
{
|
94
|
-
cidr: "A 'cidr' parameter for the subnet must be provided(e.g. IPv4: 100.10.10.0/24, IPv6: 2001:db8:abcd:12::/124)",
|
95
|
-
mac: "A 'mac' address must be provided(e.g. 00:0a:95:9d:68:10)",
|
96
|
-
ip: "Missing 'ip' parameter. An IPv4 or IPv6 address must be provided(e.g. IPv4: 100.10.10.22, IPv6: 2001:db8:abcd:12::3)",
|
97
|
-
group_name: "A 'group_name' must be provided",
|
98
|
-
no_ip: 'IP address not found',
|
99
|
-
no_free_ips: 'No free addresses found',
|
100
|
-
no_connection: 'Unable to connect to External IPAM server',
|
101
|
-
no_group: 'Group not found in External IPAM',
|
102
|
-
no_groups: 'No groups found in External IPAM',
|
103
|
-
no_subnet: 'Subnet not found in External IPAM',
|
104
|
-
no_subnets_in_group: 'No subnets found in External IPAM group',
|
105
|
-
provider: "The IPAM provider must be specified(e.g. 'phpipam' or 'netbox')",
|
106
|
-
groups_not_supported: 'Groups are not supported',
|
107
|
-
add_ip: 'Error adding IP to External IPAM',
|
108
|
-
bad_mac: 'Mac address is invalid',
|
109
|
-
bad_ip: 'IP address is invalid',
|
110
|
-
bad_cidr: 'The network cidr is invalid'
|
111
|
-
}
|
112
|
-
end
|
113
110
|
end
|
@@ -17,7 +17,7 @@ module Proxy::Ipam::IpamValidator
|
|
17
17
|
|
18
18
|
def validate_ip!(ip)
|
19
19
|
good_ip = ip =~ Regexp.union([Resolv::IPv4::Regex, Resolv::IPv6::Regex])
|
20
|
-
raise Proxy::Validations::Error,
|
20
|
+
raise Proxy::Validations::Error, ERRORS[:bad_ip] if good_ip.nil?
|
21
21
|
ip
|
22
22
|
end
|
23
23
|
|
@@ -39,9 +39,9 @@ module Proxy::Ipam::IpamValidator
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def validate_mac!(mac)
|
42
|
-
raise Proxy::Validations::Error.new,
|
42
|
+
raise Proxy::Validations::Error.new, ERRORS[:mac] if mac.nil? || mac.empty?
|
43
43
|
unless mac.match(/^([0-9a-fA-F]{2}[:]){5}[0-9a-fA-F]{2}$/i)
|
44
|
-
raise Proxy::Validations::Error.new,
|
44
|
+
raise Proxy::Validations::Error.new, ERRORS[:bad_mac]
|
45
45
|
end
|
46
46
|
mac
|
47
47
|
end
|
@@ -16,13 +16,12 @@ module Proxy::Netbox
|
|
16
16
|
include Proxy::Ipam::IpamHelper
|
17
17
|
include Proxy::Ipam::IpamValidator
|
18
18
|
|
19
|
-
@ip_cache = nil
|
20
|
-
|
21
19
|
def initialize(conf)
|
22
20
|
@api_base = "#{conf[:url]}/api/"
|
23
21
|
@token = conf[:token]
|
24
|
-
@api_resource = Proxy::Ipam::ApiResource.new(api_base: @api_base, token:
|
25
|
-
@ip_cache = Proxy::Ipam::IpCache.
|
22
|
+
@api_resource = Proxy::Ipam::ApiResource.new(api_base: @api_base, token: "Token #{@token}")
|
23
|
+
@ip_cache = Proxy::Ipam::IpCache.instance
|
24
|
+
@ip_cache.set_provider('netbox')
|
26
25
|
end
|
27
26
|
|
28
27
|
def get_ipam_subnet(cidr, group_name = nil)
|
@@ -35,7 +34,8 @@ module Proxy::Netbox
|
|
35
34
|
end
|
36
35
|
|
37
36
|
def get_ipam_subnet_by_group(cidr, group_id)
|
38
|
-
|
37
|
+
params = URI.encode_www_form({ status: 'active', prefix: cidr, vrf_id: group_id })
|
38
|
+
response = @api_resource.get("ipam/prefixes/?#{params}")
|
39
39
|
json_body = JSON.parse(response.body)
|
40
40
|
return nil if json_body['count'].zero?
|
41
41
|
subnet = subnet_from_result(json_body['results'][0])
|
@@ -43,7 +43,8 @@ module Proxy::Netbox
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def get_ipam_subnet_by_cidr(cidr)
|
46
|
-
|
46
|
+
params = URI.encode_www_form({ status: 'active', prefix: cidr })
|
47
|
+
response = @api_resource.get("ipam/prefixes/?#{params}")
|
47
48
|
json_body = JSON.parse(response.body)
|
48
49
|
return nil if json_body['count'].zero?
|
49
50
|
subnet = subnet_from_result(json_body['results'][0])
|
@@ -55,7 +56,7 @@ module Proxy::Netbox
|
|
55
56
|
json_body = JSON.parse(response.body)
|
56
57
|
groups = []
|
57
58
|
|
58
|
-
return
|
59
|
+
return groups if json_body['count'].zero?
|
59
60
|
|
60
61
|
json_body['results'].each do |group|
|
61
62
|
groups.push({
|
@@ -68,8 +69,9 @@ module Proxy::Netbox
|
|
68
69
|
end
|
69
70
|
|
70
71
|
def get_ipam_group(group_name)
|
71
|
-
raise
|
72
|
-
|
72
|
+
raise ERRORS[:groups_not_supported] unless groups_supported?
|
73
|
+
params = URI.encode_www_form({ name: group_name })
|
74
|
+
response = @api_resource.get("ipam/vrfs/?#{params}")
|
73
75
|
json_body = JSON.parse(response.body)
|
74
76
|
return nil if json_body['count'].zero?
|
75
77
|
|
@@ -85,18 +87,19 @@ module Proxy::Netbox
|
|
85
87
|
def get_group_id(group_name)
|
86
88
|
return nil if group_name.nil? || group_name.empty?
|
87
89
|
group = get_ipam_group(group_name)
|
88
|
-
raise
|
90
|
+
raise ERRORS[:no_group] if group.nil?
|
89
91
|
group[:id]
|
90
92
|
end
|
91
93
|
|
92
94
|
def get_ipam_subnets(group_name)
|
93
95
|
if group_name.nil?
|
94
|
-
|
96
|
+
params = URI.encode_www_form({ status: 'active' })
|
95
97
|
else
|
96
98
|
group_id = get_group_id(group_name)
|
97
|
-
|
99
|
+
params = URI.encode_www_form({ status: 'active', vrf_id: group_id })
|
98
100
|
end
|
99
101
|
|
102
|
+
response = @api_resource.get("ipam/prefixes/?#{params}")
|
100
103
|
json_body = JSON.parse(response.body)
|
101
104
|
return nil if json_body['count'].zero?
|
102
105
|
subnets = []
|
@@ -115,9 +118,9 @@ module Proxy::Netbox
|
|
115
118
|
|
116
119
|
def ip_exists?(ip, subnet_id, group_name)
|
117
120
|
group_id = get_group_id(group_name)
|
118
|
-
url = "ipam/ip-addresses
|
119
|
-
url += "
|
120
|
-
url += "
|
121
|
+
url = "ipam/ip-addresses/?#{URI.encode_www_form({ address: ip })}"
|
122
|
+
url += "&#{URI.encode_www_form({ prefix_id: subnet_id })}" unless subnet_id.nil?
|
123
|
+
url += "&#{URI.encode_www_form({ vrf_id: group_id })}" unless group_id.nil?
|
121
124
|
response = @api_resource.get(url)
|
122
125
|
json_body = JSON.parse(response.body)
|
123
126
|
return false if json_body['count'].zero?
|
@@ -145,15 +148,16 @@ module Proxy::Netbox
|
|
145
148
|
group_name = params[:group_name]
|
146
149
|
|
147
150
|
if group_name.nil? || group_name.empty?
|
148
|
-
|
151
|
+
params = URI.encode_www_form({ address: ip })
|
149
152
|
else
|
150
153
|
group_id = get_group_id(group_name)
|
151
|
-
|
154
|
+
params = URI.encode_www_form({ address: ip, vrf_id: group_id })
|
152
155
|
end
|
153
156
|
|
157
|
+
response = @api_resource.get("ipam/ip-addresses/?#{params}")
|
154
158
|
json_body = JSON.parse(response.body)
|
155
159
|
|
156
|
-
return { error:
|
160
|
+
return { error: ERRORS[:no_ip] } if json_body['count'].zero?
|
157
161
|
|
158
162
|
address_id = json_body['results'][0]['id']
|
159
163
|
response = @api_resource.delete("ipam/ip-addresses/#{address_id}/")
|
@@ -163,12 +167,13 @@ module Proxy::Netbox
|
|
163
167
|
|
164
168
|
def get_next_ip(mac, cidr, group_name)
|
165
169
|
subnet = get_ipam_subnet(cidr, group_name)
|
166
|
-
raise
|
170
|
+
raise ERRORS[:no_subnet] if subnet.nil?
|
167
171
|
response = @api_resource.get("ipam/prefixes/#{subnet[:id]}/available-ips/?limit=1")
|
168
172
|
json_body = JSON.parse(response.body)
|
169
173
|
return nil if json_body.empty?
|
170
174
|
ip = json_body[0]['address'].split('/').first
|
171
|
-
cache_next_ip(@ip_cache, ip, mac, cidr, subnet[:id], group_name)
|
175
|
+
next_ip = cache_next_ip(@ip_cache, ip, mac, cidr, subnet[:id], group_name)
|
176
|
+
{ data: next_ip }
|
172
177
|
end
|
173
178
|
|
174
179
|
def groups_supported?
|
@@ -16,14 +16,13 @@ module Proxy::Phpipam
|
|
16
16
|
include Proxy::Ipam::IpamHelper
|
17
17
|
include Proxy::Ipam::IpamValidator
|
18
18
|
|
19
|
-
@ip_cache = nil
|
20
|
-
|
21
19
|
def initialize(conf)
|
22
20
|
@conf = conf
|
23
21
|
@api_base = "#{@conf[:url]}/api/#{@conf[:user]}/"
|
24
22
|
@token = authenticate
|
25
23
|
@api_resource = Proxy::Ipam::ApiResource.new(api_base: @api_base, token: @token, auth_header: 'Token')
|
26
|
-
@ip_cache = Proxy::Ipam::IpCache.
|
24
|
+
@ip_cache = Proxy::Ipam::IpCache.instance
|
25
|
+
@ip_cache.set_provider('phpipam')
|
27
26
|
end
|
28
27
|
|
29
28
|
def get_ipam_subnet(cidr, group_name = nil)
|
@@ -41,7 +40,7 @@ module Proxy::Phpipam
|
|
41
40
|
subnet_id = nil
|
42
41
|
|
43
42
|
subnets.each do |subnet|
|
44
|
-
subnet_cidr = subnet[:subnet]
|
43
|
+
subnet_cidr = "#{subnet[:subnet]}/#{subnet[:mask]}"
|
45
44
|
subnet_id = subnet[:id] if subnet_cidr == cidr
|
46
45
|
end
|
47
46
|
|
@@ -78,7 +77,7 @@ module Proxy::Phpipam
|
|
78
77
|
return nil if group_name.nil?
|
79
78
|
group = @api_resource.get("sections/#{group_name}/")
|
80
79
|
json_body = JSON.parse(group.body)
|
81
|
-
raise
|
80
|
+
raise ERRORS[:no_group] if json_body['data'].nil?
|
82
81
|
|
83
82
|
data = {
|
84
83
|
id: json_body['data']['id'],
|
@@ -92,7 +91,7 @@ module Proxy::Phpipam
|
|
92
91
|
def get_ipam_groups
|
93
92
|
groups = @api_resource.get('sections/')
|
94
93
|
json_body = JSON.parse(groups.body)
|
95
|
-
return
|
94
|
+
return [] if json_body['data'].nil?
|
96
95
|
|
97
96
|
data = []
|
98
97
|
json_body['data'].each do |group|
|
@@ -108,7 +107,7 @@ module Proxy::Phpipam
|
|
108
107
|
|
109
108
|
def get_ipam_subnets(group_name)
|
110
109
|
group = get_ipam_group(group_name)
|
111
|
-
raise
|
110
|
+
raise ERRORS[:no_group] if group.nil?
|
112
111
|
subnets = @api_resource.get("sections/#{group[:id]}/subnets/")
|
113
112
|
json_body = JSON.parse(subnets.body)
|
114
113
|
return nil if json_body['data'].nil?
|
@@ -149,12 +148,13 @@ module Proxy::Phpipam
|
|
149
148
|
|
150
149
|
def get_next_ip(mac, cidr, group_name)
|
151
150
|
subnet = get_ipam_subnet(cidr, group_name)
|
152
|
-
raise
|
151
|
+
raise ERRORS[:no_subnet] if subnet.nil?
|
153
152
|
response = @api_resource.get("subnets/#{subnet[:id]}/first_free/")
|
154
153
|
json_body = JSON.parse(response.body)
|
155
154
|
return { error: json_body['message'] } if json_body['message']
|
156
155
|
ip = json_body['data']
|
157
|
-
cache_next_ip(@ip_cache, ip, mac, cidr, subnet[:id], group_name)
|
156
|
+
next_ip = cache_next_ip(@ip_cache, ip, mac, cidr, subnet[:id], group_name)
|
157
|
+
{ data: next_ip }
|
158
158
|
end
|
159
159
|
|
160
160
|
def groups_supported?
|
@@ -168,7 +168,7 @@ module Proxy::Phpipam
|
|
168
168
|
private
|
169
169
|
|
170
170
|
def authenticate
|
171
|
-
auth_uri = URI(@api_base
|
171
|
+
auth_uri = URI("#{@api_base}/user/")
|
172
172
|
request = Net::HTTP::Post.new(auth_uri)
|
173
173
|
request.basic_auth @conf[:user], @conf[:password]
|
174
174
|
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_proxy_ipam
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Smart proxy plugin for
|
13
|
+
description: Smart proxy plugin for integration with various External IPAM providers
|
14
14
|
email: chrisjsmith001@gmail.com
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
@@ -60,5 +60,5 @@ requirements: []
|
|
60
60
|
rubygems_version: 3.0.6
|
61
61
|
signing_key:
|
62
62
|
specification_version: 4
|
63
|
-
summary: Smart proxy plugin for
|
63
|
+
summary: Smart proxy plugin for integration with External IPAM providers
|
64
64
|
test_files: []
|