Project

General

Profile

« Previous | Next » 

Revision de1ecf7b

Added by Ohad Levy over 12 years ago

  • ID de1ecf7b5c4b564c3db6760d35fd7563dee70652

fixes #1154 - ms dhcp smart proxy error 400

This commit is not ideal in term of performance, as it forces us to read each
reservation options, a probably better approch is to read the output from the
dump command instead.

View differences:

lib/proxy/dhcp.rb
require "proxy/dhcp/record/reservation"
require "proxy/dhcp/server"
Standard = {
"hostname" => {:code => 12, :kind => "String" }, # The host's name
"nextserver" => {:code => 66, :kind => "String" }, # From where we download the pxeboot image via TFTP
"filename" => {:code => 67, :kind => "String" } # The pxeboot image
:hostname => {:code => 12, :kind => "String" }, # The host's name
:nextServer => {:code => 66, :kind => "String" }, # From where we download the pxeboot image via TFTP
:filename => {:code => 67, :kind => "String" } # The pxeboot image
}
SUNW = {
"root_server_ip" => {:code => 2, :kind => "IPAddress" }, # 192.168.216.241
"root_server_hostname" => {:code => 3, :kind => "String" }, # mediahost
"root_path_name" => {:code => 4, :kind => "String" }, # /vol/solgi_5.10/sol10_hw0910/Solaris_10/Tools/Boot
"install_server_ip" => {:code => 10, :kind => "IPAddress" }, # 192.168.216.241
"install_server_name" => {:code => 11, :kind => "String" }, # mediahost
"install_path" => {:code => 12, :kind => "String" }, # /vol/solgi_5.10/sol10_hw0910
"sysid_server_path" => {:code => 13, :kind => "String" }, # 192.168.216.241:/vol/jumpstart/sysidcfg/sysidcfg_primary
"jumpstart_server_path" => {:code => 14, :kind => "String" } # 192.168.216.241:/vol/jumpstart
:root_server_ip => {:code => 2, :kind => "IPAddress" }, # 192.168.216.241
:root_server_hostname => {:code => 3, :kind => "String" }, # mediahost
:root_path_name => {:code => 4, :kind => "String" }, # /vol/solgi_5.10/sol10_hw0910/Solaris_10/Tools/Boot
:install_server_ip => {:code => 10, :kind => "IPAddress" }, # 192.168.216.241
:install_server_name => {:code => 11, :kind => "String" }, # mediahost
:install_path => {:code => 12, :kind => "String" }, # /vol/solgi_5.10/sol10_hw0910
:sysid_server_path => {:code => 13, :kind => "String" }, # 192.168.216.241:/vol/jumpstart/sysidcfg/sysidcfg_primary
:jumpstart_server_path => {:code => 14, :kind => "String" } # 192.168.216.241:/vol/jumpstart
}
class Error < RuntimeError; end
class Collision < RuntimeError; end
lib/proxy/dhcp/record.rb
# represent a DHCP Record
class Record
attr_reader :ip, :mac, :subnet
attr_writer :options
attr_reader :ip, :mac, :subnet, :options
include Proxy::DHCP
include Proxy::Log
include Proxy::Validations
......
self
end
def options
@options.empty? ? @options = subnet.server.loadRecordOptions(self).merge(:mac => mac, :ip => ip) : @options
end
def [] opt
@options[opt]
options[opt.to_sym]
rescue
nil
end
lib/proxy/dhcp/record/reservation.rb
attr_reader :name
def initialize options = {}
@name = options[:name] || options[:hostname] || raise("Must define a name: #{@options.inspect}")
@name = options[:name] || options[:hostname] || raise("Must define a name: #{options.inspect}")
super options
end
......
end
def method_missing arg
@options[arg]
options[arg]
end
end
lib/proxy/dhcp/server/isc.rb
report "Enumerated hosts on #{subnet.network}"
end
# loadRecordOptions is called when a reservation does not have any options at all.
# It is not clear how this could ever occur in this server implementation
def loadRecordOptions
{} # No options
end
private
def loadSubnets
super
lib/proxy/dhcp/server/native_ms.rb
execute(cmd, "Added DHCP reservation for #{record}")
options = record.options
options.delete_if{|k,v| k == :ip or k == :mac or k == :name }
ignored_attributes = [:ip, :mac, :name, :subnet]
options.delete_if{|k,v| ignored_attributes.include?(k.to_sym) }
return if options.empty? # This reservation is just for an IP and MAC
# TODO: Refactor these execs into a popen
alternate_vendor_name = nil
for key, value in options
if match = key.match(/^<([^>]+)>(.*)/)
vendor, attr = match[1,2]
if match = key.to_s.match(/^<([^>]+)>(.*)/)
vendor, attr = match[1,2].map(&:to_sym)
msg = "set value for #{key}"
begin
execute "scope #{record.subnet.network} set reservedoptionvalue #{record.ip} #{SUNW[attr][:code]} #{SUNW[attr][:kind]} vendor=#{alternate_vendor_name || vendor} #{value}", msg, true
rescue Proxy::DHCP::Error => e
......
execute "scope #{record.subnet.network} set reservedoptionvalue #{ip} #{SUNW[attr][:code]} #{SUNW[attr][:kind]} vendor=#{alternate_vendor_name || vendor} #{value}", msg, true
end
else
execute "scope #{record.subnet.network} set reservedoptionvalue #{record.ip} #{Standard[key][:code]} #{Standard[key][:kind]} #{value}", msg, true
logger.debug "key: " + key.inspect
k = Standard[key] || Standard[key.to_sym]
execute "scope #{record.subnet.network} set reservedoptionvalue #{record.ip} #{k[:code]} #{k[:kind]} #{value}", msg, true
end
end
......
# 172.29.216.6 - 00-a0-e7-21-41-00-
if line =~ /^\s+([\w\.]+)\s+-\s+([-a-f\d]+)/
ip = $1
next unless subnet.include?(ip)
mac = $2.gsub(/-/,":").match(/^(.*?).$/)[1]
begin
Proxy::DHCP::Reservation.new(subnet, ip, mac) if subnet.include? ip
opts = {:subnet => subnet, :ip => ip, :mac => mac}
opts.merge!(loadRecordOptions(opts))
logger.debug opts.inspect
if opts.include? :hostname
Proxy::DHCP::Reservation.new opts.merge({:deleteable => true})
else
# this is not a lease, rather reservation
# but we require option 12(hostname) to be defined for our leases
# workaround until #1172 is resolved.
Proxy::DHCP::Lease.new opts
end
rescue Exception => e
logger.warn "Skipped #{line} - #{e}"
end
......
subnet.options = parse_options(execute(cmd, msg))
end
def loadRecordOptions record
raise "invalid Record" unless record.is_a? Proxy::DHCP::Record
subnet = record.subnet
raise "unable to find subnet for #{record}" if subnet.nil?
cmd = "scope #{subnet.network} Show ReservedOptionValue #{record.ip}"
msg = "Queried #{record.ip} options"
private
def loadRecordOptions opts
raise "unable to find subnet for #{opts[:ip]}" if opts[:subnet].nil?
cmd = "scope #{opts[:subnet].network} Show ReservedOptionValue #{opts[:ip]}"
msg = "Queried #{opts[:ip]} options"
record.options = parse_options(execute(cmd, msg)).merge(:ip => record.ip, :mac => record.mac)
parse_options(execute(cmd, msg))
end
def installVendorClass vendor_class
......
end
end
private
def loadVendorClasses
cmd = "show class"
msg = "Queried vendor classes"
......
std_in = std_out = std_err = nil
begin
timeout(tsecs) do
logger.debug "executing: #{command}"
std_in, std_out, std_err = Open3.popen3(command)
response = std_out.readlines
response += std_err.readlines
......
break if line.match(/^Command completed/)
case line
when /For vendor class \[([^\]]+)\]:/
vendor = "<#{$1}>"
when /OptionId : (\d+)/
optionId = "#{vendor}#{$1}"
when /Option Element Value = (\S+)/
options[optionId] = $1
when /For vendor class \[([^\]]+)\]:/
vendor = "<#{$1}>"
when /OptionId : (\d+)/
optionId = "#{vendor}#{$1}".to_i
when /Option Element Value = (\S+)/
title = Standard.select {|k,v| v[:code] == optionId}.flatten[0]
logger.debug "found option #{title}"
options[title] = $1
end
end
logger.debug options.inspect
return options
end
......
break if line.match(/^Command completed/)
case line
when /Class \[([^\]]+)\]:/
klass = $1
when /Isvendor= TRUE/
classes << klass
when /Class \[([^\]]+)\]:/
klass = $1
when /Isvendor= TRUE/
classes << klass
end
end
return classes
views/dhcp/show.erb
<td><%= record.mac %></td>
<td><%= record.nextServer %></td>
<td><%= record.filename %></td>
<td><%= record.title %></td>
<td><%= record.name %></td>
<td>
<form action="<%= "/dhcp/#{@subnet.network}/#{record.mac}" %>" method="post">
<input name='_method' type='hidden' value='delete' />

Also available in: Unified diff