diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ee686da..c6035e1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,4 +1,87 @@ +# Methods added to this helper will be available to all templates in the application. module ApplicationHelper + + def graph(type,opts = {}) + Gchart.send(type, {:size => '400x150', :bg => "E6DFCF", :format => "image_tag"}.merge(opts)) + end + + def show_habtm associations + render :partial => 'common/show_habtm', :collection => associations, :as => :association + end + + def edit_habtm klass, association + render :partial => 'common/edit_habtm', :locals =>{ :klass => klass, :associations => association.all.delete_if{|e| e == klass}} + end + + def link_to_remove_fields(name, f) + f.hidden_field(:_destroy) + link_to_function(image_tag("false.png", :title => "remove"), "remove_fields(this)") + end + + def link_to_add_fields(name, f, association, partial = nil) + new_object = f.object.class.reflect_on_association(association).klass.new + fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder| + render((partial.nil? ? association.to_s.singularize + "_fields" : partial), :f => builder) + end + link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")) + end + + def toggle_div div + update_page do |page| + page << "if ($('#{div}').visible()) {" + page[div].visual_effect :BlindUp + page << "} else {" + page[div].visual_effect :BlindDown + page << "}" + end + end + + def link_to_remove_puppetclass klass + link_to_function image_tag("delete.png") + " " + klass.name do |page| + page["selected_puppetclass_#{klass.id}"].remove + #TODO if the class is already selected, removing it will not add it to the avail class list + page << "if ($('puppetclass_#{klass.id}')) {" + page["puppetclass_#{klass.id}"].show + page << "}" + end + end + + def link_to_add_puppetclass klass, type + # link to remote is faster than inline js when having many classes + link_to_remote "   " + image_tag("add.png") + " " + klass.klass, + :url => assign_puppetclass_path(klass, :type => type), + :position => {:after => {:success => "selected_classes" }} + end + + def searchtab title, search, options + opts = {:action => params[:action], :tab_name => title, :search => search} + selected_class = options[:selected] ? "selectedtab" : "" + content_tag(:li) do + link_to opts, :class => selected_class do + title + (options[:no_close_button] ? "": (link_to "x", opts.merge(:remove_me => true), :class => "#{selected_class} close")) + end + end + end + + def toggle_searchbar + update_page do |page| + page['search'].toggle + page['tabs'].toggle + end + end + + # a simple helper to load the google JS only on pages which requires it + def gcharts_script + content_for :head do + "" + end + end + + def fact_name_select + param = params[:search]["#{@via}fact_name_id_eq"] if params[:search] + return param.to_i unless param.empty? + return @fact_name_id if @fact_name_id + end + def settings_dropdown choices = [ ['Additional Settings', ""], diff --git a/init.rb b/init.rb index 565d4f3..e4d3f7b 100644 --- a/init.rb +++ b/init.rb @@ -1 +1,3 @@ +#require_dependency File.join(File.dirname(__FILE__), "..", "..", "..", "config", "initializers", "foreman") require 'netdb_manager' +ActiveSupport::Dependencies.load_once_paths.delete lib_path \ No newline at end of file diff --git a/lib/netdb_manager.rb b/lib/netdb_manager.rb index 8b02472..747ef94 100644 --- a/lib/netdb_manager.rb +++ b/lib/netdb_manager.rb @@ -1,13 +1,10 @@ -ActiveSupport::Dependencies.load_once_paths.delete File.dirname(__FILE__) # Patch the host with a transactional update facility that we use to hook our update code -require 'netdb_manager/host_ext' +require 'netdb_manager/active_record_ext' -# Rails Engines works against us in some ways as it ensures that the last loaded module overrides the first. -# As the application's version of application_helper.rb is loaded last it overrides our overrides. -# Never mind, just load our overrides again, as the last loaded module. Maybe I should drop engines. . . . -require_or_load File.join(File.dirname(__FILE__), '..',"app", "helpers", "application_helper.rb") +ActionController::Base.prepend_view_path(File.join(File.dirname(__FILE__), '..', 'app', 'views')) -#HostsController.prepend_view_path(File.join(File.dirname(__FILE__), '..', 'app', 'views')) +# Our code overrides the application code +Engines.disable_application_code_loading = true # If we define a view then this is the one we should use. Engines.disable_application_view_loading = true diff --git a/lib/netdb_manager/active_record_ext.rb b/lib/netdb_manager/active_record_ext.rb new file mode 100644 index 0000000..8889d83 --- /dev/null +++ b/lib/netdb_manager/active_record_ext.rb @@ -0,0 +1,20 @@ +module NetdbManager + module ActiveRecordExtensions + def self.included(base) #:nodoc: + base.send :include, InstanceMethods + base.class_eval { alias_method_chain :before_save, :netdb_support } + end + + module InstanceMethods + def before_save_with_netdb_support + if self.class.to_s == "Host" + require_dependency 'netdb_manager/host_ext' + elsif self.class.to_s == "User" + require_dependency 'netdb_manager/user_ext' + end + before_save_without_netdb_support + end + end + end +end +ActiveRecord::Callbacks.send :include, NetdbManager::ActiveRecordExtensions diff --git a/lib/netdb_manager/host_ext.rb b/lib/netdb_manager/host_ext.rb index be53da0..8ea494c 100644 --- a/lib/netdb_manager/host_ext.rb +++ b/lib/netdb_manager/host_ext.rb @@ -1,112 +1,118 @@ module NetdbManager - def self.included(base) - # This implementation requires memcache - if [Rails.configuration.cache_store].flatten[0] == :mem_cache_store - require 'dhcp' - require 'iscdhcp' - require 'ipaddr' - include DHCP - else - message = "*********************************************************************\n" + - "DHCP and DNS management require that you install the memcache service\n" + - "and that you add this line to environment.db \n" + - "config.cache_store = :mem_cache_store \n" + - "and edit config.initializers/session_store to set = :mem_cache_store \n" + - "*********************************************************************\n" - RAILS_DEFAULT_LOGGER.warn message - puts message - exit - end - - base.extend ClassMethods - base.send :include, InstanceMethods - end - - module InstanceMethods - def save_network_data - return true if RAILS_ENV == "test" - if @dhcp - dhcpServer = @dhcp.serverFor subnet.number - if new_record? - setDHCP dhcpServer - end + 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 'ipaddr' + include DHCP else - true # No netdb management unless we use memcache + message = "*********************************************************************\n" + + "DHCP and DNS management require that you install the memcache service\n" + + "and that you add this line to environment.db \n" + + "config.cache_store = :mem_cache_store \n" + + "and edit config.initializers/session_store to set = :mem_cache_store \n" + + "*********************************************************************\n" + RAILS_DEFAULT_LOGGER.warn message + puts message + exit end + + base.extend ClassMethods + base.send :include, InstanceMethods + base.send :after_save, :transactional_update + true end - def delDHCP dhcpServer - status = log_status("Delete a DHCP reservation for #{name}/#{ip}", dhcpServer){ - dhcpServer.delReservation self - } - return status unless sp_valid? - log_status("Delete a DHCP reservation for #{sp_name}/#{sp_ip}", dhcpServer){ - dhcpServer.delReservation self, true - } - end - # Updates the DHCP scope to add a reservation for this host - # [+dhcpServer+] : A DHCPServer object - # +returns+ : Boolean true on success - def setDHCP dhcpServer - status = log_status("Add a DHCP reservation for #{name}/#{ip}", dhcpServer){ - dhcpServer.setReservation self - } - return status unless sp_valid? - log_status("Add a DHCP reservation for #{sp_name}/#{sp_ip}", dhcpServer){ - dhcpServer.setReservation self, true - } - end - - def log_status message, server, &block - if server - logger.info "#{message}" - unless result = yield(block) - first, rest = message.match(/(\w*)(.*)/)[1,2] - message = "Failed to " + first.downcase + rest + ": #{server.message}" - errors.add_to_base server.message - logger.error message + + module InstanceMethods + #after_save :transactional_update + def save_network_data + return true if RAILS_ENV == "test" + if @dhcp + dhcpServer = @dhcp.serverFor subnet.number + if new_record? + setDHCP dhcpServer + end + else + true # No netdb management unless we use memcache end - result - else - errors.add_to_base("Access denied") - false end - end - - def transactional_update - begin - initialise_network_cache - save_network_data + def delDHCP dhcpServer + status = log_status("Delete a DHCP reservation for #{name}/#{ip}", dhcpServer){ + dhcpServer.delReservation self + } + return status unless sp_valid? + log_status("Delete a DHCP reservation for #{sp_name}/#{sp_ip}", dhcpServer){ + dhcpServer.delReservation self, true + } + end + # Updates the DHCP scope to add a reservation for this host + # [+dhcpServer+] : A DHCPServer object + # +returns+ : Boolean true on success + def setDHCP dhcpServer + status = log_status("Add a DHCP reservation for #{name}/#{ip}", dhcpServer){ + dhcpServer.setReservation self + } + return status unless sp_valid? + log_status("Add a DHCP reservation for #{sp_name}/#{sp_ip}", dhcpServer){ + dhcpServer.setReservation self, true + } + end + + def log_status message, server, &block + if server + logger.info "#{message}" + unless result = yield(block) + first, rest = message.match(/(\w*)(.*)/)[1,2] + message = "Failed to " + first.downcase + rest + ": #{server.message}" + errors.add_to_base server.message + logger.error message + end + result + else + errors.add_to_base("Access denied") + false + end + end + + def initialise_network_cache + return true 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 + + # The DHCP instance needs access to the session as some of its DHCPServer implementations need to know about the user + per_user_dhcp_data = session[:dhcp_data] ||= {:user => @user.login} + @dhcp.personalise(per_user_dhcp_data) true - rescue => e - errors.add_to_base "Failed to update the network databases" - raise ActiveRecord::Rollback + e.message - false + end + + def transactional_update + puts "performing transactional update" + Rails.logger.debug "performing transactional update" + begin + initialise_network_cache + save_network_data + true + rescue + errors.add_to_base "Failed to update the network databases" + raise + false + end end end - end - - module ClassMethods - def initialise_network_cache - return true 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 - - # The DHCP instance needs access to the session as some of its DHCPServer implementations need to know about the user - per_user_dhcp_data = session[:dhcp_data] ||= {:user => @user.login} - @dhcp.personalise(per_user_dhcp_data) - true - end - - def reload_network_data - Rails.cache.clear - head :created + + module ClassMethods + def reload_network_data + Rails.cache.clear + head :created + end end end end -# And yes we need to put this in ActiveRecord and NOT Host -ActiveRecord::Base.send :include, NetdbManager +Host.send :include, NetdbManager::HostExtensions diff --git a/lib/netdb_manager/routing.rb b/lib/netdb_manager/routing.rb deleted file mode 100644 index b9ca1c3..0000000 --- a/lib/netdb_manager/routing.rb +++ /dev/null @@ -1,12 +0,0 @@ -module NetdbManager - #:nodoc: - module Routing - #:nodoc: - module MapperExtensions - def NetdbManagers - @set.add_route("/subnets", {:controller => "subnets", :action => "index"}) - end - end - end -end -ActionController::Routing::RouteSet::Mapper.send :include, NetdbManager::Routing::MapperExtensions diff --git a/lib/netdb_manager/user_ext.rb b/lib/netdb_manager/user_ext.rb new file mode 100644 index 0000000..1cfe0cf --- /dev/null +++ b/lib/netdb_manager/user_ext.rb @@ -0,0 +1,39 @@ +module NetdbManager + module UserExtensions + def self.included(base) #:nodoc: + base.class_eval { alias_method_chain :try_to_login, :networking_support } + base.extend ClassMethods + base.send :include, InstanceMethods + end + + module InstanceMethods + end + + module ClassMethods + + def try_to_login_with_networking_support(login, password) + if user = try_to_login_without_network_support + User.initialise_network_support + end + user + end + + def initialise_network_cache + return true 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 + + # The DHCP instance needs access to the session as some of its DHCPServer implementations need to know about the user + per_user_dhcp_data = session[:dhcp_data] ||= {:user => @user.login} + @dhcp.personalise(per_user_dhcp_data) + true + end + end + end +end +# And yes we need to put this in ActiveRecord and NOT User +User.send :include, NetdbManager::UserExtensions