diff options
| author | Luke Kanies <luke@madstop.com> | 2007-09-22 15:04:34 -0500 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2007-09-22 15:04:34 -0500 |
| commit | d6e91ae78698bdbec818d383574f4c279735e172 (patch) | |
| tree | 7072c2a71ef1c05c6a46b6050f52bf3d01ae2843 | |
| parent | a66699596452f88d2bc467af4cff3f9a1aec3d1e (diff) | |
| parent | 86dde63473d29c45d8698ce4edd53c820a621362 (diff) | |
| download | puppet-d6e91ae78698bdbec818d383574f4c279735e172.tar.gz puppet-d6e91ae78698bdbec818d383574f4c279735e172.tar.xz puppet-d6e91ae78698bdbec818d383574f4c279735e172.zip | |
Merge branch 'configurations' into indirection
Conflicts:
lib/puppet/defaults.rb
lib/puppet/indirector/facts/yaml.rb
spec/unit/indirector/indirection.rb
spec/unit/indirector/indirector.rb
63 files changed, 1393 insertions, 1614 deletions
diff --git a/bin/puppet b/bin/puppet index 36f0fcd62..9520492a2 100755 --- a/bin/puppet +++ b/bin/puppet @@ -194,8 +194,8 @@ begin if Puppet[:parseonly] exit(0) end - client.getconfig - client.apply + config = client.getconfig + config.apply rescue => detail if detail.is_a?(XMLRPC::FaultException) $stderr.puts detail.message diff --git a/ext/module_puppet b/ext/module_puppet index cb03b6ef2..194f3fa09 100755 --- a/ext/module_puppet +++ b/ext/module_puppet @@ -191,8 +191,8 @@ if parseonly end begin - client.getconfig - client.apply + config = client.getconfig + config.apply rescue => detail Puppet.err detail exit(1) diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index fa06c7fdb..64f370bec 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -494,8 +494,10 @@ module Puppet "The server through which to send email reports."] ) - self.setdefaults(:facts, - :fact_store => ["yaml", + # This needs to be in main because it's used too early in the system, such that + # we get an infinite loop otherwise. + self.setdefaults(:main, + :facts_terminus => ["yaml", "The backend store to use for client facts."] ) diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb index 795358e83..3696cd9ee 100644 --- a/lib/puppet/dsl.rb +++ b/lib/puppet/dsl.rb @@ -67,11 +67,8 @@ module Puppet def apply bucket = export() - objects = bucket.to_type - master = Puppet::Network::Client.master.new :Master => "whatever" - master.objects = objects - - master.apply + configuration = bucket.to_configuration + configuration.apply end def export diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb index 12b8cf328..aacad6c45 100644 --- a/lib/puppet/indirector/indirection.rb +++ b/lib/puppet/indirector/indirection.rb @@ -83,7 +83,7 @@ class Puppet::Indirector::Indirection # Create a new terminus instance. def make_terminus(name) # Load our terminus class. - unless klass = Puppet::Indirector::Terminus.terminus_class(self.name, name) + unless klass = Puppet::Indirector::Terminus.terminus_class(name, self.name) raise ArgumentError, "Could not find terminus %s for indirection %s" % [name, self.name] end return klass.new diff --git a/lib/puppet/metatype/closure.rb b/lib/puppet/metatype/closure.rb index efb4712c6..727bc6884 100644 --- a/lib/puppet/metatype/closure.rb +++ b/lib/puppet/metatype/closure.rb @@ -1,19 +1,6 @@ class Puppet::Type attr_writer :implicit - def self.implicitcreate(hash) - unless hash.include?(:implicit) - hash[:implicit] = true - end - if obj = self.create(hash) - obj.implicit = true - - return obj - else - return nil - end - end - # Is this type's name isomorphic with the object? That is, if the # name conflicts, does it necessarily mean that the objects conflict? # Defaults to true. diff --git a/lib/puppet/metatype/container.rb b/lib/puppet/metatype/container.rb index 7c44a7def..7bbccf8a0 100644 --- a/lib/puppet/metatype/container.rb +++ b/lib/puppet/metatype/container.rb @@ -14,14 +14,6 @@ class Puppet::Type self.class.depthfirst? end - def parent=(parent) - if self.parentof?(parent) - devfail "%s[%s] is already the parent of %s[%s]" % - [self.class.name, self.title, parent.class.name, parent.title] - end - @parent = parent - end - # Add a hook for testing for recursion. def parentof?(child) if (self == child) diff --git a/lib/puppet/metatype/instances.rb b/lib/puppet/metatype/instances.rb index f6c2fdd34..4af230b28 100644 --- a/lib/puppet/metatype/instances.rb +++ b/lib/puppet/metatype/instances.rb @@ -79,8 +79,7 @@ class Puppet::Type end # Force users to call this, so that we can merge objects if - # necessary. FIXME This method should be responsible for most of the - # error handling. + # necessary. def self.create(args) # Don't modify the original hash; instead, create a duplicate and modify it. # We have to dup and use the ! so that it stays a TransObject if it is @@ -138,9 +137,8 @@ class Puppet::Type # now pass through and create the new object elsif implicit - Puppet.notice "Ignoring implicit %s" % title - - return retobj + Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title] + return nil else # If only one of the objects is being managed, then merge them if retobj.managed? @@ -308,8 +306,8 @@ class Puppet::Type # Create the path for logging and such. def pathbuilder - if defined? @parent and @parent - [@parent.pathbuilder, self.ref].flatten + if p = parent + [p.pathbuilder, self.ref].flatten else [self.ref] end diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb index c6d7cd75d..cc66d9076 100644 --- a/lib/puppet/network/client/master.rb +++ b/lib/puppet/network/client/master.rb @@ -7,7 +7,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client @@sync = Sync.new end - attr_accessor :objects + attr_accessor :configuration attr_reader :compile_time class << self @@ -49,50 +49,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client Puppet.config[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase } end - # This method actually applies the configuration. - def apply(tags = nil, ignoreschedules = false) - unless defined? @objects - raise Puppet::Error, "Cannot apply; objects not defined" - end - - transaction = @objects.evaluate - - if tags - transaction.tags = tags - end - - if ignoreschedules - transaction.ignoreschedules = true - end - - transaction.addtimes :config_retrieval => @configtime - - begin - transaction.evaluate - rescue Puppet::Error => detail - Puppet.err "Could not apply complete configuration: %s" % - detail - rescue => detail - Puppet.err "Got an uncaught exception of type %s: %s" % - [detail.class, detail] - if Puppet[:trace] - puts detail.backtrace - end - ensure - Puppet::Util::Storage.store - end - - if Puppet[:report] or Puppet[:summarize] - report(transaction) - end - - return transaction - ensure - if defined? transaction and transaction - transaction.cleanup - end - end - # Cache the config def cache(text) Puppet.info "Caching configuration at %s" % self.cachefile @@ -111,10 +67,10 @@ class Puppet::Network::Client::Master < Puppet::Network::Client end def clear - @objects.remove(true) if @objects + @configuration.clear(true) if @configuration Puppet::Type.allclear mkdefault_objects - @objects = nil + @configuration = nil end # Initialize and load storage @@ -183,15 +139,15 @@ class Puppet::Network::Client::Master < Puppet::Network::Client facts = self.class.facts end - if self.objects or FileTest.exists?(self.cachefile) + if self.configuration or FileTest.exists?(self.cachefile) if self.fresh?(facts) Puppet.info "Config is up to date" - if self.objects + if self.configuration return end if oldtext = self.retrievecache begin - @objects = YAML.load(oldtext).to_type + @configuration = YAML.load(oldtext).to_configuration rescue => detail Puppet.warning "Could not load cached configuration: %s" % detail end @@ -213,7 +169,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client end unless objects = get_actual_config(facts) - @objects = nil + @configuration = nil return end @@ -225,21 +181,21 @@ class Puppet::Network::Client::Master < Puppet::Network::Client self.setclasses(objects.classes) # Clear all existing objects, so we can recreate our stack. - if self.objects + if self.configuration clear() end - # Now convert the objects to real Puppet objects - @objects = objects.to_type + # Now convert the objects to a puppet configuration graph. + @configuration = objects.to_configuration - if @objects.nil? + if @configuration.nil? raise Puppet::Error, "Configuration could not be processed" end - # and perform any necessary final actions before we evaluate. - @objects.finalize + # Keep the state database up to date. + @configuration.host_config = true - return @objects + return @configuration end # A simple proxy method, so it's easy to test. @@ -252,9 +208,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client Puppet.config.use(:main, :ssl, :puppetd) super - # This might be nil - @configtime = 0 - self.class.instance = self @running = false @@ -297,7 +250,9 @@ class Puppet::Network::Client::Master < Puppet::Network::Client end # The code that actually runs the configuration. - def run(tags = nil, ignoreschedules = false) + # This just passes any options on to the configuration, + # which accepts :tags and :ignoreschedules. + def run(options = {}) got_lock = false splay Puppet::Util.sync(:puppetrun).synchronize(Sync::EX) do @@ -307,19 +262,20 @@ class Puppet::Network::Client::Master < Puppet::Network::Client else got_lock = true begin - @configtime = thinmark do + duration = thinmark do self.getconfig end rescue => detail Puppet.err "Could not retrieve configuration: %s" % detail end - if defined? @objects and @objects + if defined? @configuration and @configuration + @configuration.retrieval_duration = duration unless @local Puppet.notice "Starting configuration run" end benchmark(:notice, "Finished configuration run") do - self.apply(tags, ignoreschedules) + @configuration.apply(options) end end end @@ -366,9 +322,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client # Download files from the remote server, returning a list of all # changed files. def self.download(args) - objects = Puppet::Type.type(:component).create( - :name => "#{args[:name]}_collector" - ) hash = { :path => args[:dest], :recurse => true, @@ -383,18 +336,23 @@ class Puppet::Network::Client::Master < Puppet::Network::Client if args[:ignore] hash[:ignore] = args[:ignore].split(/\s+/) end - objects.push Puppet::Type.type(:file).create(hash) + downconfig = Puppet::Node::Configuration.new("downloading") + downconfig.add_resource Puppet::Type.type(:file).create(hash) Puppet.info "Retrieving #{args[:name]}s" noop = Puppet[:noop] Puppet[:noop] = false + files = [] begin - trans = objects.evaluate - trans.ignoretags = true Timeout::timeout(self.timeout) do - trans.evaluate + downconfig.apply do |trans| + trans.changed?.find_all do |resource| + yield resource if block_given? + files << resource[:path] + end + end end rescue Puppet::Error, Timeout::Error => detail if Puppet[:debug] @@ -403,18 +361,10 @@ class Puppet::Network::Client::Master < Puppet::Network::Client Puppet.err "Could not retrieve #{args[:name]}s: %s" % detail end - # Now source all of the changed objects, but only source those - # that are top-level. - files = [] - trans.changed?.find_all do |object| - yield object if block_given? - files << object[:path] - end - trans.cleanup - # Now clean up after ourselves - objects.remove - files + downconfig.clear + + return files ensure # I can't imagine why this is necessary, but apparently at last one person has had problems with noop # being nil here. @@ -427,21 +377,21 @@ class Puppet::Network::Client::Master < Puppet::Network::Client # Retrieve facts from the central server. def self.getfacts - # Clear all existing definitions. - Facter.clear # Download the new facts path = Puppet[:factpath].split(":") files = [] download(:dest => Puppet[:factdest], :source => Puppet[:factsource], - :ignore => Puppet[:factsignore], :name => "fact") do |object| - - next unless path.include?(::File.dirname(object[:path])) + :ignore => Puppet[:factsignore], :name => "fact") do |resource| - files << object[:path] + next unless path.include?(::File.dirname(resource[:path])) + files << resource[:path] end ensure + # Clear all existing definitions. + Facter.clear + # Reload everything. if Facter.respond_to? :loadfacts Facter.loadfacts @@ -461,20 +411,20 @@ class Puppet::Network::Client::Master < Puppet::Network::Client # changed plugins, because Puppet::Type loads plugins on demand. def self.getplugins download(:dest => Puppet[:plugindest], :source => Puppet[:pluginsource], - :ignore => Puppet[:pluginsignore], :name => "plugin") do |object| + :ignore => Puppet[:pluginsignore], :name => "plugin") do |resource| - next if FileTest.directory?(object[:path]) - path = object[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '') + next if FileTest.directory?(resource[:path]) + path = resource[:path].sub(Puppet[:plugindest], '').sub(/^\/+/, '') unless Puppet::Util::Autoload.loaded?(path) next end begin Puppet.info "Reloading downloaded file %s" % path - load object[:path] + load resource[:path] rescue => detail Puppet.warning "Could not reload downloaded file %s: %s" % - [object[:path], detail] + [resource[:path], detail] end end end @@ -517,42 +467,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client return timeout end - - # Send off the transaction report. - def report(transaction) - begin - report = transaction.generate_report() - rescue => detail - Puppet.err "Could not generate report: %s" % detail - return - end - - if Puppet[:rrdgraph] == true - report.graph() - end - - if Puppet[:summarize] - puts report.summary - end - - if Puppet[:report] - begin - reportclient().report(report) - rescue => detail - Puppet.err "Reporting failed: %s" % detail - end - end - end - - def reportclient - unless defined? @reportclient - @reportclient = Puppet::Network::Client.report.new( - :Server => Puppet[:reportserver] - ) - end - - @reportclient - end loadfacts() @@ -633,7 +547,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client Puppet.err "Could not retrieve configuration: %s" % detail unless Puppet[:usecacheonfailure] - @objects = nil + @configuration = nil Puppet.warning "Not using cache on failed configuration" return end diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 993e9d51a..11cb17a90 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -243,7 +243,10 @@ class Puppet::Network::Handler # the modules. def modules_mount(module_name, client) # Find our environment, if we have one. - if node = Puppet::Node.get(client || Facter.value("hostname")) + unless hostname = (client || Facter.value("hostname")) + raise ArgumentError, "Could not find hostname" + end + if node = Puppet::Node.find(hostname) env = node.environment else env = nil diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb index 9550dd550..030950c61 100644 --- a/lib/puppet/network/handler/master.rb +++ b/lib/puppet/network/handler/master.rb @@ -74,7 +74,7 @@ class Puppet::Network::Handler client, clientip = clientname(client, clientip, facts) # Pass the facts to the fact handler - Puppet::Node::Facts.post(Puppet::Node::Facts.new(client, facts)) + Puppet::Node::Facts.new(client, facts).save # And get the configuration from the config handler begin diff --git a/lib/puppet/network/handler/resource.rb b/lib/puppet/network/handler/resource.rb index ac29dce53..7709b85fe 100755 --- a/lib/puppet/network/handler/resource.rb +++ b/lib/puppet/network/handler/resource.rb @@ -39,21 +39,14 @@ class Puppet::Network::Handler end end - component = bucket.to_type - - # Create a client, but specify the remote machine as the server - # because the class requires it, even though it's unused - client = Puppet::Network::Client.client(:Master).new(:Master => client||"localhost") - - # Set the objects - client.objects = component + config = bucket.to_configuration # And then apply the configuration. This way we're reusing all # the code in there. It should probably just be separated out, though. - transaction = client.apply + transaction = config.apply # And then clean up - component.remove + config.clear(true) # It'd be nice to return some kind of report, but... at this point # we have no such facility. diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb index c41e83608..4b9ccab75 100755 --- a/lib/puppet/network/handler/runner.rb +++ b/lib/puppet/network/handler/runner.rb @@ -50,10 +50,10 @@ class Puppet::Network::Handler # And then we need to tell it to run, with this extra info. if fg - master.run(tags, ignoreschedules) + master.run(:tags => tags, :ignoreschedules => ignoreschedules) else Puppet.newthread do - master.run(tags, ignoreschedules) + master.run(:tags => tags, :ignoreschedules => ignoreschedules) end end diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index f8ede1858..d71bd507e 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -38,6 +38,9 @@ class Puppet::Node end def initialize(name, options = {}) + unless name + raise ArgumentError, "Node names cannot be nil" + end @name = name # Provide a default value. diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb index be30ddb68..360c25fc8 100644 --- a/lib/puppet/node/configuration.rb +++ b/lib/puppet/node/configuration.rb @@ -5,9 +5,26 @@ require 'puppet/external/gratr/digraph' # of the information in the configuration, including the resources # and the relationships between them. class Puppet::Node::Configuration < Puppet::PGraph - attr_accessor :name, :version + # The host name this is a configuration for. + attr_accessor :name + + # The configuration version. Used for testing whether a configuration + # is up to date. + attr_accessor :version + + # How long this configuration took to retrieve. Used for reporting stats. + attr_accessor :retrieval_duration + + # How we should extract the configuration for sending to the client. attr_reader :extraction_format + # Whether this is a host configuration, which behaves very differently. + # In particular, reports are sent, graphs are made, and state is + # stored in the state database. If this is set incorrectly, then you often + # end up in infinite loops, because configurations are used to make things + # that the host configuration needs. + attr_accessor :host_config + # Add classes to our class list. def add_class(*classes) classes.each do |klass| @@ -18,29 +35,133 @@ class Puppet::Node::Configuration < Puppet::PGraph tag(*classes) end - # Add a resource to our graph and to our resource table. - def add_resource(resource) - unless resource.respond_to?(:ref) - raise ArgumentError, "Can only add objects that respond to :ref" + # Add one or more resources to our graph and to our resource table. + def add_resource(*resources) + resources.each do |resource| + unless resource.respond_to?(:ref) + raise ArgumentError, "Can only add objects that respond to :ref" + end + + ref = resource.ref + if @resource_table.include?(ref) + raise ArgumentError, "Resource %s is already defined" % ref + else + @resource_table[ref] = resource + end + resource.configuration = self + add_vertex!(resource) + end + end + + # Apply our configuration to the local host. Valid options + # are: + # :tags - set the tags that restrict what resources run + # during the transaction + # :ignoreschedules - tell the transaction to ignore schedules + # when determining the resources to run + def apply(options = {}) + @applying = true + + Puppet::Util::Storage.load if host_config? + transaction = Puppet::Transaction.new(self) + + transaction.tags = options[:tags] if options[:tags] + transaction.ignoreschedules = true if options[:ignoreschedules] + + transaction.addtimes :config_retrieval => @retrieval_duration + + begin + transaction.evaluate + rescue Puppet::Error => detail + Puppet.err "Could not apply complete configuration: %s" % detail + rescue => detail + if Puppet[:trace] + puts detail.backtrace + end + Puppet.err "Got an uncaught exception of type %s: %s" % [detail.class, detail] + ensure + # Don't try to store state unless we're a host config + # too recursive. + Puppet::Util::Storage.store if host_config? end - ref = resource.ref - if @resource_table.include?(ref) - raise ArgumentError, "Resource %s is already defined" % ref - else - @resource_table[ref] = resource + if block_given? + yield transaction end + + if host_config and (Puppet[:report] or Puppet[:summarize]) + transaction.send_report + end + + return transaction + ensure + @applying = false + cleanup() + if defined? transaction and transaction + transaction.cleanup + end + end + + # Are we in the middle of applying the configuration? + def applying? + @applying end - def clear - super + def clear(remove_resources = true) + super() + # We have to do this so that the resources clean themselves up. + @resource_table.values.each { |resource| resource.remove } if remove_resources @resource_table.clear + + if defined?(@relationship_graph) and @relationship_graph + @relationship_graph.clear(false) + @relationship_graph = nil + end end def classes @classes.dup end + # Create an implicit resource, meaning that it will lose out + # to any explicitly defined resources. This method often returns + # nil. + # The quirk of this method is that it's not possible to create + # an implicit resource before an explicit resource of the same name, + # because all explicit resources are created before any generate() + # methods are called on the individual resources. Thus, this + # method can safely just check if an explicit resource already exists + # and toss this implicit resource if so. + def create_implicit_resource(type, options) + unless options.include?(:implicit) + options[:implicit] = true + end + + # This will return nil if an equivalent explicit resource already exists. + # When resource classes no longer retain references to resource instances, + # this will need to be modified to catch that conflict and discard + # implicit resources. + if resource = create_resource(type, options) + resource.implicit = true + + return resource + else + return nil + end + end + + # Create a new resource and register it in the configuration. + def create_resource(type, options) + unless klass = Puppet::Type.type(type) + raise ArgumentError, "Unknown resource type %s" % type + end + return unless resource = klass.create(options) + + @transient_resources << resource if applying? + add_resource(resource) + resource + end + # Make sure we support the requested extraction format. def extraction_format=(value) unless respond_to?("extract_to_%s" % value) @@ -113,18 +234,101 @@ class Puppet::Node::Configuration < Puppet::PGraph return result end - def initialize(name) + # Make sure all of our resources are "finished". + def finalize + @resource_table.values.each { |resource| resource.finish } + + write_graph(:resources) + end + + def host_config? + host_config || false + end + + def initialize(name = nil) super() - @name = name + @name = name if name @extraction_format ||= :transportable @tags = [] @classes = [] @resource_table = {} + @transient_resources = [] + @applying = false + @relationship_graph = nil + + if block_given? + yield(self) + finalize() + end + end + + # Create a graph of all of the relationships in our configuration. + def relationship_graph + unless defined? @relationship_graph and @relationship_graph + # It's important that we assign the graph immediately, because + # the debug messages below use the relationships in the + # relationship graph to determine the path to the resources + # spitting out the messages. If this is not set, + # then we get into an infinite loop. + @relationship_graph = Puppet::Node::Configuration.new + @relationship_graph.host_config = host_config? + + # First create the dependency graph + self.vertices.each do |vertex| + @relationship_graph.add_vertex! vertex + vertex.builddepends.each do |edge| + @relationship_graph.add_edge!(edge) + end + end + + # Lastly, add in any autorequires + @relationship_graph.vertices.each do |vertex| + vertex.autorequire.each do |edge| + unless @relationship_graph.edge?(edge) + unless @relationship_graph.edge?(edge.target, edge.source) + vertex.debug "Autorequiring %s" % [edge.source] + @relationship_graph.add_edge!(edge) + else + vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source) + end + end + end + end + + @relationship_graph.write_graph(:relationships) + + # Then splice in the container information + @relationship_graph.splice!(self, Puppet::Type::Component) + + @relationship_graph.write_graph(:expanded_relationships) + end + @relationship_graph + end + + # Remove the resource from our configuration. Notice that we also call + # 'remove' on the resource, at least until resource classes no longer maintain + # references to the resource instances. + def remove_resource(*resources) + resources.each do |resource| + @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref) + remove_vertex!(resource) if vertex?(resource) + @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource) + resource.remove + end end # Look a resource up by its reference (e.g., File[/etc/passwd]). - def resource(ref) - @resource_table[ref] + def resource(type, title = nil) + if title + ref = "%s[%s]" % [type.to_s.capitalize, title] + else + ref = type + end + if resource = @resource_table[ref] + return resource + elsif defined?(@relationship_graph) and @relationship_graph + @relationship_graph.resource(ref) + end end # Add a tag. @@ -145,4 +349,29 @@ class Puppet::Node::Configuration < Puppet::PGraph def tags @tags.dup end + + # Produce the graph files if requested. + def write_graph(name) + # We only want to graph the main host configuration. + return unless host_config? + + return unless Puppet[:graph] + + Puppet.config.use(:graphing) + + file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s) + File.open(file, "w") { |f| + f.puts to_dot("name" => name.to_s.capitalize) + } + end + + private + + def cleanup + unless @transient_resources.empty? + remove_resource(*@transient_resources) + @transient_resources.clear + @relationship_graph = nil + end + end end diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb index 7a3869dcf..2399d1651 100644 --- a/lib/puppet/pgraph.rb +++ b/lib/puppet/pgraph.rb @@ -84,7 +84,7 @@ class Puppet::PGraph < GRATR::Digraph def matching_edges(events, base = nil) events.collect do |event| source = base || event.source - + unless vertex?(source) Puppet.warning "Got an event from invalid vertex %s" % source.ref next @@ -95,7 +95,7 @@ class Puppet::PGraph < GRATR::Digraph adjacent(source, :direction => :out, :type => :edges).find_all do |edge| edge.match?(event.event) end - end.flatten + end.compact.flatten end # Take container information from another graph and use it diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb index 446ed641c..6a05d9826 100644 --- a/lib/puppet/provider/mount.rb +++ b/lib/puppet/provider/mount.rb @@ -50,5 +50,3 @@ module Puppet::Provider::Mount end end end - -# $Id$ diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb index 8d6e11379..d51f50372 100644 --- a/lib/puppet/reports/store.rb +++ b/lib/puppet/reports/store.rb @@ -13,7 +13,7 @@ Puppet::Network::Handler.report.newreport(:store, :useyaml => true) do def mkclientdir(client, dir) config = Puppet::Util::Config.new config.setdefaults("reportclient-#{client}", - "clientdir-#{client}" => { :default => dir, + "client-#{client}-dir" => { :default => dir, :mode => 0750, :desc => "Client dir for %s" % client, :owner => Puppet[:user], diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 46bac3058..4e2ab702f 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -6,10 +6,14 @@ require 'puppet/propertychange' module Puppet class Transaction - attr_accessor :component, :resources, :ignoreschedules, :ignoretags - attr_accessor :relgraph, :sorted_resources, :configurator + attr_accessor :component, :configuration, :ignoreschedules + attr_accessor :sorted_resources, :configurator + # The report, once generated. attr_reader :report + + # The list of events generated in this transaction. + attr_reader :events attr_writer :tags @@ -22,13 +26,14 @@ class Transaction end end - # Check to see if we should actually allow deleition. + # Check to see if we should actually allow processing, but this really only + # matters when a resource is getting deleted. def allow_processing?(resource, changes) # If a resource is going to be deleted but it still has # dependencies, then don't delete it unless it's implicit or the # dependency is itself being deleted. if resource.purging? and resource.deleting? - if deps = @relgraph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? } + if deps = relationship_graph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? } resource.warning "%s still depend%s on me -- not purging" % [deps.collect { |r| r.ref }.join(","), deps.length > 1 ? "":"s"] return false @@ -129,6 +134,9 @@ class Transaction # Find all of the changed resources. def changed? @changes.find_all { |change| change.changed }.collect { |change| + unless change.property.resource + raise "No resource for %s" % change.inspect + end change.property.resource }.uniq end @@ -137,14 +145,8 @@ class Transaction # contained resources might never get cleaned up. def cleanup if defined? @generated - @generated.each do |resource| - resource.remove - end + relationship_graph.remove_resource(*@generated) end - if defined? @relgraph - @relgraph.clear - end - @resources.clear end # Copy an important relationships from the parent to the newly-generated @@ -158,10 +160,11 @@ class Transaction else edge = [resource, gen_child] end - unless @relgraph.edge?(edge[1], edge[0]) - @relgraph.add_edge!(*edge) + relationship_graph.add_resource(gen_child) unless relationship_graph.resource(gen_child.ref) + + unless relationship_graph.edge?(edge[1], edge[0]) + relationship_graph.add_edge!(*edge) else - @relgraph.add_vertex!(gen_child) resource.debug "Skipping automatic relationship to %s" % gen_child end end @@ -192,7 +195,8 @@ class Transaction children.each do |child| child.finish # Make sure that the vertex is in the relationship graph. - @relgraph.add_vertex!(child) + relationship_graph.add_resource(child) unless relationship_graph.resource(child.ref) + child.configuration = relationship_graph end @generated += children return children @@ -265,9 +269,12 @@ class Transaction # Collect the targets of any subscriptions to those events. We pass # the parent resource in so it will override the source in the events, # since eval_generated children can't have direct relationships. - @relgraph.matching_edges(events, resource).each do |edge| - edge = edge.dup - label = edge.label + relationship_graph.matching_edges(events, resource).each do |orig_edge| + # We have to dup the label here, else we modify the original edge label, + # which affects whether a given event will match on the next run, which is, + # of course, bad. + edge = orig_edge.class.new(orig_edge.source, orig_edge.target) + label = orig_edge.label.dup label[:event] = events.collect { |e| e.event } edge.label = label set_trigger(edge) @@ -283,8 +290,6 @@ class Transaction def evaluate @count = 0 - graph(@resources, :resources) - # Start logging. Puppet::Util::Log.newdestination(@report) @@ -314,6 +319,7 @@ class Transaction Puppet.debug "Finishing transaction %s with %s changes" % [self.object_id, @count] + @events = allevents allevents end @@ -333,7 +339,7 @@ class Transaction # enough to check the immediate dependencies, which is why we use # a tree from the reversed graph. skip = false - deps = @relgraph.dependencies(resource) + deps = relationship_graph.dependencies(resource) deps.each do |dep| if fails = failed?(dep) resource.notice "Dependency %s[%s] has %s failures" % @@ -347,7 +353,7 @@ class Transaction # Collect any dynamically generated resources. def generate - list = @resources.vertices + list = @configuration.vertices # Store a list of all generated resources, so that we can clean them up # after the transaction closes. @@ -369,7 +375,8 @@ class Transaction end made.uniq! made.each do |res| - @resources.add_vertex!(res) + @configuration.add_resource(res) + res.configuration = configuration newlist << res @generated << res res.finish @@ -410,32 +417,24 @@ class Transaction return @report end - # Produce the graph files if requested. - def graph(gr, name) - # We don't want to graph the configuration process. - return if self.configurator - - return unless Puppet[:graph] - - Puppet.config.use(:graphing) - - file = File.join(Puppet[:graphdir], "%s.dot" % name.to_s) - File.open(file, "w") { |f| - f.puts gr.to_dot("name" => name.to_s.capitalize) - } + # Should we ignore tags? + def ignore_tags? + ! @configuration.host_config? end # this should only be called by a Puppet::Type::Component resource now # and it should only receive an array def initialize(resources) - if resources.is_a?(Puppet::PGraph) - @resources = resources + if resources.is_a?(Puppet::Node::Configuration) + @configuration = resources + elsif resources.is_a?(Puppet::PGraph) + raise "Transactions should get configurations now, not PGraph" else - @resources = resources.to_graph + raise "Transactions require configurations" end @resourcemetrics = { - :total => @resources.vertices.length, + :total => @configuration.vertices.length, :out_of_sync => 0, # The number of resources that had changes :applied => 0, # The number of resources fixed :skipped => 0, # The number of resources skipped @@ -474,7 +473,7 @@ class Transaction # types, just providers. def prefetch prefetchers = {} - @resources.each do |resource| + @configuration.each do |resource| if provider = resource.provider and provider.class.respond_to?(:prefetch) prefetchers[provider.class] ||= {} prefetchers[provider.class][resource.title] = resource @@ -501,48 +500,49 @@ class Transaction # Now add any dynamically generated resources generate() - - # Create a relationship graph from our resource graph - @relgraph = relationship_graph # This will throw an error if there are cycles in the graph. - @sorted_resources = @relgraph.topsort + @sorted_resources = relationship_graph.topsort end - - # Create a graph of all of the relationships in our resource graph. + def relationship_graph - graph = Puppet::PGraph.new - - # First create the dependency graph - @resources.vertices.each do |vertex| - graph.add_vertex!(vertex) - vertex.builddepends.each do |edge| - graph.add_edge!(edge) - end + configuration.relationship_graph + end + + # Send off the transaction report. + def send_report + begin + report = generate_report() + rescue => detail + Puppet.err "Could not generate report: %s" % detail + return + end + + if Puppet[:rrdgraph] == true + report.graph() + end + + if Puppet[:summarize] + puts report.summary end - # Lastly, add in any autorequires - graph.vertices.each do |vertex| - vertex.autorequire.each do |edge| - unless graph.edge?(edge) - unless graph.edge?(edge.target, edge.source) - vertex.debug "Autorequiring %s" % [edge.source] - graph.add_edge!(edge) - else - vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source) - end - end + if Puppet[:report] + begin + reportclient().report(report) + rescue => detail + Puppet.err "Reporting failed: %s" % detail end end - - graph(graph, :relationships) - - # Then splice in the container information - graph.splice!(@resources, Puppet::Type::Component) + end - graph(graph, :expanded_relationships) - - return graph + def reportclient + unless defined? @reportclient + @reportclient = Puppet::Network::Client.report.new( + :Server => Puppet[:reportserver] + ) + end + + @reportclient end # Roll all completed changes back. @@ -572,7 +572,7 @@ class Transaction end # FIXME This won't work right now. - @relgraph.matching_edges(events).each do |edge| + relationship_graph.matching_edges(events).each do |edge| @targets[edge.target] << edge end @@ -606,7 +606,7 @@ class Transaction # Should this resource be skipped? def skip?(resource) skip = false - if ! tagged?(resource) + if missing_tags?(resource) resource.debug "Not tagged with %s" % tags.join(", ") elsif ! scheduled?(resource) resource.debug "Not scheduled" @@ -620,29 +620,22 @@ class Transaction # The tags we should be checking. def tags - # Allow the tags to be overridden unless defined? @tags - @tags = Puppet[:tags] - end - - unless defined? @processed_tags - if @tags.nil? or @tags == "" + tags = Puppet[:tags] + if tags.nil? or tags == "" @tags = [] else - @tags = [@tags] unless @tags.is_a? Array - @tags = @tags.collect do |tag| - tag.split(/\s*,\s*/) - end.flatten + @tags = tags.split(/\s*,\s*/) end - @processed_tags = true end @tags end # Is this resource tagged appropriately? - def tagged?(resource) - self.ignoretags or tags.empty? or resource.tagged?(tags) + def missing_tags?(resource) + return false if self.ignore_tags? or tags.empty? + return true unless resource.tagged?(tags) end # Are there any edges that target this resource? diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb index 782ba2467..ecd179ed7 100644 --- a/lib/puppet/transportable.rb +++ b/lib/puppet/transportable.rb @@ -71,7 +71,7 @@ module Puppet @ref end - def to_type(parent = nil) + def to_type retobj = nil if typeklass = Puppet::Type.type(self.type) # FIXME This should really be done differently, but... @@ -88,10 +88,6 @@ module Puppet raise Puppet::Error.new("Could not find object type %s" % self.type) end - if parent - parent.push retobj - end - return retobj end end @@ -178,12 +174,7 @@ module Puppet end end - str = nil - if self.top - str = "%s" - else - str = "#{@keyword} #{@type} {\n%s\n}" - end + str = "#{@keyword} #{@name} {\n%s\n}" str % @children.collect { |child| child.to_manifest }.collect { |str| @@ -200,29 +191,29 @@ module Puppet end # Create a resource graph from our structure. - def to_graph - graph = Puppet::Node::Configuration.new(Facter.value(:hostname)) - - delver = proc do |obj| - obj.each do |child| - unless container = graph.resource(obj.to_ref) + def to_configuration + configuration = Puppet::Node::Configuration.new(Facter.value("hostname")) do |config| + delver = proc do |obj| + unless container = config.resource(obj.to_ref) container = obj.to_type - graph.add_resource container - end - unless resource = graph.resource(child.to_ref) - resource = child.to_type - graph.add_resource resource + config.add_resource container end - graph.add_edge!(container, resource) - if child.is_a?(self.class) - delver.call(child) + obj.each do |child| + unless resource = config.resource(child.to_ref) + next unless resource = child.to_type + config.add_resource resource + end + config.add_edge!(container, resource) + if child.is_a?(self.class) + delver.call(child) + end end end + + delver.call(self) end - delver.call(self) - - return graph + return configuration end def to_ref @@ -236,7 +227,7 @@ module Puppet @ref end - def to_type(parent = nil) + def to_type # this container will contain the equivalent of all objects at # this level #container = Puppet::Component.new(:name => @name, :type => @type) @@ -283,45 +274,16 @@ module Puppet #Puppet.debug "%s[%s] has no parameters" % [@type, @name] end - #if parent - # hash[:parent] = parent - #end container = Puppet::Type::Component.create(hash) end #Puppet.info container.inspect - if parent - parent.push container - end - # unless we successfully created the container, return an error unless container Puppet.warning "Got no container back" return nil end - self.each { |child| - # the fact that we descend here means that we are - # always going to execute depth-first - # which is _probably_ a good thing, but one never knows... - unless child.is_a?(Puppet::TransBucket) or - child.is_a?(Puppet::TransObject) - raise Puppet::DevError, - "TransBucket#to_type cannot handle objects of type %s" % - child.class - end - - # Now just call to_type on them with the container as a parent - begin - child.to_type(container) - rescue => detail - if Puppet[:trace] and ! detail.is_a?(Puppet::Error) - puts detail.backtrace - end - Puppet.err detail.to_s - end - } - # at this point, no objects at are level are still Transportable # objects return container diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index b4b6e3b18..19f676ff4 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -44,7 +44,9 @@ class Type # that it is clear whether it operates on all attributes (thus has 'attr' in # the method name, or whether it operates on a specific type of attributes. attr_accessor :file, :line - attr_reader :parent + + # The configuration that this resource is stored in. + attr_accessor :configuration attr_writer :title attr_writer :noop @@ -310,6 +312,25 @@ class Type return self[:name] end + # Look up our parent in the configuration, if we have one. + def parent + return nil unless configuration + + # This is kinda weird. + if implicit? + parents = configuration.relationship_graph.adjacent(self, :direction => :in) + else + parents = configuration.adjacent(self, :direction => :in) + end + if parents + # We should never have more than one parent, so let's just ignore + # it if we happen to. + return parents.shift + else + return nil + end + end + # Return the "type[name]" style reference. def ref "%s[%s]" % [self.class.name.to_s.capitalize, self.title] diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb index 79afa95a7..c5842e0e7 100644 --- a/lib/puppet/type/component.rb +++ b/lib/puppet/type/component.rb @@ -52,6 +52,7 @@ Puppet::Type.newtype(:component) do # this is only called on one component over the whole system # this also won't work with scheduling, but eh def evaluate + raise "Component#evaluate is deprecated" self.finalize unless self.finalized? transaction = Puppet::Transaction.new(self) transaction.component = self @@ -127,27 +128,6 @@ Puppet::Type.newtype(:component) do return false end end - - def push(*childs) - unless defined? @children - @children = [] - end - childs.each { |child| - # Make sure we don't have any loops here. - if parentof?(child) - devfail "Already the parent of %s[%s]" % [child.class.name, child.title] - end - unless child.is_a?(Puppet::Type) - self.debug "Got object of type %s" % child.class - self.devfail( - "Containers can only contain Puppet resources, not %s" % - child.class - ) - end - @children.push(child) - child.parent = self - } - end # Component paths are special because they function as containers. def pathbuilder @@ -162,8 +142,8 @@ Puppet::Type.newtype(:component) do else myname = self.title end - if self.parent - return [@parent.pathbuilder, myname] + if p = self.parent + return [p.pathbuilder, myname] else return [myname] end @@ -173,25 +153,6 @@ Puppet::Type.newtype(:component) do title end - # Remove an object. The argument determines whether the object's - # subscriptions get eliminated, too. - def remove(rmdeps = true) - # Our children remove themselves from our @children array (else the object - # we called this on at the top would not be removed), so we duplicate the - # array and iterate over that. If we don't do this, only half of the - # objects get removed. - @children.dup.each { |child| - child.remove(rmdeps) - } - - @children.clear - - # Get rid of params and provider, too. - super - - @parent = nil - end - # We have a different way of setting the title def title unless defined? @title @@ -207,30 +168,12 @@ Puppet::Type.newtype(:component) do end def refresh - @children.collect { |child| + configuration.adjacent(self).each do |child| if child.respond_to?(:refresh) child.refresh child.log "triggering %s" % :refresh end - } - end - - # Convert to a graph object with all of the container info. - def to_graph - graph = Puppet::PGraph.new - - delver = proc do |obj| - obj.each do |child| - graph.add_edge!(obj, child) - if child.is_a?(self.class) - delver.call(child) - end - end end - - delver.call(self) - - return graph end def to_s @@ -241,5 +184,3 @@ Puppet::Type.newtype(:component) do end end end - -# $Id$ diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index 99b5a7435..5bf9fef78 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -574,6 +574,9 @@ module Puppet # Create a new file or directory object as a child to the current # object. def newchild(path, local, hash = {}) + unless configuration + raise Puppet::DevError, "File recursion cannot happen without a configuration" + end # make local copy of arguments args = symbolize_options(@arghash) @@ -608,14 +611,14 @@ module Puppet } child = nil - klass = self.class - + # The child might already exist because 'localrecurse' runs # before 'sourcerecurse'. I could push the override stuff into # a separate method or something, but the work is the same other # than this last bit, so it doesn't really make sense. - if child = klass[path] + if child = configuration.resource(:file, path) unless child.parent.object_id == self.object_id + puts("Parent is %s, I am %s" % [child.parent.ref, self.ref]) if child.parent self.debug "Not managing more explicit file %s" % path return nil @@ -640,28 +643,22 @@ module Puppet #notice "Creating new file with args %s" % args.inspect args[:parent] = self begin - child = klass.implicitcreate(args) - - # implicit creation can return nil - if child.nil? - return nil - end - rescue Puppet::Error => detail - self.notice( - "Cannot manage: %s" % - [detail.message] - ) - self.debug args.inspect - child = nil + # This method is used by subclasses of :file, so use the class name rather than hard-coding + # :file. + return nil unless child = configuration.create_implicit_resource(self.class.name, args) rescue => detail - self.notice( - "Cannot manage: %s" % - [detail] - ) - self.debug args.inspect - child = nil + puts detail.backtrace + self.notice "Cannot manage: %s" % [detail] + return nil end end + + # LAK:FIXME This shouldn't be necessary, but as long as we're + # modeling the relationship graph specifically, it is. + configuration.relationship_graph.add_edge! self, child + unless child.parent + raise "Did not set parent of %s" % child.ref + end return child end @@ -669,12 +666,14 @@ module Puppet # path names, rather than including the full parent's title each # time. def pathbuilder - if defined? @parent + # We specifically need to call the method here, so it looks + # up our parent in the configuration graph. + if parent = parent() # We only need to behave specially when our parent is also # a file - if @parent.is_a?(self.class) + if parent.is_a?(self.class) # Remove the parent file name - list = @parent.pathbuilder + list = parent.pathbuilder list.pop # remove the parent's path info return list << self.ref else @@ -695,9 +694,7 @@ module Puppet # files. def recurse # are we at the end of the recursion? - unless self.recurse? - return - end + return unless self.recurse? recurse = self[:recurse] # we might have a string, rather than a number diff --git a/lib/puppet/util/config.rb b/lib/puppet/util/config.rb index 9cdb4cfe3..4b6ae9e5b 100644 --- a/lib/puppet/util/config.rb +++ b/lib/puppet/util/config.rb @@ -69,14 +69,14 @@ class Puppet::Util::Config return options end - # Turn the config into a transaction and apply it + # Turn the config into a Puppet configuration and apply it def apply trans = self.to_transportable begin - comp = trans.to_type - trans = comp.evaluate - trans.evaluate - comp.remove + config = trans.to_configuration + config.store_state = false + config.apply + config.clear rescue => detail if Puppet[:trace] puts detail.backtrace @@ -476,57 +476,15 @@ class Puppet::Util::Config end # Convert a single section into transportable objects. - def section_to_transportable(section, done = nil, includefiles = true) + def section_to_transportable(section, done = nil) done ||= Hash.new { |hash, key| hash[key] = {} } objects = [] persection(section) do |obj| if @config[:mkusers] and value(:mkusers) - [:owner, :group].each do |attr| - type = nil - if attr == :owner - type = :user - else - type = attr - end - # If a user and/or group is set, then make sure we're - # managing that object - if obj.respond_to? attr and name = obj.send(attr) - # Skip root or wheel - next if %w{root wheel}.include?(name.to_s) - - # Skip owners and groups we've already done, but tag - # them with our section if necessary - if done[type].include?(name) - tags = done[type][name].tags - unless tags.include?(section) - done[type][name].tags = tags << section - end - elsif newobj = Puppet::Type.type(type)[name] - unless newobj.property(:ensure) - newobj[:ensure] = "present" - end - newobj.tag(section) - if type == :user - newobj[:comment] ||= "%s user" % name - end - else - newobj = Puppet::TransObject.new(name, type.to_s) - newobj.tags = ["puppet", "configuration", section] - newobj[:ensure] = "present" - if type == :user - newobj[:comment] ||= "%s user" % name - end - # Set the group appropriately for the user - if type == :user - newobj[:gid] = Puppet[:group] - end - done[type][name] = newobj - objects << newobj - end - end - end + objects += add_user_resources(section, obj, done) end + # Only files are convertable to transportable resources. if obj.respond_to? :to_transportable next if value(obj.name) =~ /^\/dev/ transobjects = obj.to_transportable @@ -544,7 +502,8 @@ class Puppet::Util::Config end bucket = Puppet::TransBucket.new - bucket.type = section + bucket.type = "Configuration" + bucket.name = section bucket.push(*objects) bucket.keyword = "class" @@ -596,9 +555,9 @@ class Puppet::Util::Config end # Convert our list of objects into a component that can be applied. - def to_component + def to_configuration transport = self.to_transportable - return transport.to_type + return transport.to_configuration end # Convert our list of objects into a configuration file. @@ -634,7 +593,7 @@ Generated on #{Time.now}. end # Convert our configuration into a list of transportable objects. - def to_transportable + def to_transportable(*sections) done = Hash.new { |hash, key| hash[key] = {} } @@ -643,14 +602,20 @@ Generated on #{Time.now}. if defined? @file.file and @file.file topbucket.name = @file.file else - topbucket.name = "configtop" + topbucket.name = "top" end - topbucket.type = "puppetconfig" + topbucket.type = "Configuration" topbucket.top = true # Now iterate over each section - eachsection do |section| - topbucket.push section_to_transportable(section, done) + if sections.empty? + eachsection do |section| + sections << section + end + end + sections.each do |section| + obj = section_to_transportable(section, done) + topbucket.push obj end topbucket @@ -683,37 +648,31 @@ Generated on #{Time.now}. } return if runners.empty? - bucket = Puppet::TransBucket.new - bucket.type = "puppetconfig" - bucket.top = true - - # Create a hash to keep track of what we've done so far. - @done = Hash.new { |hash, key| hash[key] = {} } - runners.each do |section| - bucket.push section_to_transportable(section, @done, false) - end - - objects = bucket.to_type - - objects.finalize - tags = nil - if Puppet[:tags] - tags = Puppet[:tags] - Puppet[:tags] = "" - end - trans = objects.evaluate - trans.ignoretags = true - trans.configurator = true - trans.evaluate - if tags - Puppet[:tags] = tags - end - - # Remove is a recursive process, so it's sufficient to just call - # it on the component. - objects.remove(true) - - objects = nil + bucket = to_transportable(*sections) + + config = bucket.to_configuration + config.host_config = false + config.apply + config.clear + +# tags = nil +# if Puppet[:tags] +# tags = Puppet[:tags] +# Puppet[:tags] = "" +# end +# trans = objects.evaluate +# trans.ignoretags = true +# trans.configurator = true +# trans.evaluate +# if tags +# Puppet[:tags] = tags +# end +# +# # Remove is a recursive process, so it's sufficient to just call +# # it on the component. +# objects.remove(true) +# +# objects = nil runners.each { |s| @used << s } end @@ -845,6 +804,48 @@ Generated on #{Time.now}. private + # Create the transportable objects for users and groups. + def add_user_resources(section, obj, done) + resources = [] + [:owner, :group].each do |attr| + type = nil + if attr == :owner + type = :user + else + type = attr + end + # If a user and/or group is set, then make sure we're + # managing that object + if obj.respond_to? attr and name = obj.send(attr) + # Skip root or wheel + next if %w{root wheel}.include?(name.to_s) + + # Skip owners and groups we've already done, but tag + # them with our section if necessary + if done[type].include?(name) + tags = done[type][name].tags + unless tags.include?(section) + done[type][name].tags = tags << section + end + else + newobj = Puppet::TransObject.new(name, type.to_s) + newobj.tags = ["puppet", "configuration", section] + newobj[:ensure] = :present + if type == :user + newobj[:comment] ||= "%s user" % name + end + # Set the group appropriately for the user + if type == :user + newobj[:gid] = Puppet[:group] + end + done[type][name] = newobj + resources << newobj + end + end + end + resources + end + # Extract extra setting information for files. def extract_fileinfo(string) result = {} @@ -1105,6 +1106,11 @@ Generated on #{Time.now}. # Set the type appropriately. Yep, a hack. This supports either naming # the variable 'dir', or adding a slash at the end. def munge(value) + # If it's not a fully qualified path... + if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// + # Make it one + value = File.join(Dir.getwd, value) + end if value.to_s =~ /\/$/ @type = :directory return value.sub(/\/$/, '') @@ -1127,9 +1133,6 @@ Generated on #{Time.now}. end # Convert the object to a TransObject instance. - # FIXME There's no dependency system in place right now; if you use - # a section that requires another section, there's nothing done to - # correct that for you, at the moment. def to_transportable type = self.type return nil unless type @@ -1138,9 +1141,9 @@ Generated on #{Time.now}. objects = [] path = self.value - unless path =~ /^#{File::SEPARATOR}/ - path = File.join(Dir.getwd, path) - end + + # Skip plain files that don't exist, since we won't be managing them anyway. + return nil unless self.name.to_s =~ /dir$/ or File.exist?(path) or self.create obj = Puppet::TransObject.new(path, "file") # Only create directories, or files that are specifically marked to @@ -1157,7 +1160,7 @@ Generated on #{Time.now}. } # Only chown or chgrp when root - if Puppet::Util::SUIDManager.uid == 0 + if Puppet.features.root? [:group, :owner].each { |var| if value = self.send(var) obj[var] = value @@ -1218,5 +1221,3 @@ Generated on #{Time.now}. end end end - -# $Id$ diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb index a10183615..cd41aa572 100644 --- a/lib/puppet/util/storage.rb +++ b/lib/puppet/util/storage.rb @@ -99,5 +99,3 @@ class Puppet::Util::Storage end end end - -# $Id$ diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb index e57f12072..b2320e0da 100755 --- a/spec/unit/indirector/indirection.rb +++ b/spec/unit/indirector/indirection.rb @@ -51,7 +51,7 @@ describe Puppet::Indirector::Indirection, " when choosing terminus types" do it "should follow a convention on using per-model configuration parameters to determine the terminus class" do Puppet.config.expects(:valid?).with('test_terminus').returns(true) Puppet.config.expects(:value).with('test_terminus').returns(:foo) - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) + Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class) @indirection.terminus.should equal(@terminus) end @@ -59,12 +59,12 @@ describe Puppet::Indirector::Indirection, " when choosing terminus types" do per-model configuration parameter is available" do Puppet.config.expects(:valid?).with('test_terminus').returns(false) Puppet.config.expects(:value).with(:default_terminus).returns(:foo) - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) + Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class) @indirection.terminus.should equal(@terminus) end it "should select the specified terminus class if a name is provided" do - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) + Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(@terminus_class) @indirection.terminus(:foo).should equal(@terminus) end @@ -77,7 +77,7 @@ describe Puppet::Indirector::Indirection, " when choosing terminus types" do end it "should fail when the specified terminus class cannot be found" do - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) + Puppet::Indirector::Terminus.expects(:terminus_class).with(:foo, :test).returns(nil) proc { @indirection.terminus(:foo) }.should raise_error(ArgumentError) end @@ -91,7 +91,7 @@ describe Puppet::Indirector::Indirection, " when managing terminus instances" do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @terminus = mock 'terminus' @terminus_class = mock 'terminus class' - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:foo, :test).returns(@terminus_class) end it "should create an instance of the chosen terminus class" do diff --git a/spec/unit/node/configuration.rb b/spec/unit/node/configuration.rb index 774a1550f..b37cc754d 100755 --- a/spec/unit/node/configuration.rb +++ b/spec/unit/node/configuration.rb @@ -134,25 +134,339 @@ describe Puppet::Node::Configuration, " when extracting transobjects" do end end -describe Puppet::Node::Configuration, " functioning as a resource container" do +describe Puppet::Node::Configuration, " when functioning as a resource container" do before do - @graph = Puppet::Node::Configuration.new("host") - @one = stub 'resource1', :ref => "Me[you]" - @two = stub 'resource2', :ref => "Me[him]" - @dupe = stub 'resource3', :ref => "Me[you]" + @config = Puppet::Node::Configuration.new("host") + @one = stub 'resource1', :ref => "Me[you]", :configuration= => nil + @two = stub 'resource2', :ref => "Me[him]", :configuration= => nil + @dupe = stub 'resource3', :ref => "Me[you]", :configuration= => nil + end + + it "should provide a method to add one or more resources" do + @config.add_resource @one, @two + @config.resource(@one.ref).should equal(@one) + @config.resource(@two.ref).should equal(@two) end it "should make all vertices available by resource reference" do - @graph.add_resource(@one) - @graph.resource(@one.ref).should equal(@one) + @config.add_resource(@one) + @config.resource(@one.ref).should equal(@one) + @config.vertices.find { |r| r.ref == @one.ref }.should equal(@one) end it "should not allow two resources with the same resource reference" do - @graph.add_resource(@one) - proc { @graph.add_resource(@dupe) }.should raise_error(ArgumentError) + @config.add_resource(@one) + proc { @config.add_resource(@dupe) }.should raise_error(ArgumentError) end it "should not store objects that do not respond to :ref" do - proc { @graph.add_resource("thing") }.should raise_error(ArgumentError) + proc { @config.add_resource("thing") }.should raise_error(ArgumentError) + end + + it "should remove all resources when asked" do + @config.add_resource @one + @config.add_resource @two + @one.expects :remove + @two.expects :remove + @config.clear(true) + end + + it "should support a mechanism for finishing resources" do + @one.expects :finish + @two.expects :finish + @config.add_resource @one + @config.add_resource @two + + @config.finalize + end + + it "should optionally support an initialization block and should finalize after such blocks" do + @one.expects :finish + @two.expects :finish + config = Puppet::Node::Configuration.new("host") do |conf| + conf.add_resource @one + conf.add_resource @two + end + end + + it "should inform the resource that it is the resource's configuration" do + @one.expects(:configuration=).with(@config) + @config.add_resource @one + end + + it "should be able to find resources by reference" do + @config.add_resource @one + @config.resource(@one.ref).should equal(@one) + end + + it "should be able to find resources by reference or by type/title tuple" do + @config.add_resource @one + @config.resource("me", "you").should equal(@one) + end + + it "should have a mechanism for removing resources" do + @config.add_resource @one + @one.expects :remove + @config.remove_resource(@one) + @config.resource(@one.ref).should be_nil + @config.vertex?(@one).should be_false + end +end + +module ApplyingConfigurations + def setup + @config = Puppet::Node::Configuration.new("host") + + @config.retrieval_duration = Time.now + @transaction = mock 'transaction' + Puppet::Transaction.stubs(:new).returns(@transaction) + @transaction.stubs(:evaluate) + @transaction.stubs(:cleanup) + @transaction.stubs(:addtimes) + end +end + +describe Puppet::Node::Configuration, " when applying" do + include ApplyingConfigurations + + it "should create and evaluate a transaction" do + @transaction.expects(:evaluate) + @config.apply + end + + it "should provide the configuration time to the transaction" do + @transaction.expects(:addtimes).with do |arg| + arg[:config_retrieval].should be_instance_of(Time) + true + end + @config.apply + end + + it "should clean up the transaction" do + @transaction.expects :cleanup + @config.apply + end + + it "should return the transaction" do + @config.apply.should equal(@transaction) + end + + it "should yield the transaction if a block is provided" do + @config.apply do |trans| + trans.should equal(@transaction) + end + end + + it "should default to not being a host configuration" do + @config.host_config.should be_nil + end + + it "should pass supplied tags on to the transaction" do + @transaction.expects(:tags=).with(%w{one two}) + @config.apply(:tags => %w{one two}) + end + + it "should set ignoreschedules on the transaction if specified in apply()" do + @transaction.expects(:ignoreschedules=).with(true) + @config.apply(:ignoreschedules => true) + end +end + +describe Puppet::Node::Configuration, " when applying host configurations" do + include ApplyingConfigurations + + # super() doesn't work in the setup method for some reason + before do + @config.host_config = true + end + + it "should send a report if reporting is enabled" do + Puppet[:report] = true + @transaction.expects :send_report + @config.apply + end + + it "should send a report if report summaries are enabled" do + Puppet[:summarize] = true + @transaction.expects :send_report + @config.apply + end + + it "should initialize the state database before applying a configuration" do + Puppet::Util::Storage.expects(:load) + + # Short-circuit the apply, so we know we're loading before the transaction + Puppet::Transaction.expects(:new).raises ArgumentError + proc { @config.apply }.should raise_error(ArgumentError) + end + + it "should sync the state database after applying" do + Puppet::Util::Storage.expects(:store) + @config.apply + end + + after { Puppet.config.clear } +end + +describe Puppet::Node::Configuration, " when applying non-host configurations" do + include ApplyingConfigurations + + before do + @config.host_config = false + end + + it "should never send reports" do + Puppet[:report] = true + Puppet[:summarize] = true + @transaction.expects(:send_report).never + @config.apply + end + + it "should never modify the state database" do + Puppet::Util::Storage.expects(:load).never + Puppet::Util::Storage.expects(:store).never + @config.apply + end + + after { Puppet.config.clear } +end + +describe Puppet::Node::Configuration, " when creating a relationship graph" do + before do + @config = Puppet::Node::Configuration.new("host") + @compone = Puppet::Type::Component.create :name => "one" + @comptwo = Puppet::Type::Component.create :name => "two", :require => ["class", "one"] + @file = Puppet::Type.type(:file) + @one = @file.create :path => "/one" + @two = @file.create :path => "/two" + @config.add_edge! @compone, @one + @config.add_edge! @comptwo, @two + + @three = @file.create :path => "/three" + @four = @file.create :path => "/four", :require => ["file", "/three"] + @five = @file.create :path => "/five" + @config.add_resource @compone, @comptwo, @one, @two, @three, @four, @five + @relationships = @config.relationship_graph + end + + it "should be able to create a relationship graph" do + @relationships.should be_instance_of(Puppet::Node::Configuration) + end + + it "should copy its host_config setting to the relationship graph" do + config = Puppet::Node::Configuration.new + config.host_config = true + config.relationship_graph.host_config.should be_true + end + + it "should not have any components" do + @relationships.vertices.find { |r| r.instance_of?(Puppet::Type::Component) }.should be_nil + end + + it "should have all non-component resources from the configuration" do + # The failures print out too much info, so i just do a class comparison + @relationships.vertex?(@five).should be_true + end + + it "should have all resource relationships set as edges" do + @relationships.edge?(@three, @four).should be_true + end + + it "should copy component relationships to all contained resources" do + @relationships.edge?(@one, @two).should be_true + end + + it "should get removed when the configuration is cleaned up" do + @relationships.expects(:clear).with(false) + @config.clear + @config.instance_variable_get("@relationship_graph").should be_nil + end + + it "should create a new relationship graph after clearing the old one" do + @relationships.expects(:clear).with(false) + @config.clear + @config.relationship_graph.should be_instance_of(Puppet::Node::Configuration) + end + + it "should look up resources in the relationship graph if not found in the main configuration" do + five = stub 'five', :ref => "File[five]", :configuration= => nil + @relationships.add_resource five + @config.resource(five.ref).should equal(five) + end + + it "should provide a method to create additional resources that also registers the resource" do + args = {:name => "/yay", :ensure => :file} + resource = stub 'file', :ref => "File[/yay]", :configuration= => @config + Puppet::Type.type(:file).expects(:create).with(args).returns(resource) + @config.create_resource :file, args + @config.resource("File[/yay]").should equal(resource) + end + + it "should provide a mechanism for creating implicit resources" do + args = {:name => "/yay", :ensure => :file} + resource = stub 'file', :ref => "File[/yay]", :configuration= => @config + Puppet::Type.type(:file).expects(:create).with(args).returns(resource) + resource.expects(:implicit=).with(true) + @config.create_implicit_resource :file, args + @config.resource("File[/yay]").should equal(resource) + end + + it "should remove resources created mid-transaction" do + args = {:name => "/yay", :ensure => :file} + resource = stub 'file', :ref => "File[/yay]", :configuration= => @config + @transaction = mock 'transaction' + Puppet::Transaction.stubs(:new).returns(@transaction) + @transaction.stubs(:evaluate) + @transaction.stubs(:cleanup) + @transaction.stubs(:addtimes) + Puppet::Type.type(:file).expects(:create).with(args).returns(resource) + resource.expects :remove + @config.apply do |trans| + @config.create_resource :file, args + @config.resource("File[/yay]").should equal(resource) + end + @config.resource("File[/yay]").should be_nil + end + + it "should remove resources from the relationship graph if it exists" do + @config.remove_resource(@one) + @config.relationship_graph.vertex?(@one).should be_false + end + + after do + Puppet::Type.allclear + end +end + +describe Puppet::Node::Configuration, " when writing dot files" do + before do + @config = Puppet::Node::Configuration.new("host") + @name = :test + @file = File.join(Puppet[:graphdir], @name.to_s + ".dot") + end + it "should only write when it is a host configuration" do + File.expects(:open).with(@file).never + @config.host_config = false + Puppet[:graph] = true + @config.write_graph(@name) + end + + it "should only write when graphing is enabled" do + File.expects(:open).with(@file).never + @config.host_config = true + Puppet[:graph] = false + @config.write_graph(@name) + end + + it "should write a dot file based on the passed name" do + File.expects(:open).with(@file, "w").yields(stub("file", :puts => nil)) + @config.expects(:to_dot).with("name" => @name.to_s.capitalize) + @config.host_config = true + Puppet[:graph] = true + @config.write_graph(@name) + end + + after do + Puppet.config.clear end end diff --git a/spec/unit/node/node.rb b/spec/unit/node/node.rb index 899d81ac7..53f362da6 100755 --- a/spec/unit/node/node.rb +++ b/spec/unit/node/node.rb @@ -11,6 +11,10 @@ describe Puppet::Node, " when initializing" do @node.name.should == "testnode" end + it "should not allow nil node names" do + proc { Puppet::Node.new(nil) }.should raise_error(ArgumentError) + end + it "should default to an empty parameter hash" do @node.parameters.should == {} end diff --git a/spec/unit/other/modules.rb b/spec/unit/other/modules.rb index 0ab37aa9e..dbd091d9a 100755 --- a/spec/unit/other/modules.rb +++ b/spec/unit/other/modules.rb @@ -5,10 +5,10 @@ require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Module, " when building its search path" do include PuppetTest - it "should ignore unqualified paths in the search path" do + it "should fully qualify unqualified paths in the search path" do Puppet[:modulepath] = "something:/my/something" File.stubs(:directory?).returns(true) - Puppet::Module.modulepath.should == %w{/my/something} + Puppet::Module.modulepath.should == [File.join(Dir.getwd, 'something'), "/my/something"] end it "should ignore paths that do not exist" do diff --git a/spec/unit/other/transaction.rb b/spec/unit/other/transaction.rb new file mode 100755 index 000000000..7990d2eef --- /dev/null +++ b/spec/unit/other/transaction.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Transaction, " when determining tags" do + before do + @config = Puppet::Node::Configuration.new + @transaction = Puppet::Transaction.new(@config) + end + + it "should default to the tags specified in the :tags setting" do + Puppet.expects(:[]).with(:tags).returns("one") + @transaction.tags.should == %w{one} + end + + it "should split tags based on ','" do + Puppet.expects(:[]).with(:tags).returns("one,two") + @transaction.tags.should == %w{one two} + end + + it "should use any tags set after creation" do + Puppet.expects(:[]).with(:tags).never + @transaction.tags = %w{one two} + @transaction.tags.should == %w{one two} + end +end diff --git a/spec/unit/other/transbucket.rb b/spec/unit/other/transbucket.rb index c013973ee..8cb9abaa4 100755 --- a/spec/unit/other/transbucket.rb +++ b/spec/unit/other/transbucket.rb @@ -48,7 +48,7 @@ describe Puppet::TransBucket do end end -describe Puppet::TransBucket, " when generating a resource graph" do +describe Puppet::TransBucket, " when generating a configuration" do before do @bottom = Puppet::TransBucket.new @bottom.type = "fake" @@ -70,7 +70,7 @@ describe Puppet::TransBucket, " when generating a resource graph" do @top.push(@topobj) @top.push(@middle) - @graph = @top.to_graph + @config = @top.to_configuration @users = %w{top middle bottom} @fakes = %w{fake[bottom] fake[middle] fake[top]} @@ -78,18 +78,28 @@ describe Puppet::TransBucket, " when generating a resource graph" do it "should convert all transportable objects to RAL resources" do @users.each do |name| - @graph.vertices.find { |r| r.class.name == :user and r.title == name }.should be_instance_of(Puppet::Type.type(:user)) + @config.vertices.find { |r| r.class.name == :user and r.title == name }.should be_instance_of(Puppet::Type.type(:user)) end end it "should convert all transportable buckets to RAL components" do @fakes.each do |name| - @graph.vertices.find { |r| r.class.name == :component and r.title == name }.should be_instance_of(Puppet::Type.type(:component)) + @config.vertices.find { |r| r.class.name == :component and r.title == name }.should be_instance_of(Puppet::Type.type(:component)) end end it "should add all resources to the graph's resource table" do - @graph.resource("fake[top]").should equal(@top) + @config.resource("fake[top]").should equal(@top) + end + + it "should finalize all resources" do + @config.vertices.each do |vertex| vertex.should be_finalized end + end + + it "should only call to_type on each resource once" do + @topobj.expects(:to_type) + @bottomobj.expects(:to_type) + @top.to_configuration end after do diff --git a/spec/unit/ral/type.rb b/spec/unit/ral/type.rb new file mode 100755 index 000000000..c8bf8c9b4 --- /dev/null +++ b/spec/unit/ral/type.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Type, " when in a configuration" do + before do + @configuration = Puppet::Node::Configuration.new + @container = Puppet::Type.type(:component).create(:name => "container") + @one = Puppet::Type.type(:file).create(:path => "/file/one") + @two = Puppet::Type.type(:file).create(:path => "/file/two") + @configuration.add_resource @container + @configuration.add_resource @one + @configuration.add_resource @two + @configuration.add_edge! @container, @one + @configuration.add_edge! @container, @two + end + + it "should have no parent if there is no in edge" do + @container.parent.should be_nil + end + + it "should set its parent to its in edge" do + @one.parent.ref.should equal(@container.ref) + end +end diff --git a/spec/unit/util/config.rb b/spec/unit/util/config.rb index 28ccb04d7..8114acb8e 100755 --- a/spec/unit/util/config.rb +++ b/spec/unit/util/config.rb @@ -299,7 +299,7 @@ describe Puppet::Util::Config, " when parsing its configuration" do end it "should support specifying file all metadata (owner, group, mode) in the configuration file" do - @config.setdefaults :section, :myfile => ["/my/file", "a"] + @config.setdefaults :section, :myfile => ["/myfile", "a"] text = "[main] myfile = /other/file {owner = luke, group = luke, mode = 644} @@ -312,7 +312,7 @@ describe Puppet::Util::Config, " when parsing its configuration" do end it "should support specifying file a single piece of metadata (owner, group, or mode) in the configuration file" do - @config.setdefaults :section, :myfile => ["/my/file", "a"] + @config.setdefaults :section, :myfile => ["/myfile", "a"] text = "[main] myfile = /other/file {owner = luke} @@ -388,16 +388,34 @@ describe Puppet::Util::Config, " when reparsing its configuration" do end describe Puppet::Util::Config, " when being used to manage the host machine" do + before do + @config = Puppet::Util::Config.new + @config.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"] + @config.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "luke", :group => "johnny", :mode => 0755} + @config.setdefaults :files, :myfile => {:default => "/myfile", :desc => "a", :mode => 0755} + end + it "should provide a method that writes files with the correct modes" do pending "Not converted from test/unit yet" end it "should provide a method that creates directories with the correct modes" do - pending "Not converted from test/unit yet" + Puppet::Util::SUIDManager.expects(:asuser).with("luke", "johnny").yields + Dir.expects(:mkdir).with("/otherdir", 0755) + @config.mkdir(:otherdir) end - it "should provide a method to declare what directories should exist" do - pending "Not converted from test/unit yet" + it "should be able to create needed directories in a single section" do + Dir.expects(:mkdir).with("/maindir") + Dir.expects(:mkdir).with("/seconddir") + @config.use(:main) + end + + it "should be able to create needed directories in multiple sections" do + Dir.expects(:mkdir).with("/maindir") + Dir.expects(:mkdir).with("/otherdir", 0755) + Dir.expects(:mkdir).with("/seconddir") + @config.use(:main, :other) end it "should provide a method to trigger enforcing of file modes on existing files and directories" do @@ -408,19 +426,110 @@ describe Puppet::Util::Config, " when being used to manage the host machine" do pending "Not converted from test/unit yet" end - it "should provide an option to create needed users and groups" do + it "should create files when configured to do so with the :create parameter" + + it "should provide a method to convert the file mode enforcement into transportable resources" do + # Make it think we're root so it tries to manage user and group. + Puppet.features.stubs(:root?).returns(true) + File.stubs(:exist?).with("/myfile").returns(true) + trans = nil + trans = @config.to_transportable + resources = [] + trans.delve { |obj| resources << obj if obj.is_a? Puppet::TransObject } + %w{/maindir /seconddir /otherdir /myfile}.each do |path| + obj = resources.find { |r| r.type == "file" and r.name == path } + if path.include?("dir") + obj[:ensure].should == :directory + else + # Do not create the file, just manage mode + obj[:ensure].should be_nil + end + obj.should be_instance_of(Puppet::TransObject) + case path + when "/otherdir": + obj[:owner].should == "luke" + obj[:group].should == "johnny" + obj[:mode].should == 0755 + when "/myfile": + obj[:mode].should == 0755 + end + end + end + + it "should not try to manage user or group when not running as root" do + Puppet.features.stubs(:root?).returns(false) + trans = nil + trans = @config.to_transportable(:other) + trans.delve do |obj| + next unless obj.is_a?(Puppet::TransObject) + obj[:owner].should be_nil + obj[:group].should be_nil + end + end + + it "should add needed users and groups to the manifest when asked" do + # This is how we enable user/group management + @config.setdefaults :main, :mkusers => [true, "w"] + Puppet.features.stubs(:root?).returns(false) + trans = nil + trans = @config.to_transportable(:other) + resources = [] + trans.delve { |obj| resources << obj if obj.is_a? Puppet::TransObject and obj.type != "file" } + + user = resources.find { |r| r.type == "user" } + user.should be_instance_of(Puppet::TransObject) + user.name.should == "luke" + user[:ensure].should == :present + + # This should maybe be a separate test, but... + group = resources.find { |r| r.type == "group" } + group.should be_instance_of(Puppet::TransObject) + group.name.should == "johnny" + group[:ensure].should == :present + end + + it "should ignore tags and schedules when creating files and directories" + + it "should apply all resources in debug mode to reduce logging" + + it "should not try to manage absent files" do + # Make it think we're root so it tries to manage user and group. + Puppet.features.stubs(:root?).returns(true) + trans = nil + trans = @config.to_transportable + file = nil + trans.delve { |obj| file = obj if obj.name == "/myfile" } + file.should be_nil + end + + it "should be able to turn the current configuration into a parseable manifest" + + it "should convert octal numbers correctly when producing a manifest" + + it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do pending "Not converted from test/unit yet" end - it "should provide a method to print out the current configuration" do + it "should not attempt to manage files within /dev" do pending "Not converted from test/unit yet" end - it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do - pending "Not converted from test/unit yet" + it "should not modify the stored state database when managing resources" do + Puppet::Util::Storage.expects(:store).never + Puppet::Util::Storage.expects(:load).never + Dir.expects(:mkdir).with("/maindir") + @config.use(:main) end - it "should not attempt to manage files within /dev" do - pending "Not converted from test/unit yet" + it "should convert all relative paths to fully-qualified paths (#795)" do + @config[:myfile] = "unqualified" + dir = Dir.getwd + @config[:myfile].should == File.join(dir, "unqualified") + end + + it "should support a method for re-using all currently used sections" do + Dir.expects(:mkdir).with(@config[:otherdir], 0755).times(2) + @config.use(:other) + @config.reuse end end diff --git a/test/data/snippets/failmissingexecpath.pp b/test/data/snippets/failmissingexecpath.pp deleted file mode 100644 index b03875547..000000000 --- a/test/data/snippets/failmissingexecpath.pp +++ /dev/null @@ -1,14 +0,0 @@ -define distloc($path) { - file { "/tmp/exectesting1": - ensure => file - } - exec { "exectest": - command => "touch $path", - subscribe => File["/tmp/exectesting1"], - refreshonly => true - } -} - -distloc { yay: - path => "/tmp/execdisttesting", -} diff --git a/test/language/snippets.rb b/test/language/snippets.rb index ff8a09881..7168a81d8 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -197,7 +197,7 @@ class TestSnippets < Test::Unit::TestCase def snippet_classpathtest path = "/tmp/classtest" - file = @file[path] + file = @configuration.resource(:file, path) assert(file, "did not create file %s" % path) assert_nothing_raised { @@ -271,14 +271,6 @@ class TestSnippets < Test::Unit::TestCase assert_mode_equal(0755, file) end - def snippet_failmissingexecpath - file = "/tmp/exectesting1" - execfile = "/tmp/execdisttesting" - assert_file(file) - - assert_nil(Puppet::Type.type(:exec)["exectest"], "invalid exec was created") - end - def snippet_selectorvalues nums = %w{1 2 3 4 5} files = nums.collect { |n| @@ -473,8 +465,8 @@ class TestSnippets < Test::Unit::TestCase :Local => true ) facts = Puppet::Node::Facts.new("testhost", facts) - Puppet::Node::Facts.stubs(:post) - Puppet::Node::Facts.stubs(:get).returns(facts) + Puppet::Node::Facts.stubs(:save) + Puppet::Node::Facts.stubs(:find).returns(facts) client = Puppet::Network::Client.master.new( :Master => server, :Cache => false @@ -508,6 +500,7 @@ class TestSnippets < Test::Unit::TestCase assert(obj.name) } } + @configuration = client.configuration assert_nothing_raised { self.send(mname) } diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index c4bd7dc2b..62fa7213e 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -308,17 +308,17 @@ module PuppetTest::ParserTesting ) } - config = nil + trans = nil assert_nothing_raised { - config = interp.compile(mknode) + trans = interp.compile(mknode) } - comp = nil + config = nil assert_nothing_raised { - comp = config.extract.to_type + config = trans.extract.to_configuration } - assert_apply(comp) + config.apply files.each do |file| assert(FileTest.exists?(file), "Did not create %s" % file) diff --git a/test/lib/puppettest/support/assertions.rb b/test/lib/puppettest/support/assertions.rb index 9369f17e7..7e3e5ca2b 100644 --- a/test/lib/puppettest/support/assertions.rb +++ b/test/lib/puppettest/support/assertions.rb @@ -38,7 +38,7 @@ module PuppetTest run_events(:rollback, trans, events, msg) end - def assert_events(events, *items) + def assert_events(events, *resources) trans = nil comp = nil msg = nil @@ -46,56 +46,26 @@ module PuppetTest unless events.is_a? Array raise Puppet::DevError, "Incorrect call of assert_events" end - if items[-1].is_a? String - msg = items.pop + if resources[-1].is_a? String + msg = resources.pop end - remove_comp = false - # They either passed a comp or a list of items. - if items[0].is_a? Puppet.type(:component) - comp = items.shift - else - comp = newcomp(items[0].title, *items) - remove_comp = true - end - msg ||= comp.title - assert_nothing_raised("Component %s failed" % [msg]) { - trans = comp.evaluate - } + config = resources2config(*resources) + transaction = Puppet::Transaction.new(config) - run_events(:evaluate, trans, events, msg) + run_events(:evaluate, transaction, events, msg) - if remove_comp - Puppet.type(:component).delete(comp) - end - - return trans + return transaction end # A simpler method that just applies what we have. - def assert_apply(*objects) - if objects[0].is_a?(Puppet.type(:component)) - comp = objects.shift - unless objects.empty? - objects.each { |o| comp.push o } - end - else - comp = newcomp(*objects) - end - trans = nil - - assert_nothing_raised("Failed to create transaction") { - trans = comp.evaluate - } + def assert_apply(*resources) + config = resources2config(*resources) events = nil - assert_nothing_raised("Failed to evaluate transaction") { - events = trans.evaluate.collect { |e| e.event } + assert_nothing_raised("Failed to evaluate") { + events = config.apply.events } - trans.cleanup - Puppet.type(:component).delete(comp) events end end - -# $Id$ diff --git a/test/lib/puppettest/support/resources.rb b/test/lib/puppettest/support/resources.rb index 45d89c5fb..18d7caa77 100755 --- a/test/lib/puppettest/support/resources.rb +++ b/test/lib/puppettest/support/resources.rb @@ -4,34 +4,34 @@ # Copyright (c) 2006. All rights reserved. module PuppetTest::Support::Resources - def treefile(name) - Puppet::Type.type(:file).create :path => "/tmp/#{name}", :mode => 0755 + def tree_resource(name) + Puppet::Type.type(:file).create :title => name, :path => "/tmp/#{name}", :mode => 0755 end - def treecomp(name) + def tree_container(name) Puppet::Type::Component.create :name => name, :type => "yay" end - def treenode(name, *children) - comp = treecomp name - children.each do |c| - if c.is_a?(String) - comp.push treefile(c) - else - comp.push c + def treenode(config, name, *resources) + comp = tree_container name + resources.each do |resource| + if resource.is_a?(String) + resource = tree_resource(resource) end + config.add_edge!(comp, resource) + config.add_resource resource unless config.resource(resource.ref) end return comp end def mktree - one = treenode("one", "a", "b") - two = treenode("two", "c", "d") - middle = treenode("middle", "e", "f", two) - top = treenode("top", "g", "h", middle, one) + configuration = Puppet::Node::Configuration.new do |config| + one = treenode(config, "one", "a", "b") + two = treenode(config, "two", "c", "d") + middle = treenode(config, "middle", "e", "f", two) + top = treenode(config, "top", "g", "h", middle, one) + end - return one, two, middle, top + return configuration end end - -# $Id$
\ No newline at end of file diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb index c7d54d5e6..7f4260e31 100644 --- a/test/lib/puppettest/support/utils.rb +++ b/test/lib/puppettest/support/utils.rb @@ -19,6 +19,25 @@ module PuppetTest } end + # Turn a list of resources, or possibly a configuration and some resources, + # into a configuration object. + def resources2config(*resources) + if resources[0].is_a?(Puppet::Node::Configuration) + config = resources.shift + unless resources.empty? + resources.each { |r| config.add_resource r } + end + elsif resources[0].is_a?(Puppet.type(:component)) + raise ArgumentError, "resource2config() no longer accpts components" + comp = resources.shift + comp.delve + else + config = Puppet::Node::Configuration.new + resources.each { |res| config.add_resource res } + end + return config + end + # stop any services that might be hanging around def stopservices if stype = Puppet::Type.type(:service) @@ -127,20 +146,17 @@ module PuppetTest } end - def newcomp(*ary) - name = nil - if ary[0].is_a?(String) - name = ary.shift + def mk_configuration(*resources) + if resources[0].is_a?(String) + name = resources.shift else - name = ary[0].title + name = :testing + end + config = Puppet::Node::Configuration.new :testing do |conf| + resources.each { |resource| conf.add_resource resource } end - comp = Puppet.type(:component).create(:name => name) - ary.each { |item| - comp.push item - } - - return comp + return config end def setme diff --git a/test/network/client/master.rb b/test/network/client/master.rb index a29254d16..2e9ed2752 100755 --- a/test/network/client/master.rb +++ b/test/network/client/master.rb @@ -88,51 +88,6 @@ class TestMasterClient < Test::Unit::TestCase return master, objects end - def test_apply - master, objects = mk_fake_client - - check = Proc.new do |hash| - assert(objects.trans, "transaction was not created") - trans = objects.trans - hash[:yes].each do |m| - assert_equal(1, trans.send(m.to_s + "?"), "did not call #{m} enough times") - end - hash[:no].each do |m| - assert_equal(0, trans.send(m.to_s + "?"), "called #{m} too many times") - end - end - - # First try it with no arguments - assert_nothing_raised do - master.apply - end - check.call :yes => %w{evaluate cleanup addtimes}, :no => %w{report tags ignoreschedules} - assert_equal(0, master.reported, "master sent report with reports disabled") - - - # Now enable reporting and make sure the report method gets called - Puppet[:report] = true - assert_nothing_raised do - master.apply - end - check.call :yes => %w{evaluate cleanup addtimes}, :no => %w{tags ignoreschedules} - assert_equal(1, master.reported, "master did not send report") - - # Now try it with tags enabled - assert_nothing_raised do - master.apply("tags") - end - check.call :yes => %w{evaluate cleanup tags addtimes}, :no => %w{ignoreschedules} - assert_equal(2, master.reported, "master did not send report") - - # and ignoreschedules - assert_nothing_raised do - master.apply("tags", true) - end - check.call :yes => %w{evaluate cleanup tags ignoreschedules addtimes}, :no => %w{} - assert_equal(3, master.reported, "master did not send report") - end - def test_getconfig client = mkclient @@ -167,9 +122,8 @@ class TestMasterClient < Test::Unit::TestCase [:getplugins, :get_actual_config].each do |method| assert($methodsrun.include?(method), "method %s was not run" % method) end - - objects = client.objects - assert(objects.finalized?, "objects were not finalized") + + assert_instance_of(Puppet::Node::Configuration, client.configuration, "Configuration was not created") end def test_disable @@ -233,7 +187,7 @@ class TestMasterClient < Test::Unit::TestCase } end - # This method is supposed + # This method downloads files, and yields each file object if a block is given. def test_download source = tempfile() dest = tempfile() diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb index 9749c7bdf..df946fa33 100755 --- a/test/network/handler/master.rb +++ b/test/network/handler/master.rb @@ -76,9 +76,10 @@ class TestMaster < Test::Unit::TestCase "Client is incorrectly up to date") Puppet.config.use(:main) + config = nil assert_nothing_raised { - client.getconfig - client.apply + config = client.getconfig + config.apply } # Now it should be up to date @@ -113,8 +114,8 @@ class TestMaster < Test::Unit::TestCase # Retrieve and apply the new config assert_nothing_raised { - client.getconfig - client.apply + config = client.getconfig + config.apply } assert(client.fresh?(facts), "Client is not up to date") diff --git a/test/other/dsl.rb b/test/other/dsl.rb index f1fd1a1e9..59610cd0f 100755 --- a/test/other/dsl.rb +++ b/test/other/dsl.rb @@ -214,5 +214,3 @@ class TestDSL < Test::Unit::TestCase assert_instance_of(Puppet::Parser::Resource, file) end end - -# $Id$ diff --git a/test/other/events.rb b/test/other/events.rb index 802a701a3..b67ea05a1 100755 --- a/test/other/events.rb +++ b/test/other/events.rb @@ -23,7 +23,7 @@ class TestEvents < Test::Unit::TestCase :subscribe => [[file.class.name, file.name]] ) - comp = newcomp("eventtesting", file, exec) + comp = mk_configuration("eventtesting", file, exec) trans = assert_events([:file_created, :triggered], comp) @@ -44,56 +44,16 @@ class TestEvents < Test::Unit::TestCase ) - comp = Puppet.type(:component).create( - :name => "eventtesting" - ) - comp.push exec - trans = comp.evaluate - events = nil - assert_nothing_raised { - events = trans.evaluate - } + config = mk_configuration + config.add_resource file + config.add_resource exec + trans = config.apply - assert_equal(1, events.length) + assert_equal(1, trans.events.length) assert_equal(0, trans.triggered?(exec, :refresh)) end - # Verify that one component can subscribe to another component and the "right" - # thing happens - def test_ladderrequire - comps = {} - objects = {} - fname = tempfile() - file = Puppet.type(:file).create( - :name => tempfile(), - :ensure => "file" - ) - - exec = Puppet.type(:exec).create( - :name => "touch %s" % fname, - :path => "/usr/bin:/bin", - :refreshonly => true - ) - - fcomp = newcomp(file) - ecomp = newcomp(exec) - comp = newcomp("laddercomp", fcomp, ecomp) - - ecomp[:subscribe] = [[fcomp.class.name, fcomp.name]] - - comp.finalize - - trans = comp.evaluate - events = nil - assert_nothing_raised { - events = trans.evaluate - } - - assert(FileTest.exists?(fname), "#{fname} does not exist") - #assert_equal(events.length, trans.triggered?(objects[:b], :refresh)) - end - def test_multiplerefreshes files = [] @@ -115,7 +75,7 @@ class TestEvents < Test::Unit::TestCase ["file", f.name] } - comp = newcomp(exec, *files) + comp = mk_configuration(exec, *files) assert_apply(comp) assert(FileTest.exists?(fname), "Exec file did not get created") @@ -147,17 +107,16 @@ class TestEvents < Test::Unit::TestCase ) execs = [exec1, exec2, exec3] - comp = newcomp(exec1,exec2,exec3) + config = mk_configuration(exec1,exec2,exec3) - trans = comp.evaluate - execs.each do |e| assert(trans.resources.vertex?(e), "%s is not in graph" % e.title) end + trans = Puppet::Transaction.new(config) + execs.each do |e| assert(config.vertex?(e), "%s is not in graph" % e.title) end trans.prepare - execs.each do |e| assert(trans.relgraph.vertex?(e), "%s is not in relgraph" % e.title) end - reverse = trans.relgraph.reversal + execs.each do |e| assert(config.vertex?(e), "%s is not in relgraph" % e.title) end + reverse = trans.relationship_graph.reversal execs.each do |e| assert(reverse.vertex?(e), "%s is not in reversed graph" % e.title) end - - assert_apply(comp) + config.apply assert(FileTest.exists?(file), "File does not exist") diff --git a/test/other/overrides.rb b/test/other/overrides.rb index 2bc443980..9a7c4b8ba 100755 --- a/test/other/overrides.rb +++ b/test/other/overrides.rb @@ -90,12 +90,10 @@ class TestOverrides < Test::Unit::TestCase } } - comp = newcomp("overrides", baseobj) - children.each { |child| comp.push child } + config = mk_configuration(baseobj, *children) assert_nothing_raised("Could not eval component") { - trans = comp.evaluate - trans.evaluate + config.apply } files.each { |path, mode| diff --git a/test/other/relationships.rb b/test/other/relationships.rb index a5c9db5dc..771b119ee 100755 --- a/test/other/relationships.rb +++ b/test/other/relationships.rb @@ -172,15 +172,12 @@ class TestRelationships < Test::Unit::TestCase end assert_equal([Puppet::Relationship[file, exec]], reqs) - # Now make sure that these relationships are added to the transaction's - # relgraph - trans = Puppet::Transaction.new(newcomp(file, exec)) - assert_nothing_raised do - trans.evaluate + # Now make sure that these relationships are added to the + # relationship graph + config = mk_configuration(file, exec) + config.apply do |trans| + assert(config.relationship_graph.edge?(file, exec), "autorequire edge was not created") end - - graph = trans.relgraph - assert(graph.edge?(file, exec), "autorequire edge was not created") end def test_requires? diff --git a/test/other/report.rb b/test/other/report.rb index c59881f72..7499c51e2 100755 --- a/test/other/report.rb +++ b/test/other/report.rb @@ -26,16 +26,10 @@ class TestReports < Test::Unit::TestCase ) end - comp = newcomp(*objects) - - trans = nil - assert_nothing_raised("Failed to create transaction") { - trans = comp.evaluate - } - - assert_nothing_raised("Failed to evaluate transaction") { - trans.evaluate - } + config = mk_configuration(*objects) + # So the report works out. + config.retrieval_duration = 0.001 + trans = config.apply return trans.generate_report end diff --git a/test/other/transactions.rb b/test/other/transactions.rb index bf5f65084..7d17a92e7 100755 --- a/test/other/transactions.rb +++ b/test/other/transactions.rb @@ -7,8 +7,6 @@ require 'puppettest' require 'mocha' require 'puppettest/support/resources' -# $Id$ - class TestTransactions < Test::Unit::TestCase include PuppetTest::FileTesting include PuppetTest::Support::Resources @@ -133,7 +131,7 @@ class TestTransactions < Test::Unit::TestCase inst = type.create :name => "yay" # Create a transaction - trans = Puppet::Transaction.new(newcomp(inst)) + trans = Puppet::Transaction.new(mk_configuration(inst)) # Make sure prefetch works assert_nothing_raised do @@ -255,7 +253,7 @@ class TestTransactions < Test::Unit::TestCase } - component = newcomp("file",file) + component = mk_configuration("file",file) require 'etc' groupname = Etc.getgrgid(File.stat(file.name).gid).name assert_nothing_raised() { @@ -295,12 +293,11 @@ class TestTransactions < Test::Unit::TestCase file[:check] = check file[:group] = @groups[0] - assert_apply(file) + config = mk_configuration(file) + config.apply @@tmpfiles << execfile - component = newcomp("both",file,exec) - # 'subscribe' expects an array of arrays exec[:subscribe] = [[file.class.name,file.name]] exec[:refreshonly] = true @@ -317,7 +314,11 @@ class TestTransactions < Test::Unit::TestCase file[:mode] = "755" } - trans = assert_events([:file_changed, :triggered], component) + # Make a new configuration so the resource relationships get + # set up. + config = mk_configuration(file, exec) + + trans = assert_events([:file_changed, :triggered], config) assert(FileTest.exists?(execfile), "Execfile does not exist") File.unlink(execfile) @@ -325,7 +326,7 @@ class TestTransactions < Test::Unit::TestCase file[:group] = @groups[1] } - trans = assert_events([:file_changed, :triggered], component) + trans = assert_events([:file_changed, :triggered], config) assert(FileTest.exists?(execfile), "Execfile does not exist") end @@ -343,24 +344,30 @@ class TestTransactions < Test::Unit::TestCase file[:group] = @groups[0] assert_apply(file) - fcomp = newcomp("file",file) - ecomp = newcomp("exec",exec) + config = Puppet::Node::Configuration.new + fcomp = Puppet::Type.type(:component).create(:name => "file") + config.add_resource fcomp + config.add_resource file + config.add_edge!(fcomp, file) - component = newcomp("both",fcomp,ecomp) + ecomp = Puppet::Type.type(:component).create(:name => "exec") + config.add_resource ecomp + config.add_resource exec + config.add_edge!(ecomp, exec) # 'subscribe' expects an array of arrays #component[:require] = [[file.class.name,file.name]] ecomp[:subscribe] = fcomp exec[:refreshonly] = true - trans = assert_events([], component) + trans = assert_events([], config) assert_nothing_raised() { file[:group] = @groups[1] file[:mode] = "755" } - trans = assert_events([:file_changed, :file_changed, :triggered], component) + trans = assert_events([:file_changed, :file_changed, :triggered], config) end # Make sure that multiple subscriptions get triggered. @@ -426,7 +433,8 @@ class TestTransactions < Test::Unit::TestCase Puppet[:ignoreschedules] = false file = Puppet.type(:file).create( :name => tempfile(), - :ensure => "file" + :ensure => "file", + :backup => false ) fname = tempfile() @@ -437,11 +445,10 @@ class TestTransactions < Test::Unit::TestCase :subscribe => ["file", file.name] ) - comp = newcomp(file,exec) - comp.finalize + config = mk_configuration(file, exec) # Run it once - assert_apply(comp) + assert_apply(config) assert(FileTest.exists?(fname), "File did not get created") assert(!exec.scheduled?, "Exec is somehow scheduled") @@ -451,7 +458,8 @@ class TestTransactions < Test::Unit::TestCase file[:content] = "some content" - assert_events([:file_changed, :triggered], comp) + assert_events([:file_changed, :triggered], config) + assert(FileTest.exists?(fname), "File did not get recreated") # Now remove it, so it can get created again @@ -469,7 +477,7 @@ class TestTransactions < Test::Unit::TestCase assert(! file.insync?(file.retrieve), "Uh, file is in sync?") - assert_events([:file_changed, :triggered], comp) + assert_events([:file_changed, :triggered], config) assert(FileTest.exists?(fname), "File did not get recreated") end @@ -493,11 +501,9 @@ class TestTransactions < Test::Unit::TestCase :ensure => :file ) - comp = newcomp(exec, file1, file2) - - comp.finalize + config = mk_configuration(exec, file1, file2) - assert_apply(comp) + assert_apply(config) assert(! FileTest.exists?(file1[:path]), "File got created even tho its dependency failed") @@ -506,31 +512,27 @@ class TestTransactions < Test::Unit::TestCase end end - def f(n) - Puppet::Type.type(:file)["/tmp/#{n.to_s}"] - end - def test_relationship_graph - one, two, middle, top = mktree + config = mktree + + config.meta_def(:f) do |name| + self.resource("File[%s]" % name) + end - {one => two, "f" => "c", "h" => middle}.each do |source, target| - if source.is_a?(String) - source = f(source) - end - if target.is_a?(String) - target = f(target) - end + {"one" => "two", "File[f]" => "File[c]", "File[h]" => "middle"}.each do |source_ref, target_ref| + source = config.resource(source_ref) or raise "Missing %s" % source_ref + target = config.resource(target_ref) or raise "Missing %s" % target_ref target[:require] = source end - trans = Puppet::Transaction.new(top) + trans = Puppet::Transaction.new(config) graph = nil assert_nothing_raised do graph = trans.relationship_graph end - - assert_instance_of(Puppet::PGraph, graph, + + assert_instance_of(Puppet::Node::Configuration, graph, "Did not get relationship graph") # Make sure all of the components are gone @@ -544,13 +546,13 @@ class TestTransactions < Test::Unit::TestCase sorted = graph.topsort.reverse # Now make sure the appropriate edges are there and are in the right order - assert(graph.dependents(f(:f)).include?(f(:c)), + assert(graph.dependents(config.f(:f)).include?(config.f(:c)), "c not marked a dep of f") - assert(sorted.index(f(:c)) < sorted.index(f(:f)), + assert(sorted.index(config.f(:c)) < sorted.index(config.f(:f)), "c is not before f") - one.each do |o| - two.each do |t| + config.resource("one").each do |o| + config.resource("two").each do |t| assert(graph.dependents(o).include?(t), "%s not marked a dep of %s" % [t.ref, o.ref]) assert(sorted.index(t) < sorted.index(o), @@ -558,22 +560,22 @@ class TestTransactions < Test::Unit::TestCase end end - trans.resources.leaves(middle).each do |child| - assert(graph.dependents(f(:h)).include?(child), + trans.configuration.leaves(config.resource("middle")).each do |child| + assert(graph.dependents(config.f(:h)).include?(child), "%s not marked a dep of h" % [child.ref]) - assert(sorted.index(child) < sorted.index(f(:h)), + assert(sorted.index(child) < sorted.index(config.f(:h)), "%s is not before h" % child.ref) end # Lastly, make sure our 'g' vertex made it into the relationship # graph, since it's not involved in any relationships. - assert(graph.vertex?(f(:g)), + assert(graph.vertex?(config.f(:g)), "Lost vertexes with no relations") # Now make the reversal graph and make sure all of the vertices made it into that reverse = graph.reversal %w{a b c d e f g h}.each do |letter| - file = f(letter) + file = config.f(letter) assert(reverse.vertex?(file), "%s did not make it into reversal" % letter) end end @@ -594,15 +596,15 @@ class TestTransactions < Test::Unit::TestCase yay = Puppet::Type.newgenerator :title => "yay" rah = Puppet::Type.newgenerator :title => "rah" - comp = newcomp(yay, rah) - trans = comp.evaluate + config = mk_configuration(yay, rah) + trans = Puppet::Transaction.new(config) assert_nothing_raised do trans.generate end %w{ya ra y r}.each do |name| - assert(trans.resources.vertex?(Puppet::Type.type(:generator)[name]), + assert(trans.configuration.vertex?(Puppet::Type.type(:generator)[name]), "Generated %s was not a vertex" % name) assert($finished.include?(name), "%s was not finished" % name) end @@ -613,7 +615,7 @@ class TestTransactions < Test::Unit::TestCase end %w{ya ra y r}.each do |name| - assert(!trans.resources.vertex?(Puppet::Type.type(:generator)[name]), + assert(!trans.configuration.vertex?(Puppet::Type.type(:generator)[name]), "Generated vertex %s was not removed from graph" % name) assert_nil(Puppet::Type.type(:generator)[name], "Generated vertex %s was not removed from class" % name) @@ -633,8 +635,8 @@ class TestTransactions < Test::Unit::TestCase yay = Puppet::Type.newgenerator :title => "yay" rah = Puppet::Type.newgenerator :title => "rah", :subscribe => yay - comp = newcomp(yay, rah) - trans = comp.evaluate + config = mk_configuration(yay, rah) + trans = Puppet::Transaction.new(config) trans.prepare @@ -645,13 +647,13 @@ class TestTransactions < Test::Unit::TestCase end ya = type["ya"] assert(ya, "Did not generate ya") - assert(trans.relgraph.vertex?(ya), + assert(trans.relationship_graph.vertex?(ya), "Did not add ya to rel_graph") # Now make sure the appropriate relationships were added - assert(trans.relgraph.edge?(yay, ya), + assert(trans.relationship_graph.edge?(yay, ya), "parent was not required by child") - assert(! trans.relgraph.edge?(ya, rah), + assert(! trans.relationship_graph.edge?(ya, rah), "generated child ya inherited depencency on rah") # Now make sure it in turn eval_generates appropriately @@ -662,7 +664,7 @@ class TestTransactions < Test::Unit::TestCase %w{y}.each do |name| res = type[name] assert(res, "Did not generate %s" % name) - assert(trans.relgraph.vertex?(res), + assert(trans.relationship_graph.vertex?(res), "Did not add %s to rel_graph" % name) assert($finished.include?("y"), "y was not finished") end @@ -670,7 +672,7 @@ class TestTransactions < Test::Unit::TestCase assert_nothing_raised("failed to eval_generate with nil response") do trans.eval_resource(type["y"]) end - assert(trans.relgraph.edge?(yay, ya), "no edge was created for ya => yay") + assert(trans.relationship_graph.edge?(yay, ya), "no edge was created for ya => yay") assert_nothing_raised("failed to apply rah") do trans.eval_resource(rah) @@ -678,15 +680,15 @@ class TestTransactions < Test::Unit::TestCase ra = type["ra"] assert(ra, "Did not generate ra") - assert(trans.relgraph.vertex?(ra), + assert(trans.relationship_graph.vertex?(ra), "Did not add ra to rel_graph" % name) assert($finished.include?("ra"), "y was not finished") # Now make sure this generated resource has the same relationships as # the generating resource - assert(! trans.relgraph.edge?(yay, ra), + assert(! trans.relationship_graph.edge?(yay, ra), "rah passed its dependencies on to its children") - assert(! trans.relgraph.edge?(ya, ra), + assert(! trans.relationship_graph.edge?(ya, ra), "children have a direct relationship") # Now make sure that cleanup gets rid of those generated types. @@ -695,14 +697,14 @@ class TestTransactions < Test::Unit::TestCase end %w{ya ra y r}.each do |name| - assert(!trans.relgraph.vertex?(type[name]), + assert(!trans.relationship_graph.vertex?(type[name]), "Generated vertex %s was not removed from graph" % name) assert_nil(type[name], "Generated vertex %s was not removed from class" % name) end # Now, start over and make sure that everything gets evaluated. - trans = comp.evaluate + trans = Puppet::Transaction.new(config) $evaluated.clear assert_nothing_raised do trans.evaluate @@ -711,54 +713,41 @@ class TestTransactions < Test::Unit::TestCase assert_equal(%w{yay ya y rah ra r}, $evaluated, "Not all resources were evaluated or not in the right order") end - - def test_tags - res = Puppet::Type.newfile :path => tempfile() - comp = newcomp(res) - - # Make sure they default to none - assert_equal([], comp.evaluate.tags) - - # Make sure we get the main tags - Puppet[:tags] = %w{this is some tags} - assert_equal(%w{this is some tags}, comp.evaluate.tags) - - # And make sure they get processed correctly - Puppet[:tags] = ["one", "two,three", "four"] - assert_equal(%w{one two three four}, comp.evaluate.tags) - - # lastly, make sure we can override them - trans = comp.evaluate - trans.tags = ["one", "two,three", "four"] - assert_equal(%w{one two three four}, comp.evaluate.tags) + + def test_ignore_tags? + config = Puppet::Node::Configuration.new + config.host_config = true + transaction = Puppet::Transaction.new(config) + assert(! transaction.ignore_tags?, "Ignoring tags when applying a host configuration") + + config.host_config = false + transaction = Puppet::Transaction.new(config) + assert(transaction.ignore_tags?, "Not ignoring tags when applying a non-host configuration") end - def test_tagged? - res = Puppet::Type.newfile :path => tempfile() - comp = newcomp(res) - trans = comp.evaluate - - assert(trans.tagged?(res), "tagged? defaulted to false") - - # Now set some tags - trans.tags = %w{some tags} - - # And make sure it's false - assert(! trans.tagged?(res), "matched invalid tags") - - # Set ignoretags and make sure it sticks - trans.ignoretags = true - assert(trans.tagged?(res), "tags were not ignored") - - # Now make sure we actually correctly match tags - res[:tag] = "mytag" - trans.ignoretags = false - trans.tags = %w{notag} - - assert(! trans.tagged?(res), "tags incorrectly matched") - - trans.tags = %w{mytag yaytag} - assert(trans.tagged?(res), "tags should have matched") + def test_missing_tags? + resource = stub 'resource', :tagged? => true + config = Puppet::Node::Configuration.new + + # Mark it as a host config so we don't care which test is first + config.host_config = true + transaction = Puppet::Transaction.new(config) + assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when none are set") + + # host configurations pay attention to tags, no one else does. + Puppet[:tags] = "three,four" + config.host_config = false + transaction = Puppet::Transaction.new(config) + assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when not running a host configuration") + + # + config.host_config = true + transaction = Puppet::Transaction.new(config) + assert(! transaction.missing_tags?(resource), "Considered a resource to be missing tags when running a host configuration and all tags are present") + + transaction = Puppet::Transaction.new(config) + resource.stubs :tagged? => false + assert(transaction.missing_tags?(resource), "Considered a resource not to be missing tags when running a host configuration and tags are missing") end # Make sure changes generated by eval_generated resources have proxies @@ -772,8 +761,8 @@ class TestTransactions < Test::Unit::TestCase end resource = type.create :name => "test" - comp = newcomp(resource) - trans = comp.evaluate + config = mk_configuration(resource) + trans = Puppet::Transaction.new(config) trans.prepare assert_nothing_raised do @@ -831,7 +820,7 @@ class TestTransactions < Test::Unit::TestCase end # Make a graph with some stuff in it. - graph = Puppet::PGraph.new + graph = Puppet::Node::Configuration.new # Add a non-triggering edge. a = trigger.new(:a) @@ -883,52 +872,12 @@ class TestTransactions < Test::Unit::TestCase assert(trans.triggered?(c, :refresh), "Transaction did not store the trigger") end - - def test_graph - Puppet.config.use(:main) - # Make a graph - graph = Puppet::PGraph.new - graph.add_edge!("a", "b") - - # Create our transaction - trans = Puppet::Transaction.new(graph) - - assert_nothing_raised do - trans.graph(graph, :testing) - end - - dotfile = File.join(Puppet[:graphdir], "testing.dot") - assert(! FileTest.exists?(dotfile), "Enabled graphing even tho disabled") - - # Now enable graphing - Puppet[:graph] = true - - assert_nothing_raised do - trans.graph(graph, :testing) - end - assert(FileTest.exists?(dotfile), "Did not create graph.") - end - - def test_created_graphs - FileUtils.mkdir_p(Puppet[:graphdir]) - file = Puppet::Type.newfile(:path => tempfile, :content => "yay") - exec = Puppet::Type.type(:exec).create(:command => "echo yay", :path => ENV['PATH'], - :require => file) - - Puppet[:graph] = true - assert_apply(file, exec) - - %w{resources relationships expanded_relationships}.each do |name| - file = File.join(Puppet[:graphdir], "%s.dot" % name) - assert(FileTest.exists?(file), "graph for %s was not created" % name) - end - end def test_set_target file = Puppet::Type.newfile(:path => tempfile(), :content => "yay") exec1 = Puppet::Type.type(:exec).create :command => "/bin/echo exec1" exec2 = Puppet::Type.type(:exec).create :command => "/bin/echo exec2" - trans = Puppet::Transaction.new(newcomp(file, exec1, exec2)) + trans = Puppet::Transaction.new(mk_configuration(file, exec1, exec2)) # First try it with an edge that has no callback edge = Puppet::Relationship.new(file, exec1) @@ -975,7 +924,8 @@ class TestTransactions < Test::Unit::TestCase one[:require] = two two[:require] = one - trans = newcomp(one, two).evaluate + config = mk_configuration(one, two) + trans = Puppet::Transaction.new(config) assert_raise(Puppet::Error) do trans.prepare end @@ -1042,15 +992,15 @@ class TestTransactions < Test::Unit::TestCase rels[dir] = file rels.each do |after, before| - comp = newcomp(before, after) - trans = comp.evaluate + config = mk_configuration(before, after) + trans = Puppet::Transaction.new(config) str = "from %s to %s" % [before, after] assert_nothing_raised("Failed to create graph %s" % str) do trans.prepare end - graph = trans.relgraph + graph = trans.relationship_graph assert(graph.edge?(before, after), "did not create manual relationship %s" % str) assert(! graph.edge?(after, before), "created automatic relationship %s" % str) end @@ -1063,7 +1013,7 @@ class TestTransactions < Test::Unit::TestCase one[:require] = two one[:subscribe] = two - comp = newcomp(one, two) + comp = mk_configuration(one, two) trans = Puppet::Transaction.new(comp) graph = trans.relationship_graph @@ -1188,5 +1138,3 @@ class TestTransactions < Test::Unit::TestCase assert_equal(1, $flushed, "object was flushed in noop") end end - -# $Id$ diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb index 534c35759..b2c111e60 100755 --- a/test/ral/manager/type.rb +++ b/test/ral/manager/type.rb @@ -174,7 +174,7 @@ class TestType < Test::Unit::TestCase ) } - comp = newcomp(twoobj, oneobj) + comp = mk_configuration(twoobj, oneobj) assert_nothing_raised { comp.finalize @@ -246,76 +246,6 @@ class TestType < Test::Unit::TestCase # and make sure managed objects start with them assert(user.property(:ensure), "User did not get an ensure property") end - - # Make sure removal works - def test_remove - objects = {} - top = Puppet.type(:component).create(:name => "top") - objects[top.class] = top - - base = tempfile() - - # now make a two-tier, 5 piece tree - %w{a b}.each do |letter| - name = "comp%s" % letter - comp = Puppet.type(:component).create(:name => name) - top.push comp - objects[comp.class] = comp - - 5.times do |i| - file = base + letter + i.to_s - - obj = Puppet.type(:file).create(:name => file, :ensure => "file") - - comp.push obj - objects[obj.class] = obj - end - end - - assert_nothing_raised do - top.remove - end - - objects.each do |klass, obj| - assert_nil(klass[obj.name], "object %s was not removed" % obj.name) - end - end - - # Verify that objects can't be their own children. - def test_object_recursion - comp = Puppet.type(:component).create(:name => "top") - - file = Puppet.type(:component).create(:name => "middle") - - assert_raise(Puppet::DevError) do - comp.push(comp) - end - - assert_raise(Puppet::DevError) do - file.push(file) - end - - assert_raise(Puppet::DevError) do - comp.parent = comp - end - - assert_raise(Puppet::DevError) do - file.parent = file - end - - assert_nothing_raised { - comp.push(file) - } - - assert_raise(Puppet::DevError) do - file.push(comp) - end - - assert_raise(Puppet::DevError) do - comp.parent = file - end - end - def test_newtype_methods assert_nothing_raised { Puppet::Type.newtype(:mytype) do @@ -732,12 +662,22 @@ class TestType < Test::Unit::TestCase end def test_path + config = mk_configuration + # Check that our paths are built correctly. Just pick a random, "normal" type. type = Puppet::Type.type(:exec) mk = Proc.new do |i, hash| hash[:title] = "exec%s" % i hash[:command] = "/bin/echo" - type.create(hash) + if parent = hash[:parent] + hash.delete(:parent) + end + res = type.create(hash) + config.add_resource res + if parent + config.add_edge!(parent, res) + end + res end exec = mk.call(1, {}) @@ -745,25 +685,31 @@ class TestType < Test::Unit::TestCase assert_equal("/Exec[exec1]", exec.path) comp = Puppet::Type.newcomponent :title => "My[component]", :type => "Yay" + config.add_resource comp exec = mk.call(2, :parent => comp) assert_equal("/My[component]/Exec[exec2]", exec.path) comp = Puppet::Type.newcomponent :name => "Other[thing]" + config.add_resource comp exec = mk.call(3, :parent => comp) assert_equal("/Other[thing]/Exec[exec3]", exec.path) comp = Puppet::Type.newcomponent :type => "server", :name => "server" + config.add_resource comp exec = mk.call(4, :parent => comp) assert_equal("/server/Exec[exec4]", exec.path) comp = Puppet::Type.newcomponent :type => "whatever", :name => "class[main]" + config.add_resource comp exec = mk.call(5, :parent => comp) assert_equal("//Exec[exec5]", exec.path) - comp = Puppet::Type.newcomponent :type => "yay", :name => "Good[bad]", :parent => comp - exec = mk.call(6, :parent => comp) + newcomp = Puppet::Type.newcomponent :type => "yay", :name => "Good[bad]" + config.add_resource newcomp + config.add_edge! comp, newcomp + exec = mk.call(6, :parent => newcomp) assert_equal("//Good[bad]/Exec[exec6]", exec.path) end diff --git a/test/ral/providers/service.rb b/test/ral/providers/service.rb index d21298162..5a4a6c1c2 100755 --- a/test/ral/providers/service.rb +++ b/test/ral/providers/service.rb @@ -54,7 +54,7 @@ class TestLocalService < Test::Unit::TestCase service.retrieve } - comp = newcomp("servicetst", service) + comp = mk_configuration("servicetst", service) service[:ensure] = :running Puppet.info "Starting %s" % service.name @@ -105,7 +105,7 @@ class TestLocalService < Test::Unit::TestCase service.retrieve } - comp = newcomp("servicetst", service) + comp = mk_configuration("servicetst", service) service[:enable] = true Puppet.info "Enabling %s" % service.name diff --git a/test/ral/types/basic.rb b/test/ral/types/basic.rb index 5d09a5183..2802f3440 100755 --- a/test/ral/types/basic.rb +++ b/test/ral/types/basic.rb @@ -35,12 +35,9 @@ class TestBasic < Test::Unit::TestCase :path => ENV["PATH"] ) } - assert_nothing_raised() { - @component.push( - @configfile, - @command - ) - } + @config = mk_configuration(@component, @configfile, @command) + @config.add_edge! @component, @configfile + @config.add_edge! @component, @command end def teardown @@ -86,5 +83,3 @@ class TestBasic < Test::Unit::TestCase } end end - -# $Id$ diff --git a/test/ral/types/component.rb b/test/ral/types/component.rb deleted file mode 100755 index 06c32dd01..000000000 --- a/test/ral/types/component.rb +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env ruby - -$:.unshift("../../lib") if __FILE__ =~ /\.rb$/ - -require 'puppettest' -require 'puppettest/support/resources' - -# $Id$ - -class TestComponent < Test::Unit::TestCase - include PuppetTest - include PuppetTest::Support::Resources - def setup - super - @@used = {} - @type = Puppet::Type::Component - @file = Puppet::Type.type(:file) - end - - def randnum(limit) - num = nil - looped = 0 - loop do - looped += 1 - if looped > 2000 - raise "Reached limit of looping" - break - end - num = rand(limit) - unless @@used.include?(num) - @@used[num] = true - break - end - end - - num - end - - def mkfile(num = nil) - unless num - num = randnum(1000) - end - name = tempfile() + num.to_s - - file = Puppet.type(:file).create( - :path => name, - :checksum => "md5" - ) - @@tmpfiles << name - file - end - - def mkcomp - Puppet.type(:component).create(:name => "component_" + randnum(1000).to_s) - end - - def mkrandcomp(numfiles, numdivs) - comp = mkcomp - hash = {} - found = 0 - - divs = {} - - numdivs.times { |i| - num = i + 2 - divs[num] = nil - } - while found < numfiles - num = randnum(numfiles) - found += 1 - f = mkfile(num) - hash[f.name] = f - reqd = [] - divs.each { |n,obj| - if rand(50) % n == 0 - if obj - unless reqd.include?(obj.object_id) - f[:require] = [[obj.class.name, obj.name]] - reqd << obj.object_id - end - end - end - - divs[n] = f - } - end - - hash.each { |name, obj| - comp.push obj - } - - comp.finalize - comp - end - - def test_to_graph - one, two, middle, top = mktree - - graph = nil - assert_nothing_raised do - graph = top.to_graph - end - - assert(graph.is_a?(Puppet::PGraph), "result is not a pgraph") - - [one, two, middle, top].each do |comp| - comp.each do |child| - assert(graph.edge?(comp, child), - "Did not create edge from %s => %s" % [comp.name, child.name]) - end - end - end -end diff --git a/test/ral/types/cron.rb b/test/ral/types/cron.rb index 7b2e770f0..1695befac 100755 --- a/test/ral/types/cron.rb +++ b/test/ral/types/cron.rb @@ -94,7 +94,7 @@ class TestCron < Test::Unit::TestCase text = obj.read name = cron.name - comp = newcomp(name, cron) + comp = mk_configuration(name, cron) assert_events([:cron_created], comp) cron.provider.class.prefetch @@ -157,7 +157,7 @@ class TestCron < Test::Unit::TestCase def test_makeandretrievecron %w{storeandretrieve a-name another-name more_naming SomeName}.each do |name| cron = mkcron(name) - comp = newcomp(name, cron) + comp = mk_configuration(name, cron) trans = assert_events([:cron_created], comp, name) cron.provider.class.prefetch diff --git a/test/ral/types/exec.rb b/test/ral/types/exec.rb index ede6361cd..0c7cc1d90 100755 --- a/test/ral/types/exec.rb +++ b/test/ral/types/exec.rb @@ -179,7 +179,7 @@ class TestExec < Test::Unit::TestCase ) } - comp = newcomp("createstest", exec) + comp = mk_configuration("createstest", exec) assert_events([:executed_command], comp, "creates") assert_events([], comp, "creates") end @@ -202,7 +202,7 @@ class TestExec < Test::Unit::TestCase :require => [:file, oexe] ) - comp = newcomp("Testing", file, exec) + comp = mk_configuration("Testing", file, exec) assert_events([:file_created, :executed_command], comp) end @@ -299,7 +299,7 @@ class TestExec < Test::Unit::TestCase :path => ENV['PATH'] ) } - comp = newcomp(exec) + comp = mk_configuration(exec) assert_events([:executed_command], comp) assert_events([:executed_command], comp) @@ -344,7 +344,7 @@ class TestExec < Test::Unit::TestCase exec = Puppet.type(:exec).create(args) } - comp = newcomp("usertest", exec) + comp = mk_configuration("usertest", exec) assert_events([:executed_command], comp, "usertest") assert(FileTest.exists?(file), "File does not exist") @@ -425,7 +425,7 @@ class TestExec < Test::Unit::TestCase ) } - comp = newcomp(file, exec) + comp = mk_configuration(file, exec) comp.finalize assert_events([:executed_command, :file_changed], comp) diff --git a/test/ral/types/file.rb b/test/ral/types/file.rb index f3e1a562d..0c16d6dff 100755 --- a/test/ral/types/file.rb +++ b/test/ral/types/file.rb @@ -122,7 +122,7 @@ class TestFile < Test::Unit::TestCase ) } - comp = newcomp("createusertest", file) + comp = mk_configuration("createusertest", file) assert_events([:file_created], comp) end @@ -397,6 +397,8 @@ class TestFile < Test::Unit::TestCase events = assert_apply(file) + assert(events) + assert(! events.include?(:file_changed), "File incorrectly changed") assert_events([], file) @@ -493,6 +495,7 @@ class TestFile < Test::Unit::TestCase # Create a test directory path = tempfile() dir = @file.create :path => path, :mode => 0755, :recurse => true + config = mk_configuration(dir) Dir.mkdir(path) @@ -673,6 +676,7 @@ class TestFile < Test::Unit::TestCase :check => %w{owner mode group} ) } + config = mk_configuration dir children = nil @@ -683,19 +687,22 @@ class TestFile < Test::Unit::TestCase assert_equal([subdir], children.collect {|c| c.title }, "Incorrect generated children") - dir.class[subdir].remove + # Remove our subdir resource, + subdir_resource = config.resource(:file, subdir) + config.remove_resource(subdir_resource) + # Create the test file File.open(tmpfile, "w") { |f| f.puts "yayness" } assert_nothing_raised { children = dir.eval_generate } + # And make sure we get both resources back. assert_equal([subdir, tmpfile].sort, children.collect {|c| c.title }.sort, - "Incorrect generated children") + "Incorrect generated children when recurse == %s" % value.inspect) File.unlink(tmpfile) - #system("rm -rf %s" % basedir) Puppet.type(:file).clear end end @@ -754,6 +761,7 @@ class TestFile < Test::Unit::TestCase :check => %w{owner mode group} ) } + mk_configuration dir assert_nothing_raised { dir.eval_generate @@ -796,6 +804,7 @@ class TestFile < Test::Unit::TestCase :check => %w{mode owner group} ) } + mk_configuration dirobj assert_nothing_raised { dirobj.eval_generate @@ -884,7 +893,7 @@ class TestFile < Test::Unit::TestCase ) } - comp = newcomp("yay", file) + comp = mk_configuration("yay", file) comp.finalize assert_apply(comp) #assert_events([:directory_created], comp) @@ -1274,26 +1283,27 @@ class TestFile < Test::Unit::TestCase lfobj = Puppet::Type.newfile( :title => "localfile", :path => localfile, - :content => "rahtest" + :content => "rahtest", + :backup => false ) - destobj = Puppet::Type.newfile(:title => "destdir", :path => destdir, :source => sourcedir, + :backup => false, :recurse => true) - comp = newcomp(lfobj, destobj) - assert_apply(comp) + config = mk_configuration(lfobj, destobj) + config.apply assert(FileTest.exists?(dsourcefile), "File did not get copied") assert(FileTest.exists?(localfile), "File did not get created") assert(FileTest.exists?(purgee), "File got prematurely purged") assert_nothing_raised { destobj[:purge] = true } - assert_apply(comp) + config.apply - assert(FileTest.exists?(dsourcefile), "Source file got purged") assert(FileTest.exists?(localfile), "Local file got purged") + assert(FileTest.exists?(dsourcefile), "Source file got purged") assert(! FileTest.exists?(purgee), "File did not get purged") end @@ -1333,7 +1343,7 @@ class TestFile < Test::Unit::TestCase group = Puppet.type(:group).create( :name => "pptestg" ) - comp = newcomp(user, group, home) + comp = mk_configuration(user, group, home) } # Now make sure we get a relationship for each of these @@ -1629,6 +1639,7 @@ class TestFile < Test::Unit::TestCase file = File.join(dir, "file") File.open(file, "w") { |f| f.puts "" } obj = Puppet::Type.newfile :path => dir, :recurse => true, :mode => 0755 + mk_configuration obj assert_equal("/%s" % obj.ref, obj.path) @@ -1739,6 +1750,7 @@ class TestFile < Test::Unit::TestCase File.open(file, "w") { |f| f.puts "yay" } File.chmod(0644, file) obj = Puppet::Type.newfile(:path => dir, :mode => 0750, :recurse => "2") + config = mk_configuration(obj) children = nil assert_nothing_raised("Failure when recursing") do @@ -1747,6 +1759,7 @@ class TestFile < Test::Unit::TestCase assert(obj.class[subdir], "did not create subdir object") children.each do |c| assert_nothing_raised("Failure when recursing on %s" % c) do + c.configuration = config others = c.eval_generate end end @@ -1780,6 +1793,7 @@ class TestFile < Test::Unit::TestCase obj = Puppet::Type.newfile(:path => dir, :ensure => :directory, :recurse => true) + config = mk_configuration(obj) children = nil assert_nothing_raised do children = obj.eval_generate diff --git a/test/ral/types/file/target.rb b/test/ral/types/file/target.rb index 1e62f07ac..c4597cedf 100755 --- a/test/ral/types/file/target.rb +++ b/test/ral/types/file/target.rb @@ -44,6 +44,7 @@ class TestFileTarget < Test::Unit::TestCase def test_linkrecurse dest = tempfile() link = @file.create :path => tempfile(), :recurse => true, :ensure => dest + mk_configuration link ret = nil @@ -317,9 +318,8 @@ class TestFileTarget < Test::Unit::TestCase :source => dirs["source"], :recurse => true ) - - - trans = assert_apply(obj) + config = mk_configuration obj + config.apply newfile = File.join(dirs["target"], "sourcefile") diff --git a/test/ral/types/fileignoresource.rb b/test/ral/types/fileignoresource.rb index fa01aecdc..153946770 100755 --- a/test/ral/types/fileignoresource.rb +++ b/test/ral/types/fileignoresource.rb @@ -73,19 +73,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase ) } - #make a component and adds the file - comp = Puppet.type(:component).create( - :name => "component" - ) - comp.push tofile - - #make, evaluate transaction and sync the component - assert_nothing_raised { - trans = comp.evaluate - } - assert_nothing_raised { - trans.evaluate - } + config = mk_configuration(tofile) + config.apply #topath should exist as a directory with sourcedir as a directory @@ -150,19 +139,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase ) } - #make a component and adds the file - comp = Puppet.type(:component).create( - :name => "component" - ) - comp.push tofile - - #make, evaluate transaction and sync the component - assert_nothing_raised { - trans = comp.evaluate - } - assert_nothing_raised { - trans.evaluate - } + config = mk_configuration(tofile) + config.apply #topath should exist as a directory with sourcedir as a directory @@ -170,6 +148,7 @@ class TestFileIgnoreSources < Test::Unit::TestCase assert(FileTest.exists?(File.join(topath,sourcefile1))) assert(FileTest.exists?(File.join(topath,subdir))) assert(FileTest.exists?(File.join(File.join(topath,subdir),sourcefile1))) + #This file should not assert(!(FileTest.exists?(File.join(topath,sourcefile2)))) assert(!(FileTest.exists?(File.join(topath,subdir2)))) @@ -235,19 +214,8 @@ class TestFileIgnoreSources < Test::Unit::TestCase ) } - #make a component and adds the file - comp = Puppet.type(:component).create( - :name => "component" - ) - comp.push tofile - - #make, evaluate transaction and sync the component - assert_nothing_raised { - trans = comp.evaluate - } - assert_nothing_raised { - trans.evaluate - } + config = mk_configuration(tofile) + config.apply #topath should exist as a directory with sourcedir as a directory @@ -273,5 +241,3 @@ class TestFileIgnoreSources < Test::Unit::TestCase end end - -# $Id$ diff --git a/test/ral/types/filesources.rb b/test/ral/types/filesources.rb index b257fd935..01d9766db 100755 --- a/test/ral/types/filesources.rb +++ b/test/ral/types/filesources.rb @@ -62,6 +62,7 @@ class TestFileSources < Test::Unit::TestCase :name => path ) } + config = mk_configuration(file) child = nil assert_nothing_raised { child = file.newchild("childtest", true) @@ -275,6 +276,7 @@ class TestFileSources < Test::Unit::TestCase # The sourcerecurse method will only ever get called when we're # recursing, so we go ahead and set it. obj = Puppet::Type.newfile :source => source, :path => dest, :recurse => true + config = mk_configuration(obj) result = nil sourced = nil @@ -288,7 +290,7 @@ class TestFileSources < Test::Unit::TestCase assert_equal([dfileobj], result) # Clean this up so it can be recreated - dfileobj.remove + config.remove_resource(dfileobj) # Make sure we correctly iterate over the sources nosource = tempfile() @@ -577,51 +579,6 @@ class TestFileSources < Test::Unit::TestCase } end - def test_networkSourcesWithoutService - server = nil - - Puppet[:autosign] = true - Puppet[:masterport] = 8765 - - serverpid = nil - assert_nothing_raised() { - server = Puppet::Network::Server::WEBrick.new( - :Handlers => { - :CA => {}, # so that certs autogenerate - } - ) - - } - serverpid = fork { - assert_nothing_raised() { - #trap(:INT) { server.shutdown; Kernel.exit! } - trap(:INT) { server.shutdown } - server.start - } - } - @@tmppids << serverpid - - sleep(1) - - name = File.join(tmpdir(), "nosourcefile") - file = Puppet.type(:file).create( - :source => "puppet://localhost/dist/file", - :name => name - ) - - assert_nothing_raised { - file.retrieve - } - - comp = newcomp("nosource", file) - - assert_nothing_raised { - comp.evaluate - } - - assert(!FileTest.exists?(name), "File with no source exists anyway") - end - def test_unmountedNetworkSources server = nil mounts = { @@ -669,11 +626,8 @@ class TestFileSources < Test::Unit::TestCase file.retrieve } - comp = newcomp("nosource", file) - - assert_nothing_raised { - comp.evaluate - } + comp = mk_configuration(file) + comp.apply assert(!FileTest.exists?(name), "File with no source exists anyway") end @@ -722,7 +676,7 @@ class TestFileSources < Test::Unit::TestCase ) } - comp = newcomp(file) + comp = mk_configuration(file) assert_events([:file_created], comp) assert(File.exists?(to), "File does not exist") @@ -808,9 +762,8 @@ class TestFileSources < Test::Unit::TestCase trans = nil assert_nothing_raised { file[:links] = :manage - comp = newcomp(file) - trans = comp.evaluate - trans.evaluate + comp = mk_configuration(file) + trans = comp.apply } assert(trans.failed?(file), "Object did not fail to copy links") diff --git a/test/ral/types/group.rb b/test/ral/types/group.rb index 9870d533a..5189c63a1 100755 --- a/test/ral/types/group.rb +++ b/test/ral/types/group.rb @@ -65,7 +65,7 @@ class TestGroup < Test::Unit::TestCase def attrtest_ensure(group) group[:ensure] = :absent - comp = newcomp("ensuretest", group) + comp = mk_configuration("ensuretest", group) assert_apply(comp) assert_equal(:absent, group.provider.ensure, "Group is still present") group[:ensure] = :present @@ -91,7 +91,7 @@ class TestGroup < Test::Unit::TestCase assert_equal(15, group.should(:gid), "Did not convert gid to number") - comp = newcomp(group) + comp = mk_configuration(group) trans = assert_events([:group_modified], comp, "group") assert_equal(15, group.provider.gid, "GID was not changed") diff --git a/test/ral/types/tidy.rb b/test/ral/types/tidy.rb index b8d576b9a..8fada1adb 100755 --- a/test/ral/types/tidy.rb +++ b/test/ral/types/tidy.rb @@ -55,7 +55,7 @@ class TestTidy < Test::Unit::TestCase assert_nothing_raised { link = newlink(:target => source, :recurse => true) } - comp = newcomp("linktest",link) + comp = mk_configuration("linktest",link) cycle(comp) path = link.name diff --git a/test/ral/types/user.rb b/test/ral/types/user.rb index 121ac9cf0..9b24cc74a 100755 --- a/test/ral/types/user.rb +++ b/test/ral/types/user.rb @@ -82,7 +82,7 @@ class TestUser < Test::Unit::TestCase old = user.provider.ensure user[:ensure] = :absent - comp = newcomp("ensuretest", user) + comp = mk_configuration("ensuretest", user) assert_apply(user) assert(!user.provider.exists?, "User is still present") user[:ensure] = :present @@ -102,7 +102,7 @@ class TestUser < Test::Unit::TestCase old = user.provider.comment user[:comment] = "A different comment" - comp = newcomp("commenttest", user) + comp = mk_configuration("commenttest", user) trans = assert_events([:user_changed], comp, "user") @@ -117,7 +117,7 @@ class TestUser < Test::Unit::TestCase def attrtest_home(user) obj = nil - comp = newcomp("hometest", user) + comp = mk_configuration("hometest", user) old = user.provider.home user[:home] = old @@ -137,7 +137,7 @@ class TestUser < Test::Unit::TestCase def attrtest_shell(user) old = user.provider.shell - comp = newcomp("shelltest", user) + comp = mk_configuration("shelltest", user) user[:shell] = old @@ -167,7 +167,7 @@ class TestUser < Test::Unit::TestCase def attrtest_gid(user) obj = nil old = user.provider.gid - comp = newcomp("gidtest", user) + comp = mk_configuration("gidtest", user) user.retrieve @@ -216,7 +216,7 @@ class TestUser < Test::Unit::TestCase def attrtest_uid(user) obj = nil - comp = newcomp("uidtest", user) + comp = mk_configuration("uidtest", user) user.provider.uid = 1 @@ -387,7 +387,7 @@ class TestUser < Test::Unit::TestCase ogroup = Puppet.type(:group).create( :name => "yayness" ) - comp = newcomp(user, group, home, ogroup) + comp = mk_configuration(user, group, home, ogroup) } rels = nil @@ -404,7 +404,7 @@ class TestUser < Test::Unit::TestCase user = mkuser(name) - comp = newcomp("usercomp", user) + comp = mk_configuration("usercomp", user) trans = assert_events([:user_created], comp, "user") @@ -424,7 +424,7 @@ class TestUser < Test::Unit::TestCase assert(! user.provider.exists?, "User %s is present" % name) - comp = newcomp("usercomp", user) + comp = mk_configuration("usercomp", user) trans = assert_events([:user_created], comp, "user") diff --git a/test/util/config.rb b/test/util/config.rb index f99ad54b4..cbd02b4f9 100755 --- a/test/util/config.rb +++ b/test/util/config.rb @@ -59,57 +59,6 @@ class TestConfig < Test::Unit::TestCase } end - # #795 - when --config=relative, we want to fully expand file paths. - def test_relative_paths_when_to_transportable - config = mkconfig - config.setdefaults :yay, :transtest => ["/what/ever", "yo"] - file = config.element(:transtest) - - # Now override it with a relative path name - config[:transtest] = "here" - - should = File.join(Dir.getwd, "here") - - object = file.to_transportable[0] - assert_equal(should, object.name, "Did not translate relative pathnames to full path names") - end - - def test_to_manifest - set_configs - manifest = nil - assert_nothing_raised("Could not convert to a manifest") { - manifest = @config.to_manifest - } - - Puppet[:parseonly] = true - - interp = nil - assert_nothing_raised do - interp = mkinterp :Code => manifest, :UseNodes => false - end - - trans = nil - node = Puppet::Node.new("node") - assert_nothing_raised do - trans = interp.compile(node) - end - assert_nothing_raised("Could not instantiate objects") { - trans.extract.to_type - } - end - - def test_to_comp - set_configs - comp = nil - assert_nothing_raised("Could not convert to a component") { - comp = @config.to_component - } - - assert_nothing_raised("Could not retrieve component") { - comp.retrieve - } - end - def test_to_config set_configs @@ -668,91 +617,6 @@ yay = /a/path assert_equal("/my/file", @config[:b], "Values are not equal") end - def test_reuse - c = mkconfig - - file = tempfile() - section = "testing" - assert_nothing_raised { - @config.setdefaults(section, - :myfile => {:default => file, :create => true, :desc => "yay"} - ) - } - - assert_nothing_raised("Could not use a section") { - @config.use(section) - } - - assert(FileTest.exists?(file), "Did not create file") - - assert(! Puppet::Type.type(:file)[file], "File obj still exists") - - File.unlink(file) - - @config.reuse - assert(FileTest.exists?(file), "Did not create file") - end - - def test_mkusers - c = mkconfig - - file = tempfile() - section = "testing" - assert_nothing_raised { - @config.setdefaults(section, - :mkusers => [false, "yay"], - :myfile => { - :default => file, - :owner => "pptest", - :group => "pptest", - :desc => "yay", - :create => true - } - ) - } - - comp = nil - assert_nothing_raised { - comp = @config.to_component - } - - [:user, :group].each do |type| - # The objects might get created internally by Puppet::Util; just - # make sure they're not being managed - if obj = Puppet.type(type)["pptest"] - assert(! obj.managed?, "%s objectis managed" % type) - end - end - comp.each { |o| o.remove } - - @config[:mkusers] = true - - assert_nothing_raised { - @config.to_component - } - - user = Puppet.type(:user)["pptest"] - assert(user, "User object did not get created") - assert(user.managed?, "User object is not managed.") - assert(user.should(:comment), "user does not have a comment set") - - group = Puppet.type(:group)["pptest"] - assert(group, "Group object did not get created") - assert(group.managed?, - "Group object is not managed." - ) - - if Process.uid == 0 - cleanup do - user[:ensure] = :absent - group[:ensure] = :absent - assert_apply(user, group) - end - - assert_apply(user, group) - end - end - def test_notmanagingdev c = mkconfig path = "/dev/testing" @@ -764,11 +628,9 @@ yay = /a/path } ) - assert_nothing_raised { - @config.to_component - } + config = @config.to_configuration - assert(! Puppet.type(:file)["/dev/testing"], "Created dev file") + assert(! config.resource(:file, "/dev/testing"), "Created dev file") end def test_groupsetting @@ -1119,12 +981,12 @@ yay = /a/path # Now enable it so they'll be added config[:mkusers] = true - comp = config.to_component + comp = config.to_configuration - Puppet::Type.type(:user).each do |u| + comp.vertices.find_all { |r| r.class.name == :user }.each do |u| assert(u.name != "root", "Tried to manage root user") end - Puppet::Type.type(:group).each do |u| + comp.vertices.find_all { |r| r.class.name == :group }.each do |u| assert(u.name != "root", "Tried to manage root group") assert(u.name != "wheel", "Tried to manage wheel group") end diff --git a/test/util/fact_store.rb b/test/util/fact_store.rb deleted file mode 100755 index 5b04d1374..000000000 --- a/test/util/fact_store.rb +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke Kanies on 2007-05-02. -# Copyright (c) 2007. All rights reserved. - -$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ - -require 'puppettest' -require 'puppet/util/fact_store' - -class TestFactStore < Test::Unit::TestCase - include PuppetTest - - def test_new_fact_store - klass = nil - assert_nothing_raised("Could not create fact store") do - klass = Puppet::Util::FactStore.newstore(:yay) do - end - end - - assert_equal(klass, Puppet::Util::FactStore.store(:yay), "Did not get created store back by name") - end - - def test_yaml_store - yaml = Puppet::Util::FactStore.store(:yaml) - assert(yaml, "Could not retrieve yaml store") - - name = "node" - facts = {"a" => :b, :c => "d", :e => :f, "g" => "h"} - - store = nil - assert_nothing_raised("Could not create YAML store instance") do - store = yaml.new - end - - assert_nothing_raised("Could not store host facts") do - store.set(name, facts) - end - - dir = Puppet[:yamlfactdir] - - file = File.join(dir, name + ".yaml") - assert(FileTest.exists?(file), "Did not create yaml file for node") - - text = File.read(file) - newfacts = nil - assert_nothing_raised("Could not deserialize yaml") do - newfacts = YAML::load(text) - end - - # Don't directly compare the hashes, because there might be extra - # data stored in the client hash - facts.each do |var, value| - assert_equal(value, newfacts[var], "Value for %s changed during storage" % var) - end - - # Now make sure the facts get retrieved correctly - assert_nothing_raised("Could not retrieve facts") do - newfacts = store.get(name) - end - - # Now make sure the hashes are equal, since internal facts should not be returned. - assert_equal(facts, newfacts, "Retrieved facts are not equal") - end -end - -# $Id$ diff --git a/test/util/graph.rb b/test/util/graph.rb deleted file mode 100755 index 875fd0ec3..000000000 --- a/test/util/graph.rb +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke Kanies on 2006-11-16. -# Copyright (c) 2006. All rights reserved. - -$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ - -require 'puppettest' -require 'puppettest/graph' -require 'puppet/util/graph' - -class TestUtilGraph < Test::Unit::TestCase - include PuppetTest - include PuppetTest::Graph - - def test_to_graph - children = %w{a b c d} - list = Container.new("yay", children) - - graph = nil - assert_nothing_raised do - graph = list.to_graph - end - - assert(graph.vertices.include?(list), "wtf?") - - ([list] + children).each do |thing| - assert(graph.vertex?(thing), "%s is not a vertex" % thing) - end - children.each do |child| - assert(graph.edge?(list, child), - "%s/%s was not added as an edge" % ["yay", child]) - end - end - - def test_recursive_to_graph - one, two, three, middle, top = build_tree - - graph = nil - assert_nothing_raised do - graph = top.to_graph - end - - (%w{a b c d e f g h} + [one, two, middle, top]).each do |v| - assert(graph.vertex?(v), "%s is not a vertex" % v) - end - - [one, two, middle, top].each do |con| - con.each do |child| - assert(graph.edge?(con, child), "%s/%s is not an edge" % [con, child]) - end - end - - # Now make sure we correctly retrieve the leaves from each container - {top => %w{a b c d e f g h i j}, - one => %w{a b}, - two => %w{c d}, - three => %w{i j}, - middle => %w{c d e f}}.each do |cont, list| - leaves = nil - assert_nothing_raised do - leaves = graph.leaves(cont) - end - leaves = leaves.sort - assert_equal(list.sort, leaves.sort, - "Got incorrect leaf list for %s" % cont.name) - %w{a b c d e f g h}.each do |letter| - unless list.include?(letter) - assert(!leaves.include?(letter), - "incorrectly got %s as a leaf of %s" % - [letter, cont.to_s]) - end - end - end - end - - def test_to_graph_with_block - middle = Container.new "middle", ["c", "d", 3, 4] - top = Container.new "top", ["a", "b", middle, 1, 2] - - graph = nil - assert_nothing_raised() { - graph = top.to_graph { |c| c.is_a?(String) or c.is_a?(Container) } - } - - %w{a b c d}.each do |child| - assert(graph.vertex?(child), "%s was not added as a vertex" % child) - end - - [1, 2, 3, 4].each do |child| - assert(! graph.vertex?(child), "%s is a vertex" % child) - end - end - - def test_cyclic_graphs - one = Container.new "one", %w{a b} - two = Container.new "two", %w{c d} - - one.push(two) - two.push(one) - - assert_raise(Puppet::Error, "did not fail on cyclic graph") do - one.to_graph - end - end -end - -# $Id$ |
