smart_proxy_ipam 0.0.21 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ module Proxy::Phpipam
2
+ class Plugin < ::Proxy::Provider
3
+ plugin :externalipam_phpipam, Proxy::Ipam::VERSION
4
+
5
+ requires :externalipam, Proxy::Ipam::VERSION
6
+ validate :url, url: true
7
+ validate_presence :user, :password
8
+
9
+ load_classes(proc do
10
+ require 'smart_proxy_ipam/phpipam/phpipam_client'
11
+ end)
12
+
13
+ load_dependency_injection_wirings(proc do |container_instance, settings|
14
+ container_instance.dependency :externalipam_client, -> { ::Proxy::Phpipam::PhpipamClient.new(settings) }
15
+ end)
16
+ end
17
+ end
@@ -1,6 +1,5 @@
1
-
2
1
  module Proxy
3
2
  module Ipam
4
- VERSION = '0.0.21'
3
+ VERSION = '0.1.3'.freeze
5
4
  end
6
5
  end
@@ -1,8 +1,3 @@
1
1
  ---
2
2
  :enabled: true
3
-
4
- :externalipam:
5
- :phpipam:
6
- :url: 'http://phpipam.example.com'
7
- :user: 'phpipam_api_user'
8
- :password: 'phpipam_password'
3
+ :use_provider: externalipam_phpipam
@@ -0,0 +1,3 @@
1
+ ---
2
+ :url: 'https://netbox.example.com'
3
+ :token: 'netbox_api_token'
@@ -0,0 +1,4 @@
1
+ ---
2
+ :url: 'http://phpipam.example.com'
3
+ :user: 'phpipam_api_user'
4
+ :password: 'phpipam_password'
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.0.21
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Smith
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-11 00:00:00.000000000 Z
11
+ date: 2020-12-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Smart proxy plugin for IPAM integration with various IPAM providers
13
+ description: Smart proxy plugin for integration with various External IPAM providers
14
14
  email: chrisjsmith001@gmail.com
15
15
  executables: []
16
16
  extensions: []
@@ -22,19 +22,27 @@ files:
22
22
  - README.md
23
23
  - bundler.d/ipam.rb
24
24
  - lib/smart_proxy_ipam.rb
25
+ - lib/smart_proxy_ipam/api_resource.rb
26
+ - lib/smart_proxy_ipam/dependency_injection.rb
27
+ - lib/smart_proxy_ipam/ip_cache.rb
25
28
  - lib/smart_proxy_ipam/ipam.rb
29
+ - lib/smart_proxy_ipam/ipam_api.rb
30
+ - lib/smart_proxy_ipam/ipam_helper.rb
26
31
  - lib/smart_proxy_ipam/ipam_http_config.ru
27
- - lib/smart_proxy_ipam/ipam_main.rb
28
- - lib/smart_proxy_ipam/phpipam/phpipam_api.rb
32
+ - lib/smart_proxy_ipam/ipam_validator.rb
33
+ - lib/smart_proxy_ipam/netbox/netbox_client.rb
34
+ - lib/smart_proxy_ipam/netbox/netbox_plugin.rb
29
35
  - lib/smart_proxy_ipam/phpipam/phpipam_client.rb
30
- - lib/smart_proxy_ipam/phpipam/phpipam_helper.rb
36
+ - lib/smart_proxy_ipam/phpipam/phpipam_plugin.rb
31
37
  - lib/smart_proxy_ipam/version.rb
32
38
  - settings.d/externalipam.yml.example
39
+ - settings.d/externalipam_netbox.yml.example
40
+ - settings.d/externalipam_phpipam.yml.example
33
41
  homepage: http://github.com/grizzthedj/smart_proxy_ipam
34
42
  licenses:
35
43
  - GPL-3.0
36
44
  metadata: {}
37
- post_install_message:
45
+ post_install_message:
38
46
  rdoc_options: []
39
47
  require_paths:
40
48
  - lib
@@ -42,7 +50,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
50
  requirements:
43
51
  - - ">="
44
52
  - !ruby/object:Gem::Version
45
- version: '0'
53
+ version: '2.5'
46
54
  required_rubygems_version: !ruby/object:Gem::Requirement
47
55
  requirements:
48
56
  - - ">="
@@ -50,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
58
  version: '0'
51
59
  requirements: []
52
60
  rubygems_version: 3.0.6
53
- signing_key:
61
+ signing_key:
54
62
  specification_version: 4
55
- summary: Smart proxy plugin for IPAM integration with various IPAM providers
63
+ summary: Smart proxy plugin for integration with External IPAM providers
56
64
  test_files: []
@@ -1,11 +0,0 @@
1
-
2
- module Proxy::Ipam
3
- extend ::Proxy::Util
4
- extend ::Proxy::Log
5
-
6
- class << self
7
- def get_config
8
- Proxy::Ipam::Plugin.settings.externalipam
9
- end
10
- end
11
- end
@@ -1,393 +0,0 @@
1
- require 'sinatra'
2
- require 'smart_proxy_ipam/ipam'
3
- require 'smart_proxy_ipam/ipam_main'
4
- require 'smart_proxy_ipam/phpipam/phpipam_client'
5
- require 'smart_proxy_ipam/phpipam/phpipam_helper'
6
-
7
- # TODO: Refactor later to handle multiple IPAM providers. For now, it is
8
- # just phpIPAM that is supported
9
- module Proxy::Phpipam
10
- class Api < ::Sinatra::Base
11
- include ::Proxy::Log
12
- helpers ::Proxy::Helpers
13
- helpers PhpipamHelper
14
-
15
- # Gets the next available IP address based on a given subnet
16
- #
17
- # Inputs: address: Network address of the subnet(e.g. 100.55.55.0)
18
- # prefix: Network prefix(e.g. 24)
19
- #
20
- # Returns: Hash with next available IP address in "data", or hash with "message" containing
21
- # error message from phpIPAM.
22
- #
23
- # Response if success:
24
- # {"code": 200, "success": true, "data": "100.55.55.3", "time": 0.012}
25
- get '/subnet/:address/:prefix/next_ip' do
26
- content_type :json
27
-
28
- begin
29
- err = validate_required_params(["address", "prefix", "mac"], params)
30
- return err if err.length > 0
31
-
32
- mac = params[:mac]
33
- cidr = params[:address] + '/' + params[:prefix]
34
- section_name = params[:group]
35
-
36
- phpipam_client = PhpipamClient.new
37
- return auth_error unless phpipam_client.authenticated?
38
-
39
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
40
-
41
- return {:code => subnet['code'], :error => subnet['error']}.to_json if no_subnets_found?(subnet)
42
-
43
- ipaddr = phpipam_client.get_next_ip(subnet['data']['id'], mac, cidr, section_name)
44
- ipaddr_parsed = JSON.parse(ipaddr)
45
-
46
- return {:code => 404, :error => ipaddr_parsed['error']}.to_json if no_free_ip_found?(ipaddr_parsed)
47
-
48
- ipaddr
49
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
50
- logger.debug(errors[:no_connection])
51
- raise
52
- end
53
- end
54
-
55
- # Gets the subnet from phpIPAM
56
- #
57
- # Inputs: address: Network address of the subnet
58
- # prefix: Network prefix(e.g. 24)
59
- #
60
- # Returns: JSON with "data" key on success, or JSON with "error" key when there is an error
61
- #
62
- # Examples:
63
- # Response if subnet exists:
64
- # {
65
- # "code":200,"success":true,"data":[{"id":"12","subnet":"100.30.30.0","mask":"24",
66
- # "sectionId":"5", "description":"Test Subnet","linked_subnet":null,"firewallAddressObject":null,
67
- # "vrfId":"0","masterSubnetId":"0","allowRequests":"0","vlanId":"0","showName":"0","device":"0",
68
- # "permissions":"[]","pingSubnet":"0","discoverSubnet":"0","DNSrecursive":"0","DNSrecords":"0",
69
- # "nameserverId":"0","scanAgent":"0","isFolder":"0","isFull":"0","tag":"2","threshold":"0",
70
- # "location":"0","editDate":null,"lastScan":null,"lastDiscovery":null}],"time":0.009
71
- # }
72
- #
73
- # Response if subnet not exists):
74
- # {
75
- # "code":200,"success":0,"message":"No subnets found","time":0.01
76
- # }
77
- get '/subnet/:address/:prefix' do
78
- content_type :json
79
-
80
- begin
81
- err = validate_required_params(["address", "prefix"], params)
82
- return err if err.length > 0
83
-
84
- cidr = params[:address] + '/' + params[:prefix]
85
-
86
- phpipam_client = PhpipamClient.new
87
- return auth_error unless phpipam_client.authenticated?
88
-
89
- phpipam_client.get_subnet(cidr)
90
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
91
- logger.debug(errors[:no_connection])
92
- raise
93
- end
94
- end
95
-
96
- # Get a list of sections from external ipam
97
- #
98
- # Input: None
99
- # Returns: An array of sections on success, hash with "error" key otherwise
100
- # Examples
101
- # Response if success: [
102
- # {"id":"5","name":"Awesome Section","description":"A totally awesome Section","masterSection":"0",
103
- # "permissions":"[]","strictMode":"1","subnetOrdering":"default","order":null,
104
- # "editDate":"2019-04-19 21:49:55","showVLAN":"1","showVRF":"1","showSupernetOnly":"1","DNS":null}]
105
- # ]
106
- # Response if :error =>
107
- # {"error":"Unable to connect to phpIPAM server"}
108
- get '/groups' do
109
- content_type :json
110
-
111
- begin
112
- phpipam_client = PhpipamClient.new
113
- return auth_error unless phpipam_client.authenticated?
114
-
115
- sections = phpipam_client.get_sections
116
- return {:code => 200, :data => []}.to_json if no_sections_found?(JSON.parse(sections))
117
-
118
- sections
119
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
120
- logger.debug(errors[:no_connection])
121
- raise
122
- end
123
- end
124
-
125
- # Get a single sections from external ipam
126
- #
127
- # Input: Section name
128
- # Returns: A JSON section on success, hash with "error" key otherwise
129
- # Examples
130
- # Response if success:
131
- # {"code":200,"success":true,"data":{"id":"80","name":"Development #1","description":null,
132
- # "masterSection":"0","permissions":"[]","strictMode":"1","subnetOrdering":"default","order":null,
133
- # "editDate":"2020-02-11 10:57:01","showVLAN":"1","showVRF":"1","showSupernetOnly":"1","DNS":null},"time":0.004}
134
- # Response if not found:
135
- # {"code":404,"error":"Not Found"}
136
- # Response if :error =>
137
- # {"error":"Unable to connect to phpIPAM server"}
138
- get '/groups/:group' do
139
- content_type :json
140
-
141
- begin
142
- err = validate_required_params(["group"], params)
143
- return err if err.length > 0
144
-
145
- phpipam_client = PhpipamClient.new
146
- return auth_error unless phpipam_client.authenticated?
147
-
148
- section = JSON.parse(phpipam_client.get_section(params[:group]))
149
- return {:code => section['code'], :message => section['message']}.to_json if no_section_found?(section)
150
-
151
- section.to_json
152
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
153
- logger.debug(errors[:no_connection])
154
- raise
155
- end
156
- end
157
-
158
- # Get a list of subnets for given external ipam section/group
159
- #
160
- # Input: section_name(string). The name of the external ipam section/group
161
- # Returns: Array of subnets(as json) in "data" key on success, hash with error otherwise
162
- # Examples:
163
- # Response if success:
164
- # {
165
- # "code":200,
166
- # "success":true,
167
- # "data":[
168
- # {
169
- # "id":"24",
170
- # "subnet":"100.10.10.0",
171
- # "mask":"24",
172
- # "sectionId":"10",
173
- # "description":"wrgwgwefwefw",
174
- # "linked_subnet":null,
175
- # "firewallAddressObject":null,
176
- # "vrfId":"0",
177
- # "masterSubnetId":"0",
178
- # "allowRequests":"0",
179
- # "vlanId":"0",
180
- # "showName":"0",
181
- # "device":"0",
182
- # "permissions":"[]",
183
- # "pingSubnet":"0",
184
- # "discoverSubnet":"0",
185
- # "DNSrecursive":"0",
186
- # "DNSrecords":"0",
187
- # "nameserverId":"0",
188
- # "scanAgent":"0",
189
- # "isFolder":"0",
190
- # "isFull":"0",
191
- # "tag":"2",
192
- # "threshold":"0",
193
- # "location":"0",
194
- # "editDate":null,
195
- # "lastScan":null,
196
- # "lastDiscovery":null,
197
- # "usage":{
198
- # "used":"0",
199
- # "maxhosts":"254",
200
- # "freehosts":"254",
201
- # "freehosts_percent":100,
202
- # "Offline_percent":0,
203
- # "Used_percent":0,
204
- # "Reserved_percent":0,
205
- # "DHCP_percent":0
206
- # }
207
- # }
208
- # ],
209
- # "time":0.012
210
- # }
211
- # Response if :error =>
212
- # {"error":"Unable to connect to External IPAM server"}
213
- get '/groups/:group/subnets' do
214
- content_type :json
215
-
216
- begin
217
- err = validate_required_params(["group"], params)
218
- return err if err.length > 0
219
-
220
- phpipam_client = PhpipamClient.new
221
- return auth_error unless phpipam_client.authenticated?
222
-
223
- section = JSON.parse(phpipam_client.get_section(params[:group]))
224
- return {:code => 404, :error => errors[:no_section]}.to_json if no_section_found?(section)
225
-
226
- phpipam_client.get_subnets(section['data']['id'].to_s, false)
227
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
228
- logger.debug(errors[:no_connection])
229
- raise
230
- end
231
- end
232
-
233
- # Checks whether an IP address has already been taken in external ipam.
234
- #
235
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
236
- # 2. prefix: The subnet prefix(e.g. 24)
237
- # 3. ip: IP address to be queried
238
- #
239
- # Returns: JSON object with 'exists' field being either true or false
240
- #
241
- # Example:
242
- # Response if exists:
243
- # {"ip":"100.20.20.18","exists":true}
244
- # Response if not exists:
245
- # {"ip":"100.20.20.18","exists":false}
246
- get '/subnet/:address/:prefix/:ip' do
247
- content_type :json
248
-
249
- begin
250
- err = validate_required_params(["address", "prefix", "ip"], params)
251
- return err if err.length > 0
252
-
253
- ip = params[:ip]
254
- cidr = params[:address] + '/' + params[:prefix]
255
- section_name = params[:group]
256
-
257
- phpipam_client = PhpipamClient.new
258
- return auth_error unless phpipam_client.authenticated?
259
-
260
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
261
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
262
-
263
- ip_exists = JSON.parse(phpipam_client.ip_exists(ip, subnet['data']['id']))
264
-
265
- if ip_exists['data']
266
- return {:code => 200, :exists => true}.to_json
267
- else
268
- return {:code => 404, :exists => false}.to_json
269
- end
270
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
271
- logger.debug(errors[:no_connection])
272
- raise
273
- end
274
- end
275
-
276
- # Adds an IP address to the specified subnet
277
- #
278
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
279
- # 2. prefix: The subnet prefix(e.g. 24)
280
- # 3. ip: IP address to be added
281
- #
282
- # Returns: Hash with "message" on success, or hash with "error"
283
- #
284
- # Examples:
285
- # Response if success:
286
- # IPv4: {"message":"IP 100.10.10.123 added to subnet 100.10.10.0/24 successfully."}
287
- # IPv6: {"message":"IP 2001:db8:abcd:12::3 added to subnet 2001:db8:abcd:12::/124 successfully."}
288
- # Response if :error =>
289
- # {"error":"The specified subnet does not exist in phpIPAM."}
290
- post '/subnet/:address/:prefix/:ip' do
291
- content_type :json
292
-
293
- begin
294
- err = validate_required_params(["address", "ip", "prefix"], params)
295
- return err if err.length > 0
296
-
297
- ip = params[:ip]
298
- cidr = params[:address] + '/' + params[:prefix]
299
- section_name = URI.escape(params[:group])
300
-
301
- phpipam_client = PhpipamClient.new
302
- return auth_error unless phpipam_client.authenticated?
303
-
304
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
305
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
306
-
307
- add_ip = JSON.parse(phpipam_client.add_ip_to_subnet(ip, subnet['data']['id'], 'Address auto added by Foreman'))
308
-
309
- if add_ip['message'] && add_ip['message'] == "Address created"
310
- return {:code => 200}.to_json
311
- else
312
- return {:code => 500, :error => add_ip['message']}.to_json
313
- end
314
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
315
- logger.debug(errors[:no_connection])
316
- raise
317
- end
318
- end
319
-
320
- # Deletes IP address from a given subnet
321
- #
322
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
323
- # 2. prefix: The subnet prefix(e.g. 24)
324
- # 3. ip: IP address to be deleted
325
- #
326
- # Returns: JSON object
327
- # Example:
328
- # Response if success:
329
- # {"code": 200, "success": true, "message": "Address deleted", "time": 0.017}
330
- # Response if :error =>
331
- # {"code": 404, "success": 0, "message": "Address does not exist", "time": 0.008}
332
- delete '/subnet/:address/:prefix/:ip' do
333
- content_type :json
334
-
335
- begin
336
- err = validate_required_params(["address", "prefix", "ip"], params)
337
- return err if err.length > 0
338
-
339
- ip = params[:ip]
340
- cidr = params[:address] + '/' + params[:prefix]
341
- section_name = URI.escape(params[:group])
342
- phpipam_client = PhpipamClient.new
343
- return auth_error unless phpipam_client.authenticated?
344
-
345
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
346
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
347
-
348
- delete_ip = JSON.parse(phpipam_client.delete_ip_from_subnet(ip, subnet['data']['id']))
349
-
350
- if delete_ip['message'] && delete_ip['message'] == "Address deleted"
351
- return {:code => 200}.to_json
352
- else
353
- return {:code => 500, :error => delete_ip['message']}.to_json
354
- end
355
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
356
- logger.debug(errors[:no_connection])
357
- raise
358
- end
359
- end
360
-
361
- # Checks whether a subnet exists in a specific section.
362
- #
363
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
364
- # 2. prefix: The subnet prefix(e.g. 24)
365
- # 3. group: The name of the section
366
- #
367
- # Returns: JSON object with 'data' field is exists, otherwise field with 'error'
368
- #
369
- # Example:
370
- # Response if exists:
371
- # {"code":200,"success":true,"data":{"id":"147","subnet":"172.55.55.0","mask":"29","sectionId":"84","description":null,"linked_subnet":null,"firewallAddressObject":null,"vrfId":"0","masterSubnetId":"0","allowRequests":"0","vlanId":"0","showName":"0","device":"0","permissions":"[]","pingSubnet":"0","discoverSubnet":"0","resolveDNS":"0","DNSrecursive":"0","DNSrecords":"0","nameserverId":"0","scanAgent":"0","customer_id":null,"isFolder":"0","isFull":"0","tag":"2","threshold":"0","location":"0","editDate":null,"lastScan":null,"lastDiscovery":null,"calculation":{"Type":"IPv4","IP address":"\/","Network":"172.55.55.0","Broadcast":"172.55.55.7","Subnet bitmask":"29","Subnet netmask":"255.255.255.248","Subnet wildcard":"0.0.0.7","Min host IP":"172.55.55.1","Max host IP":"172.55.55.6","Number of hosts":"6","Subnet Class":false}},"time":0.009}
372
- # Response if not exists:
373
- # {"code":404,"error":"No subnet 172.66.66.0/29 found in section :group"}
374
- get '/group/:group/subnet/:address/:prefix' do
375
- content_type :json
376
-
377
- begin
378
- err = validate_required_params(["address", "prefix", "group"], params)
379
- return err if err.length > 0
380
-
381
- cidr = params[:address] + '/' + params[:prefix]
382
-
383
- phpipam_client = PhpipamClient.new
384
- return auth_error unless phpipam_client.authenticated?
385
-
386
- phpipam_client.get_subnet_by_section(cidr, params[:group])
387
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
388
- logger.debug(errors[:no_connection])
389
- raise
390
- end
391
- end
392
- end
393
- end