smart_proxy_ipam 0.0.20 → 0.1.2

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.20'
3
+ VERSION = '0.1.2'.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.20
4
+ version: 0.1.2
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-05 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,377 +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
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
38
-
39
- return {:code => subnet['code'], :error => subnet['error']}.to_json if no_subnets_found?(subnet)
40
-
41
- ipaddr = phpipam_client.get_next_ip(subnet['data']['id'], mac, cidr, section_name)
42
- ipaddr_parsed = JSON.parse(ipaddr)
43
-
44
- return {:code => 404, :error => ipaddr_parsed['error']}.to_json if no_free_ip_found?(ipaddr_parsed)
45
-
46
- ipaddr
47
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
48
- logger.debug(errors[:no_connection])
49
- raise
50
- end
51
- end
52
-
53
- # Gets the subnet from phpIPAM
54
- #
55
- # Inputs: address: Network address of the subnet
56
- # prefix: Network prefix(e.g. 24)
57
- #
58
- # Returns: JSON with "data" key on success, or JSON with "error" key when there is an error
59
- #
60
- # Examples:
61
- # Response if subnet exists:
62
- # {
63
- # "code":200,"success":true,"data":[{"id":"12","subnet":"100.30.30.0","mask":"24",
64
- # "sectionId":"5", "description":"Test Subnet","linked_subnet":null,"firewallAddressObject":null,
65
- # "vrfId":"0","masterSubnetId":"0","allowRequests":"0","vlanId":"0","showName":"0","device":"0",
66
- # "permissions":"[]","pingSubnet":"0","discoverSubnet":"0","DNSrecursive":"0","DNSrecords":"0",
67
- # "nameserverId":"0","scanAgent":"0","isFolder":"0","isFull":"0","tag":"2","threshold":"0",
68
- # "location":"0","editDate":null,"lastScan":null,"lastDiscovery":null}],"time":0.009
69
- # }
70
- #
71
- # Response if subnet not exists):
72
- # {
73
- # "code":200,"success":0,"message":"No subnets found","time":0.01
74
- # }
75
- get '/subnet/:address/:prefix' do
76
- content_type :json
77
-
78
- begin
79
- err = validate_required_params(["address", "prefix"], params)
80
- return err if err.length > 0
81
-
82
- cidr = params[:address] + '/' + params[:prefix]
83
-
84
- phpipam_client = PhpipamClient.new
85
- phpipam_client.get_subnet(cidr)
86
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
87
- logger.debug(errors[:no_connection])
88
- raise
89
- end
90
- end
91
-
92
- # Get a list of sections from external ipam
93
- #
94
- # Input: None
95
- # Returns: An array of sections on success, hash with "error" key otherwise
96
- # Examples
97
- # Response if success: [
98
- # {"id":"5","name":"Awesome Section","description":"A totally awesome Section","masterSection":"0",
99
- # "permissions":"[]","strictMode":"1","subnetOrdering":"default","order":null,
100
- # "editDate":"2019-04-19 21:49:55","showVLAN":"1","showVRF":"1","showSupernetOnly":"1","DNS":null}]
101
- # ]
102
- # Response if :error =>
103
- # {"error":"Unable to connect to phpIPAM server"}
104
- get '/groups' do
105
- content_type :json
106
-
107
- begin
108
- phpipam_client = PhpipamClient.new
109
- sections = phpipam_client.get_sections
110
- return {:code => 200, :data => []}.to_json if no_sections_found?(JSON.parse(sections))
111
- sections
112
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
113
- logger.debug(errors[:no_connection])
114
- raise
115
- end
116
- end
117
-
118
- # Get a single sections from external ipam
119
- #
120
- # Input: Section name
121
- # Returns: A JSON section on success, hash with "error" key otherwise
122
- # Examples
123
- # Response if success:
124
- # {"code":200,"success":true,"data":{"id":"80","name":"Development #1","description":null,
125
- # "masterSection":"0","permissions":"[]","strictMode":"1","subnetOrdering":"default","order":null,
126
- # "editDate":"2020-02-11 10:57:01","showVLAN":"1","showVRF":"1","showSupernetOnly":"1","DNS":null},"time":0.004}
127
- # Response if not found:
128
- # {"code":404,"error":"Not Found"}
129
- # Response if :error =>
130
- # {"error":"Unable to connect to phpIPAM server"}
131
- get '/groups/:group' do
132
- content_type :json
133
-
134
- begin
135
- err = validate_required_params(["group"], params)
136
- return err if err.length > 0
137
-
138
- phpipam_client = PhpipamClient.new
139
- section = JSON.parse(phpipam_client.get_section(params[:group]))
140
-
141
- return {:code => section['code'], :message => section['message']}.to_json if no_section_found?(section)
142
- section.to_json
143
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
144
- logger.debug(errors[:no_connection])
145
- raise
146
- end
147
- end
148
-
149
- # Get a list of subnets for given external ipam section/group
150
- #
151
- # Input: section_name(string). The name of the external ipam section/group
152
- # Returns: Array of subnets(as json) in "data" key on success, hash with error otherwise
153
- # Examples:
154
- # Response if success:
155
- # {
156
- # "code":200,
157
- # "success":true,
158
- # "data":[
159
- # {
160
- # "id":"24",
161
- # "subnet":"100.10.10.0",
162
- # "mask":"24",
163
- # "sectionId":"10",
164
- # "description":"wrgwgwefwefw",
165
- # "linked_subnet":null,
166
- # "firewallAddressObject":null,
167
- # "vrfId":"0",
168
- # "masterSubnetId":"0",
169
- # "allowRequests":"0",
170
- # "vlanId":"0",
171
- # "showName":"0",
172
- # "device":"0",
173
- # "permissions":"[]",
174
- # "pingSubnet":"0",
175
- # "discoverSubnet":"0",
176
- # "DNSrecursive":"0",
177
- # "DNSrecords":"0",
178
- # "nameserverId":"0",
179
- # "scanAgent":"0",
180
- # "isFolder":"0",
181
- # "isFull":"0",
182
- # "tag":"2",
183
- # "threshold":"0",
184
- # "location":"0",
185
- # "editDate":null,
186
- # "lastScan":null,
187
- # "lastDiscovery":null,
188
- # "usage":{
189
- # "used":"0",
190
- # "maxhosts":"254",
191
- # "freehosts":"254",
192
- # "freehosts_percent":100,
193
- # "Offline_percent":0,
194
- # "Used_percent":0,
195
- # "Reserved_percent":0,
196
- # "DHCP_percent":0
197
- # }
198
- # }
199
- # ],
200
- # "time":0.012
201
- # }
202
- # Response if :error =>
203
- # {"error":"Unable to connect to External IPAM server"}
204
- get '/groups/:group/subnets' do
205
- content_type :json
206
-
207
- begin
208
- err = validate_required_params(["group"], params)
209
- return err if err.length > 0
210
-
211
- phpipam_client = PhpipamClient.new
212
- section = JSON.parse(phpipam_client.get_section(params[:group]))
213
-
214
- return {:code => 404, :error => errors[:no_section]}.to_json if no_section_found?(section)
215
-
216
- phpipam_client.get_subnets(section['data']['id'].to_s, false)
217
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
218
- logger.debug(errors[:no_connection])
219
- raise
220
- end
221
- end
222
-
223
- # Checks whether an IP address has already been taken in external ipam.
224
- #
225
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
226
- # 2. prefix: The subnet prefix(e.g. 24)
227
- # 3. ip: IP address to be queried
228
- #
229
- # Returns: JSON object with 'exists' field being either true or false
230
- #
231
- # Example:
232
- # Response if exists:
233
- # {"ip":"100.20.20.18","exists":true}
234
- # Response if not exists:
235
- # {"ip":"100.20.20.18","exists":false}
236
- get '/subnet/:address/:prefix/:ip' do
237
- content_type :json
238
-
239
- begin
240
- err = validate_required_params(["address", "prefix", "ip"], params)
241
- return err if err.length > 0
242
-
243
- ip = params[:ip]
244
- cidr = params[:address] + '/' + params[:prefix]
245
- section_name = params[:group]
246
- phpipam_client = PhpipamClient.new
247
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
248
-
249
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
250
-
251
- ip_exists = JSON.parse(phpipam_client.ip_exists(ip, subnet['data']['id']))
252
-
253
- if ip_exists['data']
254
- return {:code => 200, :exists => true}.to_json
255
- else
256
- return {:code => 404, :exists => false}.to_json
257
- end
258
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
259
- logger.debug(errors[:no_connection])
260
- raise
261
- end
262
- end
263
-
264
- # Adds an IP address to the specified subnet
265
- #
266
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
267
- # 2. prefix: The subnet prefix(e.g. 24)
268
- # 3. ip: IP address to be added
269
- #
270
- # Returns: Hash with "message" on success, or hash with "error"
271
- #
272
- # Examples:
273
- # Response if success:
274
- # IPv4: {"message":"IP 100.10.10.123 added to subnet 100.10.10.0/24 successfully."}
275
- # IPv6: {"message":"IP 2001:db8:abcd:12::3 added to subnet 2001:db8:abcd:12::/124 successfully."}
276
- # Response if :error =>
277
- # {"error":"The specified subnet does not exist in phpIPAM."}
278
- post '/subnet/:address/:prefix/:ip' do
279
- content_type :json
280
-
281
- begin
282
- err = validate_required_params(["address", "ip", "prefix"], params)
283
- return err if err.length > 0
284
-
285
- ip = params[:ip]
286
- cidr = params[:address] + '/' + params[:prefix]
287
- section_name = URI.escape(params[:group])
288
-
289
- phpipam_client = PhpipamClient.new
290
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
291
-
292
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
293
-
294
- add_ip = JSON.parse(phpipam_client.add_ip_to_subnet(ip, subnet['data']['id'], 'Address auto added by Foreman'))
295
-
296
- if add_ip['message'] && add_ip['message'] == "Address created"
297
- return {:code => 200}.to_json
298
- else
299
- return {:code => 500, :error => add_ip['message']}.to_json
300
- end
301
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
302
- logger.debug(errors[:no_connection])
303
- raise
304
- end
305
- end
306
-
307
- # Deletes IP address from a given subnet
308
- #
309
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
310
- # 2. prefix: The subnet prefix(e.g. 24)
311
- # 3. ip: IP address to be deleted
312
- #
313
- # Returns: JSON object
314
- # Example:
315
- # Response if success:
316
- # {"code": 200, "success": true, "message": "Address deleted", "time": 0.017}
317
- # Response if :error =>
318
- # {"code": 404, "success": 0, "message": "Address does not exist", "time": 0.008}
319
- delete '/subnet/:address/:prefix/:ip' do
320
- content_type :json
321
-
322
- begin
323
- err = validate_required_params(["address", "prefix", "ip"], params)
324
- return err if err.length > 0
325
-
326
- ip = params[:ip]
327
- cidr = params[:address] + '/' + params[:prefix]
328
- section_name = URI.escape(params[:group])
329
- phpipam_client = PhpipamClient.new
330
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
331
-
332
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
333
-
334
- delete_ip = JSON.parse(phpipam_client.delete_ip_from_subnet(ip, subnet['data']['id']))
335
-
336
- if delete_ip['message'] && delete_ip['message'] == "Address deleted"
337
- return {:code => 200}.to_json
338
- else
339
- return {:code => 500, :error => delete_ip['message']}.to_json
340
- end
341
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
342
- logger.debug(errors[:no_connection])
343
- raise
344
- end
345
- end
346
-
347
- # Checks whether a subnet exists in a specific section.
348
- #
349
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
350
- # 2. prefix: The subnet prefix(e.g. 24)
351
- # 3. group: The name of the section
352
- #
353
- # Returns: JSON object with 'data' field is exists, otherwise field with 'error'
354
- #
355
- # Example:
356
- # Response if exists:
357
- # {"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}
358
- # Response if not exists:
359
- # {"code":404,"error":"No subnet 172.66.66.0/29 found in section :group"}
360
- get '/group/:group/subnet/:address/:prefix' do
361
- content_type :json
362
-
363
- begin
364
- err = validate_required_params(["address", "prefix", "group"], params)
365
- return err if err.length > 0
366
-
367
- cidr = params[:address] + '/' + params[:prefix]
368
-
369
- phpipam_client = PhpipamClient.new
370
- phpipam_client.get_subnet_by_section(cidr, params[:group])
371
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
372
- logger.debug(errors[:no_connection])
373
- raise
374
- end
375
- end
376
- end
377
- end