pingable_ipam_plugin 0.0.3 → 0.0.8

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: 98f252592af66182ea5caa67ee7e6277b0d6c9a93a746b28c2f949cc13019176
4
- data.tar.gz: f5e007d453bd182a85d3e20bf0441c5276ae9365d9267fe9c8541d2fa187d731
3
+ metadata.gz: 901121ea8d35be4f887e6b29af60a66c5c893519c9e3deb5e68ce115c947eedf
4
+ data.tar.gz: 1debb5df608706ec4d0314eeeaede1d68bd007fd9e845f0ebd69e870713f481a
5
5
  SHA512:
6
- metadata.gz: 001c810cfc73df2a3a3cf0d767b63c5e13f1b53d29d536d13248ee045ec26cf804474c7e71f903f70814d9143ddd431182d5b362b7a1317744ed336984f09542
7
- data.tar.gz: 648e49b2f2884c8bdce12f7bb79b6df125f2d8c32d7cc4bb8c4ea272b063f712c9e881593b51974a35d8bcd178f9742447c3752908a3dd9602c35872156ca26e
6
+ metadata.gz: abb24c738c216d047affce4042bf78b7ddbf3fbbf48127c7e8c0258e8be0d18db81918a99cb1736591977b90eddf74d5daa789ff7681626c5706f224ced2783c
7
+ data.tar.gz: 5d45c0030cd6d41d75094b64d5cfa2084791dd0a49ea330bd30195a7401ecbef33cb3090cc35fbf10adf79706b1e241b367ea240c3978b2cdc0b76faa2777265
@@ -1,5 +1,6 @@
1
1
  require 'timeout'
2
2
  require 'socket'
3
+ require 'resolv'
3
4
 
4
5
  module IPAM
5
6
  class PingRandomDb < Base
@@ -7,8 +8,8 @@ module IPAM
7
8
  @generator ||= Random.new(mac ? mac.delete(':').to_i(16) : Random.new_seed)
8
9
  end
9
10
 
10
- def random_ip
11
- IPAddr.new(generator.rand(subnet_range.first.to_i..subnet_range.last.to_i), subnet.family)
11
+ def random_ip(range)
12
+ IPAddr.new(range.sample)
12
13
  end
13
14
 
14
15
  def tcp_pingable?(ip)
@@ -32,34 +33,20 @@ module IPAM
32
33
  # Whether or not Errno::ECONNREFUSED is considered a successful ping
33
34
  @service_check = true
34
35
  @timeout = 1
35
- @exception = nil
36
36
  bool = false
37
- tcp = nil
38
37
 
39
38
  begin
40
- Timeout.timeout(@timeout) do
41
- begin
42
- tcp = TCPSocket.new(ip, port)
43
- rescue Errno::ECONNREFUSED => err
44
- if @service_check
45
- bool = true
46
- else
47
- @exception = err
48
- end
49
- rescue Exception => err
50
- @exception = err
51
- else
52
- bool = true
53
- end
39
+ bool = Socket.tcp(ip, port, connect_timeout: @timeout) { true }
40
+ rescue Errno::ECONNREFUSED
41
+ if @service_check
42
+ bool = true
54
43
  end
55
- rescue Timeout::Error => err
56
- @exception = err
57
- ensure
58
- tcp.close if tcp
44
+ rescue Exception
45
+ bool = false
59
46
  end
60
47
 
61
48
  if bool
62
- logger.info "Succesful telnet ping #{ip}, port #{port}"
49
+ logger.info "[IPAM] Succesful telnet ping #{ip}, port #{port}"
63
50
  end
64
51
 
65
52
  bool
@@ -77,34 +64,62 @@ module IPAM
77
64
  system("ping -c 2 -W 1 #{ip} > /dev/null")
78
65
  end
79
66
  rescue => err
80
- logger.debug "Unable to icmp ping #{ip} because #{err.inspect}."
67
+ logger.warn "[IPAM] Unable to icmp ping #{ip} because #{err.inspect}."
81
68
  true
82
69
  end
83
70
 
71
+ def ns_resolvable? ip
72
+ begin
73
+ name = Resolv.getname ip
74
+ logger.warn "[IPAM] Found a DNS resolvable IP #{ip}, resolved name: #{name}."
75
+ true
76
+ rescue StandardError
77
+ false
78
+ end
79
+ end
80
+
84
81
  # Safety check not to spend much CPU time when there are no many free IPs left. This gives up
85
82
  # in about a second on Ryzen 1700 running with Ruby 2.4.
86
83
  MAX_ITERATIONS = 100_000
87
84
 
88
85
  def suggest_ip
89
86
  iterations = 0
87
+ # Remove IPs already excluded or known.
88
+ range = subnet_range.to_a - excluded_ips.to_a
89
+ range -= subnet.known_ips.to_a
90
+
91
+ unless range.empty?
92
+ logger.info "[IPAM] IP range from #{range.first.to_s} to #{range.last.to_s}, total: #{range.length}"
93
+ end
94
+
90
95
  loop do
91
- # next random IP from the sequence generated by MAC seed
92
- candidate = random_ip
96
+ if range.empty?
97
+ errors.add(:subnet, _('no free IP could be found in our DB, enlarge subnet range'))
98
+ return nil
99
+ end
100
+
101
+ candidate = random_ip(range)
93
102
  iterations += 1
94
103
  break if iterations >= MAX_ITERATIONS
95
104
  # try to match it
96
105
  ip = candidate.to_s
106
+ # Check again if something has been changed.
97
107
  if !excluded_ips.include?(ip) && !subnet.known_ips.include?(ip)
98
- logger.debug "Searching for free IP - pinging #{ip}."
108
+ logger.info "[IPAM] Searching for free IP - resolving #{ip}"
99
109
  if tcp_pingable?(ip) || icmp_pingable?(ip)
100
- logger.warn("Found a pingable IP (#{ip}) address which not marked as known. Skipping it...")
110
+ logger.warn("[IPAM] Found a pingable IP (#{ip}) address which not marked as known. Skipping it...")
101
111
  else
102
- logger.debug("Found #{ip} in #{iterations} iterations")
103
- return ip
112
+ unless ns_resolvable?(ip)
113
+ logger.info("[IPAM] Found #{ip} in #{iterations} iterations")
114
+ return ip
115
+ end
104
116
  end
105
117
  end
118
+
119
+ range -= [ip]
106
120
  end
107
- logger.debug("Not suggesting IP Address for #{subnet} as no free IP found in reasonable time (#{iterations} iterations)")
121
+
122
+ logger.warn("[IPAM] Not suggesting IP Address for #{subnet} as no free IP found in reasonable time (#{iterations} iterations)")
108
123
  errors.add(:subnet, _('no random free IP could be found in our DB, enlarge subnet range'))
109
124
  nil
110
125
  end
@@ -1,3 +1,3 @@
1
1
  module PingableIpamPlugin
2
- VERSION = '0.0.3'.freeze
2
+ VERSION = '0.0.8'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pingable_ipam_plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Parshin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-20 00:00:00.000000000 Z
11
+ date: 2021-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop