Project

General

Profile

« Previous | Next » 

Revision f2248acc

Added by Ohad Levy over 12 years ago

  • ID f2248accb505ab1736b67c656971656a72c3d93e

clean up code passing, and removed duplicate code between dhcp server implementations

View differences:

lib/dhcp_api.rb
post "/dhcp/:network" do
begin
content_type :json
options = params.reject{|k,v| k["network"]}
@server.addRecord(options)
@server.addRecord(params)
rescue Proxy::DHCP::Collision => e
log_halt 409, e
rescue Proxy::DHCP::AlreadyExists
lib/proxy/dhcp/record.rb
class Record
attr_reader :ip, :mac, :subnet
attr_writer :options
include Proxy::DHCP
include Proxy::Log
include Proxy::Validations
def initialize(subnet, ip, mac, options = nil)
@subnet = validate_subnet subnet
@ip = validate_ip ip
@mac = validate_mac mac.downcase
def initialize options = {}
@subnet = validate_subnet options[:subnet]
@ip = validate_ip options[:ip]
@mac = validate_mac options[:mac]
@deleteable = options.delete(:deleteable) if options[:deleteable]
@options = options
@subnet.add_record(self)
@deleteable = @options.delete(:omshell) if @options and @options[:omshell]
end
def to_s
......
self
end
def options= value
@options = value
end
def options
@options || subnet.server.loadRecordOptions(self).merge(:mac => mac, :ip => ip)
@options.empty? ? @options = subnet.server.loadRecordOptions(self).merge(:mac => mac, :ip => ip) : @options
end
def [] opt
@options[opt]
rescue
nil
end
#TODO move this away from here, as this suppose to be a generic interface
lib/proxy/dhcp/record/lease.rb
@starts = args[:starts]
@ends = args[:ends]
@state = args[:state]
super(args[:subnet], args[:ip], args[:mac],args[:options])
super(args)
end
def deletable?
lib/proxy/dhcp/record/reservation.rb
module Proxy::DHCP
# represent a DHCP Record
class Reservation < Record
attr_reader :name
def initialize options = {}
@name = options[:name] || options[:hostname] || raise("Must define a name: #{@options.inspect}")
super options
end
def to_s
"#{name} (#{ip} / #{mac})"
end
def method_missing arg
@options[arg]
lib/proxy/dhcp/server.rb
ip = validate_ip options[:ip]
mac = validate_mac options[:mac]
name = options[:hostname] || raise(Proxy::DHCP::Error, "Must provide hostname")
net = options.delete("network")
subnet = find_subnet(net) || raise(Proxy::DHCP::Error, "No Subnet detected for: #{net.inspect}")
raise(Proxy::DHCP::Error, "DHCP implementation does not support Vendor Options") if vendor_options_included?(options) and !vendor_options_supported?
raise Proxy::DHCP::Error, "Unknown subnet for #{ip}" unless subnet = find_subnet(IPAddr.new(ip))
# try to figure out if we already have this record
record = find_record(options[:ip]) || find_record(options[:mac])
record = find_record(ip) || find_record(mac)
unless record.nil?
if Record.compare_options(record.options, options)
# we already got this record, no need to do anything
......
logger.warn "Request to create a conflicting record"
logger.debug "request: #{options.inspect}"
logger.debug "local: #{record.options.inspect}"
raise Proxy::DHCP::Collision, "Record #{options[:network]}/#{options[:ip]} already exists"
raise Proxy::DHCP::Collision, "Record #{net}/#{ip} already exists"
end
end
Proxy::DHCP::Reservation.new(options.merge({:subnet => subnet, :ip => ip, :mac => mac}))
end
def delRecord subnet, record
lib/proxy/dhcp/server/isc.rb
end
def addRecord options = {}
super(options)
ip = options[:ip]
mac = options[:mac]
name = options[:hostname]
subnet = find_subnet(IPAddr.new(ip))
msg = "Added DHCP reservation for #{name}"
record = super(options)
omcmd "connect"
omcmd "set name = \"#{name}\""
omcmd "set ip-address = #{ip}"
omcmd "set hardware-address = #{mac}"
omcmd "set name = \"#{record.name}\""
omcmd "set ip-address = #{record.ip}"
omcmd "set hardware-address = #{record.mac}"
omcmd "set hardware-type = 1" # This is ethernet
options = record.options
# TODO: Extract this block into a generic dhcp options helper
statements = []
statements << "filename = \\\"#{options[:filename]}\\\";" if options[:filename]
statements << bootServer(options[:nextserver]) if options[:nextserver]
statements << "option host-name = \\\"#{name}\\\";" if name
statements << "filename = \\\"#{options[:filename]}\\\";" if options[:filename]
statements << bootServer(options[:nextServer]) if options[:nextServer]
statements << "option host-name = \\\"#{record.name}\\\";" if record.name
omcmd "set statements = \"#{statements.join(" ")}\"" unless statements.empty?
omcmd "create"
omcmd("disconnect", msg)
Proxy::DHCP::Reservation.new(subnet, ip, mac, options)
omcmd("disconnect", "Added DHCP reservation for #{record}")
record
end
def loadSubnetData subnet
......
end
end
begin
Proxy::DHCP::Reservation.new(subnet, opts[:ip], opts[:mac], opts) if subnet.include? opts[:ip]
Proxy::DHCP::Reservation.new(opts.merge({:subnet => subnet})) if subnet.include? opts[:ip]
rescue Exception => e
logger.warn "skipped #{hostname} - #{e}"
end
......
when /^supersede server.filename\s+=\s+"(\S+)"/
options[:filename] = $1
when "dynamic"
options[:omshell] = true
options[:deleteable] = true
#TODO: check if adding a new reservation with omshell for a free lease still
#generates a conflict
end
lib/proxy/dhcp/server/native_ms.rb
end
def addRecord options={}
super(options)
ip = options.delete "ip"
mac = options.delete "mac"
name = options.delete "name"
subnet = find_subnet options.delete "network"
msg = "Added DHCP reservation for #{name} => #{ip} - #{mac}"
cmd = "scope #{subnet.network} add reservedip #{ip} #{mac.gsub(/:/,"")} #{name}"
execute(cmd, msg)
record = super(options)
cmd = "scope #{record.subnet.network} add reservedip #{record.ip} #{record.mac.gsub(/:/,"")} #{record.name}"
execute(cmd, "Added DHCP reservation for #{record}")
options = record.options
options.delete_if{|k,v| k == :ip or k == :mac or k == :name }
return if options.empty? # This reservation is just for an IP and MAC
# TODO: Refactor these execs into a popen
......
if match = key.match(/^<([^>]+)>(.*)/)
vendor, attr = match[1,2]
begin
execute "scope #{subnet.network} set reservedoptionvalue #{ip} #{SUNW[attr][:code]} #{SUNW[attr][:kind]} vendor=#{alternate_vendor_name || vendor} #{value}", msg, true
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
alternate_vendor_name = find_or_create_vendor_name vendor, e
execute "scope #{subnet.network} set reservedoptionvalue #{ip} #{SUNW[attr][:code]} #{SUNW[attr][:kind]} vendor=#{alternate_vendor_name || vendor} #{value}", msg, true
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 #{subnet.network} set reservedoptionvalue #{ip} #{Standard[key][:code]} #{Standard[key][:kind]} #{value}", msg, true
execute "scope #{record.subnet.network} set reservedoptionvalue #{record.ip} #{Standard[key][:code]} #{Standard[key][:kind]} #{value}", msg, true
end
end
record = Proxy::DHCP::Reservation.new subnet, ip, mac, options
record
end
# We did not find the vendor name we wish to use registered on the DHCP server so we attempt to find if there is a vendor class using an abbreviated name.
lib/proxy/validations.rb
# validates the mac
def validate_mac mac
raise Error, "Invalid MAC #{mac}" unless mac =~ /([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/i
mac
mac.downcase
end
def validate_subnet subnet

Also available in: Unified diff