1 require 'puppet/transportable'
4 # Make 'new' private, so people have to use create instead.
9 # retrieve a named instance of the current type
11 @objects[name] || @aliases[name]
14 # add an instance by name to the class list of instances
15 def self.[]=(name,object)
17 if object.is_a?(Puppet::Type)
20 raise Puppet::DevError, "must pass a Puppet::Type object"
23 if exobj = @objects[name] and self.isomorphic?
24 msg = "Object '%s[%s]' already exists" %
25 [newobj.class.name, name]
27 if exobj.file and exobj.line
28 msg += ("in file %s at line %s" %
29 [object.file, object.line])
31 if object.file and object.line
32 msg += ("and cannot be redefined in file %s at line %s" %
33 [object.file, object.line])
35 error = Puppet::Error.new(msg)
38 #Puppet.info("adding %s of type %s to class list" %
39 # [name,object.class])
40 @objects[name] = newobj
44 # Create an alias. We keep these in a separate hash so that we don't encounter
45 # the objects multiple times when iterating over them.
46 def self.alias(name, obj)
47 if @objects.include?(name)
48 unless @objects[name] == obj
49 raise Puppet::Error.new(
50 "Cannot create alias %s: object already exists" %
56 if @aliases.include?(name)
57 unless @aliases[name] == obj
58 raise Puppet::Error.new(
59 "Object %s already has alias %s" %
60 [@aliases[name].name, name]
68 # remove all of the instances of a single type
71 @objects.each do |name, obj|
81 # Force users to call this, so that we can merge objects if
84 # Don't modify the original hash; instead, create a duplicate and modify it.
85 # We have to dup and use the ! so that it stays a TransObject if it is
90 # If we're the base class, then pass the info on appropriately
91 if self == Puppet::Type
93 if hash.is_a? Puppet::TransObject
96 # If we're using the type to determine object type, then delete it
102 # If they've specified a type and called on the base, then
103 # delegate to the subclass.
105 if typeklass = self.type(type)
106 return typeklass.create(hash)
108 raise Puppet::Error, "Unknown type %s" % type
111 raise Puppet::Error, "No type found for %s" % hash.inspect
115 # Handle this new object being implicit
116 implicit = hash[:implicit] || false
117 if hash.include?(:implicit)
118 hash.delete(:implicit)
122 unless hash.is_a? Puppet::TransObject
123 hash = self.hash2trans(hash)
126 # XXX This will have to change when transobjects change to using titles
129 # if the object already exists
130 if self.isomorphic? and retobj = self[title]
131 # if only one of our objects is implicit, then it's easy to see
132 # who wins -- the non-implicit one.
133 if retobj.implicit? and ! implicit
134 Puppet.notice "Removing implicit %s" % retobj.title
135 # Remove all of the objects, but do not remove their subscriptions.
138 # now pass through and create the new object
140 Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title]
143 raise Puppet::Error, "%s is already being managed" % retobj.ref
148 # if there's a failure, destroy the object if it got that far, but raise
153 Puppet.err "Could not create %s: %s" % [title, detail.to_s]
156 elsif obj = self[title]
166 # Store the object by title
167 self[obj.title] = obj
172 # remove a specified object
173 def self.delete(resource)
174 return unless defined? @objects
175 if @objects.include?(resource.title)
176 @objects.delete(resource.title)
178 if @aliases.include?(resource.title)
179 @aliases.delete(resource.title)
181 if @aliases.has_value?(resource)
183 @aliases.each do |name, otherres|
184 if otherres == resource
188 names.each { |name| @aliases.delete(name) }
192 # iterate across each of the type's instances
194 return unless defined? @objects
195 @objects.each { |name,instance|
200 # does the type have an object with the given name?
201 def self.has_key?(name)
202 return @objects.has_key?(name)
205 # Convert a hash to a TransObject.
206 def self.hash2trans(hash)
208 if hash.include? :title
211 elsif hash.include? self.namevar
212 title = hash[self.namevar]
213 hash.delete(self.namevar)
215 if hash.include? :name
216 raise ArgumentError, "Cannot provide both name and %s to %s" %
217 [self.namevar, self.name]
224 if catalog = hash[:catalog]
225 hash.delete(:catalog)
228 raise(Puppet::Error, "You must specify a title for objects of type %s" % self.to_s) unless title
230 if hash.include? :type
231 unless self.validattr? :type
236 # okay, now make a transobject out of hash
238 trans = Puppet::TransObject.new(title, self.name.to_s)
239 trans.catalog = catalog if catalog
240 hash.each { |param, value|
244 raise Puppet::Error, "Could not create %s: %s" %
251 # Retrieve all known instances. Either requires providers or must be overridden.
253 unless defined?(@providers) and ! @providers.empty?
254 raise Puppet::DevError, "%s has no providers and has not overridden 'instances'" % self.name
257 # Put the default provider first, then the rest of the suitable providers.
258 provider_instances = {}
259 providers_by_source.collect do |provider|
260 provider.instances.collect do |instance|
261 # First try to get the resource if it already exists
262 # Skip instances that map to a managed resource with a different provider
263 next if resource = self[instance.name] and resource.provider.class != instance.class
265 # We always want to use the "first" provider instance we find, unless the resource
266 # is already managed and has a different provider set
267 if other = provider_instances[instance.name]
268 Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
269 [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
272 provider_instances[instance.name] = instance
275 resource.provider = instance
278 create(:name => instance.name, :provider => instance, :check => :all)
284 # Return a list of one suitable provider per source, with the default provider first.
285 def self.providers_by_source
286 # Put the default provider first, then the rest of the suitable providers.
288 [defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
289 next if sources.include?(provider.source)
291 sources << provider.source
296 # Create the path for logging and such.
299 [p.pathbuilder, self.ref].flatten