On Mon, Oct 15, 2012 at 08:18:36PM +0200, Jakov Sosic wrote: > On 10/15/2012 07:23 PM, Stefan Schulte wrote: > > > The fact that your exists? method does not really answer the question if > > a resource is present or absent is a bit strange. And inside the create > > method you are basically reimplementing properties with parameters. If > > something has to be checked for correctness it should be a property. > > Otherwise it is a parameter. Like the service resource: enable is a > > property because it can be out of sync. hasstatus is a parameter because > > it cannot be out of sync but only changes the behaviour of the provider > > OK, I've figured that out through this conversation... > > Now this is somewhat fixed code: > > http://pastebin.com/q0TBX4KB > > I've moved some params to properties. > > > > Your main concern against properties if I got you correctly was about > > speed because puppet would run one query for each property. One way around > > that is to implement a query method that will query all properties at once > > and store them in a hash (@property_hash). Every get-method now check > > if @property_hash[:some_property] does already exist and return that > > value if it does or run the query method that would populate the > > @property_hash hash. > > That sounds interesting, and more important it seems to me that complete > rewrite is not necessary in this case. Do you have some examples of this > idea? > > > > Another speed improvement is to implement an `instances` and `prefetch` > > method. That has the benefit that puppet does "react" on such methods > > if they are implemented: > > > > * you are able to run "puppet resource cobblersystem" on the command > > line to get the current configuration of all systems (that depends on > > an instances classmethod) > > * you can use the resources type to purge unmanaged systems > > > > resources { 'cobblersystem': > > purge => true > > } > > * the prefetch method is automatically called by puppet if implemented > > to create provider instances > > * your get methods become trivial > > Wow, sounds very interesting. > > I would plea for possible examples :)
The instances method is a class method and has to return an array of providers. So this often looks like this def self.instances systems = [] my_fancy_command.each_line do |line| somehow_split_line_into_different_fields_like_name_and_interfaces systems << new( :name => name, :interfaces => interfaces, :ensure => :present ) end systems end One important thing: If you create a new provider instance you can pass a hash (like I did in new(:name => name, :interfaces => interface)) and this hash is stored in the member variable @property_hash of that new provider. An example of a simple instances method: https://github.com/stschulte/puppet-rpmkey/blob/master/lib/puppet/provider/rpmkey/rpm.rb The rpmkey type can make sure that a certain gpg key is imported into rpm. To get the currently installed keys the provider runs rpm -q gpg-key This command can either return with a non zero exit code (no packages found) in case we have zero keys or it will print one line per key. For each line a provider instance is added to the array that is finally returned. prefetch: The prefetch method is called by puppet for each providerclass that implements such a method (see lib/puppet/transaction.rb#prefetch). The prefetch method is called with a hash of every resource that is defined in the user's manifest (=every resource puppet should manage). The hash will have the form resource[:name] as a key and resource as the value. What the prefetch method can do now is create provider instances and bind the provider instances to resources. A common prefetch method that is also shown in the rpm provider for rpmkey: def self.prefetch(resources) instances.each do |prov| if resource = resources[prov.name] resource.provider = prov end end end The prefetch method first calls instances that will return a list of every key that is currently present. Then I check if that key is also managed by puppet. If the lookup succeeds (the key is indeed managed by puppet), I'll bind the provider to the resource. At this point the provider instance already has @property_hash[:ensure] set, so when puppet later handles the different rpmkey resources and asks exists? I can simply return the cached value. def exists? get(:ensure) != :absent end Note: get(:ensure) is implemented in lib/provider.rb as def get(param) @property_hash[param.intern] || :absent end A more complex provider that has to manage multiple properties: https://github.com/stschulte/puppetlabs-solaris/blob/feature/master/projects/lib/puppet/provider/project/projadd.rb The instances method is more complicated here but it basically does the same thing: return an array of provider instances. You'll notice that I do not implement any method to get the current values of the properties. The methodcall "mk_resource_methods" already creates these for me. "mk_resource_methods" will create a get method for every property that is essentially (if your property is named interfaces) def interfaces @property_hash[:interfaces] || :absent end I hope that helps. An example of a query method can be found in the package provider in puppet core. The package provider is a bit special here because it does not trust its prefetched values. This is because one resource can change the state of another resource: package { "mod_ssl": ensure => installed } package { "httpd": ensure => installed } The ensure property of "httpd" can change in the middle of a puppetrun (if mod_ssl is installed first httpd will be installed as a dependency) so the prefetched value of :absent can be obsolete when puppet actually handles the resource Package["httpd"]. For you cobblersystem type I do not think that one resource may influence another resource right? -Stefan -- You received this message because you are subscribed to the Google Groups "Puppet Users" group. To post to this group, send email to puppet-users@googlegroups.com. To unsubscribe from this group, send email to puppet-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/puppet-users?hl=en.