smart_proxy_ipam 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf80d5537986cfb15d05ac927e2c0498a9cdcab10c98866dab18b4ead3a91131
4
- data.tar.gz: 57d175cf91379394aae2f6ba477d0c89a84b4774363e9e391bc473fa9454bc5f
3
+ metadata.gz: f64f77c875cf2954bfe2d9fb2e1c56e1848e402ec8259959382771da8cd7158b
4
+ data.tar.gz: a4e3900fd2ad8a2ec16e9ab3887dd6412ce567b16f7cdb98278407c80add8e9c
5
5
  SHA512:
6
- metadata.gz: 47f2404f8982398568a8d6d1984116658e7dd9eead7679f836c74bef9772bab678b084b82cdddfbfcc8d6b6b19adf3962510c5b566c0f7a1b80d53b9e9505da8
7
- data.tar.gz: e3dc74e8020a7af4c7f660ef7204c03130088a58dd5fff23a0d18440061d3f602182f6a13f0a1d363429ad860499ce87ab33f71fa524a7f10f8006075f469e44
6
+ metadata.gz: 3608be9d60dda80356bdf9e9c59f79cf0edcd1c69210cb7c10aa818237ec85e1485e8fd12d2ee1c1d527ca3ab926d1090ef20c2a6bc4faf8f2c4b262f86df44c
7
+ data.tar.gz: a99d59aab8ce7b3f1a1b6d4b90e861fef90435c9071e0b42d3f7863834a660050d8e96af471473b4e6f0a0b8db8b1f1d212502e01ac80073e79a1542d731fff6
data/README.md CHANGED
@@ -1,8 +1,12 @@
1
- # smart_proxy_phpipam
1
+ # smart_proxy_ipam
2
2
 
3
- Foreman Smart Proxy plugin for IPAM integration with [phpIPAM](https://phpipam.net/).
3
+ Foreman Smart Proxy plugin for IPAM integration with various IPAM providers.
4
+
5
+ Currently supported Providers:
6
+ 1. [phpIPAM](https://phpipam.net/).
7
+
8
+ Provides a basic Dashboard for viewing phpIPAM sections, subnets. Also supports obtaining of the next available IPv4 address for a given subnet(via [IPAM Smart Proxy Plugin](https://github.com/grizzthedj/smart_proxy_ipam)).
4
9
 
5
- Used for obtaining the next available IPv4 address from phpIPAM, for a given subnet.
6
10
 
7
11
  ## Installation
8
12
 
@@ -1,11 +1,6 @@
1
1
 
2
2
  require 'smart_proxy_ipam/phpipam/phpipam_api'
3
- require 'smart_proxy_ipam/ipam/ipam_api'
4
3
 
5
- map '/phpipam' do
4
+ map '/ipam' do
6
5
  run Proxy::Phpipam::Api
7
6
  end
8
-
9
- map '/ipam' do
10
- run Proxy::Ipam::Api
11
- end
@@ -3,11 +3,27 @@ require 'smart_proxy_ipam/ipam'
3
3
  require 'smart_proxy_ipam/ipam_main'
4
4
  require 'smart_proxy_ipam/phpipam/phpipam_client'
5
5
 
6
+ # TODO: Refactor later to handle multiple IPAM providers. For now, it is
7
+ # just phpIPAM that is supported
6
8
  module Proxy::Phpipam
7
9
  class Api < ::Sinatra::Base
8
10
  include ::Proxy::Log
9
11
  helpers ::Proxy::Helpers
10
12
 
13
+ get '/providers' do
14
+ content_type :json
15
+ {ipam_providers: ['phpIPAM']}.to_json
16
+ end
17
+
18
+ # Gets the next available IP address based on a given subnet
19
+ #
20
+ # Input: cidr(string): CIDR address in the format: "100.20.20.0/24"
21
+ # Returns: Hash with "next_ip", or hash with "error"
22
+ # Examples:
23
+ # Response if success:
24
+ # {"cidr":"100.20.20.0/24","next_ip":"100.20.20.11"}
25
+ # Response if error:
26
+ # {"error":"The specified subnet does not exist in phpIPAM."}
11
27
  get '/next_ip' do
12
28
  content_type :json
13
29
 
@@ -22,10 +38,10 @@ module Proxy::Phpipam
22
38
  response = phpipam_client.get_subnet(cidr)
23
39
 
24
40
  if response['message'] && response['message'].downcase == "no subnets found"
25
- return {error: "The specified subnet does not exist in phpIPAM."}.to_json
41
+ return {error: "The specified subnet does not exist in External IPAM."}.to_json
26
42
  end
27
43
 
28
- subnet_id = response['data'][0]['id']
44
+ subnet_id = JSON.parse(response)[0]['id']
29
45
  response = phpipam_client.get_next_ip(subnet_id)
30
46
 
31
47
  if response['message'] && response['message'].downcase == "no free addresses found"
@@ -34,10 +50,29 @@ module Proxy::Phpipam
34
50
 
35
51
  {cidr: cidr, next_ip: response['data']}.to_json
36
52
  rescue Errno::ECONNREFUSED
37
- return {error: "Unable to connect to phpIPAM server"}.to_json
53
+ return {error: "Unable to connect to External IPAM server"}.to_json
38
54
  end
39
55
  end
40
56
 
57
+ # Gets the subnet from phpIPAM
58
+ #
59
+ # Input: cidr(string): CIDR address in the format: "100.20.20.0/24"
60
+ # Returns: JSON with "data" key on success, or JSON with "error" key when there is an error
61
+ # Examples:
62
+ # Response if subnet exists:
63
+ # {
64
+ # "code":200,"success":true,"data":[{"id":"12","subnet":"100.30.30.0","mask":"24",
65
+ # "sectionId":"5", "description":"Test Subnet","linked_subnet":null,"firewallAddressObject":null,
66
+ # "vrfId":"0","masterSubnetId":"0","allowRequests":"0","vlanId":"0","showName":"0","device":"0",
67
+ # "permissions":"[]","pingSubnet":"0","discoverSubnet":"0","DNSrecursive":"0","DNSrecords":"0",
68
+ # "nameserverId":"0","scanAgent":"0","isFolder":"0","isFull":"0","tag":"2","threshold":"0",
69
+ # "location":"0","editDate":null,"lastScan":null,"lastDiscovery":null}],"time":0.009
70
+ # }
71
+ #
72
+ # Response if subnet not exists):
73
+ # {
74
+ # "code":200,"success":0,"message":"No subnets found","time":0.01
75
+ # }
41
76
  get '/get_subnet' do
42
77
  content_type :json
43
78
 
@@ -52,10 +87,22 @@ module Proxy::Phpipam
52
87
  subnet = phpipam_client.get_subnet(cidr)
53
88
  subnet.to_json
54
89
  rescue Errno::ECONNREFUSED
55
- return {error: "Unable to connect to phpIPAM server"}.to_json
90
+ return {error: "Unable to connect to External IPAM server"}.to_json
56
91
  end
57
92
  end
58
93
 
94
+ # Get a list of sections from external ipam
95
+ #
96
+ # Input: None
97
+ # Returns: An array of sections on success, hash with "error" key otherwise
98
+ # Examples
99
+ # Response if success: [
100
+ # {"id":"5","name":"Awesome Section","description":"A totally awesome Section","masterSection":"0",
101
+ # "permissions":"[]","strictMode":"1","subnetOrdering":"default","order":null,
102
+ # "editDate":"2019-04-19 21:49:55","showVLAN":"1","showVRF":"1","showSupernetOnly":"1","DNS":null}]
103
+ # ]
104
+ # Response if error:
105
+ # {"error":"Unable to connect to phpIPAM server"}
59
106
  get '/sections' do
60
107
  content_type :json
61
108
 
@@ -64,10 +111,65 @@ module Proxy::Phpipam
64
111
  sections = phpipam_client.get_sections
65
112
  sections.to_json
66
113
  rescue Errno::ECONNREFUSED
67
- return {error: "Unable to connect to phpIPAM server"}.to_json
114
+ return {error: "Unable to connect to External IPAM server"}.to_json
68
115
  end
69
116
  end
70
117
 
118
+ # Get a list of subnets for given external ipam section
119
+ #
120
+ # Input: section_id(integer). The id of the external ipam section
121
+ # Returns: Array of subnets(as json) in "data" key on success, hash with error otherwise
122
+ # Examples:
123
+ # Response if success:
124
+ # {
125
+ # "code":200,
126
+ # "success":true,
127
+ # "data":[
128
+ # {
129
+ # "id":"24",
130
+ # "subnet":"100.10.10.0",
131
+ # "mask":"24",
132
+ # "sectionId":"10",
133
+ # "description":"wrgwgwefwefw",
134
+ # "linked_subnet":null,
135
+ # "firewallAddressObject":null,
136
+ # "vrfId":"0",
137
+ # "masterSubnetId":"0",
138
+ # "allowRequests":"0",
139
+ # "vlanId":"0",
140
+ # "showName":"0",
141
+ # "device":"0",
142
+ # "permissions":"[]",
143
+ # "pingSubnet":"0",
144
+ # "discoverSubnet":"0",
145
+ # "DNSrecursive":"0",
146
+ # "DNSrecords":"0",
147
+ # "nameserverId":"0",
148
+ # "scanAgent":"0",
149
+ # "isFolder":"0",
150
+ # "isFull":"0",
151
+ # "tag":"2",
152
+ # "threshold":"0",
153
+ # "location":"0",
154
+ # "editDate":null,
155
+ # "lastScan":null,
156
+ # "lastDiscovery":null,
157
+ # "usage":{
158
+ # "used":"0",
159
+ # "maxhosts":"254",
160
+ # "freehosts":"254",
161
+ # "freehosts_percent":100,
162
+ # "Offline_percent":0,
163
+ # "Used_percent":0,
164
+ # "Reserved_percent":0,
165
+ # "DHCP_percent":0
166
+ # }
167
+ # }
168
+ # ],
169
+ # "time":0.012
170
+ # }
171
+ # Response if error:
172
+ # {"error":"Unable to connect to phpIPAM server"}
71
173
  get '/sections/:section_id/subnets' do
72
174
  content_type :json
73
175
 
@@ -82,10 +184,20 @@ module Proxy::Phpipam
82
184
  subnets = phpipam_client.get_subnets(section_id)
83
185
  subnets.to_json
84
186
  rescue Errno::ECONNREFUSED
85
- return {error: "Unable to connect to phpIPAM server"}.to_json
187
+ return {error: "Unable to connect to External IPAM server"}.to_json
86
188
  end
87
189
  end
88
190
 
191
+ # Checks whether an IP address has already been taken in external ipam.
192
+ #
193
+ # Inputs: 1. ip(string). IP address to be checked.
194
+ # 2. cidr(string): CIDR address in the format: "100.20.20.0/24"
195
+ # Returns: JSON object with 'exists' field being either true or false
196
+ # Example:
197
+ # Response if exists:
198
+ # {"ip":"100.20.20.18","exists":true}
199
+ # Response if not exists:
200
+ # {"ip":"100.20.20.18","exists":false}
89
201
  get '/ip_exists' do
90
202
  content_type :json
91
203
 
@@ -100,31 +212,27 @@ module Proxy::Phpipam
100
212
  subnet = phpipam_client.get_subnet(cidr)
101
213
 
102
214
  if subnet['message'] && subnet['message'].downcase == "no subnets found"
103
- return {error: "The specified subnet does not exist in phpIPAM."}.to_json
215
+ return {error: "The specified subnet does not exist in External IPAM."}.to_json
104
216
  end
105
217
 
106
- subnet_id = subnet['data'][0]['id']
107
- usage = phpipam_client.get_subnet_usage(subnet_id)
108
-
109
- # We need to check subnet usage first in the case there are zero ips in the subnet. Checking
110
- # the ip existence on an empty subnet returns a malformed response from phpIPAM, containing
111
- # HTML in the JSON response.
112
- if usage['data']['used'] == "0"
113
- return {ip: ip, exists: false}.to_json
114
- else
115
- response = phpipam_client.ip_exists(ip, subnet_id)
116
-
117
- if response && response['message'] && response['message'].downcase == 'no addresses found'
118
- return {ip: ip, exists: false}.to_json
119
- else
120
- return {ip: ip, exists: true}.to_json
121
- end
122
- end
218
+ subnet_id = JSON.parse(subnet)[0]['id']
219
+ phpipam_client.ip_exists(ip, subnet_id)
123
220
  rescue Errno::ECONNREFUSED
124
- return {error: "Unable to connect to phpIPAM server"}.to_json
221
+ return {error: "Unable to connect to External IPAM server"}.to_json
125
222
  end
126
223
  end
127
224
 
225
+ # Adds an IP address to the specified subnet
226
+ #
227
+ # Inputs: 1. ip(string). IP address to be added.
228
+ # 2. subnet_id(integer). The id of the external ipam subnet
229
+ # 3. description(string). IP address description
230
+ # Returns: Hash with "message" on success, or hash with "error"
231
+ # Examples:
232
+ # Response if success:
233
+ # {"message":"IP 100.10.10.123 added to subnet 100.10.10.0/24 successfully."}
234
+ # Response if error:
235
+ # {"error":"The specified subnet does not exist in phpIPAM."}
128
236
  post '/add_ip_to_subnet' do
129
237
  content_type :json
130
238
 
@@ -139,19 +247,29 @@ module Proxy::Phpipam
139
247
  response = phpipam_client.get_subnet(cidr)
140
248
 
141
249
  if response['message'] && response['message'].downcase == "no subnets found"
142
- return {error: "The specified subnet does not exist in phpIPAM."}.to_json
250
+ return {error: "The specified subnet does not exist in External IPAM."}.to_json
143
251
  end
144
252
 
145
- subnet_id = response['data'][0]['id']
253
+ subnet_id = JSON.parse(response)[0]['id']
146
254
 
147
255
  phpipam_client.add_ip_to_subnet(ip, subnet_id, 'Address auto added by Foreman')
148
256
 
149
257
  {message: "IP #{ip} added to subnet #{cidr} successfully."}.to_json
150
258
  rescue Errno::ECONNREFUSED
151
- return {error: "Unable to connect to phpIPAM server"}.to_json
259
+ return {error: "Unable to connect to External IPAM server"}.to_json
152
260
  end
153
261
  end
154
262
 
263
+ # Deletes IP address from a given subnet
264
+ #
265
+ # Inputs: 1. ip(string). IP address to be checked.
266
+ # 2. cidr(string): CIDR address in the format: "100.20.20.0/24"
267
+ # Returns: JSON object
268
+ # Example:
269
+ # Response if success:
270
+ # {"code": 200, "success": true, "message": "Address deleted", "time": 0.017}
271
+ # Response if error:
272
+ # {"code": 404, "success": 0, "message": "Address does not exist", "time": 0.008}
155
273
  post '/delete_ip_from_subnet' do
156
274
  content_type :json
157
275
 
@@ -166,16 +284,16 @@ module Proxy::Phpipam
166
284
  response = phpipam_client.get_subnet(cidr)
167
285
 
168
286
  if response['message'] && response['message'].downcase == "no subnets found"
169
- return {error: "The specified subnet does not exist in phpIPAM."}.to_json
287
+ return {error: "The specified subnet does not exist in External IPAM."}.to_json
170
288
  end
171
289
 
172
- subnet_id = response['data'][0]['id']
290
+ subnet_id = JSON.parse(response)[0]['id']
173
291
 
174
292
  phpipam_client.delete_ip_from_subnet(ip, subnet_id)
175
293
 
176
294
  {message: "IP #{ip} deleted from subnet #{cidr} successfully."}.to_json
177
295
  rescue Errno::ECONNREFUSED
178
- return {error: "Unable to connect to phpIPAM server"}.to_json
296
+ return {error: "Unable to connect to External IPAM server"}.to_json
179
297
  end
180
298
  end
181
299
 
@@ -6,22 +6,40 @@ require 'smart_proxy_ipam/ipam'
6
6
  require 'smart_proxy_ipam/ipam_main'
7
7
 
8
8
  module Proxy::Phpipam
9
- class PhpipamClient
9
+ class PhpipamClient
10
10
  def initialize
11
11
  conf = Proxy::Ipam.get_config[:phpipam]
12
12
  @phpipam_config = {url: conf[:url], user: conf[:user], password: conf[:password]}
13
- @api_base = conf[:url] + '/api/' + conf[:user] + '/'
13
+ @api_base = "#{conf[:url]}/api/#{conf[:user]}/"
14
14
  @token = nil
15
15
  end
16
16
 
17
- def get_subnet(cidr)
18
- url = 'subnets/cidr/' + cidr.to_s + '/'
19
- get(url)
17
+ def init_reservations
18
+ @@ipam_reservations = {}
20
19
  end
21
20
 
22
- def get_next_ip(subnet_id)
23
- url = 'subnets/' + subnet_id.to_s + '/first_free/'
24
- get(url)
21
+ def get_subnet(cidr)
22
+ url = "subnets/cidr/#{cidr.to_s}"
23
+ subnets = get(url)
24
+ response = []
25
+
26
+ if subnets
27
+ if subnets['message'] && subnets['message'].downcase == 'no subnets found'
28
+ return {"message": "no subnets found"}.to_json
29
+ else
30
+ # Only return the relevant fields to Foreman
31
+ subnets['data'].each do |subnet|
32
+ response.push({
33
+ "id": subnet['id'],
34
+ "subnet": subnet['subnet'],
35
+ "description": subnet['description'],
36
+ "mask": subnet['mask']
37
+ })
38
+ end
39
+
40
+ return response.to_json
41
+ end
42
+ end
25
43
  end
26
44
 
27
45
  def add_ip_to_subnet(ip, subnet_id, desc)
@@ -30,26 +48,74 @@ module Proxy::Phpipam
30
48
  end
31
49
 
32
50
  def get_sections
33
- get('sections/')['data']
51
+ sections = get('sections/')['data']
52
+ response = []
53
+
54
+ if sections
55
+ sections.each do |section|
56
+ response.push({
57
+ "id": section['id'],
58
+ "name": section['name'],
59
+ "description": section['description']
60
+ })
61
+ end
62
+ end
63
+
64
+ response
34
65
  end
35
66
 
36
67
  def get_subnets(section_id)
37
- get('sections/' + section_id.to_s + '/subnets/')
68
+ subnets = get("sections/#{section_id.to_s}/subnets/")
69
+ response = []
70
+
71
+ if subnets && subnets['data']
72
+ # Only return the relevant data
73
+ subnets['data'].each do |subnet|
74
+ response.push({
75
+ "id": subnet['id'],
76
+ "subnet": subnet['subnet'],
77
+ "mask": subnet['mask'],
78
+ "sectionId": subnet['sectionId'],
79
+ "description": subnet['description']
80
+ })
81
+ end
82
+ end
83
+
84
+ response
38
85
  end
39
86
 
40
87
  def ip_exists(ip, subnet_id)
41
- get('subnets/' + subnet_id.to_s + '/addresses/' + ip + '/')
88
+ usage = get_subnet_usage(subnet_id)
89
+
90
+ # We need to check subnet usage first in the case there are zero ips in the subnet. Checking
91
+ # the ip existence on an empty subnet returns a malformed response from phpIPAM, containing
92
+ # HTML in the JSON response.
93
+ if usage['data']['used'] == "0"
94
+ return {ip: ip, exists: false}.to_json
95
+ else
96
+ response = get("subnets/#{subnet_id.to_s}/addresses/#{ip}/")
97
+
98
+ if response && response['message'] && response['message'].downcase == 'no addresses found'
99
+ return {ip: ip, exists: false}.to_json
100
+ else
101
+ return {ip: ip, exists: true}.to_json
102
+ end
103
+ end
42
104
  end
43
105
 
106
+
44
107
  def get_subnet_usage(subnet_id)
45
- get('subnets/' + subnet_id.to_s + '/usage/')
108
+ get("subnets/#{subnet_id.to_s}/usage/")
46
109
  end
47
110
 
48
111
  def delete_ip_from_subnet(ip, subnet_id)
49
- delete('addresses/' + ip + '/' + subnet_id.to_s + '/')
112
+ delete("addresses/#{ip}/#{subnet_id.to_s}/")
50
113
  end
51
114
 
52
- private
115
+ def get_next_ip(subnet_id)
116
+ url = "subnets/#{subnet_id.to_s}/first_free/"
117
+ get(url)
118
+ end
53
119
 
54
120
  def get(path, body=nil)
55
121
  authenticate
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Proxy
3
3
  module Ipam
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
6
6
  end
@@ -6,7 +6,3 @@
6
6
  :url: 'http://172.16.16.217'
7
7
  :user: 'foreman'
8
8
  :password: 'Test1234!'
9
- :netbox:
10
- :url: 'http://172.16.16.217'
11
- :user: 'netbox'
12
- :password: 'Test1234!'
@@ -6,7 +6,3 @@
6
6
  :url: 'http://phpipam.example.com'
7
7
  :user: 'phpipam_api_user'
8
8
  :password: 'phpipam_password'
9
- :netbox:
10
- :url: 'http://netbox.example.com'
11
- :user: 'netbox_api_user'
12
- :password: 'netbox_api_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.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-12 00:00:00.000000000 Z
11
+ date: 2019-07-10 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
@@ -23,7 +23,6 @@ files:
23
23
  - bundler.d/ipam.rb
24
24
  - lib/smart_proxy_ipam.rb
25
25
  - lib/smart_proxy_ipam/ipam.rb
26
- - lib/smart_proxy_ipam/ipam/ipam_api.rb
27
26
  - lib/smart_proxy_ipam/ipam_http_config.ru
28
27
  - lib/smart_proxy_ipam/ipam_main.rb
29
28
  - lib/smart_proxy_ipam/phpipam/phpipam_api.rb
@@ -1,15 +0,0 @@
1
- require 'sinatra'
2
- require 'smart_proxy_ipam/ipam'
3
- require 'smart_proxy_ipam/ipam_main'
4
-
5
- module Proxy::Ipam
6
- class Api < ::Sinatra::Base
7
- include ::Proxy::Log
8
- helpers ::Proxy::Helpers
9
-
10
- get '/providers' do
11
- content_type :json
12
- {ipam_providers: ['phpIPAM']}.to_json
13
- end
14
- end
15
- end