smart_proxy_ipam 0.0.18 → 0.1.0

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.18'
3
+ VERSION = '0.1.0'.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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_ipam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.1.0
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-02-24 00:00:00.000000000 Z
11
+ date: 2020-11-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Smart proxy plugin for IPAM integration with various IPAM providers
14
14
  email: chrisjsmith001@gmail.com
@@ -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
63
  summary: Smart proxy plugin for IPAM integration with various 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,378 +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'], :error => section['message']}.to_json if no_section_found?(section)
142
- puts "SECTION: " + section.to_json
143
- section.to_json
144
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
145
- logger.debug(errors[:no_connection])
146
- raise
147
- end
148
- end
149
-
150
- # Get a list of subnets for given external ipam section/group
151
- #
152
- # Input: section_name(string). The name of the external ipam section/group
153
- # Returns: Array of subnets(as json) in "data" key on success, hash with error otherwise
154
- # Examples:
155
- # Response if success:
156
- # {
157
- # "code":200,
158
- # "success":true,
159
- # "data":[
160
- # {
161
- # "id":"24",
162
- # "subnet":"100.10.10.0",
163
- # "mask":"24",
164
- # "sectionId":"10",
165
- # "description":"wrgwgwefwefw",
166
- # "linked_subnet":null,
167
- # "firewallAddressObject":null,
168
- # "vrfId":"0",
169
- # "masterSubnetId":"0",
170
- # "allowRequests":"0",
171
- # "vlanId":"0",
172
- # "showName":"0",
173
- # "device":"0",
174
- # "permissions":"[]",
175
- # "pingSubnet":"0",
176
- # "discoverSubnet":"0",
177
- # "DNSrecursive":"0",
178
- # "DNSrecords":"0",
179
- # "nameserverId":"0",
180
- # "scanAgent":"0",
181
- # "isFolder":"0",
182
- # "isFull":"0",
183
- # "tag":"2",
184
- # "threshold":"0",
185
- # "location":"0",
186
- # "editDate":null,
187
- # "lastScan":null,
188
- # "lastDiscovery":null,
189
- # "usage":{
190
- # "used":"0",
191
- # "maxhosts":"254",
192
- # "freehosts":"254",
193
- # "freehosts_percent":100,
194
- # "Offline_percent":0,
195
- # "Used_percent":0,
196
- # "Reserved_percent":0,
197
- # "DHCP_percent":0
198
- # }
199
- # }
200
- # ],
201
- # "time":0.012
202
- # }
203
- # Response if :error =>
204
- # {"error":"Unable to connect to External IPAM server"}
205
- get '/groups/:group/subnets' do
206
- content_type :json
207
-
208
- begin
209
- err = validate_required_params(["group"], params)
210
- return err if err.length > 0
211
-
212
- phpipam_client = PhpipamClient.new
213
- section = JSON.parse(phpipam_client.get_section(params[:group]))
214
-
215
- return {:code => 404, :error => errors[:no_section]}.to_json if no_section_found?(section)
216
-
217
- phpipam_client.get_subnets(section['data']['id'].to_s, false)
218
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
219
- logger.debug(errors[:no_connection])
220
- raise
221
- end
222
- end
223
-
224
- # Checks whether an IP address has already been taken in external ipam.
225
- #
226
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
227
- # 2. prefix: The subnet prefix(e.g. 24)
228
- # 3. ip: IP address to be queried
229
- #
230
- # Returns: JSON object with 'exists' field being either true or false
231
- #
232
- # Example:
233
- # Response if exists:
234
- # {"ip":"100.20.20.18","exists":true}
235
- # Response if not exists:
236
- # {"ip":"100.20.20.18","exists":false}
237
- get '/subnet/:address/:prefix/:ip' do
238
- content_type :json
239
-
240
- begin
241
- err = validate_required_params(["address", "prefix", "ip"], params)
242
- return err if err.length > 0
243
-
244
- ip = params[:ip]
245
- cidr = params[:address] + '/' + params[:prefix]
246
- section_name = params[:group]
247
- phpipam_client = PhpipamClient.new
248
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
249
-
250
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
251
-
252
- ip_exists = JSON.parse(phpipam_client.ip_exists(ip, subnet['data']['id']))
253
-
254
- if ip_exists['data']
255
- return {:code => 200, :exists => true}.to_json
256
- else
257
- return {:code => 404, :exists => false}.to_json
258
- end
259
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
260
- logger.debug(errors[:no_connection])
261
- raise
262
- end
263
- end
264
-
265
- # Adds an IP address to the specified subnet
266
- #
267
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
268
- # 2. prefix: The subnet prefix(e.g. 24)
269
- # 3. ip: IP address to be added
270
- #
271
- # Returns: Hash with "message" on success, or hash with "error"
272
- #
273
- # Examples:
274
- # Response if success:
275
- # IPv4: {"message":"IP 100.10.10.123 added to subnet 100.10.10.0/24 successfully."}
276
- # IPv6: {"message":"IP 2001:db8:abcd:12::3 added to subnet 2001:db8:abcd:12::/124 successfully."}
277
- # Response if :error =>
278
- # {"error":"The specified subnet does not exist in phpIPAM."}
279
- post '/subnet/:address/:prefix/:ip' do
280
- content_type :json
281
-
282
- begin
283
- err = validate_required_params(["address", "ip", "prefix"], params)
284
- return err if err.length > 0
285
-
286
- ip = params[:ip]
287
- cidr = params[:address] + '/' + params[:prefix]
288
- section_name = URI.escape(params[:group])
289
-
290
- phpipam_client = PhpipamClient.new
291
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
292
-
293
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
294
-
295
- add_ip = JSON.parse(phpipam_client.add_ip_to_subnet(ip, subnet['data']['id'], 'Address auto added by Foreman'))
296
-
297
- if add_ip['message'] && add_ip['message'] == "Address created"
298
- return {:code => 200}.to_json
299
- else
300
- return {:code => 500, :error => add_ip['message']}.to_json
301
- end
302
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
303
- logger.debug(errors[:no_connection])
304
- raise
305
- end
306
- end
307
-
308
- # Deletes IP address from a given subnet
309
- #
310
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
311
- # 2. prefix: The subnet prefix(e.g. 24)
312
- # 3. ip: IP address to be deleted
313
- #
314
- # Returns: JSON object
315
- # Example:
316
- # Response if success:
317
- # {"code": 200, "success": true, "message": "Address deleted", "time": 0.017}
318
- # Response if :error =>
319
- # {"code": 404, "success": 0, "message": "Address does not exist", "time": 0.008}
320
- delete '/subnet/:address/:prefix/:ip' do
321
- content_type :json
322
-
323
- begin
324
- err = validate_required_params(["address", "prefix", "ip"], params)
325
- return err if err.length > 0
326
-
327
- ip = params[:ip]
328
- cidr = params[:address] + '/' + params[:prefix]
329
- section_name = URI.escape(params[:group])
330
- phpipam_client = PhpipamClient.new
331
- subnet = JSON.parse(phpipam_client.get_subnet(cidr, section_name))
332
-
333
- return {:code => 404, :error => subnet['error']}.to_json if no_subnets_found?(subnet)
334
-
335
- delete_ip = JSON.parse(phpipam_client.delete_ip_from_subnet(ip, subnet['data']['id']))
336
-
337
- if delete_ip['message'] && delete_ip['message'] == "Address deleted"
338
- return {:code => 200}.to_json
339
- else
340
- return {:code => 500, :error => delete_ip['message']}.to_json
341
- end
342
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
343
- logger.debug(errors[:no_connection])
344
- raise
345
- end
346
- end
347
-
348
- # Checks whether a subnet exists in a specific section.
349
- #
350
- # Params: 1. address: The network address of the IPv4 or IPv6 subnet.
351
- # 2. prefix: The subnet prefix(e.g. 24)
352
- # 3. group: The name of the section
353
- #
354
- # Returns: JSON object with 'data' field is exists, otherwise field with 'error'
355
- #
356
- # Example:
357
- # Response if exists:
358
- # {"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}
359
- # Response if not exists:
360
- # {"code":404,"error":"No subnet 172.66.66.0/29 found in section :group"}
361
- get '/group/:group/subnet/:address/:prefix' do
362
- content_type :json
363
-
364
- begin
365
- err = validate_required_params(["address", "prefix", "group"], params)
366
- return err if err.length > 0
367
-
368
- cidr = params[:address] + '/' + params[:prefix]
369
-
370
- phpipam_client = PhpipamClient.new
371
- phpipam_client.get_subnet_by_section(cidr, params[:group])
372
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
373
- logger.debug(errors[:no_connection])
374
- raise
375
- end
376
- end
377
- end
378
- end