| Class | Puppet::Type |
| In: |
lib/puppet/type.rb
|
| Parent: | Object |
| catalog | [RW] | The catalog that this resource is stored in. |
| defaultprovider | [W] | |
| file | [RW] | In naming methods, I have tried to consistently name the method so 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. |
| implicit | [W] | Code related to the closure-like behaviour of the resource classes. |
| line | [RW] | In naming methods, I have tried to consistently name the method so 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. |
| name | [R] | |
| noop | [W] | |
| parenttype | [RW] | |
| properties | [R] | |
| provider | [R] | |
| providerloader | [RW] | |
| self_refresh | [RW] | |
| tags | [R] | All of the tagging code. |
| title | [W] |
add an instance by name to the class list of instances
# File lib/puppet/type.rb, line 995
995: def self.[]=(name,object)
996: newobj = nil
997: if object.is_a?(Puppet::Type)
998: newobj = object
999: else
1000: raise Puppet::DevError, "must pass a Puppet::Type object"
1001: end
1002:
1003: if exobj = @objects[name] and self.isomorphic?
1004: msg = "Object '%s[%s]' already exists" %
1005: [newobj.class.name, name]
1006:
1007: if exobj.file and exobj.line
1008: msg += ("in file %s at line %s" %
1009: [object.file, object.line])
1010: end
1011: if object.file and object.line
1012: msg += ("and cannot be redefined in file %s at line %s" %
1013: [object.file, object.line])
1014: end
1015: error = Puppet::Error.new(msg)
1016: raise error
1017: else
1018: #Puppet.info("adding %s of type %s to class list" %
1019: # [name,object.class])
1020: @objects[name] = newobj
1021: end
1022: end
Create an alias. We keep these in a separate hash so that we don‘t encounter the objects multiple times when iterating over them.
# File lib/puppet/type.rb, line 1026
1026: def self.alias(name, obj)
1027: if @objects.include?(name)
1028: unless @objects[name] == obj
1029: raise Puppet::Error.new(
1030: "Cannot create alias %s: object already exists" %
1031: [name]
1032: )
1033: end
1034: end
1035:
1036: if @aliases.include?(name)
1037: unless @aliases[name] == obj
1038: raise Puppet::Error.new(
1039: "Object %s already has alias %s" %
1040: [@aliases[name].name, name]
1041: )
1042: end
1043: end
1044:
1045: @aliases[name] = obj
1046: end
All parameters, in the appropriate order. The namevar comes first, then the properties, then the params and metaparams in the order they were specified in the files.
# File lib/puppet/type.rb, line 39
39: def self.allattrs
40: # now get all of the arguments, in a specific order
41: # Cache this, since it gets called so many times
42: namevar = self.namevar
43:
44: order = [namevar]
45: if self.parameters.include?(:provider)
46: order << :provider
47: end
48: order << [self.properties.collect { |property| property.name },
49: self.parameters - [:provider],
50: self.metaparams].flatten.reject { |param|
51: # we don't want our namevar in there multiple times
52: param == namevar
53: }
54:
55: order.flatten!
56:
57: return order
58: end
Find the class associated with any given attribute.
# File lib/puppet/type.rb, line 74
74: def self.attrclass(name)
75: @attrclasses ||= {}
76:
77: # We cache the value, since this method gets called such a huge number
78: # of times (as in, hundreds of thousands in a given run).
79: unless @attrclasses.include?(name)
80: @attrclasses[name] = case self.attrtype(name)
81: when :property: @validproperties[name]
82: when :meta: @@metaparamhash[name]
83: when :param: @paramhash[name]
84: end
85: end
86: @attrclasses[name]
87: end
What type of parameter are we dealing with? Cache the results, because this method gets called so many times.
# File lib/puppet/type.rb, line 91
91: def self.attrtype(attr)
92: @attrtypes ||= {}
93: unless @attrtypes.include?(attr)
94: @attrtypes[attr] = case
95: when @validproperties.include?(attr): :property
96: when @paramhash.include?(attr): :param
97: when @@metaparamhash.include?(attr): :meta
98: else
99: raise Puppet::DevError,
100: "Invalid attribute '%s' for class '%s'" %
101: [attr, self.name]
102: end
103: end
104:
105: @attrtypes[attr]
106: end
Specify a block for generating a list of objects to autorequire. This makes it so that you don‘t have to manually specify things that you clearly require.
# File lib/puppet/type.rb, line 1952
1952: def self.autorequire(name, &block)
1953: @autorequires ||= {}
1954: @autorequires[name] = block
1955: end
Copy an existing class parameter. This allows other types to avoid duplicating a parameter definition, and is mostly used by subclasses of the File class.
# File lib/puppet/type.rb, line 111
111: def self.copyparam(klass, name)
112: param = klass.attrclass(name)
113:
114: unless param
115: raise Puppet::DevError, "Class %s has no param %s" % [klass, name]
116: end
117: @parameters << param
118: @parameters.each { |p| @paramhash[name] = p }
119:
120: if param.isnamevar?
121: @namevar = param.name
122: end
123: end
Force users to call this, so that we can merge objects if necessary.
# File lib/puppet/type.rb, line 1063
1063: def self.create(args)
1064: # Don't modify the original hash; instead, create a duplicate and modify it.
1065: # We have to dup and use the ! so that it stays a TransObject if it is
1066: # one.
1067: hash = args.dup
1068: symbolizehash!(hash)
1069:
1070: # If we're the base class, then pass the info on appropriately
1071: if self == Puppet::Type
1072: type = nil
1073: if hash.is_a? Puppet::TransObject
1074: type = hash.type
1075: else
1076: # If we're using the type to determine object type, then delete it
1077: if type = hash[:type]
1078: hash.delete(:type)
1079: end
1080: end
1081:
1082: # If they've specified a type and called on the base, then
1083: # delegate to the subclass.
1084: if type
1085: if typeklass = self.type(type)
1086: return typeklass.create(hash)
1087: else
1088: raise Puppet::Error, "Unknown type %s" % type
1089: end
1090: else
1091: raise Puppet::Error, "No type found for %s" % hash.inspect
1092: end
1093: end
1094:
1095: # Handle this new object being implicit
1096: implicit = hash[:implicit] || false
1097: if hash.include?(:implicit)
1098: hash.delete(:implicit)
1099: end
1100:
1101: name = nil
1102: unless hash.is_a? Puppet::TransObject
1103: hash = self.hash2trans(hash)
1104: end
1105:
1106: # XXX This will have to change when transobjects change to using titles
1107: title = hash.name
1108:
1109: # if the object already exists
1110: if self.isomorphic? and retobj = self[title]
1111: # if only one of our objects is implicit, then it's easy to see
1112: # who wins -- the non-implicit one.
1113: if retobj.implicit? and ! implicit
1114: Puppet.notice "Removing implicit %s" % retobj.title
1115: # Remove all of the objects, but do not remove their subscriptions.
1116: retobj.remove(false)
1117:
1118: # now pass through and create the new object
1119: elsif implicit
1120: Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title]
1121: return nil
1122: else
1123: raise Puppet::Error, "%s is already being managed" % retobj.ref
1124: end
1125: end
1126:
1127: # create it anew
1128: # if there's a failure, destroy the object if it got that far, but raise
1129: # the error.
1130: begin
1131: obj = new(hash)
1132: rescue => detail
1133: Puppet.err "Could not create %s: %s" % [title, detail.to_s]
1134: if obj
1135: obj.remove(true)
1136: elsif obj = self[title]
1137: obj.remove(true)
1138: end
1139: raise
1140: end
1141:
1142: if implicit
1143: obj.implicit = true
1144: end
1145:
1146: # Store the object by title
1147: self[obj.title] = obj
1148:
1149: return obj
1150: end
Find the default provider.
# File lib/puppet/type.rb, line 1714
1714: def self.defaultprovider
1715: unless defined? @defaultprovider and @defaultprovider
1716: suitable = suitableprovider()
1717:
1718: # Find which providers are a default for this system.
1719: defaults = suitable.find_all { |provider| provider.default? }
1720:
1721: # If we don't have any default we use suitable providers
1722: defaults = suitable if defaults.empty?
1723: max = defaults.collect { |provider| provider.defaultnum }.max
1724: defaults = defaults.find_all { |provider| provider.defaultnum == max }
1725:
1726: retval = nil
1727: if defaults.length > 1
1728: Puppet.warning(
1729: "Found multiple default providers for %s: %s; using %s" %
1730: [self.name, defaults.collect { |i| i.name.to_s }.join(", "),
1731: defaults[0].name]
1732: )
1733: retval = defaults.shift
1734: elsif defaults.length == 1
1735: retval = defaults.shift
1736: else
1737: raise Puppet::DevError, "Could not find a default provider for %s" %
1738: self.name
1739: end
1740:
1741: @defaultprovider = retval
1742: end
1743:
1744: return @defaultprovider
1745: end
remove a specified object
# File lib/puppet/type.rb, line 1153
1153: def self.delete(resource)
1154: return unless defined? @objects
1155: if @objects.include?(resource.title)
1156: @objects.delete(resource.title)
1157: end
1158: if @aliases.include?(resource.title)
1159: @aliases.delete(resource.title)
1160: end
1161: if @aliases.has_value?(resource)
1162: names = []
1163: @aliases.each do |name, otherres|
1164: if otherres == resource
1165: names << name
1166: end
1167: end
1168: names.each { |name| @aliases.delete(name) }
1169: end
1170: end
Code related to the container behaviour.
# File lib/puppet/type.rb, line 759
759: def self.depthfirst?
760: if defined? @depthfirst
761: return @depthfirst
762: else
763: return false
764: end
765: end
We need to add documentation for each provider.
# File lib/puppet/type.rb, line 1871
1871: def self.doc
1872: @doc + " Available providers are:\n\n" + parenttype().providers.sort { |a,b|
1873: a.to_s <=> b.to_s
1874: }.collect { |i|
1875: "* **%s**: %s" % [i, parenttype().provider(i).doc]
1876: }.join("\n")
1877: end
A similar function but one that yields the class and type. This is mainly so that setdefaults doesn‘t call quite so many functions.
# File lib/puppet/type.rb, line 127
127: def self.eachattr(*ary)
128: if ary.empty?
129: ary = nil
130: end
131:
132: # We have to do this in a specific order, so that defaults are
133: # created in that order (e.g., providers should be set up before
134: # anything else).
135: allattrs.each do |name|
136: next unless ary.nil? or ary.include?(name)
137: if obj = @properties.find { |p| p.name == name }
138: yield obj, :property
139: elsif obj = @parameters.find { |p| p.name == name }
140: yield obj, :param
141: elsif obj = @@metaparams.find { |p| p.name == name }
142: yield obj, :meta
143: else
144: raise Puppet::DevError, "Could not find parameter %s" % name
145: end
146: end
147: end
# File lib/puppet/type.rb, line 149
149: def self.eachmetaparam
150: @@metaparams.each { |p| yield p.name }
151: end
Create the ‘ensure’ class. This is a separate method so other types can easily call it and create their own ‘ensure’ values.
# File lib/puppet/type.rb, line 155
155: def self.ensurable(&block)
156: if block_given?
157: self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
158: else
159: self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
160: self.defaultvalues
161: end
162: end
163: end
Should we add the ‘ensure’ property to this class?
# File lib/puppet/type.rb, line 166
166: def self.ensurable?
167: # If the class has all three of these methods defined, then it's
168: # ensurable.
169: ens = [:exists?, :create, :destroy].inject { |set, method|
170: set &&= self.public_method_defined?(method)
171: }
172:
173: return ens
174: end
Deal with any options passed into parameters.
# File lib/puppet/type.rb, line 177
177: def self.handle_param_options(name, options)
178: # If it's a boolean parameter, create a method to test the value easily
179: if options[:boolean]
180: define_method(name.to_s + "?") do
181: val = self[name]
182: if val == :true or val == true
183: return true
184: end
185: end
186: end
187:
188: # If this param handles relationships, store that information
189: end
does the type have an object with the given name?
# File lib/puppet/type.rb, line 1181
1181: def self.has_key?(name)
1182: return @objects.has_key?(name)
1183: end
Convert a hash, as provided by, um, a provider, into an instance of self.
# File lib/puppet/type.rb, line 1748
1748: def self.hash2obj(hash)
1749: obj = nil
1750:
1751: namevar = self.namevar
1752: unless hash.include?(namevar) and hash[namevar]
1753: raise Puppet::DevError, "Hash was not passed with namevar"
1754: end
1755:
1756: # if the obj already exists with that name...
1757: if obj = self[hash[namevar]]
1758: # We're assuming here that objects with the same name
1759: # are the same object, which *should* be the case, assuming
1760: # we've set up our naming stuff correctly everywhere.
1761:
1762: # Mark found objects as present
1763: hash.each { |param, value|
1764: if property = obj.property(param)
1765: elsif val = obj[param]
1766: obj[param] = val
1767: else
1768: # There is a value on disk, but it should go away
1769: obj[param] = :absent
1770: end
1771: }
1772: else
1773: # create a new obj, since no existing one seems to
1774: # match
1775: obj = self.create(namevar => hash[namevar])
1776:
1777: # We can't just pass the hash in at object creation time,
1778: # because it sets the should value, not the is value.
1779: hash.delete(namevar)
1780: hash.each { |param, value|
1781: obj[param] = value unless obj.add_property_parameter(param)
1782: }
1783: end
1784:
1785: return obj
1786: end
Convert a hash to a TransObject.
# File lib/puppet/type.rb, line 1186
1186: def self.hash2trans(hash)
1187: title = nil
1188: if hash.include? :title
1189: title = hash[:title]
1190: hash.delete(:title)
1191: elsif hash.include? self.namevar
1192: title = hash[self.namevar]
1193: hash.delete(self.namevar)
1194:
1195: if hash.include? :name
1196: raise ArgumentError, "Cannot provide both name and %s to %s" %
1197: [self.namevar, self.name]
1198: end
1199: elsif hash[:name]
1200: title = hash[:name]
1201: hash.delete :name
1202: end
1203:
1204: if catalog = hash[:catalog]
1205: hash.delete(:catalog)
1206: end
1207:
1208: raise(Puppet::Error, "You must specify a title for objects of type %s" % self.to_s) unless title
1209:
1210: if hash.include? :type
1211: unless self.validattr? :type
1212: hash.delete :type
1213: end
1214: end
1215:
1216: # okay, now make a transobject out of hash
1217: begin
1218: trans = Puppet::TransObject.new(title, self.name.to_s)
1219: trans.catalog = catalog if catalog
1220: hash.each { |param, value|
1221: trans[param] = value
1222: }
1223: rescue => detail
1224: raise Puppet::Error, "Could not create %s: %s" %
1225: [name, detail]
1226: end
1227:
1228: return trans
1229: end
all of the variables that must be initialized for each subclass
# File lib/puppet/type.rb, line 2165
2165: def self.initvars
2166: # all of the instances of this class
2167: @objects = Hash.new
2168: @aliases = Hash.new
2169:
2170: @providers = Hash.new
2171: @defaults = {}
2172:
2173: unless defined? @parameters
2174: @parameters = []
2175: end
2176:
2177: @validproperties = {}
2178: @properties = []
2179: @parameters = []
2180: @paramhash = {}
2181:
2182: @attr_aliases = {}
2183:
2184: @paramdoc = Hash.new { |hash,key|
2185: if key.is_a?(String)
2186: key = key.intern
2187: end
2188: if hash.include?(key)
2189: hash[key]
2190: else
2191: "Param Documentation for %s not found" % key
2192: end
2193: }
2194:
2195: unless defined? @doc
2196: @doc = ""
2197: end
2198:
2199: end
Retrieve all known instances. Either requires providers or must be overridden.
# File lib/puppet/type.rb, line 1232
1232: def self.instances
1233: unless defined?(@providers) and ! @providers.empty?
1234: raise Puppet::DevError, "%s has no providers and has not overridden 'instances'" % self.name
1235: end
1236:
1237: # Put the default provider first, then the rest of the suitable providers.
1238: provider_instances = {}
1239: providers_by_source.collect do |provider|
1240: provider.instances.collect do |instance|
1241: # First try to get the resource if it already exists
1242: # Skip instances that map to a managed resource with a different provider
1243: next if resource = self[instance.name] and resource.provider.class != instance.class
1244:
1245: # We always want to use the "first" provider instance we find, unless the resource
1246: # is already managed and has a different provider set
1247: if other = provider_instances[instance.name]
1248: Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
1249: [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
1250: next
1251: end
1252: provider_instances[instance.name] = instance
1253:
1254: if resource
1255: resource.provider = instance
1256: resource
1257: else
1258: create(:name => instance.name, :provider => instance, :check => :all)
1259: end
1260: end
1261: end.flatten.compact
1262: 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.
# File lib/puppet/type.rb, line 714
714: def self.isomorphic?
715: if defined? @isomorphic
716: return @isomorphic
717: else
718: return true
719: end
720: end
# File lib/puppet/type.rb, line 205
205: def self.metaparamdoc(metaparam)
206: @@metaparamhash[metaparam].doc
207: end
# File lib/puppet/type.rb, line 201
201: def self.metaparams
202: @@metaparams.collect { |param| param.name }
203: end
Find the namevar
# File lib/puppet/type.rb, line 238
238: def self.namevar
239: unless defined? @namevar
240: params = @parameters.find_all { |param|
241: param.isnamevar? or param.name == :name
242: }
243:
244: if params.length > 1
245: raise Puppet::DevError, "Found multiple namevars for %s" % self.name
246: elsif params.length == 1
247: @namevar = params[0].name
248: else
249: raise Puppet::DevError, "No namevar for %s" % self.name
250: end
251: end
252: @namevar
253: end
initialize the type instance
# File lib/puppet/type.rb, line 2267
2267: def initialize(hash)
2268: unless defined? @inited
2269: self.initvars
2270: end
2271: namevar = self.class.namevar
2272:
2273: orighash = hash
2274:
2275: # If we got passed a transportable object, we just pull a bunch of info
2276: # directly from it. This is the main object instantiation mechanism.
2277: if hash.is_a?(Puppet::TransObject)
2278: # XXX This will need to change when transobjects change to titles.
2279: self.title = hash.name
2280:
2281: #self[:name] = hash[:name]
2282: [:file, :line, :tags, :catalog].each { |getter|
2283: if hash.respond_to?(getter)
2284: setter = getter.to_s + "="
2285: if val = hash.send(getter)
2286: self.send(setter, val)
2287: end
2288: end
2289: }
2290:
2291: hash = hash.to_hash
2292: else
2293: if hash[:title]
2294: @title = hash[:title]
2295: hash.delete(:title)
2296: end
2297: end
2298:
2299: # Before anything else, set our parent if it was included
2300: if hash.include?(:parent)
2301: @parent = hash[:parent]
2302: hash.delete(:parent)
2303: end
2304:
2305: # Munge up the namevar stuff so we only have one value.
2306: hash = self.argclean(hash)
2307:
2308: # Let's do the name first, because some things need to happen once
2309: # we have the name but before anything else
2310:
2311: attrs = self.class.allattrs
2312:
2313: if hash.include?(namevar)
2314: #self.send(namevar.to_s + "=", hash[namevar])
2315: self[namevar] = hash[namevar]
2316: hash.delete(namevar)
2317: if attrs.include?(namevar)
2318: attrs.delete(namevar)
2319: else
2320: self.devfail "My namevar isn't a valid attribute...?"
2321: end
2322: else
2323: self.devfail "I was not passed a namevar"
2324: end
2325:
2326: # If the name and title differ, set up an alias
2327: if self.name != self.title
2328: if obj = self.class[self.name]
2329: if self.class.isomorphic?
2330: raise Puppet::Error, "%s already exists with name %s" %
2331: [obj.title, self.name]
2332: end
2333: else
2334: self.class.alias(self.name, self)
2335: end
2336: end
2337:
2338: if hash.include?(:provider)
2339: self[:provider] = hash[:provider]
2340: hash.delete(:provider)
2341: else
2342: setdefaults(:provider)
2343: end
2344:
2345: # This is all of our attributes except the namevar.
2346: attrs.each { |attr|
2347: if hash.include?(attr)
2348: begin
2349: self[attr] = hash[attr]
2350: rescue ArgumentError, Puppet::Error, TypeError
2351: raise
2352: rescue => detail
2353: error = Puppet::DevError.new( "Could not set %s on %s: %s" % [attr, self.class.name, detail])
2354: error.set_backtrace(detail.backtrace)
2355: raise error
2356: end
2357: hash.delete attr
2358: end
2359: }
2360:
2361: # Set all default values.
2362: self.setdefaults
2363:
2364: if hash.length > 0
2365: self.debug hash.inspect
2366: self.fail("Class %s does not accept argument(s) %s" %
2367: [self.class.name, hash.keys.join(" ")])
2368: end
2369:
2370: if self.respond_to?(:validate)
2371: self.validate
2372: end
2373: end
Create a new metaparam. Requires a block and a name, stores it in the @parameters array, and does some basic checking on it.
# File lib/puppet/type.rb, line 211
211: def self.newmetaparam(name, options = {}, &block)
212: @@metaparams ||= []
213: @@metaparamhash ||= {}
214: name = symbolize(name)
215:
216: param = genclass(name,
217: :parent => options[:parent] || Puppet::Parameter,
218: