diff --git a/app/views/hosts/_unattended.html.erb b/app/views/hosts/_unattended.html.erb index b3cfe9b..7647b86 100644 --- a/app/views/hosts/_unattended.html.erb +++ b/app/views/hosts/_unattended.html.erb @@ -5,6 +5,7 @@ Domain <%= f.collection_select :domain_id, Domain.all, :id, :to_label %> Subnet + <% if sn = Subnet.first.dhcp; DHCP.cache_server @dhcp_servers, @dhcp, @user_data, dhcp; end -%> <%= f.collection_select :subnet_id, Subnet.all, :id, :to_label %> IP <%= f.text_field :ip, :size => 16 %> @@ -48,6 +49,9 @@ <% end -%> <% end -%> +<%= observe_field(:host_subnet_id, + :url => { :action => :subnet_selected, :id => @host.id }, + :with => :subnet_id)%> <%= observe_field(:host_architecture_id, :url => { :action => :architecture_selected, :id => @host.id }, diff --git a/init.rb b/init.rb index e4d3f7b..51d35ab 100644 --- a/init.rb +++ b/init.rb @@ -1,3 +1,3 @@ #require_dependency File.join(File.dirname(__FILE__), "..", "..", "..", "config", "initializers", "foreman") -require 'netdb_manager' +require_dependency 'netdb_manager' ActiveSupport::Dependencies.load_once_paths.delete lib_path \ No newline at end of file diff --git a/lib/dhcp.rb b/lib/dhcp.rb deleted file mode 100644 index 89e27cc..0000000 --- a/lib/dhcp.rb +++ /dev/null @@ -1,281 +0,0 @@ -# A generic module for dhcp queries and commands -# This is accessible on two levels: -# A top-level hash based class which models all the subnets within the database -# A second-level hash based class which represents a single DHCP server -# The second level class is vendor specific Currently we support Microsoft Servers -# via a web based gateway to the netsh.exe program and the InfoBlox DHCP server, which -# is accessed directly -# The DHCP entries are cached in a Memcache store and are shared among all users of the -# system -module DHCP - # There has been a problem with the gateway transport or the data - # we received does not make sense - class DHCPError < RuntimeError; end - - # This class models the DHCP subnets within the organisation - # After initialisation - # dhcp = DHCP::Server.new(per_user_data_hash) - # individual subnets can be referenced by - # dhcp["172.29.216.0"] - # and data is available via - # mac = dhcp["172.29.216.0"]["172.29.216.12"] - # A particular server can be found by - # dhcp.serverFor["172.29.216.0"] - class Dhcp < Hash - attr_reader :user - attr_accessor :denied - - def to_s - "[" + self.keys.join(",") + "]" - end - - def logger; RAILS_DEFAULT_LOGGER; end - - # Set the per_user_data in this DHCP instance and in all DHCPServer instances - # [+per_user_data+] : Hash located in the user's session - def personalise per_user_data - for server in @servers.values - server.personalise per_user_data - end - # Extract the DHCP object's per_user_data - # This is a list of server addresses that have denied us access or are unavailable - # Some dhcp server implementations may grant or deny access based on the user - @denied = per_user_data[:denied] ||= [] - @user = per_user_data[:user] - end - - # Populate my hash with {subnet_number => nil, subnet_number => nil, . . .} - # These hashes will be filled in when the subnet is first accessed - # [+per_user_data+] : Hash located in the user's session - def initialize(per_user_data) - super() - - @servers = {} - - personalise per_user_data - - @initialized = false - for subnet in Subnet.all.map(&:number) - self[subnet] = nil - end - @initialized = true - flush - end - - # A reference to a scope will instantiate the relevant DHCP server type and - # link the server's scopes into this object - #[+scope+] : String representation of the scope's IP address - def [](scope) - sn = Subnet.find_by_number(scope) - dhcpServerAddress = sn.dhcp.address - if self.has_key? scope and not @denied.include?(dhcpServerAddress) and @initialized and - (self.fetch(scope).nil? or self.fetch(scope).size == 0) - if @servers[dhcpServerAddress].nil? - gateway = sn.domain.gateway # This will be nil if using InfoBlox - vendor = sn.dhcp.vendor.name - logger.debug "Cache miss for scope #{scope}" - begin - @servers[dhcpServerAddress] = eval("#{vendor}DHCPServer").new(dhcpServerAddress, self, gateway) - rescue NameError - raise "Failed to load DHCP vendor library. Class #{vendor}DHCPServer unavailable" - end - logger.debug "Loaded #{vendor} server #{dhcpServerAddress}" - end - server = @servers[dhcpServerAddress] - # Do a cache probe to trigger a scope read - server[scope]["0.0.0.0"] - self[scope] = server[scope] - flush - end - super # Finally call the Hash[] method to return the data that we have obtained - end - - # This method returns the dhcp server that manages this subnet It also loads the server's scopes whilst - # it does this and therefore reports the user's permissions on that server - # [+number+] : String representation of the desired subnet numer - def serverFor number - # Trigger a cache probe to be sure that the server's data has been loaded - self[number] - sn = Subnet.find_by_number(number) - @servers[sn.dhcp.address] - end - - # Remove all cached ad uncached data for the subnet - # [+subnet_number+] : String representation of the subnet's number - def invalidate subnet_number - logger.debug "Erasing DHCP data for #{subnet_number}" - self[subnet_number] = nil - server = serverFor subnet_number - server[subnet_number] = nil - flush - end - - # Push our DHCP datastructure into the memcache for others to use - def flush - # Reserialize the DHCP data back into the cache - # We have to use a dup or otherwise we are frozen. - Rails.cache.write(:dhcp, self.dup, :expires_in => NET_TTL) - end - end # class Dhcp - - # This abstract class models a generic DHCP server - # After initialisation - # # dhcp = DHCPServer.new("172.29.216.40", parent DHCP object) - # entries can be accessed by - # mac = dhcp["172.29.216"]["172.29.205.26"] - class DHCPServer < Hash - @@Option = {"hostname" => {"code" => 12, "vendor" => false, "type" => "string"},\ - "TFTP boot server" => {"code" => 66, "vendor" => false, "type" => "string"},\ - "TFTP boot file" => {"code" => 67, "vendor" => false, "type" => "string"},\ - "root server ip address" => {"code" => 2, "vendor" => true, "type" => "ipaddress"},\ - "root path name" => {"code" => 4, "vendor" => true, "type" => "string"},\ - "install server ip address" => {"code" => 10, "vendor" => true, "type" => "ipaddress"},\ - "install server hostname" => {"code" => 11, "vendor" => true, "type" => "string"},\ - "install path" => {"code" => 12, "vendor" => true, "type" => "string"},\ - "sysid config file server" => {"code" => 13, "vendor" => true, "type" => "string"},\ - "jumpstart server" => {"code" => 14, "vendor" => true, "type" => "string"}\ - } - - @@debug = false - attr_reader :dhcpServerAddress, :dhcp, :message - - def logger; RAILS_DEFAULT_LOGGER; end - def netdbType; "DHCP"; end - - def personalise per_user_data - # Override this function in your vendor implemetion to retrieve per_user data - # See DHCP#personalise - end - - def denied? - @dhcp.denied.include? @dhcpServerAddress - end - - def to_s - "[" + self.keys.join(",") + "]" - end - - # A reference to a scopeIpAddress will populate our hash - #[+ScopeIpAddress+] : String containing the scope IP address - def [](scopeIpAddress) - raise DHCPError.new("The subnet #{scopeIpAddress} is not managed by #{@dhcpServerAddress}") if not self.has_key? scopeIpAddress and not denied? - if self.has_key? scopeIpAddress and self.fetch(scopeIpAddress).nil? and not denied? - self[scopeIpAddress] = {} - if loadScopeData scopeIpAddress, self.fetch(scopeIpAddress) - @dhcp.flush - else - @dhcp.denied << @dhcpServerAddress - end - end - super # Finally call the Hash[] method to return the data that we have obtained - end - - # Connect to the named DHCP server and populate our hash keys with the scope that the machine servers - # [+dhcpServerAdress+] : String containing the DHCP server's IP addresss - # [+dhcp+] : The parent Dhcp object - def initialize(dhcpServerAddress, dhcp) - super() - - @dhcpServerAddress = dhcpServerAddress - @dhcp = dhcp - # This variable contains the last error detected in the library - @message = "" - - scopes = loadScopes unless denied? - if scopes - scopes.each do |scope| - self[scope] = nil - end - else - @dhcp.denied << @dhcpServerAddress - end - end - # Remove a DHCP reservation - # [+host+] : Host object - # [+sp+] : Boolean which indicates whether we are dealing with the primary or service processor reservation - def delReservation(host, sp = nil) - scopeIpAddress = sp ? host.sp_subnet.number : host.subnet.number - ip = sp ? host.sp_ip : host.ip - # It is not an error to remove an entry that does not exist. After all, the reservation has been removed. :-) - ((@message = "#{ip} is not registered in the DHCP") and return true) unless self[scopeIpAddress].has_key? ip - - if delRecordFor scopeIpAddress, ip - # Reserialize the DHCP data back into the cache - @dhcp.flush - true - else - false - end - end - - # Create a DHCP reservation - # [+host+] : Host object - # [+sp+] : Boolean which indicates whether we are dealing with the primary or service processor reservation - def setReservation(host, sp = nil) - scopeIpAddress = sp ? host.sp_subnet.number : host.subnet.number - ip = sp ? host.sp_ip : host.ip - mac = sp ? host.sp_mac : host.mac - name = sp ? host.sp_name : host.name - (@message = "#{ip} already exists") and return false if self[scopeIpAddress].has_key? ip - - (@message = "Cannot determine the host's hardware or vendor class!") and return false \ - if (host.operatingsystem.name =~ /Solaris/ and host.architecture == "sparc") and (host.model.hclass.nil? or host.model.vclass.nil?) - - # The puppetmaster value refers to the source of puppet manifests at runtime - # All boot servers are fully qualified in DHCP to work around some strange PXE card issues - if setRecordFor scopeIpAddress, ip, name, mac, host.media, host.model, host.architecture - # Reserialize the DHCP data back into the cache - @dhcp.flush - true - else - false - end - end - - # Access a hosts DHCP reservation and replace the mac value with a hash which also includes additional DHCP options - # This is alpha level code and is only implemented for MSDHCP servers - # [+ip+] : String containing the IP Address - def getDetails ip - raise RuntimeError.new("Running the virtual DHCPServer.getDetails method! Please provide vendor specific code") - end - - protected - # A DHCP entry may be just a mac or a hash of attributes - def MAC scopeIpAddress, ip - record = self[scopeIpAddress][ip] - mac = record.is_a?(Hash) ? record[:mac] : record - mac = mac.gsub(/:/,"") - end - - private - def loadScopes - raise RuntimeError.new("Running the virtual DHCPServer.loadScopes method! Please provide vendor specific code") - end - # Load a scope's reservation records - # [+scopeIpAddress+] : String containing the scope's IP address - # [+scope+] : Hash into which we load the scop's data - def loadScopeData scopeIpAddress, scope - raise RuntimeError.new("Running the virtual DHCPServer.loadScopes method! Please provide vendor specific code") - end - # Add a DHCP entry - # This method should be overriden in the subclass representing the type of DHCP server - # [+scopeIpAddress+] : String containing the Scope's IP address - # [+ip+] : String containing the IP for the record to be removed - # [+hostname+] : String containing the host's name - # [+mac+] : String containing the host's MAC address - # [+media+] : Media object - # [+model+] : String containing the host's model. Required for sparc machines as this is encoded in MS DHCP servers - # [+architecture+] : String containing the host's architecture - def setRecordFor(scopeIpAddress, ip, hostname, mac, media, model = nil, architecture = nil) - raise RuntimeError.new("Running the virtual DHCPServer::setRecordFor method. Please provide vendor specific code") - end - # Delete the DHCP entry - # This method should be overriden in the subclass representing the type of DHCP server - # [+scopeIpAddress+] : String contaiing the Scope's IP address - # [+ip+] : String containing the IP address - def delRecordFor(scopeIpAddress, ip) - raise RuntimeError.new("Running the virtual DHCPServer::delRecordFor method! Please provide vendor specific code") - end - end # class DHCPServer - -end # Module diff --git a/lib/iscdhcp.rb b/lib/iscdhcp.rb deleted file mode 100644 index 3d138b3..0000000 --- a/lib/iscdhcp.rb +++ /dev/null @@ -1,209 +0,0 @@ -# This class models a ISC DHCP server -# After initialiasation, entries can be accessed by -# dhcp = ISCServer.new("172.29.216.40", dhcp) -# ip = dhcp["172.29.216"]["000c291c34f2"] -class ISCDHCPServer < DHCP::DHCPServer - - # Delete the DHCP entry - # This method is vendor specific and updates the DHCP server via the adaptor - # [+scopeIpAddress+] : String containing the Scope's IP address - # [+ip+] : String containing the IP for the record to be removed - def delRecordFor(scopeIpAddress, ip) - record = self[scopeIpAddress][ip] - mac = record.is_a?(Hash) ? record[:mac] : record - #mac = mac.gsub(/:/,"") - - omcmd "connect" - omcmd "set hardware-address = #{mac}" - omcmd "open" - omcmd "remove" - omcmd "disconnect" - - Util.syslog "#{@dhcp.user} removed DHCP reservation for #{ip}/#{mac}" - self[scopeIpAddress].delete ip - true - end - protected - - # Add a DHCP entry - # This method is vendor specific and updates the dhcp entry via the adaptor - # [+scopeIpAddress+] : String containing the Scope's IP address - # [+ip+] : String containing the IP for the record to be removed - # [+name+] : String containing the host's name - # [+mac+] : String containing the host's MAC address - # [+media+] : Media object - # [+model+] : String containing the host's model Required for sparc machines as this is encoded in MS DHCP servers - # [+architecture+] : Architecture object - def setRecordFor(scopeIpAddress, ip, name, mac, media, model=nil, architecture = nil) - (@message = "#{mac} already exists in scope #{scopeIpAddress}!" and return false) if self[scopeIpAddress].has_value? mac - - omcmd "connect" - omcmd "set name = \"#{name}\"" - omcmd "set ip-address = #{ip}" - omcmd "set hardware-address = #{mac}" - omcmd "set hardware-type = 1" # This is ethernet - - self[scopeIpAddress][ip] = mac - - unless media.bootserver.nil? # We are done if this is a service processor reservation - hexserv = Resolv.getaddress(media.bootserver).split(".").map{|i| "%02x" % i }.join(":") - - - omcmd "set statements = \"filename = \\\"#{"kickstart/" + media.bootfile}\\\";\"" - - if architecture.name == "sparc" - #TODO: Add Sun vendor options - end - end - omcmd "create" - omcmd "disconnect" - Util.syslog "#{@dhcp.user} created DHCP reservation for #{name} @ #{ip}/#{mac}" - true - end - # Connect to the named DHCP server and populate our hash keys with the scope that the machine servers - # [+dhcpServerAdress+] : String containing the DHCP server's IP addresss - # [+dhcp+] : Dhcp object refering to parent - def initialize(dhcpServerAddress, dhcp, option) - # Connect to the named DHCP server and download its reservations - @dhcpd_conf = nil - @dhcpd_leased = nil - @netmask = {} - super(dhcpServerAddress, dhcp) - # For now we make the assumption that this code runs on the dhcpd server - end - - private - def omcmd cmd, *args - if cmd == "connect" - @om = IO.popen("/usr/bin/omshell", "r+") - server_addr = @dhcpServerAddress=~/^\d/ ? @dhcpServerAddress : Resolv.getaddress(@dhcpServerAddress) - @om.puts "server #{server_addr}" - @om.puts "connect" - @om.puts "new host" - elsif - cmd == "disconnect" - @om.close_write - status = @om.readlines - @om.close - @om = nil # we cannot serialize an IO obejct, even if closed. - status=~/can't/ - else - @om.puts cmd - end - end - def download_configuration - if @dhcpd_conf - system "scp -B -q #{@dhcpServerAddress}:#{@dhcpd_conf} /tmp" if not FileTest.file? "/tmp/dhcpd.conf" or File.mtime("/tmp/dhcpd.conf") > Time.now - 5.minutes - else - if system("scp -B -q #{@dhcpServerAddress}:/etc/dhcp3/dhcpd.conf /tmp") - @dhcpd_conf = "/etc/dhcp3/dhcpd.conf" - elsif system("scp -B -q #{@dhcpServerAddress}:/etc/dhcpd.conf /tmp") - @dhcpd_conf = "/etc/dhcpd.conf" - end - end - @message = "Unable to retrieve the DHCP configuration file from #{@dhcpServerAddress}" and return false unless FileTest.file? "/tmp/dhcpd.conf" - if @dhcpd_leases - system "scp -B -q #{@dhcpServerAddress}:#{@dhcpd_leases} /tmp" if not FileTest.file? "/tmp/dhclient.leases" or File.mtime("/tmp/dhclient.leases") > Time.now - 5.minutes - else - if system("scp -B -q #{@dhcpServerAddress}:/var/lib/dhcp3/dhcpd.leases /tmp") - @dhcpd_leases = "/var/lib/dhcp3/dhcpd.leases" - elsif system("scp -B -q #{@dhcpServerAddress}:/var/lib/dhcp/dhcpd.leases /tmp") - @dhcpd_leases = "/var/lib/dhcp/dhcpd.leases" - end - end - @@messsage = "Unable to retrieve the DHCP leases file from #{@dhcpServerAddress}" and return false unless FileTest.file? "/tmp/dhcpd.leases" - true - end - # Enumerates the server's scopes - # Returns a list of active scopes - def loadScopes - return false unless download_configuration - entries = open("/tmp/dhcpd.conf"){|f|f.readlines}.delete_if{|l| not l=~/^\s*subnet/}.map{|l| l.match(/^\s*subnet\s+([\d\.]+)\s+netmask\s+([\d\.]+)/)[1,2]} - scopes = [] - for subnet, netmask in entries - @netmask[subnet] = netmask - scopes << subnet - end - @message = "No scopes were found on #{@dnsServerAddress}" and return false if scopes.empty? - scopes - end - # Load a scopes' reservation records - # [+scopeIpAddress+] : String containing the scope's IP address - # [+scope+] : Hash to be populated by the load operation - def loadScopeData scopeIpAddress, scope - logger.debug "Loading scope: " + scopeIpAddress - return false unless download_configuration - # Populate the hash that represent the scope reservations - # Skip the first few lines returned by the server and gateway code - - # Clear the hash as we maybe reloading the cache - scope.clear - - # Extract the data - conf = open("/tmp/dhcpd.conf"){|f|f.readlines} + open("/tmp/dhcpd.leases"){|f|f.readlines} - # Skip comment lines - conf = conf.delete_if{|line| line=~/^\s*#/}.map{|l| l.chomp}.join("") - conf.scan(/host\s+(\S+\s*\{[^}]+\})/) do |h| - key, body = h[0].match(/^(\S+)\s*\{([^\}]+)/)[1,2] - ip = mac = nil - body.scan(/([^;]+);/) do |d| - if match = d[0].match(/hardware\s+ethernet\s(\S+)/) - mac = match[1] - elsif match = d[0].match(/deleted\s(\S+)/) - scope[key].delete if scope.has_key? key - elsif match = d[0].match(/fixed-address\s(\S+)/) - ip = match[1] - if ip=~/^\D/ - ip = Resolv.getaddress ip rescue nil - mac = nil if ip.nil? - end - end - if mac and ip and Subnet.contains? scopeIpAddress, ip - scope[ip] = mac - mac = ip = nil - end - end - end - true - end - - - # Access a hosts DHCP reservation and replace the mac value with a hash which also includes additional DHCP options - # This is alpha level code and is only implemented for MSDHCP servers - # [+ip+] : String containing the IP Address - def getDetails ip - return nil - scopeIpAddress = Subnet.find_subnet(ip).dhcp.address - #TODO: integrate with GetDetails method - logger.debug "Finding DHCP data for #{ip}" - response = invoke "query reservation", nil, "CommandName=/ShowReservedOptionValue&ScopeIPAddress=#{scopeIpAddress}&ReservedIP=#{ip}" - return if response[2] =~/not a reserved client/ # The machine had no reservation so do nothing - - scopeOptions = {} - optionId = nil - # Replace the key -> macaddress with key -> {:mac => value} - mac = self[scopeIpAddress][ip] - mac = mac[:mac] if mac.is_a?(Hash) - self[scopeIpAddress][ip] = {:mac => mac} - # Merge the scope options into each new reservation - self[scopeIpAddress][ip].update scopeOptions - - # Add any host specific options replacing any scope level options - response.each do |line| - line.chomp - break if line.match(/^Command completed/) - if optionIdMatch = line.match(/OptionId : (\d+)/) - optionId = optionIdMatch[1] - next - end - # TODO: generalise for element values containing spaces - if optionValue = line.match(/Option Element Value = (\S+)/) and optionValue = optionValue[1] - self[scopeIpAddress][ip][optionId] = optionValue - end - end - end - -end# class MSDHCPServer -if __FILE__ == $0 - # TODO Generated stub -end diff --git a/lib/netdb_manager/action_controller_ext.rb b/lib/netdb_manager/action_controller_ext.rb index cb5d5f5..fb4e24b 100644 --- a/lib/netdb_manager/action_controller_ext.rb +++ b/lib/netdb_manager/action_controller_ext.rb @@ -9,9 +9,12 @@ def self.included(base) #:nodoc: module InstanceMethods def process_with_netdb_support *args + require_dependency 'implementation/lib/dhcp' require_dependency 'netdb_manager/host_ext' require_dependency 'netdb_manager/user_ext' + require_dependency 'netdb_manager/subnet_ext' require_dependency 'netdb_manager/application_controller_ext' + require_dependency 'netdb_manager/hosts_controller_ext' process_without_netdb_support *args end end diff --git a/lib/netdb_manager/application_controller_ext.rb b/lib/netdb_manager/application_controller_ext.rb index 3ae645e..1dcaebd 100644 --- a/lib/netdb_manager/application_controller_ext.rb +++ b/lib/netdb_manager/application_controller_ext.rb @@ -5,30 +5,38 @@ module ApplicationControllerExtensions def self.included(base) #:nodoc: base.send :include, InstanceMethods base.class_eval do - before_filter :initialise_caches + # Setting the filter chain here will not work as it is too late. Set it in each controller individually. + #before_filter :load_netdb_caches end + true end - + module InstanceMethods - def initialise_caches - return true unless @user + def load_netdb_caches + raise RuntimeError "Unable to determine the user for this operation " unless @user return true if SETTINGS[:unattended] and SETTINGS[:unattended] == false - - @dhcp = Rails.cache.fetch(:dhcp, :expires_in => NET_TTL){ - DHCP::Dhcp.new(session) - }.dup # For some reason the object is frozen in this implementation of the cache! - raise RuntimeException, "Unable to create DHCP memcache storage" unless @dhcp - - @user_cache = Rails.cache.fetch("user_cache", :expires_in => NET_TTL){ - {} - }.dup # For some reason the object is frozen in this implementation of the cache! - raise RuntimeException, "Unable to create password cache storage" unless @pass + + # Fetch the list of server that are memcached + @dhcp_servers = Rails.cache.fetch("dhcp_servers", :expires_in => NET_TTL){[]}.dup + raise RuntimeException, "Unable to create DHCP memcache storage" unless @dhcp_servers + + # Fetch the memcached servers + @dhcp = {} + for server in @dhcp_servers + @dhcp[server] = Rails.cache.fetch(server, :expires_in => NET_TTL){{}}.dup + raise RuntimeError, "Unable to retrieve server data for #{server}" if @dhcp[server].size == 0 + end + + # Fetch the user data mecache. This holds per-user data dependant on the server implementation + @user_cache = Rails.cache.fetch("user_cache", :expires_in => NET_TTL){{}}.dup + raise RuntimeError, "Unable to create user cache storage" unless @user_cache # The DHCP instance needs access to the session as some of its DHCPServer implementations need to know about the user - per_user_data = @user_cache[login] - @dhcp.personalise(per_user_data) + #per_user_data = @user_cache[@user.login] + #@dhcp.personalise(per_user_data) true - end + end + def save_network_data return true if RAILS_ENV == "test" if @dhcp @@ -43,4 +51,4 @@ def save_network_data end end end -ApplicaitonController::Base.send :include, NetdbManager::ApplicationControllerExtensions +ApplicationController.send :include, NetdbManager::ApplicationControllerExtensions diff --git a/lib/netdb_manager/host_ext.rb b/lib/netdb_manager/host_ext.rb index 6f63a7c..e6de164 100644 --- a/lib/netdb_manager/host_ext.rb +++ b/lib/netdb_manager/host_ext.rb @@ -3,8 +3,8 @@ module HostExtensions def self.included(base) # This implementation requires memcache if [Rails.configuration.cache_store].flatten[0] == :mem_cache_store - require_dependency 'dhcp' - require_dependency 'iscdhcp' + require_dependency 'implementation/lib/dhcp' + #require_dependency 'iscdhcp' require_dependency 'ipaddr' include DHCP else @@ -18,16 +18,26 @@ def self.included(base) puts message exit end - + base.extend ClassMethods base.send :include, InstanceMethods base.class_eval do - after_save :transactional_update + before_validation :load_netdb_caches + after_validation :check_dns + after_save :transactional_update, :save_netdb_caches end true end - + module InstanceMethods + def check_dns + + end + + def save_netdb_caches + + end + def delDHCP dhcpServer status = log_status("Delete a DHCP reservation for #{name}/#{ip}", dhcpServer){ dhcpServer.delReservation self @@ -70,7 +80,6 @@ def transactional_update puts "performing transactional update" Rails.logger.debug "performing transactional update" begin - initialise_network_cache save_network_data true rescue diff --git a/lib/netdb_manager/hosts_controller_ext.rb b/lib/netdb_manager/hosts_controller_ext.rb new file mode 100644 index 0000000..776b947 --- /dev/null +++ b/lib/netdb_manager/hosts_controller_ext.rb @@ -0,0 +1,20 @@ +module NetdbManager + module HostsControllerExtensions + def self.included(base) #:nodoc: + base.send :include, InstanceMethods + base.class_eval do + before_filter :load_netdb_caches + end + + end + + module InstanceMethods + def subnet_selected + dhcp = Subnet.find(params[:subnet_id]).dhcp + + DHCP.cache_server @dhcp_servers, @dhcp, @user_cache, dhcp + end + end + end +end +HostsController.send :include, NetdbManager::HostsControllerExtensions diff --git a/lib/netdb_manager/subnet_ext.rb b/lib/netdb_manager/subnet_ext.rb new file mode 100644 index 0000000..28a6af6 --- /dev/null +++ b/lib/netdb_manager/subnet_ext.rb @@ -0,0 +1,30 @@ +module NetdbManager + module SubnetExtensions + def self.included(base) #:nodoc: + base.extend ClassMethods + base.send :include, InstanceMethods + base.class_eval do + belongs_to :dhcp, :class_name => 'Netdb' + validate_on_create :must_be_unique_per_site + + end + end + + module InstanceMethods + # Before we save a subnet ensure that we cannot find a subnet at our site with an identical name + def must_be_unique_per_site + if self.domain and self.domain.subnets + unless self.domain.subnets.find_by_name(self.name).nil? + errors.add_to_base "The name #{self.name} is already in use at #{self.domain.fullname}" + end + end + end + + end + + module ClassMethods + + end + end +end +Subnet.send :include, NetdbManager::SubnetExtensions