smart_proxy_ipam 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
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