smart_proxy_ipam 0.0.20 → 0.1.2

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.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