smart_proxy_ipam 0.0.11 → 0.0.12

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: 42b9945498eacd5e884248edc7770ac14fbda2b7315fd8f6997aa2fda7738323
4
- data.tar.gz: 737a679b29622a526211670cbff2cf5e2a6e0b386f3ace537ce4ebc0a12b7e5b
3
+ metadata.gz: 03e5b4db2d3b9f5ffad35e382585f0d632c7bf312c9a0b643ff24989d11283d8
4
+ data.tar.gz: 34960551000adc62f823b7d66f81d3429530b0f39cc3b8f9301d92207c6c5a7b
5
5
  SHA512:
6
- metadata.gz: '09f728a68de1da60906199cba9dada6d120ea31657f2369ba616b92c9a10dec3d3feba4e15051266af03e13e8d4be2d231841f17094b674d50fa5e2f630e0dfb'
7
- data.tar.gz: bb3c04b61e6776dabda6c2e752b7376013045b247560887481bde4701bb4d2fbbaee8bc973e49b393b695ee16f72d17c8e297219b545609e8b07ea970c847bb4
6
+ metadata.gz: da0f3c2643eac27f95a041b8181097b874aadee8d1a46a8d549862870328cb9f40766d0def9688ff487cb27fc00b8a178522a75f90e2e813b60c99256e3b0068
7
+ data.tar.gz: 1f3f74603ab6822061a29018a2eb4ef98fd1071cb15c0af0e252da93cbbfe15b7fdc2e396d1a5a3ff3e9b29de97580ce46edae20b8c5357c76d317154ee4ce7d
data/README.md CHANGED
@@ -17,8 +17,8 @@ for how to install Foreman plugins
17
17
 
18
18
  Once plugin is installed, you can use phpIPAM to get the next available IP address for a subnet:
19
19
 
20
- 1. Create a subnet in Foreman of IPAM type "External IPAM". Click on the `Proxy` tab and associate the subnet with the External IPAM proxy. _NOTE: This subnet must actually exist in phpIPAM. There is no phpIPAM integration on the subnet creation at this time._
21
- 2. Create a host in Foreman. When adding/editing interfaces, select the above created subnet, and the next available IP(pulled from phpIPAM) for the selected subnet will be displayed in the IPv4 address field. _NOTE: This is not supported for IPv6._
20
+ 1. Create a subnet in Foreman of IPAM type "External IPAM". Click on the `Proxy` tab and associate the subnet with a Smart Proxy that has the `external_ipam` feature enabled. _NOTE: This subnet must actually exist in phpIPAM. There is no integration with subnet creation at this time._
21
+ 2. Create a host in Foreman. When adding/editing interfaces, select the above created subnet, and the next available IP in the selected subnet will be pulled from phpIPAM, and displayed in the IPv4 address field. _NOTE: This is not supported for IPv6._
22
22
 
23
23
  ## Local development
24
24
 
@@ -32,29 +32,29 @@ git clone https://github.com/theforeman/smart-proxy
32
32
  ```
33
33
  3. Fork both the foreman plugin and smart proxy plugin repos, then clone
34
34
 
35
- foreman_phpipam repo: https://github.com/grizzthedj/smart_proxy_phpipam
36
- smart_proxy_phpipam repo: https://github.com/grizzthedj/smart_proxy_phpipam
35
+ foreman_ipam repo: https://github.com/grizzthedj/foreman_ipam
36
+ smart_proxy_ipam repo: https://github.com/grizzthedj/smart_proxy_ipam
37
37
 
38
38
  ```
39
- git clone https://github.com/<GITHUB_USER>/foreman_phpipam
40
- git clone https://github.com/<GITHUB_USER>/smart_proxy_phpipam
39
+ git clone https://github.com/<GITHUB_USER>/foreman_ipam
40
+ git clone https://github.com/<GITHUB_USER>/smart_proxy_ipam
41
41
  ```
42
- 4. Add the foreman_phpipam plugin to `Gemfile.local.rb` in the Foreman bundler.d directory
42
+ 4. Add the foreman_ipam plugin to `Gemfile.local.rb` in the Foreman bundler.d directory
43
43
  ```
44
- gem 'foreman_phpipam', :path => '/path/to/foreman_phpipam'
44
+ gem 'foreman_ipam', :path => '/path/to/foreman_ipam'
45
45
  ```
46
46
  5. From Foreman root directory run
47
47
  ```
48
48
  bundle install
49
49
  bundle exec rails db:migrate
50
- bundle exec rails db:seed # This adds 'phpIPAM' feature to Features table
50
+ bundle exec rails db:seed # This adds 'external_ipam' feature to Features table
51
51
  bundle exec foreman start
52
52
  ```
53
53
  6. Add the smart_proxy_phpipam plugin to `Gemfile.local.rb` in Smart Proxy bundler.d directory
54
54
  ```
55
- gem 'smart_proxy_phpipam', :path => '/path/to/smart_proxy_phpipam'
55
+ gem 'smart_proxy_ipam', :path => '/path/to/smart_proxy_ipam'
56
56
  ```
57
- 7. Copy `config/settings.d/phpipam.yml.example` to `config/settings.d/phpipam.yml` and replace values with your phpIPAM URL and credentials.
57
+ 7. Copy `config/settings.d/external_ipam.yml.example` to `config/settings.d/external_ipam.yml` and replace values with your phpIPAM URL and credentials.
58
58
  8. From Smart Proxy root directory run ...
59
59
  ```
60
60
  bundle install
@@ -62,7 +62,7 @@ bundle exec smart-proxy start
62
62
  ```
63
63
  9. Navigate to Foreman UI at http://localhost:5000
64
64
  10. Add a Local Smart Proxy in the Foreman UI(Infrastructure => Smart Proxies)
65
- 11. Ensure that the `external_ipam` feature is present on the proxy(http://proxy_url/features)
65
+ 11. Ensure that the `external_ipam` feature is present on the proxy(http://localhost:8000/features)
66
66
  12. Create a Subnet, and associate the subnet to the `external_ipam` proxy
67
67
 
68
68
  ## Contributing
@@ -2,6 +2,7 @@ require 'sinatra'
2
2
  require 'smart_proxy_ipam/ipam'
3
3
  require 'smart_proxy_ipam/ipam_main'
4
4
  require 'smart_proxy_ipam/phpipam/phpipam_client'
5
+ require 'smart_proxy_ipam/phpipam/phpipam_helper'
5
6
 
6
7
  # TODO: Refactor later to handle multiple IPAM providers. For now, it is
7
8
  # just phpIPAM that is supported
@@ -9,6 +10,7 @@ module Proxy::Phpipam
9
10
  class Api < ::Sinatra::Base
10
11
  include ::Proxy::Log
11
12
  helpers ::Proxy::Helpers
13
+ helpers PhpipamHelper
12
14
 
13
15
  # Gets the next available IP address based on a given subnet
14
16
  #
@@ -23,33 +25,23 @@ module Proxy::Phpipam
23
25
  content_type :json
24
26
 
25
27
  begin
28
+ err = validate_required_params(["cidr", "mac"], params)
29
+ return err if err.length > 0
30
+
26
31
  cidr = params[:cidr]
27
32
  mac = params[:mac]
28
-
29
- if not cidr
30
- return {:error => "A 'cidr' parameter for the subnet must be provided(e.g. 100.10.10.0/24)"}.to_json
31
- end
32
- if not mac
33
- return {:error => "A 'mac' address must be provided(e.g. 00:0a:95:9d:68:10)"}.to_json
34
- end
35
-
36
33
  phpipam_client = PhpipamClient.new
37
34
  subnet = JSON.parse(phpipam_client.get_subnet(cidr))
38
35
 
39
- if !subnet.kind_of?(Array) && subnet['message'] && subnet['message'].downcase == "no subnets found"
40
- return {:error => "The specified subnet does not exist in External IPAM."}.to_json
41
- end
42
-
43
- subnet_id = subnet[0]['id']
44
- ip = phpipam_client.get_next_ip(subnet_id, mac, cidr)
36
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnet)
37
+
38
+ ip = phpipam_client.get_next_ip(subnet[0]['id'], mac, cidr)
45
39
 
46
- if !ip.kind_of?(Array) && ip['message'] && ip['message'].downcase == "no free addresses found"
47
- return {:error => "There are no more free addresses in subnet #{cidr}"}.to_json
48
- end
40
+ return {:error => errors[:no_free_ip]}.to_json if no_free_ip_found(ip)
49
41
 
50
42
  {:cidr => cidr, :next_ip => ip['next_ip']}.to_json
51
- rescue Errno::ECONNREFUSED
52
- return {:error => "Unable to connect to External IPAM server"}.to_json
43
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
44
+ return {:error => errors[:no_connection]}.to_json
53
45
  end
54
46
  end
55
47
 
@@ -76,17 +68,15 @@ module Proxy::Phpipam
76
68
  content_type :json
77
69
 
78
70
  begin
79
- cidr = params[:cidr]
80
-
81
- if not cidr
82
- return {:error => "A 'cidr' parameter for the subnet must be provided(e.g. 100.10.10.0/24)"}.to_json
83
- end
71
+ err = validate_required_params(["cidr"], params)
72
+ return err if err.length > 0
84
73
 
85
74
  phpipam_client = PhpipamClient.new
86
- subnet = phpipam_client.get_subnet(cidr)
75
+ subnet = JSON.parse(phpipam_client.get_subnet(params[:cidr]))
76
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnet)
87
77
  subnet.to_json
88
- rescue Errno::ECONNREFUSED
89
- return {:error => "Unable to connect to External IPAM server"}.to_json
78
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
79
+ return {:error => errors[:no_connection]}.to_json
90
80
  end
91
81
  end
92
82
 
@@ -107,10 +97,9 @@ module Proxy::Phpipam
107
97
 
108
98
  begin
109
99
  phpipam_client = PhpipamClient.new
110
- sections = phpipam_client.get_sections
111
- sections.to_json
112
- rescue Errno::ECONNREFUSED
113
- return {:error => "Unable to connect to External IPAM server"}.to_json
100
+ phpipam_client.get_sections.to_json
101
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
102
+ return {:error => errors[:no_connection]}.to_json
114
103
  end
115
104
  end
116
105
 
@@ -173,17 +162,19 @@ module Proxy::Phpipam
173
162
  content_type :json
174
163
 
175
164
  begin
165
+ err = validate_required_params(["section_name"], params)
166
+ return err if err.length > 0
167
+
176
168
  section_name = URI.decode(params[:section_name])
177
-
178
- if not section_name
179
- return {:error => "A 'section_name' must be provided"}.to_json
180
- end
181
-
182
169
  phpipam_client = PhpipamClient.new
183
- subnets = phpipam_client.get_subnets(section_name)
170
+ section = phpipam_client.get_section(section_name)
171
+
172
+ return {:error => errors[:no_section]}.to_json if section.nil?
173
+
174
+ subnets = phpipam_client.get_subnets(section['id'].to_s)
184
175
  subnets.to_json
185
- rescue Errno::ECONNREFUSED
186
- return {:error => "Unable to connect to External IPAM server"}.to_json
176
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
177
+ return {:error => errors[:no_connection]}.to_json
187
178
  end
188
179
  end
189
180
 
@@ -201,23 +192,17 @@ module Proxy::Phpipam
201
192
  content_type :json
202
193
 
203
194
  begin
204
- cidr = params[:cidr]
205
- ip = params[:ip]
206
-
207
- return {:error => "Missing 'cidr' parameter. A CIDR IPv4 address must be provided(e.g. 100.10.10.0/24)"}.to_json if not cidr
208
- return {:error => "Missing 'ip' parameter. An IPv4 address must be provided(e.g. 100.10.10.22)"}.to_json if not ip
195
+ err = validate_required_params(["cidr", "ip"], params)
196
+ return err if err.length > 0
209
197
 
210
198
  phpipam_client = PhpipamClient.new
211
- subnet = phpipam_client.get_subnet(cidr)
199
+ subnet = JSON.parse(phpipam_client.get_subnet(params[:cidr]))
212
200
 
213
- if subnet['message'] && subnet['message'].downcase == "no subnets found"
214
- return {:error => "The specified subnet does not exist in External IPAM."}.to_json
215
- end
201
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnet)
216
202
 
217
- subnet_id = JSON.parse(subnet)[0]['id']
218
- phpipam_client.ip_exists(ip, subnet_id)
219
- rescue Errno::ECONNREFUSED
220
- return {:error => "Unable to connect to External IPAM server"}.to_json
203
+ phpipam_client.ip_exists(params[:ip], subnet[0]['id'])
204
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
205
+ return {:error => errors[:no_connection]}.to_json
221
206
  end
222
207
  end
223
208
 
@@ -236,26 +221,21 @@ module Proxy::Phpipam
236
221
  content_type :json
237
222
 
238
223
  begin
239
- cidr = params[:cidr]
240
- ip = params[:ip]
241
-
242
- return {:error => "Missing 'cidr' parameter. A CIDR IPv4 address must be provided(e.g. 100.10.10.0/24)"}.to_json if not cidr
243
- return {:error => "Missing 'ip' parameter. An IPv4 address must be provided(e.g. 100.10.10.22)"}.to_json if not ip
224
+ err = validate_required_params(["cidr", "ip"], params)
225
+ return err if err.length > 0
244
226
 
227
+ ip = params[:ip]
228
+ cidr = params[:cidr]
245
229
  phpipam_client = PhpipamClient.new
246
- response = phpipam_client.get_subnet(cidr)
247
-
248
- if response['message'] && response['message'].downcase == "no subnets found"
249
- return {:error => "The specified subnet does not exist in External IPAM."}.to_json
250
- end
230
+ subnet = JSON.parse(phpipam_client.get_subnet(cidr))
251
231
 
252
- subnet_id = JSON.parse(response)[0]['id']
232
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnet)
253
233
 
254
- phpipam_client.add_ip_to_subnet(ip, subnet_id, 'Address auto added by Foreman')
234
+ phpipam_client.add_ip_to_subnet(ip, subnet[0]['id'], 'Address auto added by Foreman')
255
235
 
256
236
  {:message => "IP #{ip} added to subnet #{cidr} successfully."}.to_json
257
- rescue Errno::ECONNREFUSED
258
- return {:error => "Unable to connect to External IPAM server"}.to_json
237
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
238
+ return {:error => errors[:no_connection]}.to_json
259
239
  end
260
240
  end
261
241
 
@@ -273,28 +253,22 @@ module Proxy::Phpipam
273
253
  content_type :json
274
254
 
275
255
  begin
276
- cidr = params[:cidr]
277
- ip = params[:ip]
278
-
279
- return {:error => "Missing 'cidr' parameter. A CIDR IPv4 address must be provided(e.g. 100.10.10.0/24)"}.to_json if not cidr
280
- return {:error => "Missing 'ip' parameter. An IPv4 address must be provided(e.g. 100.10.10.22)"}.to_json if not ip
256
+ err = validate_required_params(["cidr", "ip"], params)
257
+ return err if err.length > 0
281
258
 
259
+ ip = params[:ip]
260
+ cidr = params[:cidr]
282
261
  phpipam_client = PhpipamClient.new
283
- response = phpipam_client.get_subnet(cidr)
284
-
285
- if response['message'] && response['message'].downcase == "no subnets found"
286
- return {:error => "The specified subnet does not exist in External IPAM."}.to_json
287
- end
262
+ subnet = JSON.parse(phpipam_client.get_subnet(cidr))
288
263
 
289
- subnet_id = JSON.parse(response)[0]['id']
264
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnet)
290
265
 
291
- phpipam_client.delete_ip_from_subnet(ip, subnet_id)
266
+ phpipam_client.delete_ip_from_subnet(ip, subnet[0]['id'])
292
267
 
293
268
  {:message => "IP #{ip} deleted from subnet #{cidr} successfully."}.to_json
294
- rescue Errno::ECONNREFUSED
295
- return {:error => "Unable to connect to External IPAM server"}.to_json
269
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET
270
+ return {:error => errors[:no_connection]}.to_json
296
271
  end
297
272
  end
298
-
299
273
  end
300
274
  end
@@ -5,10 +5,12 @@ require 'monitor'
5
5
  require 'concurrent'
6
6
  require 'smart_proxy_ipam/ipam'
7
7
  require 'smart_proxy_ipam/ipam_main'
8
+ require 'smart_proxy_ipam/phpipam/phpipam_helper'
8
9
 
9
10
  module Proxy::Phpipam
10
11
  class PhpipamClient
11
12
  include Proxy::Log
13
+ include PhpipamHelper
12
14
 
13
15
  MAX_RETRIES = 5
14
16
  DEFAULT_CLEANUP_INTERVAL = 120 # 2 mins
@@ -26,25 +28,20 @@ module Proxy::Phpipam
26
28
 
27
29
  def get_subnet(cidr)
28
30
  subnets = get("subnets/cidr/#{cidr.to_s}")
31
+ return {:error => errors[:no_subnet]}.to_json if no_subnets_found(subnets)
29
32
  response = []
30
33
 
31
- if subnets
32
- if subnets['message'] && subnets['message'].downcase == 'no subnets found'
33
- return {:message => "no subnets found"}.to_json
34
- else
35
- # Only return the relevant fields
36
- subnets['data'].each do |subnet|
37
- response.push({
38
- :id => subnet['id'],
39
- :subnet => subnet['subnet'],
40
- :description => subnet['description'],
41
- :mask => subnet['mask']
42
- })
43
- end
44
-
45
- return response.to_json
46
- end
34
+ # Only return the relevant fields
35
+ subnets['data'].each do |subnet|
36
+ response.push({
37
+ :id => subnet['id'],
38
+ :subnet => subnet['subnet'],
39
+ :description => subnet['description'],
40
+ :mask => subnet['mask']
41
+ })
47
42
  end
43
+
44
+ response.to_json
48
45
  end
49
46
 
50
47
  def add_ip_to_subnet(ip, subnet_id, desc)
@@ -52,6 +49,10 @@ module Proxy::Phpipam
52
49
  post('addresses/', data)
53
50
  end
54
51
 
52
+ def get_section(section_name)
53
+ get("sections/#{section_name}/")["data"]
54
+ end
55
+
55
56
  def get_sections
56
57
  sections = get('sections/')['data']
57
58
  response = []
@@ -69,11 +70,7 @@ module Proxy::Phpipam
69
70
  response
70
71
  end
71
72
 
72
- def get_subnets(section_name)
73
- sections = get_sections
74
- section = sections.select {|section| section[:name] == section_name}
75
- return {:error => "Section '#{section_name}' not found"}.to_json if section.size == 0
76
- section_id = section[0][:id].to_s
73
+ def get_subnets(section_id)
77
74
  subnets = get("sections/#{section_id}/subnets/")
78
75
  response = []
79
76
 
@@ -103,8 +100,8 @@ module Proxy::Phpipam
103
100
  return {:ip => ip, :exists => false}.to_json
104
101
  else
105
102
  response = get("subnets/#{subnet_id.to_s}/addresses/#{ip}/")
106
-
107
- if response && response['message'] && response['message'].downcase == 'no addresses found'
103
+
104
+ if ip_not_found_in_ipam(response)
108
105
  return {:ip => ip, :exists => false}.to_json
109
106
  else
110
107
  return {:ip => ip, :exists => true}.to_json
@@ -127,11 +124,11 @@ module Proxy::Phpipam
127
124
 
128
125
  return response if response['message']
129
126
 
130
- if subnet_hash&.key?(mac.to_sym)
127
+ if subnet_hash && subnet_hash.key?(mac.to_sym)
131
128
  response['next_ip'] = @@ip_cache[cidr.to_sym][mac.to_sym]
132
129
  else
133
130
  new_ip = response['data']
134
- ip_not_in_cache = subnet_hash&.key(new_ip).nil?
131
+ ip_not_in_cache = subnet_hash && subnet_hash.key(new_ip).nil?
135
132
 
136
133
  if ip_not_in_cache
137
134
  next_ip = new_ip.to_s
@@ -0,0 +1,36 @@
1
+ module PhpipamHelper
2
+ def validate_required_params(required_params, params)
3
+ err = []
4
+ required_params.each do |param|
5
+ if not params[param.to_sym]
6
+ err.push errors[param.to_sym]
7
+ end
8
+ end
9
+ err.length == 0 ? [] : {:error => err}.to_json
10
+ end
11
+
12
+ def no_subnets_found(subnet)
13
+ !subnet.kind_of?(Array) && subnet['message'] && subnet['message'].downcase == "no subnets found"
14
+ end
15
+
16
+ def no_free_ip_found(ip)
17
+ !ip.kind_of?(Array) && ip['message'] && ip['message'].downcase == "no free addresses found"
18
+ end
19
+
20
+ def ip_not_found_in_ipam(ip)
21
+ ip && ip['message'] && ip['message'].downcase == 'no addresses found'
22
+ end
23
+
24
+ def errors
25
+ {
26
+ :cidr => "A 'cidr' parameter for the subnet must be provided(e.g. 100.10.10.0/24)",
27
+ :mac => "A 'mac' address must be provided(e.g. 00:0a:95:9d:68:10)",
28
+ :ip => "Missing 'ip' parameter. An IPv4 address must be provided(e.g. 100.10.10.22)",
29
+ :section_name => "A 'section_name' must be provided",
30
+ :no_free_ip => "There are no more free addresses in this subnet",
31
+ :no_section => "Section not found in External IPAM.",
32
+ :no_subnet => "The specified subnet does not exist in External IPAM.",
33
+ :no_connection => "Unable to connect to External IPAM server"
34
+ }
35
+ end
36
+ end
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Proxy
3
3
  module Ipam
4
- VERSION = '0.0.11'
4
+ VERSION = '0.0.12'
5
5
  end
6
6
  end
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.11
4
+ version: 0.0.12
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-09-03 00:00:00.000000000 Z
11
+ date: 2019-09-13 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
@@ -27,6 +27,7 @@ files:
27
27
  - lib/smart_proxy_ipam/ipam_main.rb
28
28
  - lib/smart_proxy_ipam/phpipam/phpipam_api.rb
29
29
  - lib/smart_proxy_ipam/phpipam/phpipam_client.rb
30
+ - lib/smart_proxy_ipam/phpipam/phpipam_helper.rb
30
31
  - lib/smart_proxy_ipam/version.rb
31
32
  - settings.d/external_ipam.yml
32
33
  - settings.d/external_ipam.yml.example