Project

General

Profile

« Previous | Next » 

Revision 9a387048

Added by Greg Sutcliffe over 11 years ago

  • ID 9a38704839f089942683842e6ebc369cb8502181

fixes #2016 Use a tmpfile+lockfile to avoid race conditions in IP suggestion

View differences:

lib/proxy/dhcp/monkey_patch_subnet.rb
class Array
# Ruby1.8 doesn't have a rotate function, so we add our own...
def rotate n = 1
return self if empty?
n %= length
self[n..-1]+self[0...n]
end
end
lib/proxy/dhcp/subnet.rb
require 'checks'
require 'ipaddr'
require 'proxy/dhcp/monkey_patches' unless IPAddr.new.respond_to?('to_range')
require 'proxy/dhcp/monkey_patch_subnet' unless Array.new.respond_to?('rotate')
require 'ping' unless RUBY_1_9
require 'proxy/validations'
require 'net/ping'
require 'timeout'
require 'tmpdir'
module Proxy::DHCP
# Represents a DHCP Subnet
......
"#{network}/#{netmask}"
end
def cidr
IPAddr.new(netmask).to_i.to_s(2).count("1")
end
def range
r=valid_range
"#{r.first.to_s}-#{r.last.to_s}"
......
return false
end
def get_index_and_lock filename
# Store for use in the unlock method
@filename = "#{Dir::tmpdir}/#{filename}"
@lockfile = "#{@filename}.lock"
# Loop if the file is locked
Timeout::timeout(30) { sleep 0.1 while File.exists? @lockfile }
# Touch the lock the file
File.open(@lockfile, "w") {}
@file = File.new(@filename,'r+') rescue File.new(@filename,'w+')
# this returns the index in the file
return @file.readlines.first.to_i rescue 0
end
def set_index_and_unlock index
@file.reopen(@filename,'w')
@file.write index
@file.close
File.delete @lockfile
end
# returns the next unused IP Address in a subnet
# Pings the IP address as well (just in case its not in Proxy::DHCP)
def unused_ip args = {}
......
logger.warn "No free IPs at #{to_s}"
return nil
else
free_ips.each do |ip|
logger.debug "Searching for free ip - pinging #{ip}"
if tcp_pingable?(ip) or icmp_pingable?(ip)
logger.info "Found a pingable IP(#{ip}) address which does not have a Proxy::DHCP record"
else
logger.debug "Found free ip #{ip} out of a total of #{free_ips.size} free ips"
return ip
@index = 0
begin
# Read and lock the storage file
stored_index = get_index_and_lock("foreman-proxy_#{network}_#{cidr}.tmp")
free_ips.rotate(stored_index).each do |ip|
logger.debug "Searching for free ip - pinging #{ip}"
if tcp_pingable?(ip) or icmp_pingable?(ip)
logger.info "Found a pingable IP(#{ip}) address which does not have a Proxy::DHCP record"
else
logger.debug "Found free ip #{ip} out of a total of #{free_ips.size} free ips"
@index = free_ips.index(ip)+1
return ip
end
end
logger.warn "No free IPs at #{to_s}"
rescue Exception => e
logger.debug e.message
ensure
# ensure we unlock the storage file
set_index_and_unlock @index
end
logger.warn "No free IPs at #{to_s}"
nil
end
end

Also available in: Unified diff