summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2005-10-01 19:57:07 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2005-10-01 19:57:07 +0000
commit0d6241ca97ded8e003338c6cf316e280530ea8ee (patch)
treed66e60c1a77eacf0a894d0976f6c9f5216104c90
parenta96bdac66ba703736afa7155f4d31cbe3e9fc0ef (diff)
downloadpuppet-0d6241ca97ded8e003338c6cf316e280530ea8ee.tar.gz
puppet-0d6241ca97ded8e003338c6cf316e280530ea8ee.tar.xz
puppet-0d6241ca97ded8e003338c6cf316e280530ea8ee.zip
switching all relationships to be centrally maintained and to use symbolic references, rather than literal ones; also going through and making all tests pass again after mucking with services
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@710 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/event.rb240
-rw-r--r--lib/puppet/transaction.rb7
-rw-r--r--lib/puppet/type.rb308
-rw-r--r--lib/puppet/type/pfile.rb106
-rw-r--r--lib/puppet/type/service.rb64
-rwxr-xr-xlib/puppet/type/service/smf.rb105
-rwxr-xr-xlib/puppet/type/symlink.rb2
-rwxr-xr-xtest/other/tc_events.rb18
-rwxr-xr-xtest/other/tc_relationships.rb120
-rw-r--r--test/other/tc_transactions.rb1
-rw-r--r--test/server/tc_bucket.rb2
-rw-r--r--test/types/tc_basic.rb3
-rw-r--r--test/types/tc_file.rb114
-rw-r--r--test/types/tc_query.rb3
-rw-r--r--test/types/tc_service.rb18
15 files changed, 667 insertions, 444 deletions
diff --git a/lib/puppet/event.rb b/lib/puppet/event.rb
index d01863de2..e2c364194 100644
--- a/lib/puppet/event.rb
+++ b/lib/puppet/event.rb
@@ -1,8 +1,3 @@
-#!/usr/local/bin/ruby -w
-
-# $Id$
-
-# included so we can test object types
require 'puppet'
require 'puppet/type'
@@ -12,33 +7,183 @@ module Puppet
# eventually, these will be passed on to some central event system
class Event
include Puppet
+
# subscriptions are permanent associations determining how different
# objects react to an event
class Subscription
include Puppet
- attr_accessor :source, :event, :target
+ attr_accessor :event, :callback
- def initialize(hash)
- @triggered = false
+ # Remove the existing subscriptions and such
+ def self.clear
+ self.init
+ end
+
+ # Remove a subscription
+ def self.delete(sub)
+ type, name = sub.targetarray
+ if @dependencies[type][name].include?(sub)
+ @dependencies[type][name].delete(sub)
+ end
+
+ type, name = sub.sourcearray
+ if @subscriptions[type][name].include?(sub)
+ @subscriptions[type][name].delete(sub)
+ end
+ end
+
+ # Initialize our class variables. This is in a method so it can
+ # be called to clear the variables, too.
+ def self.init
+ # A hash of subscriptions and another of dependencies, organized by
+ # type, then by name. I'm storing them all here, so that I don't
+ # have to store the subscriptions with the individual objects,
+ # which makes creating and destroying objects as necessary much
+ # easier.
+ @subscriptions = Hash.new { |hash, key|
+ hash[key] = Hash.new { |shash, skey|
+ # Each object has an array of subscriptions
+ shash[skey] = []
+ }
+ }
+
+ @dependencies = Hash.new { |hash, key|
+ hash[key] = Hash.new { |shash, skey|
+ # Each object has an array of subscriptions
+ shash[skey] = []
+ }
+ }
+ end
+
+ self.init
+ # Store the new subscription in a central hash.
+ def self.newsub(sub)
+ # The dependencies map allows me to look up a subscription by
+ # target -- find out which objects a given object is subscribed
+ # to, and thus find out which objects that given object depends
+ # upon.
+ # DEPENDENCIES == TARGET
+ ttype, tname = sub.targetarray
+ @dependencies[ttype][tname] << sub
+
+ # Subscriptions are the list of subscriptions for a given object,
+ # i.e., the list of all objects that care about a given object's
+ # events.
+ # SUBSCRIPTION == SOURCE
+ stype, sname = sub.sourcearray
+ @subscriptions[stype][sname] << sub
+ end
+
+ # Trigger the subscriptions related to an event, and then pass it up
+ # as appropriate
+ def self.trigger(source, event, transaction)
+ type, name = self.split(source)
+
+ @subscriptions[type][name].each { |sub|
+ if sub.match?(event)
+ sub.trigger(transaction)
+ end
+ }
+ end
+
+ # Look up an object by type and name. This is used because we
+ # store symbolic links in our subscription hash rather than storing
+ # actual object references.
+ def self.retrieve(ary)
+ type, name = ary
+ typeobj = Puppet::Type.type(type)
+
+ unless typeobj
+ return nil
+ end
+
+ obj = typeobj[name]
+ return obj
+ end
+
+ # Split an object into its type and name
+ def self.split(object)
+ return [object.class.name, object.name]
+ end
+
+ # Retrieve all of the subscriptions that result in a dependency.
+ # We return the whole dependency here, because it is being returned
+ # to the object that made the subscription.
+ def self.dependencies(target)
+ type, name = self.split(target)
+ return @dependencies[type][name]
+ end
+
+ # Return all objects that are subscribed to us. We are only willing
+ # to return the object, not the subscription object, because the
+ # source shouldn't need to know things like the event or method that
+ # we're subscribed to.
+ def self.subscribers(source)
+ type, name = self.split(source)
+ return @subscriptions[type][name].collect { |sub|
+ sub.target
+ }
+ end
+
+ # The hash here must include the target and source objects, the event,
+ # and the callback to call.
+ def initialize(hash)
hash.each { |param,value|
# assign each value appropriately
# this is probably wicked-slow
self.send(param.to_s + "=",value)
}
+
+ self.class.newsub(self)
#Puppet.debug "New Subscription: '%s' => '%s'" %
# [@source,@event]
end
- # the transaction is passed in so that we can notify it if
- # something fails
+ # Determine whether the passed event matches our event
+ def match?(event)
+ if event == :NONE or @event == :NONE
+ return false
+ elsif @event == :ALL_EVENTS or event == :ALL_EVENTS or event == @event
+ return true
+ else
+ return false
+ end
+ end
+
+ # The source is the event source.
+ def source=(object)
+ type, name = self.class.split(object)
+ @source = [type, name]
+ end
+
+ def source
+ self.class.retrieve(@source)
+ end
+
+ def sourcearray
+ @source
+ end
+
+ # The target is the object who will receive the callbacks, i.e.,
+ # a source generates an event, which results in a callback on the
+ # target.
+ def target=(object)
+ type, name = self.class.split(object)
+ @target = [type, name]
+ end
+
+ def target
+ self.class.retrieve(@target)
+ end
+
+ def targetarray
+ @target
+ end
+
+ # Trigger a subscription, which basically calls the associated method
+ # on the target object.
def trigger(transaction)
- # this is potentially incomplete, because refreshing an object
- # could theoretically kick off an event, which would not get run
- # or, because we're executing the first subscription rather than
- # the last, a later-refreshed object could somehow be connected
- # to the "old" object rather than "new"
- # but we're pretty far from that being a problem
event = nil
if @event == :NONE
@@ -46,30 +191,35 @@ module Puppet
return
end
- if transaction.triggercount(self) > 0
+ if transaction.triggered?(self.target, @callback) > 0
Puppet.debug "%s has already run" % self
else
- Puppet.debug "'%s' matched '%s'; triggering '%s' on '%s'" %
- [@source,@event,@method,@target]
+ # We need to call the method, so that it gets retrieved
+ # as a real object.
+ target = self.target
+ #Puppet.debug "'%s' matched '%s'; triggering '%s' on '%s'" %
+ # [@source,@event,@method,target]
begin
- if @target.respond_to?(@method)
- event = @target.send(@method)
+ if target.respond_to?(@callback)
+ event = target.send(@callback)
else
- Puppet.debug "'%s' of type '%s' does not respond to '%s'" %
- [@target,@target.class,@method.inspect]
+ Puppet.debug(
+ "'%s' of type '%s' does not respond to '%s'" %
+ [target,target.class,@callback.inspect]
+ )
end
rescue => detail
- # um, what the heck do i do when an object fails to refresh?
- # shouldn't that result in the transaction rolling back?
- # the 'onerror' metaparam will be used to determine
- # behaviour in that case
+ # um, what the heck do i do when an object fails to
+ # refresh? shouldn't that result in the transaction
+ # rolling back? the 'onerror' metaparam will be used
+ # to determine behaviour in that case
Puppet.err "'%s' failed to %s: '%s'" %
- [@target,@method,detail]
+ [target,@callback,detail]
raise
#raise "We need to roll '%s' transaction back" %
#transaction
end
- transaction.triggered(self)
+ transaction.triggered(target, @callback)
end
return event
end
@@ -81,36 +231,6 @@ module Puppet
@@subscriptions = []
- # I think this method is obsolete
- def self.process
- Puppet.debug "Processing events"
- @@events.each { |event|
- @@subscriptions.find_all { |sub|
- #debug "Sub source: '%s'; event object: '%s'" %
- # [sub.source.inspect,event.object.inspect]
- sub.source == event.object and
- (sub.event == event.event or
- sub.event == :ALL_EVENTS)
- }.each { |sub|
- Puppet.debug "Found subscription to %s" % event
- sub.trigger(event.transaction)
- }
- }
-
- @@events.clear
- end
-
- # I think this method is obsolete
- def self.subscribe(hash)
- if hash[:event] == '*'
- hash[:event] = :ALL_EVENTS
- end
- sub = Subscription.new(hash)
-
- # add to the correct area
- @@subscriptions.push sub
- end
-
def initialize(args)
unless args.include?(:event) and args.include?(:source)
raise Puppet::DevError, "Event.new called incorrectly"
@@ -136,4 +256,4 @@ module Puppet
end
end
-
+# $Id$
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 59e106902..a39ec55d1 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -85,7 +85,8 @@ class Transaction
#@triggerevents = []
events.each { |event|
object = event.source
- object.propagate(event)
+ #Puppet::Event::Subscriptions.propagate(object, event, self)
+ object.propagate(event, self)
}
#events += @triggerevents
@@ -157,7 +158,7 @@ class Transaction
#@triggerevents = []
events.each { |event|
object = event.source
- object.propagate(event)
+ object.propagate(event, self)
}
#events += @triggerevents
@@ -166,6 +167,7 @@ class Transaction
#---------------------------------------------------------------
def triggered(object, method)
+ Puppet.notice "Triggered %s" % method
@triggered[object][method] += 1
#@triggerevents << ("%s_%sed" % [object.class.name.to_s, method.to_s]).intern
end
@@ -173,6 +175,7 @@ class Transaction
#---------------------------------------------------------------
def triggered?(object, method)
+ Puppet.notice "Looking for triggered %s" % method
@triggered[object][method]
end
#---------------------------------------------------------------
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 79a8fb572..421cdf6ca 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -1,41 +1,19 @@
-#!/usr/local/bin/ruby -w
-
-# $Id$
+# This class is the abstract base class for the mechanism for organizing
+# work. No work is actually done by this class or its subclasses; rather,
+# the subclasses include states which do the actual work.
+# See state.rb for how work is actually done.
-# included so we can test object types
require 'puppet'
require 'puppet/log'
require 'puppet/element'
require 'puppet/event'
require 'puppet/metric'
require 'puppet/type/state'
-
-
# see the bottom of the file for the rest of the inclusions
-#---------------------------------------------------------------
-# This class is the abstract base class for the mechanism for organizing
-# work. No work is actually done by this class or its subclasses; rather,
-# the subclasses include states which do the actual work.
-# See state.rb for how work is actually done.
-
-# our duck type interface -- if your object doesn't match this interface,
-# it won't work
-
-# all of our first-class objects (objects, states, and components) will
-# respond to these methods
-# although states don't inherit from Puppet::Type
-# although maybe Puppet::State should...
-
-# the default behaviour that this class provides is to just call a given
-# method on each contained object, e.g., in calling 'sync', we just run:
-# object.each { |subobj| subobj.sync() }
-
-# to use this interface, just define an 'each' method and 'include Puppet::Type'
-
module Puppet
class Type < Puppet::Element
- attr_accessor :children, :parameters, :parent
+ attr_accessor :children, :parameters, :parent, :implicit
attr_accessor :file, :line
include Enumerable
@@ -102,15 +80,10 @@ class Type < Puppet::Element
@@metaparamdoc[:loglevel] = "Sets the level that information will be logged:
debug, info, verbose, notice, warning, err, alert, emerg or crit"
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# class methods dealing with Type management
- #---------------------------------------------------------------
- #---------------------------------------------------------------
public
- #---------------------------------------------------------------
# these objects are used for mapping type names (e.g., 'file')
# to actual object classes; because Type.inherited is
# called before the <subclass>.name method is defined, we need
@@ -133,7 +106,6 @@ class Type < Puppet::Element
attr_reader :name, :namevar, :states, :validstates, :parameters
end
- #---------------------------------------------------------------
# Create @@typehash from @@typeary. This is meant to be run
# multiple times -- whenever it is discovered that the two
# objects have differents lengths.
@@ -149,16 +121,12 @@ class Type < Puppet::Element
end
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# iterate across all of the subclasses of Type
def self.eachtype
@@typeary.each { |type| yield type }
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# The work that gets done for every subclass of Type
# this is an implicit method called by Ruby for us
def self.inherited(sub)
@@ -171,9 +139,7 @@ class Type < Puppet::Element
# get executed, which, um, sucks
@@typeary.push(sub)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# all of the variables that must be initialized for each subclass
def self.initvars
# all of the instances of this class
@@ -201,9 +167,7 @@ class Type < Puppet::Element
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return a Type instance by name
def self.type(type)
unless @@typeary.length == @@typehash.length
@@ -213,18 +177,11 @@ class Type < Puppet::Element
end
@@typehash[type]
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# class methods dealing with type instance management
- #---------------------------------------------------------------
- #---------------------------------------------------------------
public
- #---------------------------------------------------------------
# retrieve a named instance of the current type
def self.[](name)
if @objects.has_key?(name)
@@ -233,9 +190,7 @@ class Type < Puppet::Element
return nil
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# add an instance by name to the class list of instances
def self.[]=(name,object)
newobj = nil
@@ -260,28 +215,23 @@ class Type < Puppet::Element
# and then add it to the master list
Puppet::Type.push(object)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# remove all type instances; this is mostly only useful for testing
def self.allclear
@@allobjects.clear
+ Puppet::Event::Subscription.clear
@@typeary.each { |subtype|
subtype.clear
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# remove all of the instances of a single type
def self.clear
if defined? @objects
@objects.clear
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# remove a specified object
def self.delete(object)
if @@allobjects.include?(object)
@@ -292,9 +242,7 @@ class Type < Puppet::Element
@objects.delete(object.name)
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# iterate across each of the type's instances
def self.each
return unless defined? @objects
@@ -302,14 +250,11 @@ class Type < Puppet::Element
yield instance
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# does the type have an object with the given name?
def self.has_key?(name)
return @objects.has_key?(name)
end
- #---------------------------------------------------------------
# Allow an outside party to specify the 'is' value for a state. The
# arguments are an array because you can't use parens with 'is=' calls.
@@ -329,7 +274,6 @@ class Type < Puppet::Element
end
end
- #---------------------------------------------------------------
# add an object to the master list of Type instances
# I'm pretty sure this is currently basically unused
def self.push(object)
@@ -337,18 +281,11 @@ class Type < Puppet::Element
#debug("adding %s of type %s to master list" %
# [object.name,object.class])
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# class and instance methods dealing with parameters and states
- #---------------------------------------------------------------
- #---------------------------------------------------------------
public
- #---------------------------------------------------------------
# build a per-Type hash, mapping the states to their names
def self.buildstatehash
unless defined? @validstates
@@ -368,9 +305,7 @@ class Type < Puppet::Element
end
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# set the parameters for a type; probably only used by FileRecord
# objects
def self.parameters=(params)
@@ -383,9 +318,7 @@ class Type < Puppet::Element
end
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# does the name reflect a valid state?
def self.validstate?(name)
unless @validstates.length == @states.length
@@ -397,9 +330,7 @@ class Type < Puppet::Element
return false
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# does the name reflect a valid parameter?
def self.validparameter?(name)
unless defined? @parameters
@@ -411,9 +342,7 @@ class Type < Puppet::Element
return false
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def self.validarg?(name)
if name.is_a?(String)
name = name.intern
@@ -424,9 +353,7 @@ class Type < Puppet::Element
return false
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# abstract accessing parameters and states, and normalize
# access to always be symbols, not strings
# XXX this returns a _value_, not an object
@@ -455,9 +382,7 @@ class Type < Puppet::Element
raise TypeError.new("Invalid parameter %s" % [name])
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# abstract setting parameters and states, and normalize
# access to always be symbols, not strings
def []=(name,value)
@@ -499,9 +424,7 @@ class Type < Puppet::Element
raise Puppet::Error, "Invalid parameter %s" % [name]
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# remove a state from the object; useful in testing or in cleanup
# when an error has been encountered
def delete(attr)
@@ -511,25 +434,21 @@ class Type < Puppet::Element
raise Puppet::DevError.new("Undefined state '#{attr}' in #{self}")
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# remove a state from the object; useful in testing or in cleanup
# when an error has been encountered
def destroy
self.class.delete(self)
- @dependencies.each { |dep|
- dep.unsubscribe(self)
+ Puppet::Event::Subscription.dependencies(self).each { |dep|
+ self.unsubscribe(dep)
}
if defined? @parent and @parent
@parent.delete(self)
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# iterate across all children, and then iterate across states
# we do children first so we're sure that all dependent objects
# are checked first
@@ -553,9 +472,7 @@ class Type < Puppet::Element
}
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# iterate across the existing states
def eachstate
# states() is a private method
@@ -563,9 +480,7 @@ class Type < Puppet::Element
yield state
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# retrieve the 'is' value for a specified state
def is(state)
if @states.include?(state)
@@ -574,9 +489,7 @@ class Type < Puppet::Element
return nil
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# retrieve the 'should' value for a specified state
def should(state)
if @states.include?(state)
@@ -585,16 +498,12 @@ class Type < Puppet::Element
return nil
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# create a log at specified level
def log(msg)
Puppet::Log.create(@metaparams[:loglevel],msg)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# is the instance a managed instance? A 'yes' here means that
# the instance was created from the language, vs. being created
# in order resolve other questions, such as finding a package
@@ -612,9 +521,7 @@ class Type < Puppet::Element
return @managed
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# create a new state
def newstate(name, hash = {})
if stateklass = self.class.validstate?(name)
@@ -651,9 +558,7 @@ class Type < Puppet::Element
raise Puppet::Error, "Invalid parameter %s" % name
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return the value of a parameter
def parameter(name)
unless name.is_a? Symbol
@@ -661,9 +566,7 @@ class Type < Puppet::Element
end
return @parameters[name]
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def push(*childs)
unless defined? @children
@children = []
@@ -673,9 +576,7 @@ class Type < Puppet::Element
child.parent = self
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return an actual type by name; to return the value, use 'inst[name]'
# FIXME this method should go away
def state(name)
@@ -684,11 +585,9 @@ class Type < Puppet::Element
end
return @states[name]
end
- #---------------------------------------------------------------
private
- #---------------------------------------------------------------
def states
#debug "%s has %s states" % [self,@states.length]
tmpstates = []
@@ -702,27 +601,29 @@ class Type < Puppet::Element
end
return tmpstates
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# instance methods related to instance intrinsics
# e.g., initialize() and name()
- #---------------------------------------------------------------
- #---------------------------------------------------------------
public
- #---------------------------------------------------------------
# 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.
def self.create(hash)
+ # Handle this new object being implicit
+ implicit = hash[:implicit] || false
+ if hash.include?(:implicit)
+ hash.delete(:implicit)
+ end
+
if name = hash["name"] || hash[:name] ||
hash[self.namevar] || hash[self.namevar.to_s]
# if the object already exists
if retobj = self[name]
+ # if only one of our objects is implicit, then it's easy to see
+ # who wins -- the non-implicit one.
# merge the new data
retobj.merge(hash)
@@ -753,22 +654,27 @@ class Type < Puppet::Element
self.to_s
end
end
- #---------------------------------------------------------------
+
+ def self.implicitcreate(hash)
+ unless hash.include?(:implicit)
+ hash[:implicit] = true
+ end
+ obj = self.create(hash)
+ obj.implicit = true
+
+ return obj
+ end
# and then make 'new' private
class << self
private :new
end
- #---------------------------------------------------------------
# initialize the type instance
def initialize(hash)
@children = []
@evalcount = 0
- @subscriptions = []
- @dependencies = []
-
# callbacks are per object and event
@callbacks = Hash.new { |chash, key|
chash[key] = {}
@@ -855,9 +761,7 @@ class Type < Puppet::Element
#puts caller
self.class[self.name] = self
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# merge new information with an existing object, checking for conflicts
# and such
def merge(hash)
@@ -877,9 +781,7 @@ class Type < Puppet::Element
end
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# derive the instance name based on class.namevar
def name
unless defined? @name and @name
@@ -901,9 +803,7 @@ class Type < Puppet::Element
return @name
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# fix any namevar => param translations
def argclean(hash)
# we have to set the name of our object before anything else,
@@ -935,9 +835,7 @@ class Type < Puppet::Element
return hash
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return the full path to us, for logging and rollback
# some classes (e.g., FileTypeRecords) will have to override this
def path
@@ -947,9 +845,7 @@ class Type < Puppet::Element
return [self.name]
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# retrieve the current value of all contained states
def retrieve
# it's important to use the method here, as it follows the order
@@ -958,9 +854,7 @@ class Type < Puppet::Element
state.retrieve
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# sync the changes to disk, and return the events generated by the changes
# FIXME this method is essentially obviated, but it's still used by tests
# and i don't feel like fixing it yet
@@ -977,24 +871,16 @@ class Type < Puppet::Element
Puppet::Metric.addevents(self.class,self,events)
return events
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# convert to a string
def to_s
self.name
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# instance methods dealing with actually doing work
- #---------------------------------------------------------------
- #---------------------------------------------------------------
public
- #---------------------------------------------------------------
# this is a retarded hack method to get around the difference between
# component children and file children
def self.depthfirst?
@@ -1004,9 +890,7 @@ class Type < Puppet::Element
return false
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# this method is responsible for collecting state changes
# we always descend into the children before we evaluate our current
# states
@@ -1094,9 +978,7 @@ class Type < Puppet::Element
end
return changes.flatten
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# if all contained objects are in sync, then we're in sync
# FIXME I don't think this is used on the type instances any more
def insync?
@@ -1112,24 +994,16 @@ class Type < Puppet::Element
#Puppet.debug("%s sync status is %s" % [self,insync])
return insync
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# Meta-parameter methods: These methods deal with the results
# of specifying metaparameters
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def self.eachmetaparam
@@metaparams.each { |param|
yield param
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# This just marks states that we definitely want to retrieve values
# on. There is currently no way to uncheck a parameter.
def metacheck=(args)
@@ -1149,34 +1023,26 @@ class Type < Puppet::Element
self.newstate(state)
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# Is the parameter in question a meta-parameter?
def self.metaparam?(param)
@@metaparams.include?(param)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# for each object we require, subscribe to all events that it
# generates
# we might reduce the level of subscription eventually, but for now...
def metarequire=(requires)
self.handledepends(requires, :NONE, nil)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# for each object we require, subscribe to all events that it
# generates
# we might reduce the level of subscription eventually, but for now...
def metasubscribe=(requires)
self.handledepends(requires, :ALL_EVENTS, :refresh)
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def metanoop=(noop)
if noop == "true" or noop == true
@noop = true
@@ -1186,20 +1052,15 @@ class Type < Puppet::Element
raise Puppet::Error.new("Invalid noop value '%s'" % noop)
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def metaonerror=(response)
Puppet.debug("Would have called metaonerror")
@onerror = response
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def metaschedule=(schedule)
@schedule = schedule
end
- #---------------------------------------------------------------
def metaloglevel=(loglevel)
if loglevel.is_a?(String)
loglevel.intern
@@ -1214,42 +1075,31 @@ class Type < Puppet::Element
raise Puppet::Error.new("Invalid loglevel '%s%'" % loglevel)
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# Subscription and relationship methods
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- def addcallback(object, event, method)
- @callbacks[object][event] = method
- end
- #---------------------------------------------------------------
+ #def addcallback(object, event, method)
+ # @callbacks[object][event] = method
+ #end
- #---------------------------------------------------------------
# return all objects subscribed to the current object
def eachdependency
- @dependencies.each { |dep|
- yield dep
+ Puppet::Event::Subscription.dependencies(self).each { |dep|
+ yield dep.source
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return all objects subscribed to the current object
- def eachsubscriber
- @subscriptions.each { |sub|
- yield sub.target
- }
- end
- #---------------------------------------------------------------
+ #def eachsubscriber
+ # Puppet::Event::Subscriptions.subscribers?(self).each { |sub|
+ # yield sub.targetobject
+ # }
+ #end
- #---------------------------------------------------------------
def handledepends(requires, event, method)
- # FIXME this should probably test whether requires[0] is an array
- unless requires.is_a?(Array)
+ # Requires are specified in the form of [type, name], so they're always
+ # an array. But we want them to be an array of arrays.
+ unless requires[0].is_a?(Array)
requires = [requires]
end
requires.each { |rname|
@@ -1268,77 +1118,72 @@ class Type < Puppet::Element
end
Puppet.debug("%s subscribes to %s" % [self.name,object])
- unless @dependencies.include?(object)
- @dependencies << object
- end
+ #unless @dependencies.include?(object)
+ # @dependencies << object
+ #end
# pure requires don't call methods
- next if method.nil?
+ #next if method.nil?
# ok, both sides of the connection store some information
# we store the method to call when a given subscription is
# triggered, but the source object decides whether
- sub = object.subscribe(
+ subargs = {
:event => event,
+ :source => object,
:target => self
- )
- if self.respond_to?(method)
- self.addcallback(object, event, method)
+ }
+ if method and self.respond_to?(method)
+ subargs[:callback] = method
end
+ Puppet::Event::Subscription.new(subargs)
+ #if self.respond_to?(method)
+ # self.addcallback(object, event, method)
+ #end
#object.addnotify(self)
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- def propagate(event)
- self.subscribers?(event).each { |object|
- object.trigger(event, self)
- }
+ # Trigger any associated subscriptions, and then pass the event up to our
+ # parent.
+ def propagate(event, transaction)
+ Puppet::Event::Subscription.trigger(self, event, transaction)
if defined? @parent
- @parent.propagate(event)
+ @parent.propagate(event, transaction)
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def subscribe(hash)
hash[:source] = self
- sub = Puppet::Event::Subscription.new(hash)
+ Puppet::Event::Subscription.new(hash)
# add to the correct area
- @subscriptions.push sub
+ #@subscriptions.push sub
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
+ # Unsubscribe from a given object, possibly with a specific event.
def unsubscribe(object, event = nil)
- @subscriptions.find_all { |sub|
+ Puppet::Event::Subscription.dependencies(self).find_all { |sub|
if event
- sub.target == object and sub.event = event
+ sub.match?(event)
else
- sub.target == object
+ sub.source == object
end
}.each { |sub|
- @subscriptions.delete(sub)
+ Puppet::Event::Subscription.delete(sub)
}
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# return all of the subscriptions to a given event
- def subscribers?(event)
- @subscriptions.find_all { |sub|
- sub.event == event.event or
- sub.event == :ALL_EVENTS
- }.collect { |sub|
- sub.target
- }
- end
- #---------------------------------------------------------------
+ #def subscribers?(event)
+ # Puppet::Event::Subscription.subscriptions(self).find_all { |sub|
+ # sub.match?(event)
+ # }.collect { |sub|
+ # sub.target
+ # }
+ #end
- #---------------------------------------------------------------
# we've received an event
# we only support local events right now, so we can pass actual
# objects around, including the transaction object
@@ -1363,23 +1208,14 @@ class Type < Puppet::Element
}
end
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
# Documentation methods
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def self.paramdoc(param)
@paramdoc[param]
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
def self.metaparamdoc(metaparam)
@@metaparamdoc[metaparam]
end
- #---------------------------------------------------------------
- #---------------------------------------------------------------
end # Puppet::Type
end
@@ -1398,3 +1234,5 @@ require 'puppet/type/tidy'
#require 'puppet/type/typegen'
#require 'puppet/type/typegen/filetype'
#require 'puppet/type/typegen/filerecord'
+
+# $Id$
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb
index 980c83fdd..82581998a 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/pfile.rb
@@ -345,22 +345,22 @@ module Puppet
# If we're not root, we can check the values but we cannot change them
def should=(value)
- unless Process.uid == 0
- @should = nil
- @is = nil
- unless defined? @@notifieduid
- Puppet.notice "Cannot manage ownership unless running as root"
- #@parent.delete(self.name)
- @@notifieduid = true
- end
- return
+ #unless Process.uid == 0
+ # @should = nil
+ # @is = nil
+ # unless defined? @@notifieduid
+ # Puppet.notice "Cannot manage ownership unless running as root"
+ # #@parent.delete(self.name)
+ # @@notifieduid = true
+ # end
+ # return
#if @parent.state(:owner)
# @parent.delete(:owner)
#end
#raise Puppet::Error.new(
# "Cannot manage ownership unless running as root"
#)
- end
+ #end
if value.is_a?(Integer)
# verify the user is a valid user
begin
@@ -561,16 +561,16 @@ module Puppet
gid = nil
gname = nil
- unless Process.uid == 0
- unless defined? @@notifiedgroup
- Puppet.notice(
- "Cannot manage group unless running as root"
- )
- @@notifiedgroup = true
- end
- return
- end
-
+ #unless Process.uid == 0
+ # unless defined? @@notifiedgroup
+ # Puppet.notice(
+ # "Cannot manage group unless running as root"
+ # )
+ # @@notifiedgroup = true
+ # end
+ # return
+ #end
+#
if value.is_a?(Integer)
method = :getgrgid
else
@@ -624,16 +624,19 @@ module Puppet
end
end
+ # Normal users will only be able to manage certain groups. Right now,
+ # we'll just let it fail, but we should probably set things up so
+ # that users get warned if they try to change to an unacceptable group.
def sync
- unless Process.uid == 0
- unless defined? @@notifiedgroup
- Puppet.notice(
- "Cannot manage group ownership unless running as root"
- )
- @@notifiedgroup = true
- end
- return nil
- end
+ #unless Process.uid == 0
+ # unless defined? @@notifiedgroup
+ # Puppet.notice(
+ # "Cannot manage group ownership unless running as root"
+ # )
+ # @@notifiedgroup = true
+ # end
+ # return nil
+ #end
Puppet.debug "setting chgrp state to %s" % self.should
if @is == :notfound
@@ -660,6 +663,7 @@ module Puppet
end
end
+ # Copy files from a local or remote source.
class PFileSource < Puppet::State
attr_accessor :source, :local
@doc = "Copy a file over the current file. Uses `checksum` to
@@ -668,6 +672,7 @@ module Puppet
types are *puppet* and *file*."
@name = :source
+ # Ask the file server to describe our file.
def describe
source = @source
@@ -700,15 +705,22 @@ module Puppet
return args
end
+ # This basically calls describe() on our file, and then sets all
+ # of the local states appropriately. If the remote file is a normal
+ # file then we set it to copy; if it's a directory, then we just mark
+ # that the local directory should be created.
def retrieve
sum = nil
+ # Describe the remote file.
@stats = self.describe
if @stats.nil? or @stats[:type].nil?
@is = :notdescribed
return nil
end
+ # Take each of the stats and set them as states on the local file
+ # if a value has not already been provided.
@stats.each { |stat, value|
next if stat == :checksum
next if stat == :type
@@ -723,6 +735,8 @@ module Puppet
end
end
}
+
+ # If we're a normal file, then set things up to copy the file down.
case @stats[:type]
when "file":
if sum = @parent.state(:checksum)
@@ -749,6 +763,8 @@ module Puppet
@parent.delete(:create)
end
end
+ # If we're a directory, then do not copy anything, and instead just
+ # create the directory using the 'create' state.
when "directory":
if state = @parent.state(:create)
unless state.should == "directory"
@@ -761,6 +777,7 @@ module Puppet
# we'll let the :create state do our work
@should = true
@is = true
+ # FIXME We should at least support symlinks, I would think...
else
Puppet.err "Cannot use files of type %s as sources" %
@stats[:type]
@@ -769,15 +786,26 @@ module Puppet
end
end
+ # The special thing here is that we need to make sure that 'should'
+ # is only set for files, not directories.
def should=(source)
- @source = source
+ if ! defined? @stats or @stats.nil?
+ @source = source
- # stupid hack for now; it'll get overriden
- @should = source
+ # stupid hack for now; it'll get overriden
+ @should = source
+ else
+ if @stats[:type] == "directory"
+ @should = true
+ @is = true
+ else
+ @source = source
+ @should = source
+ end
+ end
end
def sync
- Puppet.notice "syncing %s" % @parent.name
if @is == :notdescribed
self.retrieve # try again
if @is == :notdescribed
@@ -790,6 +818,9 @@ module Puppet
end
unless @stats[:type] == "file"
+ if @stats[:type] == "directory"
+ [@parent.name, @is.inspect, @should.inspect]
+ end
raise Puppet::DevError, "Got told to copy non-file %s" %
@parent.name
end
@@ -804,8 +835,6 @@ module Puppet
return nil
end
- Puppet.notice "retrieved %s" % path
-
unless sourceobj.server.local
contents = CGI.unescape(contents)
end
@@ -1147,14 +1176,13 @@ module Puppet
next if var == :name
# behave idempotently
unless child.should(var) == value
- #Puppet.warning "%s is %s, not %s" % [var, child[var], value]
child[var] = value
end
}
else # create it anew
#notice "Creating new file with args %s" % args.inspect
begin
- child = klass.create(args)
+ child = klass.implicitcreate(args)
child.parent = self
@children << child
rescue Puppet::Error => detail
@@ -1301,6 +1329,10 @@ module Puppet
unless stat = self.stat(true)
Puppet.debug "File %s does not exist" % self.name
@states.each { |name,state|
+ # We've already retreived the source, and we don't
+ # want to overwrite whatever it did. This is a bit
+ # of a hack, but oh well, source is definitely special.
+ next if name == :source
state.is = :notfound
}
return
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index 3e87a136a..4308291fa 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -4,10 +4,45 @@
# can only be managed through the interface of an init script
# which is why they have a search path for initscripts and such
-require 'puppet/type/service/init'
-
module Puppet
class State
+ class ServiceEnabled < State
+ @doc = "Whether a service should be enabled to start at boot.
+ **true**/*false*/*runlevel*"
+ @name = :enabled
+
+ def retrieve
+ @is = @parent.enabled?
+ end
+
+ def should=(should)
+ case should
+ when true: @should = :enabled
+ when false: @should = :disabled
+ else
+ raise Puppet::Error, "Invalid 'enabled' value %s" % should
+ end
+ end
+
+ def sync
+ case @should
+ when :enabled
+ unless @parent.respond_to?(:enable)
+ raise Puppet::Error, "Service %s does not support enabling"
+ end
+ @parent.enable
+ return :service_enabled
+ when :disabled
+ unless @parent.respond_to?(:disable)
+ raise Puppet::Error,
+ "Service %s does not support disabling"
+ end
+ @parent.disable
+ return :service_disabled
+ end
+ end
+ end
+
class ServiceRunning < State
@doc = "Whether a service should be running. **true**/*false*"
@name = :running
@@ -16,9 +51,9 @@ module Puppet
# i should probably just be using booleans, but for now, i'm not...
def should=(should)
case should
- when false,0,"0":
+ when false,0,"0", "stopped", :stopped:
should = :stopped
- when true,1,"1":
+ when true,1,"1", :running, "running":
should = :running
else
Puppet.warning "%s: interpreting '%s' as false" %
@@ -106,12 +141,8 @@ module Puppet
# Return the service type we're using. Default to the Service
# class itself, but could be set to a module.
- def self.svctype
- if defined? @svctype
- return @svctype
- else
- return self
- end
+ class << self
+ attr_accessor :svctype
end
# Execute a command. Basically just makes sure it exits with a 0
@@ -176,7 +207,9 @@ module Puppet
# happen if, for instance, it has an init script (and thus responds to
# 'statuscmd') but does not have 'hasstatus' enabled.
def status
- if self[:status] or (self.respond_to?(:statuscmd) and self.statuscmd)
+ if self[:status] or (
+ self.respond_to?(:statuscmd) and self.statuscmd
+ )
cmd = self[:status] || self.statuscmd
output = %x(#{cmd} 2>&1)
Puppet.debug "%s status returned %s" %
@@ -226,15 +259,20 @@ module Puppet
end
# Now load any overlay modules to provide additional functionality
- case Facter["operatingsystem"].value
+ os = Facter["operatingsystem"].value
+ case os
when "Linux":
case Facter["distro"].value
when "Debian":
require 'puppet/type/service/init'
@svctype = Puppet::ServiceTypes::InitSvc
+
+ # and then require stupid debian-specific stuff
+ require 'puppet/type/service/debian'
+ include Puppet::ServiceTypes::DebianSvc
end
when "SunOS":
- release = Integer(Facter["operatingsystemrelease"].value)
+ release = Float(Facter["operatingsystemrelease"].value)
if release < 5.10
require 'puppet/type/service/init'
@svctype = Puppet::ServiceTypes::InitSvc
diff --git a/lib/puppet/type/service/smf.rb b/lib/puppet/type/service/smf.rb
new file mode 100755
index 000000000..4202708c8
--- /dev/null
+++ b/lib/puppet/type/service/smf.rb
@@ -0,0 +1,105 @@
+module Puppet
+ module ServiceTypes
+ module SMFSvc
+ # Mark that our init script supports 'status' commands.
+ def hasstatus=(value)
+ case value
+ when true, "true": @parameters[:hasstatus] = true
+ when false, "false": @parameters[:hasstatus] = false
+ else
+ raise Puppet::Error, "Invalid 'hasstatus' value %s" %
+ value.inspect
+ end
+ end
+
+ # it'd be nice if i didn't throw the output away...
+ # this command returns true if the exit code is 0, and returns
+ # false otherwise
+ def initcmd(cmd)
+ script = self.initscript
+
+ Puppet.debug "Executing '%s %s' as initcmd for '%s'" %
+ [script,cmd,self]
+
+ rvalue = Kernel.system("%s %s" %
+ [script,cmd])
+
+ Puppet.debug "'%s' ran with exit status '%s'" %
+ [cmd,rvalue]
+
+
+ rvalue
+ end
+
+ # Where is our init script?
+ def initscript
+ if defined? @initscript
+ return @initscript
+ else
+ @initscript = self.search(self.name)
+ end
+ end
+
+ # Store the search path for init scripts. This will generally not
+ # be called.
+ def parampath=(ary)
+ unless ary.is_a?(Array)
+ ary = [ary]
+ end
+ @parameters[:path] = ary
+ @searchpaths = ary.find_all { |dir|
+ File.directory?(dir)
+ }
+ end
+
+ # Enable a service, to it's started at boot time. This basically
+ # just creates links in the RC directories, which means that, well,
+ # we need to know where the rc directories are.
+ # FIXME This should probably be a state or something, and
+ # it should actually create use Symlink objects...
+ #def enable
+ #end
+
+ #def disable
+ #end
+
+ def search(name)
+ @searchpaths.each { |path|
+ fqname = File.join(path,name)
+ begin
+ stat = File.stat(fqname)
+ rescue
+ # should probably rescue specific errors...
+ Puppet.debug("Could not find %s in %s" % [name,path])
+ next
+ end
+
+ # if we've gotten this far, we found a valid script
+ return fqname
+ }
+ raise Puppet::Error, "Could not find init script for '%s'" % name
+ end
+
+ # The start command is just the init scriptwith 'start'.
+ def startcmd
+ self.initscript + " start"
+ end
+
+ # If it was specified that the init script has a 'status' command, then
+ # we just return that; otherwise, we return false, which causes it to
+ # fallback to other mechanisms.
+ def statuscmd
+ if self[:hasstatus]
+ return self.initscript + " status"
+ else
+ return false
+ end
+ end
+
+ # The stop command is just the init script with 'stop'.
+ def stopcmd
+ self.initscript + " stop"
+ end
+ end
+ end
+end
diff --git a/lib/puppet/type/symlink.rb b/lib/puppet/type/symlink.rb
index 050904297..79780e869 100755
--- a/lib/puppet/type/symlink.rb
+++ b/lib/puppet/type/symlink.rb
@@ -167,7 +167,7 @@ module Puppet
:source => @target
}
- dir = Puppet::Type::PFile.create(args)
+ dir = Puppet::Type::PFile.implicitcreate(args)
dir.parent = self
Puppet.debug "Got dir %s" % dir.name
self.push dir
diff --git a/test/other/tc_events.rb b/test/other/tc_events.rb
index 5f3ddcd67..c555e17f0 100755
--- a/test/other/tc_events.rb
+++ b/test/other/tc_events.rb
@@ -11,9 +11,9 @@ require 'test/unit'
# $Id$
class TestEvents < TestPuppet
- def setup
- Puppet[:loglevel] = :debug if __FILE__ == $0
+ def teardown
super
+ Puppet::Event::Subscription.clear
end
def test_simplesubscribe
@@ -30,17 +30,9 @@ class TestEvents < TestPuppet
@@tmpfiles << "/tmp/eventtestingA"
- comp = Puppet::Type::Component.create(
- :name => "eventtesting"
- )
- comp.push exec
- trans = comp.evaluate
- events = nil
- assert_nothing_raised {
- events = trans.evaluate
- }
+ comp = newcomp("eventtesting", file, exec)
- assert_equal(1, events.length)
+ trans = assert_events(comp, [:file_created], "events")
assert_equal(1, trans.triggered?(exec, :refresh))
end
@@ -74,7 +66,7 @@ class TestEvents < TestPuppet
assert_equal(0, trans.triggered?(exec, :refresh))
end
- def test_ladderrequire
+ def test_zladderrequire
comps = {}
objects = {}
fname = "/tmp/eventtestfuntest"
diff --git a/test/other/tc_relationships.rb b/test/other/tc_relationships.rb
index c8927972b..d2544ffa4 100755
--- a/test/other/tc_relationships.rb
+++ b/test/other/tc_relationships.rb
@@ -9,57 +9,103 @@ require 'puppettest'
require 'test/unit'
class TestRelationships < TestPuppet
- def setup
- super
- @groups = %x{groups}.chomp.split(/ /)
- unless @groups.length > 1
- p @groups
- raise "You must be a member of more than one group to test this"
- end
- end
-
def newfile
assert_nothing_raised() {
- cfile = File.join($puppetbase,"examples/root/etc/configfile")
- unless Puppet::Type::PFile.has_key?(cfile)
- Puppet::Type::PFile.create(
- :path => cfile,
- :check => [:mode, :owner, :group]
- )
- end
- return Puppet::Type::PFile[cfile]
+ return Puppet::Type::PFile.create(
+ :path => tempfile,
+ :check => [:mode, :owner, :group]
+ )
}
end
- def newservice
- assert_nothing_raised() {
- unless Puppet::Type::Service.has_key?("sleeper")
- Puppet::Type::Service.create(
- :name => "sleeper",
- :path => File.join($puppetbase,"examples/root/etc/init.d"),
- :check => [:running]
- )
- end
- return Puppet::Type::Service["sleeper"]
+ def test_simplerel
+ file1 = newfile()
+ file2 = newfile()
+ assert_nothing_raised {
+ file1[:require] = [file2.class.name, file2.name]
}
- end
- def newcomp(name,*args)
- comp = nil
- assert_nothing_raised() {
- comp = Puppet::Component.new(:name => name)
+ deps = []
+ assert_nothing_raised {
+ file1.eachdependency { |obj|
+ deps << obj
+ }
}
- args.each { |arg|
- assert_nothing_raised() {
- comp.push arg
+ assert_equal(1, deps.length, "Did not get dependency")
+
+ assert_nothing_raised {
+ file1.unsubscribe(file2)
+ }
+
+ deps = []
+ assert_nothing_raised {
+ file1.eachdependency { |obj|
+ deps << obj
}
}
- return comp
+ assert_equal(0, deps.length, "Still have dependency")
end
- def test_simplerel
+ def test_newsub
+ file1 = newfile()
+ file2 = newfile()
+
+ sub = nil
+ assert_nothing_raised("Could not create subscription") {
+ sub = Puppet::Event::Subscription.new(
+ :source => file1,
+ :target => file2,
+ :event => :ALL_EVENTS,
+ :callback => :refresh
+ )
+ }
+
+ subs = nil
+
+ assert_nothing_raised {
+ subs = Puppet::Event::Subscription.subscribers(file1)
+ }
+ assert_equal(1, subs.length, "Got incorrect number of subs")
+ assert_equal(sub.target, subs[0], "Got incorrect sub")
+
+ deps = nil
+ assert_nothing_raised {
+ deps = Puppet::Event::Subscription.dependencies(file2)
+ }
+ assert_equal(1, deps.length, "Got incorrect number of deps")
+ assert_equal(sub, deps[0], "Got incorrect dep")
+ end
+
+ def test_eventmatch
+ file1 = newfile()
+ file2 = newfile()
+
+ sub = nil
+ assert_nothing_raised("Could not create subscription") {
+ sub = Puppet::Event::Subscription.new(
+ :source => file1,
+ :target => file2,
+ :event => :ALL_EVENTS,
+ :callback => :refresh
+ )
+ }
+
+ assert(sub.match?(:anything), "ALL_EVENTS did not match")
+ assert(! sub.match?(:NONE), "ALL_EVENTS matched :NONE")
+
+ sub.event = :file_created
+
+ assert(sub.match?(:file_created), "event did not match")
+ assert(sub.match?(:ALL_EVENTS), "ALL_EVENTS did not match")
+ assert(! sub.match?(:NONE), "ALL_EVENTS matched :NONE")
+
+ sub.event = :NONE
+
+ assert(! sub.match?(:file_created), "Invalid match")
+ assert(! sub.match?(:ALL_EVENTS), "ALL_EVENTS matched")
+ assert(! sub.match?(:NONE), "matched :NONE")
end
end
diff --git a/test/other/tc_transactions.rb b/test/other/tc_transactions.rb
index 946d53279..6b6213b81 100644
--- a/test/other/tc_transactions.rb
+++ b/test/other/tc_transactions.rb
@@ -74,6 +74,7 @@ class TestTransactions < FileTesting
return Puppet::Type::Service.create(
:name => "sleeper",
:path => File.join($puppetbase,"examples/root/etc/init.d"),
+ :hasstatus => true,
:check => [:running]
)
}
diff --git a/test/server/tc_bucket.rb b/test/server/tc_bucket.rb
index 264a8da13..8a7e71511 100644
--- a/test/server/tc_bucket.rb
+++ b/test/server/tc_bucket.rb
@@ -22,6 +22,7 @@ class TestBucket < ServerTest
spin
name = File.basename(file)
tmppath = File.join(tmpdir,name)
+ @@tmpfiles << tmppath
# copy the files to our tmp directory so we can modify them...
File.open(tmppath,File::WRONLY|File::TRUNC|File::CREAT) { |wf|
@@ -167,6 +168,7 @@ class TestBucket < ServerTest
files = filelist()
tmpdir = File.join(tmpdir(),"tmpfiledir")
+ @@tmpfiles << tmpdir
FileUtils.mkdir_p(tmpdir)
bucket = nil
diff --git a/test/types/tc_basic.rb b/test/types/tc_basic.rb
index 585caaa95..f0257fef0 100644
--- a/test/types/tc_basic.rb
+++ b/test/types/tc_basic.rb
@@ -1,7 +1,7 @@
if __FILE__ == $0
$:.unshift '..'
$:.unshift '../../lib'
- $puppetbase = "../../../../language/trunk"
+ $puppetbase = "../.."
end
require 'puppet'
@@ -40,6 +40,7 @@ class TestBasic < Test::Unit::TestCase
@sleeper = Puppet::Type::Service.create(
:name => "sleeper",
:path => File.join($puppetbase,"examples/root/etc/init.d"),
+ :hasstatus => true,
:running => 1
)
}
diff --git a/test/types/tc_file.rb b/test/types/tc_file.rb
index 169b32995..8b19dc670 100644
--- a/test/types/tc_file.rb
+++ b/test/types/tc_file.rb
@@ -86,8 +86,66 @@ class TestFile < FileTesting
end
end
- # we can really only test changing ownership if we're root
- if Process.uid == 0
+ uid, name = users.shift
+ us = {}
+ us[uid] = name
+ users.each { |uid, name|
+ # just make sure we don't try to manage users
+ assert_nothing_raised() {
+ file.sync
+ }
+ assert_nothing_raised() {
+ file[:owner] = name
+ }
+ assert_nothing_raised() {
+ file.retrieve
+ }
+ assert_nothing_raised() {
+ file.sync
+ }
+ }
+ end
+
+ def test_zgroup
+ file = mktestfile()
+ [%x{groups}.chomp.split(/ /), Process.groups].flatten.each { |group|
+ assert_nothing_raised() {
+ file[:group] = group
+ }
+ assert(file.state(:group))
+ assert(file.state(:group).should)
+ }
+ end
+
+ if Process.uid == 0
+ def test_ownerasroot
+ file = mktestfile()
+
+ users = {}
+ count = 0
+
+ # collect five users
+ Etc.passwd { |passwd|
+ if count > 5
+ break
+ else
+ count += 1
+ end
+ users[passwd.uid] = passwd.name
+ }
+
+ fake = {}
+ # find a fake user
+ while true
+ a = rand(1000)
+ begin
+ Etc.getpwuid(a)
+ rescue
+ fake[a] = "fakeuser"
+ break
+ end
+ end
+
users.each { |uid, name|
assert_nothing_raised() {
file[:owner] = name
@@ -122,51 +180,33 @@ class TestFile < FileTesting
file[:owner] = uid
}
}
- else
- uid, name = users.shift
- us = {}
- us[uid] = name
- users.each { |uid, name|
- # just make sure we don't try to manage users
+ end
+
+ def test_groupasroot
+ file = mktestfile()
+ [%x{groups}.chomp.split(/ /), Process.groups].flatten.each { |group|
assert_nothing_raised() {
- file.sync
+ file[:group] = group
}
+ assert(file.state(:group))
+ assert(file.state(:group).should)
assert_nothing_raised() {
- file[:owner] = name
+ file.evaluate
}
assert_nothing_raised() {
- file.retrieve
+ file.sync
+ }
+ assert_nothing_raised() {
+ file.evaluate
}
assert(file.insync?())
assert_nothing_raised() {
- file.sync
+ file.delete(:group)
}
}
end
- end
-
- def test_group
- file = mktestfile()
- [%x{groups}.chomp.split(/ /), Process.groups].flatten.each { |group|
- assert_nothing_raised() {
- file[:group] = group
- }
- assert(file.state(:group))
- assert(file.state(:group).should)
- assert_nothing_raised() {
- file.evaluate
- }
- assert_nothing_raised() {
- file.sync
- }
- assert_nothing_raised() {
- file.evaluate
- }
- assert(file.insync?())
- assert_nothing_raised() {
- file.delete(:group)
- }
- }
+ else
+ $stderr.puts "Run as root for complete owner and group testing"
end
def test_create
@@ -371,6 +411,7 @@ class TestFile < FileTesting
def test_recursion
path = "/tmp/filerecursetest"
+ @@tmpfiles.push path
tmpfile = File.join(path,"testing")
system("mkdir -p #{path}")
cyclefile(path)
@@ -382,7 +423,6 @@ class TestFile < FileTesting
of.puts "goodness"
}
cyclefile(path)
- @@tmpfiles.push path
end
=begin
diff --git a/test/types/tc_query.rb b/test/types/tc_query.rb
index 5ba0e0c64..31e0d23a9 100644
--- a/test/types/tc_query.rb
+++ b/test/types/tc_query.rb
@@ -1,7 +1,7 @@
if __FILE__ == $0
$:.unshift '..'
$:.unshift '../../lib'
- $puppetbase = "../../../../language/trunk"
+ $puppetbase = "../.."
end
require 'puppet'
@@ -43,6 +43,7 @@ class TestQuery < Test::Unit::TestCase
Puppet::Type::Service.create(
:name => "sleeper",
:path => File.join($puppetbase,"examples/root/etc/init.d"),
+ :hasstatus => true,
:check => [:running]
)
end
diff --git a/test/types/tc_service.rb b/test/types/tc_service.rb
index c0df3419f..82827c734 100644
--- a/test/types/tc_service.rb
+++ b/test/types/tc_service.rb
@@ -74,14 +74,18 @@ class TestService < TestPuppet
assert(sleeper.insync?)
end
- def test_processStartWithPattern
- sleeper = mksleeper(:pattern => "bin/sleeper")
+ case Puppet::Type::Service.svctype
+ when Puppet::ServiceTypes::InitSvc
+ def test_processStartWithPattern
+ sleeper = mksleeper(:pattern => "bin/sleeper")
- cyclesleeper(sleeper)
- end
+ cyclesleeper(sleeper)
+ end
- def test_processStartWithStatus
- sleeper = mksleeper(:hasstatus => true)
- cyclesleeper(sleeper)
+ def test_processStartWithStatus
+ sleeper = mksleeper(:hasstatus => true)
+ cyclesleeper(sleeper)
+ end
+ #when Puppet::ServiceTypes::SMFSvc
end
end