Forum: CFEngine Help Subject: Re: downsizing a huge policy file, sensibly Author: davidlee Link to topic: https://cfengine.com/forum/read.php?3,24050,24053#msg-24053
Locally we have several cases where we want to apply different data in different environments but in standard ways. These include setting up one or more network interfaces, some of which may be bonded; ensuring that certain users are in the passwd file on some (nota all) machines (and some of the resulting entries may be stripped-down "+userx:..." for NIS compatibility), etc. The overall scheme I have used is to separate out the very detailed "vars:" data (which is also likely to have high-frequency maintenance) from the more general-purpose other things, and to put those other things into a method (which, once established, is likely to have low-frequency maintenance). So whereas you suggest "I was considering to write a module that, depending on hostname and location, would return a server list, a peer list, and a key list", what I do is "write an appropriate set of '*.cf' caller files that set up appropriate 'vars:' data and then do 'usemethod' to a bundle which does all the 'files:', 'commands:', etc.". In both our cases, the complexity lies in constructing our data within each environment, that is, in getting a good 'vars:' structure. Having done that, applying the data ('files:', 'commands:', etc.) can be as general purpose as reasonably possible. One technique I find very useful is to put my data into associative arrays in the caller and then pass the name of that array as an argument into the method. Overall something like: ---------- bundle agent caller_1 { vars: envir_a:: "user1" string => "username_1"; "user1" int => "111"; "user1" int => "1111"; "user2" string => "username_2"; "user2" int => "222"; "user2" int => "2222"; "userlist" slist => { "user1", "user2" }; envir_b:: ### set up different users, say, user3, user4, user5 ### ending with: "userlist" slist => { "user3", "user4", "user5" }; any:: # possible algorithmic data, always applicable to the lists defined above: "$(userlist)" string => "/users/$(userlist)"; methods: # Now call a general-purpose bundle with our data. # Note that we pass the fully-qualified name of our assoc. array. possibly_general:: "any" usebundle => action_user_promise("caller_1.$(userlist)"); } ### This is probably in a different pseudo-library ".cf" file. # "arr" is an associative array bundle agent action_user_promise(arr) { files: ### do some file business using vars from 'arr'. commands: ### do some command business using vars from 'arr'. } ---------- You can be more subtle. For instance, given the above example, where the usernames are distinct, you could actually define their particular data under an "any::" selector, and only apply the "envir_*::" selectors when building the "userlist". This would allow you to build hybrid systems: ---------- vars: any:: "user1" string => "username_1"; "user1" int => "111"; "user1" int => "1111"; ### similarly always set up user2, user3, user4, user5 ### Then construct per-environment lists of users: envir_a:: "userlist" slist => { "user1", "user2" }; envir_b:: "userlist" slist => { "user3", "user4", "user5" }; envir_hybrid_145:: "userlist" slist => { "user1", "user4", "user5" }; envir_hybrid_23:: "userlist" slist => { "user2", "user3" }; ---------- You can now imagine expanding that to more than one "caller_1" bundle. Each constructs an associative array of data and calls the common method. So "caller_N" does: ---------- bundle agent caller_N { vars: # construct data ending with: "userlist" slist => {...}; methods: # Note that we pass the fully-qualified name of our assoc. array. possibly_general:: "any" usebundle => action_user_promise("caller_N.$(userlist)"); } ---------- Hope that helps. _______________________________________________ Help-cfengine mailing list Help-cfengine@cfengine.org https://cfengine.org/mailman/listinfo/help-cfengine