[Puppet Users] Advice/Best practices inter-module dependencies

2012-01-26 Thread Jos Houtman
Hello list,

I am looking for advice/best-practices on how to handle inter-module 
dependencies.
We have a fairly large/complex code base (100+ modules) with a lot of 
history (we started at 0.24) and lately we have taken into looking how we 
can improve the quality of the codebase.
Parametrized classes, the style guide are all quick wins and no-brainers. 

But we have some inter module dependencies, mostly because of ordering, for 
which a proper design pattern is more elusive.

A good example is our ldap setup, this setup needs to happen after the 
initialization of our packaging system.
It also has to happen before a lot of the other modules, because ldap 
provides the details for some of the file owners/groups that are used.

We have experimented with a few methods of getting this setup, but 
have always found significant drawbacks. 

Without stages we tried three ways of doing this:
Creating a dependency chain between classes.
Class['Ldap'] - Class['Mysql'].
This is very easy to do, but doesn't work if we inherit from Ldap,  say: 
 class ldap::server inherits ldap
The ordering between ldap::server and Mysql is not guaranteed.
It also requires the maintainer of the ldap module to know about all 
modules that depend on ldap and update them if he decides to inherit. A 
task that is likely to be forgotten.

Creating a dependency chains between resources in the modules, f.e. 
notify's. 
Every module that is part of an dependency defines an  notify{ 'endpoint': 
} and makes sure that everything within the module is executed before the 
notify.
If we inherit from the base class, the overriding class is responsible for 
making sure that endpoint is still the last thing executed in this module. 
Making it more likely that the ordering of events will remain as we want it 
after a continued year of development.
But because of assumptions about out base image, and the rarity of 
reinstalls. it is easy to forgot the requirements in modules that actually 
need them,  
Leading to some subtle bugs where the first puppet run on a fresh install 
might not work but subsequent runs do.
Luckily execution is now in fixed-order, otherwise that would have been a 
problem as well.

The third is the use of stages for the ordering of actions, but this seems 
to be an all or nothing approach, and the result is a very splintered 
module. 
For example, our packaging setup is quite complex. First we initialise the 
packaging system and configure all the default package source, then custom 
sources could be configured on top of that we allow (un)masking of specific 
package versions.
And after all this one can install a package.
We could define 4 stages and each module that needs to do one of these 
actions would need to run classes in the designated stage, this results in 
some very splintered packages. 


Or we could define only 2 stages and have the base setup run before 
everything else and then wrap all other actions with defines that specify 
the ordering between them using some self-build ordering mechanism based on 
notify's or classes. 
A problem with this would be that those defines could only be used in the 
main stage, because of the built-in ordering. Modules adding more stages, 
like ldap, would need to do something custom for installing the required 
packages, which again makes maintenance of the package module more 
difficult to do right.


So after this rather longer email explaining our problem and some of the 
options we explored, how do you guys handle these kind of complex 
inter-module dependencies?


Cheers,

Jos Houtman

-- 
You received this message because you are subscribed to the Google Groups 
Puppet Users group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/puppet-users/-/zn97r8lyAtwJ.
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.



[Puppet Users] Advice/Best practices inter-module dependencies

2012-01-26 Thread Jos Houtman
Hello list,

I am looking for advice/best-practices on how to handle inter-module
dependencies.
We have a fairly large/complex code base (100+ modules) with a lot of
history (we started at 0.24) and lately we have taken into looking how we
can improve the quality of the codebase.
Parametrized classes, the style guide are all quick wins and no-brainers.

But we have some inter module dependencies, mostly because of ordering, for
which a proper design pattern is more elusive.

A good example is our ldap setup, this setup needs to happen after the
initialization of our packaging system.
It also has to happen before a lot of the other modules, because ldap
provides the details for some of the file owners/groups that are used.

We have experimented with a few methods of getting this setup, but
have always found significant drawbacks.

Without stages we tried three ways of doing this:
Creating a dependency chain between classes.
Class['Ldap'] - Class['Mysql'].
This is very easy to do, but doesn't work if we inherit from Ldap,  say:
 class ldap::server inherits ldap
The ordering between ldap::server and Mysql is not guaranteed.
It also requires the maintainer of the ldap module to know about all
modules that depend on ldap and update them if he decides to inherit. A
task that is likely to be forgotten.

Creating a dependency chains between resources in the modules, f.e.
notify's.
Every module that is part of an dependency defines an  notify{ 'endpoint':
} and makes sure that everything within the module is executed before the
notify.
If we inherit from the base class, the overriding class is responsible for
making sure that endpoint is still the last thing executed in this module.
Making it more likely that the ordering of events will remain as we want it
after a continued year of development.
But because of assumptions about out base image, and the rarity of
reinstalls. it is easy to forgot the requirements in modules that actually
need them,
Leading to some subtle bugs where the first puppet run on a fresh install
might not work but subsequent runs do.
Luckily execution is now in fixed-order, otherwise that would have been a
problem as well.

The third is the use of stages for the ordering of actions, but this seems
to be an all or nothing approach, and the result is a very splintered
module.
For example, our packaging setup is quite complex. First we initialise the
packaging system and configure all the default package source, then custom
sources could be configured on top of that we allow (un)masking of specific
package versions.
And after all this one can install a package.
We could define 4 stages and each module that needs to do one of these
actions would need to run classes in the designated stage, this results in
some very splintered packages.


Or we could define only 2 stages and have the base setup run before
everything else and then wrap all other actions with defines that specify
the ordering between them using some self-build ordering mechanism based on
notify's or classes.
A problem with this would be that those defines could only be used in the
main stage, because of the built-in ordering. Modules adding more stages,
like ldap, would need to do something custom for installing the required
packages, which again makes maintenance of the package module more
difficult to do right.


So after this rather longer email explaining our problem and some of the
options we explored, how do you guys handle these kind of complex
inter-module dependencies?


Cheers,

Jos Houtman

-- 
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.