Revision f5aaaae0
Added by Lukas Zapletal over 6 years ago
lib/net/dhcp/record.rb | ||
---|---|---|
module Net::DHCP
|
||
class Record < Net::Record
|
||
attr_accessor :name, :ip, :mac, :network, :nextServer, :filename, :related_macs
|
||
attr_accessor :name, :ip, :mac, :network, :nextServer, :filename, :related_macs, :type
|
||
|
||
def initialize(opts = { })
|
||
super(opts)
|
||
... | ... | |
self.mac = Net::Validations.validate_mac! self.mac
|
||
self.network = Net::Validations.validate_network! self.network
|
||
self.ip = Net::Validations.validate_ip! self.ip
|
||
self.type = opts["type"]
|
||
end
|
||
|
||
def legacy_dhcp_api?
|
||
type.nil?
|
||
end
|
||
|
||
def lease?
|
||
type && type == "lease"
|
||
end
|
||
|
||
def reservation?
|
||
!lease?
|
||
end
|
||
|
||
def to_s
|
||
... | ... | |
|
||
# Returns an array of record objects which are conflicting with our own
|
||
def conflicts
|
||
conflicts = [proxy.record(network, mac), proxy.records_by_ip(network, ip)].flatten.compact.delete_if { |c| c == self || related_macs.include?(c.mac) }
|
||
conflicts = [proxy.record(network, mac), proxy.records_by_ip(network, ip)].flatten.compact.delete_if { |c| c.lease? || c == self || related_macs.include?(c.mac) }
|
||
@conflicts ||= conflicts.uniq {|c| c.attrs}
|
||
end
|
||
|
||
... | ... | |
|
||
# If we're converting an 'ad-hoc' lease created by a host booting outside of Foreman's knowledge,
|
||
# then :hostname will be blank on the incoming lease - if the ip/mac still match, then this
|
||
# isn't a conflict.
|
||
to_compare << :hostname if other.attrs[:hostname].present? && attrs[:hostname].present?
|
||
# isn't a conflict. Only applicable on legacy proxy API without "type" attribute.
|
||
if legacy_dhcp_api?
|
||
to_compare << :hostname if other.attrs[:hostname].present? && attrs[:hostname].present?
|
||
end
|
||
|
||
# Not all DHCP smart-proxy providers support TFTP filename option (e.g. libvirt).
|
||
to_compare << :filename if other.attrs[:filename].present? && attrs[:filename].present?
|
||
... | ... | |
end
|
||
|
||
def attrs
|
||
{ :hostname => hostname, :mac => mac, :ip => ip, :network => network,
|
||
:nextServer => nextServer, :filename => filename, :name => name,
|
||
:related_macs => related_macs
|
||
{
|
||
:hostname => hostname,
|
||
:mac => mac,
|
||
:ip => ip,
|
||
:network => network,
|
||
:nextServer => nextServer,
|
||
:filename => filename,
|
||
:name => name,
|
||
:related_macs => related_macs,
|
||
:type => type
|
||
}.delete_if { |k, v| v.nil? }
|
||
end
|
||
end
|
test/unit/net/dhcp_test.rb | ||
---|---|---|
|
||
class DhcpTest < ActiveSupport::TestCase
|
||
setup do
|
||
@lease1 = '{
|
||
@lease1 = setup_lease('{
|
||
"starts": "2014-05-09 11:55:21 UTC",
|
||
"ends": "2214-05-09 12:05:21 UTC",
|
||
"state": "active",
|
||
"mac": "aa:bb:cc:dd:ee:01",
|
||
"subnet": "127.0.0.0/255.0.0.0",
|
||
"ip": "127.0.0.1"
|
||
}'
|
||
@lease1.stubs(:code).returns(200)
|
||
@lease1.stubs(:body).returns(@lease1)
|
||
@lease1_array = '[{
|
||
"starts": "2014-05-09 11:55:21 UTC",
|
||
"ends": "2214-05-09 12:05:21 UTC",
|
||
"state": "active",
|
||
"mac": "aa:bb:cc:dd:ee:01",
|
||
"subnet": "127.0.0.0/255.0.0.0",
|
||
"ip": "127.0.0.1"
|
||
}]'
|
||
@lease1_array.stubs(:code).returns(200)
|
||
@lease1_array.stubs(:body).returns(@lease1_array)
|
||
}')
|
||
@lease1_array = setup_lease_array(@lease1)
|
||
end
|
||
|
||
test "dhcp record should not be created without a mac" do
|
||
... | ... | |
end
|
||
|
||
test "dhcp record must validate with multiple leases with same MAC" do
|
||
@lease2 = '{
|
||
lease2 = setup_lease('{
|
||
"starts": "2014-05-09 11:55:21 UTC",
|
||
"ends": "2214-05-09 12:05:21 UTC",
|
||
"state": "active",
|
||
"mac": "aa:bb:cc:dd:ee:01",
|
||
"subnet": "127.0.0.0/255.0.0.0",
|
||
"ip": "127.0.0.2"
|
||
}'
|
||
@lease2.stubs(:code).returns(200)
|
||
@lease2.stubs(:body).returns(@lease2)
|
||
@lease2_array = '[{
|
||
}')
|
||
lease2_array = setup_lease_array(lease2)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/mac/aa:bb:cc:dd:ee:01").returns(lease2)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.1").returns(@lease1_array)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.2").returns(lease2_array)
|
||
record1 = Net::DHCP::Record.new(:hostname => "discovered_host1", :mac => "aa:bb:cc:dd:ee:01",
|
||
:network => "127.0.0.0", :ip => "127.0.0.2",
|
||
"proxy" => subnets(:one).dhcp_proxy)
|
||
assert record1.conflicts.empty?
|
||
assert record1.valid?
|
||
end
|
||
|
||
test "dhcp record and lease with same MAC is not a conflict" do
|
||
existing_lease = setup_lease('{
|
||
"starts": "2014-05-09 11:55:21 UTC",
|
||
"ends": "2214-05-09 12:05:21 UTC",
|
||
"state": "active",
|
||
"mac": "aa:bb:cc:dd:ee:01",
|
||
"subnet": "127.0.0.0/255.0.0.0",
|
||
"ip": "127.0.0.2"
|
||
}]'
|
||
@lease2_array.stubs(:code).returns(200)
|
||
@lease2_array.stubs(:body).returns(@lease2_array)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/mac/aa:bb:cc:dd:ee:01").returns(@lease2)
|
||
"ip": "127.0.0.2",
|
||
"type": "lease"
|
||
}')
|
||
existing_lease_array = setup_lease_array(existing_lease)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/mac/aa:bb:cc:dd:ee:01").returns(existing_lease)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.2").returns(existing_lease_array)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.1").returns(@lease1_array)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.2").returns(@lease2_array)
|
||
record1 = Net::DHCP::Record.new(:hostname => "discovered_host1", :mac => "aa:bb:cc:dd:ee:01",
|
||
:network => "127.0.0.0", :ip => "127.0.0.2",
|
||
rec = Net::DHCP::Record.new(:hostname => "a_host1", :mac => "aa:bb:cc:dd:ee:01",
|
||
:network => "127.0.0.0", :ip => "127.0.0.1",
|
||
"proxy" => subnets(:one).dhcp_proxy)
|
||
assert record1.conflicts.empty?
|
||
assert record1.valid?
|
||
assert_equal "lease", subnets(:one).dhcp_proxy.record("127.0.0.0", "aa:bb:cc:dd:ee:01").type
|
||
assert_equal "lease", subnets(:one).dhcp_proxy.records_by_ip("127.0.0.0", "127.0.0.2").first.type
|
||
assert rec.conflicts.empty?
|
||
end
|
||
|
||
test "dhcp record and reservation with same MAC is not a conflict" do
|
||
existing_lease = setup_lease('{
|
||
"starts": "2014-05-09 11:55:21 UTC",
|
||
"ends": "2214-05-09 12:05:21 UTC",
|
||
"state": "active",
|
||
"mac": "aa:bb:cc:dd:ee:01",
|
||
"subnet": "127.0.0.0/255.0.0.0",
|
||
"ip": "127.0.0.2",
|
||
"type": "reservation"
|
||
}')
|
||
existing_lease_array = setup_lease_array(existing_lease)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/mac/aa:bb:cc:dd:ee:01").returns(existing_lease)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.2").returns(existing_lease_array)
|
||
ProxyAPI::Resource.any_instance.stubs(:get).with("127.0.0.0/ip/127.0.0.1").returns(@lease1_array)
|
||
rec = Net::DHCP::Record.new(:hostname => "a_host1", :mac => "aa:bb:cc:dd:ee:01",
|
||
:network => "127.0.0.0", :ip => "127.0.0.1",
|
||
"proxy" => subnets(:one).dhcp_proxy)
|
||
assert_equal "reservation", subnets(:one).dhcp_proxy.record("127.0.0.0", "aa:bb:cc:dd:ee:01").type
|
||
assert_equal "reservation", subnets(:one).dhcp_proxy.records_by_ip("127.0.0.0", "127.0.0.2").first.type
|
||
refute rec.conflicts.empty?
|
||
end
|
||
|
||
private
|
||
... | ... | |
def make_record(attrs = {})
|
||
Net::DHCP::Record.new({:mac => "aa:bb:cc:dd:ee:ff", :network => "127.0.0.0", :ip => "127.0.0.1", "proxy" => smart_proxies(:one)}.merge(attrs))
|
||
end
|
||
|
||
def setup_lease(attrs_str)
|
||
lease = attrs_str
|
||
lease.stubs(:code).returns(200)
|
||
lease.stubs(:body).returns(lease)
|
||
lease
|
||
end
|
||
|
||
def setup_lease_array(lease)
|
||
lease_array = "[#{lease}]"
|
||
lease_array.stubs(:code).returns(200)
|
||
lease_array.stubs(:body).returns(lease_array)
|
||
lease_array
|
||
end
|
||
end
|
Also available in: Unified diff
Fixes #19706 - don't treat DHCP leases as conflicts