smart_proxy_ipam 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|