Revision de1ecf7b
Added by Ohad Levy over 12 years ago
- ID de1ecf7b5c4b564c3db6760d35fd7563dee70652
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
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.