diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index a1192bf20..a021c773a 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -1,132 +1,136 @@ # Load the appropriate libraries, or set a class indicating they aren't available require 'facter' require 'puppet' module Puppet::Rails def self.connect # This global init does not work for testing, because we remove # the state dir on every test. return if ActiveRecord::Base.connected? Puppet.settings.use(:main, :rails, :puppetmasterd) ActiveRecord::Base.logger = Logger.new(Puppet[:railslog]) begin loglevel = Logger.const_get(Puppet[:rails_loglevel].upcase) ActiveRecord::Base.logger.level = loglevel rescue => detail Puppet.warning "'%s' is not a valid Rails log level; using debug" % Puppet[:rails_loglevel] ActiveRecord::Base.logger.level = Logger::DEBUG end ActiveRecord::Base.allow_concurrency = true ActiveRecord::Base.verify_active_connections! begin ActiveRecord::Base.establish_connection(database_arguments()) rescue => detail if Puppet[:trace] puts detail.backtrace end raise Puppet::Error, "Could not connect to database: %s" % detail end end # The arguments for initializing the database connection. def self.database_arguments adapter = Puppet[:dbadapter] args = {:adapter => adapter, :log_level => Puppet[:rails_loglevel]} case adapter when "sqlite3": args[:dbfile] = Puppet[:dblocation] when "mysql", "postgresql": args[:host] = Puppet[:dbserver] unless Puppet[:dbserver].empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].empty? args[:database] = Puppet[:dbname] socket = Puppet[:dbsocket] args[:socket] = socket unless socket.empty? else raise ArgumentError, "Invalid db adapter %s" % adapter end args end # Set up our database connection. It'd be nice to have a "use" system # that could make callbacks. def self.init unless Puppet.features.rails? raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" end connect() unless ActiveRecord::Base.connection.tables.include?("resources") require 'puppet/rails/database/schema' Puppet::Rails::Schema.init end if Puppet[:dbmigrate] migrate() end end # Migrate to the latest db schema. def self.migrate dbdir = nil $:.each { |d| tmp = File.join(d, "puppet/rails/database") if FileTest.directory?(tmp) dbdir = tmp break end } unless dbdir raise Puppet::Error, "Could not find Puppet::Rails database dir" end + unless ActiveRecord::Base.connection.tables.include?("resources") + raise Puppet::Error, "Database has problems, can't migrate." + end + Puppet.notice "Migrating" begin ActiveRecord::Migrator.migrate(dbdir) rescue => detail if Puppet[:trace] puts detail.backtrace end raise Puppet::Error, "Could not migrate database: %s" % detail end end # Tear down the database. Mostly only used during testing. def self.teardown unless Puppet.features.rails? raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" end Puppet.settings.use(:puppetmasterd, :rails) begin ActiveRecord::Base.establish_connection(database_arguments()) rescue => detail if Puppet[:trace] puts detail.backtrace end raise Puppet::Error, "Could not connect to database: %s" % detail end ActiveRecord::Base.connection.tables.each do |t| ActiveRecord::Base.connection.drop_table t end end end if Puppet.features.rails? require 'puppet/rails/host' end diff --git a/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb new file mode 100644 index 000000000..71ee6aeed --- /dev/null +++ b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb @@ -0,0 +1,17 @@ +class AddCreatedAtToAllTables < ActiveRecord::Migration + def self.up + ActiveRecord::Base.connection.tables.each do |t| + unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at") + add_column t.to_s, :created_at, :datetime + end + end + end + + def self.down + ActiveRecord::Base.connection.tables.each do |t| + unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at") + remove_column t.to_s, :created_at + end + end + end +end diff --git a/lib/puppet/rails/external/tagging/README b/lib/puppet/rails/external/tagging/README deleted file mode 100644 index 8d2f90822..000000000 --- a/lib/puppet/rails/external/tagging/README +++ /dev/null @@ -1,4 +0,0 @@ -Acts As Taggable -================= - -Allows for tags to be added to multiple classes. \ No newline at end of file diff --git a/lib/puppet/rails/external/tagging/acts_as_taggable.rb b/lib/puppet/rails/external/tagging/acts_as_taggable.rb deleted file mode 100644 index 7fd7f6b12..000000000 --- a/lib/puppet/rails/external/tagging/acts_as_taggable.rb +++ /dev/null @@ -1,62 +0,0 @@ -module ActiveRecord - module Acts #:nodoc: - module Taggable #:nodoc: - def self.included(base) - base.extend(ClassMethods) - end - - module ClassMethods - def acts_as_taggable(options = {}) - write_inheritable_attribute(:acts_as_taggable_options, { - :taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s, - :from => options[:from] - }) - - class_inheritable_reader :acts_as_taggable_options - - has_many :taggings, :as => :taggable, :dependent => :destroy - has_many :tags, :through => :taggings - - include ActiveRecord::Acts::Taggable::InstanceMethods - extend ActiveRecord::Acts::Taggable::SingletonMethods - end - end - - module SingletonMethods - def find_tagged_with(list) - find_by_sql([ - "SELECT #{table_name}.* FROM #{table_name}, tags, taggings " + - "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " + - "AND taggings.taggable_type = ? " + - "AND taggings.tag_id = tags.id AND tags.name IN (?)", - acts_as_taggable_options[:taggable_type], list - ]) - end - def tags(options = {}) - options.merge!(:taggable_type => self.to_s) - Tag.tags(options) - end - end - - module InstanceMethods - def tag_with(list) - Tag.transaction do - taggings.destroy_all - - Tag.parse(list).each do |name| - if acts_as_taggable_options[:from] - send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self) - else - Tag.find_or_create_by_name(name).on(self) - end - end - end - end - - def tag_list - tags.collect { |tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name }.join(" ") - end - end - end - end -end diff --git a/lib/puppet/rails/external/tagging/init.rb b/lib/puppet/rails/external/tagging/init.rb deleted file mode 100644 index 5069d8040..000000000 --- a/lib/puppet/rails/external/tagging/init.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'puppet/rails/external/tagging/acts_as_taggable' -ActiveRecord::Base.send(:include, ActiveRecord::Acts::Taggable) - -require 'puppet/rails/external/tagging/tagging' -require 'puppet/rails/external/tagging/tag' diff --git a/lib/puppet/rails/external/tagging/tag.rb b/lib/puppet/rails/external/tagging/tag.rb deleted file mode 100644 index c6bf4ca78..000000000 --- a/lib/puppet/rails/external/tagging/tag.rb +++ /dev/null @@ -1,50 +0,0 @@ -class Tag < ActiveRecord::Base - has_many :taggings - - def self.tags(options = {}) - query = "select tags.id, name, count(*) as count" - query << " from taggings, tags" - query << " where tags.id = tag_id" - query << " group by tag_id" - query << " order by #{options[:order]}" if options[:order] != nil - query << " limit #{options[:limit]}" if options[:limit] != nil - tags = Tag.find_by_sql(query) - end - - def self.parse(list) - tag_names = [] - - # first, pull out the quoted tags - list.gsub!(/\"(.*?)\"\s*/ ) { tag_names << $1; "" } - - # then, replace all commas with a space - list.gsub!(/,/, " ") - - # then, get whatever's left - tag_names.concat list.split(/\s/) - - # strip whitespace from the names - tag_names = tag_names.map { |t| t.strip } - - # delete any blank tag names - tag_names = tag_names.delete_if { |t| t.empty? } - - return tag_names - end - - def tagged - @tagged ||= taggings.collect { |tagging| tagging.taggable } - end - - def on(taggable) - taggings.build :taggable => taggable - end - - def ==(comparison_object) - super || name == comparison_object.to_s - end - - def to_s - name - end -end diff --git a/lib/puppet/rails/external/tagging/tagging.rb b/lib/puppet/rails/external/tagging/tagging.rb deleted file mode 100644 index e06e88a14..000000000 --- a/lib/puppet/rails/external/tagging/tagging.rb +++ /dev/null @@ -1,12 +0,0 @@ -class Tagging < ActiveRecord::Base - belongs_to :tag - belongs_to :taggable, :polymorphic => true - - def self.tagged_class(taggable) - ActiveRecord::Base.send(:class_name_of_active_record_descendant, taggable.class).to_s - end - - def self.find_taggable(tagged_class, tagged_id) - tagged_class.constantize.find(tagged_id) - end -end \ No newline at end of file diff --git a/lib/puppet/rails/fact_value.rb b/lib/puppet/rails/fact_value.rb index 0eb70be72..b53591d7e 100644 --- a/lib/puppet/rails/fact_value.rb +++ b/lib/puppet/rails/fact_value.rb @@ -1,6 +1,10 @@ class Puppet::Rails::FactValue < ActiveRecord::Base belongs_to :fact_name belongs_to :host + + def to_label + "#{self.fact_name.name}" + end end # $Id: fact_value.rb 1952 2006-12-19 05:47:57Z luke $ diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb index 72898fd97..626edaa88 100644 --- a/lib/puppet/rails/host.rb +++ b/lib/puppet/rails/host.rb @@ -1,152 +1,151 @@ require 'puppet/rails/resource' require 'puppet/rails/fact_name' require 'puppet/rails/source_file' require 'puppet/util/rails/collection_merger' # Puppet::TIME_DEBUG = true class Puppet::Rails::Host < ActiveRecord::Base include Puppet::Util include Puppet::Util::CollectionMerger has_many :fact_values, :dependent => :destroy has_many :fact_names, :through => :fact_values - belongs_to :puppet_classes - has_many :source_files + belongs_to :source_file has_many :resources, :include => :param_values, :dependent => :destroy # If the host already exists, get rid of its objects def self.clean(host) if obj = self.find_by_name(host) obj.rails_objects.clear return obj else return nil end end # Store our host in the database. def self.store(node, resources) args = {} host = nil transaction do #unless host = find_by_name(name) seconds = Benchmark.realtime { unless host = find_by_name(node.name) host = new(:name => node.name) end } Puppet.notice("Searched for host in %0.2f seconds" % seconds) if defined?(Puppet::TIME_DEBUG) if ip = node.parameters["ipaddress"] host.ip = ip end # Store the facts into the database. host.setfacts node.parameters seconds = Benchmark.realtime { host.setresources(resources) } Puppet.notice("Handled resources in %0.2f seconds" % seconds) if defined?(Puppet::TIME_DEBUG) host.last_compile = Time.now host.save end return host end # Return the value of a fact. def fact(name) if fv = self.fact_values.find(:all, :include => :fact_name, :conditions => "fact_names.name = '#{name}'") return fv else return nil end end # returns a hash of fact_names.name => [ fact_values ] for this host. def get_facts_hash fact_values = self.fact_values.find(:all, :include => :fact_name) return fact_values.inject({}) do | hash, value | hash[value.fact_name.name] ||= [] hash[value.fact_name.name] << value hash end end def setfacts(facts) facts = facts.dup ar_hash_merge(get_facts_hash(), facts, :create => Proc.new { |name, values| fact_name = Puppet::Rails::FactName.find_or_create_by_name(name) values = [values] unless values.is_a?(Array) values.each do |value| fact_values.build(:value => value, :fact_name => fact_name) end }, :delete => Proc.new { |values| values.each { |value| self.fact_values.delete(value) } }, :modify => Proc.new { |db, mem| mem = [mem].flatten fact_name = db[0].fact_name db_values = db.collect { |fact_value| fact_value.value } (db_values - (db_values & mem)).each do |value| db.find_all { |fact_value| fact_value.value == value }.each { |fact_value| fact_values.delete(fact_value) } end (mem - (db_values & mem)).each do |value| fact_values.build(:value => value, :fact_name => fact_name) end }) end # Set our resources. def setresources(list) existing = nil seconds = Benchmark.realtime { # Preload the parameters with the resource query, but not the tags, since doing so makes the query take about 10x longer. # I've left the other queries in so that it's straightforward to switch between them for testing, if we so desire. #existing = resources.find(:all, :include => [{:param_values => :param_name, :resource_tags => :puppet_tag}, :source_file]).inject({}) do | hash, resource | #existing = resources.find(:all, :include => [{:resource_tags => :puppet_tag}, :source_file]).inject({}) do | hash, resource | existing = resources.find(:all, :include => [{:param_values => :param_name}, :source_file]).inject({}) do | hash, resource | hash[resource.ref] = resource hash end } Puppet.notice("Searched for resources in %0.2f seconds" % seconds) if defined?(Puppet::TIME_DEBUG) compiled = list.inject({}) do |hash, resource| hash[resource.ref] = resource hash end ar_hash_merge(existing, compiled, :create => Proc.new { |ref, resource| resource.to_rails(self) }, :delete => Proc.new { |resource| self.resources.delete(resource) }, :modify => Proc.new { |db, mem| mem.modify_rails(db) }) end def update_connect_time self.last_connect = Time.now save end end diff --git a/lib/puppet/rails/param_value.rb b/lib/puppet/rails/param_value.rb index 02c29c540..fc00a43d4 100644 --- a/lib/puppet/rails/param_value.rb +++ b/lib/puppet/rails/param_value.rb @@ -1,24 +1,28 @@ class Puppet::Rails::ParamValue < ActiveRecord::Base belongs_to :param_name belongs_to :resource def value val = self[:value] if val =~ /^--- \!/ YAML.load(val) else val end end # I could not find a cleaner way to handle making sure that resource references # were consistently serialized and deserialized. def value=(val) if val.is_a?(Puppet::Parser::Resource::Reference) self[:value] = YAML.dump(val) else self[:value] = val end end + + def to_label + "#{self.param_name.name}" + end end diff --git a/lib/puppet/rails/puppet_class.rb b/lib/puppet/rails/puppet_class.rb deleted file mode 100644 index 35cef8974..000000000 --- a/lib/puppet/rails/puppet_class.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Puppet::Rails::PuppetClass < ActiveRecord::Base - has_many :resources - has_many :source_files - has_many :hosts -end - diff --git a/lib/puppet/rails/resource_tag.rb b/lib/puppet/rails/resource_tag.rb index d06711877..f9694e082 100644 --- a/lib/puppet/rails/resource_tag.rb +++ b/lib/puppet/rails/resource_tag.rb @@ -1,4 +1,8 @@ class Puppet::Rails::ResourceTag < ActiveRecord::Base belongs_to :puppet_tag belongs_to :resource + + def to_label + "#{self.puppet_tag.name}" + end end diff --git a/lib/puppet/rails/source_file.rb b/lib/puppet/rails/source_file.rb index 51d1b1fb5..3ccf87ac6 100644 --- a/lib/puppet/rails/source_file.rb +++ b/lib/puppet/rails/source_file.rb @@ -1,5 +1,8 @@ class Puppet::Rails::SourceFile < ActiveRecord::Base has_one :host - has_one :puppet_class has_one :resource + + def to_label + "#{self.filename}" + end end