smart_proxy_ipam 0.0.22 → 0.1.4

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.
@@ -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.22'
3
+ VERSION = '0.1.4'.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.22
4
+ version: 0.1.4
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-19 00:00:00.000000000 Z
11
+ date: 2021-01-12 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,396 +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 {: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 {: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 {: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 section 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 {}.to_json if no_section_found?(section)
150
-
151
- section['data'].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 {: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 {:error => subnet['error']}.to_json if no_subnets_found?(subnet)
262
-
263
- response = phpipam_client.ip_exists(ip, subnet['data']['id'])
264
- ip_exists = JSON.parse(response.body)
265
-
266
- if ip_exists['data']
267
- return Net::HTTPFound.new('HTTP/1.1', 200, 'Found').to_json
268
- else
269
- return Net::HTTPNotFound.new('HTTP/1.1', 404, 'Not Found').to_json
270
- end
271
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
272
- logger.debug(errors[:no_connection])
273
- raise
274
- end
275
- end
276
-
277
- # Adds an IP address to the specified subnet
278
- #
279
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
280
- # 2. prefix: The subnet prefix(e.g. 24)
281
- # 3. ip: IP address to be added
282
- #
283
- # Returns: Hash with "message" on success, or hash with "error"
284
- #
285
- # Examples:
286
- # Response if success:
287
- # IPv4: {"message":"IP 100.10.10.123 added to subnet 100.10.10.0/24 successfully."}
288
- # IPv6: {"message":"IP 2001:db8:abcd:12::3 added to subnet 2001:db8:abcd:12::/124 successfully."}
289
- # Response if :error =>
290
- # {"error":"The specified subnet does not exist in phpIPAM."}
291
- post '/subnet/:address/:prefix/:ip' do
292
- content_type :json
293
-
294
- begin
295
- err = validate_required_params(["address", "ip", "prefix"], params)
296
- return err if err.length > 0
297
-
298
- ip = params[:ip]
299
- cidr = params[:address] + '/' + params[:prefix]
300
- section_name = URI.escape(params[:group])
301
-
302
- phpipam_client = PhpipamClient.new
303
- return auth_error unless phpipam_client.authenticated?
304
-
305
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
306
- return {:error => subnet['error']}.to_json if no_subnets_found?(subnet)
307
-
308
- response = phpipam_client.add_ip_to_subnet(ip, subnet['data']['id'], 'Address auto added by Foreman')
309
- add_ip = JSON.parse(response.body)
310
-
311
- if add_ip['message'] && add_ip['message'] == "Address created"
312
- return Net::HTTPCreated.new('HTTP/1.1', 201, 'Created').to_json
313
- else
314
- return {:error => add_ip['message']}.to_json
315
- end
316
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
317
- logger.debug(errors[:no_connection])
318
- raise
319
- end
320
- end
321
-
322
- # Deletes IP address from a given subnet
323
- #
324
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
325
- # 2. prefix: The subnet prefix(e.g. 24)
326
- # 3. ip: IP address to be deleted
327
- #
328
- # Returns: JSON object
329
- # Example:
330
- # Response if success:
331
- # {"code": 200, "success": true, "message": "Address deleted", "time": 0.017}
332
- # Response if :error =>
333
- # {"code": 404, "success": 0, "message": "Address does not exist", "time": 0.008}
334
- delete '/subnet/:address/:prefix/:ip' do
335
- content_type :json
336
-
337
- begin
338
- err = validate_required_params(["address", "prefix", "ip"], params)
339
- return err if err.length > 0
340
-
341
- ip = params[:ip]
342
- cidr = params[:address] + '/' + params[:prefix]
343
- section_name = URI.escape(params[:group])
344
- phpipam_client = PhpipamClient.new
345
- return auth_error unless phpipam_client.authenticated?
346
-
347
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
348
- return {:error => subnet['error']}.to_json if no_subnets_found?(subnet)
349
-
350
- response = phpipam_client.delete_ip_from_subnet(ip, subnet['data']['id'])
351
- delete_ip = JSON.parse(response.body)
352
-
353
- if delete_ip['message'] && delete_ip['message'] == "Address deleted"
354
- return Net::HTTPOK.new('HTTP/1.1', 200, 'Address Deleted').to_json
355
- else
356
- return {:error => delete_ip['message']}.to_json
357
- end
358
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
359
- logger.debug(errors[:no_connection])
360
- raise
361
- end
362
- end
363
-
364
- # Checks whether a subnet exists in a specific section.
365
- #
366
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
367
- # 2. prefix: The subnet prefix(e.g. 24)
368
- # 3. group: The name of the section
369
- #
370
- # Returns: JSON object with 'data' field is exists, otherwise field with 'error'
371
- #
372
- # Example:
373
- # Response if exists:
374
- # {"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}
375
- # Response if not exists:
376
- # {"code":404,"error":"No subnet 172.66.66.0/29 found in section :group"}
377
- get '/group/:group/subnet/:address/:prefix' do
378
- content_type :json
379
-
380
- begin
381
- err = validate_required_params(["address", "prefix", "group"], params)
382
- return err if err.length > 0
383
-
384
- cidr = params[:address] + '/' + params[:prefix]
385
-
386
- phpipam_client = PhpipamClient.new
387
- return auth_error unless phpipam_client.authenticated?
388
-
389
- phpipam_client.get_subnet_by_section(cidr, params[:group])
390
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
391
- logger.debug(errors[:no_connection])
392
- raise
393
- end
394
- end
395
- end
396
- end