Revision f2248acc
Added by Ohad Levy over 12 years ago
- ID f2248accb505ab1736b67c656971656a72c3d93e
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
clean up code passing, and removed duplicate code between dhcp server implementations