smart_proxy_ipam 0.0.18 → 0.1.0

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